VirtualBox

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

Last change on this file since 2074 was 1993, checked in by bird, 16 years ago

Merged in current GNU Make code (CVS from 2008-10-28). Ref #55.

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1/* Interface to `ar' archives for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
31998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
4Foundation, Inc.
5This file is part of GNU Make.
6
7GNU Make is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 3 of the License, or (at your option) any later
10version.
11
12GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License along with
17this program. If not, see <http://www.gnu.org/licenses/>. */
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/* Return nonzero if NAME is an archive-member reference, zero if not.
28 An archive-member reference is a name like `lib(member)'.
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 != ')')
43 return 0;
44
45 if (p[1] == '(' && end[-1] == ')')
46 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, 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 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 error (NILF, _("touch: Archive `%s' does not exist"), arname);
150 break;
151 case -2:
152 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 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 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
178struct ar_glob_state
179 {
180 const char *arname;
181 const char *pattern;
182 unsigned int size;
183 struct nameseq *chain;
184 unsigned int n;
185 };
186
187/* This function is called by `ar_scan' to match one archive
188 element against the pattern in STATE. */
189
190static long int
191ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
192 long int hdrpos UNUSED, long int datapos UNUSED,
193 long int size UNUSED, long int date UNUSED, int uid UNUSED,
194 int gid UNUSED, int mode UNUSED, const void *arg)
195{
196 struct ar_glob_state *state = (struct ar_glob_state *)arg;
197
198 if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
199 {
200 /* We have a match. Add it to the chain. */
201 struct nameseq *new = xmalloc (state->size);
202 memset (new, '\0', state->size);
203 new->name = strcache_add (concat (state->arname, mem, ")"));
204 new->next = state->chain;
205 state->chain = new;
206 ++state->n;
207 }
208
209 return 0L;
210}
211
212/* Return nonzero if PATTERN contains any metacharacters.
213 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
214static int
215glob_pattern_p (const char *pattern, int quote)
216{
217 const char *p;
218 int open = 0;
219
220 for (p = pattern; *p != '\0'; ++p)
221 switch (*p)
222 {
223 case '?':
224 case '*':
225 return 1;
226
227 case '\\':
228 if (quote)
229 ++p;
230 break;
231
232 case '[':
233 open = 1;
234 break;
235
236 case ']':
237 if (open)
238 return 1;
239 break;
240 }
241
242 return 0;
243}
244
245/* Glob for MEMBER_PATTERN in archive ARNAME.
246 Return a malloc'd chain of matching elements (or nil if none). */
247
248struct nameseq *
249ar_glob (const char *arname, const char *member_pattern, unsigned int size)
250{
251 struct ar_glob_state state;
252 struct nameseq *n;
253 const char **names;
254 char *name;
255 unsigned int i;
256
257 if (! glob_pattern_p (member_pattern, 1))
258 return 0;
259
260 /* Scan the archive for matches.
261 ar_glob_match will accumulate them in STATE.chain. */
262 i = strlen (arname);
263 name = alloca (i + 2);
264 memcpy (name, arname, i);
265 name[i] = '(';
266 name[i + 1] = '\0';
267 state.arname = name;
268 state.pattern = member_pattern;
269 state.size = size;
270 state.chain = 0;
271 state.n = 0;
272 ar_scan (arname, ar_glob_match, &state);
273
274 if (state.chain == 0)
275 return 0;
276
277 /* Now put the names into a vector for sorting. */
278 names = alloca (state.n * sizeof (const char *));
279 i = 0;
280 for (n = state.chain; n != 0; n = n->next)
281 names[i++] = n->name;
282
283 /* Sort them alphabetically. */
284 qsort (names, i, sizeof (*names), alpha_compare);
285
286 /* Put them back into the chain in the sorted order. */
287 i = 0;
288 for (n = state.chain; n != 0; n = n->next)
289 n->name = names[i++];
290
291 return state.chain;
292}
293
294#endif /* Not NO_ARCHIVES. */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette