home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 514a.lha / sregexp.library_v9.0 / sregexp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-08  |  16.2 KB  |  649 lines

  1.  
  2. /* This is a routine to test if a string matches a regular expression.
  3.  *
  4.  *
  5.  *  The regular expression sytax is a slight extension of the regular
  6.  * AmigaDos wildcard patterns. Apparently 2.0 has added a few new things
  7.  * (well, at least a not operator) to the game.  This may or may not
  8.  * be consistant with those additions (it's the way they otta done it.)
  9.  *
  10.  * Here it is:
  11.  *
  12.  *    ?        matches any one character
  13.  *
  14.  *    #(pat)      matches zero or more occurances of the pattern pat.
  15.  *
  16.  *    (pat)       seperates out a piece of the pattern.
  17.  *
  18.  *    pat1|pat2   matches to either pat1 or pat2
  19.  *
  20.  *    '           escapes the special meaning of these symbols.
  21.  *
  22.  *    %        matches the null string.
  23.  *
  24.  *  EXTENSIONS
  25.  *
  26.  *    [chars]     will match any single character in the set chars,
  27.  *            specified as single characters or ranges seperated
  28.  *            by a -.  Ex. [af-i+] would match a, f, g, h, i, and
  29.  *            +.    If ~ is the first character in the set then the
  30.  *            set matched is the complement of the set specified.
  31.  *            Ex. [~a-z] would match any one character that is
  32.  *            not a (lower case if case sensitivity is on) letter.
  33.  *            Note that a [~a] is NOT the same as a ~[a]. The former
  34.  *            would match a 'b' but not a 'ab', whereas the latter
  35.  *            would match both.
  36.  *
  37.  *    ~(pat)      will match anything that doesn't match the pattern.
  38.  *            Note: it is illegal to repeat a not. ie #~a is illegal.
  39.  *            (So is #(~(a)) so don't even try it.) You can repeat
  40.  *            something with a not IN it, as long as it can't be
  41.  *            reduced to the form #~(pattern). (A #[~a] is OK.)
  42.  *            However ~#a has the expected effect (matches any
  43.  *            non-null string not composed entirely of a's.)
  44.  *
  45.  *    *        same as #?.
  46.  *
  47.  *
  48.  */
  49.  
  50. #include "sregexp.h"
  51.  
  52. const char wilds[] = {          /* string of the wildcards, for easy access */
  53.             CHR_REPEAT,
  54.             CHR_NOT,
  55.             CHR_OPENBRACE,
  56.             CHR_CLOSEBRACE,
  57.             CHR_OPENSET,
  58.             CHR_CLOSESET,
  59.             CHR_ANYCHAR,
  60.             CHR_NULL,
  61.             CHR_OR,
  62.             CHR_ESCAPE,
  63. /*            CHR_RANGE,     <--- special case  */
  64.             CHR_STAR,
  65.             0
  66. };
  67.  
  68. #ifdef __DEBUG__
  69. extern void puts(char *);
  70. extern void printf(char *, ...);
  71. #endif
  72.  
  73.  
  74. struct SregExp *
  75. parsesregexp(expr)
  76. char *expr;
  77. /* This is the entry point into the parsing subroutines. */
  78. {
  79.     return parsesub(&expr,0);
  80. }
  81.  
  82. static struct SregExp *
  83. parsesub(p,end)
  84. char **p,end;
  85. /* This routine will parse a sub expression up until the character
  86.    'end' is encontered.  This is 0 for the whole pattern and ')'
  87.    for a subpattern */
  88. {
  89.     struct SregList *list,*head=NULL,*orlist,*orhead=NULL;
  90.     struct SregExp *sreg;
  91.     int num = 0,ornum = 0;
  92.  
  93.     if (**p == end) {
  94.     char *q;
  95.  
  96.     q = "%";
  97.     return parseone(&q,TRUE);
  98.     }
  99.  
  100.     while (**p != end) {
  101.     if (!(sreg = parseone(p,TRUE)))  /* parse on wildcard */
  102.         goto cleanup;
  103.     if (head) {     /* if there's already a list, just stick it on */
  104.         if (!(list = (list->srl_next = getmem(sizeof(struct SregList))))) {
  105.         report(MEM_ERROR);
  106.         goto cleanup;
  107.         }
  108.     } else {    /* otherwise, make a new list */
  109.         if (!(list = (head = getmem(sizeof(struct SregList))))) {
  110.         report(MEM_ERROR);
  111.         goto cleanup;
  112.         }
  113.     }
  114.     list->srl_sreg = sreg;
  115.     list->srl_next = NULL;
  116.     num++;
  117.     if (**p == CHR_OR) {        /* deal with an or */
  118.         if (!(sreg = makesum(head,num)))
  119.         goto cleanup;
  120.         if (orhead) {           /* either add onto the or list */
  121.         if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  122.             report(MEM_ERROR);
  123.             goto cleanup;
  124.         }
  125.         } else {            /* or make a new or list */
  126.         if (!(orlist = (orhead = getmem(sizeof(struct SregList))))) {
  127.             report(MEM_ERROR);
  128.             goto cleanup;
  129.         }
  130.         }
  131.         orlist->srl_sreg = sreg;
  132.         orlist->srl_next = NULL;
  133.         ornum++;
  134.         (*p)++;
  135.         head = NULL;
  136.         num = 0;
  137.     }
  138.     }
  139.     if (!(sreg = makesum(head,num)))
  140.     goto cleanup;
  141.     if (orhead) {       /* if this expression had an or, clean it up */
  142.     if (!(orlist = (orlist->srl_next = getmem(sizeof(struct SregList))))) {
  143.         report(MEM_ERROR);
  144.         goto cleanup;
  145.     }
  146.     orlist->srl_sreg = sreg;
  147.     orlist->srl_next = NULL;
  148.     ornum++;
  149.     if (!(sreg = makeor(orhead,ornum)))
  150.         goto cleanup;
  151.     }
  152.  
  153.     return sreg;    /* sub expression successfully matched. */
  154.  
  155. cleanup:    /* troubles all head here to clean up */
  156.  
  157.     list = head;
  158.     while (list) {          /* free all the bits of the current sum */
  159.     head = list->srl_next;
  160.     freesregexp(list->srl_sreg);
  161.     FreeMem(list,sizeof(struct SregList));
  162.     list = head;
  163.     }
  164.     list = orhead;
  165.     while (list) {          /* and all of the current or parts */
  166.     head = list->srl_next;
  167.     freesregexp(list->srl_sreg);
  168.     FreeMem(list,sizeof(struct SregList));
  169.     list = head;
  170.     }
  171.  
  172.     return NULL;        /* return the failure */
  173. }
  174.  
  175. static struct SregExp *
  176. makesum(list,num)
  177. struct SregList *list;
  178. int num;
  179. /* This routine takes a linked list of sreg's and joins them together
  180.    Under the auspices of one big SRP_SUM type sreg */
  181. {
  182.     struct SregList *lnk;
  183.     struct SregExp *sreg;
  184.     int i,len=0;
  185.     char fixed = SRF_FIXLEN;
  186.  
  187.     if (num == 0) {
  188.     report(ILLEGAL_ERR);
  189.     return NULL;
  190.     } else if (num == 1) {
  191.     sreg = list->srl_sreg;
  192.     FreeMem(list,sizeof(struct SregList));
  193.     return sreg;
  194.     } if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  195.     report(MEM_ERROR);
  196.     return NULL;
  197.     }
  198.     sreg->sre_Type = SRP_SUM;
  199.     sreg->sre_Flag = 0;
  200.     sreg->sre_Data.number = num;
  201.     for (i = 0; i < num; i++) {
  202.     len += realen(list->srl_sreg);
  203.     fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  204.     sreg->sre_List[i] = list->srl_sreg;
  205.     lnk = list->srl_next;
  206.     FreeMem(list,sizeof(struct SregList));
  207.     list = lnk;
  208.     }
  209.     sreg->sre_MinLen = len;
  210.     sreg->sre_Flag |= fixed;
  211.     return sreg;
  212. }
  213.  
  214. static struct SregExp *
  215. makeor(list,num)
  216. struct SregList *list;
  217. int num;
  218. /* This does basically the same thing as makesum, except it makes
  219.    an SRP_OR type sreg to join the list and doesn't deal with some
  220.    special cases */
  221. {
  222.     struct SregList *lnk;
  223.     struct SregExp *sreg;
  224.     int i,len;
  225.     char fixed = SRF_FIXLEN;
  226.  
  227.     if (!(sreg = getmem(sizeof(struct SregExp) + num*sizeof(struct SregExp *)))) {
  228.     report(MEM_ERROR);
  229.     return NULL;
  230.     }
  231.     sreg->sre_Type = SRP_OR;
  232.     sreg->sre_Flag = 0;
  233.     sreg->sre_Data.number = num;
  234.     for (i = 0; i < num; i++) {
  235.     if (i == 0)
  236.         len = realen(list->srl_sreg);
  237.     else if (len != realen(list->srl_sreg)) {
  238.         fixed = 0;
  239.         if (len > realen(list->srl_sreg))
  240.         len = realen(list->srl_sreg);
  241.     }
  242.     fixed &= isfixed(list->srl_sreg) ? SRF_FIXLEN : 0;
  243.     sreg->sre_List[i] = list->srl_sreg;
  244.     lnk = list->srl_next;
  245.     FreeMem(list,sizeof(struct SregList));
  246.     list = lnk;
  247.     }
  248.     sreg->sre_MinLen = len;
  249.     sreg->sre_Flag |= fixed;
  250.     return sreg;
  251. }
  252.  
  253. static struct SregExp *
  254. parseone(p,cat)
  255. char **p,cat;
  256. /* This routine parses one wildcard character from the string *p,
  257.    leaving it set up pointing to the begining of the next
  258.    wildcard. If 'cat' is true then a string of characters will
  259.    be grouped together as a SRP_STRING type sreg.  It may be
  260.    false because of the scope rules of ~ and #, which only
  261.    repeat the very next pattern. */
  262. {
  263.     struct SregExp *sreg;
  264.  
  265.     switch (**p) {
  266.     case (CHR_REPEAT) :
  267.         (*p)++;
  268.         if (!(sreg = parseone(p,FALSE)))
  269.         return NULL;
  270.         if (sreg->sre_Flag & SRF_NOT) {
  271.         report(ILLEGAL_ERR);
  272.         freesregexp(sreg);
  273.         return NULL;
  274.         }
  275.         sreg->sre_Flag |= SRF_REPEAT;
  276.         break;
  277.     case (CHR_NOT) :
  278.         (*p)++;
  279.         if (!(sreg = parseone(p,FALSE)))
  280.         return NULL;
  281.         sreg->sre_Flag |= SRF_NOT;
  282.         break;
  283.     case (CHR_OPENBRACE) :
  284.         (*p)++;
  285.         sreg = parsesub(p,CHR_CLOSEBRACE);
  286.         (*p)++;
  287.         break;
  288.     case (CHR_OPENSET) :
  289.         (*p)++;
  290.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  291.         report(MEM_ERROR);
  292.         return NULL;
  293.         }
  294.         sreg->sre_Type = SRP_SETCHAR;
  295.         sreg->sre_Flag = SRF_FIXLEN;
  296.         sreg->sre_MinLen = 1;
  297.         if (!(sreg->sre_Data.setchar = makeset(p))) {
  298.         FreeMem(sreg,sizeof(sreg));
  299.         return NULL;
  300.         }
  301.         (*p)++;
  302.         break;
  303.     case (CHR_ANYCHAR) :
  304.         (*p)++;
  305.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  306.         report(MEM_ERROR);
  307.         return NULL;
  308.         }
  309.         sreg->sre_Type = SRP_ANYCHAR;
  310.         sreg->sre_Flag = SRF_FIXLEN;
  311.         sreg->sre_MinLen = 1;
  312.         break;
  313.     case (CHR_STAR) :
  314.         (*p)++;
  315.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  316.         report(MEM_ERROR);
  317.         return NULL;
  318.         }
  319.         sreg->sre_Type = SRP_ANYCHAR;
  320.         sreg->sre_Flag = SRF_FIXLEN | SRF_REPEAT;
  321.         sreg->sre_MinLen = 1;
  322.         break;
  323.     case (CHR_NULL) :
  324.         (*p)++;
  325.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  326.         report(MEM_ERROR);
  327.         return NULL;
  328.         }
  329.         sreg->sre_Type = SRP_NULL;
  330.         sreg->sre_Flag = SRF_FIXLEN;
  331.         sreg->sre_MinLen = 0;
  332.         break;
  333.     case (CHR_CLOSEBRACE) :
  334.     case (CHR_CLOSESET) :
  335.     case (CHR_OR) :
  336.     case (0) :
  337.         report(ILLEGAL_ERR);
  338.         return NULL;
  339.     default :
  340.         if (!(sreg = getmem(sizeof(struct SregExp)))) {
  341.         report(MEM_ERROR);
  342.         return NULL;
  343.         }
  344.         sreg->sre_Flag = SRF_FIXLEN;
  345.         if (!cat) {
  346.         sreg->sre_Data.onechar = onechar(p,FALSE);
  347.         sreg->sre_Type = SRP_ONECHAR;
  348.         sreg->sre_MinLen = 1;
  349.         } else {
  350.         char *q=*p;
  351.         int len=0;
  352.  
  353.         while (onechar(&q,FALSE))
  354.             len++;
  355.         sreg->sre_MinLen = len;
  356.         if (len == 1) {
  357.             sreg->sre_Data.onechar = onechar(p,FALSE);
  358.             sreg->sre_Type = SRP_ONECHAR;
  359.         } else {
  360.             sreg->sre_Type = SRP_STRING;
  361.             if (!(q = sreg->sre_Data.string = getmem(len+1))) {
  362.             report(MEM_ERROR);
  363.             FreeMem(sreg,sizeof(sreg));
  364.             return NULL;
  365.             }
  366.             while (*q++ = onechar(p,FALSE)) ;
  367.             *q = 0;
  368.         }
  369.         }
  370.     }
  371.     return sreg;
  372. }
  373.  
  374. static char
  375. onechar(p,minus)
  376. char **p,minus;
  377. /* this routine picks one character off the string *p.    It handles
  378.    escaping the special meaning of the wildcard characters, and
  379.    returns 0 if we're at the end of the string or the next
  380.    char is a wildcard.    if 'minus' is true, then the '-' is
  381.    treated as a wildcard, otherwise it isn't */
  382. {
  383.     if (**p == CHR_ESCAPE)
  384.     (*p)++;
  385.     else if (strchr(wilds,**p) || (minus && **p == CHR_RANGE))
  386.     return 0;
  387.     return *(*p)++;
  388. }
  389.  
  390. static char *
  391. makeset(p)
  392. char **p;
  393. /* this makes a table of match flags from the character specifier
  394.    that goes in between [ and ].  It handles a leading '~' and
  395.    leaves *p pointing to the closing brace. Note: This routine
  396.    checks to make sure the specifier ends in a ] and fails if
  397.    it doesn't */
  398. {
  399.     char *set,not=FALSE,ok=FALSE,s,e;
  400.  
  401.     if (**p == CHR_NOT) {
  402.     (*p)++;
  403.     not = TRUE;
  404.     }
  405.     if (!(set = getmem(32))) {
  406.     report(MEM_ERROR);
  407.     return NULL;
  408.     }
  409.     for (s = 0; s < 32; s++)
  410.     set[s] = 0;
  411.     while (s = onechar(p,TRUE)) {
  412.     ok = TRUE;
  413.     if (**p == CHR_RANGE) {
  414.         (*p)++;
  415.         if (!(e = onechar(p,TRUE))) {
  416.         report(ILLEGAL_ERR);
  417.         FreeMem(set,32);
  418.         return NULL;
  419.         }
  420.         for ( ; s <= e; s++)
  421.         set[s/8] |= 1 << (s % 8);
  422.     } else
  423.         set[s/8] |= 1 << (s % 8);
  424.     }
  425.     if (!ok || **p != CHR_CLOSESET) {
  426.     report(ILLEGAL_ERR);
  427.     FreeMem(set,32);
  428.     return NULL;
  429.     }
  430.     if (not) {
  431.     for(s = 0; s < 32; s++)
  432.         set[s] = ~set[s];
  433.     }
  434.     return set;
  435. }
  436.  
  437. void
  438. freesregexp(sreg)
  439. struct SregExp *sreg;
  440. /* this routine frees up a sreg.  It correctly handles freeing the
  441.    subpattern elements in a SRP_SUM or SRP_OR sreg and frees the
  442.    match table or string from a SRP_SETCHAR or SRP_STRING sreg.
  443.    This is one of the externally visible routines. */
  444. {
  445.     int add = 0;
  446.  
  447.     if (sreg->sre_Type == SRP_SUM || sreg->sre_Type == SRP_OR) {
  448.     int i;
  449.  
  450.     add = sreg->sre_Data.number * sizeof(struct SregExp *);
  451.     for (i = 0; i < sreg->sre_Data.number; i++)
  452.         freesregexp(sreg->sre_List[i]);
  453.  
  454.     } else if (sreg->sre_Type == SRP_STRING)
  455.     FreeMem(sreg->sre_Data.string,strlen(sreg->sre_Data.string)+1);
  456.     else if (sreg->sre_Type == SRP_SETCHAR)
  457.     FreeMem(sreg->sre_Data.setchar,32);
  458.     FreeMem(sreg,sizeof(struct SregExp) + add);
  459. }
  460.  
  461. int
  462. matchsregexp(p,sreg,up)
  463. char *p;
  464. struct SregExp *sreg;
  465. int up;
  466. /* This is the externally visible stub to the pattern matching part
  467.    of sreg.  'p' is the string to match to, sreg is the preparsed
  468.    sreg, and up indicates if the match is case sensitive. */
  469. {
  470.     return matchnsregexp(p,sreg,up,strlen(p));
  471. }
  472.  
  473. int
  474. matchnsregexp(p,sreg,up,len)
  475. char *p;
  476. struct SregExp *sreg;
  477. int up,len;
  478. /* This routine will match a sreg to a string of length 'len'. */
  479. /* The length, rather than NULL terminated is used to make a
  480.    lot of things a lot simpler */
  481. {
  482.     int res,i;
  483.  
  484.     if (sreg->sre_Flag & SRF_REPEAT) {  /* deal with repeaters. */
  485.     char not,*h;
  486.  
  487.     if (len == 0 || sreg->sre_Type == SRP_ANYCHAR) { /* always true */
  488.         res = TRUE;
  489.         goto end;
  490.     }
  491.     /* check if the lengths match up */
  492.     if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN &&
  493.                (sreg->sre_MinLen == 0 || len % sreg->sre_MinLen != 0))) {
  494.         res = FALSE;
  495.         goto end;
  496.     }
  497.     not = sreg->sre_Flag & SRF_NOT;
  498.     sreg->sre_Flag &= ~(SRF_REPEAT | SRF_NOT);
  499.     if (sreg->sre_Flag & SRF_FIXLEN) { /* handle fixed lenght matches */
  500.         h = p;
  501.         while (h-p < len) {
  502.         if (!(res = matchnsregexp(h,sreg,up,sreg->sre_MinLen)))
  503.             goto end;
  504.         h += sreg->sre_MinLen;
  505.         }
  506.     } else {            /* and variable length ones */
  507.         for (i = len; i >= (sreg->sre_MinLen ? sreg->sre_MinLen : 1); i--) {
  508.         if (res = matchnsregexp(p,sreg,up,i)) {
  509.             sreg->sre_Flag |= SRF_REPEAT;
  510.             if (res = matchnsregexp(p+i,sreg,up,len-i))
  511.             break;
  512.             sreg->sre_Flag &= ~SRF_REPEAT;
  513.         }
  514.         }
  515.     }
  516.     sreg->sre_Flag |= SRF_REPEAT | not;
  517.     goto end;
  518.     }
  519.  
  520.     /* check the lengths first for quick rejection */
  521.     if (len < sreg->sre_MinLen || (sreg->sre_Flag & SRF_FIXLEN && len != sreg->sre_MinLen)) {
  522.     res = FALSE;
  523.     goto end;
  524.     }
  525.  
  526.     switch (sreg->sre_Type) {
  527.     case (SRP_SUM) :
  528.         res = matchsum(&(sreg->sre_List[0]),sreg->sre_Data.number,p,len,up);
  529.         break;
  530.     case (SRP_ONECHAR) :
  531.         res = len == 1 && (up ? *p == sreg->sre_Data.onechar :
  532.                    toupper(*p) == toupper(sreg->sre_Data.onechar));
  533.         break;
  534.     case (SRP_SETCHAR) :
  535.         res = len == 1 && matchset(sreg,*p) || (up ? FALSE :
  536.                  (isupper(*p) ? matchset(sreg,tolower(*p)) :
  537.                         matchset(sreg,toupper(*p))));
  538.         break;
  539.     case (SRP_ANYCHAR) :
  540.         res = len == 1;
  541.         break;
  542.     case (SRP_STRING) :
  543.         if (up)
  544.         res = !strncmp(p,sreg->sre_Data.string,len);
  545.         else
  546.         res = !strnicmp(p,sreg->sre_Data.string,len);
  547.         break;
  548.     case (SRP_NULL) :
  549.         res = len == 0;
  550.         break;
  551.     case (SRP_OR) :
  552.         for (i = 0; i < sreg->sre_Data.number; i++)
  553.         if (res = matchnsregexp(p,sreg->sre_List[i],up,len)) {
  554.             break;
  555.         }
  556.         break;
  557.     }
  558.  
  559. end:
  560.  
  561.     if (sreg->sre_Flag & SRF_NOT)
  562.     return !res;
  563.     else
  564.     return res;
  565. }
  566.  
  567. static int
  568. matchsum(list,num,p,len,up)
  569. struct SregExp *list[];
  570. int num,len,up;
  571. char *p;
  572. /* This routine is called by match to match the elements of a sum
  573.    of sregs.  It tries to be as effecient as possible, and keep
  574.    recursion to a minimum.  It will match any fixed length peices
  575.    at the begining and end first, then match any fixed length
  576.    peices in the middle to break the string up.  Only then does
  577.    it do the tiresome matches to the non-fixed length peices. */
  578. {
  579.     int i,res,o;
  580.  
  581.     while (num && isfixed(list[0])) {
  582.     if (!(res = matchnsregexp(p,list[0],up,list[0]->sre_MinLen)))
  583.         return FALSE;
  584.     p += list[0]->sre_MinLen;
  585.     len -= list[0]->sre_MinLen;
  586.     list++;
  587.     num--;
  588.     }
  589.     while (num && isfixed(list[num-1])) {
  590.     if (!(res = matchnsregexp(p+len-list[num-1]->sre_MinLen,list[num-1],up,
  591.                                list[num-1]->sre_MinLen)))
  592.         return FALSE;
  593.     len -= list[num-1]->sre_MinLen;
  594.     num--;
  595.     }
  596.     if (num == 0)
  597.     return TRUE;
  598.  
  599.     o = 0;
  600.     for (i = 1; i < num-1; i++) {
  601.     if (isfixed(list[i])) {
  602.         for ( ; len-o >= list[i]->sre_MinLen; o++) {
  603.         if (res = matchnsregexp(p+o,list[i],up,list[i]->sre_MinLen)) {
  604.             if (!(res = matchsum(list,i,p,o,up)))
  605.             return FALSE;
  606.             if (!(res = matchsum(list+(i+1),num-i-1,
  607.                 p+o+list[i]->sre_MinLen,len-o-list[i]->sre_MinLen,up)))
  608.             return FALSE;
  609.             return TRUE;
  610.         }
  611.         }
  612.         return FALSE;
  613.     } else
  614.         o += realen(list[i]);
  615.     }
  616.  
  617.     if (num == 1)
  618.     return matchnsregexp(p,list[0],up,len);
  619.  
  620.     for (o = len; o >= list[0]->sre_MinLen; o--)
  621.     if (matchnsregexp(p,list[0],up,o) && matchsum(list+1,num-1,p+o,len-o,up))
  622.         return TRUE;
  623.  
  624.     return FALSE;
  625. }
  626.  
  627. int
  628. iswild(p)
  629. char *p;
  630. /* this is a very simple routine, but it is externally visible.  Returns
  631.    true if the string has wildcard characters (unescaped) false if
  632.    not */
  633. {
  634.     while (onechar(&p,FALSE)) ;
  635.     return *p != 0;
  636. }
  637.  
  638. void
  639. report(i)
  640. int i;
  641. /* This routine now does set the IoErr value to more information.
  642.   For now it does nothing. */
  643. {
  644.     struct Process *myself;
  645.  
  646.     if (myself = (struct Process *)FindTask(0))
  647.     myself->pr_Result2 = i;
  648. }
  649.