要点: 1、首先进行字符串拷贝,strdup 2、while嵌套 3、不使用switch case来表述自动机 4、使用isspace这样的标准函数 代码: /* * Conninfo parser routine * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. * Defaults are supplied (from a service file, environment variables, etc) * for unspecified options, but only if use_defaults is TRUE. */ static PQconninfoOption * conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults) { char *pname; char *pval; char *buf; char *tmp; char *cp; char *cp2; PQconninfoOption *options; PQconninfoOption *option; /* Make a working copy of PQconninfoOptions */ options = malloc(sizeof(PQconninfoOptions)); if (options == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory/n")); return NULL; } memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); /* Need a modifiable copy of the input string */ if ((buf = strdup(conninfo)) == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory/n")); PQconninfoFree(options); return NULL; } cp = buf; while (*cp) { /* Skip blanks before the parameter name */ if (isspace((unsigned char) *cp)) { cp++; continue; } /* Get the parameter name */ pname = cp; while (*cp) { if (*cp == '=') break; if (isspace((unsigned char) *cp)) { *cp++ = '/0'; while (*cp) { if (!isspace((unsigned char) *cp)) break; cp++; } break; } cp++; } /* Check that there is a following '=' */ if (*cp != '=') { printfPQExpBuffer(errorMessage, libpq_gettext("missing /"=/" after /"%s/" in connection info string/n"), pname); PQconninfoFree(options); free(buf); return NULL; } *cp++ = '/0'; /* Skip blanks after the '=' */ while (*cp) { if (!isspace((unsigned char) *cp)) break; cp++; } /* Get the parameter value */ pval = cp; if (*cp != '/'') { cp2 = pval; while (*cp) { if (isspace((unsigned char) *cp)) { *cp++ = '/0'; break; } if (*cp == '//') { cp++; if (*cp != '/0') *cp2++ = *cp++; } else *cp2++ = *cp++; } *cp2 = '/0'; } else { cp2 = pval; cp++; for (;;) { if (*cp == '/0') { printfPQExpBuffer(errorMessage, libpq_gettext("unterminated quoted string in connection info string/n")); PQconninfoFree(options); free(buf); return NULL; } if (*cp == '//') { cp++; if (*cp != '/0') *cp2++ = *cp++; continue; } if (*cp == '/'') { *cp2 = '/0'; cp++; break; } *cp2++ = *cp++; } } /* * Now we have the name and the value. Search for the param record. */ for (option = options; option->keyword != NULL; option++) { if (strcmp(option->keyword, pname) == 0) break; } if (option->keyword == NULL) { printfPQExpBuffer(errorMessage, libpq_gettext("invalid connection option /"%s/"/n"), pname); PQconninfoFree(options); free(buf); return NULL; } /* * Store the value */ if (option->val) free(option->val); option->val = strdup(pval); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory/n")); PQconninfoFree(options); free(buf); return NULL; } } /* Done with the modifiable input string */ free(buf); /* * Stop here if caller doesn't want defaults filled in. */ if (!use_defaults) return options; /* * If there's a service spec, use it to obtain any not-explicitly-given * parameters. */ if (parseServiceInfo(options, errorMessage)) { PQconninfoFree(options); return NULL; } /* * Get the fallback resources for parameters not specified in the conninfo * string nor the service. */ for (option = options; option->keyword != NULL; option++) { if (option->val != NULL) continue; /* Value was in conninfo or service */ /* * Try to get the environment variable fallback */ if (option->envvar != NULL) { if ((tmp = getenv(option->envvar)) != NULL) { option->val = strdup(tmp); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory/n")); PQconninfoFree(options); return NULL; } continue; } } /* * No environment variable specified or this one isn't set - try * compiled in */ if (option->compiled != NULL) { option->val = strdup(option->compiled); if (!option->val) { printfPQExpBuffer(errorMessage, libpq_gettext("out of memory/n")); PQconninfoFree(options); return NULL; } continue; } /* * Special handling for user */ if (strcmp(option->keyword, "user") == 0) { option->val = pg_fe_getauthname(errorMessage); continue; } } return options; }