home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / m4-1.4-src.tgz / tar.out / fsf / m4 / src / builtin.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  48KB  |  1,733 lines

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