match.c (123770) | match.c (131275) |
---|---|
1/* 2 * FreeBSD install - a package for the installation and maintainance 3 * of non-core utilities. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 5 unchanged lines hidden (view full) --- 14 * Maxim Sobolev 15 * 24 February 2001 16 * 17 * Routines used to query installed packages. 18 * 19 */ 20 21#include <sys/cdefs.h> | 1/* 2 * FreeBSD install - a package for the installation and maintainance 3 * of non-core utilities. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 5 unchanged lines hidden (view full) --- 14 * Maxim Sobolev 15 * 24 February 2001 16 * 17 * Routines used to query installed packages. 18 * 19 */ 20 21#include <sys/cdefs.h> |
22__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/lib/match.c 123770 2003-12-23 15:01:12Z schweikh $"); | 22__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/lib/match.c 131275 2004-06-29 18:54:47Z eik $"); |
23 24#include "lib.h" 25#include <err.h> 26#include <fnmatch.h> 27#include <fts.h> 28#include <regex.h> 29 30/* 31 * Simple structure representing argv-like 32 * NULL-terminated list. 33 */ 34struct store { 35 int currlen; 36 int used; 37 char **store; 38}; 39 | 23 24#include "lib.h" 25#include <err.h> 26#include <fnmatch.h> 27#include <fts.h> 28#include <regex.h> 29 30/* 31 * Simple structure representing argv-like 32 * NULL-terminated list. 33 */ 34struct store { 35 int currlen; 36 int used; 37 char **store; 38}; 39 |
40static int rex_match(const char *, const char *); | 40static int rex_match(const char *, const char *, int); 41static int csh_match(const char *, const char *, int); |
41struct store *storecreate(struct store *); 42static int storeappend(struct store *, const char *); 43static int fname_cmp(const FTSENT * const *, const FTSENT * const *); 44 45/* 46 * Function to query names of installed packages. | 42struct store *storecreate(struct store *); 43static int storeappend(struct store *, const char *); 44static int fname_cmp(const FTSENT * const *, const FTSENT * const *); 45 46/* 47 * Function to query names of installed packages. |
47 * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB; | 48 * MatchType - one of MATCH_ALL, MATCH_EREGEX, MATCH_REGEX, MATCH_GLOB, MATCH_NGLOB; |
48 * patterns - NULL-terminated list of glob or regex patterns 49 * (could be NULL for MATCH_ALL); 50 * retval - return value (could be NULL if you don't want/need 51 * return value). 52 * Returns NULL-terminated list with matching names. 53 * Names in list returned are dynamically allocated and should 54 * not be altered by the caller. 55 */ --- 47 unchanged lines hidden (view full) --- 103 if (f->fts_info == FTS_D && f->fts_level == 1) { 104 fts_set(ftsp, f, FTS_SKIP); 105 matched = NULL; 106 errcode = 0; 107 if (MatchType == MATCH_ALL) 108 matched = f->fts_name; 109 else 110 for (i = 0; patterns[i]; i++) { | 49 * patterns - NULL-terminated list of glob or regex patterns 50 * (could be NULL for MATCH_ALL); 51 * retval - return value (could be NULL if you don't want/need 52 * return value). 53 * Returns NULL-terminated list with matching names. 54 * Names in list returned are dynamically allocated and should 55 * not be altered by the caller. 56 */ --- 47 unchanged lines hidden (view full) --- 104 if (f->fts_info == FTS_D && f->fts_level == 1) { 105 fts_set(ftsp, f, FTS_SKIP); 106 matched = NULL; 107 errcode = 0; 108 if (MatchType == MATCH_ALL) 109 matched = f->fts_name; 110 else 111 for (i = 0; patterns[i]; i++) { |
111 switch (MatchType) { 112 case MATCH_REGEX: 113 errcode = rex_match(patterns[i], f->fts_name); 114 if (errcode == 1) { 115 matched = f->fts_name; 116 errcode = 0; 117 } 118 break; 119 case MATCH_GLOB: 120 if (fnmatch(patterns[i], f->fts_name, 0) == 0) { 121 matched = f->fts_name; 122 lmatched[i] = TRUE; 123 } 124 break; 125 default: 126 break; | 112 errcode = pattern_match(MatchType, patterns[i], f->fts_name); 113 if (errcode == 1) { 114 matched = f->fts_name; 115 lmatched[i] = TRUE; 116 errcode = 0; |
127 } 128 if (matched != NULL || errcode != 0) 129 break; 130 } 131 if (errcode == 0 && matched != NULL) 132 errcode = storeappend(store, matched); 133 if (errcode != 0) { 134 if (retval != NULL) --- 13 unchanged lines hidden (view full) --- 148 } 149 150 if (store->used == 0) 151 return NULL; 152 else 153 return store->store; 154} 155 | 117 } 118 if (matched != NULL || errcode != 0) 119 break; 120 } 121 if (errcode == 0 && matched != NULL) 122 errcode = storeappend(store, matched); 123 if (errcode != 0) { 124 if (retval != NULL) --- 13 unchanged lines hidden (view full) --- 138 } 139 140 if (store->used == 0) 141 return NULL; 142 else 143 return store->store; 144} 145 |
146int 147pattern_match(match_t MatchType, char *pattern, const char *pkgname) 148{ 149 int errcode = 0; 150 const char *fname = pkgname; 151 char basefname[PATH_MAX]; 152 char condchar = '\0'; 153 char *condition; 154 155 /* do we have an appended condition? */ 156 condition = strpbrk(pattern, "<>="); 157 if (condition) { 158 const char *ch; 159 /* yes, isolate the pattern from the condition ... */ 160 if (condition > pattern && condition[-1] == '!') 161 condition--; 162 condchar = *condition; 163 *condition = '\0'; 164 /* ... and compare the name without version */ 165 ch = strrchr(fname, '-'); 166 if (ch && ch - fname < PATH_MAX) { 167 strlcpy(basefname, fname, ch - fname + 1); 168 fname = basefname; 169 } 170 } 171 172 switch (MatchType) { 173 case MATCH_EREGEX: 174 case MATCH_REGEX: 175 errcode = rex_match(pattern, fname, MatchType == MATCH_EREGEX ? 1 : 0); 176 break; 177 case MATCH_NGLOB: 178 case MATCH_GLOB: 179 errcode = (csh_match(pattern, fname, 0) == 0) ? 1 : 0; 180 break; 181 case MATCH_EXACT: 182 errcode = (strcmp(pattern, fname) == 0) ? 1 : 0; 183 break; 184 case MATCH_ALL: 185 errcode = 1; 186 break; 187 default: 188 break; 189 } 190 191 /* loop over all appended conditions */ 192 while (condition) { 193 /* restore the pattern */ 194 *condition = condchar; 195 /* parse the condition (fun with bits) */ 196 if (errcode == 1) { 197 char *nextcondition; 198 /* compare version numbers */ 199 int match = 0; 200 if (*++condition == '=') { 201 match = 2; 202 condition++; 203 } 204 switch(condchar) { 205 case '<': 206 match |= 1; 207 break; 208 case '>': 209 match |= 4; 210 break; 211 case '=': 212 match |= 2; 213 break; 214 case '!': 215 match = 5; 216 break; 217 } 218 /* isolate the version number from the next condition ... */ 219 nextcondition = strpbrk(condition, "<>=!"); 220 if (nextcondition) { 221 condchar = *nextcondition; 222 *nextcondition = '\0'; 223 } 224 /* and compare the versions (version_cmp removes the filename for us) */ 225 if ((match & (1 << (version_cmp(pkgname, condition) + 1))) == 0) 226 errcode = 0; 227 condition = nextcondition; 228 } else { 229 break; 230 } 231 } 232 233 return errcode; 234} 235 |
|
156/* 157 * Synopsis is similar to matchinstalled(), but use origin 158 * as a key for matching packages. 159 */ 160char ** 161matchbyorigin(const char *origin, int *retval) 162{ 163 char **installed; --- 24 unchanged lines hidden (view full) --- 188 * SPECIAL CASE: ignore empty dirs, since we can can see them 189 * during port installation. 190 */ 191 if (isemptydir(tmp)) 192 continue; 193 snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME); 194 fp = fopen(tmp, "r"); 195 if (fp == NULL) { | 236/* 237 * Synopsis is similar to matchinstalled(), but use origin 238 * as a key for matching packages. 239 */ 240char ** 241matchbyorigin(const char *origin, int *retval) 242{ 243 char **installed; --- 24 unchanged lines hidden (view full) --- 268 * SPECIAL CASE: ignore empty dirs, since we can can see them 269 * during port installation. 270 */ 271 if (isemptydir(tmp)) 272 continue; 273 snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME); 274 fp = fopen(tmp, "r"); 275 if (fp == NULL) { |
196 warn("%s", tmp); 197 if (retval != NULL) 198 *retval = 1; 199 return NULL; | 276 warnx("the package info for package '%s' is corrupt", installed[i]); 277 continue; |
200 } 201 202 cmd = -1; 203 while (fgets(tmp, sizeof(tmp), fp)) { 204 int len = strlen(tmp); 205 206 while (len && isspace(tmp[len - 1])) 207 tmp[--len] = '\0'; 208 if (!len) 209 continue; 210 cp = tmp; 211 if (tmp[0] != CMD_CHAR) 212 continue; 213 cmd = plist_cmd(tmp + 1, &cp); 214 if (cmd == PLIST_ORIGIN) { | 278 } 279 280 cmd = -1; 281 while (fgets(tmp, sizeof(tmp), fp)) { 282 int len = strlen(tmp); 283 284 while (len && isspace(tmp[len - 1])) 285 tmp[--len] = '\0'; 286 if (!len) 287 continue; 288 cp = tmp; 289 if (tmp[0] != CMD_CHAR) 290 continue; 291 cmd = plist_cmd(tmp + 1, &cp); 292 if (cmd == PLIST_ORIGIN) { |
215 if (strcmp(origin, cp) == 0) | 293 if (csh_match(origin, cp, FNM_PATHNAME) == 0) |
216 storeappend(store, installed[i]); 217 break; 218 } 219 } 220 if (cmd != PLIST_ORIGIN) 221 warnx("package %s has no origin recorded", installed[i]); 222 fclose(fp); 223 } --- 26 unchanged lines hidden (view full) --- 250} 251 252/* 253 * Returns 1 if specified pkgname matches RE pattern. 254 * Otherwise returns 0 if doesn't match or -1 if RE 255 * engine reported an error (usually invalid syntax). 256 */ 257static int | 294 storeappend(store, installed[i]); 295 break; 296 } 297 } 298 if (cmd != PLIST_ORIGIN) 299 warnx("package %s has no origin recorded", installed[i]); 300 fclose(fp); 301 } --- 26 unchanged lines hidden (view full) --- 328} 329 330/* 331 * Returns 1 if specified pkgname matches RE pattern. 332 * Otherwise returns 0 if doesn't match or -1 if RE 333 * engine reported an error (usually invalid syntax). 334 */ 335static int |
258rex_match(const char *pattern, const char *pkgname) | 336rex_match(const char *pattern, const char *pkgname, int extended) |
259{ 260 char errbuf[128]; 261 int errcode; 262 int retval; 263 regex_t rex; 264 265 retval = 0; 266 | 337{ 338 char errbuf[128]; 339 int errcode; 340 int retval; 341 regex_t rex; 342 343 retval = 0; 344 |
267 errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB); | 345 errcode = regcomp(&rex, pattern, (extended ? REG_EXTENDED : REG_BASIC) | REG_NOSUB); |
268 if (errcode == 0) 269 errcode = regexec(&rex, pkgname, 0, NULL, 0); 270 271 if (errcode == 0) { 272 retval = 1; 273 } else if (errcode != REG_NOMATCH) { 274 regerror(errcode, &rex, errbuf, sizeof(errbuf)); 275 warnx("%s: %s", pattern, errbuf); 276 retval = -1; 277 } 278 279 regfree(&rex); 280 281 return retval; 282} 283 284/* | 346 if (errcode == 0) 347 errcode = regexec(&rex, pkgname, 0, NULL, 0); 348 349 if (errcode == 0) { 350 retval = 1; 351 } else if (errcode != REG_NOMATCH) { 352 regerror(errcode, &rex, errbuf, sizeof(errbuf)); 353 warnx("%s: %s", pattern, errbuf); 354 retval = -1; 355 } 356 357 regfree(&rex); 358 359 return retval; 360} 361 362/* |
363 * Match string by a csh-style glob pattern. Returns 0 on 364 * match and FNM_NOMATCH otherwise, to be compatible with 365 * fnmatch(3). 366 */ 367static int 368csh_match(const char *pattern, const char *string, int flags) 369{ 370 int ret = FNM_NOMATCH; 371 372 373 const char *nextchoice = pattern; 374 const char *current = NULL; 375 376 int prefixlen = -1; 377 int currentlen = 0; 378 379 int level = 0; 380 381 do { 382 const char *pos = nextchoice; 383 const char *postfix = NULL; 384 385 Boolean quoted = FALSE; 386 387 nextchoice = NULL; 388 389 do { 390 const char *eb; 391 if (!*pos) { 392 postfix = pos; 393 } else if (quoted) { 394 quoted = FALSE; 395 } else { 396 switch (*pos) { 397 case '{': 398 ++level; 399 if (level == 1) { 400 current = pos+1; 401 prefixlen = pos-pattern; 402 } 403 break; 404 case ',': 405 if (level == 1 && !nextchoice) { 406 nextchoice = pos+1; 407 currentlen = pos-current; 408 } 409 break; 410 case '}': 411 if (level == 1) { 412 postfix = pos+1; 413 if (!nextchoice) 414 currentlen = pos-current; 415 } 416 level--; 417 break; 418 case '[': 419 eb = pos+1; 420 if (*eb == '!' || *eb == '^') 421 eb++; 422 if (*eb == ']') 423 eb++; 424 while(*eb && *eb != ']') 425 eb++; 426 if (*eb) 427 pos=eb; 428 break; 429 case '\\': 430 quoted = TRUE; 431 break; 432 default: 433 ; 434 } 435 } 436 pos++; 437 } while (!postfix); 438 439 if (current) { 440 char buf[FILENAME_MAX]; 441 snprintf(buf, sizeof(buf), "%.*s%.*s%s", prefixlen, pattern, currentlen, current, postfix); 442 ret = csh_match(buf, string, flags); 443 if (ret) { 444 current = nextchoice; 445 level = 1; 446 } else 447 current = NULL; 448 } else 449 ret = fnmatch(pattern, string, flags); 450 } while (current); 451 452 return ret; 453} 454 455/* |
|
285 * Create an empty store, optionally deallocating 286 * any previously allocated space if store != NULL. 287 */ 288struct store * 289storecreate(struct store *store) 290{ 291 int i; 292 --- 52 unchanged lines hidden --- | 456 * Create an empty store, optionally deallocating 457 * any previously allocated space if store != NULL. 458 */ 459struct store * 460storecreate(struct store *store) 461{ 462 int i; 463 --- 52 unchanged lines hidden --- |