Add a gettext implementation from William Orr.

This commit is contained in:
christos 2015-06-03 14:32:16 +00:00
parent 4c4ecb7844
commit c3b6f86ce5
4 changed files with 339 additions and 2 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.220 2015/03/02 21:54:13 christos Exp $ # $NetBSD: Makefile,v 1.221 2015/06/03 14:32:16 christos Exp $
# from: @(#)Makefile 8.3 (Berkeley) 1/7/94 # from: @(#)Makefile 8.3 (Berkeley) 1/7/94
.include <bsd.own.mk> .include <bsd.own.mk>
@ -12,7 +12,7 @@ SUBDIR= apply asa at audio audiocfg \
eject elf2aout elf2ecoff env error expand extattr \ eject elf2aout elf2ecoff env error expand extattr \
false fdformat fgen fincore find finger flock fmt fold fpr from \ false fdformat fgen fincore find finger flock fmt fold fpr from \
fsplit fstat ftp gcore genassym gencat getaddrinfo getconf getent \ fsplit fstat ftp gcore genassym gencat getaddrinfo getconf getent \
getopt gprof \ getopt gettext gprof \
head hexdump iconv id indent infocmp innetgr ipcrm ipcs join jot \ head hexdump iconv id indent infocmp innetgr ipcrm ipcs join jot \
kdump ktrace ktruss lam last lastcomm ldd leave \ kdump ktrace ktruss lam last lastcomm ldd leave \
locale locate lock logger login logname look lorder m4 \ locale locate lock logger login logname look lorder m4 \

10
usr.bin/gettext/Makefile Normal file
View File

@ -0,0 +1,10 @@
# $NetBSD: Makefile,v 1.1 2015/06/03 14:32:17 christos Exp $
.include <bsd.own.mk>
PROG= gettext
LDADD+= -lintl -lutil
DPADD+= ${LIBINTL} ${LIBUTIL}
.include <bsd.prog.mk>

104
usr.bin/gettext/gettext.1 Normal file
View File

@ -0,0 +1,104 @@
.\" $NetBSD: gettext.1,v 1.1 2015/06/03 14:32:17 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.
.\"
.Dd June 3, 2015
.Dt GETTEXT 1
.Os
.Sh NAME
.Nm gettext
.Nd message translation front-end
.Sh SYNOPSIS
.Nm
.Op Fl h
.Nm
.Op Fl en
.Op Ar textdomain
.Ar msgid
.Nm
.Fl s
.Op Fl n
.Op Ar msgid...
.Sh DESCRIPTION
.Nm
attempts to translate a given
.Ar msgid
into the locale-specific string as determined by the environment.
If a translation file is not found, or a translation for the given
.Ar msgid
is not found, the original string will be echoed.
.Pp
If the
.Ar textdomain
is not provided as an argument, the
.Ev textdomain
environment variable will be consulted instead.
.Pp
By default
.Nm
will look for message catalogs in
.Pa /usr/share/locale .
If the environment variable
.Ev TEXTDOMAINDIR
is defined, then that will override the default location.
.Pp
The following flags are available:
.Bl -tag -width Ds
.It Fl e
Interpret backslash escape sequences prior to translation.
.It Fl h
Print the usage information
.It Fl n
If
.Fl s
is used, do not add the trailing newline. If
.Fl s
is not provided, this flag will do nothing.
.It Fl s
Act similarly to
.Xr echo 1 .
All
.Ar msgid
arguments will be translated, and a newline will be appended to the output
string.
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It Ev TEXTDOMAIN
The domain to use when looking up
.Ar msgids
.It Ev TEXTDOMAINDIR
The location of message catalogs to use, overriding
.Pa /usr/share/locale
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
.Bd -literal -offset indent
$ LANG=es gettext grep 'writing output'
escribiendo el resultado
.Ed
.Sh SEE ALSO
.Xr gettext 3
.Xr echo 1
.Xr environ 7

223
usr.bin/gettext/gettext.c Normal file
View File

@ -0,0 +1,223 @@
/* $NetBSD: gettext.c,v 1.1 2015/06/03 14:32:17 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.1 2015/06/03 14:32:17 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 __dead void
usage(int exit_status)
{
fprintf(stderr, "Usage: %s [-ehn] [[<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;
}
}
*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(argc, argv, "d:EehnsV")) != -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);
errx(EXIT_FAILURE, "missing msgid");
}
/* 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)
errx(EXIT_FAILURE, "too many arguments");
}
/* 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;
}