2 static const char rcsid[] =
7 * FreeBSD install - a package for the installation and maintainance
8 * of non-core utilities.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
22 * Routines used to query installed packages.
33 * Simple structure representing argv-like
34 * NULL-terminated list.
42 static int rex_match(const char *, const char *);
43 static int storeappend(struct store *, const char *);
44 static int fname_cmp(const FTSENT **, const FTSENT **);
47 * Function to query names of installed packages.
48 * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
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
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.
58 matchinstalled(match_t MatchType, char **patterns, int *retval)
62 const char *paths[2] = {LOG_DIR, NULL};
63 static struct store *store = NULL;
69 store = malloc(sizeof *store);
71 warnx("%s(): malloc() failed", __FUNCTION__);
79 if (store->store != NULL)
80 /* Free previously allocated memory */
81 for (i = 0; store->store[i] != NULL; i++)
82 free(store->store[i]);
88 if (!isdir(paths[0])) {
95 /* Count number of patterns */
96 if (patterns != NULL) {
97 for (len = 0; patterns[len]; len++) {}
98 lmatched = alloca(sizeof(*lmatched) * len);
99 if (lmatched == NULL) {
100 warnx("%s(): alloca() failed", __FUNCTION__);
108 for (i = 0; i < len; i++)
111 ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
113 while ((f = fts_read(ftsp)) != NULL) {
114 if (f->fts_info == FTS_D && f->fts_level == 1) {
115 fts_set(ftsp, f, FTS_SKIP);
118 if (MatchType == MATCH_ALL)
119 matched = f->fts_name;
121 for (i = 0; patterns[i]; i++) {
124 errcode = rex_match(patterns[i], f->fts_name);
126 matched = f->fts_name;
131 if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
132 matched = f->fts_name;
139 if (matched != NULL || errcode != 0)
142 if (errcode == 0 && matched != NULL)
143 errcode = storeappend(store, matched);
155 if (MatchType == MATCH_GLOB) {
156 for (i = 0; i < len; i++)
157 if (lmatched[i] == FALSE)
158 storeappend(store, patterns[i]);
161 if (store->used == 0)
168 * Returns 1 if specified pkgname matches RE pattern.
169 * Otherwise returns 0 if doesn't match or -1 if RE
170 * engine reported an error (usually invalid syntax).
173 rex_match(const char *pattern, const char *pkgname)
182 errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
184 errcode = regexec(&rex, pkgname, 0, NULL, 0);
188 } else if (errcode != REG_NOMATCH) {
189 regerror(errcode, &rex, errbuf, sizeof(errbuf));
190 warnx("%s: %s", pattern, errbuf);
200 storeappend(struct store *store, const char *item)
202 if (store->used + 2 > store->currlen) {
203 store->currlen += 16;
204 store->store = reallocf(store->store,
205 store->currlen * sizeof(*(store->store)));
206 if (store->store == NULL) {
208 warnx("%s(): reallocf() failed", __FUNCTION__);
213 asprintf(&(store->store[store->used]), "%s", item);
214 if (store->store[store->used] == NULL) {
215 warnx("%s(): malloc() failed", __FUNCTION__);
219 store->store[store->used] = NULL;
225 fname_cmp(const FTSENT **a, const FTSENT **b)
227 return strcmp((*a)->fts_name, (*b)->fts_name);