version upgraded; added JAM_TARGET and fixed JAMCMDARGS vars
[k8jam.git] / filent.c
blob3d156f5097aa113ff25597fa5a8884f41329930c
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
7 /*
8 * filent.c - scan directories and archives on NT
10 * External routines:
12 * file_dirscan() - scan a directory for files
13 * file_time() - get timestamp of file, if not done by file_dirscan()
14 * file_archscan() - scan an archive for files
16 * File_dirscan() and file_archscan() call back a caller provided function
17 * for each file found. A flag to this callback function lets file_dirscan()
18 * and file_archscan() indicate that a timestamp is being provided with the
19 * file. If file_dirscan() or file_archscan() do not provide the file's
20 * timestamp, interested parties may later call file_time().
22 * 07/10/95 (taylor) Findfirst() returns the first file on NT.
23 * 05/03/96 (seiwald) split apart into pathnt.c
24 * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
25 * 10/03/00 (anton) - Porting for Borland C++ 5.5
26 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
27 * 11/04/02 (seiwald) - const-ing for string literals
28 * 01/23/03 (seiwald) - long long handles for NT IA64
30 # include "jam.h"
31 # include "filesys.h"
32 # include "pathsys.h"
34 # ifdef OS_NT
36 # ifdef __BORLANDC__
37 # if __BORLANDC__ < 0x550
38 # include <dir.h>
39 # include <dos.h>
40 # endif
41 # undef PATHNAME /* cpp namespace collision */
42 # define _finddata_t ffblk
43 # endif
45 # include <io.h>
46 # include <sys/stat.h>
49 * file_dirscan() - scan a directory for files
52 # ifdef _M_IA64
53 # define FINDTYPE long long
54 # else
55 # define FINDTYPE long
56 # endif
59 void file_dirscan (const char *dir, scanback func, void *closure) {
60 PATHNAME f;
61 char filespec[MAXJPATH];
62 char filename[MAXJPATH];
63 FINDTYPE handle;
64 int ret;
65 struct _finddata_t finfo[1];
67 /* First enter directory itself */
68 memset((char *)&f, '\0', sizeof(f));
69 f.f_dir.ptr = dir;
70 f.f_dir.len = strlen(dir);
71 dir = *dir ? dir : ".";
73 /* Special case \ or d:\ : enter it */
74 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
75 else if (f.f_dir.len == 3 && f.f_dir.ptr[1] == ':') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
77 /* Now enter contents of directory */
78 sprintf(filespec, "%s/*", dir);
79 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
81 # if defined(__BORLANDC__) && __BORLANDC__ < 0x550
82 if (ret = findfirst(filespec, finfo, FA_NORMAL | FA_DIREC)) return;
83 while (!ret) {
84 time_t time_write = finfo->ff_fdate;
85 time_write = (time_write << 16) | finfo->ff_ftime;
86 f.f_base.ptr = finfo->ff_name;
87 f.f_base.len = strlen(finfo->ff_name);
88 path_build(&f, filename);
89 (*func)(closure, filename, 1 /* stat()'ed */, time_write);
90 ret = findnext(finfo);
92 # else
93 handle = _findfirst(filespec, finfo);
94 if ((ret = (handle == (FINDTYPE)(-1)))) return;
95 while (!ret) {
96 f.f_base.ptr = finfo->name;
97 f.f_base.len = strlen(finfo->name);
98 path_build(&f, filename, 0);
99 (*func)(closure, filename, 1 /* stat()'ed */, finfo->time_write);
100 ret = _findnext(handle, finfo);
102 _findclose(handle);
103 # endif
108 * file_time() - get timestamp of file, if not done by file_dirscan()
110 int file_time (const char *filename, time_t *time) {
111 /* On NT this is called only for C:/ */
112 struct stat statbuf;
114 if (stat(filename, &statbuf) < 0) return -1;
115 *time = statbuf.st_mtime;
116 return 0;
121 * file_archscan() - scan an archive for files
123 /* Straight from SunOS */
124 #define ARMAG "!<arch>\n"
125 #define SARMAG 8
127 #define ARFMAG "`\n"
129 struct ar_hdr {
130 char ar_name[16];
131 char ar_date[12];
132 char ar_uid[6];
133 char ar_gid[6];
134 char ar_mode[8];
135 char ar_size[10];
136 char ar_fmag[2];
139 # define SARFMAG 2
140 # define SARHDR sizeof( struct ar_hdr )
142 void file_archscan (const char *archive, scanback func, void *closure) {
143 struct ar_hdr ar_hdr;
144 char *string_table = 0;
145 long string_table_len = 0;
146 char buf[MAXJPATH];
147 long offset;
148 int fd;
150 if ((fd = open(archive, O_RDONLY | O_BINARY, 0)) < 0) return;
151 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
152 close(fd);
153 return;
155 offset = SARMAG;
156 if (DEBUG_BINDSCAN) printf("scan archive %s\n", archive);
158 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr.ar_fmag, ARFMAG, SARFMAG)) {
159 long lar_date;
160 long lar_size;
161 char *name = 0;
162 char *endname;
163 /*char *c;*/
165 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
166 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
167 lar_size = (lar_size+1) & ~1;
168 if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/') {
169 /* this is the "string table" entry of the symbol table,
170 ** which holds strings of filenames that are longer than
171 ** 15 characters (ie. don't fit into a ar_name
173 string_table = malloc(lar_size);
174 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
175 string_table_len = lar_size;
176 goto Next;
177 } else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ') {
178 /* Long filenames are recognized by "/nnnn" where nnnn is
179 ** the offset of the string in the string table represented
180 ** in ASCII decimals.
182 ** however, the name end with 0 or '/', depending on
183 ** the librarian used to generate them (0 for Mingw,
184 * '/' for Visual C++)
186 long off = atoi(ar_hdr.ar_name+1);
187 if (off < 0 || off > string_table_len) goto Next;
188 name = string_table+off;
189 for (; off < string_table_len; off++) {
190 int c = string_table[off];
191 if (c == 0 || c == '/') break;
193 endname = string_table+off;
194 } else {
195 /* normal name */
196 long off;
198 name = ar_hdr.ar_name;
199 for (off = 0; off < sizeof(ar_hdr.ar_name); off++) {
200 if (name[off] == '/' || name[off] == 0) break; /* not strictly required, but safe */
202 endname = name+off;
204 /* strip trailing space, slashes, and backslashes */
205 while (endname > name) {
206 int c = endname[-1];
207 if (c != ' ' && c != '\\' && c != '/') break;
208 endname--;
210 /* strip leading directory names, since they're present in
211 * files generated by the Microsoft Librarian
214 char* p = name;
215 for (; p < endname; p++) {
216 if (*p == '\\') name = p+1;
219 /* don't count empty entries */
220 if (name >= endname) goto Next;
221 /* create name */
222 sprintf(buf, "%s(%.*s)", archive, endname-name, name);
223 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
224 Next:
225 offset += SARHDR+lar_size;
226 lseek(fd, offset, 0);
228 close(fd);
232 # endif /* NT */