2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
8 * filevms.c - scan directories and libaries on VMS
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
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().
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
47 #include <lib$routines.h>
50 /* Supply missing prototypes for lbr$-routines*/
57 struct dsc$descriptor_s
*,
61 int lbr$
open( void **,
62 struct dsc$descriptor_s
*,
78 int (*func
)( struct dsc$descriptor_s
*, unsigned long *),
88 unsigned int *curtime
,
91 static const size_t divisor
= 10000000;
92 static unsigned int bastim
[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
93 int delta
[2], remainder
;
95 lib$
subx( curtime
, bastim
, delta
);
96 lib$
ediv( &divisor
, delta
, unixtime
, &remainder
);
99 # define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
101 # define min( a,b ) ((a)<(b)?(a):(b))
120 memset( (char *)&f
, '\0', sizeof( f
) );
123 f
.f_root
.len
= strlen( dir
);
125 /* get the input file specification
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
);
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 */
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 */
147 status
= sys$
parse( &xfab
);
150 printf( "scan directory %s\n", dir
);
152 if ( !( status
& 1 ) )
157 /* Add bogus directory for [000000] */
159 if( !strcmp( dir
, "[000000]" ) )
161 (*func
)( closure
, "[000000]", 1 /* time valid */, 1 /* old but true */ );
164 /* Add bogus directory for [] */
166 if( !strcmp( dir
, "[]" ) )
168 (*func
)( closure
, "[]", 1 /* time valid */, 1 /* old but true */ );
169 (*func
)( closure
, "[-]", 1 /* time valid */, 1 /* old but true */ );
172 while ( (status
= sys$
search( &xfab
)) & 1 )
177 /* "I think that might work" - eml */
182 file_cvttime( (unsigned int *)&xab
.xab$q_rdt
, &time
);
184 filename
[xnam
.nam$b_rsl
] = '\0';
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 */
191 if( xnam
.nam$b_type
== 4 && !strncmp( xnam
.nam$l_type
, ".DIR", 4 ) )
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
);
204 /* normal file with a suffix */
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
;
213 path_build( &f
, filename2
, 0 );
217 printf("root '%s' base %.*s suf %.*s = %s\n",
219 xnam.nam$b_name, xnam.nam$l_name,
220 xnam.nam$b_type, xnam.nam$l_type,
224 (*func
)( closure
, filename2
, 1 /* time valid */, time
);
230 const char *filename
,
233 /* This should never be called, as all files are */
234 /* timestampped in file_dirscan() and file_archscan() */
238 static char *VMS_archive
= 0;
239 static scanback VMS_func
;
240 static void *VMS_closure
;
241 static void *context
;
245 struct dsc$descriptor_s
*module
,
248 static struct dsc$descriptor_s bufdsc
=
249 {0, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, NULL
};
253 char buf
[ MAXJPATH
];
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
);
269 mhd
= (struct mhddef
*)filename
;
271 file_cvttime( &mhd
->mhd$l_datim
, &library_date
);
273 for ( i
= 0, p
= module
->dsc$a_pointer
; i
< module
->dsc$w_length
; i
++, p
++ )
278 sprintf( buf
, "%s(%s.obj)", VMS_archive
, filename
);
280 (*VMS_func
)( VMS_closure
, buf
, 1 /* time valid */, (time_t)library_date
);
291 static struct dsc$descriptor_s library
=
292 {0, DSC$K_DTYPE_T
, DSC$K_CLASS_S
, NULL
};
294 unsigned long lfunc
= LBR$C_READ
;
295 unsigned long typ
= LBR$C_TYP_UNK
;
296 unsigned long index
= 1;
300 VMS_archive
= (char *)archive
;
302 VMS_closure
= closure
;
304 status
= lbr$
ini_control( &context
, &lfunc
, &typ
, NULL
);
305 if ( !( status
& 1 ) )
308 library
.dsc$a_pointer
= (char *)archive
;
309 library
.dsc$w_length
= strlen( archive
);
311 status
= lbr$
open( &context
, &library
, NULL
, NULL
, NULL
, NULL
, NULL
);
312 if ( !( status
& 1 ) )
315 (void) lbr$
get_index( &context
, &index
, file_archmember
, NULL
);
317 (void) lbr$
close( &context
);