1/*	$NetBSD: gettext.c,v 1.2 2015/06/03 23:15:22 enami Exp $	*/
2
3/*-
4 * Copyright (c) 2015 William Orr <will@worrbase.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28#include <sys/cdefs.h>
29__RCSID("$NetBSD: gettext.c,v 1.2 2015/06/03 23:15:22 enami Exp $");
30
31#include <err.h>
32#include <errno.h>
33#include <getopt.h>
34#include <libintl.h>
35#include <locale.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <util.h>
41
42static struct option longopts[] = {
43	{ "help",       no_argument,        NULL,   'h' },
44	{ "domain",	required_argument,  NULL,   'd' },
45	{ NULL,         0,                  NULL,   '\0' },
46};
47
48static __dead void
49usage(int exit_status)
50{
51
52	fprintf(stderr, "Usage: %s [-ehn] [[<textdomain>] <msgid>]\n",
53	    getprogname());
54	fprintf(stderr, "Usage: %s [-ehn] -d <textdomain> <msgid>\n",
55	    getprogname());
56	fprintf(stderr, "Usage: %s -s [<msgid>]...\n", getprogname());
57	exit(exit_status);
58}
59
60static bool
61expand(char *str)
62{
63	char *fp, *sp, ch, pl;
64	bool nflag = false;
65
66	for (fp = str, sp = str; *fp != 0;) {
67		if (*fp == '\\') {
68			switch (*++fp) {
69			case 'a':
70				*sp++ = '\a';
71				fp++;
72				break;
73			case 'b':
74				*sp++ = '\b';
75				fp++;
76				break;
77			case 'c':
78				nflag = true;
79				fp++;
80				break;
81			case 'f':
82				*sp++ = '\f';
83				fp++;
84				break;
85			case 'n':
86				*sp++ = '\n';
87				fp++;
88				break;
89			case 'r':
90				*sp++ = '\r';
91				fp++;
92				break;
93			case 't':
94				*sp++ = '\t';
95				fp++;
96				break;
97			case 'v':
98				*sp++ = '\v';
99				fp++;
100				break;
101			case '\\':
102				*sp++ = '\\';
103				fp++;
104				break;
105			case '0':
106			case '1':
107			case '2':
108			case '3':
109			case '4':
110			case '5':
111			case '6':
112			case '7':
113				ch = *fp++ - '0';
114				pl = 0;
115				while (*fp >= '0' && *fp <= '7' && pl < 2) {
116					ch *= 8;
117					ch += *fp++ - '0';
118					pl++;
119				}
120
121				*sp++ = ch;
122				break;
123			default:
124				*sp++ = '\\';
125				break;
126			}
127			continue;
128		}
129		*sp++ = *fp++;
130	}
131
132	*sp = '\0';
133	return nflag;
134}
135
136int
137main(int argc, char **argv)
138{
139	char *msgdomain = NULL;
140	char *msgdomaindir = NULL;
141	char *translation = NULL;
142	char *s;
143	bool eflag = false;
144	bool sflag = false;
145	bool nflag = false;
146	int ch;
147
148	setlocale(LC_ALL, "");
149	setprogname(argv[0]);
150
151	while ((ch = getopt_long(argc, argv, "d:eEhnsV", longopts, NULL)) != -1)
152	{
153		switch (ch) {
154		case 'd':
155			msgdomain = estrdup(optarg);
156			break;
157		case 'E':
158			/* GNU gettext compat */
159			break;
160		case 'e':
161			eflag = true;
162			break;
163		case 'V':
164		case 'h':
165			free(msgdomain);
166			usage(EXIT_SUCCESS);
167			/* NOTREACHED */
168		case 'n':
169			nflag = true;
170			break;
171		case 's':
172			sflag = true;
173			break;
174		default:
175			free(msgdomain);
176			usage(EXIT_FAILURE);
177			/* NOTREACHED */
178		}
179	}
180	argc -= optind;
181	argv += optind;
182
183	if (argc == 0) {
184		free(msgdomain);
185		warnx("missing msgid");
186		usage(EXIT_FAILURE);
187	}
188
189	/* msgdomain can be passed as optional arg iff -s is not passed */
190	if (!sflag) {
191		if (argc == 2) {
192			free(msgdomain);
193			msgdomain = estrdup(argv[0]);
194
195			argc -= 1;
196			argv += 1;
197		} else if (argc > 2) {
198			warnx("too many arguments");
199			usage(EXIT_FAILURE);
200		}
201	}
202
203	/* msgdomain can be passed as env var */
204	if (msgdomain == NULL) {
205		if ((s = getenv("TEXTDOMAIN")) != NULL)
206			msgdomain = estrdup(s);
207	}
208
209	if (msgdomain != NULL) {
210		if ((s = getenv("TEXTDOMAINDIR")) != NULL)
211			msgdomaindir = estrdup(s);
212		if (msgdomaindir)
213			bindtextdomain(msgdomain, msgdomaindir);
214	}
215
216	do {
217		if (eflag)
218			nflag |= expand(*argv);
219
220		translation = dgettext(msgdomain, argv[0]);
221		printf("%s", translation);
222
223		argc--;
224		argv++;
225		if (argc)
226			printf(" ");
227	} while (sflag && argc != 0);
228
229	if (sflag && !nflag)
230		printf("\n");
231
232	free(msgdomain);
233	free(msgdomaindir);
234
235	return EXIT_SUCCESS;
236}
237