summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/build/src/engine/filevms.cpp
blob: 6dc84ae633be496e81f2e67f5a7ae8197b43b73d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*
 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
 *
 * This file is part of Jam - see jam.c for Copyright information.
 */

/*  This file is ALSO:
 *  Copyright 2001-2004 David Abrahams.
 *  Copyright 2005 Rene Rivera.
 *  Copyright 2015 Artur Shepilko.
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt)
 */


#include "jam.h"
#include "filesys.h"

#include "object.h"
#include "pathsys.h"
#include "jam_strings.h"


#ifdef OS_VMS

/*
 * filevms.c - manipulate file names and scan directories on VMS.
 *
 * This implementation is based on POSIX-style path manipulation.
 *
 * VMS CTRL directly supports both POSIX- and native VMS-style path expressions,
 * with the POSIX-to-VMS path translation performed internally by the same
 * set of functions. For the most part such processing is transparent, with
 * few differences mainly related to file versions (in POSIX mode only the recent
 * version is visible).
 *
 * This should allow us to re-use fileunix.c implementation,
 * excluding archive/library member processing.
 *
 * Thus in jam-files the path references can also remain POSIX/UNIX-style on all
 * levels EXCEPT in actions scope, where these must be translated to the native
 * VMS-style. This approach is somewhat similar to jam CYGWIN handling.
 *
 *
 * External routines:
 *  file_archscan()                 - scan an archive for files
 *  file_mkdir()                    - create a directory
 *  file_supported_fmt_resolution() - file modification timestamp resolution
 *
 * External routines called only via routines in filesys.c:
 *  file_collect_dir_content_() - collects directory content information
 *  file_dirscan_()             - OS specific file_dirscan() implementation
 *  file_query_()               - query information about a path from the OS
 *  file_collect_archive_content_() - collects information about archive members
 *  file_archivescan_()         - OS specific file_archivescan() implementation
 */

#include <assert.h>
#include <stdio.h>

#include <sys/stat.h>  /* needed for mkdir() */
#include <unistd.h>  /* needed for read and close prototype */

#include <dirent.h>
#define STRUCT_DIRENT struct dirent


void path_translate_to_os_( char const * f, string * file );

/*
 * file_collect_dir_content_() - collects directory content information
 */

int file_collect_dir_content_( file_info_t * const d )
{
    LIST * files = L0;
    PATHNAME f;
    DIR * dd;
    STRUCT_DIRENT * dirent;
    string path[ 1 ];
    char const * dirstr;

    assert( d );
    assert( d->is_dir );
    assert( list_empty( d->files ) );

    dirstr = object_str( d->name );

    memset( (char *)&f, '\0', sizeof( f ) );
    f.f_dir.ptr = dirstr;
    f.f_dir.len = strlen( dirstr );

    if ( !*dirstr ) dirstr = ".";

    if ( !( dd = opendir( dirstr ) ) )
        return -1;

    string_new( path );
    while ( ( dirent = readdir( dd ) ) )
    {
        OBJECT * name;
        f.f_base.ptr = dirent->d_name
        #ifdef old_sinix
            - 2  /* Broken structure definition on sinix. */
        #endif
            ;
        f.f_base.len = strlen( f.f_base.ptr );

        string_truncate( path, 0 );
        path_build( &f, path );
        name = object_new( path->value );
        /* Immediately stat the file to preserve invariants. */
        if ( file_query( name ) )
            files = list_push_back( files, name );
        else
            object_free( name );
    }
    string_free( path );

    closedir( dd );

    d->files = files;
    return 0;
}


/*
 * file_dirscan_() - OS specific file_dirscan() implementation
 */

void file_dirscan_( file_info_t * const d, scanback func, void * closure )
{
    assert( d );
    assert( d->is_dir );

    /* Special case / : enter it */
    if ( !strcmp( object_str( d->name ), "/" ) )
        (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
}


/*
 * file_mkdir() - create a directory
 */

int file_mkdir( char const * const path )
{
    /* Explicit cast to remove const modifiers and avoid related compiler
     * warnings displayed when using the intel compiler.
     */
    return mkdir( (char *)path, 0777 );
}


/*
 * file_query_() - query information about a path from the OS
 */

void file_query_( file_info_t * const info )
{
    file_query_posix_( info );
}


/*------------------------------------------------------------------------------
* VMS-specific processing:
*
*/

#include <descrip.h>
#include <lbrdef.h>
#include <credef.h>
#include <mhddef.h>
#include <lhidef.h>
#include <lib$routines.h>
#include <starlet.h>

/* Supply missing prototypes for lbr$-routines*/

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int lbr$set_module(
    void **,
    unsigned long *,
    struct dsc$descriptor_s *,
    unsigned short *,
    void * );

int lbr$open( void **,
    struct dsc$descriptor_s *,
    void *,
    void *,
    void *,
    void *,
    void * );

int lbr$ini_control(
    void **,
    unsigned long *,
    unsigned long *,
    void * );

int lbr$get_index(
    void **,
    unsigned long * const,
    int (*func)( struct dsc$descriptor_s *, unsigned long *),
    void * );

int lbr$search(
    void **,
    unsigned long * const,
    unsigned short *,
    int (*func)( struct dsc$descriptor_s *, unsigned long *),
    unsigned long *);

int lbr$close(
    void ** );

#ifdef __cplusplus
}
#endif /* __cplusplus */



static void
file_cvttime(
    unsigned int *curtime,
    time_t *unixtime )
{
    static const int32_t divisor = 10000000;
    static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
    int delta[2], remainder;

    lib$subx( curtime, bastim, delta );
    lib$ediv( &divisor, delta, unixtime, &remainder );
}


static void downcase_inplace( char * p )
{
    for ( ; *p; ++p )
        *p = tolower( *p );
}


static file_archive_info_t * m_archive = NULL;
static file_info_t * m_member_found = NULL;
static void * m_lbr_context = NULL;
static unsigned short * m_rfa_found = NULL;
static const unsigned long LBR_MODINDEX_NUM = 1,
                           LBR_SYMINDEX_NUM = 2;  /* GST:global symbol table */


static unsigned int set_archive_symbol( struct dsc$descriptor_s *symbol,
                                        unsigned long *rfa )
{
    file_info_t * member = m_member_found;
    char buf[ MAXJPATH ] = { 0 };

    strncpy(buf, symbol->dsc$a_pointer, symbol->dsc$w_length);
    buf[ symbol->dsc$w_length ] = 0;

    member->files = list_push_back( member->files, object_new( buf ) );

    return ( 1 ); /* continue */
}


static unsigned int set_archive_member( struct dsc$descriptor_s *module,
                                        unsigned long *rfa )
{
    file_archive_info_t * archive = m_archive;

    static struct dsc$descriptor_s bufdsc =
          {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};

    struct mhddef *mhd;
    char filename[128] = { 0 };
    char buf[ MAXJPATH ] = { 0 };

    int status;
    time_t library_date;

    register int i;
    register char *p;

    bufdsc.dsc$a_pointer = filename;
    bufdsc.dsc$w_length = sizeof( filename );
    status = lbr$set_module( &m_lbr_context, rfa, &bufdsc,
                 &bufdsc.dsc$w_length, NULL );

    if ( !(status & 1) )
        return ( 1 );  /* continue */

    mhd = (struct mhddef *)filename;

    file_cvttime( &mhd->mhd$l_datim, &library_date );

    /* strncpy( filename, module->dsc$a_pointer, module->dsc$w_length );
    */
    for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; ++i, ++p )
    filename[ i ] = *p;

    filename[ i ] = '\0';

    if ( strcmp( filename, "" ) != 0 )
    {
        file_info_t * member = 0;

        /* Construct member's filename as lowercase "module.obj" */
        sprintf( buf, "%s.obj", filename );
        downcase_inplace( buf );
        archive->members = filelist_push_back( archive->members, object_new( buf ) );

        member = filelist_back( archive->members );
        member->is_file = 1;
        member->is_dir = 0;
        member->exists = 0;
        timestamp_init( &member->time, (time_t)library_date, 0 );

        m_member_found = member;
        m_rfa_found = rfa;
        status = lbr$search(&m_lbr_context, &LBR_SYMINDEX_NUM, m_rfa_found, set_archive_symbol, NULL);
    }

    return ( 1 ); /* continue */
}



void file_archscan( char const * arch, scanback func, void * closure )
{
    OBJECT * path = object_new( arch );
    file_archive_info_t * archive = file_archive_query( path );

    object_free( path );

    if ( filelist_empty( archive->members ) )
    {
        if ( DEBUG_BINDSCAN )
            out_printf( "scan archive %s\n", object_str( archive->file->name ) );

        if ( file_collect_archive_content_( archive ) < 0 )
            return;
    }

    /* Report the collected archive content. */
    {
        FILELISTITER iter = filelist_begin( archive->members );
        FILELISTITER const end = filelist_end( archive->members );
        char buf[ MAXJPATH ];

        for ( ; iter != end ; iter = filelist_next( iter ) )
        {
            file_info_t * member_file = filelist_item( iter );
            LIST * symbols = member_file->files;

            /* Construct member path: 'archive-path(member-name)'
             */
            sprintf( buf, "%s(%s)",
                object_str( archive->file->name ),
                object_str( member_file->name ) );
            {
                OBJECT * const member = object_new( buf );
                (*func)( closure, member, 1 /* time valid */, &member_file->time );
                object_free( member );
            }
        }
    }
}


/*
 *  file_archivescan_()         - OS specific file_archivescan() implementation
 */
void file_archivescan_( file_archive_info_t * const archive, archive_scanback func,
                        void * closure )
{
}


/*
 *  file_collect_archive_content_() - collects information about archive members
 */

int file_collect_archive_content_( file_archive_info_t * const archive )
{
    unsigned short rfa[3];

    static struct dsc$descriptor_s library =
          {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};

    unsigned long lfunc = LBR$C_READ;
    unsigned long typ = LBR$C_TYP_UNK;

    register int status;
    string buf[ 1 ];
    char vmspath[ MAXJPATH ] = { 0 };

    m_archive = archive;

    if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members );

    /*  Translate path to VMS
     */
    string_new( buf );
    path_translate_to_os_( object_str( archive->file->name ), buf );
    strcpy( vmspath, buf->value );
    string_free( buf );


    status = lbr$ini_control( &m_lbr_context, &lfunc, &typ, NULL );
    if ( !( status & 1 ) )
        return -1;

    library.dsc$a_pointer = vmspath;
    library.dsc$w_length = strlen( vmspath );

    status = lbr$open( &m_lbr_context, &library, NULL, NULL, NULL, NULL, NULL );
    if ( !( status & 1 ) )
        return -1;

    /*  Scan main index for modules.
     *  For each module search symbol-index to collect module's symbols.
     */
    status = lbr$get_index( &m_lbr_context, &LBR_MODINDEX_NUM, set_archive_member, NULL );

    if ( !( status & 1 ) )
        return -1;


    (void) lbr$close( &m_lbr_context );

    return 0;
}

#endif  /* OS_VMS */