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