it's now safe (i hope) to include Jambase.configure multiple times
[k8jam.git] / src / filent.c
blob32368df0d8afd562a8c5c8ec2be70f8ad794e99f
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 * This file is part of Jam - see jam.c for Copyright information.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * filent.c - scan directories and archives on NT
21 * External routines:
23 * file_dirscan() - scan a directory for files
24 * file_time() - get timestamp of file, if not done by file_dirscan()
25 * file_archscan() - scan an archive for files
27 * File_dirscan() and file_archscan() call back a caller provided function
28 * for each file found. A flag to this callback function lets file_dirscan()
29 * and file_archscan() indicate that a timestamp is being provided with the
30 * file. If file_dirscan() or file_archscan() do not provide the file's
31 * timestamp, interested parties may later call file_time().
33 #include "jam.h"
34 #include "filesys.h"
35 #include "pathsys.h"
37 #ifdef OS_NT
39 #include <io.h>
40 #include <stdint.h>
41 #include <sys/stat.h>
44 #define FINDTYPE intptr_t
48 * file_dirscan() - scan a directory for files
50 // <0: error; 0: regular; 1: directory
51 int file_type (const char *diskname) {
52 FINDTYPE handle;
53 struct _finddata_t finfo[1];
54 int res;
55 handle = _findfirst(diskname, finfo);
56 if (handle == (FINDTYPE)(-1)) return -1;
57 res = (finfo->attrib&(_A_SUBDIR) ? 1 : 0);
58 _findclose(handle);
59 return res;
63 void file_dirscan (const char *dir, scanback func, void *closure) {
64 PATHNAME f;
65 static char filespec[MAXJPATH];
66 static char filename[MAXJPATH];
67 FINDTYPE handle;
68 int ret;
69 struct _finddata_t finfo[1];
70 /* first enter directory itself */
71 memset((char *)&f, '\0', sizeof(f));
72 f.f_dir.ptr = dir;
73 f.f_dir.len = strlen(dir);
74 dir = (*dir ? dir : ".");
75 /* special case \ or d:\ : enter it */
76 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
77 else if (f.f_dir.len == 3 && f.f_dir.ptr[1] == ':') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
78 /* now enter contents of directory */
79 snprintf(filespec, sizeof(filespec), "%s/*", dir);
80 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
81 handle = _findfirst(filespec, finfo);
82 if ((ret = (handle == (FINDTYPE)(-1)))) return;
83 while (!ret) {
84 f.f_base.ptr = finfo->name;
85 f.f_base.len = strlen(finfo->name);
86 path_build(filename, &f);
87 (*func)(closure, filename, 1 /* stat()'ed */, finfo->time_write);
88 ret = _findnext(handle, finfo);
90 _findclose(handle);
95 * file_time() - get timestamp of file, if not done by file_dirscan()
97 int file_time (const char *filename, time_t *time) {
98 /* on NT this is called only for C:/ */
99 struct stat statbuf;
100 if (stat(filename, &statbuf) < 0) return -1;
101 *time = statbuf.st_mtime;
102 return 0;
106 static long scan_long (const char *str, size_t ssize) {
107 long res = 0;
108 while (ssize > 0 && str[0] && (str[0] < '0' || str[0] > '9')) { ++str; --ssize; }
109 if (ssize > 0 && str[0]) {
110 while (ssize > 0 && str[0] >= '0' && str[0] <= '9') {
111 res = res*10+str[0]-'0';
112 ++str;
113 --ssize;
116 return res;
121 * file_archscan() - scan an archive for files
123 /* straight from SunOS */
124 #define ARMAG "!<arch>\n"
125 #define SARMAG 8
126 #define ARFMAG "`\n"
128 struct ar_hdr {
129 char ar_name[16];
130 char ar_date[12];
131 char ar_uid[6];
132 char ar_gid[6];
133 char ar_mode[8];
134 char ar_size[10];
135 char ar_fmag[2];
138 #define SARFMAG 2
139 #define SARHDR sizeof(struct ar_hdr)
141 void file_archscan (const char *archive, scanback func, void *closure) {
142 struct ar_hdr ar_hdr;
143 char *string_table = 0;
144 long string_table_len = 0;
145 static char buf[MAXJPATH];
146 long offset;
147 int fd;
148 if ((fd = open(archive, O_RDONLY|O_BINARY, 0)) < 0) return;
149 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
150 close(fd);
151 return;
153 offset = SARMAG;
154 if (DEBUG_BINDSCAN) printf("scan archive %s\n", archive);
155 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr.ar_fmag, ARFMAG, SARFMAG)) {
156 long lar_date;
157 long lar_size;
158 char *name = 0;
159 char *endname;
160 /*char *c;*/
162 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
163 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
165 lar_date = scan_long(ar_hdr.ar_date, sizeof(ar_hdr.ar_date));
166 lar_size = scan_long(ar_hdr.ar_size, sizeof(ar_hdr.ar_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 */
172 string_table = malloc(lar_size);
173 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
174 string_table_len = lar_size;
175 goto next;
176 } else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ') {
177 /* Long filenames are recognized by "/nnnn" where nnnn is
178 * the offset of the string in the string table represented
179 * in ASCII decimals.
181 * however, the name end with 0 or '/', depending on
182 * the librarian used to generate them (0 for Mingw, '/' for Visual C++) */
183 long off = atoi(ar_hdr.ar_name+1);
184 if (off < 0 || off > string_table_len) goto next;
185 name = string_table+off;
186 for (; off < string_table_len; ++off) {
187 int c = string_table[off];
188 if (c == 0 || c == '/') break;
190 endname = string_table+off;
191 } else {
192 /* normal name */
193 long off;
195 name = ar_hdr.ar_name;
196 for (off = 0; off < sizeof(ar_hdr.ar_name); ++off) {
197 if (name[off] == '/' || name[off] == 0) break; /* not strictly required, but safe */
199 endname = name+off;
201 /* strip trailing space, slashes, and backslashes */
202 while (endname > name) {
203 int c = endname[-1];
204 if (c != ' ' && c != '\\' && c != '/') break;
205 --endname;
207 /* strip leading directory names, since they're present in
208 * files generated by the Microsoft Librarian */
210 char *p = name;
211 for (; p < endname; ++p) if (*p == '\\') name = p+1;
213 /* don't count empty entries */
214 if (name >= endname) goto next;
215 /* create name */
216 snprintf(buf, sizeof(buf), "%s(%.*s)", archive, endname-name, name);
217 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
218 next:
219 offset += SARHDR+lar_size;
220 lseek(fd, offset, 0);
222 close(fd);
226 #endif /* NT */