2.4 函数 getopt_long
文件 Getopt_long.c
作用 验证输入参数的合法性(代码这么长,主要是针对一些列异常输入参数)
在initdb.c中,传入的参数为:
while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
该函数依次验证argv[i] 1<=i <argc
另外 "dD:E:kL:nNU:WA:sST:X:", 这种写法也是有针对性的。后面无冒号则不带参数,否则必须带参数
/*
* getopt_long
* Parse argc/argv argument vector, with long options.
*
* This implementation does not use optreset. Instead, we guarantee that
* it can be restarted on a new argv array after a previous call returned -1,
* if the caller resets optind to 1 before the first call of the new series.
* (Internally, this means we must be sure to reset "place" to EMSG before
* returning -1.)
*/
int
getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option * longopts, int *longindex)
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (!*place)
{ /* update scanning pointer */
if (optind >= argc)
{
place = EMSG;
return -1;
}
place = argv[optind];
if (place[0] != '-')
{
place = EMSG;
return -1;
}
place++;
if (place[0] && place[0] == '-' && place[1] == '\0')
{ /* found "--" */
++optind;
place = EMSG;
return -1;
}
if (place[0] && place[0] == '-' && place[1])
{
/* long option */
size_t namelen;
int i;
place++;
namelen = strcspn(place, "=");
for (i = 0; longopts[i].name != NULL; i++)
{
if (strlen(longopts[i].name) == namelen
&& strncmp(place, longopts[i].name, namelen) == 0)
{
if (longopts[i].has_arg)
{
if (place[namelen] == '=')
optarg = place + namelen + 1;
else if (optind < argc - 1)
{
optind++;
optarg = argv[optind];
}
else
{
if (optstring[0] == ':')
return BADARG;
if (opterr)
fprintf(stderr,
"%s: option requires an argument -- %s\n",
argv[0], place);
place = EMSG;
optind++;
return BADCH;
}
}
else
{
optarg = NULL;
if (place[namelen] != 0)
{
/* XXX error? */
}
}
optind++;
if (longindex)
*longindex = i;
place = EMSG;
if (longopts[i].flag == NULL)
return longopts[i].val;
else
{
*longopts[i].flag = longopts[i].val;
return 0;
}
}
}
if (opterr && optstring[0] != ':')
fprintf(stderr,
"%s: illegal option -- %s\n", argv[0], place);
place = EMSG;
optind++;
return BADCH;
}
}
/* short option */
optopt = (int) *place++;
oli = strchr(optstring, optopt);
if (!oli)
{
if (!*place)
++optind;
if (opterr && *optstring != ':')
fprintf(stderr,
"%s: illegal option -- %c\n", argv[0], optopt);
return BADCH;
}
if (oli[1] != ':')
{ /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else
{ /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (argc <= ++optind)
{ /* no arg */
place = EMSG;
if (*optstring == ':')
return BADARG;
if (opterr)
fprintf(stderr,
"%s: option requires an argument -- %c\n",
argv[0], optopt);
return BADCH;
}
else
/* white space */
optarg = argv[optind];
place = EMSG;
++optind;
}
return optopt;
}
optarg 会传送到initdb.c中 ,其值为各个 参数对应的值 (如 -D ./data 那么optarg 为“./data”)
2.5 函数 pg_strdup (char *)
pg中改写了很多C标准库中的函数,改写的原因为增强程序的健壮性,减少出现异常的几率
pg_strdup()函数和标准库函数strdup差别在于对输入参数为空(NULL)的检测
/*
* "Safe" wrapper around strdup().
*/
char *
pg_strdup(const char *in)
{
char *tmp;
if (!in)
{
fprintf(stderr,
_("cannot duplicate null pointer (internal error)\n"));
exit(EXIT_FAILURE);
}
tmp = strdup(in);
if (!tmp)
{
fprintf(stderr, _("out of memory\n"));
exit(EXIT_FAILURE);
}
return tmp;
}
2.6 函数 setup_pgdata (void)
文件initdb.c
若initdb时没指定-D 则会默认寻找安装路径PGDATA,但是若环境变量中无此变量则报错
void
setup_pgdata(void)
{
char *pgdata_get_env,
*pgdata_set_env;
if (strlen(pg_data) == 0)
{
pgdata_get_env = getenv("PGDATA");
if (pgdata_get_env && strlen(pgdata_get_env))
{
/* PGDATA found */
pg_data = pg_strdup(pgdata_get_env);
}
else
{
fprintf(stderr,
_("%s: no data directory specified\n"
"You must identify the directory where the data for this database system\n"
"will reside. Do this with either the invocation option -D or the\n"
"environment variable PGDATA.\n"),
progname);
exit(1);
}
}
pgdata_native = pg_strdup(pg_data);
canonicalize_path(pg_data);
/*
* we have to set PGDATA for postgres rather than pass it on the command
* line to avoid dumb quoting problems on Windows, and we would especially
* need quotes otherwise on Windows because paths there are most likely to
* have embedded spaces.
*/
pgdata_set_env = pg_malloc(8 + strlen(pg_data));
sprintf(pgdata_set_env, "PGDATA=%s", pg_data);
putenv(pgdata_set_env);
}
2.6.1 函数pg_malloc()
(1)malloc(0) 是允许的,这是因为Linux中malloc有一个下限值16Bytes,注意malloc(-1)是禁止的 --这个是从百度百科看到的。
(2)If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced. --这个来自 http://www.cplusplus.com/reference/cstdlib/malloc/?kw=malloc
(3)malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size
is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to
free(). --来自 man malloc
is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to
free(). --来自 man malloc
这样处理是为了防止size为0
void *
pg_malloc(size_t size)
{
void *tmp;
/* Avoid unportable behavior of malloc(0) */
if (size == 0)
size = 1;
tmp = malloc(size);
if (!tmp)
{
fprintf(stderr, _("out of memory\n"));
exit(EXIT_FAILURE);
}
return tmp;
}