source: trunk/third/gmake/ar.c @ 15972

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