[Tizen_6_build] Fixed 32-bit arm build with gcc 9
[platform/upstream/boost-jam.git] / filent.c
1 /*
2  * Copyright 1993, 1995 Christopher Seiwald.
3  *
4  * This file is part of Jam - see jam.c for Copyright information.
5  */
6
7 /*  This file is ALSO:
8  *  Copyright 2001-2004 David Abrahams.
9  *  Copyright 2005 Rene Rivera.
10  *  Distributed under the Boost Software License, Version 1.0.
11  *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
12  */
13
14 # include "jam.h"
15
16 # include "filesys.h"
17 # include "pathsys.h"
18 # include "strings.h"
19 # include "newstr.h"
20
21 # ifdef OS_NT
22
23 # ifdef __BORLANDC__
24 # if __BORLANDC__ < 0x550
25 # include <dir.h>
26 # include <dos.h>
27 # endif
28 # undef FILENAME    /* cpp namespace collision */
29 # define _finddata_t ffblk
30 # endif
31
32 # include <io.h>
33 # include <sys/stat.h>
34 # include <ctype.h>
35 # include <direct.h>
36
37 /*
38  * filent.c - scan directories and archives on NT
39  *
40  * External routines:
41  *
42  *  file_dirscan() - scan a directory for files
43  *  file_time() - get timestamp of file, if not done by file_dirscan()
44  *  file_archscan() - scan an archive for files
45  *
46  * File_dirscan() and file_archscan() call back a caller provided function
47  * for each file found.  A flag to this callback function lets file_dirscan()
48  * and file_archscan() indicate that a timestamp is being provided with the
49  * file.   If file_dirscan() or file_archscan() do not provide the file's
50  * timestamp, interested parties may later call file_time().
51  *
52  * 07/10/95 (taylor)  Findfirst() returns the first file on NT.
53  * 05/03/96 (seiwald) split apart into pathnt.c
54  */
55
56 /*
57  * file_dirscan() - scan a directory for files
58  */
59
60 void file_dirscan( char * dir, scanback func, void * closure )
61 {
62     PROFILE_ENTER( FILE_DIRSCAN );
63
64     file_info_t * d = 0;
65
66     dir = short_path_to_long_path( dir );
67
68     /* First enter directory itself */
69
70     d = file_query( dir );
71
72     if ( !d || !d->is_dir )
73     {
74         PROFILE_EXIT( FILE_DIRSCAN );
75         return;
76     }
77
78     if ( !d->files )
79     {
80         PATHNAME f;
81         string filespec[ 1 ];
82         string filename[ 1 ];
83         long handle;
84         int ret;
85         struct _finddata_t finfo[ 1 ];
86         LIST * files = L0;
87         int d_length = strlen( d->name );
88
89         memset( (char *)&f, '\0', sizeof( f ) );
90
91         f.f_dir.ptr = d->name;
92         f.f_dir.len = d_length;
93
94         /* Now enter contents of directory */
95
96         /* Prepare file search specification for the findfirst() API. */
97         if ( d_length == 0 )
98             string_copy( filespec, ".\\*" );
99         else
100         {
101             /*
102              * We can not simply assume the given folder name will never include
103              * its trailing path separator or otherwise we would not support the
104              * Windows root folder specified without its drive letter, i.e. '\'.
105              */
106             char trailingChar = d->name[ d_length - 1 ] ;
107             string_copy( filespec, d->name );
108             if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
109                 string_append( filespec, "\\" );
110             string_append( filespec, "*" );
111         }
112
113         if ( DEBUG_BINDSCAN )
114             printf( "scan directory %s\n", dir );
115
116         #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
117         if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
118         {
119             string_free( filespec );
120             PROFILE_EXIT( FILE_DIRSCAN );
121             return;
122         }
123
124         string_new ( filename );
125         while ( !ret )
126         {
127             file_info_t * ff = 0;
128
129             f.f_base.ptr = finfo->ff_name;
130             f.f_base.len = strlen( finfo->ff_name );
131
132             string_truncate( filename, 0 );
133             path_build( &f, filename );
134
135             files = list_new( files, newstr(filename->value) );
136             ff = file_info( filename->value );
137             ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
138             ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
139             ff->size = finfo->ff_fsize;
140             ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime;
141
142             ret = findnext( finfo );
143         }
144         # else
145         handle = _findfirst( filespec->value, finfo );
146
147         if ( ret = ( handle < 0L ) )
148         {
149             string_free( filespec );
150             PROFILE_EXIT( FILE_DIRSCAN );
151             return;
152         }
153
154         string_new( filename );
155         while ( !ret )
156         {
157             file_info_t * ff = 0;
158
159             f.f_base.ptr = finfo->name;
160             f.f_base.len = strlen( finfo->name );
161
162             string_truncate( filename, 0 );
163             path_build( &f, filename, 0 );
164
165             files = list_new( files, newstr( filename->value ) );
166             ff = file_info( filename->value );
167             ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
168             ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
169             ff->size = finfo->size;
170             ff->time = finfo->time_write;
171
172             ret = _findnext( handle, finfo );
173         }
174
175         _findclose( handle );
176         # endif
177         string_free( filename );
178         string_free( filespec );
179
180         d->files = files;
181     }
182
183     /* Special case \ or d:\ : enter it */
184     {
185         unsigned long len = strlen(d->name);
186         if ( len == 1 && d->name[0] == '\\' )
187             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
188         else if ( len == 3 && d->name[1] == ':' ) {
189             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
190             /* We've just entered 3-letter drive name spelling (with trailing
191                slash), into the hash table. Now enter two-letter variant,
192                without trailing slash, so that if we try to check whether
193                "c:" exists, we hit it.
194
195                Jam core has workarounds for that. Given:
196                   x = c:\whatever\foo ;
197                   p = $(x:D) ;
198                   p2 = $(p:D) ;
199                There will be no trailing slash in $(p), but there will be one
200                in $(p2). But, that seems rather fragile.                
201             */
202             d->name[2] = 0;
203             (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
204         }
205     }
206
207     /* Now enter contents of directory */
208     if ( d->files )
209     {
210         LIST * files = d->files;
211         while ( files )
212         {
213             file_info_t * ff = file_info( files->string );
214             (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
215             files = list_next( files );
216         }
217     }
218
219     PROFILE_EXIT( FILE_DIRSCAN );
220 }
221
222 file_info_t * file_query( char * filename )
223 {
224     file_info_t * ff = file_info( filename );
225     if ( ! ff->time )
226     {
227         struct stat statbuf;
228
229         if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
230             return 0;
231
232         ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
233         ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
234         ff->size = statbuf.st_size;
235         ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
236     }
237     return ff;
238 }
239
240 /*
241  * file_time() - get timestamp of file, if not done by file_dirscan()
242  */
243
244 int
245 file_time(
246     char    *filename,
247     time_t  *time )
248 {
249     file_info_t * ff = file_query( filename );
250     if ( !ff ) return -1;
251     *time = ff->time;
252     return 0;
253 }
254
255 int file_is_file(char* filename)
256 {
257     file_info_t * ff = file_query( filename );
258     if ( !ff ) return -1;
259     return ff->is_file;
260 }
261
262 int file_mkdir(char *pathname)
263 {
264     return _mkdir(pathname);
265 }
266
267 /*
268  * file_archscan() - scan an archive for files
269  */
270
271 /* Straight from SunOS */
272
273 #define ARMAG   "!<arch>\n"
274 #define SARMAG  8
275
276 #define ARFMAG  "`\n"
277
278 struct ar_hdr {
279     char    ar_name[16];
280     char    ar_date[12];
281     char    ar_uid[6];
282     char    ar_gid[6];
283     char    ar_mode[8];
284     char    ar_size[10];
285     char    ar_fmag[2];
286 };
287
288 # define SARFMAG 2
289 # define SARHDR sizeof( struct ar_hdr )
290
291 void
292 file_archscan(
293     char *archive,
294     scanback func,
295     void *closure )
296 {
297     struct ar_hdr ar_hdr;
298     char *string_table = 0;
299     char buf[ MAXJPATH ];
300     long offset;
301     int fd;
302
303     if ( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
304         return;
305
306     if ( read( fd, buf, SARMAG ) != SARMAG ||
307         strncmp( ARMAG, buf, SARMAG ) )
308     {
309         close( fd );
310         return;
311     }
312
313     offset = SARMAG;
314
315     if ( DEBUG_BINDSCAN )
316         printf( "scan archive %s\n", archive );
317
318     while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
319            !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
320     {
321         long    lar_date;
322         long    lar_size;
323         char    *name = 0;
324         char    *endname;
325         char    *c;
326
327         sscanf( ar_hdr.ar_date, "%ld", &lar_date );
328         sscanf( ar_hdr.ar_size, "%ld", &lar_size );
329
330         lar_size = ( lar_size + 1 ) & ~1;
331
332         if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
333         {
334         /* this is the "string table" entry of the symbol table,
335         ** which holds strings of filenames that are longer than
336         ** 15 characters (ie. don't fit into a ar_name
337         */
338
339         string_table = BJAM_MALLOC_ATOMIC(lar_size+1);
340         if (read(fd, string_table, lar_size) != lar_size)
341             printf("error reading string table\n");
342         string_table[lar_size] = '\0';
343         offset += SARHDR + lar_size;
344         continue;
345         }
346         else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
347         {
348             /* Long filenames are recognized by "/nnnn" where nnnn is
349             ** the offset of the string in the string table represented
350             ** in ASCII decimals.
351             */
352
353             name = string_table + atoi( ar_hdr.ar_name + 1 );
354             for ( endname = name; *endname && *endname != '\n'; ++endname) {}
355         }
356         else
357         {
358             /* normal name */
359             name = ar_hdr.ar_name;
360             endname = name + sizeof( ar_hdr.ar_name );
361         }
362
363         /* strip trailing white-space, slashes, and backslashes */
364
365         while ( endname-- > name )
366             if ( !isspace(*endname) && ( *endname != '\\' ) && ( *endname != '/' ) )
367                 break;
368         *++endname = 0;
369
370         /* strip leading directory names, an NT specialty */
371
372         if ( c = strrchr( name, '/' ) )
373         name = c + 1;
374         if ( c = strrchr( name, '\\' ) )
375         name = c + 1;
376
377         sprintf( buf, "%s(%.*s)", archive, endname - name, name );
378         (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
379
380         offset += SARHDR + lar_size;
381         lseek( fd, offset, 0 );
382     }
383
384     close( fd );
385 }
386
387 # endif /* NT */