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 / debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-04  |  9.9 KB  |  415 lines

  1. /* GNU m4 -- A simple macro processor
  2.    Copyright (C) 1991, 1992, 1993 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. /* #if HAVE_FSTAT && HAVE_FILENO */
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. /* #endif */
  23.  
  24. #include "m4.h"
  25.  
  26. /* File for debugging output.  */
  27. static FILE *debug = NULL;
  28.  
  29. /* Obstack for trace messages.  */
  30. static struct obstack trace;
  31.  
  32. extern int expansion_level;
  33.  
  34. static void debug_set_file ();
  35.  
  36. /*----------------------------------.
  37. | Initialise the debugging module.  |
  38. `----------------------------------*/
  39.  
  40. void
  41. debug_init (void)
  42. {
  43.   debug_set_file (stderr);
  44.   obstack_init (&trace);
  45. }
  46.  
  47.  
  48. /*-----------------------------------------------------------------------.
  49. | Function to decode the debugging flags OPTS.  Used by main (-dXXX) and |
  50. | the builtin debugmode ().                         |
  51. `-----------------------------------------------------------------------*/
  52.  
  53. int
  54. debug_decode (char *opts)
  55. {
  56.   int level;
  57.  
  58.   if (opts == NULL || *opts == '\0')
  59.     level = DEBUG_TRACE_DEFAULT;
  60.   else
  61.     {
  62.       for (level = 0; *opts; opts++)
  63.     {
  64.       switch (*opts)
  65.         {
  66.         case 'a':
  67.           level |= DEBUG_TRACE_ARGS;
  68.           break;
  69.         case 'e':
  70.           level |= DEBUG_TRACE_EXPANSION;
  71.           break;
  72.         case 'q':
  73.           level |= DEBUG_TRACE_QUOTE;
  74.           break;
  75.         case 't':
  76.           level |= DEBUG_TRACE_ALL;
  77.           break;
  78.         case 'l':
  79.           level |= DEBUG_TRACE_LINE;
  80.           break;
  81.         case 'f':
  82.           level |= DEBUG_TRACE_FILE;
  83.           break;
  84.         case 'p':
  85.           level |= DEBUG_TRACE_PATH;
  86.           break;
  87.         case 'c':
  88.           level |= DEBUG_TRACE_CALL;
  89.           break;
  90.         case 'i':
  91.           level |= DEBUG_TRACE_INPUT;
  92.           break;
  93.         case 'x':
  94.           level |= DEBUG_TRACE_CALLID;
  95.           break;
  96.         case 'V':
  97.           level |= DEBUG_TRACE_VERBOSE;
  98.           break;
  99.         default:
  100.           return -1;
  101.         }
  102.     }
  103.     }
  104.  
  105.   /* This is to avoid screwing up the trace output due to changes in the
  106.      debug_level.  */
  107.  
  108.   obstack_free (&trace, obstack_finish (&trace));
  109.  
  110.   return level;
  111. }
  112.  
  113. /*------------------------------------------------------------------------.
  114. | Change the debug output stream to FP.  If the underlying file is the      |
  115. | same as stdout, use stdout instead so that debug messages appear in the |
  116. | correct relative position.                          |
  117. `------------------------------------------------------------------------*/
  118.  
  119. static void
  120. debug_set_file (FILE *fp)
  121. {
  122. /* #if HAVE_FSTAT && HAVE_FILENO */
  123.   struct stat stdout_stat, debug_stat;
  124. /* #endif */
  125.  
  126.   if (debug != NULL && debug != stderr && debug != stdout)
  127.     fclose (debug);
  128.   debug = fp;
  129.  
  130. /* #if HAVE_FSTAT && HAVE_FILENO */
  131.  
  132.   if (debug != NULL && debug != stdout)
  133.     {
  134.       if (fstat (fileno (stdout), &stdout_stat) < 0)
  135.     return;
  136.       if (fstat (fileno (debug), &debug_stat) < 0)
  137.     return;
  138.  
  139.       if (stdout_stat.st_ino == debug_stat.st_ino
  140.       && stdout_stat.st_dev == debug_stat.st_dev)
  141.     {
  142.       if (debug != stderr)
  143.         fclose (debug);
  144.       debug = stdout;
  145.     }
  146.     }
  147.  
  148. /* #endif HAVE_FSTAT && HAVE_FILENO */
  149. }
  150.  
  151. /*-------------------------------------------------------------------------.
  152. | Change the debug output to file NAME.  If NAME is NULL, debug output is  |
  153. | reverted to stderr, and if empty debug output is discarded.  Return TRUE |
  154. | iff the output stream was changed.                       |
  155. `-------------------------------------------------------------------------*/
  156.  
  157. boolean
  158. debug_set_output (char *name)
  159. {
  160.   FILE *fp;
  161.  
  162.   if (name == NULL)
  163.     debug_set_file (stderr);
  164.   else if (*name == '\0')
  165.     debug_set_file (NULL);
  166.   else
  167.     {
  168.       fp = fopen (name, "a");
  169.       if (fp == NULL)
  170.     return FALSE;
  171.  
  172.       debug_set_file (fp);
  173.     }
  174.   return TRUE;
  175. }
  176.  
  177. /*---------------------------------------------------------------------.
  178. | Generic function to do formatted output to the debug output stream.  |
  179. | Usage as for printf ().                           |
  180. `---------------------------------------------------------------------*/
  181.  
  182. void
  183. debug_print (va_alist)
  184.     va_dcl
  185. {
  186.   va_list args;
  187.   char *fmt;
  188.  
  189.   if (debug != NULL)
  190.     {
  191.       va_start (args);
  192.       fmt = va_arg (args, char *);
  193.       vfprintf (debug, fmt, args);
  194.       va_end (args);
  195.     }
  196. }
  197.  
  198. /*--------------------------------------------------------------------.
  199. | Print a one-line debug message, headed by "m4 debug".  Usage as for |
  200. | printf ().                                  |
  201. `--------------------------------------------------------------------*/
  202.  
  203. void
  204. debug_message (va_alist)
  205.     va_dcl
  206. {
  207.   va_list args;
  208.   char *fmt;
  209.  
  210.   if (debug != NULL)
  211.     {
  212.       fprintf (debug, "m4 debug: ");
  213.       if (debug_level & DEBUG_TRACE_FILE)
  214.     fprintf (debug, "%s: ", current_file);
  215.       if (debug_level & DEBUG_TRACE_LINE)
  216.     fprintf (debug, "%d: ", current_line);
  217.  
  218.       va_start (args);
  219.       fmt = va_arg (args, char *);
  220.       vfprintf (debug, fmt, args);
  221.       va_end (args);
  222.  
  223.       putc ('\n', debug);
  224.     }
  225. }
  226.  
  227. /* The rest of this file contains the functions for macro tracing output.
  228.    All tracing output for a macro call is collected on an obstack TRACE,
  229.    and printed whenever the line is complete.  This prevents tracing
  230.    output from interfering with other debug messages generated by the
  231.    various builtins.  */
  232.  
  233. /*----------------------------------------------------------------------.
  234. | Tracing output is formatted here, by a simplified printf-to-obstack   |
  235. | function trace_format ().  Understands only %s, %d, %l (optional left |
  236. | quote) and %r (optional right quote).                        |
  237. `----------------------------------------------------------------------*/
  238.  
  239. static void
  240. trace_format (va_alist)
  241.     va_dcl
  242. {
  243.   va_list args;
  244.   char *fmt;
  245.   char ch;
  246.  
  247.   int d;
  248.   char nbuf[32];
  249.   char *s;
  250.   int slen;
  251.   int maxlen;
  252.  
  253.   va_start (args);
  254.   fmt = va_arg (args, char *);
  255.  
  256.   while (TRUE)
  257.     {
  258.       while ((ch = *fmt++) != '\0' && ch != '%')
  259.     obstack_1grow (&trace, ch);
  260.  
  261.       if (ch == '\0')
  262.     break;
  263.  
  264.       maxlen = 0;
  265.       switch (*fmt++)
  266.     {
  267.     case 'S':
  268.       maxlen = max_debug_argument_length;
  269.       /* fall through */
  270.     case 's':
  271.       s = va_arg (args, char *);
  272.       break;
  273.     case 'l':
  274.       s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote : "";
  275.       break;
  276.     case 'r':
  277.       s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote : "";
  278.       break;
  279.     case 'd':
  280.       d = va_arg (args, int);
  281.       sprintf (nbuf, "%d", d);
  282.       s = nbuf;
  283.       break;
  284.     default:
  285.       s = "";
  286.       break;
  287.     }
  288.  
  289.       slen = strlen (s);
  290.       if (maxlen == 0 || maxlen > slen)
  291.     obstack_grow (&trace, s, slen);
  292.       else
  293.     {
  294.       obstack_grow (&trace, s, maxlen);
  295.       obstack_grow (&trace, "...", 3);
  296.     }
  297.     }
  298.  
  299.   va_end (args);
  300. }
  301.  
  302. /*------------------------------------------------------------------.
  303. | Format the standard header attached to all tracing output lines.  |
  304. `------------------------------------------------------------------*/
  305.  
  306. static void
  307. trace_header (int id)
  308. {
  309.   trace_format ("m4trace:");
  310.   if (debug_level & DEBUG_TRACE_FILE)
  311.     trace_format ("%s:", current_file);
  312.   if (debug_level & DEBUG_TRACE_LINE)
  313.     trace_format ("%d:", current_line);
  314.   trace_format (" -%d- ", expansion_level);
  315.   if (debug_level & DEBUG_TRACE_CALLID)
  316.     trace_format ("id %d: ", id);
  317. }
  318.  
  319. /*----------------------------------------------------.
  320. | Print current tracing line, and clear the obstack.  |
  321. `----------------------------------------------------*/
  322.  
  323. static void
  324. trace_flush (void)
  325. {
  326.   char *line;
  327.  
  328.   obstack_1grow (&trace, '\0');
  329.   line = obstack_finish (&trace);
  330.   debug_print ("%s\n", line);
  331.   obstack_free (&trace, line);
  332. }
  333.  
  334. /*-------------------------------------------------------------.
  335. | Do pre-argument-collction tracing for macro NAME.  Used from |
  336. | expand_macro ().                           |
  337. `-------------------------------------------------------------*/
  338.  
  339. void
  340. trace_prepre (char *name, int id)
  341. {
  342.   trace_header (id);
  343.   trace_format ("%s ...", name);
  344.   trace_flush ();
  345. }
  346.  
  347. /*-----------------------------------------------------------------------.
  348. | Format the parts of a trace line, that can be made before the macro is |
  349. | actually expanded.  Used from expand_macro ().             |
  350. `-----------------------------------------------------------------------*/
  351.  
  352. void
  353. trace_pre (char *name, int id, int argc, token_data **argv)
  354. {
  355.   int i;
  356.   const builtin *bp;
  357.  
  358.   trace_header (id);
  359.   trace_format ("%s", name);
  360.  
  361.   if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
  362.     {
  363.       trace_format ("(");
  364.  
  365.       for (i = 1; i < argc; i++)
  366.     {
  367.       if (i != 1)
  368.         trace_format (", ");
  369.  
  370.       switch (TOKEN_DATA_TYPE (argv[i]))
  371.         {
  372.         case TOKEN_TEXT:
  373.           trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
  374.           break;
  375.         case TOKEN_FUNC:
  376.           bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
  377.           if (bp == NULL)
  378.         internal_error ("builtin not found in builtin table! (trace_pre ())");
  379.           trace_format ("<%s>", bp->name);
  380.           break;
  381.         default:
  382.           internal_error ("Bad token data type (trace_pre ())");
  383.           break;
  384.         }
  385.  
  386.     }
  387.       trace_format (")");
  388.     }
  389.  
  390.   if (debug_level & DEBUG_TRACE_CALL)
  391.     {
  392.       trace_format (" -> ???");
  393.       trace_flush ();
  394.     }
  395. }
  396.  
  397. /*-------------------------------------------------------------------.
  398. | Format the final part of a trace line and print it all.  Used from |
  399. | expand_macro ().                             |
  400. `-------------------------------------------------------------------*/
  401.  
  402. void
  403. trace_post (char *name, int id, int argc, token_data **argv, char *expanded)
  404. {
  405.   if (debug_level & DEBUG_TRACE_CALL)
  406.     {
  407.       trace_header (id);
  408.       trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
  409.     }
  410.  
  411.   if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
  412.     trace_format (" -> %l%S%r", expanded);
  413.   trace_flush ();
  414. }
  415.