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