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",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",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",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标准库中的函数,改写的原因为增强程序的健壮性,减少出现异常的几率
/* * "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()
(2)Ifsizeis zero,the return value depends on the particular library implementation (it may or may not be anull 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; }