home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / cake / part03 / pat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-14  |  6.2 KB  |  353 lines

  1. /*
  2. **    Module to manipulate Cake patterns.
  3. */
  4.  
  5. static    char
  6. rcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/pat.c,v 1.15 87/10/05 20:15:15 zs Exp $";
  7.  
  8. #include    "cake.h"
  9. #include    <ctype.h>
  10.  
  11. /*
  12. **    This function serves as an interface to the rest of the system
  13. **    for domatch, looking after its environment.
  14. */
  15.  
  16. bool
  17. match(env, str, pat)
  18. Env        env;
  19. reg    char    *str;
  20. reg    Pat    *pat;
  21. {
  22.     extern    bool    domatch();
  23.     reg    bool    result;
  24.     reg    int    i;
  25.     reg    char    *s, *p;
  26.  
  27.     if (patdebug)
  28.         printf("Match %s vs %s\n", str, pat->p_str);
  29.  
  30.     if (pat->p_cmd)
  31.     {
  32.         fprintf(stderr, "cake internal error: undereferenced pattern %s in match\n",
  33.             pat->p_str);
  34.         exit_cake(TRUE);
  35.     }
  36.  
  37.     if (streq(str, CHASEROOT))
  38.         result = streq(pat->p_str, CHASEROOT);
  39.     else
  40.     {
  41.         result = TRUE; /* assume so for the moment */
  42.         p = pat->p_str+strlen(pat->p_str)-1;
  43.         if (*p != '%' && !isdigit(*p))    /* not part of a var */
  44.         {
  45.             s = str+strlen(str)-1;
  46.             if (*s != *p)        /* last chars differ */
  47.                 result = FALSE;
  48.         }
  49.         
  50.         if (result) /* if last-char test inconclusive */
  51.         {
  52.             for (i = 0; i < MAXVAR; i++)
  53.                 env[i].v_bound = FALSE;
  54.  
  55.             result = domatch(env, str, pat->p_str);
  56.         }
  57.     }
  58.  
  59.     if (patdebug)
  60.     {
  61.         if (result == FALSE)
  62.             printf("Match failed\n");
  63.         else
  64.         {
  65.             printf("Match succeeded\n");
  66.             for (i = 0; i < MAXVAR; i++)
  67.                 if (env[i].v_bound)
  68.                     printf("X%d: %s\n", i, env[i].v_val);
  69.         }
  70.     }
  71.  
  72.     return result;
  73. }
  74.  
  75. /*
  76. **    Match a string against a pattern.
  77. **    The pattern is expected to have been dereferenced.
  78. **    To handle nondeterminism, a brute force recursion approach
  79. **    is taken.
  80. */
  81.  
  82. bool
  83. domatch(env, str, patstr)
  84. Env        env;
  85. reg    char    *str;
  86. reg    char    *patstr;
  87. {
  88.     char        buf[MAXPATSIZE];
  89.     reg    char    *follow;
  90.     reg    char    *s, *t;
  91.     reg    int    varno;
  92.     reg    int    i;
  93.     reg    bool    more;
  94.  
  95.     put_trail("domatch", "start");
  96.     if (patstr[0] == '%')
  97.     {
  98.         if (isdigit(patstr[1]))
  99.         {
  100.             varno  = patstr[1] - '0';
  101.             follow = patstr + 2;
  102.         }
  103.         else
  104.         {
  105.             varno  = NOVAR;
  106.             follow = patstr + 1;
  107.         }
  108.  
  109.         if (env[varno].v_bound)
  110.         {
  111.             /* lifetime of buf is local */
  112.             strcpy(buf, env[varno].v_val);
  113.             strcat(buf, follow);
  114.             checkpatlen(buf);
  115.             put_trail("domatch", "recurse");
  116.             return domatch(env, str, buf);
  117.         }
  118.  
  119.         i = 0;
  120.         buf[0] = '\0';
  121.         env[varno].v_bound = TRUE;
  122.         env[varno].v_val = buf;
  123.  
  124.         /* keep invariant: buf = tentative value of var  */
  125.         /* the value of a variable may never contain a % */
  126.         /* must consider *s == \0, but do not overshoot  */
  127.         for (s = str, more = TRUE; more && *s != '%'; s++)
  128.         {
  129.             if (patdebug)
  130.                 printf("trying X%d = '%s'\n", varno, buf);
  131.  
  132.             if (domatch(env, s, follow))
  133.             {
  134.                 checkpatlen(buf);
  135.                 env[varno].v_val = new_name(buf);
  136.                 /* lifetime of buf is now global */
  137.                 put_trail("domatch", "finish");
  138.                 return TRUE;
  139.             }
  140.  
  141.             /* maintain invariant */
  142.             buf[i++] = *s;
  143.             buf[i]   = '\0';
  144.  
  145.             more = (*s != '\0');
  146.         }
  147.         
  148.         /* no luck, match failed */
  149.         env[varno].v_bound = FALSE;
  150.         put_trail("domatch", "finish");
  151.         return FALSE;
  152.     }
  153.  
  154.     /* here we have something other than a variable first off */
  155.     for (s = str, t = patstr; *t != '\0' && *t != '%'; s++, t++)
  156.     {
  157.         if (*t == '\\')
  158.             t++;    /* the new *t is not checked for % */
  159.         
  160.         if (*s != *t)
  161.         {
  162.             put_trail("domatch", "finish");
  163.             return FALSE;
  164.         }
  165.     }
  166.  
  167.     /* see if we have come to the end of the pattern */
  168.     if (*t == '\0')
  169.     {
  170.         put_trail("domatch", "finish");
  171.         return *s == '\0';
  172.     }
  173.     
  174.     /* if not, recurse on the next variable */
  175.     put_trail("domatch", "recurse");
  176.     return domatch(env, s, t);
  177. }
  178.  
  179. /*
  180. **    Ground the argument string, i.e. replace all occurrences
  181. **    of variables in it. It is fatal error for the string to
  182. **    contain a variable which has no value.
  183. */
  184.  
  185. char *
  186. ground(env, str)
  187. Env        env;
  188. reg    char    *str;
  189. {
  190.     reg    char    *s, *t;
  191.     reg    int    i, var;
  192.     char        buf[MAXSIZE];
  193.  
  194.     put_trail("ground", "start");
  195.     i = 0;
  196.     for (s = str; *s != '\0'; s++)
  197.     {
  198.         if (*s == '%')
  199.         {
  200.             if (isdigit(s[1]))
  201.                 var = *++s - '0';
  202.             else
  203.                 var = NOVAR;
  204.             
  205.             if (! env[var].v_bound)
  206.             {
  207.                 if (var == NOVAR)
  208.                     fprintf(stderr, "cake: %s is undefined in %s\n", "%", str);
  209.                 else
  210.                     fprintf(stderr, "cake: %s%1d is undefined in %s\n", "%", var, str);
  211.                 exit_cake(FALSE);
  212.             }
  213.  
  214.             for (t = env[var].v_val; *t != '\0'; t++)
  215.                 buf[i++] = *t;
  216.         }
  217.         or (*s == '\\')
  218.         {
  219.             if (s[1] != '\0')
  220.                 buf[i++] = *++s;
  221.         }
  222.         else
  223.             buf[i++] = *s;
  224.     }
  225.  
  226.     buf[i] = '\0';
  227.     if (i >= MAXSIZE)
  228.     {
  229.         fprintf(stderr, "cake internal error: pattern buffer overflow for %s\n", buf);
  230.         exit_cake(FALSE);
  231.     }
  232.  
  233.     put_trail("ground", "new_name finish");
  234.     return new_name(buf);
  235. }
  236.  
  237. /*
  238. **    See if the argument contains any variebles.
  239. */
  240.  
  241. bool
  242. hasvars(str)
  243. reg    char    *str;
  244. {
  245.     reg    char    *s;
  246.  
  247.     for (s = str; *s != '\0'; s++)
  248.     {
  249.         if (*s == '%')
  250.             return TRUE;
  251.         or (*s == '\\')
  252.         {
  253.             if (s[1] != '\0')
  254.                 s++;
  255.         }
  256.     }
  257.  
  258.     return FALSE;
  259. }
  260.  
  261. /*
  262. **    Dereference the pattern; i.e. if it a command pattern
  263. **    replace it with the output of the command. It is the task
  264. **    of the caller to break this up if necessary.
  265. **    Note that the pattern will never have to be dereferenced again.
  266. **
  267. **    The second arg says whether the pattern is to be broken after
  268. **    dereferencing: this is needed purely for debugging purposes.
  269. */
  270.  
  271. deref(pat, broken)
  272. reg    Pat    *pat;
  273. reg    bool    broken;
  274. {
  275.     extern    char    *expand_cmds();
  276.  
  277.     if (! pat->p_cmd)
  278.         return;
  279.     
  280.     pat->p_cmd = FALSE;
  281.     pat->p_str = expand_cmds(pat->p_str);
  282.  
  283.     if (! broken)
  284.         checkpatlen(pat->p_str);
  285. }
  286.  
  287. /*
  288. **    Break the given pattern up into a (possibly empty) list
  289. **    of smaller patterns at white space positions.
  290. */
  291.  
  292. List *
  293. break_pat(pat)
  294. reg    Pat    *pat;
  295. {
  296.     reg    Pat    *newpat;
  297.     reg    List    *list;
  298.     reg    char    *s;
  299.  
  300.     put_trail("break_pat", "start");
  301.     if (pat->p_cmd)
  302.     {
  303.         fprintf(stderr, "cake internal error: trying to break command pattern %s\n", pat->p_str);
  304.         exit_cake(TRUE);
  305.     }
  306.  
  307.     list = makelist0();
  308.     s = pat->p_str;
  309.     while (*s != '\0')
  310.     {
  311.         char        buf[MAXSIZE];
  312.         reg    int    i;
  313.  
  314.         for (; *s != '\0' && isspace(*s); s++)
  315.             ;
  316.  
  317.         i = 0;
  318.         for (; *s != '\0' && !isspace(*s); s++)
  319.             buf[i++] = *s;
  320.         
  321.         buf[i] = '\0';
  322.         if (i > 0)
  323.         {
  324.             newpat = make_pat(new_name(buf), FALSE, pat->p_flag);
  325.             addtail(list, newpat);    /* no assignment */
  326.         }
  327.     }
  328.  
  329.     put_trail("break_pat", "finish");
  330.     return list;
  331. }
  332.  
  333. /*
  334. **    Add flags to a list of patterns.
  335. */
  336.  
  337. List *
  338. set_flag(patlist, flags)
  339. reg    List    *patlist;
  340. reg    int    flags;
  341. {
  342.     reg    List    *ptr;
  343.     reg    Pat    *pat;
  344.  
  345.     for_list (ptr, patlist)
  346.     {
  347.         pat = (Pat *) ldata(ptr);
  348.         pat->p_flag |= flags;
  349.     }
  350.  
  351.     return patlist;
  352. }
  353.