1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 2000-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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