tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[PATCH 1/2] Add BSD-licensed gettext(1) implementation
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
+
+LDADD+= -lintl
+
+MAN= gettext.1
+
+.include <bsd.prog.mk>
diff --git a/src/usr.bin/gettext/gettext.c b/src/usr.bin/gettext/gettext.c
new file mode 100644
index 0000000..1bcf216
--- /dev/null
+++ b/src/usr.bin/gettext/gettext.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2015 William Orr <will%worrbase.com@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char *optarg;
+extern int optopt;
+extern int optind;
+
+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));
+ 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;
+}
+
+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, "");
+
+ 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");
+ 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;
+ default:
+ usage(argv[0], EXIT_FAILURE);
+ /* NOTREACHED */
+ break;
+ }
+ }
+ progname = argv[0];
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ fprintf(stderr, "missing msgid\n");
+ 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");
+
+ argc -= 1;
+ argv += 1;
+ } else if (argc > 2 && !sflag) {
+ fprintf(stderr, "%s: too many arguments\n", basename(progname));
+ 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;
+}
--
2.1.0
Home |
Main Index |
Thread Index |
Old Index