Logo Search packages:      
Sourcecode: ksh version File versions

msgcpp.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 2000-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * C message catalog preprocessor
 */

static const char usage[] =
"[-?\n@(#)$Id: msgcpp (AT&T Research) 2002-03-11 $\n]"
USAGE_LICENSE
"[+NAME?msgcpp - C language message catalog preprocessor]"
"[+DESCRIPTION?\bmsgcpp\b is a C language message catalog preprocessor."
"     It accepts \bcpp\b(1) style options and arguments. \bmsgcpp\b"
"     preprocesses an input C source file and emits keyed lines to the"
"     output, usually for further processing by \bmsgcc\b(1). \bmsgcc\b"
"     output is in the \bgencat\b(1) syntax. Candidate message text is"
"     determined by arguments to the \bast\b \b<error.h>\b and"
"     \b<option.h>\b functions. The \bmsgcpp\b keyed output lines are:]{"
"     [+cmd \acommand\a?\acommand\a is a candidate for \b--??keys\b"
"           option string generation. Triggered by"
"           \bb_\b\acommand\a\b(int argc,\b in the input.]"
"     [+def \aname\a \astring\a?\aname\a is a candidate variable with"
"           string value \astring\a.]"
"     [+str \astring\a?\astring\a should be entered into the catalog.]"
"     [+var \aname\a?If \bdef\b \aname\a occurs then its \astring\a value"
"           should be entered into the catalog.]"
"     }"
"[+?The input source file is preprocessed with the \bpp:allpossible\b"
"     option on. This enables non-C semantics; all source should first"
"     be compiled error-free with a real compiler before running \bmsgcpp\b."
"     The following changes are enabled for the top level files (i.e.,"
"     included file behavior is not affected):]{"
"           [+(1)?All \b#if\b, \b#ifdef\b and \b#ifndef\b branches"
"                 are enabled.]"
"           [+(2)?The first definition for a macro is retained, even when"
"                 subsequent \b#define\b statements would normally"
"                 redefine the macro. \b#undef\b must be used to"
"                 redefine a macro.]"
"           [+(3)?Macro calls with an improper number of arguments are"
"                 silently ignored.]"
"           [+(4)?\b#include\b on non-existent headers are silently"
"                 ignored.]"
"           [+(5)?Invalid C source characters are silently ignored.]"
"     }"
"[+?\b\"msgcat.h\"\b is included if it exists. This file may contain macro"
"     definitions for functions that translate string arguments. If \afoo\a"
"     is a function that translates its string arguments then include the"
"     line \b#define \b\afoo\a\b _TRANSLATE_\b in \bmsgcat.h\b or specify"
"     the option \b-D\b\afoo\a\b=_TRANSLATE_\b. If \abar\a is a function"
"     that translates string arguments if the first argument is \bstderr\b"
"     then use either \b#define \b\abar\a\b _STDIO_\b or"
"     \b-D\b\abar\a\b=_STDIO_\b.]"
"[+?The macro \b_BLD_msgcat\b is defined to be \b1\b. As an alternative to"
"     \bmsgcat.h\b, \b_TRANSLATE_\b definitions could be placed inside"
"     \b#ifdef _BLD_msgcat\b ... \b#endif\b.]"

"\n"
"\n[ input [ output ] ]\n"
"\n"

"[+SEE ALSO?\bcc\b(1), \bcpp\b(1), \bgencat\b(1), \bmsggen\b(1),"
"     \bmsgcc\b(1), \bmsgcvt\b(1)]"
;

#include <ast.h>
#include <error.h>

#include "pp.h"
#include "ppkey.h"

#define T_STDERR  (T_KEYWORD+1)
#define T_STDIO         (T_KEYWORD+2)
#define T_TRANSLATE     (T_KEYWORD+3)

#define OMIT            "*@(\\[[-+]*\\?*\\]|\\@\\(#\\)|Copyright \\(c\\)|\\\\000|\\\\00[!0-9]|\\\\0[!0-9])*"

static struct ppkeyword keys[] =
{
      "char",           T_CHAR,
      "int",            T_INT,
      "sfstderr", T_STDERR,
      "stderr",   T_STDERR,
      "_STDIO_",  T_STDIO,
      "_TRANSLATE_",    T_TRANSLATE,
      0,          0
};

static int
msgppargs(char** argv, int last)
{
      for (;;)
      {
            switch (optget(argv, usage))
            {
            case 0:
                  break;
            case '?':
                  if (!last)
                  {
                        opt_info.again = 1;
                        return 1;
                  }
                  error(ERROR_USAGE|4, "%s", opt_info.arg);
                  break;
            case ':':
                  if (!last)
                  {
                        opt_info.again = 1;
                        return 1;
                  }
                  error(2, "%s", opt_info.arg);
                  continue;
            default:
                  if (!last)
                  {
                        opt_info.again = 1;
                        return 1;
                  }
                  continue;
            }
            break;
      }
      return argv[opt_info.index] != 0;
}

int
main(int argc, char** argv)
{
      register char*    s;
      register int      x;
      register int      c;
      Sfio_t*           tmp;

      NoP(argc);
      if (s = strrchr(*argv, '/'))
            s++;
      else
            s = *argv;
      error_info.id = s;
      ppop(PP_DEFAULT, PPDEFAULT);
      optjoin(argv, msgppargs, ppargs, NiL);
      if (strlen(s) >= 5 && *(s + 3) != 'c')
      {
            ppop(PP_PLUSPLUS, 1);
            ppop(PP_NOHASH, 1);
            ppop(PP_PROBE, "CC");
      }
      ppop(PP_SPACEOUT, 0);
      ppop(PP_COMPILE, keys);
      ppop(PP_OPTION, "allpossible");
      ppop(PP_OPTION, "catliteral");
      ppop(PP_OPTION, "modern");
      ppop(PP_OPTION, "readonly");
      ppop(PP_DEFINE, "_BLD_msgcat=1");
      ppop(PP_DEFINE, "const=");
      ppop(PP_DEFINE, "errorf=_TRANSLATE_");
      ppop(PP_DEFINE, "register=");
      ppop(PP_DEFINE, "sfstderr=sfstderr");
      ppop(PP_DEFINE, "stderr=stderr");
      ppop(PP_DEFINE, "_(m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "__(m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "gettxt(i,m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "gettext(m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "dgettext(d,m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "dcgettext(d,m,c)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "ERROR_catalog(m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "ERROR_dictionary(m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "ERROR_translate(l,i,c,m)=_TRANSLATE_(m)");
      ppop(PP_DEFINE, "error(l,f,...)=_TRANSLATE_(f)");
      ppop(PP_DEFINE, "errormsg(t,l,f,...)=_TRANSLATE_(f)");
      ppop(PP_DIRECTIVE, "include \"msgcat.h\"");
      ppop(PP_OPTION, "noreadonly");
      ppop(PP_INIT);
      if (!(tmp = sfstropen()))
            error(ERROR_SYSTEM|3, "out of space");
      x = 0;
      for (;;)
      {
            c = pplex();
      again:
            switch (c)
            {
            case 0:
                  break;
            case T_TRANSLATE:
                  switch (c = pplex())
                  {
                  case '(':
                        x = 1;
                        break;
                  case ')':
                        if ((c = pplex()) != '(')
                        {
                              x = 0;
                              goto again;
                        }
                        x = 1;
                        break;
                  default:
                        x = 0;
                        goto again;
                  }
                  continue;
            case '(':
                  if (x > 0)
                        x++;
                  continue;
            case ')':
                  if (x > 0)
                        x--;
                  continue;
            case T_STDIO:
                  if ((c = pplex()) != '(' || (c = pplex()) != T_STDERR || (c = pplex()) != ',')
                  {
                        x = 0;
                        goto again;
                  }
                  x = 1;
                  continue;
            case T_STRING:
                  if (x > 0 && !strmatch(pp.token, OMIT))
                        sfprintf(sfstdout, "str \"%s\"\n", pp.token);
                  continue;
            case T_ID:
                  s = pp.symbol->name;
                  if (x > 0)
                  {
                        if ((c = pplex()) == '+' && ppisinteger(c = pplex()))
                              sfprintf(sfstdout, "var %s %s\n", pp.token, s);
                        else
                              sfprintf(sfstdout, "var %s\n", s);
                  }
                  else if (s[0] == 'b' && s[1] == '_' && s[2])
                  {
                        if ((c = pplex()) == '(' && (c = pplex()) == T_INT && (c = pplex()) == T_ID && (c = pplex()) == ',' && (c = pplex()) == T_CHAR && (c = pplex()) == '*')
                              sfprintf(sfstdout, "cmd %s\n", s + 2);
                        else
                              goto again;
                  }
                  else
                  {
                        if ((c = pplex()) == '[')
                        {
                              if (ppisinteger(c = pplex()))
                                    c = pplex();
                              if (c != ']')
                                    goto again;
                              c = pplex();
                        }
                        if (c == '=' && (c = pplex()) == T_STRING && !strmatch(pp.token, OMIT))
                        {
                              sfprintf(sfstdout, "def %s \"%s\"\n", s, pp.token);
                              sfprintf(tmp, "#define %s \"%s\"\n", s, pp.token);
                              if (!(s = sfstruse(tmp)))
                                    error(ERROR_SYSTEM|3, "out of space");
                              ppinput(s, "string", 0);
                        }
                        else
                              goto again;
                  }
                  continue;
            default:
                  continue;
            }
            break;
      }
      ppop(PP_DONE);
      return error_info.errors != 0;
}

Generated by  Doxygen 1.6.0   Back to index