home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / MAK358AS.ZIP / FUNCTION.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-22  |  32.6 KB  |  1,281 lines

  1. /* Variable function expansion for GNU Make.
  2. Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  3. This file is part of GNU Make.
  4.  
  5. GNU Make 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. GNU Make 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 GNU Make; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /*
  20.  * MS-DOS port (c) 1990 by Thorsten Ohl <ohl@gnu.ai.mit.edu>
  21.  *
  22.  * To this port, the same copying conditions apply as to the
  23.  * original release.
  24.  *
  25.  * IMPORTANT:
  26.  * This file is not identical to the original GNU release!
  27.  * You should have received this code as patch to the official
  28.  * GNU release.
  29.  *
  30.  * MORE IMPORTANT:
  31.  * This port comes with ABSOLUTELY NO WARRANTY.
  32.  *
  33.  * $Header: e:/gnu/make/RCS/function.c'v 3.58.0.3 90/07/19 01:01:52 tho Exp $
  34.  */
  35.  
  36. #include "make.h"
  37. #include "variable.h"
  38. #include "dep.h"
  39. #include "commands.h"
  40. #include "job.h"
  41. #include <errno.h>
  42.  
  43. #ifdef MSDOS
  44. #include <fcntl.h>
  45. #include <io.h>
  46. #include <time.h>
  47. #include <process.h>
  48. #include <swaplib.h>
  49.  
  50. extern int last_child_pid;
  51. extern int last_child_status;
  52. #endif /* MSDOS */
  53.  
  54. #ifndef MSDOS
  55. extern int errno;
  56. #endif /* not MSDOS */
  57.  
  58. #ifdef MSDOS
  59. static  char *expand_function (char *o, enum function function, char *text, char *end);
  60. static  char *string_glob (char *line);
  61. #else /* not MSDOS */
  62. static char *string_glob ();
  63. #endif /* not MSDOS */
  64.  
  65.  
  66. /* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing
  67.    each occurrence of SUBST with REPLACE. TEXT is null-terminated.  SLEN is
  68.    the length of SUBST and RLEN is the length of REPLACE.  If BY_WORD is
  69.    nonzero, substitutions are done only on matches which are complete
  70.    whitespace-delimited words.  If SUFFIX_ONLY is nonzero, substitutions are
  71.    done only at the ends of whitespace-delimited words.  */
  72.    
  73. char *
  74. subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only)
  75.      char *o;
  76.      char *text;
  77.      char *subst, *replace;
  78.      unsigned int slen, rlen;
  79.      int by_word, suffix_only;
  80. {
  81.   register char *t = text;
  82.   register char *p;
  83.  
  84.   if (slen == 0 && !by_word && !suffix_only)
  85.     {
  86.       /* The first occurence of "" in any string is its end.  */
  87.       o = variable_buffer_output (o, t, strlen (t));
  88.       if (rlen > 0)
  89.     o = variable_buffer_output (o, replace, rlen);
  90.       return o;
  91.     }
  92.  
  93.   while ((p = sindex (t, 0, subst, slen)) != 0)
  94.     {
  95.       /* Output everything before this occurence of the string to replace.  */
  96.       if (p > t)
  97.     o = variable_buffer_output (o, t, p - t);
  98.  
  99.       /* If we're substituting only by fully matched words,
  100.      or only at the ends of words, check that this case qualifies.  */
  101.       if ((by_word
  102.        && ((p > t && p[-1] != ' ' && p[-1] != '\t')
  103.            || (p[slen] != '\0' && p[slen] != ' ' && p[slen] != '\t'))
  104.        || (suffix_only
  105.            && (p[slen] != '\0' && p[slen] != ' ' && p[slen] != '\t'))))
  106.     /* Struck out.  Output the rest of the string that is
  107.        no longer to be replaced.  */
  108.     o = variable_buffer_output (o, subst, slen);
  109.       else if (rlen > 0)
  110.     /* Output the replacement string.  */
  111.     o = variable_buffer_output (o, replace, rlen);
  112.  
  113.       /* Advance T past the string to be replaced.  */
  114.       t = p + slen;
  115.     }
  116.  
  117.   /* Output everything left on the end.  */
  118.   if (*t != '\0')
  119.     o = variable_buffer_output (o, t, strlen (t));
  120.  
  121.   return o;
  122. }
  123.  
  124.  
  125. /* Store into VARIABLE_BUFFER at O the result of scanning TEXT
  126.    and replacing strings matching PATTERN with REPLACE.
  127.    If PATTERN_PERCENT is not nil, PATTERN has already been
  128.    run through find_percent, and PATTERN_PERCENT is the result.
  129.    If REPLACE_PERCENT is not nil, REPLACE has already been
  130.    run through find_percent, and REPLACE_PERCENT is the result.  */
  131.  
  132. char *
  133. patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent)
  134.      char *o;
  135.      char *text;
  136.      register char *pattern, *replace;
  137.      register char *pattern_percent, *replace_percent;
  138. {
  139.   register int pattern_prepercent_len, pattern_postpercent_len;
  140.   register int replace_prepercent_len, replace_postpercent_len;
  141.   register char *t;
  142.   unsigned int len;
  143.   int doneany = 0;
  144.  
  145.   /* We call find_percent on REPLACE before checking PATTERN so that REPLACE
  146.      will be collapsed before we call subst_expand if PATTERN has no %.  */
  147.   if (replace_percent == 0)
  148.     replace_percent = find_percent (replace);
  149.   if (replace_percent != 0)
  150.     {
  151.       /* Record the length of REPLACE before and after the % so
  152.      we don't have to compute these lengths more than once.  */
  153.       replace_prepercent_len = replace_percent - replace;
  154.       replace_postpercent_len = strlen (replace_percent + 1);
  155.     }
  156.   else
  157.     /* We store the length of the replacement
  158.        so we only need to compute it once.  */
  159.     replace_prepercent_len = strlen (replace);
  160.  
  161.   if (pattern_percent == 0)
  162.     pattern_percent = find_percent (pattern);
  163.   if (pattern_percent == 0)
  164.     /* With no % in the pattern, this is just a simple substitution.  */
  165.     return subst_expand (o, text, pattern, replace,
  166.              strlen (pattern), strlen (replace), 1, 0);
  167.  
  168.   /* Record the length of PATTERN before and after the %
  169.      so we don't have to compute it more than once.  */
  170.   pattern_prepercent_len = pattern_percent - pattern;
  171.   pattern_postpercent_len = strlen (pattern_percent + 1);
  172.  
  173.   while (t = find_next_token (&text, &len))
  174.     {
  175.       int fail = 0;
  176.  
  177.       /* Is it big enough to match?  */
  178.       if (len < pattern_prepercent_len + pattern_postpercent_len)
  179.     fail = 1;
  180.  
  181.       /* Does the prefix match?  */
  182.       if (!fail && pattern_prepercent_len > 0
  183.       && (*t != *pattern
  184.           || t[pattern_prepercent_len - 1] != pattern_percent[-1]
  185.           || strncmp (t + 1, pattern + 1, pattern_prepercent_len - 1)))
  186.     fail = 1;
  187.  
  188.       /* Does the suffix match?  */
  189.       if (!fail && pattern_postpercent_len > 0
  190.       && (t[len - 1] != pattern_percent[pattern_postpercent_len]
  191.           || t[len - pattern_postpercent_len] != pattern_percent[1]
  192.           || strncmp (&t[len - pattern_postpercent_len],
  193.               &pattern_percent[1], pattern_postpercent_len - 1)))
  194.     fail = 1;
  195.  
  196.       if (fail)
  197.     /* It didn't match.  Output the string.  */
  198.     o = variable_buffer_output (o, t, len);
  199.       else
  200.     {
  201.       /* It matched.  Output the replacement.  */
  202.  
  203.       /* Output the part of the replacement before the %.  */
  204.       o = variable_buffer_output (o, replace, replace_prepercent_len);
  205.  
  206.       if (replace_percent != 0)
  207.         {
  208.           /* Output the part of the matched string that
  209.          matched the % in the pattern.  */
  210.           o = variable_buffer_output (o, t + pattern_prepercent_len,
  211.                       len - (pattern_prepercent_len
  212.                          + pattern_postpercent_len));
  213.           /* Output the part of the replacement after the %.  */
  214.           o = variable_buffer_output (o, replace_percent + 1,
  215.                       replace_postpercent_len);
  216.         }
  217.     }
  218.  
  219.       /* Output a space, but not if the replacement is "".  */
  220.       if (fail || replace_prepercent_len > 0
  221.       || (replace_percent != 0 && len + replace_postpercent_len > 0))
  222.     {
  223.       o = variable_buffer_output (o, " ", 1);
  224.       doneany = 1;
  225.     }
  226.     }
  227.   if (doneany)
  228.     /* Kill the last space.  */
  229.     --o;
  230.  
  231.   return o;
  232. }
  233.  
  234. /* Handle variable-expansion-time functions such as $(dir foo/bar) ==> foo/  */
  235.  
  236. /* These enumeration constants distinguish the
  237.    various expansion-time built-in functions.  */
  238.  
  239. enum function
  240.   {
  241.     function_subst,
  242.     function_addsuffix,
  243.     function_addprefix,
  244.     function_dir,
  245.     function_notdir,
  246.     function_suffix,
  247.     function_basename,
  248.     function_wildcard,
  249.     function_firstword,
  250.     function_word,
  251.     function_words,
  252.     function_findstring,
  253.     function_strip,
  254.     function_join,
  255.     function_patsubst,
  256.     function_filter,
  257.     function_filter_out,
  258.     function_foreach,
  259.     function_sort,
  260.     function_origin,
  261.     function_shell,
  262.     function_invalid
  263.   };
  264.  
  265. /* Greater than the length of any function name.  */
  266. #define MAXFUNCTIONLEN 11
  267.  
  268. /* The function names and lengths of names, for looking them up.  */
  269.  
  270. static struct
  271.   {
  272.     char *name;
  273.     unsigned int len;
  274.     enum function function;
  275.   } function_table[] =
  276.   {
  277.     { "subst", 5, function_subst },
  278.     { "addsuffix", 9, function_addsuffix },
  279.     { "addprefix", 9, function_addprefix },
  280.     { "dir", 3, function_dir },
  281.     { "notdir", 6, function_notdir },
  282.     { "suffix", 6, function_suffix },
  283.     { "basename", 8, function_basename },
  284.     { "wildcard", 8, function_wildcard },
  285.     { "firstword", 9, function_firstword },
  286.     { "word", 4, function_word },
  287.     { "words", 5, function_words },
  288.     { "findstring", 10, function_findstring },
  289.     { "strip", 5, function_strip },
  290.     { "join", 4, function_join },
  291.     { "patsubst", 8, function_patsubst },
  292.     { "filter", 6, function_filter },
  293.     { "filter-out", 10, function_filter_out },
  294.     { "foreach", 7, function_foreach },
  295.     { "sort", 4, function_sort },
  296.     { "origin", 6, function_origin },
  297.     { "shell", 5, function_shell },
  298.     { 0, 0, function_invalid }
  299.   };
  300.  
  301. /* Return 1 if PATTERN matches WORD, 0 if not.  */
  302.  
  303. int
  304. pattern_matches (pattern, percent, word)
  305.      register char *pattern, *percent, *word;
  306. {
  307.   unsigned int len;
  308.  
  309.   if (percent == 0)
  310.     {
  311.       unsigned int len = strlen (pattern) + 1;
  312.       char *new = (char *) alloca (len);
  313.       bcopy (pattern, new, len);
  314.       pattern = new;
  315.       percent = find_percent (pattern);
  316.       if (percent == 0)
  317.     return streq (pattern, word);
  318.     }
  319.  
  320.   len = strlen (percent + 1);
  321.  
  322.   if (strlen (word) < (percent - pattern) + len
  323.       || strncmp (pattern, word, percent - pattern))
  324.     return 0;
  325.  
  326.   return !strcmp (percent + 1, word + (strlen (word) - len));
  327. }
  328.  
  329. int shell_function_pid = 0, shell_function_completed;
  330.  
  331. /* Perform the function specified by FUNCTION on the text at TEXT.
  332.    END is points to the end of the argument text (exclusive).
  333.    The output is written into VARIABLE_BUFFER starting at O.  */
  334.  
  335. /* Note this absorbs a semicolon and is safe to use in conditionals.  */
  336. #define BADARGS(func)  \
  337.   if (reading_filename != 0)                    \
  338.     fatal ("%s:%u: Insufficient arguments to function `%s'",    \
  339.        reading_filename, *reading_lineno_ptr, func);    \
  340.   else fatal ("insufficient arguments to function `%s'", func)
  341.  
  342. static char *
  343. expand_function (o, function, text, end)
  344.      char *o;
  345.      enum function function;
  346.      char *text;
  347.      char *end;
  348. {
  349. #ifdef MSDOS
  350.   extern char **construct_command_argv ();
  351.   char **argv;
  352.   int save_stdout;
  353.   char *pipe_file = swap_mktmpname ("pi");
  354.   int pipe_fds;
  355.   char *buffer = (char *) xmalloc (201);
  356.   unsigned int maxlen = 200;
  357.   int cc;
  358. #endif /* MSDOS */
  359.   char *p, *p2, *p3;
  360.   unsigned int i, len;
  361.   int doneany = 0;
  362.   int count;
  363.   char endparen = *end, startparen = *end == ')' ? '(' : '{';
  364.  
  365.   switch (function)
  366.     {
  367.     default:
  368.       abort ();
  369.       break;
  370.       
  371.     case function_shell:
  372.       {
  373.     char buf[100];
  374.     int pipedes[2];
  375.     int pid;
  376.  
  377.     /* Expand the command line.  */
  378.     text = expand_argument (text, end);
  379.  
  380.     /* For error messages.  */
  381.     if (reading_filename != 0)
  382.       sprintf (buf, "%s:%u: ", reading_filename, *reading_lineno_ptr);
  383.     else
  384.       buf[0] = '\0';
  385.  
  386. #ifdef MSDOS
  387.  
  388.           argv = construct_command_argv (text, (struct file *) 0);
  389.  
  390. #if 0
  391.      {
  392.         int ac = 0;
  393.         char **av = argv;
  394.         printf ( "expand_function(): spawning process");
  395.         while (*av)
  396.         printf( " $%d=`%s'", ac++, *av++);
  397.         printf( "\n");
  398.      }
  399. #endif /* NEVER */
  400.  
  401.     save_stdout = dup (1);            /* redirect stdout */
  402.     pipe_fds = open (pipe_file, O_CREAT|O_RDWR|O_TEXT, S_IREAD|S_IWRITE);
  403.     if (dup2 (pipe_fds, 1) == -1)
  404.       pfatal_with_name ("Can't redirect /dev/stdout");
  405.  
  406.           last_child_pid = pid = abs ((int) clock());    /* reasonably random */
  407.  
  408.     last_child_status = swap_spawnvpe (argv[0], argv, environ);
  409.  
  410.     dup2 (save_stdout, 1);            /* reset stdout */
  411.     if (lseek (pipe_fds, 0L, SEEK_SET) == -1L)
  412.       pfatal_with_name ("Can't rewind intermediate file for pipe");
  413.  
  414.           /* Record the PID for child_handler.  */
  415.           shell_function_pid = pid;
  416.           shell_function_completed = 0;
  417.  
  418.           /* Loop until child_handler sets shell_function_completed
  419.        to the status of our child shell.  */
  420.           while (shell_function_completed == 0)
  421.               wait_for_children (1, 0);
  422.  
  423.           /* Read from the pipe until it gets EOF.  */
  424.  
  425.           i = 0;
  426.           do {
  427.                if (i == maxlen)
  428.          {
  429.              maxlen += 512;
  430.              buffer = (char *) xrealloc (buffer, maxlen + 1);
  431.          }
  432.  
  433.         cc = read (pipe_fds, &buffer[i], maxlen - i);
  434.         if (cc > 0)
  435.           i += cc;
  436.  
  437.            } while (cc > 0);
  438.  
  439.           unlink(pipe_file);
  440.  
  441.           /* The child finished normally.  Replace all
  442.              newlines in its output with spaces, and put
  443.              that in the variable output buffer.  */
  444.           for (p = buffer; p < buffer + i; ++p)
  445.               if (*p == '\n')
  446.                 *p = ' ';
  447.  
  448.           o = variable_buffer_output (o, buffer, i);
  449.  
  450.           free (buffer);
  451.  
  452. #else
  453.     if (pipe (pipedes) < 0)
  454.       {
  455.         perror_with_name (buf, "pipe");
  456.         break;
  457.       }
  458.  
  459.     block_children ();
  460.  
  461.     pid = fork ();
  462.     if (pid < 0)
  463.       perror_with_name (buf, "fork");
  464.     else if (pid == 0)
  465.       child_execute_job (0, pipedes[1], (struct file *) 0,
  466.                  construct_command_argv (text, (struct file *) 0),
  467.                  environ);
  468.     else
  469.       {
  470.         /* We are the parent.  Set up and read from the pipe.  */
  471.         char *buffer = (char *) xmalloc (201);
  472.         unsigned int maxlen = 200;
  473.         int cc;
  474.  
  475.         /* Record the PID for child_handler.  */
  476.         shell_function_pid = pid;
  477.         shell_function_completed = 0;
  478.  
  479.         unblock_children ();
  480.  
  481.         /* Close the write side of the pipe.  */
  482.         (void) close (pipedes[1]);
  483.  
  484.         /* Read from the pipe until it gets EOF.  */
  485.         i = 0;
  486.         do
  487.           {
  488.         if (i == maxlen)
  489.           {
  490.             maxlen += 512;
  491.             buffer = (char *) xrealloc (buffer, maxlen + 1);
  492.           }
  493.  
  494.         errno = 0;
  495.         cc = read (pipedes[0], &buffer[i], maxlen - i);
  496.         if (cc > 0)
  497.           i += cc;
  498.           }
  499. #ifdef EINTR
  500.         while (cc > 0 || errno == EINTR);
  501. #else
  502.         while (cc > 0);
  503. #endif
  504.  
  505.         /* Close the read side of the pipe.  */
  506.         (void) close (pipedes[0]);
  507.  
  508.         /* Loop until child_handler sets shell_function_completed
  509.            to the status of our child shell.  */
  510.         while (shell_function_completed == 0)
  511.           wait_for_children (1, 0);
  512.  
  513.         shell_function_pid = 0;
  514.  
  515.         /* The child_handler function will set shell_function_completed
  516.            to 1 when the child dies normally, or to -1 if it
  517.            dies with status 127, which is most likely an exec fail.  */
  518.  
  519.         if (shell_function_completed == -1)
  520.           {
  521.         /* This most likely means that the execvp failed,
  522.            so we should just write out the error message
  523.            that came in over the pipe from the child.  */
  524.         fputs (buffer, stderr);
  525.         fflush (stderr);
  526.           }
  527.         else
  528.           {
  529.         /* The child finished normally.  Replace all
  530.            newlines in its output with spaces, and put
  531.            that in the variable output buffer.  */
  532.         if (i > 0)
  533.           {
  534.             if (buffer[i - 1] == '\n')
  535.               buffer[--i] = '\0';
  536.             p = buffer;
  537.             while ((p = index (p, '\n')) != 0)
  538.               *p++ = ' ';
  539.             o = variable_buffer_output (o, buffer, i);
  540.           }
  541.           }
  542.  
  543.         free (buffer);
  544.       }
  545. #endif /* MSDOS */
  546.  
  547.     free (text);
  548.     break;
  549.       }
  550.  
  551.     case function_origin:
  552.       /* Expand the argument.  */
  553.       text = expand_argument (text, end);
  554.  
  555.       {
  556.     register struct variable *v = lookup_variable (text, strlen (text));
  557.     if (v == 0)
  558.       o = variable_buffer_output (o, "undefined", 9);
  559.     else
  560.       switch (v->origin)
  561.         {
  562.         default:
  563.         case o_invalid:
  564.           abort ();
  565.           break;
  566.         case o_default:
  567.           o = variable_buffer_output (o, "default", 7);
  568.           break;
  569.         case o_env:
  570.           o = variable_buffer_output (o, "environment", 11);
  571.           break;
  572.         case o_file:
  573.           o = variable_buffer_output (o, "file", 4);
  574.           break;
  575.         case o_env_override:
  576.           o = variable_buffer_output (o, "environment override", 20);
  577.           break;
  578.         case o_command:
  579.           o = variable_buffer_output (o, "command line", 12);
  580.           break;
  581.         case o_override:
  582.           o = variable_buffer_output (o, "override", 8);
  583.           break;
  584.         case o_automatic:
  585.           o = variable_buffer_output (o, "automatic", 9);
  586.           break;
  587.         }
  588.       }
  589.  
  590.       free (text);
  591.       break;
  592.       
  593.     case function_sort:
  594.       /* Expand the argument.  */
  595.       text = expand_argument (text, end);
  596.  
  597.       {
  598.     char **words = (char **) xmalloc (10 * sizeof (char *));
  599.     unsigned int nwords = 10;
  600.     register unsigned int wordi = 0;
  601.     char *t;
  602.  
  603.     /* Chop TEXT into words and put them in WORDS.  */
  604.     t = text;
  605.     while (p = find_next_token (&t, &len))
  606.       {
  607.         if (wordi >= nwords - 1)
  608.           {
  609.         nwords += 5;
  610.         words = (char **) xrealloc ((char *) words,
  611.                         nwords * sizeof (char *));
  612.           }    
  613.         words[wordi++] = savestring (p, len);
  614.       }
  615.  
  616.     if (wordi > 0)
  617.       {
  618.         /* Now sort the list of words.  */
  619.         qsort ((char *) words, wordi, sizeof (char *), alpha_compare);
  620.  
  621.         /* Now write the sorted list.  */
  622.         for (i = 0; i < wordi; ++i)
  623.           {
  624.         len = strlen (words[i]);
  625.         if (i == wordi - 1 || strlen (words[i + 1]) != len
  626.             || strcmp (words[i], words[i + 1]))
  627.           {
  628.             o = variable_buffer_output (o, words[i], len);
  629.             o = variable_buffer_output (o, " ", 1);
  630.           }
  631.         free (words[i]);
  632.           }
  633.         /* Kill the last space.  */
  634.         --o;
  635.       }
  636.  
  637.     free ((char *) words);
  638.       }
  639.  
  640.       free (text);
  641.       break;
  642.       
  643.     case function_foreach:
  644.       {
  645.     /* Get three comma-separated arguments but
  646.        expand only the first two.  */
  647.     char *var, *list;
  648.     register struct variable *v;
  649.  
  650.     count = 0;
  651.     for (p = text; p < end; ++p)
  652.       {
  653.         if (*p == startparen)
  654.           ++count;
  655.         else if (*p == endparen)
  656.           --count;
  657.         else if (*p == ',' && count <= 0)
  658.           break;
  659.       }
  660.     if (p == end)
  661.       BADARGS ("foreach");
  662.     var = expand_argument (text, p);
  663.  
  664.     p2 = p + 1;
  665.     count = 0;
  666.     for (p = p2; p < end; ++p)
  667.       {
  668.         if (*p == startparen)
  669.           ++count;
  670.         else if (*p == endparen)
  671.           --count;
  672.         else if (*p == ',' && count <= 0)
  673.           break;
  674.       }
  675.     if (p == end)
  676.       BADARGS ("foreach");
  677.     list = expand_argument (p2, p);
  678.  
  679.     ++p;
  680.     text = savestring (p, end - p);
  681.  
  682.     push_new_variable_scope ();
  683.     v = define_variable (var, strlen (var), "", o_automatic, 0);
  684.     p3 = list;
  685.     while ((p = find_next_token (&p3, &len)) != 0)
  686.       {
  687.         char *result;
  688.         char save = p[len];
  689.         p[len] = '\0';
  690.         v->value = p;
  691.         result = allocated_variable_expand (text);
  692.         p[len] = save;
  693.  
  694.         o = variable_buffer_output (o, result, strlen (result));
  695.         o = variable_buffer_output (o, " ", 1);
  696.         doneany = 1;
  697.         free (result);
  698.       }
  699.     if (doneany)
  700.       /* Kill the last space.  */
  701.       --o;
  702.  
  703.     pop_variable_scope ();
  704.  
  705.     free (var);
  706.     free (list);
  707.     free (text);
  708.       }
  709.       break;
  710.  
  711.     case function_filter:
  712.     case function_filter_out:
  713.       {
  714.     char **words;
  715.     unsigned int nwords;
  716.     register unsigned int wordi;
  717.     
  718.     /* Get two comma-separated arguments and expand each one.  */
  719.     count = 0;
  720.     for (p = text; p < end; ++p)
  721.       {
  722.         if (*p == startparen)
  723.           ++count;
  724.         else if (*p == endparen)
  725.           --count;
  726.         else if (*p == ',' && count <= 0)
  727.           break;
  728.       }
  729.     if (p == end)
  730.       BADARGS (function == function_filter ? "filter" : "filter-out");
  731.     p2 = expand_argument (text, p);
  732.     
  733.     text = expand_argument (p + 1, end);
  734.  
  735.     /* Chop TEXT up into words and then run each pattern through.  */
  736.     nwords = 10;
  737.     words = (char **) xmalloc (10 * sizeof (char *));
  738.     wordi = 0;
  739.     p3 = text;
  740.     while ((p = find_next_token (&p3, &len)) != 0)
  741.       {
  742.         if (wordi == nwords - 1)
  743.           {
  744.         nwords += 10;
  745.         words = (char **) xrealloc ((char *) words,
  746.                         nwords * sizeof (char *));
  747.           }
  748.         if (*p3 != '\0')
  749.           ++p3;
  750.         p[len] = '\0';
  751.         words[wordi++] = p;
  752.       }
  753.  
  754.     /* Run each pattern through the words, killing words.  */
  755.     p3 = p2;
  756.     while ((p = find_next_token (&p3, &len)) != 0)
  757.       {
  758.         char *percent;
  759.         char save = p[len];
  760.         p[len] = '\0';
  761.  
  762.         percent = find_percent (p);
  763.         for (i = 0; i < wordi; ++i)
  764.           if (words[i] != 0 &&
  765.           (percent == 0 ? streq (p, words[i])
  766.            : pattern_matches (p, percent, words[i]))
  767.           == (function == function_filter_out))
  768.         words[i] = 0;
  769.         p[len] = save;
  770.       }
  771.  
  772.     /* Output the words that remain.  */
  773.     for (i = 0; i < wordi; ++i)
  774.       if (words[i] != 0)
  775.         {
  776.           o = variable_buffer_output (o, words[i], strlen (words[i]));
  777.           o = variable_buffer_output (o, " ", 1);
  778.           doneany = 1;
  779.         }
  780.     if (doneany)
  781.       /* Kill the last space.  */
  782.       --o;
  783.  
  784.     free ((char *) words);
  785.     free (p2);
  786.     free (text);
  787.       }
  788.       break;
  789.       
  790.     case function_patsubst:
  791.       /* Get three comma-separated arguments and expand each one.  */
  792.       count = 0;
  793.       for (p = text; p < end; ++p)
  794.     {
  795.       if (*p == startparen)
  796.         ++count;
  797.       else if (*p == endparen)
  798.         --count;
  799.       else if (*p == ',' && count <= 0)
  800.         break;
  801.     }
  802.       if (p == end)
  803.     BADARGS ("patsubst");
  804.  
  805.       p2 = p;
  806.       count = 0;
  807.       for (++p; p < end; ++p)
  808.     {
  809.       if (*p == startparen)
  810.         ++count;
  811.       else if (*p == endparen)
  812.         --count;
  813.       else if (*p == ',' && count <= 0)
  814.         break;
  815.     }
  816.       if (p == end)
  817.     BADARGS ("patsubst");
  818.  
  819.       text = expand_argument (text, p2);
  820.       p3 = expand_argument (p2 + 1, p);
  821.       p2 = expand_argument (p + 1, end);
  822.       
  823.       o = patsubst_expand (o, p2, text, p3, (char *) 0, (char *) 0);
  824.       
  825.       free (text);
  826.       free (p3);
  827.       free (p2);
  828.       break;
  829.  
  830.     case function_join:
  831.       /* Get two comma-separated arguments and expand each one.  */
  832.       count = 0;
  833.       for (p = text; p < end; ++p)
  834.     {
  835.       if (*p == startparen)
  836.         ++count;
  837.       else if (*p == endparen)
  838.         --count;
  839.       else if (*p == ',' && count <= 0)
  840.         break;
  841.     }
  842.       if (p == end)
  843.     BADARGS ("join");
  844.       text = expand_argument (text, p);
  845.  
  846.       p = expand_argument (p + 1, end);
  847.       
  848.       {
  849.     /* Write each word of the first argument directly followed
  850.        by the corresponding word of the second argument.
  851.        If the two arguments have a different number of words,
  852.        the excess words are just output separated by blanks.  */
  853.     register char *tp, *pp;
  854.     p2 = text;
  855.     p3 = p;
  856.     do
  857.       {
  858.         unsigned int tlen, plen;
  859.  
  860.         tp = find_next_token (&p2, &tlen);
  861.         if (tp != 0)
  862.           o = variable_buffer_output (o, tp, tlen);
  863.         
  864.         pp = find_next_token (&p3, &plen);
  865.         if (pp != 0)
  866.           o = variable_buffer_output (o, pp, plen);
  867.         
  868.         if (tp != 0 || pp != 0)
  869.           {
  870.         o = variable_buffer_output (o, " ", 1);
  871.         doneany = 1;
  872.           }
  873.       }
  874.     while (tp != 0 || pp != 0);
  875.     if (doneany)
  876.       /* Kill the last blank.  */
  877.       --o;
  878.       }
  879.       
  880.       free (text);
  881.       free (p);
  882.       break;
  883.       
  884.     case function_strip:
  885.       /* Expand the argument.  */
  886.       text = expand_argument (text, end);
  887.  
  888.       p2 = text;
  889.       while ((p = find_next_token (&p2, &i)) != 0)
  890.     {
  891.       o = variable_buffer_output (o, p, i);
  892.       o = variable_buffer_output (o, " ", 1);
  893.       doneany = 1;
  894.     }
  895.       if (doneany)
  896.     /* Kill the last space.  */
  897.     --o;
  898.       
  899.       free (text);
  900.       break;
  901.       
  902.     case function_wildcard:
  903.       text = expand_argument (text, end);
  904.       
  905.       p = string_glob (text);
  906.       o = variable_buffer_output (o, p, strlen (p));
  907.       
  908.       free (text);
  909.       break;
  910.       
  911.     case function_subst:
  912.       /* Get three comma-separated arguments and expand each one.  */
  913.       count = 0;
  914.       for (p = text; p < end; ++p)
  915.     {
  916.       if (*p == startparen)
  917.         ++count;
  918.       else if (*p == endparen)
  919.         --count;
  920.       else if (*p == ',' && count <= 0)
  921.         break;
  922.     }
  923.       if (p == end)
  924.     BADARGS ("subst");
  925.  
  926.       p2 = p;
  927.       count = 0;
  928.       for (++p; p < end; ++p)
  929.     {
  930.       if (*p == startparen)
  931.         ++count;
  932.       else if (*p == endparen)
  933.         --count;
  934.       else if (*p == ',' && count <= 0)
  935.         break;
  936.     }
  937.       if (p == end)
  938.     BADARGS ("subst");
  939.  
  940.       text = expand_argument (text, p2);
  941.       p3 = expand_argument (p2 + 1, p);
  942.       p2 = expand_argument (p + 1, end);
  943.       
  944.       o = subst_expand (o, p2, text, p3, strlen (text), strlen (p3), 0, 0);
  945.       
  946.       free (text);
  947.       free (p3);
  948.       free (p2);
  949.       break;
  950.       
  951.     case function_firstword:
  952.       /* Expand the argument.  */
  953.       text = expand_argument (text, end);
  954.  
  955.       /* Find the first word in TEXT.  */
  956.       p2 = text;
  957.       p = find_next_token (&p2, &i);
  958.       if (p != 0)
  959.     o = variable_buffer_output (o, p, i);
  960.       
  961.       free (text);
  962.       break;
  963.       
  964.     case function_word:
  965.       /* Get two comma-separated arguments and expand each one.  */
  966.       count = 0;
  967.       for (p = text; p < end; ++p)
  968.     {
  969.       if (*p == startparen)
  970.         ++count;
  971.       else if (*p == endparen)
  972.         --count;
  973.       else if (*p == ',' && count <= 0)
  974.         break;
  975.     }
  976.       if (p == end)
  977.     BADARGS ("word");
  978.       text = expand_argument (text, p);
  979.  
  980.       p3 = expand_argument (p + 1, end);
  981.  
  982.       /* Check the first argument.  */
  983.       for (p2 = text; *p2 != '\0'; ++p2)
  984.     if (*p2 < '0' || *p2 > '9')
  985.       {
  986.         if (reading_filename != 0)
  987.           fatal ("%s:%u: non-numeric first argument to `word' function",
  988.              reading_filename, *reading_lineno_ptr);
  989.         else
  990.           fatal ("non-numeric first argument to `word' function");
  991.       }
  992.  
  993.       i = (unsigned int) atoi (text);
  994.       if (i == 0)
  995.     {
  996.       if (reading_filename != 0)
  997.         fatal ("%s:%u: the `word' function takes a one-origin \
  998. index argument",
  999.            reading_filename, *reading_lineno_ptr);
  1000.       else
  1001.         fatal ("the `word' function takes a one-origin index argument");
  1002.     }
  1003.  
  1004.       p2 = p3;
  1005.       while ((p = find_next_token (&p2, &len)) != 0)
  1006.     if (--i == 0)
  1007.       break;
  1008.       if (i == 0)
  1009.     o = variable_buffer_output (o, p, len);
  1010.  
  1011.       free (text);
  1012.       free (p3);
  1013.       break;
  1014.  
  1015.     case function_words:
  1016.       /* Expand the argument.  */
  1017.       text = expand_argument (text, end);
  1018.  
  1019.       i = 0;
  1020.       p2 = text;
  1021.       while (find_next_token (&p2, (unsigned int *) 0) != 0)
  1022.     ++i;
  1023.  
  1024.       {
  1025.     char buf[20];
  1026.     sprintf (buf, "%d", i);
  1027.     o = variable_buffer_output (o, buf, strlen (buf));
  1028.       }
  1029.  
  1030.       free (text);
  1031.       break;
  1032.  
  1033.     case function_findstring:
  1034.       /* Get two comma-separated arguments and expand each one.  */
  1035.       count = 0;
  1036.       for (p = text; p < end; ++p)
  1037.     {
  1038.       if (*p == startparen)
  1039.         ++count;
  1040.       else if (*p == endparen)
  1041.         --count;
  1042.       else if (*p == ',' && count <= 0)
  1043.         break;
  1044.     }
  1045.       if (p == end)
  1046.     BADARGS ("findstring");
  1047.       text = expand_argument (text, p);
  1048.  
  1049.       p = expand_argument (p + 1, end);
  1050.  
  1051.       /* Find the first occurence of the first string in the second.  */
  1052.       i = strlen (text);
  1053.       if (sindex (p, 0, text, i) != 0)
  1054.     o = variable_buffer_output (o, text, i);
  1055.       
  1056.       free (p);
  1057.       free (text);
  1058.       break;
  1059.       
  1060.     case function_addsuffix:
  1061.     case function_addprefix:
  1062.       /* Get two comma-separated arguments and expand each one.  */
  1063.       count = 0;
  1064.       for (p = text; p < end; ++p)
  1065.     {
  1066.       if (*p == startparen)
  1067.         ++count;
  1068.       else if (*p == endparen)
  1069.         --count;
  1070.       else if (*p == ',' && count <= 0)
  1071.         break;
  1072.     }
  1073.       if (p == end)
  1074.     BADARGS (function == function_addsuffix ? "addsuffix" : "addprefix");
  1075.       text = expand_argument (text, p);
  1076.       i = strlen (text);
  1077.  
  1078.       p2 = expand_argument (p + 1, end);
  1079.       
  1080.       p3 = p2;
  1081.       while ((p = find_next_token (&p3, &len)) != 0)
  1082.     {
  1083.       if (function == function_addprefix)
  1084.         o = variable_buffer_output (o, text, i);
  1085.       o = variable_buffer_output (o, p, len);
  1086.       if (function == function_addsuffix)
  1087.         o = variable_buffer_output (o, text, i);
  1088.       o = variable_buffer_output (o, " ", 1);
  1089.       doneany = 1;
  1090.     }
  1091.       if (doneany)
  1092.     /* Kill last space.  */
  1093.     --o;
  1094.       
  1095.       free (p2);
  1096.       free (text);
  1097.       break;
  1098.       
  1099.     case function_dir:
  1100.     case function_basename:
  1101.       /* Expand the argument.  */
  1102.       text = expand_argument (text, end);
  1103.  
  1104.       p3 = text;
  1105.       while ((p2 = find_next_token (&p3, &len)) != 0)
  1106.     {
  1107.       p = p2 + len;
  1108.       while (p >= p2 && *p != (function == function_dir ? '/' : '.'))
  1109.         --p;
  1110.       if (p >= p2)
  1111.         {
  1112.           if (function == function_dir)
  1113.         ++p;
  1114.           o = variable_buffer_output (o, p2, p - p2);
  1115.         }
  1116.       else if (function == function_dir)
  1117.             o = variable_buffer_output (o, "./", 2);
  1118.       else
  1119.         /* The entire name is the basename.  */
  1120.         o = variable_buffer_output (o, p2, len);
  1121.  
  1122.       o = variable_buffer_output (o, " ", 1);
  1123.       doneany = 1;
  1124.     }
  1125.       if (doneany)
  1126.     /* Kill last space.  */
  1127.     --o;
  1128.       
  1129.       free (text);
  1130.       break;
  1131.       
  1132.     case function_notdir:
  1133.     case function_suffix:
  1134.       /* Expand the argument.  */
  1135.       text = expand_argument (text, end);
  1136.  
  1137.       p3 = text;
  1138.       while ((p2 = find_next_token (&p3, &len)) != 0)
  1139.     {
  1140.       p = p2 + len;
  1141.       while (p >= p2 && *p != (function == function_notdir ? '/' : '.'))
  1142.         --p;
  1143.       if (p >= p2)
  1144.         {
  1145.           ++p;
  1146.           o = variable_buffer_output (o, p, len - (p - p2));
  1147.         }
  1148.       else if (function == function_notdir)
  1149.         o = variable_buffer_output (o, p2, len);
  1150.  
  1151.       if (function == function_notdir || p >= p2)
  1152.         o = variable_buffer_output (o, " ", 1);
  1153.       doneany = 1;
  1154.     }
  1155.       if (doneany)
  1156.     /* Kill last space.  */
  1157.     --o;
  1158.  
  1159.       free (text);
  1160.       break;
  1161.     }
  1162.  
  1163.   return o;
  1164. }
  1165.  
  1166. /* Check for a function invocation in *STRINGP.  *STRINGP points at the
  1167.    opening ( or { and is not null-terminated.  If a function invocation
  1168.    is found, expand it into the buffer at *OP, updating *OP, incrementing
  1169.    *STRINGP past the reference and returning nonzero.  If not, return zero.  */
  1170.  
  1171. int
  1172. handle_function (op, stringp)
  1173.      char **op;
  1174.      char **stringp;
  1175.  
  1176. {
  1177.   register unsigned int code;
  1178.   unsigned int maxlen;
  1179.   char *beg = *stringp + 1;
  1180.   char *endref;
  1181.  
  1182.   endref = lindex (beg, beg + MAXFUNCTIONLEN, '\0');
  1183.   maxlen = endref != 0 ? endref - beg : MAXFUNCTIONLEN;
  1184.  
  1185.   for (code = 0; function_table[code].name != 0; ++code)
  1186.     {
  1187.       if (maxlen < function_table[code].len)
  1188.     continue;
  1189.       endref = beg + function_table[code].len;
  1190.       if ((*endref == ' ' || *endref == '\t')
  1191.       && !strncmp (function_table[code].name, beg,
  1192.                function_table[code].len))
  1193.     break;
  1194.     }
  1195.   if (function_table[code].name != 0)
  1196.     {
  1197.       /* We have found a call to an expansion-time function.
  1198.      Find the end of the arguments, and do the function.  */
  1199.  
  1200.       char openparen = beg[-1], closeparen = openparen == '(' ? ')' : '}';
  1201.       int count = 0;
  1202.       char *argbeg;
  1203.       register char *p;
  1204.  
  1205.       /* Space after function name isn't part of the args.  */
  1206.       p = next_token (endref);
  1207.       argbeg = p;
  1208.  
  1209.       /* Count nested use of whichever kind of parens we use,
  1210.      so that nested calls and variable refs work.  */
  1211.  
  1212.       for (; *p != '\0'; ++p)
  1213.     {
  1214.       if (*p == openparen)
  1215.         ++count;
  1216.       else if (*p == closeparen && --count < 0)
  1217.         break;
  1218.     }
  1219.  
  1220.       /* We found the end; expand the function call.  */
  1221.  
  1222.       *op = expand_function (*op, function_table[code].function, argbeg, p);
  1223.       *stringp = p;
  1224.       return 1;
  1225.     }
  1226.  
  1227.   return 0;
  1228. }
  1229.  
  1230. /* Glob-expand LINE.  The returned pointer is
  1231.    only good until the next call to string_glob.  */
  1232.  
  1233. static char *
  1234. string_glob (line)
  1235.      char *line;
  1236. {
  1237.   static char *result = 0;
  1238.   static unsigned int length;
  1239.   register struct nameseq *chain;
  1240.   register unsigned int idx;
  1241.  
  1242.   chain = multi_glob (parse_file_seq (&line, '\0', sizeof (struct nameseq)),
  1243.               sizeof (struct nameseq));
  1244.  
  1245.   if (result == 0)
  1246.     {
  1247.       length = 100;
  1248.       result = (char *) xmalloc (100);
  1249.     }
  1250.  
  1251.   idx = 0;
  1252.   while (chain != 0)
  1253.     {
  1254.       register char *name = chain->name;
  1255.       unsigned int len = strlen (name);
  1256.  
  1257.       struct nameseq *next = chain->next;
  1258.       free ((char *) chain);
  1259.       chain = next;
  1260.  
  1261.       /* multi_glob will pass names without globbing metacharacters
  1262.      through as is, but we want only files that actually exist.  */
  1263.       if (file_exists_p (name))
  1264.     {
  1265.       if (idx + len + 1 > length)
  1266.         {
  1267.           length += (len + 1) * 2;
  1268.           result = (char *) xrealloc (result, length);
  1269.         }
  1270.       bcopy (name, &result[idx], len);
  1271.       idx += len;
  1272.       result[idx++] = ' ';
  1273.     }
  1274.  
  1275.       free (name);
  1276.     }
  1277.  
  1278.   result[idx] = '\0';
  1279.   return result;
  1280. }
  1281.