VirtualBox

source: kBuild/trunk/src/gmakenew/ar.c@ 903

Last change on this file since 903 was 903, checked in by bird, 18 years ago

Merged with the 2007-05-23 CVS. Added rsort and fixed a couple of windows build issues.

  • 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 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 2, or (at your option) any later version.
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
16GNU Make; see the file COPYING. If not, write to the Free Software
17Foundation, 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/* 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 new->name = strcache_add (concat (state->arname, mem, ")"));
203 new->next = state->chain;
204 state->chain = new;
205 ++state->n;
206 }
207
208 return 0L;
209}
210
211/* Return nonzero if PATTERN contains any metacharacters.
212 Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
213static int
214glob_pattern_p (const char *pattern, int quote)
215{
216 const char *p;
217 int open = 0;
218
219 for (p = pattern; *p != '\0'; ++p)
220 switch (*p)
221 {
222 case '?':
223 case '*':
224 return 1;
225
226 case '\\':
227 if (quote)
228 ++p;
229 break;
230
231 case '[':
232 open = 1;
233 break;
234
235 case ']':
236 if (open)
237 return 1;
238 break;
239 }
240
241 return 0;
242}
243
244/* Glob for MEMBER_PATTERN in archive ARNAME.
245 Return a malloc'd chain of matching elements (or nil if none). */
246
247struct nameseq *
248ar_glob (const char *arname, const char *member_pattern, unsigned int size)
249{
250 struct ar_glob_state state;
251 struct nameseq *n;
252 const char **names;
253 char *name;
254 unsigned int i;
255
256 if (! glob_pattern_p (member_pattern, 1))
257 return 0;
258
259 /* Scan the archive for matches.
260 ar_glob_match will accumulate them in STATE.chain. */
261 i = strlen (arname);
262 name = alloca (i + 2);
263 memcpy (name, arname, i);
264 name[i] = '(';
265 name[i + 1] = '\0';
266 state.arname = name;
267 state.pattern = member_pattern;
268 state.size = size;
269 state.chain = 0;
270 state.n = 0;
271 ar_scan (arname, ar_glob_match, &state);
272
273 if (state.chain == 0)
274 return 0;
275
276 /* Now put the names into a vector for sorting. */
277 names = alloca (state.n * sizeof (const char *));
278 i = 0;
279 for (n = state.chain; n != 0; n = n->next)
280 names[i++] = n->name;
281
282 /* Sort them alphabetically. */
283 qsort (names, i, sizeof (*names), alpha_compare);
284
285 /* Put them back into the chain in the sorted order. */
286 i = 0;
287 for (n = state.chain; n != 0; n = n->next)
288 n->name = names[i++];
289
290 return state.chain;
291}
292
293#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