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 / builtin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-03  |  45.2 KB  |  1,691 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. /* Code for all builtin macros, initialisation of symbol table, and
  20.    expansion of user defined macros.  */
  21.  
  22. #include "m4.h"
  23. #ifndef size_t
  24. #include <sys/types.h>
  25. #endif
  26. #include "regex.h"
  27.  
  28. #define ARG(i)    (argc > (i) ? TOKEN_DATA_TEXT (argv[i]) : "")
  29.  
  30. /* Initialisation of builtin and predefined macros.  The table
  31.    "builtin_tab" is both used for initialisation, and by the "builtin"
  32.    builtin.  */
  33.  
  34. #ifndef __STDC__
  35. #define DECLARE(name) static void name ()
  36. #else
  37. #define DECLARE(name) static void name (struct obstack *, int, token_data **)
  38. #endif
  39.  
  40. DECLARE (m4___file__);
  41. DECLARE (m4___line__);
  42. DECLARE (m4_builtin);
  43. DECLARE (m4_changecom);
  44. DECLARE (m4_changequote);
  45. DECLARE (m4_debugmode);
  46. DECLARE (m4_debugfile);
  47. DECLARE (m4_decr);
  48. DECLARE (m4_define);
  49. DECLARE (m4_defn);
  50. DECLARE (m4_divert);
  51. DECLARE (m4_divnum);
  52. DECLARE (m4_dnl);
  53. DECLARE (m4_dumpdef);
  54. DECLARE (m4_errprint);
  55. DECLARE (m4_esyscmd);
  56. DECLARE (m4_eval);
  57. DECLARE (m4_format);
  58. DECLARE (m4_ifdef);
  59. DECLARE (m4_ifelse);
  60. DECLARE (m4_include);
  61. DECLARE (m4_incr);
  62. DECLARE (m4_index);
  63. DECLARE (m4_indir);
  64. DECLARE (m4_len);
  65. DECLARE (m4_m4exit);
  66. DECLARE (m4_m4wrap);
  67. DECLARE (m4_maketemp);
  68. DECLARE (m4_patsubst);
  69. DECLARE (m4_popdef);
  70. DECLARE (m4_pushdef);
  71. DECLARE (m4_regexp);
  72. DECLARE (m4_shift);
  73. DECLARE (m4_sinclude);
  74. DECLARE (m4_substr);
  75. DECLARE (m4_syscmd);
  76. DECLARE (m4_sysval);
  77. DECLARE (m4_traceoff);
  78. DECLARE (m4_traceon);
  79. DECLARE (m4_translit);
  80. DECLARE (m4_undefine);
  81. DECLARE (m4_undivert);
  82.  
  83. #undef DECLARE
  84.  
  85. static builtin
  86. builtin_tab[] =
  87. {
  88.  
  89.   /* name        gnu    args    blind    function */
  90.  
  91.   { "__file__",        TRUE,    FALSE,    FALSE,    m4___file__ },
  92.   { "__line__",        TRUE,    FALSE,    FALSE,    m4___line__ },
  93.   { "builtin",        TRUE,    FALSE,    TRUE,    m4_builtin },
  94.   { "changecom",    FALSE,    FALSE,    FALSE,    m4_changecom },
  95.   { "changequote",    FALSE,    FALSE,    FALSE,    m4_changequote },
  96.   { "debugmode",    TRUE,    FALSE,    FALSE,    m4_debugmode },
  97.   { "debugfile",    TRUE,    FALSE,    FALSE,    m4_debugfile },
  98.   { "decr",        FALSE,    FALSE,    TRUE,    m4_decr },
  99.   { "define",        FALSE,    TRUE,    TRUE,    m4_define },
  100.   { "defn",        FALSE,    FALSE,    TRUE,    m4_defn },
  101.   { "divert",        FALSE,    FALSE,    FALSE,    m4_divert },
  102.   { "divnum",        FALSE,    FALSE,    FALSE,    m4_divnum },
  103.   { "dnl",        FALSE,    FALSE,    FALSE,    m4_dnl },
  104.   { "dumpdef",        FALSE,    FALSE,    FALSE,    m4_dumpdef },
  105.   { "errprint",        FALSE,    FALSE,    FALSE,    m4_errprint },
  106.   { "esyscmd",        TRUE,    FALSE,    TRUE,    m4_esyscmd },
  107.   { "eval",        FALSE,    FALSE,    TRUE,    m4_eval },
  108.   { "format",        TRUE,    FALSE,    FALSE,    m4_format },
  109.   { "ifdef",        FALSE,    FALSE,    TRUE,    m4_ifdef },
  110.   { "ifelse",        FALSE,    FALSE,    TRUE,    m4_ifelse },
  111.   { "include",        FALSE,    FALSE,    TRUE,    m4_include },
  112.   { "incr",        FALSE,    FALSE,    TRUE,    m4_incr },
  113.   { "index",        FALSE,    FALSE,    TRUE,    m4_index },
  114.   { "indir",        TRUE,    FALSE,    FALSE,    m4_indir },
  115.   { "len",        FALSE,    FALSE,    TRUE,    m4_len },
  116.   { "m4exit",        FALSE,    FALSE,    FALSE,    m4_m4exit },
  117.   { "m4wrap",        FALSE,    FALSE,    FALSE,    m4_m4wrap },
  118.   { "maketemp",        FALSE,    FALSE,    TRUE,    m4_maketemp },
  119.   { "patsubst",        TRUE,    FALSE,    TRUE,    m4_patsubst },
  120.   { "popdef",        FALSE,    FALSE,    TRUE,    m4_popdef },
  121.   { "pushdef",        FALSE,    TRUE,    TRUE,    m4_pushdef },
  122.   { "regexp",        TRUE,    FALSE,    TRUE,    m4_regexp },
  123.   { "shift",        FALSE,    FALSE,    FALSE,    m4_shift },
  124.   { "sinclude",        FALSE,    FALSE,    TRUE,    m4_sinclude },
  125.   { "substr",        FALSE,    FALSE,    TRUE,    m4_substr },
  126.   { "syscmd",        FALSE,    FALSE,    TRUE,    m4_syscmd },
  127.   { "sysval",        FALSE,    FALSE,    FALSE,    m4_sysval },
  128.   { "traceoff",        FALSE,    FALSE,    FALSE,    m4_traceoff },
  129.   { "traceon",        FALSE,    FALSE,    FALSE,    m4_traceon },
  130.   { "translit",        FALSE,    FALSE,    TRUE,    m4_translit },
  131.   { "undefine",        FALSE,    FALSE,    TRUE,    m4_undefine },
  132.   { "undivert",        FALSE,    FALSE,    FALSE,    m4_undivert },
  133.  
  134.   { 0,            FALSE,    FALSE,    FALSE,    0 },
  135. };
  136.  
  137. static predefined const
  138. predefined_tab[] =
  139. {
  140.   { "unix",    "__unix__",    "" },
  141.   { NULL,    "__gnu__",    "" },
  142.  
  143.   { NULL,    NULL,        NULL },
  144. };
  145.  
  146. /* The number of the currently active diversion.  */
  147. static int current_diversion;
  148.  
  149.  
  150. /*----------------------------------------.
  151. | Prefix names of all builtins by "m4_".  |
  152. `----------------------------------------*/
  153.  
  154. void
  155. prefix_all_builtins (void)
  156. {
  157.   static int already_prefixed = 0;
  158.  
  159.   char *string;
  160.   builtin *cursor;
  161.   builtin *limit;
  162.  
  163.   if (already_prefixed)
  164.     return;
  165.  
  166.   limit = builtin_tab + (sizeof (builtin_tab) / sizeof (builtin));
  167.   for (cursor = builtin_tab; cursor < limit; cursor++)
  168.     {
  169.       string = xmalloc (strlen (cursor->name) + 4);
  170.       strcpy (string, "m4_");
  171.       strcat (string, cursor->name);
  172.       cursor->name = string;
  173.     }
  174.  
  175.   already_prefixed = 1;
  176. }
  177.  
  178. /*----------------------------------------.
  179. | Find the builtin, which lives on ADDR.  |
  180. `----------------------------------------*/
  181.  
  182. const builtin *
  183. find_builtin_by_addr (builtin_func *func)
  184. {
  185.   const builtin *bp;
  186.  
  187.   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
  188.     if (bp->func == func)
  189.       return bp;
  190.   return NULL;
  191. }
  192.  
  193. /*-----------------------------------.
  194. | Find the builtin, which has NAME.  |
  195. `-----------------------------------*/
  196.  
  197. const builtin *
  198. find_builtin_by_name (char *name)
  199. {
  200.   const builtin *bp;
  201.  
  202.   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
  203.     if (strcmp (bp->name, name) == 0)
  204.       return bp;
  205.   return NULL;
  206. }
  207.  
  208.  
  209. /*-------------------------------------------------------------------------.
  210. | Install a builtin macro with name NAME, bound to the C function given in |
  211. | BP.  MODE is SYMBOL_INSERT or SYMBOL_PUSHDEF.  TRACED defines wheather   |
  212. | NAME is to be traced.                               |
  213. `-------------------------------------------------------------------------*/
  214.  
  215. static void
  216. define_builtin (const char *name, const builtin *bp, symbol_lookup mode,
  217.         boolean traced)
  218. {
  219.   symbol *sym;
  220.  
  221.   sym = lookup_symbol (name, mode);
  222.   SYMBOL_TYPE (sym) = TOKEN_FUNC;
  223.   SYMBOL_MACRO_ARGS (sym) = bp->groks_macro_args;
  224.   SYMBOL_BLIND_NO_ARGS (sym) = bp->blind_if_no_args;
  225.   SYMBOL_FUNC (sym) = bp->func;
  226.   SYMBOL_TRACED (sym) = traced;
  227. }
  228.  
  229. /*-------------------------------------------------------------------------.
  230. | Define a predefined or user-defined macro, with name NAME, and expansion |
  231. | TEXT.  MODE destinguishes between the "define" and the "pushdef" case.   |
  232. | It is also used from main ().                           |
  233. `-------------------------------------------------------------------------*/
  234.  
  235. void
  236. define_user_macro (const char *name, const char *text, symbol_lookup mode)
  237. {
  238.   symbol *s;
  239.  
  240.   s = lookup_symbol (name, mode);
  241.   if (SYMBOL_TYPE (s) == TOKEN_TEXT)
  242.     xfree (SYMBOL_TEXT (s));
  243.  
  244.   SYMBOL_TYPE (s) = TOKEN_TEXT;
  245.   SYMBOL_TEXT (s) = xstrdup (text);
  246. }
  247.  
  248. /*-----------------------------------------------.
  249. | Initialise all builtin and predefined macros.     |
  250. `-----------------------------------------------*/
  251.  
  252. void
  253. builtin_init (void)
  254. {
  255.   const builtin *bp;
  256.   const predefined *pp;
  257.  
  258.   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
  259.     {
  260.       if (!(no_gnu_extensions && bp->gnu_extension))
  261.     define_builtin (bp->name, bp, SYMBOL_INSERT, FALSE);
  262.     }
  263.  
  264.   for (pp = &predefined_tab[0]; pp->func != NULL; pp++)
  265.     {
  266.       if (no_gnu_extensions)
  267.     {
  268.       if (pp->unix_name != NULL)
  269.         define_user_macro (pp->unix_name, pp->func, SYMBOL_INSERT);
  270.     }
  271.       else
  272.     {
  273.       if (pp->gnu_name != NULL)
  274.         define_user_macro (pp->gnu_name, pp->func, SYMBOL_INSERT);
  275.     }
  276.     }
  277.  
  278.   current_diversion = 0;
  279. }
  280.  
  281. /*------------------------------------------------------------------------.
  282. | Give friendly warnings if a builtin macro is passed an inappropriate      |
  283. | number of arguments.  NAME is macro name for messages, ARGC is actual      |
  284. | number of arguments, MIN is the minimum number of acceptable arguments, |
  285. | negative if not applicable, MAX is the maximum number, negative if not  |
  286. | applicable.                                  |
  287. `------------------------------------------------------------------------*/
  288.  
  289. static boolean
  290. bad_argc (token_data *name, int argc, int min, int max)
  291. {
  292.   boolean isbad = FALSE;
  293.  
  294.   if (min > 0 && argc < min)
  295.     {
  296.       if (!suppress_warnings)
  297.     warning ("too few arguments to built-in `%s'", TOKEN_DATA_TEXT (name));
  298.       isbad = TRUE;
  299.     }
  300.   else if (max > 0 && argc > max && !suppress_warnings)
  301.     warning ("excess arguments to built-in `%s' ignored",
  302.          TOKEN_DATA_TEXT (name));
  303.  
  304.   return isbad;
  305. }
  306.  
  307. /*--------------------------------------------------------------------------.
  308. | The function numeric_arg () converts ARG to an int pointed to by VALUEP.  |
  309. | If the conversion fails, print error message for macro MACRO.  Return        |
  310. | TRUE iff conversion succeeds.                            |
  311. `--------------------------------------------------------------------------*/
  312.  
  313. static boolean
  314. numeric_arg (token_data *macro, char *arg, int *valuep)
  315. {
  316.   if (sscanf (arg, "%d", valuep) != 1)
  317.     {
  318.       m4error ("non-numeric argument to built-in `%s'", TOKEN_DATA_TEXT (macro));
  319.       return FALSE;
  320.     }
  321.   return TRUE;
  322. }
  323.  
  324. /*------------------------------------------------------------------------.
  325. | The function ntoa () converts VALUE to a signed ascii representation in |
  326. | radix RADIX.                                  |
  327. `------------------------------------------------------------------------*/
  328.  
  329. /* Digits for number to ascii conversions.  */
  330. static char const digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  331.  
  332. static char *
  333. ntoa (register int value, int radix)
  334. {
  335.   boolean negative;
  336.   unsigned int uvalue;
  337.   static char str[256];
  338.   register char *s = &str[sizeof str];
  339.  
  340.   *--s = '\0';
  341.  
  342.   if (value < 0)
  343.     {
  344.       negative = TRUE;
  345.       uvalue = (unsigned int) -value;
  346.     }
  347.   else
  348.     {
  349.       negative = FALSE;
  350.       uvalue = (unsigned int) value;
  351.     }
  352.  
  353.   do
  354.     {
  355.       *--s = digits[uvalue % radix];
  356.       uvalue /= radix;
  357.     }
  358.   while (uvalue > 0);
  359.  
  360.   if (negative)
  361.     *--s = '-';
  362.   return s;
  363. }
  364.  
  365. /*----------------------------------------------------------------------.
  366. | Format an int VAL, and stuff it into an obstack OBS.  Used for macros |
  367. | expanding to numbers.                                |
  368. `----------------------------------------------------------------------*/
  369.  
  370. static void
  371. shipout_int (struct obstack *obs, int val)
  372. {
  373.   char *s;
  374.  
  375.   s = ntoa (val, 10);
  376.   obstack_grow (obs, s, strlen (s));
  377. }
  378.  
  379. /*----------------------------------------------------------------------.
  380. | Print ARGC arguments from the table ARGV to obstack OBS, separated by |
  381. | SEP, and quoted by the current quotes, if QUOTED is TRUE.            |
  382. `----------------------------------------------------------------------*/
  383.  
  384. static void
  385. dump_args (struct obstack *obs, int argc, token_data **argv,
  386.        char *sep, boolean quoted)
  387. {
  388.   int i;
  389.   int len = strlen (sep);
  390.  
  391.   for (i = 1; i < argc; i++)
  392.     {
  393.       if (i > 1)
  394.     obstack_grow (obs, sep, len);
  395.       if (quoted)
  396.     obstack_grow (obs, lquote, len_lquote);
  397.       obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]),
  398.             strlen (TOKEN_DATA_TEXT (argv[i])));
  399.       if (quoted)
  400.     obstack_grow (obs, rquote, len_rquote);
  401.     }
  402.  
  403. }
  404.  
  405. /* The rest of this file is code for builtins and expansion of user
  406.    defined macros.  All the functions for builtins have a prototype as:
  407.    
  408.     void m4_MACRONAME (struct obstack *obs, int argc, char *argv[]);
  409.    
  410.    The function are expected to leave their expansion on the obstack OBS,
  411.    as an unfinished object.  ARGV is a table of ARGC pointers to the
  412.    individual arguments to the macro.  Please note that in general
  413.    argv[argc] != NULL.  */
  414.  
  415. /* The first section are macros for definining, undefining, examining,
  416.    changing, ... other macros.  */
  417.  
  418. /*-------------------------------------------------------------------------.
  419. | The function define_macro is common for the builtins "define",       |
  420. | "undefine", "pushdef" and "popdef".  ARGC and ARGV is as for the caller, |
  421. | and MODE argument determines how the macro name is entered into the       |
  422. | symbol table.                                   |
  423. `-------------------------------------------------------------------------*/
  424.  
  425. static void
  426. define_macro (int argc, token_data **argv, symbol_lookup mode)
  427. {
  428.   const builtin *bp;
  429.  
  430.   if (bad_argc (argv[0], argc, 2, 3))
  431.     return;
  432.  
  433.   if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
  434.     return;
  435.  
  436.   if (argc == 2)
  437.     {
  438.       define_user_macro (ARG (1), "", mode);
  439.       return;
  440.     }
  441.  
  442.   switch (TOKEN_DATA_TYPE (argv[2]))
  443.     {
  444.     case TOKEN_TEXT:
  445.       define_user_macro (ARG (1), ARG (2), mode);
  446.       break;
  447.     case TOKEN_FUNC:
  448.       bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[2]));
  449.       if (bp == NULL)
  450.     return;
  451.       else
  452.     define_builtin (ARG (1), bp, mode, TOKEN_DATA_FUNC_TRACED (argv[2]));
  453.       break;
  454.     default:
  455.       internal_error ("Bad token data type in define_macro ()");
  456.       break;
  457.     }
  458.   return;
  459. }
  460.  
  461. static void
  462. m4_define (struct obstack *obs, int argc, token_data **argv)
  463. {
  464.   define_macro (argc, argv, SYMBOL_INSERT);
  465. }
  466.  
  467. static void
  468. m4_undefine (struct obstack *obs, int argc, token_data **argv)
  469. {
  470.   if (bad_argc (argv[0], argc, 2, 2))
  471.     return;
  472.   lookup_symbol (ARG (1), SYMBOL_DELETE);
  473. }
  474.  
  475. static void
  476. m4_pushdef (struct obstack *obs, int argc, token_data **argv)
  477. {
  478.   define_macro (argc, argv,  SYMBOL_PUSHDEF);
  479. }
  480.  
  481. static void
  482. m4_popdef (struct obstack *obs, int argc, token_data **argv)
  483. {
  484.   if (bad_argc (argv[0], argc, 2, 2))
  485.     return;
  486.   lookup_symbol (ARG (1), SYMBOL_POPDEF);
  487. }
  488.  
  489.  
  490. /*---------------------.
  491. | Conditionals of m4.  |
  492. `---------------------*/
  493.  
  494. static void
  495. m4_ifdef (struct obstack *obs, int argc, token_data **argv)
  496. {
  497.   symbol *s;
  498.   char *result;
  499.  
  500.   if (bad_argc (argv[0], argc, 3, 4))
  501.     return;
  502.   s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
  503.  
  504.   if (s != NULL)
  505.     result = ARG (2);
  506.   else if (argc == 4)
  507.     result = ARG (3);
  508.   else
  509.     result = NULL;
  510.  
  511.   if (result != NULL)
  512.     obstack_grow (obs, result, strlen (result));
  513. }
  514.  
  515. static void
  516. m4_ifelse (struct obstack *obs, int argc, token_data **argv)
  517. {
  518.   char *result;
  519.   token_data *argv0;
  520.  
  521.   if (argc == 2)
  522.     return;
  523.  
  524.   if (bad_argc (argv[0], argc, 4, -1))
  525.     return;
  526.   else
  527.     /* Diagnose excess arguments if 5, 8, 11, etc., actual arguments.  */
  528.     bad_argc (argv[0], (argc + 2) % 3, -1, 1);
  529.  
  530.   argv0 = argv[0];
  531.   argv++;
  532.   argc--;
  533.  
  534.   result = NULL;
  535.   while (result == NULL)
  536.  
  537.     if (strcmp (ARG (0), ARG (1)) == 0)
  538.       result = ARG (2);
  539.  
  540.     else
  541.       switch (argc)
  542.     {
  543.     case 3:
  544.       return;
  545.  
  546.     case 4:
  547.     case 5:
  548.       result = ARG (3);
  549.       break;
  550.  
  551.     default:
  552.       argc -= 3;
  553.       argv += 3;
  554.     }
  555.  
  556.   obstack_grow (obs, result, strlen (result));
  557. }
  558.  
  559.  
  560. /*---------------------------------------------------------------------.
  561. | The function dump_symbol () is for use by "dumpdef".  It builds up a |
  562. | table of all defined, un-shadowed, symbols.                   |
  563. `---------------------------------------------------------------------*/
  564.  
  565. /* The structure dump_symbol_data is used to pass the information needed
  566.    from call to call to dump_symbol.  */
  567.  
  568. struct dump_symbol_data
  569. {
  570.   struct obstack *obs;        /* obstack for table */
  571.   symbol **base;        /* base of table */
  572.   int size;            /* size of table */
  573. };
  574.  
  575. static void
  576. dump_symbol (symbol *sym, struct dump_symbol_data *data)
  577. {
  578.   if (!SYMBOL_SHADOWED (sym) && SYMBOL_TYPE (sym) != TOKEN_VOID)
  579.     {
  580.       obstack_blank (data->obs, sizeof (symbol *));
  581.       data->base = (symbol **) obstack_base (data->obs);
  582.       data->base[data->size++] = sym;
  583.     }
  584. }
  585.  
  586. /*------------------------------------------------------------------------.
  587. | qsort comparison routine, for sorting the table made in m4_dumpdef ().  |
  588. `------------------------------------------------------------------------*/
  589.  
  590. static int
  591. dumpdef_cmp (const void *s1, const void *s2)
  592. {
  593.   return strcmp (SYMBOL_NAME (* (const symbol **) s1),
  594.          SYMBOL_NAME (* (const symbol **) s2));
  595. }
  596.  
  597. /*-------------------------------------------------------------------------.
  598. | Implementation of "dumpdef" itself.  It builds up a table of pointers to |
  599. | symbols, sorts it and prints the sorted table.               |
  600. `-------------------------------------------------------------------------*/
  601.  
  602. static void
  603. m4_dumpdef (struct obstack *obs, int argc, token_data **argv)
  604. {
  605.   symbol *s;
  606.   int i;
  607.   struct dump_symbol_data data;
  608.   const builtin *bp;
  609.  
  610.   data.obs = obs;
  611.   data.base = (symbol **) obstack_base (obs);
  612.   data.size = 0;
  613.  
  614.   if (argc == 1)
  615.     {
  616.       hack_all_symbols (dump_symbol, (char *) &data);
  617.     }
  618.   else
  619.     {
  620.       for (i = 1; i < argc; i++)
  621.     {
  622.       s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP);
  623.       if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
  624.         dump_symbol (s, &data);
  625.       else
  626.         m4error ("Undefined name %s", TOKEN_DATA_TEXT (argv[i]));
  627.     }
  628.     }
  629.  
  630.   /* Make table of symbols invisible to expand_macro ().  */
  631.  
  632.   (void) obstack_finish (obs);
  633.  
  634.   qsort ((char *) data.base, data.size, sizeof (symbol *), dumpdef_cmp);
  635.  
  636.   for (; data.size > 0; --data.size, data.base++)
  637.     {
  638.       debug_print ("%s:\t", SYMBOL_NAME (data.base[0]));
  639.  
  640.       switch (SYMBOL_TYPE (data.base[0]))
  641.     {
  642.     case TOKEN_TEXT:
  643.       if (debug_level & DEBUG_TRACE_QUOTE)
  644.         debug_print ("%s%s%s\n", lquote, SYMBOL_TEXT (data.base[0]), rquote);
  645.       else
  646.         debug_print ("%s\n", SYMBOL_TEXT (data.base[0]));
  647.       break;
  648.     case TOKEN_FUNC:
  649.       bp = find_builtin_by_addr (SYMBOL_FUNC (data.base[0]));
  650.       if (bp == NULL)
  651.         internal_error ("built-in not found in builtin table!");
  652.       debug_print ("<%s>\n", bp->name);
  653.       break;
  654.     default:
  655.       internal_error ("Bad token data type in m4_dumpdef ()");
  656.       break;
  657.     }
  658.     }
  659. }
  660.  
  661. /*---------------------------------------------------------------------.
  662. | The builtin "builtin" allows calls to builtin macros, even if their  |
  663. | definition has been overridden or shadowed.  It is thus possible to  |
  664. | redefine builtins, and still access their original definition.  This |
  665. | macro is not available in compatibility mode.                   |
  666. `---------------------------------------------------------------------*/
  667.  
  668. static void
  669. m4_builtin (struct obstack *obs, int argc, token_data **argv)
  670. {
  671.   const builtin *bp;
  672.   char *name = ARG (1);
  673.  
  674.   if (bad_argc (argv[0], argc, 2, -1))
  675.     return;
  676.  
  677.   bp = find_builtin_by_name (name);
  678.   if (bp == NULL)
  679.     m4error ("Undefined name %s", name);
  680.   else
  681.     (*bp->func) (obs, argc - 1, argv + 1);
  682. }
  683.  
  684. /*------------------------------------------------------------------------.
  685. | The builtin "indir" allows indirect calls to macros, even if their name |
  686. | is not a proper macro name.  It is thus possible to define macros with  |
  687. | ill-formed names for internal use in larger macro packages.  This macro |
  688. | is not available in compatibility mode.                  |
  689. `------------------------------------------------------------------------*/
  690.  
  691. static void
  692. m4_indir (struct obstack *obs, int argc, token_data **argv)
  693. {
  694.   symbol *s;
  695.   char *name = ARG (1);
  696.  
  697.   if (bad_argc (argv[0], argc, 1, -1))
  698.     return;
  699.  
  700.   s = lookup_symbol (name, SYMBOL_LOOKUP);
  701.   if (s == NULL)
  702.     m4error ("Undefined macro `%s'", name);
  703.   else
  704.     call_macro (s, argc - 1, argv + 1, obs);
  705. }
  706.  
  707. /*-------------------------------------------------------------------------.
  708. | The macro "defn" returns the quoted definition of the macro named by the |
  709. | first argument.  If the macro is builtin, it will push a special       |
  710. | macro-definition token on ht input stack.                   |
  711. `-------------------------------------------------------------------------*/
  712.  
  713. static void
  714. m4_defn (struct obstack *obs, int argc, token_data **argv)
  715. {
  716.   symbol *s;
  717.  
  718.   if (bad_argc (argv[0], argc, 2, 2))
  719.     return;
  720.  
  721.   s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
  722.   if (s == NULL)
  723.     return;
  724.  
  725.   switch (SYMBOL_TYPE (s))
  726.     {
  727.     case TOKEN_TEXT:
  728.       obstack_grow (obs, lquote, len_lquote);
  729.       obstack_grow (obs, SYMBOL_TEXT (s), strlen (SYMBOL_TEXT (s)));
  730.       obstack_grow (obs, rquote, len_rquote);
  731.       break;
  732.     case TOKEN_FUNC:
  733.       push_macro (SYMBOL_FUNC (s), SYMBOL_TRACED (s));
  734.       break;
  735.     case TOKEN_VOID:
  736.       break;
  737.     default:
  738.       internal_error ("Bad symbol type in m4_defn ()");
  739.       break;
  740.     }
  741. }
  742.  
  743.  
  744. /*------------------------------------------------------------------------.
  745. | This section contains macros to handle the builtins "syscmd", "esyscmd" |
  746. | and "sysval".  "esyscmd" is GNU specific.                  |
  747. `------------------------------------------------------------------------*/
  748.  
  749. /* Exit code from last "syscmd" command.  */
  750. static int sysval;
  751.  
  752. static void
  753. m4_syscmd (struct obstack *obs, int argc, token_data **argv)
  754. {
  755.   if (bad_argc (argv[0], argc, 2, 2))
  756.     return;
  757.   sysval = system (ARG (1));
  758. }
  759.  
  760. static void
  761. m4_esyscmd (struct obstack *obs, int argc, token_data **argv)
  762. {
  763.   FILE *pin;
  764.   int ch;
  765.  
  766.   if (bad_argc (argv[0], argc, 2, 2))
  767.     return;
  768.  
  769.   pin = popen (ARG (1), "r");
  770.   if (pin == NULL)
  771.     {
  772.       m4error ("Cannot open pipe to command \"%s\": %s", ARG (1), syserr ());
  773.       sysval = 0xff << 8;
  774.     }
  775.   else
  776.     {
  777.       while ((ch = getc (pin)) != EOF)
  778.     obstack_1grow (obs, (char) ch);
  779.       sysval = pclose (pin);
  780.     }
  781. }
  782.  
  783. static void
  784. m4_sysval (struct obstack *obs, int argc, token_data **argv)
  785. {
  786.   shipout_int (obs, (sysval >> 8) & 0xff);
  787. }
  788.  
  789.  
  790. /*-------------------------------------------------------------------------.
  791. | This section contains the top level code for the "eval" builtin.  The       |
  792. | actual work is done in the function evaluate (), which lives in eval.c.  |
  793. `-------------------------------------------------------------------------*/
  794.  
  795. static void
  796. m4_eval (struct obstack *obs, int argc, token_data **argv)
  797. {
  798.   int value;
  799.   int radix = 10;
  800.   int min = 1;
  801.   char *s;
  802.  
  803.   if (bad_argc (argv[0], argc, 2, 4))
  804.     return;
  805.  
  806.   if (argc >= 3 && !numeric_arg (argv[0], ARG (2), &radix))
  807.     return;
  808.  
  809.   if (radix <= 1 || radix > strlen (digits))
  810.     {
  811.       m4error ("radix in eval out of range (radix = %d)", radix);
  812.       return;
  813.     }
  814.  
  815.   if (argc >= 4 && !numeric_arg (argv[0], ARG (3), &min))
  816.     return;
  817.   if  (min <= 0)
  818.     {
  819.       m4error ("negative width to eval");
  820.       return;
  821.     }
  822.  
  823.   if (evaluate (ARG (1), &value))
  824.     return;
  825.  
  826.   s = ntoa (value, radix);
  827.  
  828.   if (*s == '-')
  829.     {
  830.       obstack_1grow (obs, '-');
  831.       min--;
  832.       s++;
  833.     }
  834.   for (min -= strlen (s); --min >= 0;)
  835.     obstack_1grow (obs, '0');
  836.  
  837.   obstack_grow (obs, s, strlen (s));
  838. }
  839.  
  840. static void
  841. m4_incr (struct obstack *obs, int argc, token_data **argv)
  842. {
  843.   int value;
  844.  
  845.   if (bad_argc (argv[0], argc, 2, 2))
  846.     return;
  847.  
  848.   if (!numeric_arg (argv[0], ARG (1), &value))
  849.     return;
  850.  
  851.   shipout_int (obs, value + 1);
  852. }
  853.  
  854. static void
  855. m4_decr (struct obstack *obs, int argc, token_data **argv)
  856. {
  857.   int value;
  858.  
  859.   if (bad_argc (argv[0], argc, 2, 2))
  860.     return;
  861.  
  862.   if (!numeric_arg (argv[0], ARG (1), &value))
  863.     return;
  864.  
  865.   shipout_int (obs, value - 1);
  866. }
  867.  
  868. /* This section contains the macros "divert", "undivert" and "divnum" for
  869.    handling diversion.  The utility functions used lives in output.c.  */
  870.  
  871. /*-----------------------------------------------------------------------.
  872. | Divert further output to the diversion given by ARGV[1].  Out of range |
  873. | means discard further output.                         |
  874. `-----------------------------------------------------------------------*/
  875.  
  876. static void
  877. m4_divert (struct obstack *obs, int argc, token_data **argv)
  878. {
  879.   int i = 0;
  880.  
  881.   if (bad_argc (argv[0], argc, 1, 2))
  882.     return;
  883.  
  884.   if (argc == 2 && !numeric_arg (argv[0], ARG (1), &i))
  885.     return;
  886.  
  887.   make_diversion (i);
  888.   current_diversion = i;
  889. }
  890.  
  891. /*-----------------------------------------------------.
  892. | Expand to the current diversion number, -1 if none.  |
  893. `-----------------------------------------------------*/
  894.  
  895. static void
  896. m4_divnum (struct obstack *obs, int argc, token_data **argv)
  897. {
  898.   if (bad_argc (argv[0], argc, 1, 1))
  899.     return;
  900.   shipout_int (obs, current_diversion);
  901. }
  902.  
  903. /*-----------------------------------------------------------------------.
  904. | Bring back the diversion given by the argument list.  If none is     |
  905. | specified, bring back all diversions.  GNU specific is the option of     |
  906. | undiverting named files, by passing a non-numeric argument to undivert |
  907. | ().                                     |
  908. `-----------------------------------------------------------------------*/
  909.  
  910. static void
  911. m4_undivert (struct obstack *obs, int argc, token_data **argv)
  912. {
  913.   int i, div;
  914.   FILE *fp;
  915.  
  916.   if (argc == 1)
  917.     {
  918.       undivert_all ();
  919.     }
  920.   else
  921.     for (i = 1; i < argc; i++)
  922.       {
  923.     if (sscanf (ARG (i), "%d", &div) == 1)
  924.       insert_diversion (div);
  925.     else if (no_gnu_extensions)
  926.       m4error ("non-numeric argument to %s", TOKEN_DATA_TEXT (argv[0]));
  927.     else
  928.       {
  929.         fp = path_search (ARG (i));
  930.         if (fp != NULL)
  931.           {
  932.         insert_file (fp);
  933.         fclose (fp);
  934.           }
  935.         else
  936.           m4error ("can't undivert %s: %s", ARG (i), syserr ());
  937.       }
  938.       }
  939. }
  940.  
  941. /* This section contains various macros, which does not fall into any
  942.    specific group.  These are "dnl", "shift", "changequote" and
  943.    "changecom".  */
  944.  
  945. /*------------------------------------------------------------------------.
  946. | Delete all subsequent whitespace from input.  The function skip_line () |
  947. | lives in input.c.                              |
  948. `------------------------------------------------------------------------*/
  949.  
  950. static void
  951. m4_dnl (struct obstack *obs, int argc, token_data **argv)
  952. {
  953.   if (bad_argc (argv[0], argc, 1, 1))
  954.     return;
  955.  
  956.   skip_line ();
  957. }
  958.  
  959. /*-------------------------------------------------------------------------.
  960. | Shift all argument one to the left, discarding the first argument.  Each |
  961. | output argument is quoted with the current quotes.               |
  962. `-------------------------------------------------------------------------*/
  963.  
  964. static void
  965. m4_shift (struct obstack *obs, int argc, token_data **argv)
  966. {
  967.   dump_args (obs, argc - 1, argv + 1, ",", TRUE);
  968. }
  969.  
  970. /*--------------------------------------------------------------------------.
  971. | Change the current quotes.  The function set_quotes () lives in input.c.  |
  972. `--------------------------------------------------------------------------*/
  973.  
  974. static void
  975. m4_changequote (struct obstack *obs, int argc, token_data **argv)
  976. {
  977.   if (bad_argc (argv[0], argc, 1, 3))
  978.     return;
  979.  
  980.   set_quotes ((argc >= 2) ? TOKEN_DATA_TEXT (argv[1]) : NULL,
  981.          (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL);
  982. }
  983.  
  984. /*--------------------------------------------------------------------.
  985. | Change the current comment delimiters.  The function set_comment () |
  986. | lives in input.c.                              |
  987. `--------------------------------------------------------------------*/
  988.  
  989. static void
  990. m4_changecom (struct obstack *obs, int argc, token_data **argv)
  991. {
  992.   if (bad_argc (argv[0], argc, 1, 3))
  993.     return;
  994.  
  995.   if (argc == 1)
  996.     set_comment ("", "");    /* disable comments */
  997.   else
  998.     set_comment (TOKEN_DATA_TEXT (argv[1]),
  999.         (argc >= 3) ? TOKEN_DATA_TEXT (argv[2]) : NULL);
  1000. }
  1001.  
  1002. /* This section contains macros for inclusion of other files -- "include"
  1003.    and "sinclude".  This differs from bringing back diversions, in that
  1004.    the input is scanned before being copied to the output.  */
  1005.  
  1006. /*-------------------------------------------------------------------------.
  1007. | Generic include function.  Include the file given by the first argument, |
  1008. | if it exists.  Complain about inaccesible files iff SILENT is FALSE.       |
  1009. `-------------------------------------------------------------------------*/
  1010.  
  1011. static void
  1012. include (int argc, token_data **argv, boolean silent)
  1013. {
  1014.   FILE *fp;
  1015.  
  1016.   if (bad_argc (argv[0], argc, 2, 2))
  1017.     return;
  1018.  
  1019.   fp = path_search (ARG (1));
  1020.   if (fp == NULL)
  1021.     {
  1022.       if (!silent)
  1023.     m4error ("can't open %s: %s", ARG (1), syserr ());
  1024.       return;
  1025.     }
  1026.  
  1027.   push_file (fp, ARG (1));
  1028. }
  1029.  
  1030. /*------------------------------------------------.
  1031. | Include a file, complaining in case of errors.  |
  1032. `------------------------------------------------*/
  1033.  
  1034. static void
  1035. m4_include (struct obstack *obs, int argc, token_data **argv)
  1036. {
  1037.   include (argc, argv, FALSE);
  1038. }
  1039.  
  1040. /*----------------------------------.
  1041. | Include a file, ignoring errors.  |
  1042. `----------------------------------*/
  1043.  
  1044. static void
  1045. m4_sinclude (struct obstack *obs, int argc, token_data **argv)
  1046. {
  1047.   include (argc, argv, TRUE);
  1048. }
  1049.  
  1050. /* More miscellaneous builtins -- "maketemp", "errprint", "__file__" and
  1051.    "__line__".  The last two are GNU specific.  */
  1052.  
  1053. /*------------------------------------------------------------------.
  1054. | Use the first argument as at template for a temporary file name.  |
  1055. `------------------------------------------------------------------*/
  1056.  
  1057. static void
  1058. m4_maketemp (struct obstack *obs, int argc, token_data **argv)
  1059. {
  1060.   if (bad_argc (argv[0], argc, 2, 2))
  1061.     return;
  1062.   mktemp (ARG (1));
  1063.   obstack_grow (obs, ARG (1), strlen (ARG (1)));
  1064. }
  1065.  
  1066. /*----------------------------------------.
  1067. | Print all arguments on standard error.  |
  1068. `----------------------------------------*/
  1069.  
  1070. static void
  1071. m4_errprint (struct obstack *obs, int argc, token_data **argv)
  1072. {
  1073.   dump_args (obs, argc, argv, " ", FALSE);
  1074.   obstack_1grow (obs, '\0');
  1075.   fprintf (stderr, "%s", (char *) obstack_finish (obs));
  1076.   fflush (stderr);
  1077. }
  1078.  
  1079. static void
  1080. m4___file__ (struct obstack *obs, int argc, token_data **argv)
  1081. {
  1082.   if (bad_argc (argv[0], argc, 1, 1))
  1083.     return;
  1084.   obstack_grow (obs, lquote, len_lquote);
  1085.   obstack_grow (obs, current_file, strlen (current_file));
  1086.   obstack_grow (obs, rquote, len_rquote);
  1087. }
  1088.  
  1089. static void
  1090. m4___line__ (struct obstack *obs, int argc, token_data **argv)
  1091. {
  1092.   if (bad_argc (argv[0], argc, 1, 1))
  1093.     return;
  1094.   shipout_int (obs, current_line);
  1095. }
  1096.  
  1097. /* This section contains various macros for exiting, saving input until
  1098.    EOF is seen, and tracing macro calls.  That is: "m4exit", "m4wrap",
  1099.    "traceon" and "traceoff".  */
  1100.  
  1101. /*-------------------------------------------------------------------------.
  1102. | Exit immediately, with exitcode specified by the first argument, 0 if no |
  1103. | arguments are present.                           |
  1104. `-------------------------------------------------------------------------*/
  1105.  
  1106. static void
  1107. m4_m4exit (struct obstack *obs, int argc, token_data **argv)
  1108. {
  1109.   int exit_code = 0;
  1110.  
  1111.   if (bad_argc (argv[0], argc, 1, 2))
  1112.     return;
  1113.   if (argc == 2  && !numeric_arg (argv[0], ARG (1), &exit_code))
  1114.     exit_code = 0;
  1115.  
  1116.   exit (exit_code);
  1117. }
  1118.  
  1119. /*-------------------------------------------------------------------------.
  1120. | Save the argument text until EOF has been seen, allowing for user       |
  1121. | specified cleanup action.  GNU version saves all arguments, the standard |
  1122. | version only the first.                           |
  1123. `-------------------------------------------------------------------------*/
  1124.  
  1125. static void
  1126. m4_m4wrap (struct obstack *obs, int argc, token_data **argv)
  1127. {
  1128.   if (no_gnu_extensions)
  1129.     obstack_grow (obs, ARG (1), strlen (ARG (1)));
  1130.   else
  1131.     dump_args (obs, argc, argv, " ", FALSE);
  1132.   obstack_1grow (obs, '\0');
  1133.   push_wrapup (obstack_finish (obs));
  1134. }
  1135.  
  1136. /* Enable tracing of all specified macros, or all, if none is specified.
  1137.    Tracing is disabled by default, when a macro is defined.  This can be
  1138.    overridden by the "t" debug flag.  */
  1139.  
  1140. /*-----------------------------------------------------------------------.
  1141. | Set_trace () is used by "traceon" and "traceoff" to enable and disable |
  1142. | tracing of a macro.  It disables tracing if DATA is NULL, otherwise it |
  1143. | enable tracing.                             |
  1144. `-----------------------------------------------------------------------*/
  1145.  
  1146. static void
  1147. set_trace (symbol *sym, char *data)
  1148. {
  1149.   SYMBOL_TRACED (sym) = (boolean) (data != NULL);
  1150. }
  1151.  
  1152. static void
  1153. m4_traceon (struct obstack *obs, int argc, token_data **argv)
  1154. {
  1155.   symbol *s;
  1156.   int i;
  1157.  
  1158.   if (argc == 1)
  1159.     hack_all_symbols (set_trace, (char *) obs);
  1160.   else
  1161.     for (i = 1; i < argc; i++)
  1162.       {
  1163.     s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP);
  1164.     if (s != NULL)
  1165.       set_trace (s, (char *) obs);
  1166.     else
  1167.       m4error ("Undefined name %s", TOKEN_DATA_TEXT (argv[i]));
  1168.       }
  1169. }
  1170.  
  1171. /*------------------------------------------------------------------------.
  1172. | Disable tracing of all specified macros, or all, if none is specified.  |
  1173. `------------------------------------------------------------------------*/
  1174.  
  1175. static void
  1176. m4_traceoff (struct obstack *obs, int argc, token_data **argv)
  1177. {
  1178.   symbol *s;
  1179.   int i;
  1180.  
  1181.   if (argc == 1)
  1182.     hack_all_symbols (set_trace, NULL);
  1183.   else
  1184.     for (i = 1; i < argc; i++)
  1185.       {
  1186.     s = lookup_symbol (TOKEN_DATA_TEXT (argv[i]), SYMBOL_LOOKUP);
  1187.     if (s != NULL)
  1188.       set_trace (s, NULL);
  1189.     else
  1190.       m4error ("Undefined name %s", TOKEN_DATA_TEXT (argv[i]));
  1191.       }
  1192. }
  1193.  
  1194. /*----------------------------------------------------------------------.
  1195. | On-the-fly control of the format of the tracing output.  It takes one |
  1196. | argument, which is a character string like given to the -d option, or |
  1197. | none in which case the debug_level is zeroed.                    |
  1198. `----------------------------------------------------------------------*/
  1199.  
  1200. static void
  1201. m4_debugmode (struct obstack *obs, int argc, token_data **argv)
  1202. {
  1203.   int new_debug_level;
  1204.   int change_flag;
  1205.  
  1206.   if (bad_argc (argv[0], argc, 1, 2))
  1207.     return;
  1208.  
  1209.   if (argc == 1)
  1210.     debug_level = 0;
  1211.   else
  1212.     {
  1213.       if (ARG (1)[0] == '+' || ARG (1)[0] == '-')
  1214.     {
  1215.       change_flag = ARG (1)[0];
  1216.       new_debug_level = debug_decode (ARG (1) + 1);
  1217.     }
  1218.       else
  1219.     {
  1220.       change_flag = 0;
  1221.       new_debug_level = debug_decode (ARG (1));
  1222.     }
  1223.  
  1224.       if (new_debug_level < 0)
  1225.     m4error ("debugmode: bad debug flags: `%s'", ARG (1));
  1226.       else
  1227.     {
  1228.       switch (change_flag)
  1229.         {
  1230.         case 0:
  1231.           debug_level = new_debug_level;
  1232.           break;
  1233.         case '+':
  1234.           debug_level |= new_debug_level;
  1235.           break;
  1236.         case '-':
  1237.           debug_level &= ~new_debug_level;
  1238.           break;
  1239.         }
  1240.     }
  1241.     }
  1242. }
  1243.  
  1244. /*-------------------------------------------------------------------------.
  1245. | Specify the destination of the debugging output.  With one argument, the |
  1246. | argument is taken as a file name, with no arguments, revert to stderr.   |
  1247. `-------------------------------------------------------------------------*/
  1248.  
  1249. static void
  1250. m4_debugfile (struct obstack *obs, int argc, token_data **argv)
  1251. {
  1252.   if (bad_argc (argv[0], argc, 1, 2))
  1253.     return;
  1254.  
  1255.   if (argc == 1)
  1256.     debug_set_output (NULL);
  1257.   else if (!debug_set_output (ARG (1)))
  1258.     m4error ("cannot set error file: %s: %s", ARG (1), syserr ());
  1259. }
  1260.  
  1261. /* This section contains text processing macros: "len", "index",
  1262.    "substr", "translit", "format", "regexp" and "patsubst".  The last
  1263.    three are GNU specific.  */
  1264.  
  1265. /*---------------------------------------------.
  1266. | Expand to the length of the first argument.  |
  1267. `---------------------------------------------*/
  1268.  
  1269. static void
  1270. m4_len (struct obstack *obs, int argc, token_data **argv)
  1271. {
  1272.   if (bad_argc (argv[0], argc, 2, 2))
  1273.     return;
  1274.   shipout_int (obs, strlen (ARG (1)));
  1275. }
  1276.  
  1277. /*-------------------------------------------------------------------------.
  1278. | The macro expands to the first index of the second argument in the first |
  1279. | argument.                                   |
  1280. `-------------------------------------------------------------------------*/
  1281.  
  1282. static void
  1283. m4_index (struct obstack *obs, int argc, token_data **argv)
  1284. {
  1285.   char *cp, *last;
  1286.   int l1, l2, retval;
  1287.  
  1288.   if (bad_argc (argv[0], argc, 3, 3))
  1289.     return;
  1290.  
  1291.   l1 = strlen (ARG (1));
  1292.   l2 = strlen (ARG (2));
  1293.  
  1294.   last = ARG (1) + l1 - l2;
  1295.  
  1296.   for (cp = ARG (1); cp <= last; cp++)
  1297.     {
  1298.       if (strncmp (cp, ARG (2), l2) == 0)
  1299.     break;
  1300.     }
  1301.   retval = (cp <= last) ? cp - ARG (1) : -1;
  1302.  
  1303.   shipout_int (obs, retval);
  1304. }
  1305.  
  1306. /*-------------------------------------------------------------------------.
  1307. | The macro "substr" extracts substrings from the first argument, starting |
  1308. | from the index given by the second argument, extending for a length       |
  1309. | given by the third argument.  If the third argument is missing, the       |
  1310. | substring extends to the end of the first argument.               |
  1311. `-------------------------------------------------------------------------*/
  1312.  
  1313. static void
  1314. m4_substr (struct obstack *obs, int argc, token_data **argv)
  1315. {
  1316.   int start, length, avail;
  1317.  
  1318.   if (bad_argc (argv[0], argc, 3, 4))
  1319.     return;
  1320.  
  1321.   length = avail = strlen (ARG (1));
  1322.   if (!numeric_arg (argv[0], ARG (2), &start))
  1323.     return;
  1324.  
  1325.   if (argc == 4 && !numeric_arg (argv[0], ARG (3), &length))
  1326.     return;
  1327.  
  1328.   if (start < 0 || length <= 0 || start >= avail)
  1329.     return;
  1330.  
  1331.   if (start + length > avail)
  1332.     length = avail - start;
  1333.   obstack_grow (obs, ARG (1) + start, length);
  1334. }
  1335.  
  1336. /*------------------------------------------------------------------------.
  1337. | For "translit", ranges are allowed in the second and third argument.      |
  1338. | They are expanded in the following function, and the expanded strings,  |
  1339. | without any ranges left, are used to translate the characters of the      |
  1340. | first argument.  A single - (dash) can be included in the strings by      |
  1341. | being the first or the last character in the string.  If the first      |
  1342. | character in a range is after the first in the character set, the range |
  1343. | is made backwards, thus 9-0 is the string 9876543210.              |
  1344. `------------------------------------------------------------------------*/
  1345.  
  1346. static char *
  1347. expand_ranges (char *s, struct obstack *obs)
  1348. {
  1349.   char from;
  1350.   char to;
  1351.  
  1352.   for (from = '\0'; *s != '\0'; from = *s++)
  1353.     {
  1354.       if (*s == '-' && from != '\0')
  1355.     {
  1356.       to = *++s;
  1357.       if (to == '\0')
  1358.         obstack_1grow (obs, '-'); /* trailing dash */
  1359.       else if (from <= to)
  1360.         {
  1361.           while (from++ < to)
  1362.         obstack_1grow (obs, from);
  1363.         }
  1364.       else
  1365.         {
  1366.           while (--from >= to)
  1367.         obstack_1grow (obs, from);
  1368.         }
  1369.     }
  1370.       else
  1371.     obstack_1grow (obs, *s);
  1372.     }
  1373.   obstack_1grow (obs, '\0');
  1374.   return obstack_finish (obs);
  1375. }
  1376.  
  1377. /*----------------------------------------------------------------------.
  1378. | The macro "translit" translates all characters in the first argument, |
  1379. | which are present in the second argument, into the corresponding      |
  1380. | character from the third argument.  If the third argument is shorter  |
  1381. | than the second, the extra characters in the second argument, are     |
  1382. | deleted from the first (pueh).                        |
  1383. `----------------------------------------------------------------------*/
  1384.  
  1385. static void
  1386. m4_translit (struct obstack *obs, int argc, token_data **argv)
  1387. {
  1388.   register char *data, *tmp;
  1389.   char *from, *to;
  1390.   int tolen;
  1391.  
  1392.   if (bad_argc (argv[0], argc, 3, 4))
  1393.     return;
  1394.  
  1395.   from = ARG (2);
  1396.   if (index (from, '-') != NULL)
  1397.     {
  1398.       from = expand_ranges (from, obs);
  1399.       if (from == NULL)
  1400.     return;
  1401.     }
  1402.  
  1403.   if (argc == 4)
  1404.     {
  1405.       to = ARG (3);
  1406.       if (index (to, '-') != NULL)
  1407.     {
  1408.       to = expand_ranges (to, obs);
  1409.       if (to == NULL)
  1410.         return;
  1411.     }
  1412.     }
  1413.   else
  1414.     to = "";
  1415.  
  1416.   tolen = strlen (to);
  1417.  
  1418.   for (data = ARG (1); *data; data++)
  1419.     {
  1420.       tmp = (char *) index (from, *data);
  1421.       if (tmp == NULL)
  1422.     {
  1423.       obstack_1grow (obs, *data);
  1424.     }
  1425.       else
  1426.     {
  1427.       if (tmp - from < tolen)
  1428.         obstack_1grow (obs, *(to + (tmp - from)));
  1429.     }
  1430.     }
  1431. }
  1432.  
  1433. /*----------------------------------------------------------------------.
  1434. | Frontend for printf like formatting.  The function format () lives in |
  1435. | the file format.c.                                |
  1436. `----------------------------------------------------------------------*/
  1437.  
  1438. static void
  1439. m4_format (struct obstack *obs, int argc, token_data **argv)
  1440. {
  1441.   format (obs, argc - 1, argv + 1);
  1442. }
  1443.  
  1444. /*--------------------------------------------------------------------------.
  1445. | Function to perform substitution by regular expressions.  Used by the        |
  1446. | builtins regexp and patsubst.  The changed text is place on the obstack.  |
  1447. | The substitution is REPL, with \& substituted by VICTIM (of length        |
  1448. | LENGTH), and \N substituted by the text matched by the Nth parenthesized  |
  1449. | sub-expression, taken from REGS.                        |
  1450. `--------------------------------------------------------------------------*/
  1451.  
  1452. static void
  1453. substitute (struct obstack *obs, char *victim, int length,
  1454.         char *repl, struct re_registers *regs)
  1455. {
  1456.   register unsigned int ch;
  1457.  
  1458.   for (;;)
  1459.     {
  1460.       while ((ch = *repl++) != '\\')
  1461.     {
  1462.       if (ch == '\0')
  1463.         return;
  1464.       obstack_1grow (obs, ch);
  1465.     }
  1466.  
  1467.       switch ((ch = *repl++))
  1468.     {
  1469.     case '0': case '1': case '2': case '3': case '4':
  1470.     case '5': case '6': case '7': case '8': case '9':
  1471.       ch -= '0';
  1472.       if (regs->end[ch] > 0)
  1473.         obstack_grow (obs, victim + regs->start[ch],
  1474.               regs->end[ch] - regs->start[ch]);
  1475.       break;
  1476.     case '&':
  1477.       obstack_grow (obs, victim, length);
  1478.       break;
  1479.     default:
  1480.       obstack_1grow (obs, ch);
  1481.       break;
  1482.     }
  1483.     }
  1484. }
  1485.  
  1486. /*--------------------------------------------------------------------------.
  1487. | Regular expression version of index.  Given two arguments, expand to the  |
  1488. | index of the first match of the second argument (a regexp) in the first.  |
  1489. | Expand to -1 if here is no match.  Given a third argument, is changes        |
  1490. | the expansion to this argument.                        |
  1491. `--------------------------------------------------------------------------*/
  1492.  
  1493. static void
  1494. m4_regexp (struct obstack *obs, int argc, token_data **argv)
  1495. {
  1496.   char *victim;            /* first argument */
  1497.   char *regexp;            /* regular expression */
  1498.   char *repl;            /* replacement string */
  1499.  
  1500.   struct re_pattern_buffer buf;    /* compiled regular expression */
  1501.   struct re_registers regs;    /* for subexpression matches */
  1502.   const char *msg;        /* error message from re_compile_pattern */
  1503.   int startpos;            /* start position of match */
  1504.   int length;            /* length of first argument */
  1505.  
  1506.   if (bad_argc (argv[0], argc, 3, 4))
  1507.     return;
  1508.  
  1509.   victim = TOKEN_DATA_TEXT (argv[1]);
  1510.   regexp = TOKEN_DATA_TEXT (argv[2]);
  1511.   if (argc == 4)
  1512.     repl = TOKEN_DATA_TEXT (argv[3]);
  1513.  
  1514.   buf.buffer = NULL;
  1515.   buf.allocated = 0;
  1516.   buf.fastmap = NULL;
  1517.   buf.translate = NULL;
  1518.   msg = re_compile_pattern (regexp, strlen (regexp), &buf);
  1519.  
  1520.   if (msg != NULL)
  1521.     {
  1522.       m4error ("bad regular expression: \"%s\": %s", regexp, msg);
  1523.       return;
  1524.     }
  1525.  
  1526.   length = strlen (victim);
  1527.   startpos = re_search (&buf, victim, length, 0, length, ®s);
  1528.   xfree (buf.buffer);
  1529.  
  1530.   if (startpos  == -2)
  1531.     {
  1532.       m4error ("error matching regular expression \"%s\"", regexp);
  1533.       return;
  1534.     }
  1535.  
  1536.   if (argc == 3)
  1537.     shipout_int (obs, startpos);
  1538.   else if (startpos >= 0)
  1539.     substitute (obs, victim, length, repl, ®s);
  1540.  
  1541.   return;
  1542. }
  1543.  
  1544. /*--------------------------------------------------------------------------.
  1545. | Substitute all matches of a regexp occuring in a string.  Each match of   |
  1546. | the second argument (a regexp) in the first argument is changed to the    |
  1547. | third argument, with \& substituted by the matched text, and \N        |
  1548. | substituted by the text matched by the Nth parenthesized sub-expression.  |
  1549. `--------------------------------------------------------------------------*/
  1550.  
  1551. static void
  1552. m4_patsubst (struct obstack *obs, int argc, token_data **argv)
  1553. {
  1554.   char *victim;            /* first argument */
  1555.   char *regexp;            /* regular expression */
  1556.  
  1557.   struct re_pattern_buffer buf;    /* compiled regular expression */
  1558.   struct re_registers regs;    /* for subexpression matches */
  1559.   const char *msg;        /* error message from re_compile_pattern */
  1560.   int matchpos;            /* start position of match */
  1561.   int offset;            /* current match offset */
  1562.   int length;            /* length of first argument */
  1563.  
  1564.   if (bad_argc (argv[0], argc, 3, 4))
  1565.     return;
  1566.  
  1567.   regexp = TOKEN_DATA_TEXT (argv[2]);
  1568.  
  1569.   buf.buffer = NULL;
  1570.   buf.allocated = 0;
  1571.   buf.fastmap = NULL;
  1572.   buf.translate = NULL;
  1573.   msg = re_compile_pattern (regexp, strlen (regexp), &buf);
  1574.  
  1575.   if (msg != NULL)
  1576.     {
  1577.       m4error ("bad regular expression: \"%s\": %s", regexp, msg);
  1578.       if (buf.buffer != NULL)
  1579.     xfree (buf.buffer);
  1580.       return;
  1581.     }
  1582.  
  1583.   victim = TOKEN_DATA_TEXT (argv[1]);
  1584.   length = strlen (victim);
  1585.  
  1586.   offset = 0;
  1587.   matchpos = 0;
  1588.   while (offset < length)
  1589.     {
  1590.       matchpos = re_search (&buf, victim, length,
  1591.                 offset, length - offset, ®s);
  1592.       if (matchpos < 0)
  1593.     {
  1594.       /*
  1595.        * Match failed -- either error or there is no match in the
  1596.        * rest of the string, in which case the rest of the string
  1597.        * is copied verbatim.
  1598.        */
  1599.       if (matchpos == -2)
  1600.         m4error ("error matching regular expression \"%s\"", regexp);
  1601.       else if (offset < length)
  1602.         obstack_grow (obs, victim + offset, length - offset);
  1603.       break;
  1604.     }
  1605.       /*
  1606.        * Copy the part of the string that was skipped by re_search ().
  1607.        */
  1608.       if (matchpos > offset)
  1609.     obstack_grow (obs, victim + offset, matchpos - offset);
  1610.  
  1611.       /*
  1612.        * Handle the part of the string that was covered by the match.
  1613.        */
  1614.       substitute (obs, victim, length, ARG (3), ®s);
  1615.  
  1616.       /*
  1617.        * Update the offset to the end of the match.  If the regexp
  1618.        * matched a null string, advance offset one more, to avoid
  1619.        * infinite loops.
  1620.        */
  1621.       offset = regs.end[0];
  1622.       if (regs.start[0] == regs.end[0])
  1623.     obstack_1grow (obs, victim[offset++]);
  1624.     }
  1625.   obstack_1grow (obs, '\0');
  1626.  
  1627.   xfree (buf.buffer);
  1628.   return;
  1629. }
  1630.  
  1631.  
  1632. /*-------------------------------------------------------------------------.
  1633. | This function handles all expansion of user defined and predefined       |
  1634. | macros.  It is called with an obstack OBS, where the macros expansion       |
  1635. | will be placed, as an unfinished object.  SYM points to the macro       |
  1636. | definition, giving the expansion text.  ARGC and ARGV are the arguments, |
  1637. | as usual.                                   |
  1638. `-------------------------------------------------------------------------*/
  1639.  
  1640. void
  1641. expand_user_macro (struct obstack *obs, symbol *sym,
  1642.            int argc, token_data **argv)
  1643. {
  1644.   register char *text;
  1645.   int i;
  1646.  
  1647.   for (text = SYMBOL_TEXT (sym); *text != '\0';)
  1648.     {
  1649.       if (*text != '$')
  1650.     {
  1651.       obstack_1grow (obs, *text);
  1652.       text++;
  1653.       continue;
  1654.     }
  1655.       text++;
  1656.       switch (*text)
  1657.     {
  1658.     case '0': case '1': case '2': case '3': case '4':
  1659.     case '5': case '6': case '7': case '8': case '9':
  1660.       if (no_gnu_extensions)
  1661.         {
  1662.           i = *text++ - '0';
  1663.         }
  1664.       else
  1665.         {
  1666.           for (i = 0; isdigit (*text); text++)
  1667.         i = i*10 + (*text - '0');
  1668.         }
  1669.       if (i < argc)
  1670.         obstack_grow (obs, TOKEN_DATA_TEXT (argv[i]),
  1671.               strlen (TOKEN_DATA_TEXT (argv[i])));
  1672.       break;
  1673.  
  1674.     case '#':        /* number of arguments */
  1675.       shipout_int (obs, argc - 1);
  1676.       text++;
  1677.       break;
  1678.  
  1679.     case '*':        /* all arguments */
  1680.     case '@':        /* ... same, but quoted */
  1681.       dump_args (obs, argc, argv, ",", *text == '@');
  1682.       text++;
  1683.       break;
  1684.  
  1685.     default:
  1686.       obstack_1grow (obs, '$');
  1687.       break;
  1688.     }
  1689.     }
  1690. }
  1691.