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 PARAMS ((char *archive, long int (*function) (), intptr_t 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, char *name)); 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, (intptr_t) 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, char *name) 128 { 129 return ar_name_equal (name, mem, truncated) ? date : 0; 130 } 131 132 /* Set the archive-member NAME's modtime to now. */ 134 135 #ifdef VMS 136 int 137 ar_touch (char *name) 138 { 139 error (NILF, _("touch archive member is not available on VMS")); 140 return -1; 141 } 142 #else 143 int 144 ar_touch (char *name) 145 { 146 char *arname, *memname; 147 int arname_used = 0; 148 register int val; 149 150 ar_parse_name (name, &arname, &memname); 151 152 /* Make sure we know the modtime of the archive itself before we 153 touch the member, since this will change the archive itself. */ 154 { 155 struct file *arfile; 156 arfile = lookup_file (arname); 157 if (arfile == 0) 158 { 159 arfile = enter_file (arname); 160 arname_used = 1; 161 } 162 163 (void) f_mtime (arfile, 0); 164 } 165 166 val = 1; 167 switch (ar_member_touch (arname, memname)) 168 { 169 case -1: 170 error (NILF, _("touch: Archive `%s' does not exist"), arname); 171 break; 172 case -2: 173 error (NILF, _("touch: `%s' is not a valid archive"), arname); 174 break; 175 case -3: 176 perror_with_name ("touch: ", arname); 177 break; 178 case 1: 179 error (NILF, 180 _("touch: Member `%s' does not exist in `%s'"), memname, arname); 181 break; 182 case 0: 183 val = 0; 184 break; 185 default: 186 error (NILF, 187 _("touch: Bad return code from ar_member_touch on `%s'"), name); 188 } 189 190 if (!arname_used) 191 free (arname); 192 free (memname); 193 194 return val; 195 } 196 #endif /* !VMS */ 197 198 /* State of an `ar_glob' run, passed to `ar_glob_match'. */ 200 201 struct ar_glob_state 202 { 203 char *arname; 204 char *pattern; 205 unsigned int size; 206 struct nameseq *chain; 207 unsigned int n; 208 }; 209 210 /* This function is called by `ar_scan' to match one archive 211 element against the pattern in STATE. */ 212 213 static long int 214 ar_glob_match (int desc UNUSED, char *mem, int truncated UNUSED, 215 long int hdrpos UNUSED, long int datapos UNUSED, 216 long int size UNUSED, long int date UNUSED, int uid UNUSED, 217 int gid UNUSED, int mode UNUSED, struct ar_glob_state *state) 218 { 219 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) 220 { 221 /* We have a match. Add it to the chain. */ 222 struct nameseq *new = (struct nameseq *) xmalloc (state->size); 223 new->name = concat (state->arname, mem, ")"); 224 new->next = state->chain; 225 state->chain = new; 226 ++state->n; 227 } 228 229 return 0L; 230 } 231 232 /* Return nonzero if PATTERN contains any metacharacters. 233 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ 234 static int 235 glob_pattern_p (const char *pattern, int quote) 236 { 237 const char *p; 238 int open = 0; 239 240 for (p = pattern; *p != '\0'; ++p) 241 switch (*p) 242 { 243 case '?': 244 case '*': 245 return 1; 246 247 case '\\': 248 if (quote) 249 ++p; 250 break; 251 252 case '[': 253 open = 1; 254 break; 255 256 case ']': 257 if (open) 258 return 1; 259 break; 260 } 261 262 return 0; 263 } 264 265 /* Glob for MEMBER_PATTERN in archive ARNAME. 266 Return a malloc'd chain of matching elements (or nil if none). */ 267 268 struct nameseq * 269 ar_glob (char *arname, char *member_pattern, unsigned int size) 270 { 271 struct ar_glob_state state; 272 char **names; 273 struct nameseq *n; 274 unsigned int i; 275 276 if (! glob_pattern_p (member_pattern, 1)) 277 return 0; 278 279 /* Scan the archive for matches. 280 ar_glob_match will accumulate them in STATE.chain. */ 281 i = strlen (arname); 282 state.arname = (char *) alloca (i + 2); 283 bcopy (arname, state.arname, i); 284 state.arname[i] = '('; 285 state.arname[i + 1] = '\0'; 286 state.pattern = member_pattern; 287 state.size = size; 288 state.chain = 0; 289 state.n = 0; 290 (void) ar_scan (arname, ar_glob_match, (intptr_t) &state); 291 292 if (state.chain == 0) 293 return 0; 294 295 /* Now put the names into a vector for sorting. */ 296 names = (char **) alloca (state.n * sizeof (char *)); 297 i = 0; 298 for (n = state.chain; n != 0; n = n->next) 299 names[i++] = n->name; 300 301 /* Sort them alphabetically. */ 302 qsort ((char *) names, i, sizeof (*names), alpha_compare); 303 304 /* Put them back into the chain in the sorted order. */ 305 i = 0; 306 for (n = state.chain; n != 0; n = n->next) 307 n->name = names[i++]; 308 309 return state.chain; 310 } 311 312 #endif /* Not NO_ARCHIVES. */ 313