1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*
8 * filevms.c - scan directories and libaries on VMS
9 *
10 * External routines:
11 *
12 *	file_dirscan() - scan a directory for files
13 *	file_time() - get timestamp of file, if not done by file_dirscan()
14 *	file_archscan() - scan an archive for files
15 *
16 * File_dirscan() and file_archscan() call back a caller provided function
17 * for each file found.  A flag to this callback function lets file_dirscan()
18 * and file_archscan() indicate that a timestamp is being provided with the
19 * file.   If file_dirscan() or file_archscan() do not provide the file's
20 * timestamp, interested parties may later call file_time().
21 *
22 * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
23 * 05/03/96 (seiwald) - split into pathvms.c
24 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
25 * 03/23/01 (seiwald) - VMS C++ changes.
26 * 11/04/02 (seiwald) - const-ing for string literals
27 */
28
29# include "jam.h"
30# include "filesys.h"
31# include "pathsys.h"
32
33# ifdef OS_VMS
34
35# include <rms.h>
36# include <iodef.h>
37# include <ssdef.h>
38# include <string.h>
39# include <stdlib.h>
40# include <stdio.h>
41# include <descrip.h>
42
43#include <lbrdef.h>
44#include <credef.h>
45#include <mhddef.h>
46#include <lhidef.h>
47#include <lib$routines.h>
48#include <starlet.h>
49
50/* Supply missing prototypes for lbr$-routines*/
51
52extern "C" {
53
54int lbr$set_module(
55	void **,
56	unsigned long *,
57	struct dsc$descriptor_s *,
58	unsigned short *,
59	void * );
60
61int lbr$open( void **,
62	struct dsc$descriptor_s *,
63	void *,
64	void *,
65	void *,
66	void *,
67	void * );
68
69int lbr$ini_control(
70	void **,
71	unsigned long *,
72	unsigned long *,
73	void * );
74
75int lbr$get_index(
76	void **,
77	unsigned long *,
78	int (*func)( struct dsc$descriptor_s *, unsigned long *),
79	void * );
80
81int lbr$close(
82	void ** );
83
84}
85
86static void
87file_cvttime(
88    unsigned int *curtime,
89    time_t *unixtime )
90{
91    static const size_t divisor = 10000000;
92    static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
93    int delta[2], remainder;
94
95    lib$subx( curtime, bastim, delta );
96    lib$ediv( &divisor, delta, unixtime, &remainder );
97}
98
99# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
100
101# define min( a,b ) ((a)<(b)?(a):(b))
102
103void
104file_dirscan(
105	const char *dir,
106	scanback func,
107	void	*closure )
108{
109
110    struct FAB xfab;
111    struct NAM xnam;
112    struct XABDAT xab;
113    char esa[256];
114    char filename[256];
115    char filename2[256];
116    char dirname[256];
117    register int status;
118    PATHNAME f;
119
120    memset( (char *)&f, '\0', sizeof( f ) );
121
122    f.f_root.ptr = dir;
123    f.f_root.len = strlen( dir );
124
125	/* get the input file specification
126	 */
127    xnam = cc$rms_nam;
128    xnam.nam$l_esa = esa;
129    xnam.nam$b_ess = sizeof( esa ) - 1;
130    xnam.nam$l_rsa = filename;
131    xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
132
133    xab = cc$rms_xabdat;                /* initialize extended attributes */
134    xab.xab$b_cod = XAB$C_DAT;		/* ask for date */
135    xab.xab$l_nxt = NULL;               /* terminate XAB chain      */
136
137    xfab = cc$rms_fab;
138    xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
139    xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
140    xfab.fab$l_fop = FAB$M_NAM;
141    xfab.fab$l_fna = (char *)dir;		/* address of file name	    */
142    xfab.fab$b_fns = strlen( dir );		/* length of file name	    */
143    xfab.fab$l_nam = &xnam;			/* address of NAB block	    */
144    xfab.fab$l_xab = (char *)&xab;       /* address of XAB block     */
145
146
147    status = sys$parse( &xfab );
148
149    if( DEBUG_BINDSCAN )
150	printf( "scan directory %s\n", dir );
151
152    if ( !( status & 1 ) )
153	return;
154
155
156
157    /* Add bogus directory for [000000] */
158
159    if( !strcmp( dir, "[000000]" ) )
160    {
161	(*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ );
162    }
163
164    /* Add bogus directory for [] */
165
166    if( !strcmp( dir, "[]" ) )
167    {
168	(*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ );
169	(*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ );
170    }
171
172    while ( (status = sys$search( &xfab )) & 1 )
173    {
174	char *s;
175	time_t time;
176
177	/* "I think that might work" - eml */
178
179	sys$open( &xfab );
180	sys$close( &xfab );
181
182	file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
183
184	filename[xnam.nam$b_rsl] = '\0';
185
186	/* What we do with the name depends on the suffix: */
187	/* .dir is a directory */
188	/* .xxx is a file with a suffix */
189	/* . is no suffix at all */
190
191	if( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
192	{
193	    /* directory */
194	    sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
195	    f.f_dir.ptr = dirname;
196	    f.f_dir.len = strlen( dirname );
197	    f.f_base.ptr = 0;
198	    f.f_base.len = 0;
199	    f.f_suffix.ptr = 0;
200	    f.f_suffix.len = 0;
201	}
202	else
203	{
204	    /* normal file with a suffix */
205	    f.f_dir.ptr = 0;
206	    f.f_dir.len = 0;
207	    f.f_base.ptr = xnam.nam$l_name;
208	    f.f_base.len = xnam.nam$b_name;
209	    f.f_suffix.ptr = xnam.nam$l_type;
210	    f.f_suffix.len = xnam.nam$b_type;
211	}
212
213	path_build( &f, filename2, 0 );
214
215	/*
216	if( DEBUG_SEARCH )
217	    printf("root '%s' base %.*s suf %.*s = %s\n",
218		    dir,
219		    xnam.nam$b_name, xnam.nam$l_name,
220		    xnam.nam$b_type, xnam.nam$l_type,
221		    filename2);
222	*/
223
224	(*func)( closure, filename2, 1 /* time valid */, time );
225    }
226}
227
228int
229file_time(
230	const char *filename,
231	time_t	*time )
232{
233	/* This should never be called, as all files are */
234	/* timestampped in file_dirscan() and file_archscan() */
235	return -1;
236}
237
238static char *VMS_archive = 0;
239static scanback VMS_func;
240static void *VMS_closure;
241static void *context;
242
243static int
244file_archmember(
245    struct dsc$descriptor_s *module,
246    unsigned long *rfa )
247{
248    static struct dsc$descriptor_s bufdsc =
249		  {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
250
251    struct mhddef *mhd;
252    char filename[128];
253    char buf[ MAXJPATH ];
254
255    int status;
256    time_t library_date;
257
258    register int i;
259    register char *p;
260
261    bufdsc.dsc$a_pointer = filename;
262    bufdsc.dsc$w_length = sizeof( filename );
263    status = lbr$set_module( &context, rfa, &bufdsc,
264			     &bufdsc.dsc$w_length, NULL );
265
266    if ( !(status & 1) )
267	return ( 1 );
268
269    mhd = (struct mhddef *)filename;
270
271    file_cvttime( &mhd->mhd$l_datim, &library_date );
272
273    for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; i++, p++ )
274	filename[i] = *p;
275
276    filename[i] = '\0';
277
278    sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
279
280    (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date );
281
282    return ( 1 );
283}
284
285void
286file_archscan(
287	const char *archive,
288	scanback func,
289	void	*closure )
290{
291    static struct dsc$descriptor_s library =
292		  {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
293
294    unsigned long lfunc = LBR$C_READ;
295    unsigned long typ = LBR$C_TYP_UNK;
296    unsigned long index = 1;
297
298    register int status;
299
300    VMS_archive = (char *)archive;
301    VMS_func = func;
302    VMS_closure = closure;
303
304    status = lbr$ini_control( &context, &lfunc, &typ, NULL );
305    if ( !( status & 1 ) )
306	return;
307
308    library.dsc$a_pointer = (char *)archive;
309    library.dsc$w_length = strlen( archive );
310
311    status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
312    if ( !( status & 1 ) )
313	return;
314
315    (void) lbr$get_index( &context, &index, file_archmember, NULL );
316
317    (void) lbr$close( &context );
318}
319
320# endif /* VMS */
321
322