1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 2000-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18da2e3ebdSchin * * 19da2e3ebdSchin ***********************************************************************/ 20da2e3ebdSchin #pragma prototyped 21da2e3ebdSchin /* 22da2e3ebdSchin * Glenn Fowler 23da2e3ebdSchin * AT&T Research 24da2e3ebdSchin * 25da2e3ebdSchin * C message catalog preprocessor 26da2e3ebdSchin */ 27da2e3ebdSchin 28da2e3ebdSchin static const char usage[] = 29da2e3ebdSchin "[-?\n@(#)$Id: msgcpp (AT&T Research) 2002-03-11 $\n]" 30da2e3ebdSchin USAGE_LICENSE 31da2e3ebdSchin "[+NAME?msgcpp - C language message catalog preprocessor]" 32da2e3ebdSchin "[+DESCRIPTION?\bmsgcpp\b is a C language message catalog preprocessor." 33da2e3ebdSchin " It accepts \bcpp\b(1) style options and arguments. \bmsgcpp\b" 34da2e3ebdSchin " preprocesses an input C source file and emits keyed lines to the" 35da2e3ebdSchin " output, usually for further processing by \bmsgcc\b(1). \bmsgcc\b" 36da2e3ebdSchin " output is in the \bgencat\b(1) syntax. Candidate message text is" 37da2e3ebdSchin " determined by arguments to the \bast\b \b<error.h>\b and" 38da2e3ebdSchin " \b<option.h>\b functions. The \bmsgcpp\b keyed output lines are:]{" 39da2e3ebdSchin " [+cmd \acommand\a?\acommand\a is a candidate for \b--??keys\b" 40da2e3ebdSchin " option string generation. Triggered by" 41da2e3ebdSchin " \bb_\b\acommand\a\b(int argc,\b in the input.]" 42da2e3ebdSchin " [+def \aname\a \astring\a?\aname\a is a candidate variable with" 43da2e3ebdSchin " string value \astring\a.]" 44da2e3ebdSchin " [+str \astring\a?\astring\a should be entered into the catalog.]" 45da2e3ebdSchin " [+var \aname\a?If \bdef\b \aname\a occurs then its \astring\a value" 46da2e3ebdSchin " should be entered into the catalog.]" 47da2e3ebdSchin " }" 48da2e3ebdSchin "[+?The input source file is preprocessed with the \bpp:allpossible\b" 49da2e3ebdSchin " option on. This enables non-C semantics; all source should first" 50da2e3ebdSchin " be compiled error-free with a real compiler before running \bmsgcpp\b." 51da2e3ebdSchin " The following changes are enabled for the top level files (i.e.," 52da2e3ebdSchin " included file behavior is not affected):]{" 53da2e3ebdSchin " [+(1)?All \b#if\b, \b#ifdef\b and \b#ifndef\b branches" 54da2e3ebdSchin " are enabled.]" 55da2e3ebdSchin " [+(2)?The first definition for a macro is retained, even when" 56da2e3ebdSchin " subsequent \b#define\b statements would normally" 57da2e3ebdSchin " redefine the macro. \b#undef\b must be used to" 58da2e3ebdSchin " redefine a macro.]" 59da2e3ebdSchin " [+(3)?Macro calls with an improper number of arguments are" 60da2e3ebdSchin " silently ignored.]" 61da2e3ebdSchin " [+(4)?\b#include\b on non-existent headers are silently" 62da2e3ebdSchin " ignored.]" 63da2e3ebdSchin " [+(5)?Invalid C source characters are silently ignored.]" 64da2e3ebdSchin " }" 65da2e3ebdSchin "[+?\b\"msgcat.h\"\b is included if it exists. This file may contain macro" 66da2e3ebdSchin " definitions for functions that translate string arguments. If \afoo\a" 67da2e3ebdSchin " is a function that translates its string arguments then include the" 68da2e3ebdSchin " line \b#define \b\afoo\a\b _TRANSLATE_\b in \bmsgcat.h\b or specify" 69da2e3ebdSchin " the option \b-D\b\afoo\a\b=_TRANSLATE_\b. If \abar\a is a function" 70da2e3ebdSchin " that translates string arguments if the first argument is \bstderr\b" 71da2e3ebdSchin " then use either \b#define \b\abar\a\b _STDIO_\b or" 72da2e3ebdSchin " \b-D\b\abar\a\b=_STDIO_\b.]" 73da2e3ebdSchin "[+?The macro \b_BLD_msgcat\b is defined to be \b1\b. As an alternative to" 74da2e3ebdSchin " \bmsgcat.h\b, \b_TRANSLATE_\b definitions could be placed inside" 75da2e3ebdSchin " \b#ifdef _BLD_msgcat\b ... \b#endif\b.]" 76da2e3ebdSchin 77da2e3ebdSchin "\n" 78da2e3ebdSchin "\n[ input [ output ] ]\n" 79da2e3ebdSchin "\n" 80da2e3ebdSchin 81da2e3ebdSchin "[+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1)," 82da2e3ebdSchin " \bmsgcc\b(1), \bmsgcvt\b(1)]" 83da2e3ebdSchin ; 84da2e3ebdSchin 85da2e3ebdSchin #include <ast.h> 86da2e3ebdSchin #include <error.h> 87da2e3ebdSchin 88da2e3ebdSchin #include "pp.h" 89da2e3ebdSchin #include "ppkey.h" 90da2e3ebdSchin 91da2e3ebdSchin #define T_STDERR (T_KEYWORD+1) 92da2e3ebdSchin #define T_STDIO (T_KEYWORD+2) 93da2e3ebdSchin #define T_TRANSLATE (T_KEYWORD+3) 94da2e3ebdSchin 95da2e3ebdSchin #define OMIT "*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\\\000|\\\\00[!0-9]|\\\\0[!0-9])*" 96da2e3ebdSchin 97da2e3ebdSchin static struct ppkeyword keys[] = 98da2e3ebdSchin { 99da2e3ebdSchin "char", T_CHAR, 100da2e3ebdSchin "int", T_INT, 101da2e3ebdSchin "sfstderr", T_STDERR, 102da2e3ebdSchin "stderr", T_STDERR, 103da2e3ebdSchin "_STDIO_", T_STDIO, 104da2e3ebdSchin "_TRANSLATE_", T_TRANSLATE, 105da2e3ebdSchin 0, 0 106da2e3ebdSchin }; 107da2e3ebdSchin 108da2e3ebdSchin static int 109da2e3ebdSchin msgppargs(char** argv, int last) 110da2e3ebdSchin { 111da2e3ebdSchin for (;;) 112da2e3ebdSchin { 113da2e3ebdSchin switch (optget(argv, usage)) 114da2e3ebdSchin { 115da2e3ebdSchin case 0: 116da2e3ebdSchin break; 117da2e3ebdSchin case '?': 118da2e3ebdSchin if (!last) 119da2e3ebdSchin { 120da2e3ebdSchin opt_info.again = 1; 121da2e3ebdSchin return 1; 122da2e3ebdSchin } 123da2e3ebdSchin error(ERROR_USAGE|4, "%s", opt_info.arg); 124da2e3ebdSchin break; 125da2e3ebdSchin case ':': 126da2e3ebdSchin if (!last) 127da2e3ebdSchin { 128da2e3ebdSchin opt_info.again = 1; 129da2e3ebdSchin return 1; 130da2e3ebdSchin } 131da2e3ebdSchin error(2, "%s", opt_info.arg); 132da2e3ebdSchin continue; 133da2e3ebdSchin default: 134da2e3ebdSchin if (!last) 135da2e3ebdSchin { 136da2e3ebdSchin opt_info.again = 1; 137da2e3ebdSchin return 1; 138da2e3ebdSchin } 139da2e3ebdSchin continue; 140da2e3ebdSchin } 141da2e3ebdSchin break; 142da2e3ebdSchin } 143da2e3ebdSchin return argv[opt_info.index] != 0; 144da2e3ebdSchin } 145da2e3ebdSchin 146da2e3ebdSchin int 147da2e3ebdSchin main(int argc, char** argv) 148da2e3ebdSchin { 149da2e3ebdSchin register char* s; 150da2e3ebdSchin register int x; 151da2e3ebdSchin register int c; 152da2e3ebdSchin Sfio_t* tmp; 153da2e3ebdSchin 154da2e3ebdSchin NoP(argc); 155da2e3ebdSchin if (s = strrchr(*argv, '/')) 156da2e3ebdSchin s++; 157da2e3ebdSchin else 158da2e3ebdSchin s = *argv; 159da2e3ebdSchin error_info.id = s; 160da2e3ebdSchin ppop(PP_DEFAULT, PPDEFAULT); 161da2e3ebdSchin optjoin(argv, msgppargs, ppargs, NiL); 162da2e3ebdSchin if (strlen(s) >= 5 && *(s + 3) != 'c') 163da2e3ebdSchin { 164da2e3ebdSchin ppop(PP_PLUSPLUS, 1); 165da2e3ebdSchin ppop(PP_NOHASH, 1); 166da2e3ebdSchin ppop(PP_PROBE, "CC"); 167da2e3ebdSchin } 168da2e3ebdSchin ppop(PP_SPACEOUT, 0); 169da2e3ebdSchin ppop(PP_COMPILE, keys); 170da2e3ebdSchin ppop(PP_OPTION, "allpossible"); 171da2e3ebdSchin ppop(PP_OPTION, "catliteral"); 172da2e3ebdSchin ppop(PP_OPTION, "modern"); 173da2e3ebdSchin ppop(PP_OPTION, "readonly"); 174da2e3ebdSchin ppop(PP_DEFINE, "_BLD_msgcat=1"); 175da2e3ebdSchin ppop(PP_DEFINE, "const="); 176da2e3ebdSchin ppop(PP_DEFINE, "errorf=_TRANSLATE_"); 177da2e3ebdSchin ppop(PP_DEFINE, "register="); 178da2e3ebdSchin ppop(PP_DEFINE, "sfstderr=sfstderr"); 179da2e3ebdSchin ppop(PP_DEFINE, "stderr=stderr"); 180da2e3ebdSchin ppop(PP_DEFINE, "_(m)=_TRANSLATE_(m)"); 181da2e3ebdSchin ppop(PP_DEFINE, "__(m)=_TRANSLATE_(m)"); 182da2e3ebdSchin ppop(PP_DEFINE, "gettxt(i,m)=_TRANSLATE_(m)"); 183da2e3ebdSchin ppop(PP_DEFINE, "gettext(m)=_TRANSLATE_(m)"); 184da2e3ebdSchin ppop(PP_DEFINE, "dgettext(d,m)=_TRANSLATE_(m)"); 185da2e3ebdSchin ppop(PP_DEFINE, "dcgettext(d,m,c)=_TRANSLATE_(m)"); 186da2e3ebdSchin ppop(PP_DEFINE, "ERROR_catalog(m)=_TRANSLATE_(m)"); 187da2e3ebdSchin ppop(PP_DEFINE, "ERROR_dictionary(m)=_TRANSLATE_(m)"); 188da2e3ebdSchin ppop(PP_DEFINE, "ERROR_translate(l,i,c,m)=_TRANSLATE_(m)"); 189da2e3ebdSchin ppop(PP_DEFINE, "error(l,f,...)=_TRANSLATE_(f)"); 190da2e3ebdSchin ppop(PP_DEFINE, "errormsg(t,l,f,...)=_TRANSLATE_(f)"); 191da2e3ebdSchin ppop(PP_DIRECTIVE, "include \"msgcat.h\""); 192da2e3ebdSchin ppop(PP_OPTION, "noreadonly"); 193da2e3ebdSchin ppop(PP_INIT); 194da2e3ebdSchin if (!(tmp = sfstropen())) 195da2e3ebdSchin error(ERROR_SYSTEM|3, "out of space"); 196da2e3ebdSchin x = 0; 197da2e3ebdSchin for (;;) 198da2e3ebdSchin { 199da2e3ebdSchin c = pplex(); 200da2e3ebdSchin again: 201da2e3ebdSchin switch (c) 202da2e3ebdSchin { 203da2e3ebdSchin case 0: 204da2e3ebdSchin break; 205da2e3ebdSchin case T_TRANSLATE: 206da2e3ebdSchin switch (c = pplex()) 207da2e3ebdSchin { 208da2e3ebdSchin case '(': 209da2e3ebdSchin x = 1; 210da2e3ebdSchin break; 211da2e3ebdSchin case ')': 212da2e3ebdSchin if ((c = pplex()) != '(') 213da2e3ebdSchin { 214da2e3ebdSchin x = 0; 215da2e3ebdSchin goto again; 216da2e3ebdSchin } 217da2e3ebdSchin x = 1; 218da2e3ebdSchin break; 219da2e3ebdSchin default: 220da2e3ebdSchin x = 0; 221da2e3ebdSchin goto again; 222da2e3ebdSchin } 223da2e3ebdSchin continue; 224da2e3ebdSchin case '(': 225da2e3ebdSchin if (x > 0) 226da2e3ebdSchin x++; 227da2e3ebdSchin continue; 228da2e3ebdSchin case ')': 229da2e3ebdSchin if (x > 0) 230da2e3ebdSchin x--; 231da2e3ebdSchin continue; 232da2e3ebdSchin case T_STDIO: 233da2e3ebdSchin if ((c = pplex()) != '(' || (c = pplex()) != T_STDERR || (c = pplex()) != ',') 234da2e3ebdSchin { 235da2e3ebdSchin x = 0; 236da2e3ebdSchin goto again; 237da2e3ebdSchin } 238da2e3ebdSchin x = 1; 239da2e3ebdSchin continue; 240da2e3ebdSchin case T_STRING: 241da2e3ebdSchin if (x > 0 && !strmatch(pp.token, OMIT)) 242da2e3ebdSchin sfprintf(sfstdout, "str \"%s\"\n", pp.token); 243da2e3ebdSchin continue; 244da2e3ebdSchin case T_ID: 245da2e3ebdSchin s = pp.symbol->name; 246da2e3ebdSchin if (x > 0) 247da2e3ebdSchin { 248da2e3ebdSchin if ((c = pplex()) == '+' && ppisinteger(c = pplex())) 249da2e3ebdSchin sfprintf(sfstdout, "var %s %s\n", pp.token, s); 250da2e3ebdSchin else 251da2e3ebdSchin sfprintf(sfstdout, "var %s\n", s); 252da2e3ebdSchin } 253da2e3ebdSchin else if (s[0] == 'b' && s[1] == '_' && s[2]) 254da2e3ebdSchin { 255da2e3ebdSchin if ((c = pplex()) == '(' && (c = pplex()) == T_INT && (c = pplex()) == T_ID && (c = pplex()) == ',' && (c = pplex()) == T_CHAR && (c = pplex()) == '*') 256da2e3ebdSchin sfprintf(sfstdout, "cmd %s\n", s + 2); 257da2e3ebdSchin else 258da2e3ebdSchin goto again; 259da2e3ebdSchin } 260da2e3ebdSchin else 261da2e3ebdSchin { 262da2e3ebdSchin if ((c = pplex()) == '[') 263da2e3ebdSchin { 264da2e3ebdSchin if (ppisinteger(c = pplex())) 265da2e3ebdSchin c = pplex(); 266da2e3ebdSchin if (c != ']') 267da2e3ebdSchin goto again; 268da2e3ebdSchin c = pplex(); 269da2e3ebdSchin } 270da2e3ebdSchin if (c == '=' && (c = pplex()) == T_STRING && !strmatch(pp.token, OMIT)) 271da2e3ebdSchin { 272da2e3ebdSchin sfprintf(sfstdout, "def %s \"%s\"\n", s, pp.token); 273da2e3ebdSchin sfprintf(tmp, "#define %s \"%s\"\n", s, pp.token); 274da2e3ebdSchin if (!(s = sfstruse(tmp))) 275da2e3ebdSchin error(ERROR_SYSTEM|3, "out of space"); 276da2e3ebdSchin ppinput(s, "string", 0); 277da2e3ebdSchin } 278da2e3ebdSchin else 279da2e3ebdSchin goto again; 280da2e3ebdSchin } 281da2e3ebdSchin continue; 282da2e3ebdSchin default: 283da2e3ebdSchin continue; 284da2e3ebdSchin } 285da2e3ebdSchin break; 286da2e3ebdSchin } 287da2e3ebdSchin ppop(PP_DONE); 288da2e3ebdSchin return error_info.errors != 0; 289da2e3ebdSchin } 290