Formerly rule.h.~5~
[make.git] / ar.c
blob29ee43b79a10c07bce79694336856e754bf01f8a
1 /* Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993
2 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 "file.h"
24 #include "dep.h"
25 #include <fnmatch.h>
27 /* Defined in arscan.c. */
28 extern long int ar_scan ();
29 extern int ar_member_touch ();
30 extern int ar_name_equal ();
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 static long int ar_member_date_1 ();
73 /* Return the modtime of NAME. */
75 time_t
76 ar_member_date (name)
77 char *name;
79 char *arname;
80 int arname_used = 0;
81 char *memname;
82 long int val;
84 ar_parse_name (name, &arname, &memname);
86 /* Make sure we know the modtime of the archive itself because
87 we are likely to be called just before commands to remake a
88 member are run, and they will change the archive itself. */
90 struct file *arfile;
91 arfile = lookup_file (arname);
92 if (arfile == 0)
94 arfile = enter_file (arname);
95 arname_used = 1;
98 (void) f_mtime (arfile, 0);
101 val = ar_scan (arname, ar_member_date_1, (long int) memname);
103 if (!arname_used)
104 free (arname);
105 free (memname);
107 return (val <= 0 ? (time_t) -1 : (time_t) val);
110 /* This function is called by `ar_scan' to find which member to look at. */
112 /* ARGSUSED */
113 static long int
114 ar_member_date_1 (desc, mem, truncated,
115 hdrpos, datapos, size, date, uid, gid, mode, name)
116 int desc;
117 char *mem;
118 int truncated;
119 long int hdrpos, datapos, size, date;
120 int uid, gid, mode;
121 char *name;
123 return ar_name_equal (name, mem, truncated) ? date : 0;
126 /* Set the archive-member NAME's modtime to now. */
129 ar_touch (name)
130 char *name;
132 char *arname, *memname;
133 int arname_used = 0;
134 register int val;
136 ar_parse_name (name, &arname, &memname);
138 /* Make sure we know the modtime of the archive itself before we
139 touch the member, since this will change the archive itself. */
141 struct file *arfile;
142 arfile = lookup_file (arname);
143 if (arfile == 0)
145 arfile = enter_file (arname);
146 arname_used = 1;
149 (void) f_mtime (arfile, 0);
152 val = 1;
153 switch (ar_member_touch (arname, memname))
155 case -1:
156 error ("touch: Archive `%s' does not exist", arname);
157 break;
158 case -2:
159 error ("touch: `%s' is not a valid archive", arname);
160 break;
161 case -3:
162 perror_with_name ("touch: ", arname);
163 break;
164 case 1:
165 error ("touch: Member `%s' does not exist in `%s'", memname, arname);
166 break;
167 case 0:
168 val = 0;
169 break;
170 default:
171 error ("touch: Bad return code from ar_member_touch on `%s'", name);
174 if (!arname_used)
175 free (arname);
176 free (memname);
178 return val;
181 /* State of an `ar_glob' run, passed to `ar_glob_match'. */
183 struct ar_glob_state
185 char *arname;
186 char *pattern;
187 unsigned int size;
188 struct nameseq *chain;
189 unsigned int n;
192 /* This function is called by `ar_scan' to match one archive
193 element against the pattern in STATE. */
195 static long int
196 ar_glob_match (desc, mem, truncated,
197 hdrpos, datapos, size, date, uid, gid, mode,
198 state)
199 int desc;
200 char *mem;
201 int truncated;
202 long int hdrpos, datapos, size, date;
203 int uid, gid, mode;
204 struct ar_glob_state *state;
206 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
208 /* We have a match. Add it to the chain. */
209 struct nameseq *new = (struct nameseq *) xmalloc (state->size);
210 new->name = concat (state->arname, mem, ")");
211 new->next = state->chain;
212 state->chain = new;
213 ++state->n;
216 return 0L;
219 /* Alphabetic sorting function for `qsort'. */
221 static int
222 ar_glob_alphacompare (a, b)
223 char **a, **b;
225 return strcmp (*a, *b);
228 /* Return nonzero if PATTERN contains any metacharacters.
229 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
230 static int
231 glob_pattern_p (pattern, quote)
232 const char *pattern;
233 const int quote;
235 register const char *p;
236 int open = 0;
238 for (p = pattern; *p != '\0'; ++p)
239 switch (*p)
241 case '?':
242 case '*':
243 return 1;
245 case '\\':
246 if (quote)
247 ++p;
248 break;
250 case '[':
251 open = 1;
252 break;
254 case ']':
255 if (open)
256 return 1;
257 break;
260 return 0;
263 /* Glob for MEMBER_PATTERN in archive ARNAME.
264 Return a malloc'd chain of matching elements (or nil if none). */
266 struct nameseq *
267 ar_glob (arname, member_pattern, size)
268 char *arname, *member_pattern;
269 unsigned int size;
271 struct ar_glob_state state;
272 char **names;
273 struct nameseq *n;
274 unsigned int i;
276 if (! glob_pattern_p (member_pattern, 1))
277 return 0;
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, (long int) &state);
292 if (state.chain == 0)
293 return 0;
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;
301 /* Sort them alphabetically. */
302 qsort ((char *) names, i, sizeof (*names), ar_glob_alphacompare);
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++];
309 return state.chain;
312 #endif /* Not NO_ARCHIVES. */