Add some more unit tests for variable flavors.
[make.git] / ar.c
blob6715142b045ab7462d74e561e125113bd818adab
1 /* Interface to `ar' archives for GNU Make.
2 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1997,
3 2002 Free Software Foundation, Inc.
4 This file is part of GNU Make.
6 GNU Make is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Make is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Make; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include "make.h"
23 #ifndef NO_ARCHIVES
25 #include "filedef.h"
26 #include "dep.h"
27 #include <fnmatch.h>
29 /* Defined in arscan.c. */
30 extern long int ar_scan PARAMS ((char *archive, long int (*function) (), long int arg));
31 extern int ar_name_equal PARAMS ((char *name, char *mem, int truncated));
32 #ifndef VMS
33 extern int ar_member_touch PARAMS ((char *arname, char *memname));
34 #endif
36 /* Return nonzero if NAME is an archive-member reference, zero if not.
37 An archive-member reference is a name like `lib(member)'.
38 If a name like `lib((entry))' is used, a fatal error is signaled at
39 the attempt to use this unsupported feature. */
41 int
42 ar_name (char *name)
44 char *p = strchr (name, '(');
45 char *end;
47 if (p == 0 || p == name)
48 return 0;
50 end = p + strlen (p) - 1;
51 if (*end != ')')
52 return 0;
54 if (p[1] == '(' && end[-1] == ')')
55 fatal (NILF, _("attempt to use unsupported feature: `%s'"), name);
57 return 1;
61 /* Parse the archive-member reference NAME into the archive and member names.
62 Put the malloc'd archive name in *ARNAME_P if ARNAME_P is non-nil;
63 put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */
65 void
66 ar_parse_name (char *name, char **arname_p, char **memname_p)
68 char *p = strchr (name, '('), *end = name + strlen (name) - 1;
70 if (arname_p != 0)
71 *arname_p = savestring (name, p - name);
73 if (memname_p != 0)
74 *memname_p = savestring (p + 1, end - (p + 1));
77 static long int ar_member_date_1 PARAMS ((int desc, char *mem, int truncated, long int hdrpos,
78 long int datapos, long int size, long int date, int uid, int gid, int mode, char *name));
80 /* Return the modtime of NAME. */
82 time_t
83 ar_member_date (char *name)
85 char *arname;
86 int arname_used = 0;
87 char *memname;
88 long int val;
90 ar_parse_name (name, &arname, &memname);
92 /* Make sure we know the modtime of the archive itself because we are
93 likely to be called just before commands to remake a member are run,
94 and they will change the archive itself.
96 But we must be careful not to enter_file the archive itself if it does
97 not exist, because pattern_search assumes that files found in the data
98 base exist or can be made. */
100 struct file *arfile;
101 arfile = lookup_file (arname);
102 if (arfile == 0 && file_exists_p (arname))
104 arfile = enter_file (arname);
105 arname_used = 1;
108 if (arfile != 0)
109 (void) f_mtime (arfile, 0);
112 val = ar_scan (arname, ar_member_date_1, (long int) memname);
114 if (!arname_used)
115 free (arname);
116 free (memname);
118 return (val <= 0 ? (time_t) -1 : (time_t) val);
121 /* This function is called by `ar_scan' to find which member to look at. */
123 /* ARGSUSED */
124 static long int
125 ar_member_date_1 (int desc UNUSED, char *mem, int truncated,
126 long int hdrpos UNUSED, long int datapos UNUSED,
127 long int size UNUSED, long int date,
128 int uid UNUSED, int gid UNUSED, int mode UNUSED, char *name)
130 return ar_name_equal (name, mem, truncated) ? date : 0;
133 /* Set the archive-member NAME's modtime to now. */
135 #ifdef VMS
137 ar_touch (char *name)
139 error (NILF, _("touch archive member is not available on VMS"));
140 return -1;
142 #else
144 ar_touch (char *name)
146 char *arname, *memname;
147 int arname_used = 0;
148 register int val;
150 ar_parse_name (name, &arname, &memname);
152 /* Make sure we know the modtime of the archive itself before we
153 touch the member, since this will change the archive itself. */
155 struct file *arfile;
156 arfile = lookup_file (arname);
157 if (arfile == 0)
159 arfile = enter_file (arname);
160 arname_used = 1;
163 (void) f_mtime (arfile, 0);
166 val = 1;
167 switch (ar_member_touch (arname, memname))
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);
190 if (!arname_used)
191 free (arname);
192 free (memname);
194 return val;
196 #endif /* !VMS */
198 /* State of an `ar_glob' run, passed to `ar_glob_match'. */
200 struct ar_glob_state
202 char *arname;
203 char *pattern;
204 unsigned int size;
205 struct nameseq *chain;
206 unsigned int n;
209 /* This function is called by `ar_scan' to match one archive
210 element against the pattern in STATE. */
212 static long int
213 ar_glob_match (int desc UNUSED, char *mem, int truncated UNUSED,
214 long int hdrpos UNUSED, long int datapos UNUSED,
215 long int size UNUSED, long int date UNUSED, int uid UNUSED,
216 int gid UNUSED, int mode UNUSED, struct ar_glob_state *state)
218 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
220 /* We have a match. Add it to the chain. */
221 struct nameseq *new = (struct nameseq *) xmalloc (state->size);
222 new->name = concat (state->arname, mem, ")");
223 new->next = state->chain;
224 state->chain = new;
225 ++state->n;
228 return 0L;
231 /* Return nonzero if PATTERN contains any metacharacters.
232 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
233 static int
234 glob_pattern_p (const char *pattern, int quote)
236 const char *p;
237 int open = 0;
239 for (p = pattern; *p != '\0'; ++p)
240 switch (*p)
242 case '?':
243 case '*':
244 return 1;
246 case '\\':
247 if (quote)
248 ++p;
249 break;
251 case '[':
252 open = 1;
253 break;
255 case ']':
256 if (open)
257 return 1;
258 break;
261 return 0;
264 /* Glob for MEMBER_PATTERN in archive ARNAME.
265 Return a malloc'd chain of matching elements (or nil if none). */
267 struct nameseq *
268 ar_glob (char *arname, char *member_pattern, unsigned int size)
270 struct ar_glob_state state;
271 char **names;
272 struct nameseq *n;
273 unsigned int i;
275 if (! glob_pattern_p (member_pattern, 1))
276 return 0;
278 /* Scan the archive for matches.
279 ar_glob_match will accumulate them in STATE.chain. */
280 i = strlen (arname);
281 state.arname = (char *) alloca (i + 2);
282 bcopy (arname, state.arname, i);
283 state.arname[i] = '(';
284 state.arname[i + 1] = '\0';
285 state.pattern = member_pattern;
286 state.size = size;
287 state.chain = 0;
288 state.n = 0;
289 (void) ar_scan (arname, ar_glob_match, (long int) &state);
291 if (state.chain == 0)
292 return 0;
294 /* Now put the names into a vector for sorting. */
295 names = (char **) alloca (state.n * sizeof (char *));
296 i = 0;
297 for (n = state.chain; n != 0; n = n->next)
298 names[i++] = n->name;
300 /* Sort them alphabetically. */
301 qsort ((char *) names, i, sizeof (*names), alpha_compare);
303 /* Put them back into the chain in the sorted order. */
304 i = 0;
305 for (n = state.chain; n != 0; n = n->next)
306 n->name = names[i++];
308 return state.chain;
311 #endif /* Not NO_ARCHIVES. */