Home | History | Annotate | Line # | Download | only in dist
      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 (char *archive, long int (*function) PARAMS ((int, char *, int, long int, long int, long int, long int, int, int, int, void *)), void *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,
     77 	long int datapos, long int size, long int date, int uid, int gid, int mode, void *arg));
     78 
     79 /* Return the modtime of NAME.  */
     80 
     81 time_t
     82 ar_member_date (char *name)
     83 {
     84   char *arname;
     85   int arname_used = 0;
     86   char *memname;
     87   long int val;
     88 
     89   ar_parse_name (name, &arname, &memname);
     90 
     91   /* Make sure we know the modtime of the archive itself because we are
     92      likely to be called just before commands to remake a member are run,
     93      and they will change the archive itself.
     94 
     95      But we must be careful not to enter_file the archive itself if it does
     96      not exist, because pattern_search assumes that files found in the data
     97      base exist or can be made.  */
     98   {
     99     struct file *arfile;
    100     arfile = lookup_file (arname);
    101     if (arfile == 0 && file_exists_p (arname))
    102       {
    103 	arfile = enter_file (arname);
    104 	arname_used = 1;
    105       }
    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   if (!arname_used)
    114     free (arname);
    115   free (memname);
    116 
    117   return (val <= 0 ? (time_t) -1 : (time_t) val);
    118 }
    119 
    120 /* This function is called by `ar_scan' to find which member to look at.  */
    121 
    122 /* ARGSUSED */
    123 static long int
    124 ar_member_date_1 (int desc UNUSED, char *mem, int truncated,
    125 		  long int hdrpos UNUSED, long int datapos UNUSED,
    126                   long int size UNUSED, long int date,
    127                   int uid UNUSED, int gid UNUSED, int mode UNUSED, void *arg)
    128 {
    129   char *name = arg;
    130   return ar_name_equal (name, mem, truncated) ? date : 0;
    131 }
    132 
    133 /* Set the archive-member NAME's modtime to now.  */
    135 
    136 #ifdef VMS
    137 int
    138 ar_touch (char *name)
    139 {
    140   error (NILF, _("touch archive member is not available on VMS"));
    141   return -1;
    142 }
    143 #else
    144 int
    145 ar_touch (char *name)
    146 {
    147   char *arname, *memname;
    148   int arname_used = 0;
    149   register int val;
    150 
    151   ar_parse_name (name, &arname, &memname);
    152 
    153   /* Make sure we know the modtime of the archive itself before we
    154      touch the member, since this will change the archive itself.  */
    155   {
    156     struct file *arfile;
    157     arfile = lookup_file (arname);
    158     if (arfile == 0)
    159       {
    160 	arfile = enter_file (arname);
    161 	arname_used = 1;
    162       }
    163 
    164     (void) f_mtime (arfile, 0);
    165   }
    166 
    167   val = 1;
    168   switch (ar_member_touch (arname, memname))
    169     {
    170     case -1:
    171       error (NILF, _("touch: Archive `%s' does not exist"), arname);
    172       break;
    173     case -2:
    174       error (NILF, _("touch: `%s' is not a valid archive"), arname);
    175       break;
    176     case -3:
    177       perror_with_name ("touch: ", arname);
    178       break;
    179     case 1:
    180       error (NILF,
    181              _("touch: Member `%s' does not exist in `%s'"), memname, arname);
    182       break;
    183     case 0:
    184       val = 0;
    185       break;
    186     default:
    187       error (NILF,
    188              _("touch: Bad return code from ar_member_touch on `%s'"), name);
    189     }
    190 
    191   if (!arname_used)
    192     free (arname);
    193   free (memname);
    194 
    195   return val;
    196 }
    197 #endif /* !VMS */
    198 
    199 /* State of an `ar_glob' run, passed to `ar_glob_match'.  */
    201 
    202 struct ar_glob_state
    203   {
    204     char *arname;
    205     char *pattern;
    206     unsigned int size;
    207     struct nameseq *chain;
    208     unsigned int n;
    209   };
    210 
    211 /* This function is called by `ar_scan' to match one archive
    212    element against the pattern in STATE.  */
    213 
    214 static long int
    215 ar_glob_match (int desc UNUSED, char *mem, int truncated UNUSED,
    216 	       long int hdrpos UNUSED, long int datapos UNUSED,
    217                long int size UNUSED, long int date UNUSED, int uid UNUSED,
    218                int gid UNUSED, int mode UNUSED, void *arg)
    219 {
    220   struct ar_glob_state *state = arg;
    221 
    222   if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
    223     {
    224       /* We have a match.  Add it to the chain.  */
    225       struct nameseq *new = (struct nameseq *) xmalloc (state->size);
    226       new->name = concat (state->arname, mem, ")");
    227       new->next = state->chain;
    228       state->chain = new;
    229       ++state->n;
    230     }
    231 
    232   return 0L;
    233 }
    234 
    235 /* Return nonzero if PATTERN contains any metacharacters.
    236    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
    237 static int
    238 glob_pattern_p (const char *pattern, int quote)
    239 {
    240   const char *p;
    241   int open = 0;
    242 
    243   for (p = pattern; *p != '\0'; ++p)
    244     switch (*p)
    245       {
    246       case '?':
    247       case '*':
    248 	return 1;
    249 
    250       case '\\':
    251 	if (quote)
    252 	  ++p;
    253 	break;
    254 
    255       case '[':
    256 	open = 1;
    257 	break;
    258 
    259       case ']':
    260 	if (open)
    261 	  return 1;
    262 	break;
    263       }
    264 
    265   return 0;
    266 }
    267 
    268 /* Glob for MEMBER_PATTERN in archive ARNAME.
    269    Return a malloc'd chain of matching elements (or nil if none).  */
    270 
    271 struct nameseq *
    272 ar_glob (char *arname, char *member_pattern, unsigned int size)
    273 {
    274   struct ar_glob_state state;
    275   char **names;
    276   struct nameseq *n;
    277   unsigned int i;
    278 
    279   if (! glob_pattern_p (member_pattern, 1))
    280     return 0;
    281 
    282   /* Scan the archive for matches.
    283      ar_glob_match will accumulate them in STATE.chain.  */
    284   i = strlen (arname);
    285   state.arname = (char *) alloca (i + 2);
    286   bcopy (arname, state.arname, i);
    287   state.arname[i] = '(';
    288   state.arname[i + 1] = '\0';
    289   state.pattern = member_pattern;
    290   state.size = size;
    291   state.chain = 0;
    292   state.n = 0;
    293   (void) ar_scan (arname, ar_glob_match, &state);
    294 
    295   if (state.chain == 0)
    296     return 0;
    297 
    298   /* Now put the names into a vector for sorting.  */
    299   names = (char **) alloca (state.n * sizeof (char *));
    300   i = 0;
    301   for (n = state.chain; n != 0; n = n->next)
    302     names[i++] = n->name;
    303 
    304   /* Sort them alphabetically.  */
    305   qsort ((char *) names, i, sizeof (*names), alpha_compare);
    306 
    307   /* Put them back into the chain in the sorted order.  */
    308   i = 0;
    309   for (n = state.chain; n != 0; n = n->next)
    310     n->name = names[i++];
    311 
    312   return state.chain;
    313 }
    314 
    315 #endif	/* Not NO_ARCHIVES.  */
    316