home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / m4-1.4-src.tgz / tar.out / fsf / m4 / src / freeze.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  9KB  |  370 lines

  1. /* GNU m4 -- A simple macro processor
  2.    Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
  3.   
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.   
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.   
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /* This module handles frozen files.  */
  20.  
  21. #include "m4.h"
  22.  
  23. /*-------------------------------------------------------------------.
  24. | Destructively reverse a symbol list and return the reversed list.  |
  25. `-------------------------------------------------------------------*/
  26.  
  27. static symbol *
  28. reverse_symbol_list (symbol *sym)
  29. {
  30.   symbol *result;
  31.   symbol *next;
  32.  
  33.   result = NULL;
  34.   while (sym)
  35.     {
  36.       next = SYMBOL_NEXT (sym);
  37.       SYMBOL_NEXT (sym) = result;
  38.       result = sym;
  39.       sym = next;
  40.     }
  41.   return result;
  42. }
  43.  
  44. /*------------------------------------------------.
  45. | Produce a frozen state to the given file NAME.  |
  46. `------------------------------------------------*/
  47.  
  48. void
  49. produce_frozen_state (const char *name)
  50. {
  51.   FILE *file;
  52.   int h;
  53.   symbol *sym;
  54.   const builtin *bp;
  55.  
  56.   if (file = fopen (name, "w"), !file)
  57.     {
  58.       M4ERROR ((warning_status, errno, name));
  59.       return;
  60.     }
  61.  
  62.   /* Write a recognizable header.  */
  63.  
  64.   fprintf (file, "# This is a frozen state file generated by GNU %s %s\n",
  65.        PRODUCT, VERSION);
  66.   fprintf (file, "V1\n");
  67.  
  68.   /* Dump quote delimiters.  */
  69.  
  70.   if (strcmp (lquote.string, DEF_LQUOTE) || strcmp (rquote.string, DEF_RQUOTE))
  71.     {
  72.       fprintf (file, "Q%d,%d\n", (int) lquote.length, (int) rquote.length);
  73.       fputs (lquote.string, file);
  74.       fputs (rquote.string, file);
  75.       fputc ('\n', file);
  76.     }
  77.  
  78.   /* Dump comment delimiters.  */
  79.  
  80.   if (strcmp (bcomm.string, DEF_BCOMM) || strcmp (ecomm.string, DEF_ECOMM))
  81.     {
  82.       fprintf (file, "C%d,%d\n", (int) bcomm.length, (int) ecomm.length);
  83.       fputs (bcomm.string, file);
  84.       fputs (ecomm.string, file);
  85.       fputc ('\n', file);
  86.     }
  87.  
  88.   /* Dump all symbols.  */
  89.  
  90.   for (h = 0; h < hash_table_size; h++)
  91.     {
  92.  
  93.       /* Process all entries in one bucket, from the last to the first.
  94.      This order ensures that, at reload time, pushdef's will be
  95.      executed with the oldest definitions first.  */
  96.  
  97.       symtab[h] = reverse_symbol_list (symtab[h]);
  98.       for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
  99.     {
  100.       switch (SYMBOL_TYPE (sym))
  101.         {
  102.         case TOKEN_TEXT:
  103.           fprintf (file, "T%d,%d\n",
  104.                (int) strlen (SYMBOL_NAME (sym)),
  105.                (int) strlen (SYMBOL_TEXT (sym)));
  106.           fputs (SYMBOL_NAME (sym), file);
  107.           fputs (SYMBOL_TEXT (sym), file);
  108.           fputc ('\n', file);
  109.           break;
  110.  
  111.         case TOKEN_FUNC:
  112.           bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
  113.           if (bp == NULL)
  114.         {
  115.           M4ERROR ((warning_status, 0, "\
  116. INTERNAL ERROR: Built-in not found in builtin table!"));
  117.           abort ();
  118.         }
  119.           fprintf (file, "F%d,%d\n",
  120.                (int) strlen (SYMBOL_NAME (sym)),
  121.                (int) strlen (bp->name));
  122.           fputs (SYMBOL_NAME (sym), file);
  123.           fputs (bp->name, file);
  124.           fputc ('\n', file);
  125.           break;
  126.  
  127.         default:
  128.           M4ERROR ((warning_status, 0, "\
  129. INTERNAL ERROR: Bad token data type in freeze_one_symbol ()"));
  130.           abort ();
  131.           break;
  132.         }
  133.     }
  134.  
  135.       /* Reverse the bucket once more, putting it back as it was.  */
  136.  
  137.       symtab[h] = reverse_symbol_list (symtab[h]);
  138.     }
  139.  
  140.   /* Let diversions be issued from output.c module, its cleaner to have this
  141.      piece of code there.  */
  142.  
  143.   freeze_diversions (file);
  144.  
  145.   /* All done.  */
  146.  
  147.   fputs ("# End of frozen state file\n", file);
  148.   fclose (file);
  149. }
  150.  
  151. /*----------------------------------------------------------------------.
  152. | Issue a message saying that some character is an EXPECTED character.  |
  153. `----------------------------------------------------------------------*/
  154.  
  155. static void
  156. issue_expect_message (int expected)
  157. {
  158.   if (expected == '\n')
  159.     M4ERROR ((EXIT_FAILURE, 0, "Expecting line feed in frozen file"));
  160.   else
  161.     M4ERROR ((EXIT_FAILURE, 0, "Expecting character `%c' in frozen file",
  162.           expected));
  163. }
  164.  
  165. /*-------------------------------------------------.
  166. | Reload a frozen state from the given file NAME.  |
  167. `-------------------------------------------------*/
  168.  
  169. /* We are seeking speed, here.  */
  170.  
  171. void
  172. reload_frozen_state (const char *name)
  173. {
  174.   FILE *file;
  175.   int character;
  176.   int operation;
  177.   char *string[2];
  178.   int allocated[2];
  179.   int number[2];
  180.   const builtin *bp;
  181.  
  182. #define GET_CHARACTER \
  183.   (character = getc (file))
  184.  
  185. #define GET_NUMBER(Number) \
  186.   do                                \
  187.     {                                \
  188.       (Number) = 0;                        \
  189.       while (isdigit (character))                \
  190.     {                            \
  191.       (Number) = 10 * (Number) + character - '0';        \
  192.       GET_CHARACTER;                    \
  193.     }                            \
  194.     }                                \
  195.   while (0)
  196.  
  197. #define VALIDATE(Expected) \
  198.   do                                \
  199.     {                                \
  200.       if (character != (Expected))                \
  201.     issue_expect_message ((Expected));            \
  202.     }                                \
  203.   while (0)
  204.  
  205.   file = path_search (name);
  206.   if (file == NULL)
  207.     M4ERROR ((EXIT_FAILURE, errno, "Cannot open %s", name));
  208.  
  209.   allocated[0] = 100;
  210.   string[0] = xmalloc ((size_t) allocated[0]);
  211.   allocated[1] = 100;
  212.   string[1] = xmalloc ((size_t) allocated[1]);
  213.  
  214.   while (GET_CHARACTER, character != EOF)
  215.     switch (character)
  216.       {
  217.       default:
  218.     M4ERROR ((EXIT_FAILURE, 0, "Ill-formated frozen file"));
  219.  
  220.       case '\n':
  221.  
  222.     /* Skip empty lines.  */
  223.  
  224.     break;
  225.  
  226.       case '#':
  227.  
  228.     /* Comments are introduced by `#' at beginning of line, and are
  229.        ignored.  */
  230.  
  231.     while (character != EOF && character != '\n')
  232.       GET_CHARACTER;
  233.     VALIDATE ('\n');
  234.     break;
  235.  
  236.       case 'C':
  237.       case 'D':
  238.       case 'F':
  239.       case 'T':
  240.       case 'Q':
  241.     operation = character;
  242.     GET_CHARACTER;
  243.  
  244.     /* Get string lengths.  Accept a negative diversion number.  */
  245.  
  246.     if (operation == 'D' && character == '-')
  247.       {
  248.         GET_CHARACTER;
  249.         GET_NUMBER (number[0]);
  250.         number[0] = -number[0];
  251.       }
  252.     else
  253.       GET_NUMBER (number[0]);
  254.     VALIDATE (',');
  255.     GET_CHARACTER;
  256.     GET_NUMBER (number[1]);
  257.     VALIDATE ('\n');
  258.  
  259.     if (operation != 'D')
  260.       {
  261.         
  262.         /* Get first string contents.  */
  263.  
  264.         if (number[0] + 1 > allocated[0])
  265.           {
  266.         free (string[0]);
  267.         allocated[0] = number[0] + 1;
  268.         string[0] = xmalloc ((size_t) allocated[0]);
  269.           }
  270.  
  271.         if (number[0] > 0)
  272.           if (!fread (string[0], (size_t) number[0], 1, file))
  273.         M4ERROR ((EXIT_FAILURE, 0, "Premature end of frozen file"));
  274.  
  275.         string[0][number[0]] = '\0';
  276.       }
  277.  
  278.     /* Get second string contents.  */
  279.  
  280.     if (number[1] + 1 > allocated[1])
  281.       {
  282.         free (string[1]);
  283.         allocated[1] = number[1] + 1;
  284.         string[1] = xmalloc ((size_t) allocated[1]);
  285.       }
  286.  
  287.     if (number[1] > 0)
  288.       if (!fread (string[1], (size_t) number[1], 1, file))
  289.         M4ERROR ((EXIT_FAILURE, 0, "Premature end of frozen file"));
  290.  
  291.     string[1][number[1]] = '\0';
  292.     GET_CHARACTER;
  293.     VALIDATE ('\n');
  294.       
  295.     /* Act according to operation letter.  */
  296.  
  297.     switch (operation)
  298.       {
  299.       case 'C':
  300.  
  301.         /* Change comment strings.  */
  302.  
  303.         set_comment (string[0], string[1]);
  304.         break;
  305.  
  306.       case 'D':
  307.  
  308.         /* Select a diversion and add a string to it.  */
  309.  
  310.         make_diversion (number[0]);
  311.         if (number[1] > 0)
  312.           shipout_text (NULL, string[1], number[1]);
  313.         break;
  314.  
  315.       case 'F':
  316.  
  317.         /* Enter a macro having a builtin function as a definition.  */
  318.  
  319.         bp = find_builtin_by_name (string[1]);
  320.         if (bp)
  321.           define_builtin (string[0], bp, SYMBOL_PUSHDEF, 0);
  322.         else
  323.           M4ERROR ((warning_status, 0, "\
  324. `%s' from frozen file not found in builtin table!",
  325.             string[0]));
  326.         break;
  327.  
  328.       case 'T':
  329.  
  330.         /* Enter a macro having an expansion text as a definition.  */
  331.  
  332.         define_user_macro (string[0], string[1], SYMBOL_PUSHDEF);
  333.         break;
  334.  
  335.       case 'Q':
  336.  
  337.         /* Change quote strings.  */
  338.  
  339.         set_quotes (string[0], string[1]);
  340.         break;
  341.  
  342.       default:
  343.  
  344.         /* Cannot happen.  */
  345.  
  346.         break;
  347.       }
  348.     break;
  349.     
  350.       case 'V':
  351.  
  352.     /* Validate format version.  Only `1' is acceptable for now.  */
  353.  
  354.     GET_CHARACTER;
  355.     VALIDATE ('1');
  356.     GET_CHARACTER;
  357.     VALIDATE ('\n');
  358.     break;
  359.  
  360.       }
  361.  
  362.   free (string[0]);
  363.   free (string[1]);
  364.   fclose (file);
  365.  
  366. #undef GET_CHARACTER
  367. #undef GET_NUMBER
  368. #undef VALIDATE
  369. }
  370.