1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*34f9b3eeSRoland Mainz * Copyright (c) 2000-2009 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril 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
msgppargs(char ** argv,int last)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
main(int argc,char ** argv)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