1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 2000-2010 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * C message catalog preprocessor
1N/A */
1N/A
1N/Astatic const char usage[] =
1N/A"[-?\n@(#)$Id: msgcpp (AT&T Research) 2002-03-11 $\n]"
1N/AUSAGE_LICENSE
1N/A"[+NAME?msgcpp - C language message catalog preprocessor]"
1N/A"[+DESCRIPTION?\bmsgcpp\b is a C language message catalog preprocessor."
1N/A" It accepts \bcpp\b(1) style options and arguments. \bmsgcpp\b"
1N/A" preprocesses an input C source file and emits keyed lines to the"
1N/A" output, usually for further processing by \bmsgcc\b(1). \bmsgcc\b"
1N/A" output is in the \bgencat\b(1) syntax. Candidate message text is"
1N/A" determined by arguments to the \bast\b \b<error.h>\b and"
1N/A" \b<option.h>\b functions. The \bmsgcpp\b keyed output lines are:]{"
1N/A" [+cmd \acommand\a?\acommand\a is a candidate for \b--??keys\b"
1N/A" option string generation. Triggered by"
1N/A" \bb_\b\acommand\a\b(int argc,\b in the input.]"
1N/A" [+def \aname\a \astring\a?\aname\a is a candidate variable with"
1N/A" string value \astring\a.]"
1N/A" [+str \astring\a?\astring\a should be entered into the catalog.]"
1N/A" [+var \aname\a?If \bdef\b \aname\a occurs then its \astring\a value"
1N/A" should be entered into the catalog.]"
1N/A" }"
1N/A"[+?The input source file is preprocessed with the \bpp:allpossible\b"
1N/A" option on. This enables non-C semantics; all source should first"
1N/A" be compiled error-free with a real compiler before running \bmsgcpp\b."
1N/A" The following changes are enabled for the top level files (i.e.,"
1N/A" included file behavior is not affected):]{"
1N/A" [+(1)?All \b#if\b, \b#ifdef\b and \b#ifndef\b branches"
1N/A" are enabled.]"
1N/A" [+(2)?The first definition for a macro is retained, even when"
1N/A" subsequent \b#define\b statements would normally"
1N/A" redefine the macro. \b#undef\b must be used to"
1N/A" redefine a macro.]"
1N/A" [+(3)?Macro calls with an improper number of arguments are"
1N/A" silently ignored.]"
1N/A" [+(4)?\b#include\b on non-existent headers are silently"
1N/A" ignored.]"
1N/A" [+(5)?Invalid C source characters are silently ignored.]"
1N/A" }"
1N/A"[+?\b\"msgcat.h\"\b is included if it exists. This file may contain macro"
1N/A" definitions for functions that translate string arguments. If \afoo\a"
1N/A" is a function that translates its string arguments then include the"
1N/A" line \b#define \b\afoo\a\b _TRANSLATE_\b in \bmsgcat.h\b or specify"
1N/A" the option \b-D\b\afoo\a\b=_TRANSLATE_\b. If \abar\a is a function"
1N/A" that translates string arguments if the first argument is \bstderr\b"
1N/A" then use either \b#define \b\abar\a\b _STDIO_\b or"
1N/A" \b-D\b\abar\a\b=_STDIO_\b.]"
1N/A"[+?The macro \b_BLD_msgcat\b is defined to be \b1\b. As an alternative to"
1N/A" \bmsgcat.h\b, \b_TRANSLATE_\b definitions could be placed inside"
1N/A" \b#ifdef _BLD_msgcat\b ... \b#endif\b.]"
1N/A
1N/A"\n"
1N/A"\n[ input [ output ] ]\n"
1N/A"\n"
1N/A
1N/A"[+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1),"
1N/A" \bmsgcc\b(1), \bmsgcvt\b(1)]"
1N/A;
1N/A
1N/A#include <ast.h>
1N/A#include <error.h>
1N/A
1N/A#include "pp.h"
1N/A#include "ppkey.h"
1N/A
1N/A#define T_STDERR (T_KEYWORD+1)
1N/A#define T_STDIO (T_KEYWORD+2)
1N/A#define T_TRANSLATE (T_KEYWORD+3)
1N/A
1N/A#define OMIT "*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\\\000|\\\\00[!0-9]|\\\\0[!0-9])*"
1N/A
1N/Astatic struct ppkeyword keys[] =
1N/A{
1N/A "char", T_CHAR,
1N/A "int", T_INT,
1N/A "sfstderr", T_STDERR,
1N/A "stderr", T_STDERR,
1N/A "_STDIO_", T_STDIO,
1N/A "_TRANSLATE_", T_TRANSLATE,
1N/A 0, 0
1N/A};
1N/A
1N/Astatic int
1N/Amsgppargs(char** argv, int last)
1N/A{
1N/A for (;;)
1N/A {
1N/A switch (optget(argv, usage))
1N/A {
1N/A case 0:
1N/A break;
1N/A case '?':
1N/A if (!last)
1N/A {
1N/A opt_info.again = 1;
1N/A return 1;
1N/A }
1N/A error(ERROR_USAGE|4, "%s", opt_info.arg);
1N/A break;
1N/A case ':':
1N/A if (!last)
1N/A {
1N/A opt_info.again = 1;
1N/A return 1;
1N/A }
1N/A error(2, "%s", opt_info.arg);
1N/A continue;
1N/A default:
1N/A if (!last)
1N/A {
1N/A opt_info.again = 1;
1N/A return 1;
1N/A }
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A return argv[opt_info.index] != 0;
1N/A}
1N/A
1N/Aint
1N/Amain(int argc, char** argv)
1N/A{
1N/A register char* s;
1N/A register int x;
1N/A register int c;
1N/A Sfio_t* tmp;
1N/A
1N/A NoP(argc);
1N/A if (s = strrchr(*argv, '/'))
1N/A s++;
1N/A else
1N/A s = *argv;
1N/A error_info.id = s;
1N/A ppop(PP_DEFAULT, PPDEFAULT);
1N/A optjoin(argv, msgppargs, ppargs, NiL);
1N/A if (strlen(s) >= 5 && *(s + 3) != 'c')
1N/A {
1N/A ppop(PP_PLUSPLUS, 1);
1N/A ppop(PP_NOHASH, 1);
1N/A ppop(PP_PROBE, "CC");
1N/A }
1N/A ppop(PP_SPACEOUT, 0);
1N/A ppop(PP_COMPILE, keys);
1N/A ppop(PP_OPTION, "allpossible");
1N/A ppop(PP_OPTION, "catliteral");
1N/A ppop(PP_OPTION, "modern");
1N/A ppop(PP_OPTION, "readonly");
1N/A ppop(PP_DEFINE, "_BLD_msgcat=1");
1N/A ppop(PP_DEFINE, "const=");
1N/A ppop(PP_DEFINE, "errorf=_TRANSLATE_");
1N/A ppop(PP_DEFINE, "register=");
1N/A ppop(PP_DEFINE, "sfstderr=sfstderr");
1N/A ppop(PP_DEFINE, "stderr=stderr");
1N/A ppop(PP_DEFINE, "_(m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "__(m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "gettxt(i,m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "gettext(m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "dgettext(d,m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "dcgettext(d,m,c)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "ERROR_catalog(m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "ERROR_dictionary(m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "ERROR_translate(l,i,c,m)=_TRANSLATE_(m)");
1N/A ppop(PP_DEFINE, "error(l,f,...)=_TRANSLATE_(f)");
1N/A ppop(PP_DEFINE, "errormsg(t,l,f,...)=_TRANSLATE_(f)");
1N/A ppop(PP_DIRECTIVE, "include \"msgcat.h\"");
1N/A ppop(PP_OPTION, "noreadonly");
1N/A ppop(PP_INIT);
1N/A if (!(tmp = sfstropen()))
1N/A error(ERROR_SYSTEM|3, "out of space");
1N/A x = 0;
1N/A for (;;)
1N/A {
1N/A c = pplex();
1N/A again:
1N/A switch (c)
1N/A {
1N/A case 0:
1N/A break;
1N/A case T_TRANSLATE:
1N/A switch (c = pplex())
1N/A {
1N/A case '(':
1N/A x = 1;
1N/A break;
1N/A case ')':
1N/A if ((c = pplex()) != '(')
1N/A {
1N/A x = 0;
1N/A goto again;
1N/A }
1N/A x = 1;
1N/A break;
1N/A default:
1N/A x = 0;
1N/A goto again;
1N/A }
1N/A continue;
1N/A case '(':
1N/A if (x > 0)
1N/A x++;
1N/A continue;
1N/A case ')':
1N/A if (x > 0)
1N/A x--;
1N/A continue;
1N/A case T_STDIO:
1N/A if ((c = pplex()) != '(' || (c = pplex()) != T_STDERR || (c = pplex()) != ',')
1N/A {
1N/A x = 0;
1N/A goto again;
1N/A }
1N/A x = 1;
1N/A continue;
1N/A case T_STRING:
1N/A if (x > 0 && !strmatch(pp.token, OMIT))
1N/A sfprintf(sfstdout, "str \"%s\"\n", pp.token);
1N/A continue;
1N/A case T_ID:
1N/A s = pp.symbol->name;
1N/A if (x > 0)
1N/A {
1N/A if ((c = pplex()) == '+' && ppisinteger(c = pplex()))
1N/A sfprintf(sfstdout, "var %s %s\n", pp.token, s);
1N/A else
1N/A sfprintf(sfstdout, "var %s\n", s);
1N/A }
1N/A else if (s[0] == 'b' && s[1] == '_' && s[2])
1N/A {
1N/A if ((c = pplex()) == '(' && (c = pplex()) == T_INT && (c = pplex()) == T_ID && (c = pplex()) == ',' && (c = pplex()) == T_CHAR && (c = pplex()) == '*')
1N/A sfprintf(sfstdout, "cmd %s\n", s + 2);
1N/A else
1N/A goto again;
1N/A }
1N/A else
1N/A {
1N/A if ((c = pplex()) == '[')
1N/A {
1N/A if (ppisinteger(c = pplex()))
1N/A c = pplex();
1N/A if (c != ']')
1N/A goto again;
1N/A c = pplex();
1N/A }
1N/A if (c == '=' && (c = pplex()) == T_STRING && !strmatch(pp.token, OMIT))
1N/A {
1N/A sfprintf(sfstdout, "def %s \"%s\"\n", s, pp.token);
1N/A sfprintf(tmp, "#define %s \"%s\"\n", s, pp.token);
1N/A if (!(s = sfstruse(tmp)))
1N/A error(ERROR_SYSTEM|3, "out of space");
1N/A ppinput(s, "string", 0);
1N/A }
1N/A else
1N/A goto again;
1N/A }
1N/A continue;
1N/A default:
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A ppop(PP_DONE);
1N/A return error_info.errors != 0;
1N/A}