Fossil SCM
Add the glob_multi_match() interface that allows checking against a comma-separated list of GLOB patterns without having to compile the list first.
Commit
dc86831179acbe3a4ce9ef6ddb642375eccfa4a8f25819ff6611a8cc85a8402c
Parent
6b5606d8321c396…
2 files changed
+59
-1
+4
-13
+59
-1
| --- src/glob.c | ||
| +++ src/glob.c | ||
| @@ -138,10 +138,61 @@ | ||
| 138 | 138 | z[i] = 0; |
| 139 | 139 | z += i+1; |
| 140 | 140 | } |
| 141 | 141 | return p; |
| 142 | 142 | } |
| 143 | + | |
| 144 | +/* | |
| 145 | +** Return TRUE if zString matches any of the GLOB patterns in the | |
| 146 | +** string zPatternList. | |
| 147 | +** | |
| 148 | +** This is a like calling glob_create(), glob_match(), and glob_free() | |
| 149 | +** in sequence, without the overhead of creating the reusable Glob object. | |
| 150 | +** Use this for one-time matches against a comma-separated GLOB list. | |
| 151 | +*/ | |
| 152 | +int glob_multi_match(const char *zPatternList, const char *zString){ | |
| 153 | + int i; /* Loop counters */ | |
| 154 | + int n = 0; /* Pattern counter */ | |
| 155 | + const char *z; /* Current GLOB pattern */ | |
| 156 | + char delimiter; /* '\'' or '\"' or 0 */ | |
| 157 | + int rc; /* Result of comparison */ | |
| 158 | + char zPat[100]; /* Copy of just the current pattern */ | |
| 159 | + | |
| 160 | + if( zPatternList==0 ) return 0; | |
| 161 | + z = zPatternList; | |
| 162 | + while( z[0] ){ | |
| 163 | + while( fossil_isspace(z[0]) || z[0]==',' ){ | |
| 164 | + z++; /* Skip leading commas, spaces, and newlines */ | |
| 165 | + } | |
| 166 | + if( z[0]==0 ) break; | |
| 167 | + if( z[0]=='\'' || z[0]=='"' ){ | |
| 168 | + delimiter = z[0]; | |
| 169 | + z++; | |
| 170 | + }else{ | |
| 171 | + delimiter = ','; | |
| 172 | + } | |
| 173 | + /* Find the next delimiter (or the end of the string). */ | |
| 174 | + for(i=0; z[i] && z[i]!=delimiter && | |
| 175 | + !(delimiter==',' && fossil_isspace(z[i])); i++){ | |
| 176 | + /* keep looking for the end of the glob pattern */ | |
| 177 | + } | |
| 178 | + n++; | |
| 179 | + if( i>sizeof(zPat)-1 ){ | |
| 180 | + char *zMPat = fossil_strndup(z, i); | |
| 181 | + rc = sqlite3_strglob(zMPat, zString); | |
| 182 | + fossil_free(zMPat); | |
| 183 | + }else{ | |
| 184 | + memcpy(zPat, z, i); | |
| 185 | + zPat[i] = 0; | |
| 186 | + rc = sqlite3_strglob(zPat, zString); | |
| 187 | + } | |
| 188 | + if( rc==0 ) return n; | |
| 189 | + if( z[i]==0 ) break; | |
| 190 | + z += i+1; | |
| 191 | + } | |
| 192 | + return 0; | |
| 193 | +} | |
| 143 | 194 | |
| 144 | 195 | /* |
| 145 | 196 | ** Return true (non-zero) if zString matches any of the patterns in |
| 146 | 197 | ** the Glob. The value returned is actually a 1-based index of the pattern |
| 147 | 198 | ** that matched. Return 0 if none of the patterns match zString. |
| @@ -210,10 +261,14 @@ | ||
| 210 | 261 | ** the PATTERN. |
| 211 | 262 | ** |
| 212 | 263 | ** If PATTERN begins with "@" the rest of the pattern is understood |
| 213 | 264 | ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob) |
| 214 | 265 | ** and the value of that setting is used as the actually glob pattern. |
| 266 | +** | |
| 267 | +** The output consists of two numbers and a STRING. The first number | |
| 268 | +** is the result of glob_match() and the second is the result of | |
| 269 | +** glob_multi_match(). | |
| 215 | 270 | */ |
| 216 | 271 | void glob_test_cmd(void){ |
| 217 | 272 | Glob *pGlob; |
| 218 | 273 | int i; |
| 219 | 274 | char *zPattern; |
| @@ -229,9 +284,12 @@ | ||
| 229 | 284 | pGlob = glob_create(zPattern); |
| 230 | 285 | for(i=0; i<pGlob->nPattern; i++){ |
| 231 | 286 | fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]); |
| 232 | 287 | } |
| 233 | 288 | for(i=3; i<g.argc; i++){ |
| 234 | - fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]); | |
| 289 | + fossil_print("%d %d %s\n", | |
| 290 | + glob_match(pGlob, g.argv[i]), | |
| 291 | + glob_multi_match(zPattern, g.argv[i]), | |
| 292 | + g.argv[i]); | |
| 235 | 293 | } |
| 236 | 294 | glob_free(pGlob); |
| 237 | 295 | } |
| 238 | 296 |
| --- src/glob.c | |
| +++ src/glob.c | |
| @@ -138,10 +138,61 @@ | |
| 138 | z[i] = 0; |
| 139 | z += i+1; |
| 140 | } |
| 141 | return p; |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | ** Return true (non-zero) if zString matches any of the patterns in |
| 146 | ** the Glob. The value returned is actually a 1-based index of the pattern |
| 147 | ** that matched. Return 0 if none of the patterns match zString. |
| @@ -210,10 +261,14 @@ | |
| 210 | ** the PATTERN. |
| 211 | ** |
| 212 | ** If PATTERN begins with "@" the rest of the pattern is understood |
| 213 | ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob) |
| 214 | ** and the value of that setting is used as the actually glob pattern. |
| 215 | */ |
| 216 | void glob_test_cmd(void){ |
| 217 | Glob *pGlob; |
| 218 | int i; |
| 219 | char *zPattern; |
| @@ -229,9 +284,12 @@ | |
| 229 | pGlob = glob_create(zPattern); |
| 230 | for(i=0; i<pGlob->nPattern; i++){ |
| 231 | fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]); |
| 232 | } |
| 233 | for(i=3; i<g.argc; i++){ |
| 234 | fossil_print("%d %s\n", glob_match(pGlob, g.argv[i]), g.argv[i]); |
| 235 | } |
| 236 | glob_free(pGlob); |
| 237 | } |
| 238 |
| --- src/glob.c | |
| +++ src/glob.c | |
| @@ -138,10 +138,61 @@ | |
| 138 | z[i] = 0; |
| 139 | z += i+1; |
| 140 | } |
| 141 | return p; |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | ** Return TRUE if zString matches any of the GLOB patterns in the |
| 146 | ** string zPatternList. |
| 147 | ** |
| 148 | ** This is a like calling glob_create(), glob_match(), and glob_free() |
| 149 | ** in sequence, without the overhead of creating the reusable Glob object. |
| 150 | ** Use this for one-time matches against a comma-separated GLOB list. |
| 151 | */ |
| 152 | int glob_multi_match(const char *zPatternList, const char *zString){ |
| 153 | int i; /* Loop counters */ |
| 154 | int n = 0; /* Pattern counter */ |
| 155 | const char *z; /* Current GLOB pattern */ |
| 156 | char delimiter; /* '\'' or '\"' or 0 */ |
| 157 | int rc; /* Result of comparison */ |
| 158 | char zPat[100]; /* Copy of just the current pattern */ |
| 159 | |
| 160 | if( zPatternList==0 ) return 0; |
| 161 | z = zPatternList; |
| 162 | while( z[0] ){ |
| 163 | while( fossil_isspace(z[0]) || z[0]==',' ){ |
| 164 | z++; /* Skip leading commas, spaces, and newlines */ |
| 165 | } |
| 166 | if( z[0]==0 ) break; |
| 167 | if( z[0]=='\'' || z[0]=='"' ){ |
| 168 | delimiter = z[0]; |
| 169 | z++; |
| 170 | }else{ |
| 171 | delimiter = ','; |
| 172 | } |
| 173 | /* Find the next delimiter (or the end of the string). */ |
| 174 | for(i=0; z[i] && z[i]!=delimiter && |
| 175 | !(delimiter==',' && fossil_isspace(z[i])); i++){ |
| 176 | /* keep looking for the end of the glob pattern */ |
| 177 | } |
| 178 | n++; |
| 179 | if( i>sizeof(zPat)-1 ){ |
| 180 | char *zMPat = fossil_strndup(z, i); |
| 181 | rc = sqlite3_strglob(zMPat, zString); |
| 182 | fossil_free(zMPat); |
| 183 | }else{ |
| 184 | memcpy(zPat, z, i); |
| 185 | zPat[i] = 0; |
| 186 | rc = sqlite3_strglob(zPat, zString); |
| 187 | } |
| 188 | if( rc==0 ) return n; |
| 189 | if( z[i]==0 ) break; |
| 190 | z += i+1; |
| 191 | } |
| 192 | return 0; |
| 193 | } |
| 194 | |
| 195 | /* |
| 196 | ** Return true (non-zero) if zString matches any of the patterns in |
| 197 | ** the Glob. The value returned is actually a 1-based index of the pattern |
| 198 | ** that matched. Return 0 if none of the patterns match zString. |
| @@ -210,10 +261,14 @@ | |
| 261 | ** the PATTERN. |
| 262 | ** |
| 263 | ** If PATTERN begins with "@" the rest of the pattern is understood |
| 264 | ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob) |
| 265 | ** and the value of that setting is used as the actually glob pattern. |
| 266 | ** |
| 267 | ** The output consists of two numbers and a STRING. The first number |
| 268 | ** is the result of glob_match() and the second is the result of |
| 269 | ** glob_multi_match(). |
| 270 | */ |
| 271 | void glob_test_cmd(void){ |
| 272 | Glob *pGlob; |
| 273 | int i; |
| 274 | char *zPattern; |
| @@ -229,9 +284,12 @@ | |
| 284 | pGlob = glob_create(zPattern); |
| 285 | for(i=0; i<pGlob->nPattern; i++){ |
| 286 | fossil_print("pattern[%d] = [%s]\n", i, pGlob->azPattern[i]); |
| 287 | } |
| 288 | for(i=3; i<g.argc; i++){ |
| 289 | fossil_print("%d %d %s\n", |
| 290 | glob_match(pGlob, g.argv[i]), |
| 291 | glob_multi_match(zPattern, g.argv[i]), |
| 292 | g.argv[i]); |
| 293 | } |
| 294 | glob_free(pGlob); |
| 295 | } |
| 296 |
+4
-13
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -1289,21 +1289,18 @@ | ||
| 1289 | 1289 | ** an empty string. |
| 1290 | 1290 | */ |
| 1291 | 1291 | void login_restrict_robot_access(void){ |
| 1292 | 1292 | const char *zReferer; |
| 1293 | 1293 | const char *zGlob; |
| 1294 | - Glob *pGlob; | |
| 1295 | 1294 | int isMatch = 1; |
| 1296 | 1295 | if( g.zLogin!=0 ) return; |
| 1297 | 1296 | zReferer = P("HTTP_REFERER"); |
| 1298 | 1297 | if( zReferer && zReferer[0]!=0 ) return; |
| 1299 | 1298 | zGlob = db_get("robot-restrict",0); |
| 1300 | 1299 | if( zGlob==0 || zGlob[0]==0 ) return; |
| 1301 | 1300 | if( cgi_qp_count()<1 ) return; |
| 1302 | - pGlob = glob_create(zGlob); | |
| 1303 | - isMatch = glob_match(pGlob, g.zPath); | |
| 1304 | - glob_free(pGlob); | |
| 1301 | + isMatch = glob_multi_match(zGlob, g.zPath); | |
| 1305 | 1302 | if( !isMatch ) return; |
| 1306 | 1303 | |
| 1307 | 1304 | /* If we reach this point, it means we have a situation where we |
| 1308 | 1305 | ** want to restrict the activity of a robot. |
| 1309 | 1306 | */ |
| @@ -1559,17 +1556,15 @@ | ||
| 1559 | 1556 | ** one of the globs in public-pages, then also add in all default-perms |
| 1560 | 1557 | ** permissions. |
| 1561 | 1558 | */ |
| 1562 | 1559 | zPublicPages = db_get("public-pages",0); |
| 1563 | 1560 | if( zPublicPages!=0 ){ |
| 1564 | - Glob *pGlob = glob_create(zPublicPages); | |
| 1565 | 1561 | const char *zUri = PD("REQUEST_URI",""); |
| 1566 | 1562 | zUri += (int)strlen(g.zTop); |
| 1567 | - if( glob_match(pGlob, zUri) ){ | |
| 1563 | + if( glob_multi_match(zPublicPages, zUri) ){ | |
| 1568 | 1564 | login_set_capabilities(db_get("default-perms", "u"), 0); |
| 1569 | 1565 | } |
| 1570 | - glob_free(pGlob); | |
| 1571 | 1566 | } |
| 1572 | 1567 | return g.zLogin!=0; |
| 1573 | 1568 | } |
| 1574 | 1569 | |
| 1575 | 1570 | /* |
| @@ -1967,23 +1962,19 @@ | ||
| 1967 | 1962 | ** it is a comma-separated list of GLOB patterns for email addresses |
| 1968 | 1963 | ** that are authorized to self-register. |
| 1969 | 1964 | */ |
| 1970 | 1965 | int authorized_subscription_email(const char *zEAddr){ |
| 1971 | 1966 | char *zGlob = db_get("auth-sub-email",0); |
| 1972 | - Glob *pGlob; | |
| 1973 | 1967 | char *zAddr; |
| 1974 | 1968 | int rc; |
| 1975 | 1969 | |
| 1976 | 1970 | if( zGlob==0 || zGlob[0]==0 ) return 1; |
| 1977 | 1971 | zGlob = fossil_strtolwr(fossil_strdup(zGlob)); |
| 1978 | - pGlob = glob_create(zGlob); | |
| 1972 | + zAddr = fossil_strtolwr(fossil_strdup(zEAddr)); | |
| 1973 | + rc = glob_multi_match(zGlob, zAddr); | |
| 1979 | 1974 | fossil_free(zGlob); |
| 1980 | - | |
| 1981 | - zAddr = fossil_strtolwr(fossil_strdup(zEAddr)); | |
| 1982 | - rc = glob_match(pGlob, zAddr); | |
| 1983 | 1975 | fossil_free(zAddr); |
| 1984 | - glob_free(pGlob); | |
| 1985 | 1976 | return rc!=0; |
| 1986 | 1977 | } |
| 1987 | 1978 | |
| 1988 | 1979 | /* |
| 1989 | 1980 | ** WEBPAGE: register |
| 1990 | 1981 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -1289,21 +1289,18 @@ | |
| 1289 | ** an empty string. |
| 1290 | */ |
| 1291 | void login_restrict_robot_access(void){ |
| 1292 | const char *zReferer; |
| 1293 | const char *zGlob; |
| 1294 | Glob *pGlob; |
| 1295 | int isMatch = 1; |
| 1296 | if( g.zLogin!=0 ) return; |
| 1297 | zReferer = P("HTTP_REFERER"); |
| 1298 | if( zReferer && zReferer[0]!=0 ) return; |
| 1299 | zGlob = db_get("robot-restrict",0); |
| 1300 | if( zGlob==0 || zGlob[0]==0 ) return; |
| 1301 | if( cgi_qp_count()<1 ) return; |
| 1302 | pGlob = glob_create(zGlob); |
| 1303 | isMatch = glob_match(pGlob, g.zPath); |
| 1304 | glob_free(pGlob); |
| 1305 | if( !isMatch ) return; |
| 1306 | |
| 1307 | /* If we reach this point, it means we have a situation where we |
| 1308 | ** want to restrict the activity of a robot. |
| 1309 | */ |
| @@ -1559,17 +1556,15 @@ | |
| 1559 | ** one of the globs in public-pages, then also add in all default-perms |
| 1560 | ** permissions. |
| 1561 | */ |
| 1562 | zPublicPages = db_get("public-pages",0); |
| 1563 | if( zPublicPages!=0 ){ |
| 1564 | Glob *pGlob = glob_create(zPublicPages); |
| 1565 | const char *zUri = PD("REQUEST_URI",""); |
| 1566 | zUri += (int)strlen(g.zTop); |
| 1567 | if( glob_match(pGlob, zUri) ){ |
| 1568 | login_set_capabilities(db_get("default-perms", "u"), 0); |
| 1569 | } |
| 1570 | glob_free(pGlob); |
| 1571 | } |
| 1572 | return g.zLogin!=0; |
| 1573 | } |
| 1574 | |
| 1575 | /* |
| @@ -1967,23 +1962,19 @@ | |
| 1967 | ** it is a comma-separated list of GLOB patterns for email addresses |
| 1968 | ** that are authorized to self-register. |
| 1969 | */ |
| 1970 | int authorized_subscription_email(const char *zEAddr){ |
| 1971 | char *zGlob = db_get("auth-sub-email",0); |
| 1972 | Glob *pGlob; |
| 1973 | char *zAddr; |
| 1974 | int rc; |
| 1975 | |
| 1976 | if( zGlob==0 || zGlob[0]==0 ) return 1; |
| 1977 | zGlob = fossil_strtolwr(fossil_strdup(zGlob)); |
| 1978 | pGlob = glob_create(zGlob); |
| 1979 | fossil_free(zGlob); |
| 1980 | |
| 1981 | zAddr = fossil_strtolwr(fossil_strdup(zEAddr)); |
| 1982 | rc = glob_match(pGlob, zAddr); |
| 1983 | fossil_free(zAddr); |
| 1984 | glob_free(pGlob); |
| 1985 | return rc!=0; |
| 1986 | } |
| 1987 | |
| 1988 | /* |
| 1989 | ** WEBPAGE: register |
| 1990 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -1289,21 +1289,18 @@ | |
| 1289 | ** an empty string. |
| 1290 | */ |
| 1291 | void login_restrict_robot_access(void){ |
| 1292 | const char *zReferer; |
| 1293 | const char *zGlob; |
| 1294 | int isMatch = 1; |
| 1295 | if( g.zLogin!=0 ) return; |
| 1296 | zReferer = P("HTTP_REFERER"); |
| 1297 | if( zReferer && zReferer[0]!=0 ) return; |
| 1298 | zGlob = db_get("robot-restrict",0); |
| 1299 | if( zGlob==0 || zGlob[0]==0 ) return; |
| 1300 | if( cgi_qp_count()<1 ) return; |
| 1301 | isMatch = glob_multi_match(zGlob, g.zPath); |
| 1302 | if( !isMatch ) return; |
| 1303 | |
| 1304 | /* If we reach this point, it means we have a situation where we |
| 1305 | ** want to restrict the activity of a robot. |
| 1306 | */ |
| @@ -1559,17 +1556,15 @@ | |
| 1556 | ** one of the globs in public-pages, then also add in all default-perms |
| 1557 | ** permissions. |
| 1558 | */ |
| 1559 | zPublicPages = db_get("public-pages",0); |
| 1560 | if( zPublicPages!=0 ){ |
| 1561 | const char *zUri = PD("REQUEST_URI",""); |
| 1562 | zUri += (int)strlen(g.zTop); |
| 1563 | if( glob_multi_match(zPublicPages, zUri) ){ |
| 1564 | login_set_capabilities(db_get("default-perms", "u"), 0); |
| 1565 | } |
| 1566 | } |
| 1567 | return g.zLogin!=0; |
| 1568 | } |
| 1569 | |
| 1570 | /* |
| @@ -1967,23 +1962,19 @@ | |
| 1962 | ** it is a comma-separated list of GLOB patterns for email addresses |
| 1963 | ** that are authorized to self-register. |
| 1964 | */ |
| 1965 | int authorized_subscription_email(const char *zEAddr){ |
| 1966 | char *zGlob = db_get("auth-sub-email",0); |
| 1967 | char *zAddr; |
| 1968 | int rc; |
| 1969 | |
| 1970 | if( zGlob==0 || zGlob[0]==0 ) return 1; |
| 1971 | zGlob = fossil_strtolwr(fossil_strdup(zGlob)); |
| 1972 | zAddr = fossil_strtolwr(fossil_strdup(zEAddr)); |
| 1973 | rc = glob_multi_match(zGlob, zAddr); |
| 1974 | fossil_free(zGlob); |
| 1975 | fossil_free(zAddr); |
| 1976 | return rc!=0; |
| 1977 | } |
| 1978 | |
| 1979 | /* |
| 1980 | ** WEBPAGE: register |
| 1981 |