mux/src/wild.cpp

Go to the documentation of this file.
00001 // wild.cpp -- Wildcard routines.
00002 //
00003 // $Id: wild.cpp,v 1.9 2006/01/07 01:33:44 sdennis Exp $
00004 //
00005 // Written by T. Alexander Popiel, 24 June 1993
00006 // Last modified by T. Alexander Popiel, 19 August 1993
00007 //
00008 // Thanks go to Andrew Molitor for debugging
00009 // Thanks also go to Rich $alz for code to benchmark against
00010 //
00011 // Copyright (c) 1993 by T. Alexander Popiel
00012 // This code is hereby placed under GNU copyleft,
00013 // see copyright.h for details.
00014 //
00015 
00016 #include "copyright.h"
00017 #include "autoconf.h"
00018 #include "config.h"
00019 #include "externs.h"
00020 
00021 #define EQUAL(a,b) (mux_tolower(a) == mux_tolower(b))
00022 #define NOTEQUAL(a,b) (mux_tolower(a) != mux_tolower(b))
00023 
00024 // Argument return space and size.
00025 //
00026 static char **arglist;
00027 static int numargs;
00028 
00029 //
00030 // ---------------------------------------------------------------------------
00031 // quick_wild: do a wildcard match, without remembering the wild data.
00032 //
00033 // This routine will cause crashes if fed NULLs instead of strings.
00034 //
00035 bool quick_wild(const char *tstr, const char *dstr)
00036 {
00037     if (mudstate.wild_invk_ctr >= mudconf.wild_invk_lim)
00038     {
00039         return false;
00040     }
00041     mudstate.wild_invk_ctr++;
00042 
00043     while (*tstr != '*')
00044     {
00045         switch (*tstr)
00046         {
00047         case '?':
00048 
00049             // Single character match.  Return false if at end of data.
00050             //
00051             if (!*dstr)
00052             {
00053                 return false;
00054             }
00055             break;
00056 
00057         case '\\':
00058 
00059             // Escape character.  Move up, and force literal match of next
00060             // character.
00061             //
00062             tstr++;
00063 
00064             // FALL THROUGH
00065 
00066         default:
00067 
00068             // Literal character.  Check for a match. If matching end of data,
00069             // return true.
00070             //
00071             if (NOTEQUAL(*dstr, *tstr))
00072             {
00073                 return false;
00074             }
00075             if (!*dstr)
00076             {
00077                 return true;
00078             }
00079         }
00080         tstr++;
00081         dstr++;
00082     }
00083 
00084     // Skip over '*'.
00085     //
00086     tstr++;
00087 
00088     // Return true on trailing '*'.
00089     //
00090     if (!*tstr)
00091     {
00092         return true;
00093     }
00094 
00095     // Skip over wildcards.
00096     //
00097     while (  *tstr == '?'
00098           || *tstr == '*')
00099     {
00100         if (*tstr == '?')
00101         {
00102             if (!*dstr)
00103             {
00104                 return false;
00105             }
00106             dstr++;
00107         }
00108         tstr++;
00109     }
00110 
00111     // Skip over a backslash in the pattern string if it is there.
00112     //
00113     if (*tstr == '\\')
00114     {
00115         tstr++;
00116     }
00117 
00118     // Return true on trailing '*'.
00119     //
00120     if (!*tstr)
00121     {
00122         return true;
00123     }
00124 
00125     // Scan for possible matches.
00126     //
00127     while (*dstr)
00128     {
00129         if (  EQUAL(*dstr, *tstr)
00130            && quick_wild(tstr + 1, dstr + 1))
00131         {
00132             return true;
00133         }
00134         dstr++;
00135     }
00136     return false;
00137 }
00138 
00139 // ---------------------------------------------------------------------------
00140 // wild1: INTERNAL: do a wildcard match, remembering the wild data.
00141 //
00142 // DO NOT CALL THIS FUNCTION DIRECTLY - DOING SO MAY RESULT IN SERVER CRASHES
00143 // AND IMPROPER ARGUMENT RETURN.
00144 //
00145 // Side Effect: this routine modifies the 'arglist' static global variable.
00146 //
00147 static bool wild1(char *tstr, char *dstr, int arg)
00148 {
00149     if (mudstate.wild_invk_ctr >= mudconf.wild_invk_lim)
00150     {
00151         return false;
00152     }
00153     mudstate.wild_invk_ctr++;
00154 
00155     char *datapos;
00156     int argpos, numextra;
00157 
00158     while (*tstr != '*')
00159     {
00160         switch (*tstr)
00161         {
00162         case '?':
00163 
00164             // Single character match.  Return false if at end of data.
00165             //
00166             if (!*dstr)
00167             {
00168                 return false;
00169             }
00170             arglist[arg][0] = *dstr;
00171             arglist[arg][1] = '\0';
00172             arg++;
00173 
00174             // Jump to the fast routine if we can.
00175             //
00176             if (arg >= numargs)
00177             {
00178                 return quick_wild(tstr + 1, dstr + 1);
00179             }
00180             break;
00181 
00182         case '\\':
00183 
00184             // Escape character.  Move up, and force literal match of next
00185             // character.
00186             //
00187             tstr++;
00188 
00189             // FALL THROUGH
00190 
00191         default:
00192 
00193             // Literal character.  Check for a match. If matching end of data,
00194             // return true.
00195             //
00196             if (NOTEQUAL(*dstr, *tstr))
00197             {
00198                 return false;
00199             }
00200             if (!*dstr)
00201             {
00202                 return true;
00203             }
00204         }
00205         tstr++;
00206         dstr++;
00207     }
00208 
00209     // If at end of pattern, slurp the rest, and leave.
00210     //
00211     if (!tstr[1])
00212     {
00213         strncpy(arglist[arg], dstr, LBUF_SIZE - 1);
00214         arglist[arg][LBUF_SIZE - 1] = '\0';
00215         return true;
00216     }
00217 
00218     // Remember current position for filling in the '*' return.
00219     //
00220     datapos = dstr;
00221     argpos = arg;
00222 
00223     // Scan forward until we find a non-wildcard.
00224     //
00225     do
00226     {
00227         if (argpos < arg)
00228         {
00229             // Fill in arguments if someone put another '*' before a fixed
00230             // string.
00231             //
00232             arglist[argpos][0] = '\0';
00233             argpos++;
00234 
00235             // Jump to the fast routine if we can.
00236             //
00237             if (argpos >= numargs)
00238             {
00239                 return quick_wild(tstr, dstr);
00240             }
00241 
00242             // Fill in any intervening '?'s
00243             //
00244             while (argpos < arg)
00245             {
00246                 arglist[argpos][0] = *datapos;
00247                 arglist[argpos][1] = '\0';
00248                 datapos++;
00249                 argpos++;
00250 
00251                 // Jump to the fast routine if we can.
00252                 //
00253                 if (argpos >= numargs)
00254                 {
00255                     return quick_wild(tstr, dstr);
00256                 }
00257             }
00258         }
00259 
00260         // Skip over the '*' for now...
00261         //
00262         tstr++;
00263         arg++;
00264 
00265         // Skip over '?'s for now...
00266         //
00267         numextra = 0;
00268         while (*tstr == '?')
00269         {
00270             if (!*dstr)
00271             {
00272                 return false;
00273             }
00274             tstr++;
00275             dstr++;
00276             arg++;
00277             numextra++;
00278         }
00279     } while (*tstr == '*');
00280 
00281     // Skip over a backslash in the pattern string if it is there.
00282     //
00283     if (*tstr == '\\')
00284     {
00285         tstr++;
00286     }
00287 
00288     // Check for possible matches.  This loop terminates either at end of data
00289     // (resulting in failure), or at a successful match.
00290     //
00291     for (;;)
00292     {
00293         // Scan forward until first character matches.
00294         //
00295         if (*tstr)
00296         {
00297             while (NOTEQUAL(*dstr, *tstr))
00298             {
00299                 if (!*dstr)
00300                 {
00301                     return false;
00302                 }
00303                 dstr++;
00304             }
00305         }
00306         else
00307         {
00308             while (*dstr)
00309             {
00310                 dstr++;
00311             }
00312         }
00313 
00314         // The first character matches, now.  Check if the rest does, using
00315         // the fastest method, as usual.
00316         //
00317         if (  !*dstr
00318            || ((arg < numargs) ? wild1(tstr + 1, dstr + 1, arg)
00319                                : quick_wild(tstr + 1, dstr + 1)))
00320         {
00321             // Found a match!  Fill in all remaining arguments. First do the
00322             // '*'...
00323             //
00324             strncpy(arglist[argpos], datapos,
00325                             (dstr - datapos) - numextra);
00326             arglist[argpos][(dstr - datapos) - numextra] = '\0';
00327             datapos = dstr - numextra;
00328             argpos++;
00329 
00330             // Fill in any trailing '?'s that are left.
00331             //
00332             while (numextra)
00333             {
00334                 if (argpos >= numargs)
00335                 {
00336                     return true;
00337                 }
00338                 arglist[argpos][0] = *datapos;
00339                 arglist[argpos][1] = '\0';
00340                 datapos++;
00341                 argpos++;
00342                 numextra--;
00343             }
00344 
00345             // It's done!
00346             //
00347             return true;
00348         }
00349         else
00350         {
00351             dstr++;
00352         }
00353     }
00354 }
00355 
00356 // ---------------------------------------------------------------------------
00357 // wild: do a wildcard match, remembering the wild data.
00358 //
00359 // This routine will cause crashes if fed NULLs instead of strings.
00360 //
00361 // Side Effect: this routine modifies the 'arglist' and 'numargs' static
00362 // global variables.
00363 //
00364 bool wild(char *tstr, char *dstr, char *args[], int nargs)
00365 {
00366     mudstate.wild_invk_ctr = 0;
00367 
00368     int i;
00369     char *scan;
00370 
00371     // Initialize the return array.
00372     //
00373     for (i = 0; i < nargs; i++)
00374     {
00375         args[i] = NULL;
00376     }
00377 
00378     // Do fast match.
00379     //
00380     while (  *tstr != '*'
00381           && *tstr != '?')
00382     {
00383         if (*tstr == '\\')
00384         {
00385             tstr++;
00386         }
00387         if (NOTEQUAL(*dstr, *tstr))
00388         {
00389             return false;
00390         }
00391         if (!*dstr)
00392         {
00393             return true;
00394         }
00395         tstr++;
00396         dstr++;
00397     }
00398 
00399     // Allocate space for the return args.
00400     //
00401     i = 0;
00402     scan = tstr;
00403     while (  *scan
00404           && i < nargs)
00405     {
00406         switch (*scan)
00407         {
00408         case '?':
00409 
00410             args[i] = alloc_lbuf("wild.?");
00411             i++;
00412             break;
00413 
00414         case '*':
00415 
00416             args[i] = alloc_lbuf("wild.*");
00417             i++;
00418         }
00419         scan++;
00420     }
00421 
00422     // Put stuff in globals for quick recursion.
00423     //
00424     arglist = args;
00425     numargs = nargs;
00426 
00427     // Do the match.
00428     //
00429     bool value = nargs ? wild1(tstr, dstr, 0) : quick_wild(tstr, dstr);
00430 
00431     // Clean out any fake match data left by wild1.
00432     //
00433     for (i = 0; i < nargs; i++)
00434     {
00435         if (  args[i] != NULL
00436            && (  !*args[i]
00437               || !value))
00438         {
00439             free_lbuf(args[i]);
00440             args[i] = NULL;
00441         }
00442     }
00443     return value;
00444 }
00445 
00446 // ---------------------------------------------------------------------------
00447 // wild_match: do either an order comparison or a wildcard match, remembering
00448 // the wild data, if wildcard match is done.
00449 //
00450 // This routine will cause crashes if fed NULLs instead of strings.
00451 //
00452 bool wild_match(char *tstr, const char *dstr)
00453 {
00454     switch (*tstr)
00455     {
00456     case '>':
00457 
00458         tstr++;
00459         if (  mux_isdigit(*tstr)
00460            || *tstr == '-')
00461         {
00462             long lt = mux_atol(tstr);
00463             long ld = mux_atol(dstr);
00464             return (lt < ld);
00465         }
00466         else
00467         {
00468             return (strcmp(tstr, dstr) < 0);
00469         }
00470 
00471     case '<':
00472 
00473         tstr++;
00474         if (  mux_isdigit(*tstr)
00475            || *tstr == '-')
00476         {
00477             long lt = mux_atol(tstr);
00478             long ld = mux_atol(dstr);
00479             return (lt > ld);
00480         }
00481         else
00482         {
00483             return (strcmp(tstr, dstr) > 0);
00484         }
00485     }
00486     mudstate.wild_invk_ctr = 0;
00487     return quick_wild(tstr, dstr);
00488 }

Generated on Mon May 28 04:40:12 2007 for MUX by  doxygen 1.4.7