Back to index

lightning-sunbird  0.9+nobinonly
portreg.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *     Ken Key <key+mozilla@ksquared.net>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* 
00039  * shexp.c: shell-like wildcard match routines
00040  *
00041  *
00042  * See shexp.h for public documentation.
00043  *
00044  */
00045 
00046 #include "seccomon.h"
00047 #include "portreg.h"
00048 
00049 /* ----------------------------- shexp_valid ------------------------------ */
00050 
00051 
00052 static int 
00053 _valid_subexp(const char *exp, char stop) 
00054 {
00055     register int x,y,t;
00056     int nsc,np,tld;
00057 
00058     x=0;nsc=0;tld=0;
00059 
00060     while(exp[x] && (exp[x] != stop)) {
00061         switch(exp[x]) {
00062           case '~':
00063             if(tld) return INVALID_SXP;
00064             else ++tld;
00065           case '*':
00066           case '?':
00067           case '^':
00068           case '$':
00069             ++nsc;
00070             break;
00071           case '[':
00072             ++nsc;
00073             if((!exp[++x]) || (exp[x] == ']'))
00074                 return INVALID_SXP;
00075             for(++x;exp[x] && (exp[x] != ']');++x)
00076                 if(exp[x] == '\\')
00077                     if(!exp[++x])
00078                         return INVALID_SXP;
00079             if(!exp[x])
00080                 return INVALID_SXP;
00081             break;
00082           case '(':
00083             ++nsc;np = 0;
00084             while(1) {
00085                 if(exp[++x] == ')')
00086                     return INVALID_SXP;
00087                 for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
00088                     if(exp[y] == '\\')
00089                         if(!exp[++y])
00090                             return INVALID_SXP;
00091                 if(!exp[y])
00092                     return INVALID_SXP;
00093                 if(exp[y] == '|')
00094                     ++np;
00095                 t = _valid_subexp(&exp[x],exp[y]);
00096                 if(t == INVALID_SXP)
00097                     return INVALID_SXP;
00098                 x+=t;
00099                 if(exp[x] == ')') {
00100                     if(!np)
00101                         return INVALID_SXP;
00102                     break;
00103                 }
00104             }
00105             break;
00106           case ')':
00107           case ']':
00108             return INVALID_SXP;
00109           case '\\':
00110             if(!exp[++x])
00111                 return INVALID_SXP;
00112           default:
00113             break;
00114         }
00115         ++x;
00116     }
00117     if((!stop) && (!nsc))
00118         return NON_SXP;
00119     return ((exp[x] == stop) ? x : INVALID_SXP);
00120 }
00121 
00122 int 
00123 PORT_RegExpValid(const char *exp) 
00124 {
00125     int x;
00126 
00127     x = _valid_subexp(exp, '\0');
00128     return (x < 0 ? x : VALID_SXP);
00129 }
00130 
00131 
00132 /* ----------------------------- shexp_match ----------------------------- */
00133 
00134 
00135 #define MATCH 0
00136 #define NOMATCH 1
00137 #define ABORTED -1
00138 
00139 static int _shexp_match(const char *str, const char *exp, PRBool case_insensitive);
00140 
00141 static int 
00142 _handle_union(const char *str, const char *exp, PRBool case_insensitive) 
00143 {
00144     char *e2 = (char *) PORT_Alloc(sizeof(char)*strlen(exp));
00145     register int t,p2,p1 = 1;
00146     int cp;
00147 
00148     while(1) {
00149         for(cp=1;exp[cp] != ')';cp++)
00150             if(exp[cp] == '\\')
00151                 ++cp;
00152         for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
00153             if(exp[p1] == '\\')
00154                 e2[p2++] = exp[p1++];
00155             e2[p2] = exp[p1];
00156         }
00157         for (t=cp+1; ((e2[p2] = exp[t]) != 0); ++t,++p2) {}
00158         if(_shexp_match(str,e2, case_insensitive) == MATCH) {
00159             PORT_Free(e2);
00160             return MATCH;
00161         }
00162         if(p1 == cp) {
00163             PORT_Free(e2);
00164             return NOMATCH;
00165         }
00166         else ++p1;
00167     }
00168 }
00169 
00170 
00171 static int 
00172 _shexp_match(const char *str, const char *exp, PRBool case_insensitive) 
00173 {
00174     register int x,y;
00175     int ret,neg;
00176 
00177     ret = 0;
00178     for(x=0,y=0;exp[y];++y,++x) {
00179         if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
00180             ret = ABORTED;
00181         else {
00182             switch(exp[y]) {
00183               case '$':
00184                 if( (str[x]) )
00185                     ret = NOMATCH;
00186                 else
00187                     --x;             /* we don't want loop to increment x */
00188                 break;
00189               case '*':
00190                 while(exp[++y] == '*'){}
00191                 if(!exp[y])
00192                     return MATCH;
00193                 while(str[x]) {
00194                     switch(_shexp_match(&str[x++],&exp[y], case_insensitive)) {
00195                     case NOMATCH:
00196                         continue;
00197                     case ABORTED:
00198                         ret = ABORTED;
00199                         break;
00200                     default:
00201                         return MATCH;
00202                     }
00203                     break;
00204                 }
00205                 if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
00206                     return MATCH;
00207                 else
00208                     ret = ABORTED;
00209                 break;
00210               case '[':
00211                      neg = ((exp[++y] == '^') && (exp[y+1] != ']'));
00212                 if (neg)
00213                     ++y;
00214                 
00215                 if ((isalnum(exp[y])) && (exp[y+1] == '-') && 
00216                    (isalnum(exp[y+2])) && (exp[y+3] == ']'))
00217                     {
00218                         int start = exp[y], end = exp[y+2];
00219                         
00220                         /* no safeguards here */
00221                         if(neg ^ ((str[x] < start) || (str[x] > end))) {
00222                             ret = NOMATCH;
00223                             break;
00224                         }
00225                         y+=3;
00226                     }
00227                 else {
00228                     int matched;
00229                     
00230                     for (matched=0;exp[y] != ']';y++)
00231                         matched |= (str[x] == exp[y]);
00232                     if (neg ^ (!matched))
00233                         ret = NOMATCH;
00234                 }
00235                 break;
00236               case '(':
00237                 return _handle_union(&str[x],&exp[y], case_insensitive);
00238                 break;
00239               case '?':
00240                 break;
00241               case '\\':
00242                 ++y;
00243               default:
00244               if(case_insensitive)
00245                 {
00246                     if(toupper(str[x]) != toupper(exp[y]))
00247                         ret = NOMATCH;
00248                 }
00249               else
00250                 {
00251                     if(str[x] != exp[y])
00252                         ret = NOMATCH;
00253                 }
00254                 break;
00255             }
00256         }
00257         if(ret)
00258             break;
00259     }
00260     return (ret ? ret : (str[x] ? NOMATCH : MATCH));
00261 }
00262 
00263 static int 
00264 port_RegExpMatch(const char *str, const char *xp, PRBool case_insensitive) {
00265     register int x;
00266     char *exp = 0;
00267 
00268     exp = PORT_Strdup(xp);
00269 
00270     if(!exp)
00271        return 1;
00272 
00273     for(x=strlen(exp)-1;x;--x) {
00274         if((exp[x] == '~') && (exp[x-1] != '\\')) {
00275             exp[x] = '\0';
00276             if(_shexp_match(str,&exp[++x], case_insensitive) == MATCH)
00277                 goto punt;
00278             break;
00279         }
00280     }
00281     if(_shexp_match(str,exp, case_insensitive) == MATCH) {
00282         PORT_Free(exp);
00283         return 0;
00284     }
00285 
00286   punt:
00287     PORT_Free(exp);
00288     return 1;
00289 }
00290 
00291 
00292 /* ------------------------------ shexp_cmp ------------------------------- */
00293 
00294 int 
00295 PORT_RegExpSearch(const char *str, const char *exp)
00296 {
00297     switch(PORT_RegExpValid(exp)) 
00298          {
00299         case INVALID_SXP:
00300             return -1;
00301         case NON_SXP:
00302             return (strcmp(exp,str) ? 1 : 0);
00303         default:
00304             return port_RegExpMatch(str, exp, PR_FALSE);
00305       }
00306 }
00307 
00308 int
00309 PORT_RegExpCaseSearch(const char *str, const char *exp)
00310 {
00311     switch(PORT_RegExpValid(exp))
00312       {
00313         case INVALID_SXP:
00314             return -1;
00315         case NON_SXP:
00316             return (PORT_Strcasecmp(exp,str) ? 1 : 0);
00317         default:
00318             return port_RegExpMatch(str, exp, PR_TRUE);
00319       }
00320 }
00321