home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gettext-0.10.24-src.tgz / tar.out / fsf / gettext / src / po-lex.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  11KB  |  529 lines

  1. /* GNU gettext - internationalization aids
  2.    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
  3.  
  4.    This file was written by Peter Miller <pmiller@agso.gov.au>
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  19.  
  20.  
  21. #ifdef HAVE_CONFIG_H
  22. # include "config.h"
  23. #endif
  24.  
  25. #include <ctype.h>
  26. #include <errno.h>
  27. #include <stdio.h>
  28. #include <sys/types.h>
  29.  
  30. #include <libintl.h>
  31. #define _(str) gettext(str)
  32.  
  33. #if HAVE_VPRINTF || HAVE_DOPRNT
  34. # if __STDC__
  35. #  include <stdarg.h>
  36. #  define VA_START(args, lastarg) va_start(args, lastarg)
  37. # else
  38. #  include <varargs.h>
  39. #  define VA_START(args, lastarg) va_start(args)
  40. # endif
  41. #else
  42. # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
  43. # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
  44. #endif
  45.  
  46. #include "po-lex.h"
  47. #include "po-gram.h"
  48. #include "system.h"
  49. #include "error.h"
  50. #include "po-gram.gen.h"
  51.  
  52.  
  53. static FILE *fp;
  54. lex_pos_ty gram_pos;
  55. size_t gram_max_allowed_errors = 20;
  56. static int pass_comments = 0;
  57. static int pass_obsolete_entries = 0;
  58.  
  59.  
  60. /* Prototypes for local functions.  */
  61. static int lex_getc PARAMS ((void));
  62. static void lex_ungetc PARAMS ((int __ch));
  63. static int keyword_p PARAMS ((char *__s));
  64. static int control_sequence PARAMS ((void));
  65.  
  66.  
  67. void
  68. lex_open (fname)
  69.      const char *fname;
  70. {
  71.   fp = open_po_file (fname, &gram_pos.file_name);
  72.   if (!fp)
  73.     error (EXIT_FAILURE, errno,
  74.        _("error while opening \"%s\" for reading"), fname);
  75.  
  76.   gram_pos.line_number = 1;
  77. }
  78.  
  79.  
  80. void
  81. lex_close ()
  82. {
  83.   if (error_message_count > 0)
  84.     error (EXIT_FAILURE, 0, _("found %d fatal errors"), error_message_count);
  85.  
  86.   if (fp != stdin)
  87.     fclose (fp);
  88.   fp = NULL;
  89.   gram_pos.file_name = 0;
  90.   gram_pos.line_number = 0;
  91.   error_message_count = 0;
  92. }
  93.  
  94.  
  95. #if !__STDC__ || !defined __GNUC__ || __GNUC__ == 1
  96. /* VARARGS1 */
  97. void
  98. # if defined VA_START && __STDC__
  99. po_gram_error (const char *fmt, ...)
  100. # else
  101. po_gram_error (fmt, va_alist)
  102.      const char *fmt;
  103.      va_dcl
  104. # endif
  105. {
  106. # ifdef VA_START
  107.   va_list ap;
  108.   char *buffer;
  109.  
  110.   VA_START (ap, fmt);
  111.  
  112.   vasprintf (&buffer, fmt, ap);
  113.   va_end (ap);
  114.   error_at_line (0, 0, gram_pos.file_name, gram_pos.line_number, "%s", buffer);
  115. # else
  116.   error_at_line (0, 0, gram_pos.file_name, gram_pos.line_number, fmt,
  117.          a1, a2, a3, a4, a5, a6, a7, a8);
  118. # endif
  119.  
  120.   if (error_message_count >= gram_max_allowed_errors)
  121.     error (1, 0, _("too many errors, aborting"));
  122. }
  123.  
  124.  
  125. /* VARARGS2 */
  126. void
  127. # if defined VA_START && __STDC__
  128. gram_error_at_line (const lex_pos_ty *pp, const char *fmt, ...)
  129. # else
  130. gram_error_at_line (pp, fmt, va_alist)
  131.      const lex_pos_ty *pp;
  132.      const char *fmt;
  133.      va_dcl
  134. # endif
  135. {
  136. # ifdef VA_START
  137.   va_list ap;
  138.   char *buffer;
  139.  
  140.   VA_START (ap, fmt);
  141.  
  142.   vasprintf (&buffer, fmt, ap);
  143.   va_end (ap);
  144.   error_at_line (0, 0, pp->file_name, pp->line_number, "%s", buffer);
  145. # else
  146.   error_at_line (0, 0, pp->file_name, pp->line_number, fmt,
  147.          a1, a2, a3, a4, a5, a6, a7, a8);
  148. # endif
  149.  
  150.   if (*fmt != '.' && error_message_count >= gram_max_allowed_errors)
  151.     error (1, 0, _("too many errors, aborting"));
  152. }
  153. #endif
  154.  
  155.  
  156. static int
  157. lex_getc ()
  158. {
  159.   int c;
  160.  
  161.   for (;;)
  162.     {
  163.       c = getc (fp);
  164.       switch (c)
  165.     {
  166.     case EOF:
  167.       if (ferror (fp))
  168.         error (EXIT_FAILURE, errno,    _("error while reading \"%s\""),
  169.            gram_pos.file_name);
  170.       return EOF;
  171.  
  172.     case '\n':
  173.       ++gram_pos.line_number;
  174.       return '\n';
  175.  
  176.     case '\\':
  177.       c = getc (fp);
  178.       if (c != '\n')
  179.         {
  180.           if (c != EOF)
  181.         ungetc (c, fp);
  182.           return '\\';
  183.         }
  184.       ++gram_pos.line_number;
  185.       break;
  186.  
  187.     default:
  188.       return c;
  189.     }
  190.     }
  191. }
  192.  
  193.  
  194. static void
  195. lex_ungetc (c)
  196.      int c;
  197. {
  198.   switch (c)
  199.     {
  200.     case EOF:
  201.       break;
  202.  
  203.     case '\n':
  204.       --gram_pos.line_number;
  205.       /* FALLTHROUGH */
  206.  
  207.     default:
  208.       ungetc (c, fp);
  209.       break;
  210.     }
  211. }
  212.  
  213.  
  214. static int
  215. keyword_p (s)
  216.      char *s;
  217. {
  218.   if (!strcmp (s, "domain"))
  219.     return DOMAIN;
  220.   if (!strcmp (s, "msgid"))
  221.     return MSGID;
  222.   if (!strcmp (s, "msgstr"))
  223.     return MSGSTR;
  224.   po_gram_error (_("keyword \"%s\" unknown"), s);
  225.   return NAME;
  226. }
  227.  
  228.  
  229. static int
  230. control_sequence ()
  231. {
  232.   int c;
  233.   int val;
  234.   int max;
  235.  
  236.   c = lex_getc ();
  237.   switch (c)
  238.     {
  239.     case 'n':
  240.       return '\n';
  241.  
  242.     case 't':
  243.       return '\t';
  244.  
  245.     case 'b':
  246.       return '\b';
  247.  
  248.     case 'r':
  249.       return '\r';
  250.  
  251.     case 'f':
  252.       return '\f';
  253.  
  254.     case '\\':
  255.     case '"':
  256.       return c;
  257.  
  258.     case '0': case '1': case '2': case '3':
  259.     case '4': case '5': case '6': case '7':
  260.       val = 0;
  261.       for (max = 0; max < 3; ++max)
  262.     {
  263.       /* Warning: not portable, can't depend on '0'..'7' ordering.  */
  264.       val = val * 8 + c - '0';
  265.       c = lex_getc ();
  266.       switch (c)
  267.         {
  268.         case '0': case '1': case '2': case '3':
  269.         case '4': case '5': case '6': case '7':
  270.           continue;
  271.  
  272.         default:
  273.           break;
  274.         }
  275.       break;
  276.     }
  277.       lex_ungetc (c);
  278.       return val;
  279.  
  280.     case 'x': case 'X':
  281.       c = lex_getc ();
  282.       if (c == EOF || !isxdigit (c))
  283.     break;
  284.  
  285.       val = 0;
  286.       for (;;)
  287.     {
  288.       val *= 16;
  289.       if (isdigit (c))
  290.         /* Warning: not portable, can't depend on '0'..'9' ordering */
  291.         val += c - '0';
  292.       else if (isupper (c))
  293.         /* Warning: not portable, can't depend on 'A'..'F' ordering */
  294.         val += c - 'A' + 10;
  295.       else
  296.         /* Warning: not portable, can't depend on 'a'..'f' ordering */
  297.         val += c - 'a' + 10;
  298.  
  299.       c = lex_getc ();
  300.       switch (c)
  301.         {
  302.         case '0': case '1': case '2': case '3': case '4':
  303.         case '5': case '6': case '7': case '8': case '9':
  304.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  305.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  306.           continue;
  307.  
  308.         default:
  309.           break;
  310.         }
  311.       break;
  312.     }
  313.       return val;
  314.     }
  315.   po_gram_error (_("illegal control sequence"));
  316.   return ' ';
  317. }
  318.  
  319.  
  320. int
  321. po_gram_lex ()
  322. {
  323.   static char *buf;
  324.   static size_t bufmax;
  325.   int c;
  326.   size_t bufpos;
  327.  
  328.   for (;;)
  329.     {
  330.       c = lex_getc ();
  331.       switch (c)
  332.     {
  333.     case EOF:
  334.       /* Yacc want this for end of file.  */
  335.       return 0;
  336.  
  337.     case ' ':
  338.     case '\t':
  339.     case '\n':
  340.     case '\r':
  341.     case '\f':
  342.       break;
  343.  
  344.     case '#':
  345.       /* Accumulate comments into a buffer.  If we have been asked
  346.           to pass comments, generate a COMMENT token, otherwise
  347.           discard it.  */
  348.       c = lex_getc ();
  349.       if (c == '~' && pass_obsolete_entries)
  350.         /* A special comment beginning with #~ is found.  This
  351.            is the format for obsolete entries and if we are
  352.            asked to return them is entries not as comments be
  353.            simply stop processing the comment here.  The
  354.            following characters are expected to be well formed.  */
  355.         break;
  356.  
  357.       if (pass_comments)
  358.         {
  359.           bufpos = 0;
  360.           while (1)
  361.         {
  362.           if (bufpos >= bufmax)
  363.             {
  364.               bufmax += 100;
  365.               buf = xrealloc (buf, bufmax);
  366.             }
  367.           if (c == EOF || c == '\n')
  368.             break;
  369.  
  370.           buf[bufpos++] = c;
  371.           c = lex_getc ();
  372.         }
  373.           buf[bufpos] = 0;
  374.  
  375.           po_gram_lval.string = buf;
  376.           return COMMENT;
  377.         }
  378.       else
  379.         /* We do this in separate loop because collecting large
  380.            comments while they get not passed to the upper layers
  381.            is not very effective.  */
  382.         while (c != EOF && c != '\n')
  383.           c = lex_getc ();
  384.       break;
  385.  
  386.     case '"':
  387.       bufpos = 0;
  388.       while (1)
  389.         {
  390.           if (bufpos >= bufmax)
  391.         {
  392.           bufmax += 100;
  393.           buf = xrealloc (buf, bufmax);
  394.         }
  395.           c = lex_getc ();
  396.           if (c == '\n')
  397.         {
  398.           po_gram_error (_("end-of-line within string"));
  399.           break;
  400.         }
  401.           if (c == EOF)
  402.         {
  403.           po_gram_error (_("end-of-file within string"));
  404.           break;
  405.         }
  406.           if (c == '"')
  407.         break;
  408.  
  409.           if (c == '\\')
  410.         c = control_sequence ();
  411.  
  412.           buf[bufpos++] = c;
  413.         }
  414.       buf[bufpos] = 0;
  415.  
  416.       po_gram_lval.string = xstrdup (buf);
  417.       return STRING;
  418.  
  419.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  420.     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
  421.     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
  422.     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
  423.     case 'y': case 'z':
  424.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  425.     case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
  426.     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
  427.     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
  428.     case 'Y': case 'Z':
  429.     case '_': case '$':
  430.       bufpos = 0;
  431.       for (;;)
  432.         {
  433.           if (bufpos + 1 >= bufmax)
  434.         {
  435.           bufmax += 100;
  436.           buf = xrealloc (buf, bufmax);
  437.         }
  438.           buf[bufpos++] = c;
  439.           c = lex_getc ();
  440.           switch (c)
  441.         {
  442.         default:
  443.           break;
  444.         case 'a': case 'b': case 'c': case 'd':
  445.         case 'e': case 'f': case 'g': case 'h':
  446.         case 'i': case 'j': case 'k': case 'l':
  447.         case 'm': case 'n': case 'o': case 'p':
  448.         case 'q': case 'r': case 's': case 't':
  449.         case 'u': case 'v': case 'w': case 'x':
  450.         case 'y': case 'z':
  451.         case 'A': case 'B': case 'C': case 'D':
  452.         case 'E': case 'F': case 'G': case 'H':
  453.         case 'I': case 'J': case 'K': case 'L':
  454.         case 'M': case 'N': case 'O': case 'P':
  455.         case 'Q': case 'R': case 'S': case 'T':
  456.         case 'U': case 'V': case 'W': case 'X':
  457.         case 'Y': case 'Z':
  458.         case '_': case '$':
  459.         case '0': case '1': case '2': case '3':
  460.         case '4': case '5': case '6': case '7':
  461.         case '8': case '9':
  462.           continue;
  463.         }
  464.           break;
  465.         }
  466.       lex_ungetc (c);
  467.  
  468.       buf[bufpos] = 0;
  469.  
  470.       c = keyword_p (buf);
  471.       if (c == NAME)
  472.         po_gram_lval.string = xstrdup (buf);
  473.       return c;
  474.  
  475.     case '0': case '1': case '2': case '3': case '4':
  476.     case '5': case '6': case '7': case '8': case '9':
  477.       /* I know, we don't need numbers, yet.  */
  478.       bufpos = 0;
  479.       for (;;)
  480.         {
  481.           if (bufpos + 1 >= bufmax)
  482.         {
  483.           bufmax += 100;
  484.           buf = xrealloc (buf, bufmax + 1);
  485.         }
  486.           buf[bufpos++] = c;
  487.           c = lex_getc ();
  488.           switch (c)
  489.         {
  490.         default:
  491.           break;
  492.  
  493.         case '0': case '1': case '2': case '3':
  494.         case '4': case '5': case '6': case '7':
  495.         case '8': case '9':
  496.           continue;
  497.         }
  498.           break;
  499.         }
  500.       lex_ungetc (c);
  501.  
  502.       buf[bufpos] = 0;
  503.  
  504.       po_gram_lval.number = atol (buf);
  505.       return NUMBER;
  506.  
  507.     default:
  508.       /* This will cause a syntax error.  */
  509.       return JUNK;
  510.     }
  511.     }
  512. }
  513.  
  514.  
  515. void
  516. po_lex_pass_comments (flag)
  517.      int flag;
  518. {
  519.   pass_comments = (flag != 0);
  520. }
  521.  
  522.  
  523. void
  524. po_lex_pass_obsolete_entries (flag)
  525.      int flag;
  526. {
  527.   pass_obsolete_entries = (flag != 0);
  528. }
  529.