Add some more unit tests for variable flavors.
[make.git] / arscan.c
blobddc8ed8d2eb91c4b6814862df35d8f20d1a2b712
1 /* Library function for scanning an archive file.
2 Copyright (C) 1987,89,91,92,93,94,95,97 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA. */
19 #include "make.h"
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #else
24 #include <sys/file.h>
25 #endif
27 #ifndef NO_ARCHIVES
29 #ifdef VMS
30 #include <lbrdef.h>
31 #include <mhddef.h>
32 #include <credef.h>
33 #include <descrip.h>
34 #include <ctype.h>
35 #if __DECC
36 #include <unixlib.h>
37 #include <lbr$routines.h>
38 #endif
40 static void *VMS_lib_idx;
42 static char *VMS_saved_memname;
44 static time_t VMS_member_date;
46 static long int (*VMS_function) ();
48 static int
49 VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa)
51 int status, i;
52 long int fnval;
54 time_t val;
56 static struct dsc$descriptor_s bufdesc =
57 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
59 struct mhddef *mhd;
60 char filename[128];
62 bufdesc.dsc$a_pointer = filename;
63 bufdesc.dsc$w_length = sizeof (filename);
65 status = lbr$set_module (&VMS_lib_idx, rfa, &bufdesc,
66 &bufdesc.dsc$w_length, 0);
67 if (! (status & 1))
69 error (NILF, _("lbr$set_module failed to extract module info, status = %d"),
70 status);
72 lbr$close (&VMS_lib_idx);
74 return 0;
77 mhd = (struct mhddef *) filename;
79 #ifdef __DECC
80 /* John Fowler <jfowler@nyx.net> writes this is needed in his environment,
81 * but that decc$fix_time() isn't documented to work this way. Let me
82 * know if this causes problems in other VMS environments.
84 val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600;
85 #endif
87 for (i = 0; i < module->dsc$w_length; i++)
88 filename[i] = _tolower ((unsigned char)module->dsc$a_pointer[i]);
90 filename[i] = '\0';
92 VMS_member_date = (time_t) -1;
94 fnval =
95 (*VMS_function) (-1, filename, 0, 0, 0, 0, val, 0, 0, 0,
96 VMS_saved_memname);
98 if (fnval)
100 VMS_member_date = fnval;
101 return 0;
103 else
104 return 1;
107 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
109 Open the archive named ARCHIVE, find its members one by one,
110 and for each one call FUNCTION with the following arguments:
111 archive file descriptor for reading the data,
112 member name,
113 member name might be truncated flag,
114 member header position in file,
115 member data position in file,
116 member data size,
117 member date,
118 member uid,
119 member gid,
120 member protection mode,
121 ARG.
123 NOTE: on VMS systems, only name, date, and arg are meaningful!
125 The descriptor is poised to read the data of the member
126 when FUNCTION is called. It does not matter how much
127 data FUNCTION reads.
129 If FUNCTION returns nonzero, we immediately return
130 what FUNCTION returned.
132 Returns -1 if archive does not exist,
133 Returns -2 if archive has invalid format.
134 Returns 0 if have scanned successfully. */
136 long int
137 ar_scan (char *archive, long int (*function) PARAMS ((void)), long int arg)
139 char *p;
141 static struct dsc$descriptor_s libdesc =
142 { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
144 unsigned long func = LBR$C_READ;
145 unsigned long type = LBR$C_TYP_UNK;
146 unsigned long index = 1;
148 int status;
150 status = lbr$ini_control (&VMS_lib_idx, &func, &type, 0);
152 if (! (status & 1))
154 error (NILF, _("lbr$ini_control failed with status = %d"),status);
155 return -2;
158 libdesc.dsc$a_pointer = archive;
159 libdesc.dsc$w_length = strlen (archive);
161 status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0);
163 if (! (status & 1))
165 error (NILF, _("unable to open library `%s' to lookup member `%s'"),
166 archive, (char *)arg);
167 return -1;
170 VMS_saved_memname = (char *)arg;
172 /* For comparison, delete .obj from arg name. */
174 p = strrchr (VMS_saved_memname, '.');
175 if (p)
176 *p = '\0';
178 VMS_function = function;
180 VMS_member_date = (time_t) -1;
181 lbr$get_index (&VMS_lib_idx, &index, VMS_get_member_info, 0);
183 /* Undo the damage. */
184 if (p)
185 *p = '.';
187 lbr$close (&VMS_lib_idx);
189 return VMS_member_date > 0 ? VMS_member_date : 0;
192 #else /* !VMS */
194 /* SCO Unix's compiler defines both of these. */
195 #ifdef M_UNIX
196 #undef M_XENIX
197 #endif
199 /* On the sun386i and in System V rel 3, ar.h defines two different archive
200 formats depending upon whether you have defined PORTAR (normal) or PORT5AR
201 (System V Release 1). There is no default, one or the other must be defined
202 to have a nonzero value. */
204 #if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0)
205 #undef PORTAR
206 #ifdef M_XENIX
207 /* According to Jim Sievert <jas1@rsvl.unisys.com>, for SCO XENIX defining
208 PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the
209 right one. */
210 #define PORTAR 0
211 #else
212 #define PORTAR 1
213 #endif
214 #endif
216 /* On AIX, define these symbols to be sure to get both archive formats.
217 AIX 4.3 introduced the "big" archive format to support 64-bit object
218 files, so on AIX 4.3 systems we need to support both the "normal" and
219 "big" archive formats. An archive's format is indicated in the
220 "fl_magic" field of the "FL_HDR" structure. For a normal archive,
221 this field will be the string defined by the AIAMAG symbol. For a
222 "big" archive, it will be the string defined by the AIAMAGBIG symbol
223 (at least on AIX it works this way).
225 Note: we'll define these symbols regardless of which AIX version
226 we're compiling on, but this is okay since we'll use the new symbols
227 only if they're present. */
228 #ifdef _AIX
229 # define __AR_SMALL__
230 # define __AR_BIG__
231 #endif
233 #ifndef WINDOWS32
234 # ifndef __BEOS__
235 # include <ar.h>
236 # else
237 /* BeOS 5 doesn't have <ar.h> but has archives in the same format
238 * as many other Unices. This was taken from GNU binutils for BeOS.
240 # define ARMAG "!<arch>\n" /* String that begins an archive file. */
241 # define SARMAG 8 /* Size of that string. */
242 # define ARFMAG "`\n" /* String in ar_fmag at end of each header. */
243 struct ar_hdr
245 char ar_name[16]; /* Member file name, sometimes / terminated. */
246 char ar_date[12]; /* File date, decimal seconds since Epoch. */
247 char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
248 char ar_mode[8]; /* File mode, in ASCII octal. */
249 char ar_size[10]; /* File size, in ASCII decimal. */
250 char ar_fmag[2]; /* Always contains ARFMAG. */
252 # endif
253 #else
254 /* These should allow us to read Windows (VC++) libraries (according to Frank
255 * Libbrecht <frankl@abzx.belgium.hp.com>)
257 # include <windows.h>
258 # include <windef.h>
259 # include <io.h>
260 # define ARMAG IMAGE_ARCHIVE_START
261 # define SARMAG IMAGE_ARCHIVE_START_SIZE
262 # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
263 # define ar_name Name
264 # define ar_mode Mode
265 # define ar_size Size
266 # define ar_date Date
267 # define ar_uid UserID
268 # define ar_gid GroupID
269 #endif
271 /* Cray's <ar.h> apparently defines this. */
272 #ifndef AR_HDR_SIZE
273 # define AR_HDR_SIZE (sizeof (struct ar_hdr))
274 #endif
276 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
278 Open the archive named ARCHIVE, find its members one by one,
279 and for each one call FUNCTION with the following arguments:
280 archive file descriptor for reading the data,
281 member name,
282 member name might be truncated flag,
283 member header position in file,
284 member data position in file,
285 member data size,
286 member date,
287 member uid,
288 member gid,
289 member protection mode,
290 ARG.
292 The descriptor is poised to read the data of the member
293 when FUNCTION is called. It does not matter how much
294 data FUNCTION reads.
296 If FUNCTION returns nonzero, we immediately return
297 what FUNCTION returned.
299 Returns -1 if archive does not exist,
300 Returns -2 if archive has invalid format.
301 Returns 0 if have scanned successfully. */
303 long int
304 ar_scan (char *archive, long int (*function)(), long int arg)
306 #ifdef AIAMAG
307 FL_HDR fl_header;
308 #ifdef AIAMAGBIG
309 int big_archive = 0;
310 FL_HDR_BIG fl_header_big;
311 #endif
312 #else
313 int long_name = 0;
314 #endif
315 char *namemap = 0;
316 register int desc = open (archive, O_RDONLY, 0);
317 if (desc < 0)
318 return -1;
319 #ifdef SARMAG
321 char buf[SARMAG];
322 register int nread = read (desc, buf, SARMAG);
323 if (nread != SARMAG || bcmp (buf, ARMAG, SARMAG))
325 (void) close (desc);
326 return -2;
329 #else
330 #ifdef AIAMAG
332 register int nread = read (desc, (char *) &fl_header, FL_HSZ);
334 if (nread != FL_HSZ)
336 (void) close (desc);
337 return -2;
339 #ifdef AIAMAGBIG
340 /* If this is a "big" archive, then set the flag and
341 re-read the header into the "big" structure. */
342 if (!bcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG))
344 big_archive = 1;
346 /* seek back to beginning of archive */
347 if (lseek (desc, 0, 0) < 0)
349 (void) close (desc);
350 return -2;
353 /* re-read the header into the "big" structure */
354 nread = read (desc, (char *) &fl_header_big, FL_HSZ_BIG);
355 if (nread != FL_HSZ_BIG)
357 (void) close (desc);
358 return -2;
361 else
362 #endif
363 /* Check to make sure this is a "normal" archive. */
364 if (bcmp (fl_header.fl_magic, AIAMAG, SAIAMAG))
366 (void) close (desc);
367 return -2;
370 #else
372 #ifndef M_XENIX
373 int buf;
374 #else
375 unsigned short int buf;
376 #endif
377 register int nread = read(desc, &buf, sizeof (buf));
378 if (nread != sizeof (buf) || buf != ARMAG)
380 (void) close (desc);
381 return -2;
384 #endif
385 #endif
387 /* Now find the members one by one. */
389 #ifdef SARMAG
390 register long int member_offset = SARMAG;
391 #else
392 #ifdef AIAMAG
393 long int member_offset;
394 long int last_member_offset;
396 #ifdef AIAMAGBIG
397 if ( big_archive )
399 sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset);
400 sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset);
402 else
403 #endif
405 sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset);
406 sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset);
409 if (member_offset == 0)
411 /* Empty archive. */
412 close (desc);
413 return 0;
415 #else
416 #ifndef M_XENIX
417 register long int member_offset = sizeof (int);
418 #else /* Xenix. */
419 register long int member_offset = sizeof (unsigned short int);
420 #endif /* Not Xenix. */
421 #endif
422 #endif
424 while (1)
426 register int nread;
427 struct ar_hdr member_header;
428 #ifdef AIAMAGBIG
429 struct ar_hdr_big member_header_big;
430 #endif
431 #ifdef AIAMAG
432 char name[256];
433 int name_len;
434 long int dateval;
435 int uidval, gidval;
436 long int data_offset;
437 #else
438 char namebuf[sizeof member_header.ar_name + 1];
439 char *name;
440 int is_namemap; /* Nonzero if this entry maps long names. */
441 #endif
442 long int eltsize;
443 int eltmode;
444 long int fnval;
446 if (lseek (desc, member_offset, 0) < 0)
448 (void) close (desc);
449 return -2;
452 #ifdef AIAMAG
453 #define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name))
455 #ifdef AIAMAGBIG
456 if (big_archive)
458 nread = read (desc, (char *) &member_header_big,
459 AR_MEMHDR_SZ(member_header_big) );
461 if (nread != AR_MEMHDR_SZ(member_header_big))
463 (void) close (desc);
464 return -2;
467 sscanf (member_header_big.ar_namlen, "%4d", &name_len);
468 nread = read (desc, name, name_len);
470 if (nread != name_len)
472 (void) close (desc);
473 return -2;
476 name[name_len] = 0;
478 sscanf (member_header_big.ar_date, "%12ld", &dateval);
479 sscanf (member_header_big.ar_uid, "%12d", &uidval);
480 sscanf (member_header_big.ar_gid, "%12d", &gidval);
481 sscanf (member_header_big.ar_mode, "%12o", &eltmode);
482 sscanf (member_header_big.ar_size, "%20ld", &eltsize);
484 data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big)
485 + name_len + 2);
487 else
488 #endif
490 nread = read (desc, (char *) &member_header,
491 AR_MEMHDR_SZ(member_header) );
493 if (nread != AR_MEMHDR_SZ(member_header))
495 (void) close (desc);
496 return -2;
499 sscanf (member_header.ar_namlen, "%4d", &name_len);
500 nread = read (desc, name, name_len);
502 if (nread != name_len)
504 (void) close (desc);
505 return -2;
508 name[name_len] = 0;
510 sscanf (member_header.ar_date, "%12ld", &dateval);
511 sscanf (member_header.ar_uid, "%12d", &uidval);
512 sscanf (member_header.ar_gid, "%12d", &gidval);
513 sscanf (member_header.ar_mode, "%12o", &eltmode);
514 sscanf (member_header.ar_size, "%12ld", &eltsize);
516 data_offset = (member_offset + AR_MEMHDR_SZ(member_header)
517 + name_len + 2);
519 data_offset += data_offset % 2;
521 fnval =
522 (*function) (desc, name, 0,
523 member_offset, data_offset, eltsize,
524 dateval, uidval, gidval,
525 eltmode, arg);
527 #else /* Not AIAMAG. */
528 nread = read (desc, (char *) &member_header, AR_HDR_SIZE);
529 if (nread == 0)
530 /* No data left means end of file; that is OK. */
531 break;
533 if (nread != AR_HDR_SIZE
534 #if defined(ARFMAG) || defined(ARFZMAG)
535 || (
536 # ifdef ARFMAG
537 bcmp (member_header.ar_fmag, ARFMAG, 2)
538 # else
540 # endif
542 # ifdef ARFZMAG
543 bcmp (member_header.ar_fmag, ARFZMAG, 2)
544 # else
546 # endif
548 #endif
551 (void) close (desc);
552 return -2;
555 name = namebuf;
556 bcopy (member_header.ar_name, name, sizeof member_header.ar_name);
558 register char *p = name + sizeof member_header.ar_name;
560 *p = '\0';
561 while (p > name && *--p == ' ');
563 #ifndef AIAMAG
564 /* If the member name is "//" or "ARFILENAMES/" this may be
565 a list of file name mappings. The maximum file name
566 length supported by the standard archive format is 14
567 characters. This member will actually always be the
568 first or second entry in the archive, but we don't check
569 that. */
570 is_namemap = (!strcmp (name, "//")
571 || !strcmp (name, "ARFILENAMES/"));
572 #endif /* Not AIAMAG. */
573 /* On some systems, there is a slash after each member name. */
574 if (*p == '/')
575 *p = '\0';
577 #ifndef AIAMAG
578 /* If the member name starts with a space or a slash, this
579 is an index into the file name mappings (used by GNU ar).
580 Otherwise if the member name looks like #1/NUMBER the
581 real member name appears in the element data (used by
582 4.4BSD). */
583 if (! is_namemap
584 && (name[0] == ' ' || name[0] == '/')
585 && namemap != 0)
587 name = namemap + atoi (name + 1);
588 long_name = 1;
590 else if (name[0] == '#'
591 && name[1] == '1'
592 && name[2] == '/')
594 int namesize = atoi (name + 3);
596 name = (char *) alloca (namesize + 1);
597 nread = read (desc, name, namesize);
598 if (nread != namesize)
600 close (desc);
601 return -2;
603 name[namesize] = '\0';
605 long_name = 1;
607 #endif /* Not AIAMAG. */
610 #ifndef M_XENIX
611 sscanf (member_header.ar_mode, "%o", &eltmode);
612 eltsize = atol (member_header.ar_size);
613 #else /* Xenix. */
614 eltmode = (unsigned short int) member_header.ar_mode;
615 eltsize = member_header.ar_size;
616 #endif /* Not Xenix. */
618 fnval =
619 (*function) (desc, name, ! long_name, member_offset,
620 member_offset + AR_HDR_SIZE, eltsize,
621 #ifndef M_XENIX
622 atol (member_header.ar_date),
623 atoi (member_header.ar_uid),
624 atoi (member_header.ar_gid),
625 #else /* Xenix. */
626 member_header.ar_date,
627 member_header.ar_uid,
628 member_header.ar_gid,
629 #endif /* Not Xenix. */
630 eltmode, arg);
632 #endif /* AIAMAG. */
634 if (fnval)
636 (void) close (desc);
637 return fnval;
640 #ifdef AIAMAG
641 if (member_offset == last_member_offset)
642 /* End of the chain. */
643 break;
645 #ifdef AIAMAGBIG
646 if (big_archive)
647 sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset);
648 else
649 #endif
650 sscanf (member_header.ar_nxtmem, "%12ld", &member_offset);
652 if (lseek (desc, member_offset, 0) != member_offset)
654 (void) close (desc);
655 return -2;
657 #else
659 /* If this member maps archive names, we must read it in. The
660 name map will always precede any members whose names must
661 be mapped. */
662 if (is_namemap)
664 char *clear;
665 char *limit;
667 namemap = (char *) alloca (eltsize);
668 nread = read (desc, namemap, eltsize);
669 if (nread != eltsize)
671 (void) close (desc);
672 return -2;
675 /* The names are separated by newlines. Some formats have
676 a trailing slash. Null terminate the strings for
677 convenience. */
678 limit = namemap + eltsize;
679 for (clear = namemap; clear < limit; clear++)
681 if (*clear == '\n')
683 *clear = '\0';
684 if (clear[-1] == '/')
685 clear[-1] = '\0';
689 is_namemap = 0;
692 member_offset += AR_HDR_SIZE + eltsize;
693 if (member_offset % 2 != 0)
694 member_offset++;
695 #endif
699 close (desc);
700 return 0;
702 #endif /* !VMS */
704 /* Return nonzero iff NAME matches MEM.
705 If TRUNCATED is nonzero, MEM may be truncated to
706 sizeof (struct ar_hdr.ar_name) - 1. */
709 ar_name_equal (char *name, char *mem, int truncated)
711 char *p;
713 p = strrchr (name, '/');
714 if (p != 0)
715 name = p + 1;
717 #ifndef VMS
718 if (truncated)
720 #ifdef AIAMAG
721 /* TRUNCATED should never be set on this system. */
722 abort ();
723 #else
724 struct ar_hdr hdr;
725 #if !defined (__hpux) && !defined (cray)
726 return strneq (name, mem, sizeof(hdr.ar_name) - 1);
727 #else
728 return strneq (name, mem, sizeof(hdr.ar_name) - 2);
729 #endif /* !__hpux && !cray */
730 #endif /* !AIAMAG */
732 #endif /* !VMS */
734 return !strcmp (name, mem);
737 #ifndef VMS
738 /* ARGSUSED */
739 static long int
740 ar_member_pos (int desc UNUSED, char *mem, int truncated,
741 long int hdrpos, long int datapos UNUSED, long int size UNUSED,
742 long int date UNUSED, int uid UNUSED, int gid UNUSED,
743 int mode UNUSED, char *name)
745 if (!ar_name_equal (name, mem, truncated))
746 return 0;
747 return hdrpos;
750 /* Set date of member MEMNAME in archive ARNAME to current time.
751 Returns 0 if successful,
752 -1 if file ARNAME does not exist,
753 -2 if not a valid archive,
754 -3 if other random system call error (including file read-only),
755 1 if valid but member MEMNAME does not exist. */
758 ar_member_touch (char *arname, char *memname)
760 long int pos = ar_scan (arname, ar_member_pos, (long int) memname);
761 int fd;
762 struct ar_hdr ar_hdr;
763 int i;
764 unsigned int ui;
765 struct stat statbuf;
767 if (pos < 0)
768 return (int) pos;
769 if (!pos)
770 return 1;
772 fd = open (arname, O_RDWR, 0666);
773 if (fd < 0)
774 return -3;
775 /* Read in this member's header */
776 if (lseek (fd, pos, 0) < 0)
777 goto lose;
778 if (AR_HDR_SIZE != read (fd, (char *) &ar_hdr, AR_HDR_SIZE))
779 goto lose;
780 /* Write back the header, thus touching the archive file. */
781 if (lseek (fd, pos, 0) < 0)
782 goto lose;
783 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
784 goto lose;
785 /* The file's mtime is the time we we want. */
786 EINTRLOOP (i, fstat (fd, &statbuf));
787 if (i < 0)
788 goto lose;
789 #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
790 /* Advance member's time to that time */
791 for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++)
792 ar_hdr.ar_date[ui] = ' ';
793 sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime);
794 #ifdef AIAMAG
795 ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' ';
796 #endif
797 #else
798 ar_hdr.ar_date = statbuf.st_mtime;
799 #endif
800 /* Write back this member's header */
801 if (lseek (fd, pos, 0) < 0)
802 goto lose;
803 if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE))
804 goto lose;
805 close (fd);
806 return 0;
808 lose:
809 i = errno;
810 close (fd);
811 errno = i;
812 return -3;
814 #endif
816 #ifdef TEST
818 long int
819 describe_member (int desc, char *name, int truncated,
820 long int hdrpos, long int datapos, long int size,
821 long int date, int uid, int gid, int mode)
823 extern char *ctime ();
825 printf (_("Member `%s'%s: %ld bytes at %ld (%ld).\n"),
826 name, truncated ? _(" (name might be truncated)") : "",
827 size, hdrpos, datapos);
828 printf (_(" Date %s"), ctime (&date));
829 printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
831 return 0;
835 main (int argc, char **argv)
837 ar_scan (argv[1], describe_member);
838 return 0;
841 #endif /* TEST. */
842 #endif /* NO_ARCHIVES. */