Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*	$NetBSD: gettext.c,v 1.3 2015/07/12 11:40:52 christos Exp $	*/

/*-
 * Copyright (c) 2015 William Orr <will@worrbase.com>
 * 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 <sys/cdefs.h>
__RCSID("$NetBSD: gettext.c,v 1.3 2015/07/12 11:40:52 christos Exp $");

#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <libintl.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>

static struct option longopts[] = {
	{ "help",       no_argument,        NULL,   'h' },
	{ "domain",	required_argument,  NULL,   'd' },
	{ NULL,         0,                  NULL,   '\0' },
};

static __dead void
usage(int exit_status)
{

	fprintf(stderr, "Usage: %s [-ehn] [[<textdomain>] <msgid>]\n",
	    getprogname());
	fprintf(stderr, "Usage: %s [-ehn] -d <textdomain> <msgid>\n",
	    getprogname());
	fprintf(stderr, "Usage: %s -s [<msgid>]...\n", getprogname());
	exit(exit_status);
}

static bool
expand(char *str)
{
	char *fp, *sp, ch, pl;
	bool nflag = false;

	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;
			}
			continue;
		}
		*sp++ = *fp++;
	}

	*sp = '\0';
	return nflag;
}

int
main(int argc, char **argv)
{
	char *msgdomain = NULL;
	char *msgdomaindir = NULL;
	char *translation = NULL;
	char *s;
	bool eflag = false;
	bool sflag = false;
	bool nflag = false;
	int ch;

	setlocale(LC_ALL, "");
	setprogname(argv[0]);

	while ((ch = getopt_long(argc, argv, "d:eEhnsV", longopts, NULL)) != -1)
	{
		switch (ch) {
		case 'd':
			msgdomain = estrdup(optarg);
			break;
		case 'E':
			/* GNU gettext compat */
			break;
		case 'e':
			eflag = true;
			break;
		case 'V':
		case 'h':
			free(msgdomain);
			usage(EXIT_SUCCESS);
			/* NOTREACHED */
		case 'n':
			nflag = true;
			break;
		case 's':
			sflag = true;
			break;
		default:
			free(msgdomain);
			usage(EXIT_FAILURE);
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 0) {
		free(msgdomain);
		warnx("missing msgid");
		usage(EXIT_FAILURE);
	}

	/* msgdomain can be passed as optional arg iff -s is not passed */
	if (!sflag) {
		if (argc == 2) {
			free(msgdomain);
			msgdomain = estrdup(argv[0]);

			argc -= 1;
			argv += 1;
		} else if (argc > 2) {
			warnx("too many arguments");
			usage(EXIT_FAILURE);
		}
	}

	/* msgdomain can be passed as env var */
	if (msgdomain == NULL) {
		if ((s = getenv("TEXTDOMAIN")) != NULL)
			msgdomain = estrdup(s);
	}

	if (msgdomain != NULL) {
		if ((s = getenv("TEXTDOMAINDIR")) != NULL)
			msgdomaindir = estrdup(s);
		if (msgdomaindir)
			bindtextdomain(msgdomain, msgdomaindir);
	}

	do {
		if (eflag)
			nflag |= 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;
}