option.c: fixed warnings
[k8jam.git] / src / fileunix.c
blob1386e375d391843b4e515f730cfba71479d24400
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, version 3 of the License ONLY.
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, see <http://www.gnu.org/licenses/>.
18 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
20 * External routines:
22 * file_dirscan() - scan a directory for files
23 * file_time() - get timestamp of file, if not done by file_dirscan()
24 * file_archscan() - scan an archive for files
26 * File_dirscan() and file_archscan() call back a caller provided function
27 * for each file found. A flag to this callback function lets file_dirscan()
28 * and file_archscan() indicate that a timestamp is being provided with the
29 * file. If file_dirscan() or file_archscan() do not provide the file's
30 * timestamp, interested parties may later call file_time().
32 #include <unistd.h>
34 #include "jam.h"
35 #include "filesys.h"
36 #include "pathsys.h"
38 #ifdef USE_FILEUNIX
40 #if defined(OS_MACOSX)
41 /* need unistd for rhapsody's proper lseek */
42 # include <sys/dir.h>
43 # include <unistd.h>
44 # define STRUCT_DIRENT struct direct
45 #else
46 # include <dirent.h>
47 # define STRUCT_DIRENT struct dirent
48 #endif
50 #include <ar.h>
53 // <0: error; 0: regular; 1: directory
54 int file_type (const char *diskname) {
55 struct stat stbuf;
56 if (stat(diskname, &stbuf) != 0) return -1;
57 if (S_ISDIR(stbuf.st_mode)) return 1;
58 if (S_ISREG(stbuf.st_mode)) return 0;
59 return -1;
64 * file_dirscan() - scan a directory for files
66 void file_dirscan (const char *dir, scanback func, void *closure) {
67 PATHNAME f;
68 DIR *d;
69 STRUCT_DIRENT *dirent;
70 static char filename[MAXJPATH];
71 /* first enter directory itself */
72 memset((char *)&f, '\0', sizeof(f));
73 f.f_dir.ptr = dir;
74 f.f_dir.len = strlen(dir);
75 dir = (*dir ? dir : ".");
76 /* special case / : enter it */
77 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '/') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
78 /* Now enter contents of directory */
79 if (!(d = opendir(dir))) return;
80 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
81 while ((dirent = readdir(d))) {
82 f.f_base.ptr = dirent->d_name;
83 f.f_base.len = strlen(f.f_base.ptr);
84 path_build(filename, &f);
85 (*func)(closure, filename, 0 /* not stat()'ed */, (time_t)0);
87 closedir(d);
92 * file_time() - get timestamp of file, if not done by file_dirscan()
94 int file_time (const char *filename, time_t *time) {
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 #define SARFMAG 2
120 #define SARHDR sizeof(struct ar_hdr)
122 void file_archscan (const char *archive, scanback func, void *closure) {
123 #ifndef NO_AR
124 struct ar_hdr ar_hdr;
125 static char buf[MAXJPATH];
126 long offset;
127 char *string_table = 0;
128 int fd;
129 if ((fd = open(archive, O_RDONLY, 0)) < 0) return;
130 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
131 close(fd);
132 return;
134 offset = SARMAG;
135 if (DEBUG_BINDSCAN) printf("scan archive %s\n", archive);
136 #ifdef _AIX
137 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr._ar_name.ar_fmag, ARFMAG, SARFMAG)) {
138 #else
139 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr.ar_fmag, ARFMAG, SARFMAG)) {
140 #endif
141 long lar_date;
142 long lar_size;
143 char lar_name[256];
144 char *dst = lar_name;
145 /* solaris sscanf() does strlen first, so terminate somewhere */
146 #ifdef _AIX
147 ar_hdr._ar_name.ar_fmag[0] = 0;
148 #else
149 ar_hdr.ar_fmag[0] = 0;
150 #endif
151 /* get date & size */
153 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
154 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
156 lar_date = scan_long(ar_hdr.ar_date, sizeof(ar_hdr.ar_date));
157 lar_size = scan_long(ar_hdr.ar_size, sizeof(ar_hdr.ar_size));
158 /* handle solaris string table
159 * the entry under the name // is the table, and entries with the name /nnnn refer to the table */
160 #ifdef _AIX
161 if (ar_hdr._ar_name.ar_name[0] != '/') {
162 #else
163 if (ar_hdr.ar_name[0] != '/') {
164 #endif
165 /* traditional archive entry names: ends at the first space, /, or null */
166 #ifdef _AIX
167 char *src = ar_hdr._ar_name.ar_name;
168 const char *e = src+sizeof(ar_hdr._ar_name.ar_name);
169 #else
170 char *src = ar_hdr.ar_name;
171 const char *e = src+sizeof(ar_hdr.ar_name);
172 #endif
174 while (src < e && *src && *src != ' ' && *src != '/') *dst++ = *src++;
175 #ifdef _AIX
176 } else if (ar_hdr._ar_name.ar_name[1] == '/') {
177 #else
178 } else if (ar_hdr.ar_name[1] == '/') {
179 #endif
180 /* this is the "string table" entry of the symbol table,
181 * which holds strings of filenames that are longer than
182 * 15 characters (ie. don't fit into a ar_name) */
183 string_table = (char *)malloc(lar_size);
184 lseek(fd, offset+SARHDR, 0);
185 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
186 #ifdef _AIX
187 } else if (string_table && ar_hdr._ar_name.ar_name[1] != ' ') {
188 #else
189 } else if (string_table && ar_hdr.ar_name[1] != ' ') {
190 #endif
191 /* long filenames are recognized by "/nnnn" where nnnn is
192 * the offset of the string in the string table represented
193 * in ASCII decimals */
194 #ifdef _AIX
195 char *src = string_table+atoi(ar_hdr._ar_name.ar_name+1);
196 #else
197 char *src = string_table+atoi(ar_hdr.ar_name+1);
198 #endif
199 while (*src != '/') *dst++ = *src++;
201 /* terminate lar_name */
202 *dst = 0;
203 /* modern (BSD4.4) long names: if the name is "#1/nnnn", then the actual name is the nnnn bytes after the header */
204 if (!strcmp(lar_name, "#1")) {
205 #ifdef _AIX
206 int len = atoi(ar_hdr._ar_name.ar_name+3);
207 #else
208 int len = atoi(ar_hdr.ar_name+3);
209 #endif
210 if (read(fd, lar_name, len) != len) printf("error reading archive entry\n");
211 lar_name[len] = 0;
213 /* build name and pass it on */
214 if (lar_name[0]) {
215 if (DEBUG_BINDSCAN) printf("archive name %s found\n", lar_name);
216 snprintf(buf, sizeof(buf), "%s(%s)", archive, lar_name);
217 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
219 /* Position at next member */
220 offset += SARHDR+((lar_size+1)&(~1));
221 lseek(fd, offset, 0);
223 if (string_table) free(string_table);
224 close(fd);
225 #endif /* NO_AR */
229 #endif /* USE_FILEUNIX */