home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / m4-1.1-src.lha / src / amiga / m4-1.1 / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-06  |  6.4 KB  |  247 lines

  1. /* GNU m4 -- A simple macro processor
  2.    Copyright (C) 1989, 90, 91, 92, 93 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. #include "m4.h"
  20.  
  21. #ifdef HAVE_TMPFILE
  22. extern FILE *tmpfile ();
  23. #endif
  24.  
  25. /* Output functions.  Most of the complexity is for handling cpp like
  26.    sync lines.
  27.   
  28.    This code is fairly entangled with the code in input.c, and maybe it
  29.    belongs there?  */
  30.  
  31. /* Number of input line we are generating output for.  */
  32. int output_current_line;
  33.  
  34. /* Current output stream.  */
  35. static FILE *output;
  36.  
  37. /* Table of diversion files.  */
  38. static FILE **divtab;
  39.  
  40.  
  41. /*-------------------------------------------------------------------------.
  42. | Output initialisation.  It handles allocation of memory for diversions.  |
  43. | This is done dynamically, to allow customisation of the number of       |
  44. | available diversions.                               |
  45. `-------------------------------------------------------------------------*/
  46.  
  47. void
  48. output_init (void)
  49. {
  50.   int i;
  51.  
  52.   output = stdout;
  53.  
  54.   divtab = (FILE **) xmalloc (ndiversion * sizeof (FILE *));
  55.   for (i = 0; i < ndiversion; i++)
  56.     divtab[i] = NULL;
  57.   divtab[0] = stdout;
  58. }
  59.  
  60.  
  61. /*-------------------------------------------------------------------------.
  62. | Output TEXT to either an obstack or a file.  If OBS is NULL, and there   |
  63. | is no output file, the text is discarded.                   |
  64. |                                        |
  65. | If we are generating sync lines, the output have to be examined, because |
  66. | we need to know how much output each input line generates.  In general,  |
  67. | sync lines are output whenever a single input lines generates several       |
  68. | output lines, or when several input lines does not generate any output.  |
  69. `-------------------------------------------------------------------------*/
  70.  
  71. void
  72. shipout_text (struct obstack *obs, char *text)
  73. {
  74.   static boolean start_of_output_line = TRUE;
  75.  
  76.   if (obs != NULL)
  77.     {                /* output to obstack OBS */
  78.       obstack_grow (obs, text, strlen (text));
  79.       return;
  80.     }
  81.   if (output == NULL)        /* discard TEXT */
  82.     return;
  83.  
  84.   if (!sync_output)
  85.     fputs (text, output);
  86.   else
  87.     for (; *text; text++)
  88.       {
  89.     if (start_of_output_line)
  90.       {
  91.         start_of_output_line = FALSE;
  92.         output_current_line++;
  93.  
  94. #ifdef DEBUG_OUTPUT
  95.         printf ("DEBUG: cur %d, cur out %d\n",
  96.             current_line, output_current_line);
  97. #endif
  98.  
  99.         /* Output a `#line NUM' synchronisation directive if needed.
  100.            If output_current_line was previously given a negative
  101.            value (invalidated), rather output `#line NUM "FILE"'.  */
  102.  
  103.         if (output_current_line != current_line)
  104.           {
  105.         if (output != NULL)
  106.           {
  107.             fprintf (output, "#line %d", current_line);
  108.             if (output_current_line < 1)
  109.               fprintf (output, " \"%s\"", current_file);
  110.             putc ('\n', output);
  111.           }
  112.         output_current_line = current_line;
  113.           }
  114.       }
  115.     putc (*text, output);
  116.     if (*text == '\n')
  117.       start_of_output_line = TRUE;
  118.       }
  119. }
  120.  
  121. /* Functions for use by diversions.  */
  122.  
  123. #ifndef HAVE_TMPFILE
  124.  
  125. /* Implement tmpfile(3) for non-USG systems.  */
  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.  
  159. #endif /* not HAVE_MKSTEMP */
  160.  
  161. #endif /* not HAVE_TMPFILE */
  162.  
  163. /*------------------------------------------------------------------------.
  164. | Make a file for diversion DIVNUM, and install it in the diversion table |
  165. | "divtab".  The file is opened read-write, so we can unlink it          |
  166. | immediately.                                  |
  167. `------------------------------------------------------------------------*/
  168.  
  169. void
  170. make_diversion (int divnum)
  171. {
  172.   if (output != NULL)
  173.     fflush (output);
  174.  
  175.   if (divnum < 0 || divnum >= ndiversion)
  176.     {
  177.       output = NULL;
  178.       return;
  179.     }
  180.  
  181.   if (divtab[divnum] == NULL)
  182.     {
  183.       divtab[divnum] = tmpfile ();
  184.       if (divtab[divnum] == NULL)
  185.     fatal ("can't create file for diversion: %s", syserr ());
  186.     }
  187.   output = divtab[divnum];
  188.   output_current_line = -1;
  189. }
  190.  
  191. /*-------------------------------------------------------------------.
  192. | Insert a FILE into the current output file, in tha same manner     |
  193. | diversions are handled.  This allows files to be included, without |
  194. | having them rescanned by m4.                         |
  195. `-------------------------------------------------------------------*/
  196.  
  197. void
  198. insert_file (FILE *file)
  199. {
  200.   int ch;
  201.  
  202.   while ((ch = getc (file)) != EOF)
  203.     putc (ch, output);
  204. }
  205.  
  206. /*-------------------------------------------------------------------------.
  207. | Insert diversion number DIVNUM into the current output file.  The       |
  208. | diversion is NOT placed on the expansion obstack, because it must not be |
  209. | rescanned.  When the file is closed, it is deleted by the system.       |
  210. `-------------------------------------------------------------------------*/
  211.  
  212. void
  213. insert_diversion (int divnum)
  214. {
  215.   FILE *div;
  216.  
  217.   if (divnum < 0 || divnum >= ndiversion)
  218.     return;
  219.  
  220.   div  = divtab[divnum];
  221.   if (div == NULL || div == output)
  222.     return;
  223.  
  224.   if (output != NULL)
  225.     {
  226.       rewind (div);
  227.       insert_file (div);
  228.       output_current_line = -1;
  229.     }
  230.   fclose (div);
  231.   divtab[divnum] = NULL;
  232. }
  233.  
  234. /*-------------------------------------------------------------------------.
  235. | Get back all diversions.  This is done just before exiting from main (), |
  236. | and from m4_undivert (), if called without arguments.               |
  237. `-------------------------------------------------------------------------*/
  238.  
  239. void
  240. undivert_all (void)
  241. {
  242.   int divnum;
  243.  
  244.   for (divnum = 1; divnum < ndiversion; divnum++)
  245.     insert_diversion (divnum);
  246. }
  247.