"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "gtkfind-1.1/glob.c" of archive gtkfind-1.1.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /* glob.c */
    2 /* wildcard matching routines */
    3 /*
    4 gtkfind - a graphical "find" program
    5 Copyright (C) 1999  Matthew Grossman <mattg@oz.net>
    6 
    7 This program is free software; you can redistribute it and/or modify
    8 it under the terms of the GNU General Public License as published by
    9 the Free Software Foundation; either version 2 of the License, or
   10 (at your option) any later version.
   11 
   12 This program is distributed in the hope that it will be useful,
   13 but WITHOUT ANY WARRANTY; without even the implied warranty of
   14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15 GNU General Public License for more details.
   16 
   17 You should have received a copy of the GNU General Public License
   18 along with this program; if not, write to the Free Software
   19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20 */
   21 
   22 
   23 /* this should be just a routine to match a text string with a
   24    wildcard-containing text string.  I want to have the capability to save
   25    portions of the match into a register, so you can access them later
   26    by using \1, \2, etc. just like in sed
   27 
   28    \0 should be the whole string
   29 
   30    we have a max of 10 registers...should be enough...
   31 
   32    wildcards: ? * {...} [...]
   33 
   34    registers: (...)
   35 
   36    you can use a \ to escape a special character
   37 
   38    Because of this (the special capabilities we want), we are not
   39    using a library
   40 
   41    when copy_stringp == 0, registers are disabled. () are just ignored
   42    in the pattern
   43 */
   44 
   45 #include "glob.h"
   46 
   47 #define MAX_REGISTERS 10
   48 
   49 /* globals for keeping track of registers */
   50 
   51 static caddr_t r_start[MAX_REGISTERS];
   52 static caddr_t r_end[MAX_REGISTERS];
   53 
   54 
   55 static char *
   56 strechr(char *s, char c)
   57      /* return a pointer to the first non \-escaped character in s, or NULL */
   58 {
   59   char *rv = NULL;
   60   char *p = NULL;
   61   int match = 0;
   62 
   63   p = s;
   64 
   65   while(*p && !match) {
   66     if(*p == c) {
   67       if(c == '\\') {
   68 	if(*(p + 1) == '\\')
   69 	  p += 2;
   70 	else
   71 	  match++;
   72       }
   73       else {
   74 	if((p > s && *(p - 1) != '\\') || p == s)
   75 	  match++;
   76 	else
   77 	  p += 1;
   78       }
   79     }
   80     else
   81       p += 1;
   82   }
   83 
   84   if(match)
   85     rv = p;
   86 
   87   return(rv);
   88 }
   89 
   90 static char *
   91 stretok(char *s, char *tokens)
   92      /* do a strtok on s with tokens that are not \-escaped */
   93 {
   94   static char *mem = NULL;
   95   char *p = NULL, *q = NULL, *r = NULL;
   96   char *rv = NULL;
   97 
   98   if(s)
   99     mem = s;
  100   else if(mem == NULL) /* s == NULL && mem == NULL */
  101     goto DONE;
  102 
  103   p = mem;
  104   q = tokens;
  105 
  106   do {
  107     r = strechr(p, *q); /* in a real libc we couldn't do this? */
  108     if(r) {
  109       *r = '\0';
  110       break;
  111     }
  112   } while(*q && q++);
  113 
  114   if(r)
  115     mem = r + 1;
  116   else
  117     mem = NULL;
  118 
  119   rv = p;
  120 
  121  DONE:
  122   return(rv);
  123 }
  124 
  125 
  126 
  127 char *
  128 match_squares(char *pattern, char *string)
  129      /* see if the square braces in pattern match the next
  130 	character in string, if they do return the new pattern */
  131 {
  132   int negated = 0;
  133   char start = 0, end = 0;
  134   int success = 0;
  135   char *rv = NULL;
  136 
  137   if(*(++pattern) == '!' || *pattern == '^')
  138     negated = 1;
  139 
  140   while(1) {
  141     if(*pattern == ']' &&
  142        (*(pattern - 1) != '[' ||
  143 	*(pattern + 1) != ']'))
  144       break; /* you can include a ']' by putting it first or last */
  145 
  146     if(success) {
  147       pattern++;
  148       continue; /* we've already matched, and now we are just searching
  149 		   for the last ] */
  150     }
  151 
  152     else if((*pattern == '-') &&
  153 	    (*(pattern - 1) != '[' &&
  154 	     *(pattern + 1) != ']')) {
  155 
  156       /* this is a "-" used as a range */
  157 
  158       start = *(pattern - 1) + 1;
  159       end = *(pattern + 1);
  160       while(start <= end) {
  161 	if(start++ == *string) {
  162 	  success = 1;
  163 	}
  164       }
  165       pattern += 1;
  166     }
  167     if(*pattern == *string)
  168       success = 1;
  169 
  170     pattern++;
  171   }
  172 
  173   if((success && !negated) ||
  174      (!success && negated))
  175     rv = pattern + 1;
  176   else
  177     rv = NULL;
  178 
  179   return(rv);
  180 }
  181 
  182 int
  183 glob(char *pattern, char *string, char **registers, int c_reg)
  184      /* glob pattern to string, return 1 if it matches, 0 if it doesn't */
  185 {
  186   int rv = 0;
  187 
  188   if(*pattern == '\0' && *string == '\0')
  189     rv = 1; /* this case occurs sometimes, as long as both strings
  190 	       run out at the same time we know that they matched previously
  191 	    */
  192 
  193   else if(*pattern == '\\') {
  194     if(*(pattern + 1) == *string)
  195       rv = glob(pattern + 2, string + 1, registers, c_reg);
  196     else
  197       rv = 0;
  198   }
  199 
  200   else if(*pattern == '(') {
  201     /* we always know where the register starts, we just don't know
  202        where it ends */
  203     if(r_start[c_reg]) {
  204 #ifdef DEBUG
  205       fprintf(stderr, "glob: registers cannot be nested!\n");
  206 #endif
  207       rv = 0;
  208     }
  209     else {
  210       r_start[c_reg] = (caddr_t)string;
  211       if(glob(pattern + 1, string, registers, c_reg)) {
  212 	rv = 1;
  213       }
  214     }
  215   }
  216 
  217   else if(*pattern == ')') {
  218     /* deal with trailing stars */
  219     if(*(pattern + 1) == '\0' && *(pattern - 1) == '*') {
  220       rv = 1;
  221       r_end[c_reg] = (caddr_t)(string + strlen(string));
  222 
  223       if(registers)
  224 	registers[c_reg] = copy_string((char *)r_start[c_reg],
  225 				       (char *)r_end[c_reg]);
  226     }
  227     else if(glob(pattern + 1, string, registers, c_reg + 1)) {
  228       rv = 1;
  229 
  230       /* we already know this pattern matches, so we can put it into
  231 	 the register with no fear... */
  232 
  233       r_end[c_reg] = (caddr_t)string;
  234 
  235       if(registers)
  236 	registers[c_reg] = copy_string((char *)r_start[c_reg],
  237 				       (char *)r_end[c_reg]);
  238     }
  239   }
  240 
  241 
  242   else if(*pattern == '?') {
  243     rv = glob(pattern + 1, string + 1, registers, c_reg);
  244   }
  245 
  246   else if(*pattern == '*') {
  247     while(*(pattern + 1) == '*')
  248       pattern++; /* eat up extra '*' */
  249     if(strlen(pattern) == 1) {
  250       rv = 1;
  251     }
  252     else {
  253       while(*string) {
  254 	if(glob(pattern + 1, string++, registers, c_reg)) {
  255 	  rv = 1;
  256 	}
  257       }
  258     }
  259   }
  260 
  261   else if(*pattern == '[') {
  262     pattern = match_squares(pattern, string);
  263     if(pattern)
  264       rv = glob(pattern, string + 1, registers, c_reg);
  265     else
  266       goto DONE;
  267   }
  268 
  269   else if(*pattern == '{') {
  270     /* best way to handle this:
  271        dynamically make up a pattern and match it */
  272     char *tmp = NULL, *q = NULL;
  273     char *copy = NULL;
  274     char *s = NULL;
  275     char *last_brace = NULL;
  276     int i = 0;
  277 
  278     copy = (char *)alloca(strlen(pattern) + 1);
  279     if(!copy)
  280       goto DONE;
  281     strcpy(copy, pattern + 1);
  282     last_brace = strechr(copy, '}');
  283     if(!last_brace)
  284       goto DONE;
  285     *last_brace = '\0';
  286 
  287     q = stretok(copy, ",");
  288 
  289     s = strechr(pattern, '}'); /* get the rest of the pattern after the { */
  290     s++;
  291 
  292     if(!s || !q || q >= s) {
  293       goto DONE;
  294     }
  295 
  296     i = strlen(q) + strlen(s) + 1;
  297     tmp = (char *)malloc(sizeof(char) * i);
  298     strcpy(tmp, q);
  299     strcat(tmp, s); /* make up a pattern and try matching it, if we fail
  300 		       make up the next one, etc. */
  301     while((rv = glob(tmp, string, registers, c_reg)) == 0) {
  302       q = stretok(NULL, ",");
  303       if(!q || q >= s)
  304 	break;
  305       else {
  306 	i = strlen(q) + strlen(s) + 1;
  307 	tmp = (char *)realloc(tmp,sizeof(char) * i);
  308 	strcpy(tmp, q);
  309 	strcat(tmp, s);
  310       }
  311     }
  312     if(tmp)
  313       free(tmp);
  314   }
  315 
  316 
  317   else if(strcmp(pattern, string) == 0)
  318     rv = 1;
  319 
  320   else if(*pattern == *string)
  321     rv = glob(pattern + 1, string + 1, registers, c_reg);
  322 
  323   DONE:
  324     return(rv);
  325 }
  326 
  327 char **
  328 glob_string(char *pattern, char *string, int copy_stringp)
  329      /* the user-visible function, returns the registers, with the
  330 	string in register[0] if copy_stringp */
  331 {
  332   char **registers = NULL;
  333 
  334   if(copy_stringp) {
  335     registers = allocate_glob_registers();
  336     memset(r_start, 0, MAX_REGISTERS * sizeof(caddr_t));
  337     memset(r_end, 0, MAX_REGISTERS * sizeof(caddr_t));
  338 
  339     registers[0] = copy_string(string, string + strlen(string));
  340   }
  341 
  342   if(strcmp(pattern, "*") == 0 || glob(pattern, string, registers, 1)) {
  343     if(copy_stringp)
  344       return(registers);
  345     else
  346       return((char **)1);
  347   }
  348   else {
  349     if(registers)
  350       free_glob_registers(registers);
  351     return(NULL);
  352   }
  353 }
  354 
  355 char **
  356 allocate_glob_registers()
  357 {
  358   char **rv = NULL;
  359 
  360   rv = (char **)calloc(1, MAX_REGISTERS * sizeof(char *));
  361   return(rv);
  362 }
  363 
  364 void
  365 free_glob_registers(char **registers)
  366      /* use this to free glob registers */
  367 {
  368   int i = 0;
  369 
  370   if(registers) {
  371     for(i = 0; i < MAX_REGISTERS; i++) {
  372       if(registers[i])
  373 	free(registers[i]);
  374     }
  375     free(registers);
  376   }
  377 
  378   return;
  379 }
  380 
  381 char *
  382 copy_string(char *start, char *end)
  383      /* allocate string between start and end, return it */
  384 {
  385   char *rv = NULL;
  386   int length = 0;
  387 
  388   length = (end - start) + 1;
  389   rv = (char *)malloc(length * sizeof(char));
  390 
  391   strncpy(rv, start, length - 1);
  392   rv[length - 1] = '\0';
  393 
  394   return(rv);
  395 }
  396 
  397 
  398 #ifdef GLOBTEST
  399 
  400 
  401 int
  402 main(int argc, char *argv[])
  403 {
  404   char **registers = NULL;
  405   int i = 0;
  406 
  407   if((registers = glob_string(argv[1], argv[2], 1)) != NULL)
  408     printf("%s matches %s!\n", argv[1], argv[2]);
  409   else
  410     printf("%s doesn't match %s\n", argv[1], argv[2]);
  411 
  412   for(i = 0; i < MAX_REGISTERS; i++) {
  413     if(registers && registers[i])
  414       printf("registers[%d] = %s\n", i, registers[i]);
  415   }
  416 
  417   free_glob_registers(registers);
  418 
  419   exit(0);
  420 }
  421 
  422 #endif /* GLOBTEST */