Deleted Added
full compact
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 ---