tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: [PATCH 1/2] Add BSD-licensed gettext(1) implementation



In article <1433139701-11940-2-git-send-email-will%worrbase.com@localhost>,
William Orr  <will%worrbase.com@localhost> wrote:
>Simple gettext implementation that models GNU gettext(1). Is
>feature-complete compared to GNU gettext(1).
>
>Needs manpages and tests
>---
> src/usr.bin/gettext/Makefile  |  12 +++
> src/usr.bin/gettext/gettext.c | 237 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 249 insertions(+)
> create mode 100644 src/usr.bin/gettext/Makefile
> create mode 100644 src/usr.bin/gettext/gettext.c
>
>diff --git a/src/usr.bin/gettext/Makefile b/src/usr.bin/gettext/Makefile
>new file mode 100644
>index 0000000..b928780
>--- /dev/null
>+++ b/src/usr.bin/gettext/Makefile
>@@ -0,0 +1,12 @@
>+.include <bsd.own.mk>
>+
>+PROG=	gettext
>+SRCS=	gettext.c
>+
>+CFLAGS+=-g

Delete -g

>+
>+LDADD+=	-lintl

DPADD+= ${LIBINTL}

>+
>+MAN=	gettext.1
>+


>+.include <bsd.prog.mk>
>+extern char *optarg;
>+extern int optopt;
>+extern int optind;

delete, provided.

>+
>+static bool nflag;
>+
>+static void
>+usage(char *progname, int exit_status)
>+{
>+
>+	printf("Usage: %s [-ehn] [[TEXTDOMAIN] MSGID]\n", basename(progname));
>+	printf("Usage: %s -s [MSGID]...\n", basename(progname));

getprogname();

>+	exit(exit_status);
>+}
>+
>+static void
>+expand(char *str)
>+{
>+	char *fp, *sp, ch, pl;
>+
>+	for (fp = str, sp = str; *fp != 0;) {
>+		if (*fp == '\\') {
>+			switch (*++fp) {
>+			case 'a':
>+				*sp++ = '\a';
>+				fp++;
>+				break;
>+			case 'b':
>+				*sp++ = '\b';
>+				fp++;
>+				break;
>+			case 'c':
>+				nflag = true;
>+				fp++;
>+				break;
>+			case 'f':
>+				*sp++ = '\f';
>+				fp++;
>+				break;
>+			case 'n':
>+				*sp++ = '\n';
>+				fp++;
>+				break;
>+			case 'r':
>+				*sp++ = '\r';
>+				fp++;
>+				break;
>+			case 't':
>+				*sp++ = '\t';
>+				fp++;
>+				break;
>+			case 'v':
>+				*sp++ = '\v';
>+				fp++;
>+				break;
>+			case '\\':
>+				*sp++ = '\\';
>+				fp++;
>+				break;
>+			case '0':
>+			case '1':
>+			case '2':
>+			case '3':
>+			case '4':
>+			case '5':
>+			case '6':
>+			case '7':
>+				ch = *fp++ - '0';
>+				pl = 0;
>+				while (*fp >= '0' && *fp <= '7' && pl < 2) {
>+					ch *= 8;
>+					ch += *fp++ - '0';
>+					pl++;
>+				}
>+
>+				*sp++ = ch;
>+				break;
>+			default:
>+				*sp++ = '\\';
>+				break;
>+			}
>+		}
>+		*sp++ = *fp++;
>+	}
>+
>+	*sp = '\0';
>+}
>+
>+static char *
>+gettext_getenv(const char *env, size_t len)
>+{
>+	char *ret = NULL;
>+
>+	ret = calloc(len, 1);
>+	if (ret == NULL)
>+		err(EXIT_FAILURE, "can't allocate memory");
>+
>+	if (getenv_r(env, ret, len)) {
>+		free(ret);
>+		ret = NULL;
>+
>+		if (errno != ENOENT)
>+			err(EXIT_FAILURE, "couldn't read %s from env", env);
>+	}
>+	return ret;

Why this complexity? It is not re-entrant/threaded just use regular
getenv, estrdup() it.

>+}
>+
>+int
>+main(int argc, char **argv)
>+{
>+	char *msgdomain = NULL;
>+	char *msgdomaindir = NULL;
>+	char *msgid = NULL;
>+	char *progname = NULL;
>+	char *translation = NULL;
>+	bool eflag = false;
>+	bool sflag = false;
>+	int ch;
>+
>+	setlocale(LC_ALL, "");

also setprogname();

>+
>+	while ((ch = getopt(argc, argv, "d:eEhnsV")) != -1) {
>+		switch (ch) {
>+		case 'd':
>+			msgdomain = strdup(optarg);
>+			if (msgdomain == NULL)
>+				err(EXIT_FAILURE, "can't allocate memory");

estrdup()?

>+			break;
>+		case 'e':
>+			eflag = true;
>+			break;
>+		case 'h':
>+			usage(argv[0], EXIT_SUCCESS);
>+			/* NOTREACHED */
>+			break;
>+		case 'n':
>+			nflag = true;
>+			break;
>+		case 's':
>+			sflag = true;
>+			break;
>+		case 'E':
>+			/* GNU gettext compat */
>+			break;

Sort options.

>+		default:
>+			usage(argv[0], EXIT_FAILURE);
>+			/* NOTREACHED */
>+			break;
>+		}
>+	}
>+	progname = argv[0];
>+	argc -= optind;
>+	argv += optind;
>+
>+	if (argc == 0) {
>+		fprintf(stderr, "missing msgid\n");

warnx()?

>+		usage(progname, EXIT_FAILURE);
>+	}
>+	/* msgdomain can be passed as optional arg iff -s is not passed */
>+	if (argc == 2 && !sflag) {
>+		msgdomain = strdup(argv[0]);
>+		if (msgdomain == NULL)
>+			err(EXIT_FAILURE, "can't allocate memory");

estrdup()?

>+
>+		argc -= 1;
>+		argv += 1;
>+	} else if (argc > 2 && !sflag) {
>+		fprintf(stderr, "%s: too many arguments\n", basename(progname));

warnx()?

>+		usage(progname, EXIT_FAILURE);
>+	}
>+	/* msgdomain can be passed as env var */
>+	if (msgdomain == NULL)
>+		msgdomain = gettext_getenv("TEXTDOMAIN", PATH_MAX);
>+
>+	if (msgdomain != NULL) {
>+		msgdomaindir = gettext_getenv("TEXTDOMAINDIR", PATH_MAX);
>+		if (msgdomaindir)
>+			bindtextdomain(msgdomain, msgdomaindir);
>+	}
>+	do {
>+		if (eflag)
>+			expand(*argv);
>+
>+		translation = dgettext(msgdomain, argv[0]);
>+		printf("%s", translation);
>+
>+		argc--;
>+		argv++;
>+		if (argc)
>+			printf(" ");
>+	} while (sflag && argc != 0);
>+
>+	if (sflag && !nflag)
>+		printf("\n");
>+
>+	free(msgdomain);
>+	free(msgdomaindir);
>+	return EXIT_SUCCESS;
>+}



Home | Main Index | Thread Index | Old Index