postgres 之 initdb 源码分析 三

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标准库中的函数,改写的原因为增强程序的健壮性,减少出现异常的几率
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)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
这样处理是为了防止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;
}

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...