root/trunk/freewrt/tools/gmake/ar.c

Revision 2223, 7.8 kB (checked in by tg, 5 years ago)

add some of the sources from GNU make 3.81
unchanged

Line 
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
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
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
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
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
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
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
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
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 *
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.  */
Note: See TracBrowser for help on using the browser.