14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*10898Sroland.mainz@nrubsig.org * Copyright (c) 2000-2009 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * Glenn Fowler
234887Schin * AT&T Research
244887Schin *
254887Schin * C message catalog preprocessor
264887Schin */
274887Schin
284887Schin static const char usage[] =
294887Schin "[-?\n@(#)$Id: msgcpp (AT&T Research) 2002-03-11 $\n]"
304887Schin USAGE_LICENSE
314887Schin "[+NAME?msgcpp - C language message catalog preprocessor]"
324887Schin "[+DESCRIPTION?\bmsgcpp\b is a C language message catalog preprocessor."
334887Schin " It accepts \bcpp\b(1) style options and arguments. \bmsgcpp\b"
344887Schin " preprocesses an input C source file and emits keyed lines to the"
354887Schin " output, usually for further processing by \bmsgcc\b(1). \bmsgcc\b"
364887Schin " output is in the \bgencat\b(1) syntax. Candidate message text is"
374887Schin " determined by arguments to the \bast\b \b<error.h>\b and"
384887Schin " \b<option.h>\b functions. The \bmsgcpp\b keyed output lines are:]{"
394887Schin " [+cmd \acommand\a?\acommand\a is a candidate for \b--??keys\b"
404887Schin " option string generation. Triggered by"
414887Schin " \bb_\b\acommand\a\b(int argc,\b in the input.]"
424887Schin " [+def \aname\a \astring\a?\aname\a is a candidate variable with"
434887Schin " string value \astring\a.]"
444887Schin " [+str \astring\a?\astring\a should be entered into the catalog.]"
454887Schin " [+var \aname\a?If \bdef\b \aname\a occurs then its \astring\a value"
464887Schin " should be entered into the catalog.]"
474887Schin " }"
484887Schin "[+?The input source file is preprocessed with the \bpp:allpossible\b"
494887Schin " option on. This enables non-C semantics; all source should first"
504887Schin " be compiled error-free with a real compiler before running \bmsgcpp\b."
514887Schin " The following changes are enabled for the top level files (i.e.,"
524887Schin " included file behavior is not affected):]{"
534887Schin " [+(1)?All \b#if\b, \b#ifdef\b and \b#ifndef\b branches"
544887Schin " are enabled.]"
554887Schin " [+(2)?The first definition for a macro is retained, even when"
564887Schin " subsequent \b#define\b statements would normally"
574887Schin " redefine the macro. \b#undef\b must be used to"
584887Schin " redefine a macro.]"
594887Schin " [+(3)?Macro calls with an improper number of arguments are"
604887Schin " silently ignored.]"
614887Schin " [+(4)?\b#include\b on non-existent headers are silently"
624887Schin " ignored.]"
634887Schin " [+(5)?Invalid C source characters are silently ignored.]"
644887Schin " }"
654887Schin "[+?\b\"msgcat.h\"\b is included if it exists. This file may contain macro"
664887Schin " definitions for functions that translate string arguments. If \afoo\a"
674887Schin " is a function that translates its string arguments then include the"
684887Schin " line \b#define \b\afoo\a\b _TRANSLATE_\b in \bmsgcat.h\b or specify"
694887Schin " the option \b-D\b\afoo\a\b=_TRANSLATE_\b. If \abar\a is a function"
704887Schin " that translates string arguments if the first argument is \bstderr\b"
714887Schin " then use either \b#define \b\abar\a\b _STDIO_\b or"
724887Schin " \b-D\b\abar\a\b=_STDIO_\b.]"
734887Schin "[+?The macro \b_BLD_msgcat\b is defined to be \b1\b. As an alternative to"
744887Schin " \bmsgcat.h\b, \b_TRANSLATE_\b definitions could be placed inside"
754887Schin " \b#ifdef _BLD_msgcat\b ... \b#endif\b.]"
764887Schin
774887Schin "\n"
784887Schin "\n[ input [ output ] ]\n"
794887Schin "\n"
804887Schin
814887Schin "[+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1),"
824887Schin " \bmsgcc\b(1), \bmsgcvt\b(1)]"
834887Schin ;
844887Schin
854887Schin #include <ast.h>
864887Schin #include <error.h>
874887Schin
884887Schin #include "pp.h"
894887Schin #include "ppkey.h"
904887Schin
914887Schin #define T_STDERR (T_KEYWORD+1)
924887Schin #define T_STDIO (T_KEYWORD+2)
934887Schin #define T_TRANSLATE (T_KEYWORD+3)
944887Schin
954887Schin #define OMIT "*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\\\000|\\\\00[!0-9]|\\\\0[!0-9])*"
964887Schin
974887Schin static struct ppkeyword keys[] =
984887Schin {
994887Schin "char", T_CHAR,
1004887Schin "int", T_INT,
1014887Schin "sfstderr", T_STDERR,
1024887Schin "stderr", T_STDERR,
1034887Schin "_STDIO_", T_STDIO,
1044887Schin "_TRANSLATE_", T_TRANSLATE,
1054887Schin 0, 0
1064887Schin };
1074887Schin
1084887Schin static int
msgppargs(char ** argv,int last)1094887Schin msgppargs(char** argv, int last)
1104887Schin {
1114887Schin for (;;)
1124887Schin {
1134887Schin switch (optget(argv, usage))
1144887Schin {
1154887Schin case 0:
1164887Schin break;
1174887Schin case '?':
1184887Schin if (!last)
1194887Schin {
1204887Schin opt_info.again = 1;
1214887Schin return 1;
1224887Schin }
1234887Schin error(ERROR_USAGE|4, "%s", opt_info.arg);
1244887Schin break;
1254887Schin case ':':
1264887Schin if (!last)
1274887Schin {
1284887Schin opt_info.again = 1;
1294887Schin return 1;
1304887Schin }
1314887Schin error(2, "%s", opt_info.arg);
1324887Schin continue;
1334887Schin default:
1344887Schin if (!last)
1354887Schin {
1364887Schin opt_info.again = 1;
1374887Schin return 1;
1384887Schin }
1394887Schin continue;
1404887Schin }
1414887Schin break;
1424887Schin }
1434887Schin return argv[opt_info.index] != 0;
1444887Schin }
1454887Schin
1464887Schin int
main(int argc,char ** argv)1474887Schin main(int argc, char** argv)
1484887Schin {
1494887Schin register char* s;
1504887Schin register int x;
1514887Schin register int c;
1524887Schin Sfio_t* tmp;
1534887Schin
1544887Schin NoP(argc);
1554887Schin if (s = strrchr(*argv, '/'))
1564887Schin s++;
1574887Schin else
1584887Schin s = *argv;
1594887Schin error_info.id = s;
1604887Schin ppop(PP_DEFAULT, PPDEFAULT);
1614887Schin optjoin(argv, msgppargs, ppargs, NiL);
1624887Schin if (strlen(s) >= 5 && *(s + 3) != 'c')
1634887Schin {
1644887Schin ppop(PP_PLUSPLUS, 1);
1654887Schin ppop(PP_NOHASH, 1);
1664887Schin ppop(PP_PROBE, "CC");
1674887Schin }
1684887Schin ppop(PP_SPACEOUT, 0);
1694887Schin ppop(PP_COMPILE, keys);
1704887Schin ppop(PP_OPTION, "allpossible");
1714887Schin ppop(PP_OPTION, "catliteral");
1724887Schin ppop(PP_OPTION, "modern");
1734887Schin ppop(PP_OPTION, "readonly");
1744887Schin ppop(PP_DEFINE, "_BLD_msgcat=1");
1754887Schin ppop(PP_DEFINE, "const=");
1764887Schin ppop(PP_DEFINE, "errorf=_TRANSLATE_");
1774887Schin ppop(PP_DEFINE, "register=");
1784887Schin ppop(PP_DEFINE, "sfstderr=sfstderr");
1794887Schin ppop(PP_DEFINE, "stderr=stderr");
1804887Schin ppop(PP_DEFINE, "_(m)=_TRANSLATE_(m)");
1814887Schin ppop(PP_DEFINE, "__(m)=_TRANSLATE_(m)");
1824887Schin ppop(PP_DEFINE, "gettxt(i,m)=_TRANSLATE_(m)");
1834887Schin ppop(PP_DEFINE, "gettext(m)=_TRANSLATE_(m)");
1844887Schin ppop(PP_DEFINE, "dgettext(d,m)=_TRANSLATE_(m)");
1854887Schin ppop(PP_DEFINE, "dcgettext(d,m,c)=_TRANSLATE_(m)");
1864887Schin ppop(PP_DEFINE, "ERROR_catalog(m)=_TRANSLATE_(m)");
1874887Schin ppop(PP_DEFINE, "ERROR_dictionary(m)=_TRANSLATE_(m)");
1884887Schin ppop(PP_DEFINE, "ERROR_translate(l,i,c,m)=_TRANSLATE_(m)");
1894887Schin ppop(PP_DEFINE, "error(l,f,...)=_TRANSLATE_(f)");
1904887Schin ppop(PP_DEFINE, "errormsg(t,l,f,...)=_TRANSLATE_(f)");
1914887Schin ppop(PP_DIRECTIVE, "include \"msgcat.h\"");
1924887Schin ppop(PP_OPTION, "noreadonly");
1934887Schin ppop(PP_INIT);
1944887Schin if (!(tmp = sfstropen()))
1954887Schin error(ERROR_SYSTEM|3, "out of space");
1964887Schin x = 0;
1974887Schin for (;;)
1984887Schin {
1994887Schin c = pplex();
2004887Schin again:
2014887Schin switch (c)
2024887Schin {
2034887Schin case 0:
2044887Schin break;
2054887Schin case T_TRANSLATE:
2064887Schin switch (c = pplex())
2074887Schin {
2084887Schin case '(':
2094887Schin x = 1;
2104887Schin break;
2114887Schin case ')':
2124887Schin if ((c = pplex()) != '(')
2134887Schin {
2144887Schin x = 0;
2154887Schin goto again;
2164887Schin }
2174887Schin x = 1;
2184887Schin break;
2194887Schin default:
2204887Schin x = 0;
2214887Schin goto again;
2224887Schin }
2234887Schin continue;
2244887Schin case '(':
2254887Schin if (x > 0)
2264887Schin x++;
2274887Schin continue;
2284887Schin case ')':
2294887Schin if (x > 0)
2304887Schin x--;
2314887Schin continue;
2324887Schin case T_STDIO:
2334887Schin if ((c = pplex()) != '(' || (c = pplex()) != T_STDERR || (c = pplex()) != ',')
2344887Schin {
2354887Schin x = 0;
2364887Schin goto again;
2374887Schin }
2384887Schin x = 1;
2394887Schin continue;
2404887Schin case T_STRING:
2414887Schin if (x > 0 && !strmatch(pp.token, OMIT))
2424887Schin sfprintf(sfstdout, "str \"%s\"\n", pp.token);
2434887Schin continue;
2444887Schin case T_ID:
2454887Schin s = pp.symbol->name;
2464887Schin if (x > 0)
2474887Schin {
2484887Schin if ((c = pplex()) == '+' && ppisinteger(c = pplex()))
2494887Schin sfprintf(sfstdout, "var %s %s\n", pp.token, s);
2504887Schin else
2514887Schin sfprintf(sfstdout, "var %s\n", s);
2524887Schin }
2534887Schin else if (s[0] == 'b' && s[1] == '_' && s[2])
2544887Schin {
2554887Schin if ((c = pplex()) == '(' && (c = pplex()) == T_INT && (c = pplex()) == T_ID && (c = pplex()) == ',' && (c = pplex()) == T_CHAR && (c = pplex()) == '*')
2564887Schin sfprintf(sfstdout, "cmd %s\n", s + 2);
2574887Schin else
2584887Schin goto again;
2594887Schin }
2604887Schin else
2614887Schin {
2624887Schin if ((c = pplex()) == '[')
2634887Schin {
2644887Schin if (ppisinteger(c = pplex()))
2654887Schin c = pplex();
2664887Schin if (c != ']')
2674887Schin goto again;
2684887Schin c = pplex();
2694887Schin }
2704887Schin if (c == '=' && (c = pplex()) == T_STRING && !strmatch(pp.token, OMIT))
2714887Schin {
2724887Schin sfprintf(sfstdout, "def %s \"%s\"\n", s, pp.token);
2734887Schin sfprintf(tmp, "#define %s \"%s\"\n", s, pp.token);
2744887Schin if (!(s = sfstruse(tmp)))
2754887Schin error(ERROR_SYSTEM|3, "out of space");
2764887Schin ppinput(s, "string", 0);
2774887Schin }
2784887Schin else
2794887Schin goto again;
2804887Schin }
2814887Schin continue;
2824887Schin default:
2834887Schin continue;
2844887Schin }
2854887Schin break;
2864887Schin }
2874887Schin ppop(PP_DONE);
2884887Schin return error_info.errors != 0;
2894887Schin }
290