fixed warning for 'size' profile
[k8jam.git] / src / filent.c
blob1a37808ec06a804b1d7f5497ba689ccfb0fa053a
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 */
6 /*
7 * filent.c - scan directories and archives on NT
9 * External routines:
11 * file_dirscan() - scan a directory for files
12 * file_time() - get timestamp of file, if not done by file_dirscan()
13 * file_archscan() - scan an archive for files
15 * File_dirscan() and file_archscan() call back a caller provided function
16 * for each file found. A flag to this callback function lets file_dirscan()
17 * and file_archscan() indicate that a timestamp is being provided with the
18 * file. If file_dirscan() or file_archscan() do not provide the file's
19 * timestamp, interested parties may later call file_time().
21 * 07/10/95 (taylor) Findfirst() returns the first file on NT.
22 * 05/03/96 (seiwald) split apart into pathnt.c
23 * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
24 * 10/03/00 (anton) - Porting for Borland C++ 5.5
25 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
26 * 11/04/02 (seiwald) - const-ing for string literals
27 * 01/23/03 (seiwald) - long long handles for NT IA64
29 #include "jam.h"
30 #include "filesys.h"
31 #include "pathsys.h"
33 #ifdef OS_NT
35 #include <io.h>
36 #include <stdint.h>
37 #include <sys/stat.h>
40 #define FINDTYPE intptr_t
44 * file_dirscan() - scan a directory for files
46 // <0: error; 0: regular; 1: directory
47 int file_type (const char *diskname) {
48 FINDTYPE handle;
49 struct _finddata_t finfo[1];
50 int res;
51 handle = _findfirst(diskname, finfo);
52 if (handle == (FINDTYPE)(-1)) return -1;
53 res = (finfo->attrib&(_A_SUBDIR) ? 1 : 0);
54 _findclose(handle);
55 return res;
59 void file_dirscan (const char *dir, scanback func, void *closure) {
60 PATHNAME f;
61 static char filespec[MAXJPATH];
62 static char filename[MAXJPATH];
63 FINDTYPE handle;
64 int ret;
65 struct _finddata_t finfo[1];
66 /* first enter directory itself */
67 memset((char *)&f, '\0', sizeof(f));
68 f.f_dir.ptr = dir;
69 f.f_dir.len = strlen(dir);
70 dir = (*dir ? dir : ".");
71 /* special case \ or d:\ : enter it */
72 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
73 else if (f.f_dir.len == 3 && f.f_dir.ptr[1] == ':') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
74 /* now enter contents of directory */
75 snprintf(filespec, sizeof(filespec), "%s/*", dir);
76 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
77 handle = _findfirst(filespec, finfo);
78 if ((ret = (handle == (FINDTYPE)(-1)))) return;
79 while (!ret) {
80 f.f_base.ptr = finfo->name;
81 f.f_base.len = strlen(finfo->name);
82 path_build(filename, &f);
83 (*func)(closure, filename, 1 /* stat()'ed */, finfo->time_write);
84 ret = _findnext(handle, finfo);
86 _findclose(handle);
91 * file_time() - get timestamp of file, if not done by file_dirscan()
93 int file_time (const char *filename, time_t *time) {
94 /* on NT this is called only for C:/ */
95 struct stat statbuf;
96 if (stat(filename, &statbuf) < 0) return -1;
97 *time = statbuf.st_mtime;
98 return 0;
102 static long scan_long (const char *str, size_t ssize) {
103 long res = 0;
104 while (ssize > 0 && str[0] && (str[0] < '0' || str[0] > '9')) { ++str; --ssize; }
105 if (ssize > 0 && str[0]) {
106 while (ssize > 0 && str[0] >= '0' && str[0] <= '9') {
107 res = res*10+str[0]-'0';
108 ++str;
109 --ssize;
112 return res;
117 * file_archscan() - scan an archive for files
119 /* straight from SunOS */
120 #define ARMAG "!<arch>\n"
121 #define SARMAG 8
122 #define ARFMAG "`\n"
124 struct ar_hdr {
125 char ar_name[16];
126 char ar_date[12];
127 char ar_uid[6];
128 char ar_gid[6];
129 char ar_mode[8];
130 char ar_size[10];
131 char ar_fmag[2];
134 #define SARFMAG 2
135 #define SARHDR sizeof(struct ar_hdr)
137 void file_archscan (const char *archive, scanback func, void *closure) {
138 struct ar_hdr ar_hdr;
139 char *string_table = 0;
140 long string_table_len = 0;
141 static char buf[MAXJPATH];
142 long offset;
143 int fd;
144 if ((fd = open(archive, O_RDONLY | O_BINARY, 0)) < 0) return;
145 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
146 close(fd);
147 return;
149 offset = SARMAG;
150 if (DEBUG_BINDSCAN) printf("scan archive %s\n", archive);
151 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr.ar_fmag, ARFMAG, SARFMAG)) {
152 long lar_date;
153 long lar_size;
154 char *name = 0;
155 char *endname;
156 /*char *c;*/
158 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
159 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
161 lar_date = scan_long(ar_hdr.ar_date, sizeof(ar_hdr.ar_date));
162 lar_size = scan_long(ar_hdr.ar_size, sizeof(ar_hdr.ar_size));
163 lar_size = (lar_size+1) & ~1;
164 if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/') {
165 /* this is the "string table" entry of the symbol table,
166 * which holds strings of filenames that are longer than
167 * 15 characters (ie. don't fit into a ar_name */
168 string_table = malloc(lar_size);
169 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
170 string_table_len = lar_size;
171 goto next;
172 } else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ') {
173 /* Long filenames are recognized by "/nnnn" where nnnn is
174 * the offset of the string in the string table represented
175 * in ASCII decimals.
177 * however, the name end with 0 or '/', depending on
178 * the librarian used to generate them (0 for Mingw, '/' for Visual C++) */
179 long off = atoi(ar_hdr.ar_name+1);
180 if (off < 0 || off > string_table_len) goto next;
181 name = string_table+off;
182 for (; off < string_table_len; ++off) {
183 int c = string_table[off];
184 if (c == 0 || c == '/') break;
186 endname = string_table+off;
187 } else {
188 /* normal name */
189 long off;
191 name = ar_hdr.ar_name;
192 for (off = 0; off < sizeof(ar_hdr.ar_name); ++off) {
193 if (name[off] == '/' || name[off] == 0) break; /* not strictly required, but safe */
195 endname = name+off;
197 /* strip trailing space, slashes, and backslashes */
198 while (endname > name) {
199 int c = endname[-1];
200 if (c != ' ' && c != '\\' && c != '/') break;
201 --endname;
203 /* strip leading directory names, since they're present in
204 * files generated by the Microsoft Librarian */
206 char *p = name;
207 for (; p < endname; ++p) if (*p == '\\') name = p+1;
209 /* don't count empty entries */
210 if (name >= endname) goto next;
211 /* create name */
212 snprintf(buf, sizeof(buf), "%s(%.*s)", archive, endname-name, name);
213 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
214 next:
215 offset += SARHDR+lar_size;
216 lseek(fd, offset, 0);
218 close(fd);
222 #endif /* NT */