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