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