diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0106afe8a2f625813d7547b237578c9c2b7bbc19..501c23e67f9b9913a261a9bedb511acad4d3e73b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1208,6 +1208,7 @@ virBitmapNextSetBit; virBitmapOverlaps; virBitmapParse; virBitmapParseSeparator; +virBitmapParseUnlimited; virBitmapSetAll; virBitmapSetBit; virBitmapSetBitExpand; diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index 3381a3d348eea7ad416e74429f6e472efb3cec60..32767631334495eec40812f7614c486056ca861d 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -542,6 +542,118 @@ virBitmapParse(const char *str, return virBitmapParseSeparator(str, '\0', bitmap, bitmapSize); } +/** + * virBitmapParseUnlimited: + * @str: points to a string representing a human-readable bitmap + * @bitmap: a bitmap created from @str + * + * This function is the counterpart of virBitmapFormat. This function creates + * a bitmap, in which bits are set according to the content of @str. + * + * The bitmap is expanded to accomodate all the bits. + * + * @str is a comma separated string of fields N, which means a number of bit + * to set, and ^N, which means to unset the bit, and N-M for ranges of bits + * to set. + * + * Returns 0 on success, or -1 in case of error. + */ +int +virBitmapParseUnlimited(const char *str, + virBitmapPtr *bitmap) +{ + bool neg = false; + const char *cur = str; + char *tmp; + size_t i; + int start, last; + + if (!(*bitmap = virBitmapNewEmpty())) + return -1; + + if (!str) + goto error; + + virSkipSpaces(&cur); + + if (*cur == '\0') + goto error; + + while (*cur != 0) { + /* + * 3 constructs are allowed: + * - N : a single CPU number + * - N-M : a range of CPU numbers with N < M + * - ^N : remove a single CPU number from the current set + */ + if (*cur == '^') { + cur++; + neg = true; + } + + if (!c_isdigit(*cur)) + goto error; + + if (virStrToLong_i(cur, &tmp, 10, &start) < 0) + goto error; + if (start < 0) + goto error; + + cur = tmp; + + virSkipSpaces(&cur); + + if (*cur == ',' || *cur == 0) { + if (neg) { + if (virBitmapClearBitExpand(*bitmap, start) < 0) + goto error; + } else { + if (virBitmapSetBitExpand(*bitmap, start) < 0) + goto error; + } + } else if (*cur == '-') { + if (neg) + goto error; + + cur++; + virSkipSpaces(&cur); + + if (virStrToLong_i(cur, &tmp, 10, &last) < 0) + goto error; + if (last < start) + goto error; + + cur = tmp; + + for (i = start; i <= last; i++) { + if (virBitmapSetBitExpand(*bitmap, i) < 0) + goto error; + } + + virSkipSpaces(&cur); + } + + if (*cur == ',') { + cur++; + virSkipSpaces(&cur); + neg = false; + } else if (*cur == 0) { + break; + } else { + goto error; + } + } + + return 0; + + error: + virReportError(VIR_ERR_INVALID_ARG, + _("Failed to parse bitmap '%s'"), str); + virBitmapFree(*bitmap); + *bitmap = NULL; + return -1; +} + /** * virBitmapNewCopy: * @src: the source bitmap. diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h index 3356e1e7778462fb4bd66609782e47edbe6e33ff..5984b80ea17253957aeee2bfe6cc92da3d97cf86 100644 --- a/src/util/virbitmap.h +++ b/src/util/virbitmap.h @@ -94,6 +94,10 @@ virBitmapParseSeparator(const char *str, char terminator, virBitmapPtr *bitmap, size_t bitmapSize); +int +virBitmapParseUnlimited(const char *str, + virBitmapPtr *bitmap) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); virBitmapPtr virBitmapNewCopy(virBitmapPtr src) ATTRIBUTE_NONNULL(1); diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c index 89c41d00c7c3d53f13077d1f5e1e21f367ba0c13..009fa0dad363374dafd525472a5b0d0bfe067a18 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -632,12 +632,19 @@ test12(const void *opaque ATTRIBUTE_UNUSED) TEST_MAP(151, "100"); + virBitmapFree(map); + if (virBitmapParseUnlimited("34,1023", &map) < 0) + goto cleanup; + + TEST_MAP(1024, "34,1023"); + ret = 0; cleanup: virBitmapFree(map); return ret; } + #undef TEST_MAP