1 /* $NetBSD: opattern.c,v 1.1.1.3 2012/02/19 17:46:47 tron Exp $ */ 2 3 #if HAVE_CONFIG_H 4 #include "config.h" 5 #endif 6 #include <nbcompat.h> 7 #if HAVE_SYS_CDEFS_H 8 #include <sys/cdefs.h> 9 #endif 10 __RCSID("$NetBSD: opattern.c,v 1.1.1.3 2012/02/19 17:46:47 tron Exp $"); 11 12 /* 13 * FreeBSD install - a package for the installation and maintainance 14 * of non-core utilities. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * Jordan K. Hubbard 26 * 18 July 1993 27 * 28 * Miscellaneous string utilities. 29 * 30 */ 31 32 #if HAVE_ASSERT_H 33 #include <assert.h> 34 #endif 35 #if HAVE_ERR_H 36 #include <err.h> 37 #endif 38 #if HAVE_FNMATCH_H 39 #include <fnmatch.h> 40 #endif 41 #include "lib.h" 42 #include "dewey.h" 43 44 /* pull in definitions and macros for resizing arrays as we go */ 45 #include "defs.h" 46 47 /* 48 * Perform alternate match on "pkg" against "pattern", 49 * calling pkg_match (recursively) to resolve any other patterns. 50 * Return 1 on match, 0 otherwise 51 */ 52 static int 53 alternate_match(const char *pattern, const char *pkg) 54 { 55 char *sep; 56 char buf[MaxPathSize]; 57 char *last; 58 char *alt; 59 char *cp; 60 int cnt; 61 int found; 62 63 if ((sep = strchr(pattern, '{')) == (char *) NULL) { 64 errx(EXIT_FAILURE, "alternate_match(): '{' expected in `%s'", pattern); 65 } 66 (void) strncpy(buf, pattern, (size_t) (sep - pattern)); 67 alt = &buf[sep - pattern]; 68 last = (char *) NULL; 69 for (cnt = 0, cp = sep; *cp && last == (char *) NULL; cp++) { 70 if (*cp == '{') { 71 cnt++; 72 } else if (*cp == '}' && --cnt == 0 && last == (char *) NULL) { 73 last = cp + 1; 74 } 75 } 76 if (cnt != 0) { 77 errx(EXIT_FAILURE, "Malformed alternate `%s'", pattern); 78 } 79 for (found = 0, cp = sep + 1; *sep != '}'; cp = sep + 1) { 80 for (cnt = 0, sep = cp; cnt > 0 || (cnt == 0 && *sep != '}' && *sep != ','); sep++) { 81 if (*sep == '{') { 82 cnt++; 83 } else if (*sep == '}') { 84 cnt--; 85 } 86 } 87 (void) snprintf(alt, sizeof(buf) - (alt - buf), "%.*s%s", (int) (sep - cp), cp, last); 88 if (pkg_match(buf, pkg) == 1) { 89 found = 1; 90 } 91 } 92 return found; 93 } 94 95 /* 96 * Perform glob match on "pkg" against "pattern". 97 * Return 1 on match, 0 otherwise 98 */ 99 static int 100 glob_match(const char *pattern, const char *pkg) 101 { 102 return fnmatch(pattern, pkg, FNM_PERIOD) == 0; 103 } 104 105 /* 106 * Perform simple match on "pkg" against "pattern". 107 * Return 1 on match, 0 otherwise 108 */ 109 static int 110 simple_match(const char *pattern, const char *pkg) 111 { 112 return strcmp(pattern, pkg) == 0; 113 } 114 115 /* 116 * Performs a fast check if pattern can ever match pkg. 117 * Returns 1 if a match is possible and 0 otherwise. 118 */ 119 int 120 quick_pkg_match(const char *pattern, const char *pkg) 121 { 122 #define simple(x) (isalnum((unsigned char)(x)) || (x) == '-') 123 if (!simple(pattern[0])) 124 return 1; 125 if (pattern[0] != pkg[0]) 126 return 0; 127 128 if (!simple(pattern[1])) 129 return 1; 130 if (pattern[1] != pkg[1]) 131 return 0; 132 return 1; 133 #undef simple 134 } 135 136 /* 137 * Match pkg against pattern, return 1 if matching, 0 else 138 */ 139 int 140 pkg_match(const char *pattern, const char *pkg) 141 { 142 if (!quick_pkg_match(pattern, pkg)) 143 return 0; 144 145 if (strchr(pattern, '{') != (char *) NULL) { 146 /* emulate csh-type alternates */ 147 return alternate_match(pattern, pkg); 148 } 149 if (strpbrk(pattern, "<>") != (char *) NULL) { 150 int ret; 151 152 /* perform relational dewey match on version number */ 153 ret = dewey_match(pattern, pkg); 154 if (ret < 0) 155 errx(EXIT_FAILURE, "dewey_match returned error"); 156 return ret; 157 } 158 if (strpbrk(pattern, "*?[]") != (char *) NULL) { 159 /* glob match */ 160 if (glob_match(pattern, pkg)) 161 return 1; 162 } 163 164 /* no alternate, dewey or glob match -> simple compare */ 165 if (simple_match(pattern, pkg)) 166 return 1; 167 168 /* globbing patterns and simple matches may be specified with or 169 * without the version number, so check for both cases. */ 170 171 { 172 char *pattern_ver; 173 int retval; 174 175 pattern_ver = xasprintf("%s-[0-9]*", pattern); 176 retval = glob_match(pattern_ver, pkg); 177 free(pattern_ver); 178 return retval; 179 } 180 } 181 182 int 183 pkg_order(const char *pattern, const char *first_pkg, const char *second_pkg) 184 { 185 const char *first_version; 186 const char *second_version; 187 188 if (first_pkg == NULL && second_pkg == NULL) 189 return 0; 190 191 if (first_pkg == NULL) 192 return pkg_match(pattern, second_pkg) ? 2 : 0; 193 if (second_pkg == NULL) 194 return pkg_match(pattern, first_pkg) ? 1 : 0; 195 196 first_version = strrchr(first_pkg, '-'); 197 second_version = strrchr(second_pkg, '-'); 198 199 if (first_version == NULL || !pkg_match(pattern, first_pkg)) 200 return pkg_match(pattern, second_pkg) ? 2 : 0; 201 202 if (second_version == NULL || !pkg_match(pattern, second_pkg)) 203 return pkg_match(pattern, first_pkg) ? 1 : 0; 204 205 if (dewey_cmp(first_version + 1, DEWEY_GT, second_version + 1)) 206 return 1; 207 else if (dewey_cmp(first_version + 1, DEWEY_LT, second_version + 1)) 208 return 2; 209 else if (strcmp(first_pkg, second_pkg) < 0) 210 return 1; 211 else 212 return 2; 213 } 214