added "jammod" command and "genman" module
[k8jam.git] / src / fileunix.c
blob0ae12cec8cdbb8b823648fd9f906b5caecc35fe7
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 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
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 <unistd.h>
35 #include "jam.h"
36 #include "filesys.h"
37 #include "pathsys.h"
39 #ifdef USE_FILEUNIX
41 #if defined(OS_MACOSX)
42 /* need unistd for rhapsody's proper lseek */
43 # include <sys/dir.h>
44 # include <unistd.h>
45 # define STRUCT_DIRENT struct direct
46 #else
47 # include <dirent.h>
48 # define STRUCT_DIRENT struct dirent
49 #endif
51 #include <ar.h>
54 // <0: error; 0: regular; 1: directory
55 int file_type (const char *diskname) {
56 struct stat stbuf;
57 if (stat(diskname, &stbuf) != 0) return -1;
58 if (S_ISDIR(stbuf.st_mode)) return 1;
59 if (S_ISREG(stbuf.st_mode)) return 0;
60 return -1;
65 * file_dirscan() - scan a directory for files
67 void file_dirscan (const char *dir, scanback func, void *closure) {
68 PATHNAME f;
69 DIR *d;
70 STRUCT_DIRENT *dirent;
71 static char filename[MAXJPATH];
72 /* first enter directory itself */
73 memset((char *)&f, '\0', sizeof(f));
74 f.f_dir.ptr = dir;
75 f.f_dir.len = strlen(dir);
76 dir = (*dir ? dir : ".");
77 /* special case / : enter it */
78 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '/') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
79 /* Now enter contents of directory */
80 if (!(d = opendir(dir))) return;
81 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
82 while ((dirent = readdir(d))) {
83 f.f_base.ptr = dirent->d_name;
84 f.f_base.len = strlen(f.f_base.ptr);
85 path_build(filename, &f);
86 (*func)(closure, filename, 0 /* not stat()'ed */, (time_t)0);
88 closedir(d);
93 * file_time() - get timestamp of file, if not done by file_dirscan()
95 int file_time (const char *filename, time_t *time) {
96 struct stat statbuf;
97 if (stat(filename, &statbuf) < 0) return -1;
98 *time = statbuf.st_mtime;
99 return 0;
103 static long scan_long (const char *str, size_t ssize) {
104 long res = 0;
105 while (ssize > 0 && str[0] && (str[0] < '0' || str[0] > '9')) { ++str; --ssize; }
106 if (ssize > 0 && str[0]) {
107 while (ssize > 0 && str[0] >= '0' && str[0] <= '9') {
108 res = res*10+str[0]-'0';
109 ++str;
110 --ssize;
113 return res;
118 * file_archscan() - scan an archive for files
120 #define SARFMAG 2
121 #define SARHDR sizeof(struct ar_hdr)
123 void file_archscan (const char *archive, scanback func, void *closure) {
124 #ifndef NO_AR
125 struct ar_hdr ar_hdr;
126 static char buf[MAXJPATH];
127 long offset;
128 char *string_table = 0;
129 int fd;
130 if ((fd = open(archive, O_RDONLY, 0)) < 0) return;
131 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
132 close(fd);
133 return;
135 offset = SARMAG;
136 if (DEBUG_BINDSCAN) printf("scan archive %s\n", archive);
137 while (read(fd, &ar_hdr, SARHDR) == SARHDR && !memcmp(ar_hdr.ar_fmag, ARFMAG, SARFMAG)) {
138 long lar_date;
139 long lar_size;
140 char lar_name[256];
141 char *dst = lar_name;
142 /* solaris sscanf() does strlen first, so terminate somewhere */
143 ar_hdr.ar_fmag[0] = 0;
144 /* get date & size */
146 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
147 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
149 lar_date = scan_long(ar_hdr.ar_date, sizeof(ar_hdr.ar_date));
150 lar_size = scan_long(ar_hdr.ar_size, sizeof(ar_hdr.ar_size));
151 /* handle solaris string table
152 * the entry under the name // is the table, and entries with the name /nnnn refer to the table */
153 if (ar_hdr.ar_name[0] != '/') {
154 /* traditional archive entry names: ends at the first space, /, or null */
155 char *src = ar_hdr.ar_name;
156 const char *e = src+sizeof(ar_hdr.ar_name);
158 while (src < e && *src && *src != ' ' && *src != '/') *dst++ = *src++;
159 } else if (ar_hdr.ar_name[1] == '/') {
160 /* this is the "string table" entry of the symbol table,
161 * which holds strings of filenames that are longer than
162 * 15 characters (ie. don't fit into a ar_name) */
163 string_table = (char *)malloc(lar_size);
164 lseek(fd, offset+SARHDR, 0);
165 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
166 } else if (string_table && ar_hdr.ar_name[1] != ' ') {
167 /* long filenames are recognized by "/nnnn" where nnnn is
168 * the offset of the string in the string table represented
169 * in ASCII decimals */
170 char *src = string_table+atoi(ar_hdr.ar_name+1);
171 while (*src != '/') *dst++ = *src++;
173 /* terminate lar_name */
174 *dst = 0;
175 /* modern (BSD4.4) long names: if the name is "#1/nnnn", then the actual name is the nnnn bytes after the header */
176 if (!strcmp(lar_name, "#1")) {
177 int len = atoi(ar_hdr.ar_name+3);
178 if (read(fd, lar_name, len) != len) printf("error reading archive entry\n");
179 lar_name[len] = 0;
181 /* build name and pass it on */
182 if (lar_name[0]) {
183 if (DEBUG_BINDSCAN) printf("archive name %s found\n", lar_name);
184 snprintf(buf, sizeof(buf), "%s(%s)", archive, lar_name);
185 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
187 /* Position at next member */
188 offset += SARHDR+((lar_size+1)&(~1));
189 lseek(fd, offset, 0);
191 if (string_table) free(string_table);
192 close(fd);
193 #endif /* NO_AR */
197 #endif /* USE_FILEUNIX */