home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / m4v05as.zip / BUILTIN.C next >
C/C++ Source or Header  |  1992-02-22  |  32KB  |  1,352 lines

  1. /*
  2.  * GNU m4 -- A simple macro processor
  3.  * Copyright (C) 1989, 1990 Free Software Foundation, Inc. 
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /*
  21.  * MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
  22.  * This port is also distributed under the terms of the
  23.  * GNU General Public License as published by the
  24.  * Free Software Foundation.
  25.  *
  26.  * Please note that this file is not identical to the
  27.  * original GNU release, you should have received this
  28.  * code as patch to the official release.
  29.  *
  30.  * $Header: e:/gnu/m4/RCS/builtin.c 0.5.1.0 90/09/28 18:34:53 tho Exp $
  31.  */
  32.  
  33. /* 
  34.  * Code for all builtin macros, initialisation of symbol table, and
  35.  * expansion of user defined macros.
  36.  */
  37.  
  38. #include "m4.h"
  39.  
  40. #define ARG(i)    (argc > (i) ? TOKEN_DATA_TEXT(argv[i]) : "")
  41.  
  42.  
  43. /* 
  44.  * Initialisation of builtin and predefined macros.  The table
  45.  * "builtin_tab" is both used for initialisation, and by the "builtin"
  46.  * builtin. 
  47.  */
  48.  
  49. #ifdef MSDOS
  50.  
  51. #include <process.h>
  52. #include <errno.h>
  53. #include <io.h>
  54.  
  55. #define M4_ARGS \
  56.   struct obstack *obs, int argc, struct token_data **argv
  57.  
  58. builtin *find_builtin_by_name(char *name);
  59. builtin *find_builtin_by_addr(builtin_func *func);
  60. static char *ntoa (eval_t value, int radix);
  61. static enum boolean bad_argc (char *name, int argc, int min, int max);
  62. static int dumpdef_cmp (struct symbol **s1, struct symbol **s2);
  63. static void define_builtin (char *name, struct builtin *bp,\
  64.                 enum symbol_lookup mode);
  65. static void define_macro (int argc, struct token_data **argv,\
  66.               enum symbol_lookup mode);
  67. static void dump_args (struct obstack *obs, int argc,\
  68.                struct token_data **argv, char *sep,\
  69.                enum boolean quoted);
  70. static void dump_symbol (struct symbol *sym, struct dump_symbol_data *data);
  71. static void include (int argc, struct token_data **argv, enum boolean silent);
  72. static void m4_builtin (M4_ARGS);
  73. static void m4_changecom (M4_ARGS);
  74. static void m4_changequote (M4_ARGS);
  75. static void m4_define (M4_ARGS);
  76. static void m4_defn (M4_ARGS);
  77. static void m4_divert (M4_ARGS);
  78. static void m4_divnum (M4_ARGS);
  79. static void m4_dnl (M4_ARGS);
  80. static void m4_dumpdef (M4_ARGS);
  81. static void m4_errprint (M4_ARGS);
  82. static void m4_eval (M4_ARGS);
  83. static void m4_ifdef (M4_ARGS);
  84. static void m4_ifelse (M4_ARGS);
  85. static void m4_include (M4_ARGS);
  86. static void m4_index (M4_ARGS);
  87. static void m4_len (M4_ARGS);
  88. static void m4_m4exit (M4_ARGS);
  89. static void m4_m4wrap (M4_ARGS);
  90. static void m4_maketemp (M4_ARGS);
  91. static void m4_popdef (M4_ARGS);
  92. static void m4_pushdef (M4_ARGS);
  93. static void m4_shift (M4_ARGS);
  94. static void m4_sinclude (M4_ARGS);
  95. static void m4_substr (M4_ARGS);
  96. static void m4_syscmd (M4_ARGS);
  97. static void m4_sysval (M4_ARGS);
  98. static void m4_traceoff (M4_ARGS);
  99. static void m4_traceon (M4_ARGS);
  100. static void m4_translit (M4_ARGS);
  101. static void m4_undefine (M4_ARGS);
  102. static void m4_undivert (M4_ARGS);
  103. static void set_trace (struct symbol *sym, char *data);
  104. static void shipout_int (struct obstack *obs, int val);
  105.  
  106. #else /* not MSDOS */
  107.  
  108. static void m4_builtin();
  109. static void m4_changecom();
  110. static void m4_changequote();
  111. static void m4_define();
  112. static void m4_defn();
  113. static void m4_divert();
  114. static void m4_divnum();
  115. static void m4_dnl();
  116. static void m4_dumpdef();
  117. static void m4_errprint();
  118. static void m4_eval();
  119. static void m4_ifdef();
  120. static void m4_ifelse();
  121. static void m4_include();
  122. static void m4_index();
  123. static void m4_len();
  124. static void m4_m4exit();
  125. static void m4_m4wrap();
  126. static void m4_maketemp();
  127. static void m4_popdef();
  128. static void m4_pushdef();
  129. static void m4_shift();
  130. static void m4_sinclude();
  131. static void m4_substr();
  132. static void m4_syscmd();
  133. static void m4_sysval();
  134. static void m4_traceoff();
  135. static void m4_traceon();
  136. static void m4_translit();
  137. static void m4_undefine();
  138. static void m4_undivert();
  139.  
  140. #endif /* not MSDOS */
  141.  
  142. static builtin
  143. builtin_tab[] = {
  144.  
  145.     /* name        gnu    macro-args    function */
  146.  
  147.     { "builtin",    true,    false,        m4_builtin },
  148.     { "changecom",    false,    false,        m4_changecom },
  149.     { "changequote",    false,    false,        m4_changequote },
  150.     { "define",        false,    true,        m4_define },
  151.     { "defn",        false,    false,        m4_defn },
  152.     { "divert",        false,    false,        m4_divert },
  153.     { "divnum",        false,    false,        m4_divnum },
  154.     { "dnl",        false,    false,        m4_dnl },
  155.     { "dumpdef",    false,    false,        m4_dumpdef },
  156.     { "errprint",    false,    false,        m4_errprint },
  157.     { "eval",        false,    false,        m4_eval },
  158.     { "ifdef",        false,    false,        m4_ifdef },
  159.     { "ifelse",        false,    false,        m4_ifelse },
  160.     { "include",    false,    false,        m4_include },
  161.     { "index",        false,    false,        m4_index },
  162.     { "len",        false,    false,        m4_len },
  163.     { "m4exit",        false,    false,        m4_m4exit },
  164.     { "m4wrap",        false,    false,        m4_m4wrap },
  165.     { "maketemp",    false,    false,        m4_maketemp },
  166.     { "popdef",        false,    false,        m4_popdef },
  167.     { "pushdef",    false,    true,        m4_pushdef },
  168.     { "shift",        false,    false,        m4_shift },
  169.     { "sinclude",    false,    false,        m4_sinclude },
  170.     { "substr"    ,    false,    false,        m4_substr },
  171.     { "syscmd",        false,    false,        m4_syscmd },
  172.     { "sysval",        false,    false,        m4_sysval },
  173.     { "traceoff",    false,    false,        m4_traceoff },
  174.     { "traceon",    false,    false,        m4_traceon },
  175.     { "translit",    false,    false,        m4_translit },
  176.     { "undefine",    false,    false,        m4_undefine },
  177.     { "undivert",    false,    false,        m4_undivert },
  178.  
  179.     { 0, false,    false, 0 },
  180. };
  181.  
  182. static predefined 
  183. predefined_tab[] = {
  184.  
  185.     { "unix",    false,    "" },
  186.     { "gnu",    true,    "" },
  187.     { "incr",    false,    "eval(`($1)+1')" },
  188.     { "decr",    false,    "eval(`($1)-1')" },
  189.  
  190.     { 0, false,    0 },
  191. };
  192.  
  193. /* The number of the currently active diversion */
  194. static int current_diversion;
  195.  
  196.  
  197. /* 
  198.  * Find the builtin, which lives on ADDR
  199.  */
  200.  
  201. builtin *
  202. find_builtin_by_addr(func)
  203.     builtin_func *func;
  204. {
  205.     builtin *bp;
  206.  
  207.     for (bp = &builtin_tab[0]; bp->name != nil; bp++)
  208.     if (bp->func == func)
  209.         return bp;
  210.     return nil;
  211. }
  212.  
  213. /* 
  214.  * Find the builtin, which has NAME
  215.  */
  216.  
  217. builtin *
  218. find_builtin_by_name(name)
  219.     char *name;
  220. {
  221.     builtin *bp;
  222.  
  223.     for (bp = &builtin_tab[0]; bp->name != nil; bp++)
  224.     if (strcmp(bp->name, name) == 0)
  225.         return bp;
  226.     return nil;
  227. }
  228.  
  229.  
  230. /* 
  231.  * Install a builtin macro with name NAME, bound to the C function given
  232.  * in BP.
  233.  */
  234. static void 
  235. define_builtin(name, bp, mode)
  236.     char *name;
  237.     builtin *bp;
  238.     symbol_lookup mode;
  239. {
  240.     symbol *sym;
  241.  
  242.     sym = lookup_symbol(name, mode);
  243.     SYMBOL_TYPE(sym) = TOKEN_FUNC;
  244.     SYMBOL_MACRO_ARGS(sym) = bp->groks_macro_args;
  245.     SYMBOL_FUNC(sym) = bp->func;
  246. }
  247.  
  248. /* 
  249.  * Define a predefined or user-defined macro, with name NAME, and
  250.  * expansion TEXT.  MODE destinguishes between the "define" and the
  251.  * "pushdef" case.  It is also used from main().
  252.  */
  253. void 
  254. define_user_macro(name, text, mode)
  255.     char *name;
  256.     char *text;
  257.     symbol_lookup mode;
  258. {
  259.     symbol *s;
  260.     
  261.     s = lookup_symbol(name, mode);
  262.     if (SYMBOL_TYPE(s) == TOKEN_TEXT)
  263.     xfree(SYMBOL_TEXT(s));
  264.     
  265.     SYMBOL_TYPE(s) = TOKEN_TEXT;
  266.     SYMBOL_TEXT(s) = xstrdup(text);
  267. }
  268.  
  269. /* 
  270.  * Initialise all builtin and predefined macros.
  271.  */
  272. void 
  273. builtin_init()
  274. {
  275.     builtin *bp;
  276.     predefined *pp;
  277.  
  278.     for (bp = &builtin_tab[0]; bp->name != nil; bp++) {
  279.     if (!(no_gnu_extensions && bp->gnu_extension))
  280.         define_builtin(bp->name, bp, SYMBOL_INSERT);
  281.     }
  282.  
  283.     for (pp = &predefined_tab[0]; pp->name != nil; pp++) {
  284.     if (!(no_gnu_extensions && pp->gnu_extension))
  285.         define_user_macro(pp->name, pp->func, SYMBOL_INSERT);
  286.     }
  287.  
  288.     current_diversion = 0;
  289. }
  290.  
  291. /* 
  292.  * Give friendly warnings, if a builtin macro is passed an inappropriate
  293.  * number of arguments.  NAME is macro name for messages, ARGC is actual
  294.  * number of arguments, MIN is minimum number of acceptable arguments,
  295.  * negative if inapplicable, MAX is maximum number, negative if
  296.  * inapplicable.
  297.  */
  298. static boolean 
  299. bad_argc(name, argc, min, max)
  300.     char *name;
  301.     int argc;
  302.     int min;
  303.     int max;
  304. {
  305.     if (min > 0 && argc < min) {
  306.     warning("too few arguments to %s", name);
  307.     return true;
  308.     } else if (max > 0 && argc > max)
  309.     warning("excess arguments to %s ignored", name);
  310.     return false;
  311. }
  312.  
  313. /* 
  314.  * Format an int VAL, and stuff it into an obstack OBS.
  315.  */
  316. static void 
  317. shipout_int(obs, val)
  318.     struct obstack *obs;
  319.     int val;
  320. {
  321.     char buf[512];
  322.     sprintf(buf, "%d", val);
  323.     obstack_grow(obs, buf, strlen(buf));
  324. }
  325.     
  326.  
  327. /* 
  328.  * Print all arguments to a macro to obstack OBS, separated by SEP, and
  329.  * quoted by the current quotes, if QUOTED is true.
  330.  */
  331. static void 
  332. dump_args(obs, argc, argv, sep, quoted)
  333.     struct obstack *obs;
  334.     int argc;
  335.     token_data **argv;
  336.     char *sep;
  337.     boolean quoted;
  338. {
  339.     int i;
  340.     int len = strlen(sep);
  341.  
  342.     for (i = 1; i < argc; i++) {
  343.     if (i > 1)
  344.         obstack_grow(obs, sep, len);
  345.     if (quoted)
  346.         obstack_1grow(obs, lquote);
  347.     obstack_grow(obs, TOKEN_DATA_TEXT(argv[i]), strlen(TOKEN_DATA_TEXT(argv[i])));
  348.     if (quoted)
  349.         obstack_1grow(obs, rquote);
  350.     }
  351. }
  352.  
  353.  
  354. /* 
  355.  * The rest of this file is code for builtins and expansion of user
  356.  * defined macros.  All the functions for builtins have a prototype as:
  357.  * 
  358.  *     void m4_MACRONAME(struct obstack *obs, int argc, char *argv[]);
  359.  *
  360.  * The function are expected to leave their expansion on the obstack
  361.  * OBS, as an unfinished object.  ARGV is a table of ARGC pointers to
  362.  * the individual arguments to the macro.  Please note that in general
  363.  * argv[argc] != nil.
  364.  */
  365.  
  366. /* 
  367.  * The first section are macros for definining, undefining, examining,
  368.  * changing, ... other macros.
  369.  */
  370. static void 
  371. define_macro(argc, argv, mode)
  372.     int argc;
  373.     token_data **argv;
  374.     symbol_lookup mode;
  375. {
  376.     builtin *bp;
  377.  
  378.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 3, 3))
  379.     return;
  380.  
  381.     if (TOKEN_DATA_TYPE(argv[1]) != TOKEN_TEXT)
  382.     return;
  383.  
  384.     switch (TOKEN_DATA_TYPE(argv[2])) {
  385.     case TOKEN_TEXT:
  386.     define_user_macro(ARG(1), ARG(2), mode);
  387.     break;
  388.     case TOKEN_FUNC:
  389.     bp = find_builtin_by_addr(TOKEN_DATA_FUNC(argv[2]));
  390.     if (bp == nil)
  391.         return;
  392.     else
  393.         define_builtin(ARG(1), bp, mode);
  394.     break;
  395.     default:
  396.     internal_error("Bad token data type in define_macro()");
  397.     break;
  398.     }
  399.     return;
  400. }
  401.  
  402. static void 
  403. m4_define(obs, argc, argv)
  404.     struct obstack *obs;
  405.     int argc;
  406.     token_data **argv;
  407. {
  408.     define_macro(argc, argv, SYMBOL_INSERT);
  409. }
  410.  
  411.  
  412. static void 
  413. m4_undefine(obs, argc, argv)
  414.     struct obstack *obs;
  415.     int argc;
  416.     token_data **argv;
  417. {
  418.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  419.     return;
  420.     lookup_symbol(ARG(1), SYMBOL_DELETE);
  421. }
  422.  
  423. static void 
  424. m4_pushdef(obs, argc, argv)
  425.     struct obstack *obs;
  426.     int argc;
  427.     token_data **argv;
  428. {
  429.     define_macro(argc, argv,  SYMBOL_PUSHDEF);
  430. }
  431.  
  432.  
  433. static void 
  434. m4_popdef(obs, argc, argv)
  435.     struct obstack *obs;
  436.     int argc;
  437.     token_data **argv;
  438. {
  439.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  440.     return;
  441.     lookup_symbol(ARG(1), SYMBOL_POPDEF);
  442. }
  443.  
  444. static void 
  445. m4_ifdef(obs, argc, argv)
  446.     struct obstack *obs;
  447.     int argc;
  448.     token_data **argv;
  449. {
  450.     symbol *s;
  451.     char *result;
  452.     
  453.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 3, 4))
  454.     return;
  455.     s = lookup_symbol(ARG(1), SYMBOL_LOOKUP);
  456.  
  457.     if (s != nil)
  458.     result = ARG(2);
  459.     else if (argc == 4)
  460.     result = ARG(3);
  461.     else
  462.     result = nil;
  463.  
  464.     if (result != nil)
  465.     obstack_grow(obs, result, strlen(result));
  466. }
  467.  
  468. static void 
  469. m4_ifelse(obs, argc, argv)
  470.     struct obstack *obs;
  471.     int argc;
  472.     token_data **argv;
  473. {
  474.     char *result;
  475.     char *name = TOKEN_DATA_TEXT(argv[0]);
  476.  
  477.     --argc, ++argv;
  478.  
  479.     result = nil;
  480.     while (result == nil) {
  481.     bad_argc(name, argc, 3, -1);
  482.  
  483.     if (strcmp(ARG(0), ARG(1)) == 0) {
  484.         result = ARG(2);
  485.     } else {
  486.         switch (argc) {
  487.         case 2:
  488.         result = "";
  489.         break;
  490.         case 3:
  491.         case 4:
  492.         result = ARG(3);
  493.         break;
  494.         default:
  495.         argc -= 3;
  496.         argv += 3;
  497.         break;
  498.         }
  499.     }
  500.     }
  501.     obstack_grow(obs, result, strlen(result));
  502. }
  503.  
  504. /* 
  505.  * The function dump_symbol() is for use by "dumpdef".  It builds up a
  506.  * table of all defined, un-shadowed, symbols.  The structure
  507.  * dump_symbol_data is used to pass the information needed from call to
  508.  * call to dump_symbol.
  509.  */
  510.  
  511. struct dump_symbol_data {
  512.     struct obstack *obs;        /* obstack for table */
  513.     symbol **base;            /* base of table */
  514.     int size;                /* size of table */
  515. };
  516.  
  517. static void 
  518. dump_symbol(sym, data)
  519.     symbol *sym;
  520.     struct dump_symbol_data *data;
  521. {
  522.     if (!sym->shadowed) {
  523.     obstack_blank(data->obs, sizeof(symbol*));
  524.     data->base = (symbol **)obstack_base(data->obs);
  525. #if defined(_MSC_VER) && (_MSC_VER == 600)
  526.     /* Work around an optimizer bug.  */
  527.     { int tmp = data->size++; data->base[tmp] = sym; }
  528. #else
  529.     data->base[data->size++] = sym;
  530. #endif
  531.     }
  532. }
  533.  
  534. /* 
  535.  * qsort comparison routine, for sorting the table made in m4_dumpdef().
  536.  */
  537. static int 
  538. dumpdef_cmp(s1, s2)
  539.     symbol **s1, **s2;
  540. {
  541.     return strcmp(SYMBOL_NAME(*s1), SYMBOL_NAME(*s2));
  542. }
  543.  
  544. /* 
  545.  * Implementation of "dumpdef" itself.  It builds up a table of pointers
  546.  * to symbols, sorts it and prints the sorted table.
  547.  */
  548. static void 
  549. m4_dumpdef(obs, argc, argv)
  550.     struct obstack *obs;
  551.     int argc;
  552.     token_data **argv;
  553. {
  554.     symbol *s;
  555.     int i;
  556.     struct dump_symbol_data data;
  557.     builtin *bp;
  558.  
  559.     data.obs = obs;
  560.     data.base = (symbol **)obstack_base(obs);
  561.     data.size = 0;
  562.     
  563.     if (argc == 1) {
  564.     hack_all_symbols(dump_symbol, (char *)&data);
  565.     } else {
  566.     for (i = 1; i < argc; i++) {
  567.         s = lookup_symbol(TOKEN_DATA_TEXT(argv[i]), SYMBOL_LOOKUP);
  568.         if (s != nil)
  569. #ifdef MSDOS
  570.         dump_symbol(s, &data);
  571. #else /* not MSDOS */
  572.         dump_symbol(s, (char *)&data);
  573. #endif /* not MSDOS */
  574.         else
  575.         error("Undefined name %s", TOKEN_DATA_TEXT(argv[i]));
  576.     }
  577.     }
  578.  
  579.     qsort((char*)data.base, data.size, sizeof(symbol*), dumpdef_cmp);
  580.  
  581.     for ( ; data.size > 0; --data.size, data.base++) {
  582.     fprintf(stderr, "%s:\t", SYMBOL_NAME(data.base[0]));
  583.     switch(SYMBOL_TYPE(data.base[0])) {
  584.     case TOKEN_TEXT:
  585.         fprintf(stderr, "`%s'\n", SYMBOL_TEXT(data.base[0]));
  586.         break;
  587.     case TOKEN_FUNC:
  588.         bp = find_builtin_by_addr(SYMBOL_FUNC(data.base[0]));
  589.         if (bp == nil)
  590.         internal_error("builtin not found in builtin table!");
  591.         fprintf(stderr, "<%s>\n", bp->name);
  592.         break;
  593.     default:
  594.         internal_error("Bad token data type in m4_dumpdef()");
  595.         break;
  596.     }
  597.     }
  598.  
  599. #ifdef MSDOS            /* but it's a genuine bug.  */
  600.   /* Or is the intention to finalize the object?
  601.      (cf. m4_errprint (), which could also free the object)  */
  602.   obstack_free (obs, obstack_base (obs));
  603. #endif
  604. }
  605.  
  606. /* 
  607.  * This is non-standard.  "Builtin" allows calls to builtin macros, even
  608.  * if thier definition has been overridden or shadowed.  It is thus
  609.  * possible to redefine builtins, and still access their original
  610.  * definition.
  611.  *
  612.  * This macro is not available in compatibility mode.
  613.  */
  614. static void 
  615. m4_builtin(obs, argc, argv)
  616.     struct obstack *obs;
  617.     int argc;
  618.     token_data **argv;
  619. {
  620.     struct builtin *bp;
  621.     char *name = ARG(1);
  622.  
  623.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, -1))
  624.     return;
  625.  
  626.     bp = find_builtin_by_name(name);
  627.     if (bp == nil)
  628.     error("Undefined name %s", name);
  629.     else
  630.     (*bp->func)(obs, argc-1, argv+1);
  631. }
  632.  
  633. /* 
  634.  * The macro "defn" returns the quoted definition of its first argument.
  635.  */
  636. static void 
  637. m4_defn(obs, argc, argv)
  638.     struct obstack *obs;
  639.     int argc;
  640.     token_data **argv;
  641. {
  642.     symbol *s;
  643.     
  644.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  645.     return;
  646.  
  647.     s = lookup_symbol(ARG(1), SYMBOL_LOOKUP);
  648.     if (s == nil)
  649.     return;
  650.  
  651.     switch (SYMBOL_TYPE(s)) {
  652.     case TOKEN_TEXT:
  653.     obstack_1grow(obs, lquote);
  654.     obstack_grow(obs, SYMBOL_TEXT(s), strlen(SYMBOL_TEXT(s)));
  655.     obstack_1grow(obs, rquote);
  656.     break;
  657.     case TOKEN_FUNC:
  658.     push_macro(SYMBOL_FUNC(s));
  659.     break;
  660.     default:
  661.     internal_error("Bad symbol type in m4_defn()");
  662.     break;
  663.     }
  664. }
  665.  
  666.  
  667. /* 
  668.  * This section contains macros to handle the builtins "syscmd" and
  669.  * "sysval".
  670.  */
  671.  
  672. /* Exit code from last "syscmd" command. */
  673. static int sysval;
  674.  
  675. static void 
  676. m4_syscmd(obs, argc, argv)
  677.     struct obstack *obs;
  678.     int argc;
  679.     token_data **argv;
  680. {
  681. #ifdef MSDOS
  682.  
  683.   /* The system function from the MSC runtime lib doesn't return
  684.      the exit code, so we have to hack one ourselves.  */
  685.  
  686.   char *sysargv[4];
  687.   char *p = NULL;
  688.  
  689.   if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  690.     return;
  691.  
  692.   /* Find $SHELL or $COMSPEC, assuming the former is a UNIX style
  693.      shell (preferred) and the latter is a DOS style command
  694.      processor.  */
  695.  
  696.   sysargv[0] = getenv ("SHELL");
  697.   if (sysargv[0])
  698.     sysargv[1] = "-c";
  699.   else
  700.     {
  701.       sysargv[0] = getenv ("COMSPEC");
  702.       if (sysargv[0])
  703.     sysargv[1] = "/c";
  704.       else
  705.     {
  706.       errno = ENOENT;
  707.       sysval = (-1) << 8;
  708.       return;
  709.     }
  710.     }
  711.  
  712.   /* Let the shell execute COMMAND.  */
  713.  
  714.   sysargv[2] = ARG(1);
  715.   sysargv[3] = NULL;
  716.  
  717.   /* Precompensate the ">> 8" from m4_sysval ()  */
  718.   sysval = spawnvpe (P_WAIT, sysargv[0], sysargv, NULL) << 8;
  719.  
  720. #else /* not MSDOS */
  721.  
  722.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  723.     return;
  724.     sysval = system(ARG(1));
  725.  
  726. #endif /* not MSDOS */
  727. }
  728.  
  729. static void 
  730. m4_sysval(obs, argc, argv)
  731.     struct obstack *obs;
  732.     int argc;
  733.     token_data **argv;
  734. {
  735.     shipout_int(obs, sysval>>8);
  736. }
  737.     
  738.  
  739.  
  740. /* 
  741.  * This section contains the top level code for the "eval" builtin.  The
  742.  * actual work is done in the function evaluate(), which lives in eval.c.
  743.  */
  744.  
  745. /* digits for number to ascii conversions. */
  746. static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  747.  
  748. static char *
  749. ntoa(value, radix)
  750.     register eval_t value;
  751.     int radix;
  752. {
  753. #ifdef MSDOS
  754.     unsigned long uvalue;
  755. #else
  756.     unsigned int uvalue;
  757. #endif
  758.     static char str[256];
  759.     register char *s = &str[sizeof str];
  760.     boolean negative = false;
  761.  
  762.     *--s = '\0';
  763.     
  764.     if (radix == 10 && value < 0) {
  765.     int tmp;
  766.  
  767.     negative = true;
  768.     value = -(value+1);
  769.  
  770. #ifdef MSDOS            /* shut up the compiler.  */
  771.     tmp = (int) (value%radix);
  772. #else
  773.     tmp = value%radix;
  774. #endif
  775.     if (tmp == radix - 1) {
  776.         *--s = '0';
  777.         value = value/radix + 1;
  778.     } else {
  779.         *--s = digits[tmp+1];
  780.         value /= radix;
  781.     }
  782.     if (value == 0) {
  783.         *--s = '-';
  784.         return s;
  785.     }
  786.     }
  787.  
  788.  
  789. #ifdef MSDOS
  790.     uvalue = (unsigned long)value;
  791. #else
  792.     uvalue = (unsigned int)value;
  793. #endif
  794.     do {
  795.     *--s = digits[uvalue%radix];
  796.     uvalue /= radix;
  797.     } while (uvalue > 0);
  798.  
  799.     if (negative)
  800.     *--s = '-';
  801.     return s;
  802. }
  803.  
  804. static void 
  805. m4_eval(obs, argc, argv)
  806.     struct obstack *obs;
  807.     int argc;
  808.     token_data **argv;
  809. {
  810.     eval_t value;
  811.     int radix = 10;
  812.     int min = 1;
  813.     char *s;
  814.  
  815.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 4))
  816.     return;
  817.  
  818.     if (argc >= 3 && (sscanf(ARG(2), "%d", &radix) != 1)) {
  819.     error("non-numeric second argument to eval");
  820.     return;
  821.     }
  822.     if (radix <= 1 || radix > strlen(digits)) {
  823.     error("radix in eval out of range (radix = %d)", radix);
  824.     return;
  825.     }
  826.     if (argc >= 4 && (sscanf(ARG(3), "%d", &min) != 1 || min <= 0)) {
  827.     error("non-numeric third argument to eval");
  828.     return;
  829.     }
  830.     
  831.     if (evaluate(ARG(1), &value))
  832.     return;
  833.  
  834.     s = ntoa(value, radix);
  835.  
  836.     if (*s == '-') {
  837.     obstack_1grow(obs, '-');
  838.     min--;
  839.     s++;
  840.     }
  841.     for (min -= strlen(s); --min >= 0; )
  842.     obstack_1grow(obs, '0');
  843.  
  844.     obstack_grow(obs, s, strlen(s));
  845. }
  846.  
  847.  
  848.  
  849. /* 
  850.  * This section contains the macros for handling diversion.
  851.  */
  852.  
  853. /* 
  854.  * Divert further output to the diversion given by ARGV[ARGC].  Out of
  855.  * range means discard further output.
  856.  */
  857. static void 
  858. m4_divert(obs, argc, argv)
  859.     struct obstack *obs;
  860.     int argc;
  861.     token_data **argv;
  862. {
  863.     int i = 0;
  864.  
  865.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 1, 2))
  866.     return;
  867.     
  868.     if (argc == 2 && sscanf(ARG(1), "%d", &i) != 1) {
  869.     error("non-numeric argument to divert");
  870.     return;
  871.     }
  872.     make_divertion(i);
  873.     current_diversion = i;
  874. }
  875.  
  876. /* 
  877.  * Expand to the current diversion number, -1 if none.
  878.  */
  879. static void 
  880. m4_divnum(obs, argc, argv)
  881.     struct obstack *obs;
  882.     int argc;
  883.     token_data **argv;
  884. {
  885.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 1, 1))
  886.     return;
  887.     shipout_int(obs, current_diversion);
  888. }
  889.     
  890. /* 
  891.  * Bring back the diversion given by the argument list.  If none is
  892.  * specified, bring back all diversions.
  893.  */
  894. static void 
  895. m4_undivert(obs, argc, argv)
  896.     struct obstack *obs;
  897.     int argc;
  898.     token_data **argv;
  899. {
  900.     int i, div;
  901.  
  902.     if (argc == 1) {
  903.     undivert_all();
  904.     } else {
  905.     for (i = 1; i < argc; i++) {
  906.         if (sscanf(ARG(1), "%d", &div) != 1) {
  907.         error("non-numeric argument to divert");
  908.         continue;
  909.         }
  910.         insert_divertion(div);
  911.     }
  912.     }
  913. }
  914.  
  915.  
  916. /* 
  917.  * This section contains various macros, which does not fall into any
  918.  * specific group.
  919.  */
  920.  
  921. /* 
  922.  * Delete all subsequent whitespace from input.  skip_whitespace() lives
  923.  * in input.c.
  924.  */
  925. static void 
  926. m4_dnl(obs, argc, argv)
  927.     struct obstack *obs;
  928.     int argc;
  929.     token_data **argv;
  930. {
  931.     skip_line();
  932. }
  933.  
  934. /* 
  935.  * Shift all argument one to the left, discarding the first argument.
  936.  * Each output argument is quoted iwth the current quotes.
  937.  */
  938. static void 
  939. m4_shift(obs, argc, argv)
  940.     struct obstack *obs;
  941.     int argc;
  942.     token_data **argv;
  943. {
  944.     dump_args(obs, argc-1, argv+1, ", ", true);
  945. }
  946.  
  947. /* 
  948.  * Change the current quotes.  Currently, only single character quotes
  949.  * are supported.
  950.  */
  951. static void 
  952. m4_changequote(obs, argc, argv)
  953.     struct obstack *obs;
  954.     int argc;
  955.     token_data **argv;
  956. {
  957.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 1, 3))
  958.     return;
  959.  
  960.     lquote = (argc >= 2) ? TOKEN_DATA_TEXT(argv[1])[0] : DEF_LQUOTE;
  961.     rquote = (argc >= 3) ? TOKEN_DATA_TEXT(argv[2])[0] : DEF_RQUOTE;
  962. }
  963.  
  964. /* 
  965.  * Change the current comment delimiters.  Currently, only single
  966.  * comment delimiters are supported.
  967.  */
  968. static void 
  969. m4_changecom(obs, argc, argv)
  970.     struct obstack *obs;
  971.     int argc;
  972.     token_data **argv;
  973. {
  974.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 1, 3))
  975.     return;
  976.  
  977.     bcomm = (argc >= 2) ? TOKEN_DATA_TEXT(argv[1])[0] : DEF_BCOMM;
  978.     ecomm = (argc >= 3) ? TOKEN_DATA_TEXT(argv[2])[0] : DEF_ECOMM;
  979. }
  980.  
  981.  
  982. /* 
  983.  * This section contains macros for inclusion of other files.  This
  984.  * differs from diversion, in that the input is scanned before being
  985.  * copied to the output.
  986.  */
  987. /* 
  988.  * Generic include function.  Include the file given by the first
  989.  * argument, if it exists.  Complain about inaccesible files, only if
  990.  * SILENT is false.
  991.  */
  992. static void 
  993. include(argc, argv, silent)
  994.     int argc;
  995.     token_data **argv;
  996.     boolean silent;
  997. {
  998.     FILE *fp;
  999.  
  1000.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  1001.     return;
  1002.  
  1003.     fp = fopen(ARG(1), "r");
  1004.     if (fp == nil) {
  1005.     if (!silent)
  1006.         error("can't open %s: %s", ARG(1), syserr());
  1007.     return;
  1008.     }
  1009.  
  1010.     push_file(fp, ARG(1));
  1011. }
  1012.  
  1013. /* 
  1014.  * Include a file, complaining in case of errors.
  1015.  */
  1016. static void 
  1017. m4_include(obs, argc, argv)
  1018.     struct obstack *obs;
  1019.     int argc;
  1020.     token_data **argv;
  1021. {
  1022.     include(argc, argv, false);
  1023. }
  1024.  
  1025. /* 
  1026.  * Include a file, ignoring errors.
  1027.  */
  1028. static void 
  1029. m4_sinclude(obs, argc, argv)
  1030.     struct obstack *obs;
  1031.     int argc;
  1032.     token_data **argv;
  1033. {
  1034.     include(argc, argv, true);
  1035. }
  1036.  
  1037.  
  1038. /* 
  1039.  * Use the first argument as at template for a temporary file name.
  1040.  */
  1041. static void 
  1042. m4_maketemp(obs, argc, argv)
  1043.     struct obstack *obs;
  1044.     int argc;
  1045.     token_data **argv;
  1046. {
  1047.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  1048.     return;
  1049.     mktemp(ARG(1));
  1050.     obstack_grow(obs, ARG(1), strlen(ARG(1)));
  1051. }
  1052.  
  1053. /* 
  1054.  * Print all arguments on standard error.
  1055.  */
  1056. static void 
  1057. m4_errprint(obs, argc, argv)
  1058.     struct obstack *obs;
  1059.     int argc;
  1060.     token_data **argv;
  1061. {
  1062.     dump_args(obs, argc, argv, " ", false);
  1063. #ifdef MSDOS            /* but it's a genuine bug.  */
  1064.     obstack_1grow(obs, '\0');
  1065. #endif
  1066.     fprintf(stderr, "%s", obstack_finish(obs));
  1067.     fflush(stderr);
  1068. }
  1069.  
  1070.  
  1071. /* 
  1072.  * This section contains various macros for exiting, saving input until
  1073.  * EOF is seen, and tracing macro calls.
  1074.  */
  1075. /* 
  1076.  * Exit immediately, with exitcode specified by the first argument, 0 if
  1077.  * no arguments are present.
  1078.  */
  1079. static void 
  1080. m4_m4exit(obs, argc, argv)
  1081.     struct obstack *obs;
  1082.     int argc;
  1083.     token_data **argv;
  1084. {
  1085.     int exit_code = 0;
  1086.  
  1087.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 1, 2))
  1088.     return;
  1089.     if (argc == 2  && sscanf(ARG(1), "%d", &exit_code) != 1) {
  1090.     error("non-numeric argument to m4exit");
  1091.     exit_code = 0;
  1092.     }
  1093.     exit(exit_code);
  1094. }
  1095.  
  1096. /* 
  1097.  * Save the argument text until EOF has been seen, allowing for user
  1098.  * specified cleanup action.  GNU version saves all arguments, the
  1099.  * standard version only the first.
  1100.  */
  1101. static void 
  1102. m4_m4wrap(obs, argc, argv)
  1103.     struct obstack *obs;
  1104.     int argc;
  1105.     token_data **argv;
  1106. {
  1107.     if (no_gnu_extensions) {
  1108.     obstack_grow(obs, ARG(1), strlen(ARG(1)));
  1109.     } else
  1110.     dump_args(obs, argc, argv, " ", false);
  1111. #ifdef MSDOS            /* but it's a genuine bug.  */
  1112.     obstack_1grow(obs, '\0');
  1113. #endif
  1114.     push_wrapup(obstack_finish(obs));
  1115. }
  1116.  
  1117. /* 
  1118.  * Enable tracing of all specified macros, or all, if none is specified.
  1119.  * Tracing is disabled by default, when a macro is defined.
  1120.  */
  1121.  
  1122. /* 
  1123.  * Set_trace() is used by "traceon" and "traceoff" to enable and disable
  1124.  * tracing of a macro.  It disables tracing if DATA is nil, otherwise it
  1125.  * enable tracing.
  1126.  */
  1127. static void 
  1128. set_trace(sym, data)
  1129.     symbol *sym;
  1130.     char *data;
  1131. {
  1132.     SYMBOL_TRACED(sym) = (boolean)(data != nil);
  1133. }
  1134.  
  1135. static void 
  1136. m4_traceon(obs, argc, argv)
  1137.     struct obstack *obs;
  1138.     int argc;
  1139.     token_data **argv;
  1140. {
  1141.     symbol *s;
  1142.     int i;
  1143.  
  1144.     if (argc == 1)
  1145.     hack_all_symbols(set_trace, (char *)obs);
  1146.     else
  1147.     for (i = 1; i < argc; i++) {
  1148.         s = lookup_symbol(TOKEN_DATA_TEXT(argv[i]), SYMBOL_LOOKUP);
  1149.         if (s != nil)
  1150.         set_trace(s, (char *)obs);
  1151.         else
  1152.         error("Undefined name %s", TOKEN_DATA_TEXT(argv[i]));
  1153.     }
  1154. }
  1155.  
  1156. /* 
  1157.  * Disable tracing of all specified macros, or all, if none is
  1158.  * specified.
  1159.  */
  1160. static void 
  1161. m4_traceoff(obs, argc, argv)
  1162.     struct obstack *obs;
  1163.     int argc;
  1164.     token_data **argv;
  1165. {
  1166.     symbol *s;
  1167.     int i;
  1168.  
  1169.     if (argc == 1)
  1170.     hack_all_symbols(set_trace, nil);
  1171.     else
  1172.     for (i = 1; i < argc; i++) {
  1173.         s = lookup_symbol(TOKEN_DATA_TEXT(argv[i]), SYMBOL_LOOKUP);
  1174.         if (s != nil)
  1175.         set_trace(s, nil);
  1176.         else
  1177.         error("Undefined name %s", TOKEN_DATA_TEXT(argv[i]));
  1178.     }
  1179. }
  1180.  
  1181.  
  1182. /* 
  1183.  * This section contains some text processing macros.
  1184.  */
  1185. /* 
  1186.  * Expand to the length of the first argument.
  1187.  */
  1188. static void 
  1189. m4_len(obs, argc, argv)
  1190.     struct obstack *obs;
  1191.     int argc;
  1192.     token_data **argv;
  1193. {
  1194.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 2, 2))
  1195.     return;
  1196.     shipout_int(obs, strlen(ARG(1)));
  1197. }
  1198.  
  1199. /* 
  1200.  * The macro expands to the first index of the second argument in the
  1201.  * first argument.
  1202.  */
  1203. static void 
  1204. m4_index(obs, argc, argv)
  1205.     struct obstack *obs;
  1206.     int argc;
  1207.     token_data **argv;
  1208. {
  1209.     char *cp, *last;
  1210.     int l1, l2, retval;
  1211.  
  1212.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 3, 3))
  1213.     return;
  1214.  
  1215.     l1 = strlen(ARG(1));
  1216.     l2 = strlen(ARG(2));
  1217.     
  1218.     last = ARG(1) + l1 - l2;
  1219.  
  1220.     for (cp = ARG(1); cp <= last; cp++) {
  1221.     if (strncmp(cp, ARG(2), l2) == 0)
  1222.         break;
  1223.     }
  1224.     retval = (cp <= last) ? cp - ARG(1) : -1;
  1225.     
  1226.     shipout_int(obs, retval);
  1227. }
  1228.  
  1229. /* 
  1230.  * The macro "substr" extracts substrings from the first argument,
  1231.  * starting from the index given by the second argument, extending for a
  1232.  * length given by the third argument.  If the third argument is
  1233.  * missing, the substring extends to the end of the first argument.
  1234.  */
  1235. static void 
  1236. m4_substr(obs, argc, argv)
  1237.     struct obstack *obs;
  1238.     int argc;
  1239.     token_data **argv;
  1240. {
  1241.     int start, length, avail;
  1242.  
  1243.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 3, 4))
  1244.     return;
  1245.     
  1246.     length = avail = strlen(ARG(1));
  1247.     if (sscanf(ARG(2), "%d", &start) != 1) {
  1248.     error("non-numeric second argument to substr");
  1249.     return;
  1250.     }
  1251.     if (argc == 4 && sscanf(ARG(3), "%d", &length) != 1) {
  1252.     error("non-numeric third argument to substr");
  1253.     return;
  1254.     }
  1255.     if (start < 0 || length <= 0 || start >= avail)
  1256.     return;
  1257.     if (start + length > avail)
  1258.     length = avail - start;
  1259.     obstack_grow(obs, ARG(1) + start, length);
  1260. }
  1261.  
  1262. /* 
  1263.  * The macro "translit" transliterates all characters in the first
  1264.  * argument, which are present in the second argument, into the
  1265.  * corresponding character from the third argument.  If the third
  1266.  * argument is shorter than the second, the extra characters in the
  1267.  * second argument, are delete from the first. (pueh)
  1268.  */
  1269. static void 
  1270. m4_translit(obs, argc, argv)
  1271.     struct obstack *obs;
  1272.     int argc;
  1273.     token_data **argv;
  1274. {
  1275.     register char *data, *tmp;
  1276.     char *from, *to;
  1277.     int tolen;
  1278.  
  1279.     if (bad_argc(TOKEN_DATA_TEXT(argv[0]), argc, 3, 4))
  1280.     return;
  1281.  
  1282.     from = ARG(2);
  1283.     to = argc == 4 ? ARG(3) : "";
  1284.     tolen = strlen(to);
  1285.  
  1286.     for (data = ARG(1); *data; data++) {
  1287.     tmp = (char*)index(from, *data);
  1288.     if (tmp == nil){
  1289.         obstack_1grow(obs, *data);
  1290.         continue;
  1291.     }
  1292.     if (tmp - from >= tolen)
  1293.         continue;
  1294.     obstack_1grow(obs, *(to + (tmp - from)));
  1295.     }
  1296. }
  1297.  
  1298. /* 
  1299.  * This function handles all expansion of user defined and predefined
  1300.  * macros.  It is called with an obstack OBS, where the macros expansion
  1301.  * will be placed, as an unfinished object.  SYM points to the macro
  1302.  * definition, giving the expansin text.  ARGC and ARGV are the
  1303.  * arguments, as usual.
  1304.  */
  1305. void 
  1306. expand_user_macro(obs, sym, argc, argv)
  1307.     struct obstack *obs;
  1308.     symbol *sym;
  1309.     int argc;
  1310.     token_data **argv;
  1311. {
  1312.     register char *text;
  1313.     int i;
  1314.  
  1315.     for  (text = SYMBOL_TEXT(sym); *text != '\0'; ) {
  1316.     if (*text != '$') {
  1317.         obstack_1grow(obs, *text);
  1318.         text++;
  1319.         continue;
  1320.     }
  1321.     text++;
  1322.     switch (*text) {
  1323.     case '0': case '1': case '2': case '3': case '4':
  1324.     case '5': case '6': case '7': case '8': case '9':
  1325.         if (no_gnu_extensions) {
  1326.         i = *text++ - '0';
  1327.         } else {
  1328.         for (i = 0; isdigit(*text); text++)
  1329.             i = i*10 + (*text - '0');
  1330.         }
  1331.         if (i < argc)
  1332.         obstack_grow(obs, TOKEN_DATA_TEXT(argv[i]), strlen(TOKEN_DATA_TEXT(argv[i])));
  1333.         break;
  1334.  
  1335.     case '#':            /* number of arguments */
  1336.         shipout_int(obs, argc-1);
  1337.         text++;
  1338.         break;
  1339.  
  1340.     case '*':            /* all arguments */
  1341.     case '@':            /* ... same, but quoted */
  1342.         dump_args(obs, argc, argv, ", ", *text == '@');
  1343.         text++;
  1344.         break;
  1345.  
  1346.     default:
  1347.         obstack_1grow(obs, '$');
  1348.         break;
  1349.     }
  1350.     }
  1351. }
  1352.