.
[make.git] / ar.c
blob117e11b4be4bebff795b0e9bac627ddcd60c7f98
1 /* Interface to `ar' archives for GNU Make.
2 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3 This file is part of GNU Make.
5 GNU Make is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 GNU Make is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU Make; see the file COPYING. If not, write to
17 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19 #include "make.h"
21 #ifndef NO_ARCHIVES
23 #include "filedef.h"
24 #include "dep.h"
25 #include <fnmatch.h>
27 /* Defined in arscan.c. */
28 extern long int ar_scan PARAMS ((char *archive, long int (*function) (), long int arg));
29 extern int ar_member_touch PARAMS ((char *arname, char *memname));
30 extern int ar_name_equal PARAMS ((char *name, char *mem, int truncated));
33 /* Return nonzero if NAME is an archive-member reference, zero if not.
34 An archive-member reference is a name like `lib(member)'.
35 If a name like `lib((entry))' is used, a fatal error is signaled at
36 the attempt to use this unsupported feature. */
38 int
39 ar_name (name)
40 char *name;
42 char *p = index (name, '('), *end = name + strlen (name) - 1;
44 if (p == 0 || p == name || *end != ')')
45 return 0;
47 if (p[1] == '(' && end[-1] == ')')
48 fatal ("attempt to use unsupported feature: `%s'", name);
50 return 1;
54 /* Parse the archive-member reference NAME into the archive and member names.
55 Put the malloc'd archive name in *ARNAME_P if ARNAME_P is non-nil;
56 put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */
58 void
59 ar_parse_name (name, arname_p, memname_p)
60 char *name, **arname_p, **memname_p;
62 char *p = index (name, '('), *end = name + strlen (name) - 1;
64 if (arname_p != 0)
65 *arname_p = savestring (name, p - name);
67 if (memname_p != 0)
68 *memname_p = savestring (p + 1, end - (p + 1));
71 #ifdef VMS
72 #include <lbrdef.h>
73 #include <mhddef.h>
74 #include <credef.h>
75 #include <descrip.h>
76 #include <ctype.h>
77 #if __DECC
78 #include <lbr$routines.h>
79 #endif
81 #define uppercasify(str) {char *str1; for (str1 = str; *str1; str1++) *str1 = _toupper(*str1);}
83 #define LBR$_KEYNOTFND 2527330 /* This isn't in any .h file anywhere so I got it from a MACRO library */
85 time_t
86 ar_member_date (name)
87 char *name;
89 static char *arname;
90 static char *memname;
91 char *p,*q;
92 long int val;
93 static struct {
94 struct mhddef mhd;
95 struct credef cre;
96 char garbage[256];
97 } buf;
98 int func=LBR$C_READ,
99 type=LBR$C_TYP_OBJ,
100 rfa[2],
101 lidx,
102 status;
103 $DESCRIPTOR(bufdesc,(char *)&buf);
104 $DESCRIPTOR(libdesc,arname);
105 $DESCRIPTOR(moddesc,memname);
107 /* This "file" is an archive member. */
108 p = index (name, '(');
109 arname = savestring (name, p - name);
110 val = strlen (p) - 2;
112 if (val > 15)
113 val = 15;
115 memname = savestring (p + 1, val);
116 #ifdef OLDWAY
117 p = rindex (memname, ')');
118 if (p != 0) {
119 q = rindex(p,'.');
120 if (q)
121 *q = '\0'; /* to get rid of extension */
123 #endif
125 q = rindex(memname,'.');
126 if (q)
127 *q = '\0'; /* to get rid of extension */
129 uppercasify(memname);
131 /* Make sure we know the modtime of the archive itself because
132 we are likely to be called just before commands to remake a
133 member are run, and they will change the archive itself. */
134 (void) f_mtime (enter_file (arname));
136 libdesc.dsc$a_pointer = arname;
137 libdesc.dsc$w_length = strlen(arname);
138 moddesc.dsc$a_pointer = memname;
139 moddesc.dsc$w_length = strlen(memname);
141 if (!((status = lbr$ini_control(&lidx,&func,&type,0)) & 1)) {
142 printf("Error in lbr$ini_control, %d\n",status);
143 return(-1);
146 if (!((status = lbr$open(&lidx,&libdesc,0,0,0,0,0)) & 1)) {
147 printf("Error opening library %s to lookup member %s, %d\n",arname, memname ,status);
148 return(-1);
151 if (!((status = lbr$lookup_key(&lidx,&moddesc,rfa)) & 1)) {
152 if (status != LBR$_KEYNOTFND)
153 printf("Error looking up module %s in library %s, %d\n",memname, arname ,status);
154 lbr$close(&lidx);
155 return(-1);
158 if (!((status = lbr$set_module(&lidx,rfa,&bufdesc,&bufdesc,0)) & 1)) {
159 printf("Error getting module info, %d\n",status);
160 lbr$close(&lidx);
161 return(-1);
164 lbr$close(&lidx);
166 val = SHELL$FIX_TIME(&buf.mhd.mhd$l_datim);
168 free (arname);
169 free (memname);
170 return (val <= 0 ? (time_t) -1 : (time_t) val);
173 #else
175 static long int ar_member_date_1 PARAMS ((int desc, char *mem, int truncated, long int hdrpos,
176 long int datapos, long int size, long int date, int uid, int gid, int mode, char *name));
178 /* Return the modtime of NAME. */
180 time_t
181 ar_member_date (name)
182 char *name;
184 char *arname;
185 int arname_used = 0;
186 char *memname;
187 long int val;
189 ar_parse_name (name, &arname, &memname);
191 /* Make sure we know the modtime of the archive itself because we are
192 likely to be called just before commands to remake a member are run,
193 and they will change the archive itself.
195 But we must be careful not to enter_file the archive itself if it does
196 not exist, because pattern_search assumes that files found in the data
197 base exist or can be made. */
199 struct file *arfile;
200 arfile = lookup_file (arname);
201 if (arfile == 0 && file_exists_p (arname))
203 arfile = enter_file (arname);
204 arname_used = 1;
207 if (arfile != 0)
208 (void) f_mtime (arfile, 0);
211 val = ar_scan (arname, ar_member_date_1, (long int) memname);
213 if (!arname_used)
214 free (arname);
215 free (memname);
217 return (val <= 0 ? (time_t) -1 : (time_t) val);
220 /* This function is called by `ar_scan' to find which member to look at. */
222 /* ARGSUSED */
223 static long int
224 ar_member_date_1 (desc, mem, truncated,
225 hdrpos, datapos, size, date, uid, gid, mode, name)
226 int desc;
227 char *mem;
228 int truncated;
229 long int hdrpos, datapos, size, date;
230 int uid, gid, mode;
231 char *name;
233 return ar_name_equal (name, mem, truncated) ? date : 0;
235 #endif /* !VMS */
237 /* Set the archive-member NAME's modtime to now. */
239 #ifdef VMS
241 ar_touch (name)
242 char *name;
244 error ("touch archive member is not available on VMS");
245 return -1;
247 #else
249 ar_touch (name)
250 char *name;
252 char *arname, *memname;
253 int arname_used = 0;
254 register int val;
256 ar_parse_name (name, &arname, &memname);
258 /* Make sure we know the modtime of the archive itself before we
259 touch the member, since this will change the archive itself. */
261 struct file *arfile;
262 arfile = lookup_file (arname);
263 if (arfile == 0)
265 arfile = enter_file (arname);
266 arname_used = 1;
269 (void) f_mtime (arfile, 0);
272 val = 1;
273 switch (ar_member_touch (arname, memname))
275 case -1:
276 error ("touch: Archive `%s' does not exist", arname);
277 break;
278 case -2:
279 error ("touch: `%s' is not a valid archive", arname);
280 break;
281 case -3:
282 perror_with_name ("touch: ", arname);
283 break;
284 case 1:
285 error ("touch: Member `%s' does not exist in `%s'", memname, arname);
286 break;
287 case 0:
288 val = 0;
289 break;
290 default:
291 error ("touch: Bad return code from ar_member_touch on `%s'", name);
294 if (!arname_used)
295 free (arname);
296 free (memname);
298 return val;
300 #endif /* !VMS */
302 /* State of an `ar_glob' run, passed to `ar_glob_match'. */
304 struct ar_glob_state
306 char *arname;
307 char *pattern;
308 unsigned int size;
309 struct nameseq *chain;
310 unsigned int n;
313 /* This function is called by `ar_scan' to match one archive
314 element against the pattern in STATE. */
316 static long int
317 ar_glob_match (desc, mem, truncated,
318 hdrpos, datapos, size, date, uid, gid, mode,
319 state)
320 int desc;
321 char *mem;
322 int truncated;
323 long int hdrpos, datapos, size, date;
324 int uid, gid, mode;
325 struct ar_glob_state *state;
327 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
329 /* We have a match. Add it to the chain. */
330 struct nameseq *new = (struct nameseq *) xmalloc (state->size);
331 new->name = concat (state->arname, mem, ")");
332 new->next = state->chain;
333 state->chain = new;
334 ++state->n;
337 return 0L;
340 /* Alphabetic sorting function for `qsort'. */
342 static int
343 ar_glob_alphacompare (a, b)
344 char **a, **b;
346 return strcmp (*a, *b);
349 /* Return nonzero if PATTERN contains any metacharacters.
350 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
351 static int
352 glob_pattern_p (pattern, quote)
353 const char *pattern;
354 const int quote;
356 register const char *p;
357 int open = 0;
359 for (p = pattern; *p != '\0'; ++p)
360 switch (*p)
362 case '?':
363 case '*':
364 return 1;
366 case '\\':
367 if (quote)
368 ++p;
369 break;
371 case '[':
372 open = 1;
373 break;
375 case ']':
376 if (open)
377 return 1;
378 break;
381 return 0;
384 /* Glob for MEMBER_PATTERN in archive ARNAME.
385 Return a malloc'd chain of matching elements (or nil if none). */
387 struct nameseq *
388 ar_glob (arname, member_pattern, size)
389 char *arname, *member_pattern;
390 unsigned int size;
392 struct ar_glob_state state;
393 char **names;
394 struct nameseq *n;
395 unsigned int i;
397 if (! glob_pattern_p (member_pattern, 1))
398 return 0;
400 /* Scan the archive for matches.
401 ar_glob_match will accumulate them in STATE.chain. */
402 i = strlen (arname);
403 state.arname = (char *) alloca (i + 2);
404 bcopy (arname, state.arname, i);
405 state.arname[i] = '(';
406 state.arname[i + 1] = '\0';
407 state.pattern = member_pattern;
408 state.size = size;
409 state.chain = 0;
410 state.n = 0;
411 (void) ar_scan (arname, ar_glob_match, (long int) &state);
413 if (state.chain == 0)
414 return 0;
416 /* Now put the names into a vector for sorting. */
417 names = (char **) alloca (state.n * sizeof (char *));
418 i = 0;
419 for (n = state.chain; n != 0; n = n->next)
420 names[i++] = n->name;
422 /* Sort them alphabetically. */
423 qsort ((char *) names, i, sizeof (*names), ar_glob_alphacompare);
425 /* Put them back into the chain in the sorted order. */
426 i = 0;
427 for (n = state.chain; n != 0; n = n->next)
428 n->name = names[i++];
430 return state.chain;
433 #endif /* Not NO_ARCHIVES. */