95dcbbbe26da21808dae9e255ad7ba9cad35ee32
[platform/upstream/make.git] / ar.c
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, 2007, 2008, 2009,
4 2010 Free Software Foundation, Inc.
5
6 This file is part of GNU Make.
7
8 GNU Make is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 3 of the License, or (at your option) any later
11 version.
12
13 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 this program.  If not, see <http://www.gnu.org/licenses/>.  */
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 /* Return nonzero if NAME is an archive-member reference, zero if not.  An
29    archive-member reference is a name like `lib(member)' where member is a
30    non-empty string.
31    If a name like `lib((entry))' is used, a fatal error is signaled at
32    the attempt to use this unsupported feature.  */
33
34 int
35 ar_name (const char *name)
36 {
37   const char *p = strchr (name, '(');
38   const char *end;
39
40   if (p == 0 || p == name)
41     return 0;
42
43   end = p + strlen (p) - 1;
44   if (*end != ')' || end == p + 1)
45     return 0;
46
47   if (p[1] == '(' && end[-1] == ')')
48     fatal (NILF, _("attempt to use unsupported feature: `%s'"), name);
49
50   return 1;
51 }
52
53
54 /* Parse the archive-member reference NAME into the archive and member names.
55    Creates one allocated string containing both names, pointed to by ARNAME_P.
56    MEMNAME_P points to the member.  */
57
58 void
59 ar_parse_name (const char *name, char **arname_p, char **memname_p)
60 {
61   char *p;
62
63   *arname_p = xstrdup (name);
64   p = strchr (*arname_p, '(');
65   *(p++) = '\0';
66   p[strlen(p) - 1] = '\0';
67   *memname_p = p;
68 }
69 \f
70
71 /* This function is called by `ar_scan' to find which member to look at.  */
72
73 /* ARGSUSED */
74 static long int
75 ar_member_date_1 (int desc UNUSED, const char *mem, int truncated,
76                   long int hdrpos UNUSED, long int datapos UNUSED,
77                   long int size UNUSED, long int date,
78                   int uid UNUSED, int gid UNUSED, int mode UNUSED,
79                   const void *name)
80 {
81   return ar_name_equal (name, mem, truncated) ? date : 0;
82 }
83
84 /* Return the modtime of NAME.  */
85
86 time_t
87 ar_member_date (const char *name)
88 {
89   char *arname;
90   char *memname;
91   long int val;
92
93   ar_parse_name (name, &arname, &memname);
94
95   /* Make sure we know the modtime of the archive itself because we are
96      likely to be called just before commands to remake a member are run,
97      and they will change the archive itself.
98
99      But we must be careful not to enter_file the archive itself if it does
100      not exist, because pattern_search assumes that files found in the data
101      base exist or can be made.  */
102   {
103     struct file *arfile;
104     arfile = lookup_file (arname);
105     if (arfile == 0 && file_exists_p (arname))
106       arfile = enter_file (strcache_add (arname));
107
108     if (arfile != 0)
109       (void) f_mtime (arfile, 0);
110   }
111
112   val = ar_scan (arname, ar_member_date_1, memname);
113
114   free (arname);
115
116   return (val <= 0 ? (time_t) -1 : (time_t) val);
117 }
118 \f
119 /* Set the archive-member NAME's modtime to now.  */
120
121 #ifdef VMS
122 int
123 ar_touch (const char *name)
124 {
125   error (NILF, _("touch archive member is not available on VMS"));
126   return -1;
127 }
128 #else
129 int
130 ar_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 \f
175 /* State of an `ar_glob' run, passed to `ar_glob_match'.  */
176
177 struct ar_glob_state
178   {
179     const char *arname;
180     const char *pattern;
181     unsigned int size;
182     struct nameseq *chain;
183     unsigned int n;
184   };
185
186 /* This function is called by `ar_scan' to match one archive
187    element against the pattern in STATE.  */
188
189 static long int
190 ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
191                long int hdrpos UNUSED, long int datapos UNUSED,
192                long int size UNUSED, long int date UNUSED, int uid UNUSED,
193                int gid UNUSED, int mode UNUSED, const void *arg)
194 {
195   struct ar_glob_state *state = (struct ar_glob_state *)arg;
196
197   if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
198     {
199       /* We have a match.  Add it to the chain.  */
200       struct nameseq *new = xcalloc (state->size);
201       new->name = strcache_add (concat (4, state->arname, "(", mem, ")"));
202       new->next = state->chain;
203       state->chain = new;
204       ++state->n;
205     }
206
207   return 0L;
208 }
209
210 /* Return nonzero if PATTERN contains any metacharacters.
211    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
212 static int
213 glob_pattern_p (const char *pattern, int quote)
214 {
215   const char *p;
216   int opened = 0;
217
218   for (p = pattern; *p != '\0'; ++p)
219     switch (*p)
220       {
221       case '?':
222       case '*':
223         return 1;
224
225       case '\\':
226         if (quote)
227           ++p;
228         break;
229
230       case '[':
231         opened = 1;
232         break;
233
234       case ']':
235         if (opened)
236           return 1;
237         break;
238       }
239
240   return 0;
241 }
242
243 /* Glob for MEMBER_PATTERN in archive ARNAME.
244    Return a malloc'd chain of matching elements (or nil if none).  */
245
246 struct nameseq *
247 ar_glob (const char *arname, const char *member_pattern, unsigned int size)
248 {
249   struct ar_glob_state state;
250   struct nameseq *n;
251   const char **names;
252   unsigned int i;
253
254   if (! glob_pattern_p (member_pattern, 1))
255     return 0;
256
257   /* Scan the archive for matches.
258      ar_glob_match will accumulate them in STATE.chain.  */
259   state.arname = arname;
260   state.pattern = member_pattern;
261   state.size = size;
262   state.chain = 0;
263   state.n = 0;
264   ar_scan (arname, ar_glob_match, &state);
265
266   if (state.chain == 0)
267     return 0;
268
269   /* Now put the names into a vector for sorting.  */
270   names = alloca (state.n * sizeof (const char *));
271   i = 0;
272   for (n = state.chain; n != 0; n = n->next)
273     names[i++] = n->name;
274
275   /* Sort them alphabetically.  */
276   /* MSVC erroneously warns without a cast here.  */
277   qsort ((void *)names, i, sizeof (*names), alpha_compare);
278
279   /* Put them back into the chain in the sorted order.  */
280   i = 0;
281   for (n = state.chain; n != 0; n = n->next)
282     n->name = names[i++];
283
284   return state.chain;
285 }
286
287 #endif  /* Not NO_ARCHIVES.  */