1 /* Interface to `ar' archives for GNU Make. 2 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 3 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software 4 Foundation, Inc. 5 This file is part of GNU Make. 6 7 GNU Make is free software; you can redistribute it and/or modify it under the 8 terms of the GNU General Public License as published by the Free Software 9 Foundation; either version 2, or (at your option) any later version. 10 11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 13 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along with 16 GNU Make; see the file COPYING. If not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ 18 19 #include "make.h" 20 21 #ifndef NO_ARCHIVES 22 23 #include "filedef.h" 24 #include "dep.h" 25 #include <fnmatch.h> 26 27 /* Defined in arscan.c. */ 28 extern long int ar_scan (char *archive, long int (*function) PARAMS ((int, char *, int, long int, long int, long int, long int, int, int, int, void *)), void *arg); 29 extern int ar_name_equal PARAMS ((char *name, char *mem, int truncated)); 30 #ifndef VMS 31 extern int ar_member_touch PARAMS ((char *arname, char *memname)); 32 #endif 33 34 /* Return nonzero if NAME is an archive-member reference, zero if not. 35 An archive-member reference is a name like `lib(member)'. 36 If a name like `lib((entry))' is used, a fatal error is signaled at 37 the attempt to use this unsupported feature. */ 38 39 int 40 ar_name (char *name) 41 { 42 char *p = strchr (name, '('); 43 char *end; 44 45 if (p == 0 || p == name) 46 return 0; 47 48 end = p + strlen (p) - 1; 49 if (*end != ')') 50 return 0; 51 52 if (p[1] == '(' && end[-1] == ')') 53 fatal (NILF, _("attempt to use unsupported feature: `%s'"), name); 54 55 return 1; 56 } 57 58 59 /* Parse the archive-member reference NAME into the archive and member names. 60 Put the malloc'd archive name in *ARNAME_P if ARNAME_P is non-nil; 61 put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */ 62 63 void 64 ar_parse_name (char *name, char **arname_p, char **memname_p) 65 { 66 char *p = strchr (name, '('), *end = name + strlen (name) - 1; 67 68 if (arname_p != 0) 69 *arname_p = savestring (name, p - name); 70 71 if (memname_p != 0) 72 *memname_p = savestring (p + 1, end - (p + 1)); 73 } 74 75 static long int ar_member_date_1 PARAMS ((int desc, char *mem, int truncated, long int hdrpos, 77 long int datapos, long int size, long int date, int uid, int gid, int mode, void *arg)); 78 79 /* Return the modtime of NAME. */ 80 81 time_t 82 ar_member_date (char *name) 83 { 84 char *arname; 85 int arname_used = 0; 86 char *memname; 87 long int val; 88 89 ar_parse_name (name, &arname, &memname); 90 91 /* Make sure we know the modtime of the archive itself because we are 92 likely to be called just before commands to remake a member are run, 93 and they will change the archive itself. 94 95 But we must be careful not to enter_file the archive itself if it does 96 not exist, because pattern_search assumes that files found in the data 97 base exist or can be made. */ 98 { 99 struct file *arfile; 100 arfile = lookup_file (arname); 101 if (arfile == 0 && file_exists_p (arname)) 102 { 103 arfile = enter_file (arname); 104 arname_used = 1; 105 } 106 107 if (arfile != 0) 108 (void) f_mtime (arfile, 0); 109 } 110 111 val = ar_scan (arname, ar_member_date_1, memname); 112 113 if (!arname_used) 114 free (arname); 115 free (memname); 116 117 return (val <= 0 ? (time_t) -1 : (time_t) val); 118 } 119 120 /* This function is called by `ar_scan' to find which member to look at. */ 121 122 /* ARGSUSED */ 123 static long int 124 ar_member_date_1 (int desc UNUSED, char *mem, int truncated, 125 long int hdrpos UNUSED, long int datapos UNUSED, 126 long int size UNUSED, long int date, 127 int uid UNUSED, int gid UNUSED, int mode UNUSED, void *arg) 128 { 129 char *name = arg; 130 return ar_name_equal (name, mem, truncated) ? date : 0; 131 } 132 133 /* Set the archive-member NAME's modtime to now. */ 135 136 #ifdef VMS 137 int 138 ar_touch (char *name) 139 { 140 error (NILF, _("touch archive member is not available on VMS")); 141 return -1; 142 } 143 #else 144 int 145 ar_touch (char *name) 146 { 147 char *arname, *memname; 148 int arname_used = 0; 149 register int val; 150 151 ar_parse_name (name, &arname, &memname); 152 153 /* Make sure we know the modtime of the archive itself before we 154 touch the member, since this will change the archive itself. */ 155 { 156 struct file *arfile; 157 arfile = lookup_file (arname); 158 if (arfile == 0) 159 { 160 arfile = enter_file (arname); 161 arname_used = 1; 162 } 163 164 (void) f_mtime (arfile, 0); 165 } 166 167 val = 1; 168 switch (ar_member_touch (arname, memname)) 169 { 170 case -1: 171 error (NILF, _("touch: Archive `%s' does not exist"), arname); 172 break; 173 case -2: 174 error (NILF, _("touch: `%s' is not a valid archive"), arname); 175 break; 176 case -3: 177 perror_with_name ("touch: ", arname); 178 break; 179 case 1: 180 error (NILF, 181 _("touch: Member `%s' does not exist in `%s'"), memname, arname); 182 break; 183 case 0: 184 val = 0; 185 break; 186 default: 187 error (NILF, 188 _("touch: Bad return code from ar_member_touch on `%s'"), name); 189 } 190 191 if (!arname_used) 192 free (arname); 193 free (memname); 194 195 return val; 196 } 197 #endif /* !VMS */ 198 199 /* State of an `ar_glob' run, passed to `ar_glob_match'. */ 201 202 struct ar_glob_state 203 { 204 char *arname; 205 char *pattern; 206 unsigned int size; 207 struct nameseq *chain; 208 unsigned int n; 209 }; 210 211 /* This function is called by `ar_scan' to match one archive 212 element against the pattern in STATE. */ 213 214 static long int 215 ar_glob_match (int desc UNUSED, char *mem, int truncated UNUSED, 216 long int hdrpos UNUSED, long int datapos UNUSED, 217 long int size UNUSED, long int date UNUSED, int uid UNUSED, 218 int gid UNUSED, int mode UNUSED, void *arg) 219 { 220 struct ar_glob_state *state = arg; 221 222 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) 223 { 224 /* We have a match. Add it to the chain. */ 225 struct nameseq *new = (struct nameseq *) xmalloc (state->size); 226 new->name = concat (state->arname, mem, ")"); 227 new->next = state->chain; 228 state->chain = new; 229 ++state->n; 230 } 231 232 return 0L; 233 } 234 235 /* Return nonzero if PATTERN contains any metacharacters. 236 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ 237 static int 238 glob_pattern_p (const char *pattern, int quote) 239 { 240 const char *p; 241 int open = 0; 242 243 for (p = pattern; *p != '\0'; ++p) 244 switch (*p) 245 { 246 case '?': 247 case '*': 248 return 1; 249 250 case '\\': 251 if (quote) 252 ++p; 253 break; 254 255 case '[': 256 open = 1; 257 break; 258 259 case ']': 260 if (open) 261 return 1; 262 break; 263 } 264 265 return 0; 266 } 267 268 /* Glob for MEMBER_PATTERN in archive ARNAME. 269 Return a malloc'd chain of matching elements (or nil if none). */ 270 271 struct nameseq * 272 ar_glob (char *arname, char *member_pattern, unsigned int size) 273 { 274 struct ar_glob_state state; 275 char **names; 276 struct nameseq *n; 277 unsigned int i; 278 279 if (! glob_pattern_p (member_pattern, 1)) 280 return 0; 281 282 /* Scan the archive for matches. 283 ar_glob_match will accumulate them in STATE.chain. */ 284 i = strlen (arname); 285 state.arname = (char *) alloca (i + 2); 286 bcopy (arname, state.arname, i); 287 state.arname[i] = '('; 288 state.arname[i + 1] = '\0'; 289 state.pattern = member_pattern; 290 state.size = size; 291 state.chain = 0; 292 state.n = 0; 293 (void) ar_scan (arname, ar_glob_match, &state); 294 295 if (state.chain == 0) 296 return 0; 297 298 /* Now put the names into a vector for sorting. */ 299 names = (char **) alloca (state.n * sizeof (char *)); 300 i = 0; 301 for (n = state.chain; n != 0; n = n->next) 302 names[i++] = n->name; 303 304 /* Sort them alphabetically. */ 305 qsort ((char *) names, i, sizeof (*names), alpha_compare); 306 307 /* Put them back into the chain in the sorted order. */ 308 i = 0; 309 for (n = state.chain; n != 0; n = n->next) 310 n->name = names[i++]; 311 312 return state.chain; 313 } 314 315 #endif /* Not NO_ARCHIVES. */ 316