/* * Copyright (c) 2005 * iMil . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by iMil. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY iMil AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL iMil OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $Id: parsedirs.c,v 1.6 2005/12/09 15:28:12 imil Exp $ */ #include "pkg_select.h" #if __NetBSD__ #define DIRENT const struct dirent #else #define DIRENT struct dirent #endif static int checkskip(DIRENT *); static int partialmatch(const char *, const char *); /* from pkgfind */ static const char *skip[] = { ".", "..", "CVS", "bootstrap", "doc", "cross", "mk", "distfiles", "packages", "licenses", "templates", NULL }; static struct dirent **dlist; static int count; static int checkskip(DIRENT *dp) { const char **p; for (p = skip; *p != NULL; p++) if (strcmp(dp->d_name, *p) == 0) return 0; return 1; } Etree ** get_tree(const char *path, int where) { int i, j, deepness; struct stat sb; struct cf *file; Etree **etree; char buf[MAXLEN], **tmp, *p; /* check if we are browsing a directory */ if (stat(path, &sb) < 0) return(NULL); if ((sb.st_mode & S_IFMT) != S_IFDIR) return(NULL); if ((count = scandir(path, &dlist, checkskip, alphasort)) < 0) err(EXIT_FAILURE, "%s", path); if (count == 0) return(NULL); /* we donc want to recurse on pkgsrc-wip */ if (strstr(path, "/wip") != NULL) deepness = ONE_LEVEL; else deepness = PARTIAL; XMALLOC(etree, (count + 1) * sizeof(Etree *)); /* NULL every line */ for (i = 0; i < count; i++) etree[i] = NULL; /* map list to an array */ for (i = 0, j = 0; i < count; i++, j++) { /* DESCR found, we are in a package dir */ if (strcmp(dlist[i]->d_name, "DESCR") == 0) { etree[j] = NULL; free_tree(&etree); return(NULL); } /* check if entry is a directory */ snprintf(buf, MAXLEN, "%s/%s", path, dlist[i]->d_name); if ((stat(buf, &sb) < 0) || !S_ISDIR(sb.st_mode)) { j--; continue; } XMALLOC(etree[j], sizeof(Etree)); /* unused here */ etree[j]->dep_path = NULL; if (where == IN_PKGSRC || where == IN_SYSINST) { etree[j]->entry = dlist[i]->d_name; file = load_makefile(buf, deepness); etree[j]->comment = getcomment(file, buf); freecf(file); } else { /* depends */ snprintf(buf, MAXLEN, "%s/%s/+COMMENT", pkg_dbdir, dlist[i]->d_name); tmp = loadfile(buf); if (tmp != NULL && tmp[0] != NULL) XSTRDUP(etree[j]->comment, tmp[0]); else XSTRDUP(etree[j]->comment, NOCOMMENT); freefile(tmp); p = strrchr(etree[j]->comment, '\n'); if (p != NULL) *p = '\0'; p = strrchr(dlist[i]->d_name, '-'); if (p != NULL) *p = '\0'; etree[j]->entry = dlist[i]->d_name; } } etree[j] = NULL; return(etree); } void free_tree(Etree ***etree) { int i; Etree **ptree; /* free dirent's */ if (dlist != NULL) { for (i = 0; i < count; i++) XFREE(dlist[i]); XFREE(dlist); } if (*etree != NULL) { ptree = *etree; for (i = 0; ptree[i] != NULL; i++) { XFREE(ptree[i]->comment); XFREE(ptree[i]); } XFREE(*etree); } } Etree ** get_nodir_tree(const char *path, char **list) { int i; char *p, pkgdep[MAXLEN]; Etree **etree; struct cf *file; if (list == NULL) return(NULL); for (i = 0; list[i] != NULL; i++); count = i; XMALLOC(etree, (count + 1) * sizeof(Etree *)); for (i = 0; i < count; i++) { XMALLOC(etree[i], sizeof(Etree)); p = strchr(list[i], ':'); if (p != NULL) { snprintf(pkgdep, MAXLEN, "%s/%s", path, ++p); XSTRDUP(etree[i]->dep_path, p); p = strrchr(etree[i]->dep_path, '/'); if (p != NULL) { p++; XSTRDUP(etree[i]->entry, p); } file = load_makefile(pkgdep, PARTIAL); etree[i]->comment = getcomment(file, pkgdep); freecf(file); } } etree[i] = NULL; return(etree); } void free_nodir_tree(Etree ***etree) { int i; Etree **ptree; if (*etree != NULL) { ptree = *etree; for (i = 0; ptree[i] != NULL; i++) { XFREE(ptree[i]->entry); XFREE(ptree[i]->dep_path); XFREE(ptree[i]->comment); XFREE(ptree[i]); } XFREE(*etree); } } /* adaptation from Peter Postma's pkgfind */ char ** pkgfind(const char *path, const char *pkg, int nres) { struct dirent **cat, **list; int ncat, nlist, i, j, k, called; char tmp[MAXLEN]; char *text; static char **reslist = NULL; struct stat sb; if (!isalnum((unsigned char)*pkg)) return(NULL); if ((ncat = scandir(path, &cat, checkskip, alphasort)) < 0) return(NULL); k = 0; if (nres > 0) { XMALLOC(reslist, (nres + 1) * sizeof(char *)); called = T_TRUE; } else called = T_FALSE; for (i = 0; i < ncat; i++) { if ((unsigned int)snprintf(tmp, sizeof(tmp), "%s/%s", path, cat[i]->d_name) >= sizeof(tmp)) { warnx("filename too long"); continue; } if (stat(tmp, &sb) < 0 || !S_ISDIR(sb.st_mode)) continue; if ((nlist = scandir(tmp, &list, checkskip, alphasort)) < 0) { warn("%s", tmp); continue; } for (j = 0; j < nlist; j++) { if ((unsigned int)snprintf(tmp, sizeof(tmp), "%s/%s/%s", path, cat[i]->d_name, list[j]->d_name) >= sizeof(tmp)) { warnx("filename too long"); continue; } if (stat(tmp, &sb) < 0 || !S_ISDIR(sb.st_mode)) continue; text = list[j]->d_name; /* match */ if (partialmatch(text, pkg)) { if (called == T_FALSE) nres++; else { snprintf(tmp, MAXLEN, ":%s/%s", cat[i]->d_name, list[j]->d_name); XSTRDUP(reslist[k], tmp); k++; } } /* showpkg(path, cat[i]->d_name, list[j]->d_name);*/ free(list[j]); } free(cat[i]); } free(list); free(cat); if (called == T_FALSE) { if (nres == 0) return(NULL); return(pkgfind(path, pkg, nres)); } reslist[k] = NULL; return(reslist); } static int partialmatch(const char *s, const char *find) { size_t len, n; len = strlen(find); n = strlen(s) - len; do { if (strncasecmp(s, find, len) == 0) return 1; } while (*++s != '\0' && n-- > 0); return 0; }