[libvirt] [PATCH] esx: Replace scanf with STRSKIP and strtok_r
Eric Blake
eblake at redhat.com
Thu Apr 15 15:27:23 UTC 2010
On 04/14/2010 06:34 PM, Matthias Bolte wrote:
> This also fixes a portability problem with the %a format modifier.
> %a is not portable and made esxDomainDumpXML fail at runtime in
> MinGW builds.
>
> Pull in strtok_r from gnulib, because MinGW lacks it.
> ---
> bootstrap.conf | 1 +
See my comments about moving this hunk into your patch for .gnulib.
> @@ -60,8 +60,8 @@ esxSupportsLongMode(esxPrivate *priv)
> esxVI_DynamicProperty *dynamicProperty = NULL;
> esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL;
> esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL;
> + esxVI_ParsedHostCpuIdInfo parsedHostCpuIdInfo;
> char edxLongModeBit = '?';
> - char edxFirstBit = '?';
>
> if (priv->supportsLongMode != esxVI_Boolean_Undefined) {
> return priv->supportsLongMode;
> @@ -96,23 +96,12 @@ esxSupportsLongMode(esxPrivate *priv)
> for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo != NULL;
> hostCpuIdInfo = hostCpuIdInfo->_next) {
> if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */
> -#define _SKIP4 "%*c%*c%*c%*c"
> -#define _SKIP12 _SKIP4":"_SKIP4":"_SKIP4
> -
> - /* Expected format: "--X-:----:----:----:----:----:----:----" */
> - if (sscanf(hostCpuIdInfo->edx,
> - "%*c%*c%c%*c:"_SKIP12":"_SKIP12":%*c%*c%*c%c",
> - &edxLongModeBit, &edxFirstBit) != 2) {
Oh my. I see why you want this replaced.
> @@ -213,37 +217,34 @@ esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
> return -1;
> }
>
> - /*
> - * Parse string as '[<datastore>] <path>'. '%as' is similar to '%s', but
> - * sscanf() will allocate the memory for the string, so the caller doesn't
> - * need to preallocate a buffer that's large enough.
> - *
> - * The s in '%as' can be replaced with a character set, e.g. [a-z].
> - *
> - * '%a[^]%]' matches <datastore>. '[^]%]' excludes ']' from the accepted
> - * characters, otherwise sscanf() wont match what it should.
> - *
> - * '%a[^\n]' matches <path>. '[^\n]' excludes '\n' from the accepted
> - * characters, otherwise sscanf() would only match up to the first space,
> - * but spaces are valid in <path>.
> - */
> - if (sscanf(datastoreRelatedPath, "[%a[^]%]] %a[^\n]", datastoreName,
> - &directoryAndFileName) != 2) {
> + if (esxVI_String_DeepCopyValue(©OfDatastoreRelatedPath,
> + datastoreRelatedPath) < 0) {
> + goto failure;
> + }
> +
> + /* Expected format: '[<datastore>] <path>' */
> + if ((tmp = STRSKIP(copyOfDatastoreRelatedPath, "[")) == NULL ||
> + (preliminaryDatastoreName = strtok_r(tmp, "]", &saveptr)) == NULL ||
> + (directoryAndFileName = strtok_r(NULL, "", &saveptr)) == NULL) {
Even though it is more lines of code, it is much smaller based on fewer
justification comments, and possibly faster execution to boot (strtok_r
is certainly simpler to implement than sscanf). I like it.
> +int
> +esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedhostCpuIdInfo,
> + esxVI_HostCpuIdInfo *hostCpuIdInfo)
> +{
> + int expectedLength = 39; /* = strlen("----:----:----:----:----:----:----:----"); */
> + char *input[4] = { hostCpuIdInfo->eax, hostCpuIdInfo->ebx,
> + hostCpuIdInfo->ecx, hostCpuIdInfo->edx };
> + char *output[4] = { parsedhostCpuIdInfo->eax, parsedhostCpuIdInfo->ebx,
> + parsedhostCpuIdInfo->ecx, parsedhostCpuIdInfo->edx };
> + const char *name[4] = { "eax", "ebx", "ecx", "edx" };
> + int r, i, o;
> +
> + memset(parsedhostCpuIdInfo, 0, sizeof (esxVI_ParsedHostCpuIdInfo));
> +
> + parsedhostCpuIdInfo->level = hostCpuIdInfo->level->value;
> +
> + for (r = 0; r < 4; ++r) {
> + if (strlen(input[r]) != expectedLength) {
> + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
> + _("HostCpuIdInfo register '%s' has an unexpected length"),
> + name[r]);
> + goto failure;
> + }
> +
> + /* Strip the ':' and invert the "bit" order from 31..0 to 0..31 */
> + for (i = 0, o = 31; i < expectedLength; i += 5, o -= 4) {
> + output[r][o] = input[r][i];
> + output[r][o - 1] = input[r][i + 1];
> + output[r][o - 2] = input[r][i + 2];
> + output[r][o - 3] = input[r][i + 3];
> +
> + if (i + 4 < expectedLength && input[r][i + 4] != ':') {
> + ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
> + _("HostCpuIdInfo register '%s' has an unexpected format"),
> + name[r]);
> + goto failure;
> + }
> + }
I spent quite a few minutes looking at this, and didn't see any semantic
differences between this longer implementation and the original sscanf.
> + }
> +
> + return 0;
> +
> + failure:
> + memset(parsedhostCpuIdInfo, 0, sizeof (esxVI_ParsedHostCpuIdInfo));
In general, I prefer to see:
memset(parsedhostCpuIdInfo, 0, sizeof *parsedhostCpuIdInfo);
on the grounds that sizeof expr is more robust if expr changes types, in
contrast to sizeof(type).
Many existing uses in libvirt also have the style
sizeof(*parsedhostCpuIdInfo), although that makes it harder to see at a
glance whether you are using sizeof expr or sizeof(type) for expressions
that do not include *. So it's up to you whether to include () around
the expr.
ACK with that nit addressed.
--
Eric Blake eblake at redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 323 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20100415/fcf9a1a2/attachment-0001.sig>
More information about the libvir-list
mailing list