home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / m4-1.0.3 / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  5.4 KB  |  243 lines

  1. /*
  2.  * GNU m4 -- A simple macro processor
  3.  * Copyright (C) 1989-1992 Free Software Foundation, Inc.
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include "m4.h"
  21.  
  22. /*
  23.  * Output functions.  Most of the complexity is for handling cpp like
  24.  * sync lines.
  25.  *
  26.  * This code is fairly entangled with the code in input.c, and maybe it
  27.  * belongs there?
  28.  */
  29.  
  30. /* Number of input line we are generating output for.  */
  31. int output_current_line;
  32.  
  33. /* Current output stream.  */
  34. static FILE *output;
  35.  
  36. /* Table of diversion files.  */
  37. static FILE **divtab;
  38.  
  39.  
  40. /*
  41.  * Output initialisation.  It handles allocation of memory for
  42.  * diversions.  This is done dynamically, to allow customisation of the
  43.  * number of available diversions.
  44.  */
  45. void
  46. output_init (void)
  47. {
  48.   int i;
  49.  
  50.   output = stdout;
  51.  
  52.   divtab = (FILE **) xmalloc (ndiversion * sizeof (FILE *));
  53.   for (i = 0; i < ndiversion; i++)
  54.     divtab[i] = NULL;
  55.   divtab[0] = stdout;
  56. }
  57.  
  58.  
  59. /*
  60.  * Output TEXT to either an obstack or a file.  If OBS is NULL, and there
  61.  * is no output file, the text is discarded.
  62.  *
  63.  * If we are generating sync lines, the output have to be examined,
  64.  * because we need to know how much output each input line generates.
  65.  * In general, sync lines are output whenever a single input lines
  66.  * generates several output lines, or when several input lines does not
  67.  * generate any output.
  68.  */
  69. void
  70. shipout_text (struct obstack *obs, char *text)
  71. {
  72.   static boolean start_of_output_line = TRUE;
  73.  
  74.   if (obs != NULL)
  75.     {                /* output to obstack OBS */
  76.       obstack_grow (obs, text, strlen (text));
  77.       return;
  78.     }
  79.   if (output == NULL)        /* discard TEXT */
  80.     return;
  81.  
  82.   if (!sync_output)
  83.     fputs (text, output);
  84.   else
  85.     for (; *text; text++)
  86.       {
  87.     if (start_of_output_line)
  88.       {
  89.         start_of_output_line = FALSE;
  90.         output_current_line++;
  91.  
  92. #ifdef DEBUG_OUTPUT
  93.         printf ("DEBUG: cur %d, cur out %d\n",
  94.             current_line, output_current_line);
  95. #endif
  96.  
  97.         /* Output a `#line NUM' synchronisation directive if needed.
  98.            If output_current_line was previously given a negative
  99.            value (invalidated), rather output `#line NUM "FILE"'.  */
  100.  
  101.         if (output_current_line != current_line)
  102.           {
  103.         if (output != NULL)
  104.           {
  105.             fprintf (output, "#line %d", current_line);
  106.             if (output_current_line < 1)
  107.               fprintf (output, " \"%s\"", current_file);
  108.             putc ('\n', output);
  109.           }
  110.         output_current_line = current_line;
  111.           }
  112.       }
  113.     putc (*text, output);
  114.     if (*text == '\n')
  115.       start_of_output_line = TRUE;
  116.       }
  117. }
  118.  
  119. /*
  120.  * Functions for use by diversions.
  121.  */
  122. #ifndef HAVE_TMPFILE
  123. /*
  124.  * Implement tmpfile(3) for non-USG systems.
  125.  */
  126. static int mkstemp ();
  127. extern int unlink ();
  128.  
  129. static FILE *
  130. tmpfile (void)
  131. {
  132.   char buf[32];
  133.   int fd;
  134.  
  135.   strcpy (buf, "/tmp/m4XXXXXX");
  136.   fd = mkstemp (buf);
  137.   if (fd < 0)
  138.     return NULL;
  139.  
  140.   unlink (buf);
  141.   return fdopen (fd, "w+");
  142. }
  143.  
  144. #ifndef HAVE_MKSTEMP
  145. /*
  146.  * This implementation of mkstemp(3) does not avoid any races, but its
  147.  * there.
  148.  */
  149. #include <sys/types.h>
  150. #include <fcntl.h>
  151.  
  152. static int
  153. mkstemp (char *tmpl)
  154. {
  155.   mktemp (tmpl);
  156.   return open (tmpl, O_RDWR | O_TRUNC | O_CREAT, 0600);
  157. }
  158. #endif /* not HAVE_MKSTEMP */
  159. #endif /* not HAVE_TMPFILE */
  160.  
  161. /*
  162.  * Make a file for diversion DIVNUM, and install it in the diversion
  163.  * table "divtab".  The file is opened read-write, so we can unlink it
  164.  * immediately.
  165.  */
  166. void
  167. make_diversion (int divnum)
  168. {
  169.   if (output != NULL)
  170.     fflush (output);
  171.  
  172.   if (divnum < 0 || divnum >= ndiversion)
  173.     {
  174.       output = NULL;
  175.       return;
  176.     }
  177.  
  178.   if (divtab[divnum] == NULL)
  179.     {
  180.       divtab[divnum] = tmpfile ();
  181.       if (divtab[divnum] == NULL)
  182.     fatal ("can't create file for diversion: %s", syserr ());
  183.     }
  184.   output = divtab[divnum];
  185.   output_current_line = -1;
  186. }
  187.  
  188. /*
  189.  *
  190.  * Insert a FILE into the current output file, in tha same manner
  191.  * diversions are handled.  This allows files to be included, without
  192.  * having them rescanned by m4.
  193.  */
  194.  
  195. void
  196. insert_file (FILE *file)
  197. {
  198.   int ch;
  199.  
  200.   while ((ch = getc (file)) != EOF)
  201.     putc (ch, output);
  202. }
  203.  
  204. /*
  205.  * Insert diversion number DIVNUM into the current output file.  The
  206.  * diversion is NOT placed on the expansion obstack, because it must not
  207.  * be rescanned.  When the file is closed, it is deleted by the system.
  208.  */
  209. void
  210. insert_diversion (int divnum)
  211. {
  212.   FILE *div;
  213.  
  214.   if (divnum < 0 || divnum >= ndiversion)
  215.     return;
  216.  
  217.   div  = divtab[divnum];
  218.   if (div == NULL || div == output)
  219.     return;
  220.  
  221.   if (output != NULL)
  222.     {
  223.       rewind (div);
  224.       insert_file (div);
  225.       output_current_line = -1;
  226.     }
  227.   fclose (div);
  228.   divtab[divnum] = NULL;
  229. }
  230.  
  231. /*
  232.  * Get back all diversions.  This is done just before exiting from
  233.  * main (), and from m4_undivert (), if called without arguments.
  234.  */
  235. void
  236. undivert_all (void)
  237. {
  238.   int divnum;
  239.  
  240.   for (divnum = 1; divnum < ndiversion; divnum++)
  241.     insert_diversion (divnum);
  242. }
  243.