home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume22 / crefine / part01 / crefine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-26  |  29.4 KB  |  856 lines

  1.  
  2. /*************************************************************************
  3. Project : C-Refine Precompiler
  4. Module  : main module
  5. Author  : Lutz Prechelt, Karlsruhe
  6. Date    : 10.06.91  Version 16
  7. Compiler: ANSI C, C-Refine 2.3 (bootstrapped)
  8. **************************************************************************/
  9. /*
  10.     Copyright (C) 1988,89,90,91 by Lutz Prechelt, Karlsruhe
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 1, or (at your option)
  15.     any later version.
  16.     This program is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.     You should have received a copy of the GNU General Public License
  21.     along with this program; if not, write to the Free Software
  22.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. */
  24.  
  25. /************************************************************************
  26. *********************** C - R e f i n e *********************************
  27. *************************************************************************/
  28.  
  29. #if 0
  30. REMARK:
  31.   This program was originally written using german identifiers and
  32.   comments. I worked through it to change this (at least in most parts)
  33.   but please do not flame me if there are relicts from this state.
  34.   I did not find a sensible replacement for the german word 'Klammer' that
  35.   may stand for any of the characters ( ) [ ] { }  so sometimes I still
  36.   use the german one.
  37.  
  38. Variants:
  39. #define deutsch   fuer deutsche Meldungen statt englische
  40. #define ms_dos    for  MS-DOS Operating System (Compiler Microsoft C 5.0)
  41. #define unix      for  Unix
  42. #define vms       for  VMS
  43. #define ansi      for  ANSI-C Compiler
  44.  
  45. For version changes see refinement startup message and file cr_texts.h
  46.  
  47. ============================== History: ====================================
  48.  
  49.  
  50. Version 1.0  (Alpha)    (0, 1)
  51.  
  52. 1987
  53.   procedural refinements only
  54.   not comfortable, few error messages
  55.  
  56.  
  57. Version 2.0  (Alpha)    (2, 3)
  58.  
  59. Feb. 88
  60.   value-returning refinements,
  61.   improved error handling,
  62.   Options comment, feedback, list, numbering, refinementsymbol, small
  63.  
  64.  
  65. Version 2.1  (Beta)     (4, 5)
  66.  
  67. 09.04.88  ( --> Martin, Ihno, Volker, Beat)
  68.   improved error handling
  69.   triple error messages (german, english, german nonsense),
  70.   Context description in error messages,
  71.   Options anyway, feedback, ibm chars, message type, tabsize, warning level
  72.   Expires 31.07.88
  73.  
  74.  
  75. Version 2.2             (6, 7, 8)
  76.  
  77. 08.07.88   ( --> Martin)
  78.   corr: Changes blanks in namen to underscrores again (like in Version 1.0)
  79.         (otherwise error in goto occur)
  80.   corr: Removed semicolon after value-returning refinements kept
  81.         (via introduction of refcallr)
  82.   improved error handling: Warning for "often used" only for
  83.   "big" refinements.
  84. 03.08.88
  85.   corr: When inserting file names in "#line"-commands, backslashes
  86.         are doubled (backslash is Escape symbol in C string denoters)
  87. 13.09.88
  88.   corr: empty refinements will not give syntax errors anymore.
  89.  
  90.  
  91. Version 2.3             (9, 10, 11, 12, 13)
  92.  
  93. 29.09.88 ( --> Martin, Ihno)
  94.   corr: refinements with just 1 semicolon are enclosed in braces also
  95.         (to avoid "else"-conflict)
  96.   C++ Mode (i.e. // Kommentare) as option p
  97. 17.03.89
  98.   "std.h" introduced,  #ifdefs for environment switches introduced.
  99.   Look-through, further "refinementized", several small corrections
  100.   ported to SUN-OS (Berkeley-Unix)
  101.   Size restrictions released (500 -> 800 lines, 50 -> 100 Refinements)
  102. 18.03.89
  103.   dito, expires 31.07.89
  104. 11.09.89
  105.   ported to PCS maschine under Munix 5.3 (System V)
  106.   further #ifdefs for deutsch, expire
  107.   The switches are given in the Makefile
  108. 11.09.89
  109.   dito, expires 31.10.89
  110.  
  111.  
  112. Version 2.4             (14, 15, 16)
  113.  
  114. 27.08.90 ( --> Uni)
  115.   Line numbering switchable in 4 levels.
  116.   Quiet-Option
  117.   Buffersizes selectable via option.
  118.   New name handling for input/output files
  119.  
  120. 23.01.91 ( --> Uni, Usenet announcement, iraun1)
  121.   Names and Comments changed to english (was german before)
  122.   error in level switching of line numbering fixed.
  123.  
  124. 10.06.91 ()
  125.   History translated to english
  126.   some small corrections
  127.   corr: REF_INFO storage has to be 0-initialized,
  128.         so use calloc instead of malloc
  129.   Eliminated duplication of function declarations for ansi and non-ansi
  130.   by introduction of the A(a) macro in std.h
  131.  
  132. =============================================================================
  133. #endif
  134.  
  135. #include <stdio.h>
  136. #include <string.h>
  137. #include <malloc.h>
  138. #include <time.h>
  139.  
  140. #define DATA_HERE     /* Here the data declarations are NOT extern */
  141. #include "cr_decl.h"  /* global Functions, Types and Data */
  142. #include "getargs.h"
  143.  
  144.  
  145. /******************* lokal Functions ************************************/
  146.  
  147. extern int  main A((int argc,  charp *argv));
  148. extern int  crefine A((int argc, charp *argv));
  149. static void process_c_refine A((FILE *in, FILE *out));
  150. static void process_line A((FILE *out, int semicolons));
  151. static void insert_refinements A((FILE *out));
  152. static void insert_refinement A((FILE *out, LINE_INFO *l, int startindent,
  153.                                int recursive_level));
  154. static void line_cmd A((FILE* out, int nr, int indent, int min_level));
  155. static void put_indent A((FILE *out, int how_much));
  156. static void put_line A((FILE *out, LINE_INFO *line, int additional_indent,
  157.                       int min_linenumbering_level));
  158. static int  refinement_nr A((char *refinementname));
  159. static void allocate A((charp *buffer, unsigned *size, unsigned minsize));
  160. static void copy_with_doubled_backslashes A((char *string, char *copy));
  161. static void do_expire A((int day, int month, int year_in_century));
  162. static void reset_l_r_s A((void));
  163.  
  164. /*********************** Lokal Data ************************************/
  165.  
  166. /***** line info, refinement info *****/
  167. static LINES l;           /* line info */
  168. static int   l_pos;
  169.  
  170. static REFS  r;           /* refinement info */
  171. static int   r_pos;
  172.  
  173. /***** Status *****/
  174. static int   old_level,          /* level at line before */
  175.              commanded_line_no;  /* line_no according to last line_cmd */
  176.  
  177. /***** Sonstiges *****/
  178. static char  blanks[] =  /* indents are made from this. */
  179.   "                                                                       ";
  180. /* "blanks" is taken as  72 Blanks long (see put_indent) */
  181.  
  182. static option_msg;
  183.  
  184. #define refdecl_line(i)  /* line no of refinement head of r[i] */\
  185.                           (l [r[i].firstentry].line_no)
  186.  
  187. /******************************** crefine *********************************/
  188.  
  189. extern int main (argc, argv)      /* MAIN */
  190.   int   argc;
  191.   charp argv[];
  192. {
  193.   return (crefine (argc, argv));
  194. }
  195.  
  196. static ARG argtab[] = {
  197. #if  deutsch
  198.   {'a', BOOLEAN, &option_anyway,
  199.    "alle: Ausgabedatei trotz Fehlern nicht loeschen" },
  200.   {'c', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  201.   {'e', BOOLEAN, &option_indent,   "#line Kommandos einruecken" },
  202.   {'f', BOOLEAN, &option_feedback, "Fortschrittsanzeige (Zeilennummern)" },
  203. #if ms_dos
  204.   {'I', BOOLEAN, &option_ibmchars,
  205.    "erlaube IBM internationale Zeichen fuer Namen" },
  206. #endif
  207.   {'k', BOOLEAN, &option_comment,  "Refinementnamen-Kommentare in Ausgabe" },
  208.   {'l', BOOLEAN, &option_list,     "liste alle Refinementnamen" },
  209.   {'m', CHARACTER, &option_msg,
  210.    "Meldungen in: d=deutsch, e=english, sonst humorig" },
  211.   {'n', INTEGER, &numbering_level,
  212.    "Stufe der Numerierung mit #line Kommandos" },
  213.   {'p', BOOLEAN, &option_cplusplus,"C++ Modus" },
  214.   {'q', BOOLEAN, &option_cplusplus,"keine Startmeldung ausgeben" },
  215.   {'r', CHARACTER, &refinementsymbol, "Refinementsymbol (als Zeichen)" },
  216.   {'R', INTEGER, &refinementsymbol, "Refinementsymbol (als Zahl)" },
  217.   {'s', BOOLEAN, &option_small,    "strippen: Kompaktifizierte Ausgabe" },
  218.   {'w', INTEGER, &warning_level,   "Warnstufe (0 - 3)" }
  219.   {'F', INTEGER, &maxerrors,       "Max. Anzahl Fehler" },
  220.   {'L', INTEGER, &b_size,          "Max. Zeilenlaenge" },
  221.   {'N', INTEGER, &maxref,          "Max. Refinements je Funktion" },
  222.   {'P', INTEGER, &s_size,          "Codepuffer in Bytes" },
  223.   {'T', INTEGER, &tabsize,         "Tabulatorgroesse" },
  224.   {'W', INTEGER, &maxwarnings,     "Max. Anzahl Warnungen" },
  225.   {'Z', INTEGER, &maxline,         "Max. Zeilen je Funktion" },
  226. #else
  227.   {'a', BOOLEAN, &option_anyway,   "anyway: don't delete output on errors" },
  228.   {'c', BOOLEAN, &option_comment,  "comment refinement names in output" },
  229.   {'f', BOOLEAN, &option_feedback, "feedback that you work" },
  230.   {'i', BOOLEAN, &option_indent,   "indent the #line commands" },
  231. #if ms_dos
  232.   {'I', BOOLEAN, &option_ibmchars,
  233.    "enable IBM International Charset for names" },
  234. #endif
  235.   {'l', BOOLEAN, &option_list,     "list all refinement names" },
  236.   {'m', CHARACTER, &option_msg,
  237.    "Messages in: g=german, e=english, else sense of humor ?" },
  238.   {'n', INTEGER, &numbering_level,
  239.    "level of numbering with #line commands" },
  240.   {'p', BOOLEAN, &option_cplusplus,"C++ mode" },
  241.   {'q', BOOLEAN, &option_quiet,    "quiet mode (no startup message)" },
  242.   {'r', CHARACTER, &refinementsymbol, "refinementsymbol (character form)" },
  243.   {'R', INTEGER, &refinementsymbol, "refinementsymbol (decimal form)" },
  244.   {'s', BOOLEAN, &option_small,    "small compactified output" },
  245.   {'w', INTEGER, &warning_level,   "warning level (0 - 3)" },
  246.   {'B', INTEGER, (int*)&s_size,    "code buffer in bytes" },
  247.   {'E', INTEGER, &maxerrors,       "max errors" },
  248.   {'L', INTEGER, (int*)&maxline,   "max lines per function" },
  249.   {'N', INTEGER, (int*)&maxref,    "max refinements per function" },
  250.   {'T', INTEGER, &tabsize,         "tab size" },
  251.   {'W', INTEGER, &maxwarnings,     "max warnings" },
  252. #endif
  253. };
  254.  
  255.  
  256. extern int crefine (argc, argv)    /* C-REFINE */
  257.   int   argc;
  258.   charp argv[];
  259. {
  260.   /* Analyses options and opens files.
  261.      Then calls  process_c_refine and closes files again.
  262.      Returns the number of errors that have been found
  263.   */
  264.   bool two_filenames_given;
  265.   int  wrong_options;
  266.   FILE *in, *out;
  267.   {   /* analysis_of_options  (Level 1) */
  268.   option_anyway = option_feedback = option_indent = option_comment
  269.                 = option_list = option_ibmchars = option_cplusplus
  270.                 = false;
  271.   option_small = true;
  272.   numbering_level = 3;
  273. #if deutsch
  274.   option_msg  = 'd';
  275.   msg_type    =  0;  /* deutsche Meldungen als Standard */
  276. #else
  277.   option_msg  = 'e';
  278.   msg_type    =  1;  /* english warnings and errors as default */
  279. #endif
  280.   refinementsymbol = std_refinementsymbol;
  281.   tabsize          = 1;
  282.   warning_level    = 3;
  283.   maxline          = STD_MAXLINE;
  284.   maxref           = STD_MAXREF;
  285.   b_size           = STD_MAXLINELENGTH;
  286.   s_size           = STD_S_SIZE;
  287.   maxerrors        = STD_MAXERRORS;
  288.   maxwarnings      = STD_MAXWARNINGS;
  289.   wrong_options = getargs (&argc, argv, argtab, ARGTABSIZE (argtab));
  290.   if (option_small) {
  291.      tabsize = 1;
  292.   }
  293.   if (option_msg == 'd' || option_msg == 'D' ||
  294.       option_msg == 'g' || option_msg == 'G')
  295.      msg_type = 0;
  296.   else if (option_msg == 'e' || option_msg == 'E')
  297.      msg_type = 1;
  298.   else
  299.      msg_type = 2;
  300.   two_filenames_given = argc == 3;
  301.   }
  302.   if (wrong_options || argc>>1 != 1) {
  303.      print_usage (argv[0], usagestring[msg_type],
  304.                   argtab, ARGTABSIZE (argtab));
  305.     {   /* startup_message  (Level 1) */
  306.     fprintf (stderr,
  307.              "C-Refine Precompiler   %s\n", versionstring[msg_type]);
  308.     fprintf (stderr,
  309.              "Copyright (C) 1988,89,90,91  Lutz Prechelt, Karlsruhe\n");
  310.     }
  311.      exit (100);
  312.   }
  313.   if (!option_quiet)
  314.     {   /* startup_message  (Level 1) */
  315.     fprintf (stderr,
  316.              "C-Refine Precompiler   %s\n", versionstring[msg_type]);
  317.     fprintf (stderr,
  318.              "Copyright (C) 1988,89,90,91  Lutz Prechelt, Karlsruhe\n");
  319.     }
  320.   {   /* open_files_and_complain_if_necessary  (Level 1) */
  321.   strcpy (name_in, argv[1]);            /* get */
  322. #if ms_dos
  323.   in = fopen (name_in, "rt");  /* read, translated mode */
  324. #else
  325.   in = fopen (name_in, "r");  /* read */
  326. #endif
  327.   if (in == NULL || ferror (in)) {
  328.      fprintf (stderr, Eopen[msg_type], name_in);
  329.      exit (100);
  330.   }
  331.   copy_with_doubled_backslashes (name_in, modified_name_in);
  332.   if (two_filenames_given) {            /* if second name given */
  333.      strcpy (name_out, argv[2]);        /* take it as it is */
  334.   }
  335.   else {                                /* else */
  336.      strcpy (name_out, argv[1]);        /* take first name */
  337.      if (name_out[strlen(name_out)-1] == 'r')
  338.        name_out[strlen(name_out)-1] = 0; /* remove 'r' from end */
  339.      else
  340.        strcat (name_out, "RRR");         /* or append 'RRR' */
  341.   }
  342. #if ms_dos
  343.   out = fopen (name_out, "wt");  /* write, translated mode */
  344. #else
  345.   out = fopen (name_out, "w");  /* write */
  346. #endif
  347.   if (out == NULL || ferror (out)) {
  348.      fprintf (stderr, Eopen[msg_type], name_out);
  349.      exit (100);
  350.   }
  351.   }
  352.   {   /* reserve_memory_and_complain_if_necessary  (Level 1) */
  353.   b      = malloc (b_size);
  354.   r      = (REFS)calloc ((maxref+1), sizeof (REF_INFO));
  355.   l      = (LINES)malloc ((maxline+1) * sizeof (LINE_INFO));
  356.   s_root = malloc (s_size);
  357.   if (!(b && s_root && r && l)) {
  358.      fprintf (stderr, Ememory[msg_type]);
  359.      exit (100);
  360.   }
  361.   }
  362.   /* here we go: */
  363.   rewind (in);  /* Begin at the beginning, then proceed until you come */
  364.                 /* to the end, there stop.   (from: Alice in Wonderland) */
  365.   process_c_refine (in, out);
  366.   fclose (in);
  367.   fclose (out);   /* Schliessen vor unlink noetig ! */
  368.   if (errors && !option_anyway) /* don't produce errorneous outputfiles */
  369.      unlink (name_out);         /* delete file */
  370.   if (errors || warnings)
  371. #if deutsch
  372.      fprintf (stderr, "%d Fehler%s   %d Warnung%s   Ausgabedatei %s\n",
  373.               errors,   errors   != 1 ? "" : "",
  374.               warnings, warnings != 1 ? "en" : "",
  375.               errors && !option_anyway ?
  376.                  "geloescht" : (errors ? "dennoch erhalten"
  377.                                        : "ist fragwuerdig"));
  378. #else
  379.      fprintf (stderr, "%d error%s   %d warning%s   Output %s\n",
  380.               errors,   errors   != 1 ? "s" : "",
  381.               warnings, warnings != 1 ? "s" : "",
  382.               errors && !option_anyway ?
  383.                  "deleted" : (errors ? "kept anyway" : "is doubtful"));
  384. #endif
  385.   return (errors);
  386. }
  387.  
  388. /************************ process_c_refine *********************************/
  389.  
  390. static void process_c_refine (in, out)
  391.   FILE *in, *out;
  392. {
  393.   /* Reads the file 'in' to the end line by line via 'get_line' and
  394.      generates the C source code by inserting the refinement bodies for
  395.      the calls.
  396.      Generates error messages for undeclares refinements and warnings for
  397.      unused or often used ones.
  398.      Uses the variables stop_processing, errors, warnings,
  399.      s, l, r and the option indicators.
  400.   */
  401.   commanded_line_no = line_no = 0;
  402.   reset_l_r_s ();
  403.   if (numbering_level > 0)
  404.     /* we get a linefeed anyway! */
  405.     fprintf (out, "#line 1 \"%s\"", modified_name_in);
  406.   while (!stop_processing)
  407.      {   /* handle_next_line  (Level 1) */
  408.      int semicolons = 0;
  409.      if (option_feedback && line_no % FEEDBACK_INTERVAL == 0)
  410.         cout (line_no);
  411.      if (ferror (in))
  412.         fatal_error (Ereadinput, l[l_pos-1].start, line_no);
  413.      if (ferror (out))
  414.         fatal_error (Ewriteoutput, NULL, line_no);
  415.      get_line (in, l+l_pos, &semicolons);
  416.      process_line (out, semicolons);
  417.      }
  418.   if (option_feedback)
  419.      cout (line_no);
  420.   free (s_root);
  421. }
  422.  
  423. /************************** process_line ************************************/
  424.  
  425. static void process_line (out, semicolons)
  426.   FILE *out;
  427.   int   semicolons;
  428. {
  429.   /* Works on the lines up to the current line l[l_pos] in the way that
  430.      it decides whether a function has ended and thus the insertion of
  431.      refinements has to be started.
  432.      On level 0 all lines are copied from in to out immediately.
  433.      After a state change from level 0 to level 1 all lines (along with
  434.      a lineinfo) are kept until the next transition to level 0 and the
  435.      refinement info is being built.
  436.      If necessary, error messages for overflow or refinement errors and
  437.      warnings for not or multiply used refinements are generated.
  438.   */
  439.   if (r_pos > 0)
  440.      r[r_pos - 1].semicolons += semicolons;
  441.   if (old_level == 0)
  442.      {   /* we_came_from_level_0  (Level 1) */
  443.      assert (l_pos == 0);   /* nothing can be stored from level 0 */
  444.      if (l[0].level == 0 || stop_processing)
  445.         {   /* remains_on_level_0_so_just_copy_it  (Level 2) */
  446.         if (l[0].type != normal && l[0].type != empty)
  447.            error (Elevel0_ref, l[0].start, line_no);
  448.         put_line (out, &l[0], 0, 1);
  449.         reset_l_r_s ();
  450.         }
  451.      else
  452.         {   /* function_has_begun  (Level 2) */
  453.         error_in_this_function = false;
  454.         old_level = l[0].level;    /* neuen Level merken */
  455.         if (l[0].type == refdecl && r_pos < maxref) {  /* empty function */
  456.            r[r_pos].name         = l[0].start;
  457.            r[r_pos].firstentry   = 0;
  458.            r[r_pos].active       = false;
  459.            r[r_pos++].semicolons = 0;
  460.            warning (Wempty_function, NULL, line_no - 1, 3);
  461.         }
  462.         l_pos++;                   /* store line */
  463.         }
  464.      }
  465.   else
  466.      {   /* we_were_inside_a_function_or_so  (Level 1) */
  467.      if (l[l_pos].level == 0 || stop_processing)
  468.         {   /* but_now_we_are_outside  (Level 2) */
  469.         insert_refinements (out);
  470.         put_line (out, &l[l_pos-1], 0, 1);  /* last line (Blockklammer) */
  471.         put_line (out, &l[l_pos], 0, 1);    /* the level 0 line */
  472.         error_in_this_function = false;
  473.         reset_l_r_s ();
  474.         }
  475.      else
  476.         {   /* and_still_keep_being_in  (Level 2) */
  477.         if (l[l_pos].type == refdecl && r_pos < maxref) {
  478.            r[r_pos].name         = l[l_pos].start;   /* enter Refinement */
  479.            r[r_pos].active       = false;
  480.            r[r_pos].firstentry   = l_pos;
  481.            r[r_pos++].semicolons = 0;
  482.         }
  483.         old_level = l[l_pos].level;/* store new level */
  484.         l_pos++;                   /* store line */
  485.         if (l_pos >= maxline)
  486.            fatal_error (Elines_in_func, l[l_pos].start, line_no);
  487.         if (s - s_root >= s_size - 150)  /* Reserve too small */
  488.            fatal_error (Ebytes_in_func, l[l_pos].start, line_no);
  489.         }
  490.      }
  491. }
  492.  
  493. /************************ insert_refinements ******************************/
  494.  
  495. static void insert_refinements (out)
  496.   FILE *out;
  497. {
  498.   /* Replaces the refinement calls with the bodies, after the whole function
  499.      has been read in.
  500.      In the output #line statements are generated, except if option
  501.      numbering_level is zero.
  502.      Comments and indentations are thrown away if option_small is true.
  503.      Comments stating the refinement names are inserted in the output if
  504.      option_comment is true.
  505.   */
  506.   int  i, end;
  507.   bool extern_stop = stop_processing;  /* Protect last function against */
  508.   stop_processing  = false;            /* local use of this variable */
  509.   r[r_pos].firstentry = l_pos-1;       /* line of Blockklammer */
  510.   r[r_pos].name       = NULL;
  511.   {   /* generate_refinement_list_if_necessary  (Level 1) */
  512.   if (option_list && r_pos > 0) {
  513.      fputc ('\n', stdout);
  514.      for (i = 0; i < r_pos; i++)
  515.          fprintf (stdout, "(%d) %s\n", refdecl_line (i), r[i].name);
  516.   }
  517.   }
  518.   {   /* find_last_line_to_insert  (Level 1) */
  519.   end = r[0].firstentry - 1;
  520.   while (l[end].type == empty)   /* suppress trailing empty lines */
  521.      end--;
  522.   }
  523.   for (i = 0; i <= end; i++) {  /* lines up to first ref. declaration */
  524.       switch (l[i].type) {
  525.          case refcall  :
  526.          case refcallr :
  527.                 {   /* insert_refinement  (Level 1) */
  528.                 insert_refinement (out, l+i, l[i].indent, 1);
  529.                 if (stop_processing)
  530.                    return;
  531.                 }
  532.                 break;
  533.          case leave    :
  534.                 {   /* whatshallthatbe  (Level 1) */
  535.                 assert (false);
  536.                 }
  537.                 break;
  538.          case normal   :
  539.                 {   /* insert_normal_line  (Level 1) */
  540.                 put_line (out, &l[i], 0, 1);
  541.                 }
  542.                 break;
  543.          case empty    :
  544.                 putc ('\n', out);
  545.                 commanded_line_no++;
  546.                 break;
  547.          case refdecl  :
  548.          default       :
  549.                  assert (false);
  550.       }
  551.   }
  552.   {   /* maybe_give_sermon_on_refinements  (Level 1) */
  553.   for (i = 0; i < r_pos; i++)
  554.       if (r[i].semicolons > 50)
  555.          warning (Wlong_ref, l[r[i].firstentry].start,
  556.                   refdecl_line (i), 3);
  557.       else if (r[i].calls > 5 && r[i].semicolons > 2)
  558.          warning (Wref_often_used, l[r[i].firstentry].start,
  559.                   refdecl_line (i), 3);
  560.       else if (r[i].calls == 0)
  561.          warning (Wref_unused, l[r[i].firstentry].start,
  562.                   refdecl_line (i), 1);
  563.   }
  564.   stop_processing = stop_processing || extern_stop;  /* Merging-Restore */
  565. }
  566.  
  567. /************************* insert_refinement ******************************/
  568.  
  569. static void insert_refinement (out, z, startindent, recursive_level)
  570.   FILE *out;
  571.   LINE_INFO *z;
  572.   int  startindent, recursive_level;
  573. {
  574.   /* Looks for the refinement to insert by its name, computes the range
  575.      of lines to work on and does then do the same as insert_refinements
  576.      does.
  577.      If necessary the refinement name is given as a comment before the
  578.      body is inserted.
  579.      The refinement body is enclosed in delimiters:
  580.        if ref.semicolons == 0 in parentheses (on first and last line)
  581.        if ref.semicolons >= 1 in curly braces (on separate lines)
  582.      The refinement calls are counted and maybe messages generated.
  583.      In case of leave-statements the refinement that shall be leave'd is
  584.      marked, so a label can be generated.
  585.      Errors:
  586.        1. Refinement is not declared
  587.        2. recursive call to refinement
  588.        3. leave is impossible because the refinement is not
  589.           present in static call hierarchy
  590.   */
  591.   int i;
  592.   int  nr, ref_startindent, end;
  593.   assert (startindent > 0);
  594.   nr = refinement_nr ((
  595.   z->start)
  596.   );  /* search for refinement */
  597.   if (nr == -1) {
  598.      error (Eref_not_decl, (
  599.      z->start)
  600.      , z->line_no);
  601.      return;
  602.   }
  603.   else if (r[nr].active)
  604.      {   /* complain_for_recursive_refinement_call  (Level 1) */
  605.      error (Erecursive_ref, (
  606.      z->start)
  607.      , z->line_no);
  608.      stop_processing = true;
  609.      return;
  610.      }
  611.   else {
  612.      r[nr].calls++;           /* register the call */
  613.      r[nr].active   = true;
  614.      r[nr].leave_it = false;
  615.   }
  616.   end = r[nr+1].firstentry - 1;
  617.   while (l[end].type == empty)   /* suppress trailing empty lines */
  618.      end--;
  619.   i = r[nr].firstentry + 1;
  620.   if (i > end)
  621.      warning (Wref_empty, l[r[nr].firstentry].start, refdecl_line (nr), 2);
  622.   else
  623.      {   /* insert_the_refinement  (Level 1) */
  624.      /* for an empty refinement, this is not called at all! */
  625.      {   /* write_indentation_and_opening_klammer  (Level 2) */
  626.      int sc = r[nr].semicolons;
  627.      if (sc > 0)
  628.         put_indent (out, startindent);
  629.      putc (sc > 0 ? '{' : '(', out);  /* Klammer auf */
  630.      if (option_comment && sc > 0)
  631.         fprintf (out, Tlistline[msg_type], (
  632.         z->start)
  633.         , recursive_level);
  634.      }
  635.      ref_startindent = l[i].indent;
  636.      for ( ; i <= end; i++) {
  637.          switch (l[i].type) {
  638.             case refcall  :
  639.             case refcallr :
  640.                    {   /* insert_refinement  (Level 2) */
  641.                    insert_refinement (out, l+i,
  642.                                       startindent + l[i].indent
  643.                                                   - ref_startindent,
  644.                                       recursive_level+1);
  645.                    }
  646.                    break;
  647.             case leave    :
  648.                    {   /* insert_goto_statement  (Level 2) */
  649.                    int leave_nr = refinement_nr (l[i].start);
  650.                    if (leave_nr == -1)
  651.                       error (Eunknown_leave, l[i].start, l[i].line_no);
  652.                    else if (!r[leave_nr].active)
  653.                       error (Eleave_unpresent, l[i].start, l[i].line_no);
  654.                    else {
  655.                       r[leave_nr].leave_it = true;
  656.                       put_indent (out, startindent);
  657.                       fprintf (out, "goto %s_%d;",
  658.                                l[i].start, r[leave_nr].calls);
  659.                    }
  660.                    }
  661.                    break;
  662.             case normal   :
  663.                    {   /* insert_normal_line  (Level 2) */
  664.                    put_line (out, &l[i], startindent - ref_startindent, (
  665.                    r[nr].semicolons == 0 ? 3 : 2)
  666.                    );
  667.                    }
  668.                    break;
  669.             case empty    :
  670.                    putc ('\n', out);
  671.                    commanded_line_no++;
  672.                    break;
  673.             case refdecl  :
  674.             default       :
  675.                     assert (false);
  676.          }
  677.      }
  678.      if (r[nr].leave_it)
  679.         {   /* generate_label  (Level 2) */
  680.         fprintf (out, "\n%s_%d: ;", (
  681.         z->start)
  682.         , r[nr].calls);
  683.         commanded_line_no++;
  684.         }
  685.      {   /* write_closing_klammer  (Level 2) */
  686.      int sc = r[nr].semicolons;
  687.      if (sc > 0) {
  688.         put_indent (out, startindent);
  689.         putc ('}', out);
  690.      }
  691.      else {
  692.         putc (')', out);
  693.         if (z->type == refcallr)  /* semicolon has been removed illegaly */
  694.            putc (';', out);
  695.      }
  696.      }
  697.      }
  698.   r[nr].active = false;
  699.   return;
  700. }
  701.  
  702. /************************* line_cmd **************************************/
  703.  
  704. static void line_cmd (out, nr, indent, min_level)
  705.   FILE *out;
  706.   int  nr;
  707.   int  indent;
  708.   int  min_level;
  709. {
  710.   /* Writes a "preprocessor #line directive" including file name if
  711.      requested.
  712.      Is suppressed, if min_level is less than numbering_level.
  713.      Using numbering_level, option_indent, commanded_line_no and name_in
  714.   */
  715.   if (numbering_level >= min_level) {
  716.      if (option_indent)
  717.         put_indent (out, indent);
  718.      else
  719.         putc ('\n', out);
  720.      fprintf (out, "#line %d \"%s\"", nr, modified_name_in);
  721.      commanded_line_no = nr-1; /* #line 3  means: next comes line 3 ! */
  722.   }
  723. }
  724.  
  725. /********************** put_indent **************************************/
  726.  
  727. static void put_indent (out, how_far)
  728.   FILE *out;
  729.   int how_far;
  730. {
  731.   putc ('\n', out);      /* begin newline */
  732.   commanded_line_no++;
  733.   if (!option_small)
  734.      fwrite (blanks, how_far > 72 ? 72 : (how_far < 0 ? 0 : how_far),
  735.              1, out);
  736. }
  737.  
  738. /*************************** put_line ***********************************/
  739.  
  740. static void put_line (out, line, additional_indent, min_level)
  741.   FILE       *out;
  742.   LINE_INFO  *line;    /* pointer for efficiency (is big object) */
  743.   int        additional_indent;
  744.   int        min_level;
  745. {
  746.   /* Writes the line 'line' to 'out' with the appropriate indentation
  747.      (which is the line's indentation plus additional_indent).
  748.      If the current line numbering is not right a line_cmd is made before.
  749.   */
  750.   if (line->line_no != commanded_line_no + 1)
  751.      line_cmd (out, line->line_no, line->indent + additional_indent,
  752.                min_level);
  753.   if (line->type == empty) {    /* for empty lines: nothing */
  754.      putc ('\n', out);
  755.      commanded_line_no++;
  756.      return;
  757.   }
  758.   else if (option_small || (!option_indent && *line->start == '#')) {
  759.      putc ('\n', out);
  760.      commanded_line_no++;
  761.   }
  762.   else
  763.      put_indent (out,
  764.                  line->indent + additional_indent);  /* starts new line */
  765.   assert (line->start != NULL);
  766.   fputs (line->start, out);
  767. #if debug
  768.   fprintf (stdout, "put:\"%s\"\n", line->start);
  769. #endif
  770. }
  771.  
  772. /********************** refinement_nr ************************************/
  773.  
  774. static int refinement_nr (name)
  775.   char *name;
  776. {
  777.   /* computes the number of a refinement from its name 'name'.
  778.      Uses r from 0 to r_pos. Returns the number or -1 if undeclared.
  779.      If the refinement is declared more than once an error message is
  780.      generated.
  781.   */
  782.   int i, match = -1, matches = 0;
  783.   assert (name != NULL);
  784.   for (i = 0; i < r_pos; i++)
  785.       if (!strcmp (name, r[i].name)) {
  786.          match = i;
  787.          matches++;
  788.       }
  789.   if (matches > 1)
  790.      error (Eref_multi_decl, r[match].name, refdecl_line (match));
  791.   return (match);
  792. }
  793.  
  794. /********************* Auxiliary functions ******************************/
  795.  
  796. static void copy_with_doubled_backslashes (string, copy)
  797.   char *string, *copy;
  798. {
  799.   /* copies the string string to the location copy. All backslash
  800.      characters (code 92) in string are copied twice, so for example
  801.      "back\slas\\h" is copied to "back\\slas\\\\h".
  802.      The purpose of this is to make the copy usable as a C string denoter,
  803.      in which the backslash is interpreted as an escape symbol.
  804.      No checks are made, thus there must be enough memory allocated
  805.      to make the copy.
  806.   */
  807.   assert (string != NULL);
  808.   assert (copy != NULL);
  809.   while (*string != 0) {
  810.      *copy = *string;
  811.      string++;
  812.      if (*copy == 92) {      /* is backslash ? */
  813.        *(copy + 1) = 92;     /* then put another and */
  814.        copy += 2;            /* proceed two bytes */
  815.      }
  816.      else                    /* else */
  817.        copy++;               /* proceed one byte */
  818.   }
  819.   *copy = 0;
  820. }
  821.  
  822.  
  823. static void do_expire (day, month, year)
  824.   int day, month, year;
  825. {
  826.   long act_time;
  827.   struct tm *t;
  828.   time (&act_time);
  829.   t = localtime (&act_time);
  830.   month--;   /* localtime uses months 0 - 11 ! */
  831.   if ((
  832.   t->tm_year > year || (t->tm_year == year && t->tm_mon > month) ||
  833.   (t->tm_year == year && t->tm_mon == month && t->tm_mday > day))
  834.   ) {
  835.      fprintf (stderr, "\n%s\n\n", Thas_expired[msg_type]);
  836.      exit (100);
  837.   }
  838. }
  839.  
  840.  
  841. static void reset_l_r_s ()
  842. {
  843.   /* Sets LINE_INFO- and REF_INFO-Arrays 'l' and 'r' into
  844.      their empty state.
  845.   */
  846.   int i;
  847.   for (i = 0; i <= r_pos; i++) { /* Alle Refinements loeschen */
  848.       r[i].name  = NULL;
  849.       r[i].calls = 0;
  850.   }
  851.   s = s_root;                    /* Zeilenspeicher loeschen */
  852.   l_pos = r_pos = old_level = 0;
  853. }
  854.  
  855.  
  856.