VirtualBox

source: kBuild/trunk/src/kmk/ar.c@ 3387

Last change on this file since 3387 was 3140, checked in by bird, 6 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1/* Interface to 'ar' archives for GNU Make.
2Copyright (C) 1988-2016 Free Software Foundation, Inc.
3
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify it under the
7terms of the GNU General Public License as published by the Free Software
8Foundation; either version 3 of the License, or (at your option) any later
9version.
10
11GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#include "makeint.h"
19
20#ifndef NO_ARCHIVES
21
22#include "filedef.h"
23#include "dep.h"
24#include <fnmatch.h>
25
26/* Return nonzero if NAME is an archive-member reference, zero if not. An
27 archive-member reference is a name like 'lib(member)' where member is a
28 non-empty string.
29 If a name like 'lib((entry))' is used, a fatal error is signaled at
30 the attempt to use this unsupported feature. */
31
32int
33ar_name (const char *name)
34{
35 const char *p = strchr (name, '(');
36 const char *end;
37
38 if (p == 0 || p == name)
39 return 0;
40
41 end = p + strlen (p) - 1;
42 if (*end != ')' || end == p + 1)
43 return 0;
44
45 if (p[1] == '(' && end[-1] == ')')
46 OS (fatal, NILF, _("attempt to use unsupported feature: '%s'"), name);
47
48 return 1;
49}
50
51
52/* Parse the archive-member reference NAME into the archive and member names.
53 Creates one allocated string containing both names, pointed to by ARNAME_P.
54 MEMNAME_P points to the member. */
55
56void
57ar_parse_name (const char *name, char **arname_p, char **memname_p)
58{
59 char *p;
60
61 *arname_p = xstrdup (name);
62 p = strchr (*arname_p, '(');
63 *(p++) = '\0';
64 p[strlen (p) - 1] = '\0';
65 *memname_p = p;
66}
67
68
69
70/* This function is called by 'ar_scan' to find which member to look at. */
71
72/* ARGSUSED */
73static long int
74ar_member_date_1 (int desc UNUSED, const char *mem, int truncated,
75 long int hdrpos UNUSED, long int datapos UNUSED,
76 long int size UNUSED, long int date,
77 int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED,
78 const void *name)
79{
80 return ar_name_equal (name, mem, truncated) ? date : 0;
81}
82
83/* Return the modtime of NAME. */
84
85time_t
86ar_member_date (const char *name)
87{
88 char *arname;
89 char *memname;
90 long int val;
91
92 ar_parse_name (name, &arname, &memname);
93
94 /* Make sure we know the modtime of the archive itself because we are
95 likely to be called just before commands to remake a member are run,
96 and they will change the archive itself.
97
98 But we must be careful not to enter_file the archive itself if it does
99 not exist, because pattern_search assumes that files found in the data
100 base exist or can be made. */
101 {
102 struct file *arfile;
103 arfile = lookup_file (arname);
104 if (arfile == 0 && file_exists_p (arname))
105 arfile = enter_file (strcache_add (arname));
106
107 if (arfile != 0)
108 (void) f_mtime (arfile, 0);
109 }
110
111 val = ar_scan (arname, ar_member_date_1, memname);
112
113 free (arname);
114
115 return (val <= 0 ? (time_t) -1 : (time_t) val);
116}
117
118
119/* Set the archive-member NAME's modtime to now. */
120
121#ifdef VMS
122int
123ar_touch (const char *name)
124{
125 O (error, NILF, _("touch archive member is not available on VMS"));
126 return -1;
127}
128#else
129int
130ar_touch (const char *name)
131{
132 char *arname, *memname;
133 int val;
134
135 ar_parse_name (name, &arname, &memname);
136
137 /* Make sure we know the modtime of the archive itself before we
138 touch the member, since this will change the archive modtime. */
139 {
140 struct file *arfile;
141 arfile = enter_file (strcache_add (arname));
142 f_mtime (arfile, 0);
143 }
144
145 val = 1;
146 switch (ar_member_touch (arname, memname))
147 {
148 case -1:
149 OS (error, NILF, _("touch: Archive '%s' does not exist"), arname);
150 break;
151 case -2:
152 OS (error, NILF, _("touch: '%s' is not a valid archive"), arname);
153 break;
154 case -3:
155 perror_with_name ("touch: ", arname);
156 break;
157 case 1:
158 OSS (error, NILF,
159 _("touch: Member '%s' does not exist in '%s'"), memname, arname);
160 break;
161 case 0:
162 val = 0;
163 break;
164 default:
165 OS (error, NILF,
166 _("touch: Bad return code from ar_member_touch on '%s'"), name);
167 }
168
169 free (arname);
170
171 return val;
172}
173#endif /* !VMS */
174
175
176/* State of an 'ar_glob' run, passed to 'ar_glob_match'. */
177
178/* On VMS, (object) modules in libraries do not have suffixes. That is, to
179 find a match for a pattern, the pattern must not have any suffix. So the
180 suffix of the pattern is saved and the pattern is stripped (ar_glob).
181 If there is a match and the match, which is a module name, is added to
182 the chain, the saved suffix is added back to construct a source filename
183 (ar_glob_match). */
184
185struct ar_glob_state
186 {
187 const char *arname;
188 const char *pattern;
189#ifdef VMS
190 char *suffix;
191#endif
192 unsigned int size;
193 struct nameseq *chain;
194 unsigned int n;
195 };
196
197/* This function is called by 'ar_scan' to match one archive
198 element against the pattern in STATE. */
199
200static long int
201ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
202 long int hdrpos UNUSED, long int datapos UNUSED,
203 long int size UNUSED, long int date UNUSED, int uid UNUSED,
204 int gid UNUSED, unsigned int mode UNUSED, const void *arg)
205{
206 struct ar_glob_state *state = (struct ar_glob_state *)arg;
207
208 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
209 {
210 /* We have a match. Add it to the chain. */
211 struct nameseq *new = xcalloc (state->size);
212#ifdef VMS
213 if (state->suffix)
214 new->name = strcache_add(
215 concat(5, state->arname, "(", mem, state->suffix, ")"));
216 else
217#endif
218 new->name = strcache_add(concat(4, state->arname, "(", mem, ")"));
219 new->next = state->chain;
220 state->chain = new;
221 ++state->n;
222 }
223
224 return 0L;
225}
226
227/* Return nonzero if PATTERN contains any metacharacters.
228 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
229static int
230ar_glob_pattern_p (const char *pattern, int quote)
231{
232 const char *p;
233 int opened = 0;
234
235 for (p = pattern; *p != '\0'; ++p)
236 switch (*p)
237 {
238 case '?':
239 case '*':
240 return 1;
241
242 case '\\':
243 if (quote)
244 ++p;
245 break;
246
247 case '[':
248 opened = 1;
249 break;
250
251 case ']':
252 if (opened)
253 return 1;
254 break;
255 }
256
257 return 0;
258}
259
260/* Glob for MEMBER_PATTERN in archive ARNAME.
261 Return a malloc'd chain of matching elements (or nil if none). */
262
263struct nameseq *
264ar_glob (const char *arname, const char *member_pattern, unsigned int size)
265{
266 struct ar_glob_state state;
267 struct nameseq *n;
268 const char **names;
269 unsigned int i;
270#ifdef VMS
271 char *vms_member_pattern;
272#endif
273 if (! ar_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 state.arname = arname;
279 state.pattern = member_pattern;
280#ifdef VMS
281 {
282 /* In a copy of the pattern, find the suffix, save it and remove it from
283 the pattern */
284 char *lastdot;
285 vms_member_pattern = xstrdup(member_pattern);
286 lastdot = strrchr(vms_member_pattern, '.');
287 state.suffix = lastdot;
288 if (lastdot)
289 {
290 state.suffix = xstrdup(lastdot);
291 *lastdot = 0;
292 }
293 state.pattern = vms_member_pattern;
294 }
295#endif
296 state.size = size;
297 state.chain = 0;
298 state.n = 0;
299 ar_scan (arname, ar_glob_match, &state);
300
301#ifdef VMS
302 /* Deallocate any duplicated string */
303 free(vms_member_pattern);
304 if (state.suffix)
305 {
306 free(state.suffix);
307 }
308#endif
309
310 if (state.chain == 0)
311 return 0;
312
313 /* Now put the names into a vector for sorting. */
314 names = alloca (state.n * sizeof (const char *));
315 i = 0;
316 for (n = state.chain; n != 0; n = n->next)
317 names[i++] = n->name;
318
319 /* Sort them alphabetically. */
320 /* MSVC erroneously warns without a cast here. */
321 qsort ((void *)names, i, sizeof (*names), alpha_compare);
322
323 /* Put them back into the chain in the sorted order. */
324 i = 0;
325 for (n = state.chain; n != 0; n = n->next)
326 n->name = names[i++];
327
328 return state.chain;
329}
330
331#endif /* Not NO_ARCHIVES. */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use