$! ------------------ CUT HERE ----------------------- $! $! This archive created by VMS_SHARE Version 7.1-001 26-JUN-1989 $! On 20-AUG-1990 19:59:48.69 By user TIHOR $! $! This VMS_SHARE Written by: $! Andy Harper, Kings College London UK $! $! Acknowledgements to: $! James Gray - Original VMS_SHARE $! Michael Bednarek - Original Concept and implementation $! $! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER $! AND EXECUTE AS A COMMAND PROCEDURE ( @name ) $! $! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING: $! 1. DIRENT.H;1 $! 2. READDIR.SH-HDR;1 $! 3. README.;1 $! 4. VMSREADDIR.C;1 $! $f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID")) $e="write sys$error ""%UNPACK"", " $w="write sys$output ""%UNPACK"", " $ if f$trnlnm("SHARE_LOG") then $ w = "!" $ if f$getsyi("version") .ges. "4.4" then $ goto START $ e "-E-OLDVER, Must run at least VMS 4.4" $ exit 44 $UNPACK: SUBROUTINE ! P1=filename, P2=checksum $ if f$search(P1) .eqs. "" then $ goto file_absent $ e "-W-EXISTS, File ''P1' exists. Skipped." $ delete/nolog 'f'* $ exit $file_absent: $ if f$parse(P1) .nes. "" then $ goto dirok $ dn=f$parse(P1,,,"DIRECTORY") $ w "-I-CREDIR, Creating directory ''dn'." $ create/dir 'dn' $ if $status then $ goto dirok $ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped." $ delete/nolog 'f'* $ exit $dirok: $ w "-I-PROCESS, Processing file ''P1'." $ define/user sys$output nl: $ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1' PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET( SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name"); buff:=CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(buff)) ;LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION( BEGINNING_OF(buff));g:=0;LOOP EXITIF MARK(NONE)=END_OF(buff);x:= ERASE_CHARACTER(1);IF g = 0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x= "V" THEN APPEND_LINE;MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF; IF x="+" THEN g:=1;ERASE_LINE;ENDIF;ELSE IF x="-" THEN g:=0;ENDIF;ERASE_LINE; ENDIF;ENDLOOP;p:="`";POSITION(BEGINNING_OF(buff));LOOP r:=SEARCH(p,FORWARD); EXITIF r=0;POSITION(r);ERASE(r);COPY_TEXT(ASCII(INT(ERASE_CHARACTER(3)))); ENDLOOP;o:=GET_INFO(COMMAND_LINE,"output_file");WRITE_FILE(buff,o); ENDPROCEDURE;Unpacker;EXIT; $ delete/nolog 'f'* $ CHECKSUM 'P1' $ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT $ e "-E-CHKSMFAIL, Checksum of ''P1' failed." $ ENDSUBROUTINE $START: $ create/nolog 'f' X/* X** Header file for VMS readdir() routines. X** Written by Rich $alz, in August, 1990. X** This code has no copyright. X** X** You must #include before this file. X*/ X X /* Data structure returned by READDIR(). */ Xstruct dirent `123 X char`009d_name`091100`093;`009`009/* File name`009`009*/ X int`009`009vms_verscount;`009`009/* Number of versions`009*/ X int`009`009vms_versions`09120`093;`009/* Version numbers`009*/ X`125; X X /* Handle returned by opendir(), used by the other routines. You X * are not supposed to care what's inside this structure. */ Xtypedef struct _dirdesc `123 X long`009`009`009context; X int`009`009`009`009vms_wantversions; X char`009`009`009*pattern; X struct dirent`009`009entry; X struct dsc$descriptor_s`009pat; X`125 DIR; X X X#define rewinddir(dirp)`009`009seekdir((dirp), 0L) X X Xextern DIR`009`009*opendir(); Xextern struct dirent`009*readdir(); Xextern long`009`009telldir(); Xextern void`009`009seekdir(); Xextern void`009`009closedir(); Xextern void`009`009vmsreaddirversions(); $ CALL UNPACK DIRENT.H;1 1582785354 $ create/nolog 'f' XRelay-Version: version nyu B notes v1.6 9/18/89; site acf4.NYU.EDU XFrom: rsalz@bbn.com (Rich Salz) XDate: 20 Aug 90 10:05 EDT XDate-Received: 20 Aug 90 10:56 EDT XSubject: A readdir() implementation for VMS XMessage-ID: <2772@litchi.bbn.com> XPath: acf4!cmcl2!yale!cs.utexas.edu!usc!bbn.com!papaya.bbn.com!rsalz XNewsgroups: comp.os.vms,alt.sources,comp.lang.c XOrganization: BBN Systems and Technology, Inc. XFollowup-to: --pick appropriate group-- XLines: 435 XXref: cmcl2 comp.os.vms:107018 alt.sources:2157 comp.lang.c:65000 X XI needed the "readdir" package for VMS. Other implementations I've seen Xall seemed to have lots of knowledge of the internals of the VMS directory Xstructure (eww, gross!) or didn't really handle file versions the way that XI needed them done. X XThe following code is in the public domain. I hope it gets very widespread Xuse. Enjoy. X`009/r$ X $ CALL UNPACK READDIR.SH-HDR;1 824849043 $ create/nolog 'f' X XThis code implements the Berkeley Unix "readdir" package. Readdir is an Xabstract interface for reading entries out of directories, and getting the Xnames of the files (and directories, etc.) contained therein. Versions Xexist for all Unix systems, MS-DOS, Amiga, and no doubt others as well. X XThis code was written by Rich $alz, in August, 1990, and Xhas no copyright. X X #include XThis header file must be included by any files that use any of the routines Xdescribed here. You must also #include first. X X DIR * X opendir(name) X`009char`009*name; XNAME is a filespec that names a directory. It does not have to be in Xstrict canonical form -- logicals such as "sys$login:" will be expanded. XOnce the directory has been opened, any of the other routines described Xhere can be used on the handle that is returned. X X X void X vmsreaddirversions(dd, flag) X`009DIR`009`009*dd; X`009int`009`009flag; XBy default, READDIR() ignores file versions, and returns a file name once, Xno matter how many versions it has. This routine can be used to collect Xthe version numbers in an that is returned with each file. The FLAG Xargument should be non-zero to collect version information, or zero to Xignore it. This routine can be called any number of times while the Xdirectory is open. X X X void X closedir(dd) X`009DIR`009`009*dd; XOnce you are finished reading the contents of a directory, the CLOSEDIR() Xroutine frees up all the storage associated with it, and invalidates the Xhandle. X X X struct dirent * X readdir(dd) X`009DIR`009`009*dd; XThe READDIR() routine takes a handle returned by OPENDIR() and returns the Xname of the next file in the directory, or a NULL pointer when there are Xno more files. The STRUCT DIRENT returned by this routine will have the Xfollowing fields that may be accessed by user code: X d_name`091`093`009`009A C character string with the file name X vms_verscount`009The number of versions the file has X vms_versions`091`093`009An array of the version numbers; the number -1 X`009`009`009indicates a file-parsing error. XNote that the fields starting with "vms_" are not part of the standard XREADDIR() library available on other systems, so strictly portable code Xshould take care to avoid using them except on VMS machines. X X long X telldir(dd) X`009DIR`009`009*dd; XThis routine returns a "magic cookie" that can be used in a later XSEEKDIR() call. This allows you to remember one or more spots while Xreading through a directory and return to them later. X X X void X seekdir(dd, pos) X`009DIR`009`009*dd; X`009long`009`009pos; XThe SEEKDIR() routine takes the "cookie" returned by a previous call to XTELLDIR() and sets the internal state so that the next READDIR() call will Xreturn the file read just after the TELLDIR() call. X X void X rewinddir(dd) X`009DIR`009`009*dd; XThe REWINDDIR() routine resets the internal state of the DD handle so that XREADDIR() starts reading over from the beginning of the directory. X XHere is a sample routine showing how to use the package: X main() X `123 X`009DIR`009`009*dd; X`009struct dirent`009*dp; X`009int`009`009i; X X`009if ((dd = opendir("sys$login")) == NULL) `123 X`009 perror(buff); X`009 continue; X`009`125 X`009vmsreaddirversions(dd, 1); X X`009while (dp = readdir(dd)) `123 X`009 printf("%s", dp->d_name); X`009 for (i = 0; i < dp->vms_verscount; i++) X`009`009printf(" %d", dp->vms_versions`091i`093); X`009 printf("\n"); X`009`125 X`009closedir(dd); X`009exit(0); X `125 $ CALL UNPACK README.;1 1313679286 $ create/nolog 'f' X/* X** VMS readdir() routines. X** Written by Rich $alz, in August, 1990. X** This code has no copyright. X*/ X#include X#include X#include X#include X#include X#include "dirent.h" X X /* Uncomment the next line to get a test routine. */ X/*#define TEST*/ X X /* Number of elements in vms_versions array */ X#define VERSIZE(e)`009(sizeof e->vms_versions / sizeof e->vms_versions`0910` V093) X X /* Linked in later. */ Xextern char`009*malloc(); Xextern char`009*strrchr(); Xextern char`009*strcpy(); X X X/* X** Open a directory, return a handle for later use. X*/ XDIR * Xopendir(name) X char`009*name; X`123 X DIR`009`009*dd; X X /* Get memory for the handle, and the pattern. */ X if ((dd = (DIR *)malloc(sizeof *dd)) == NULL) `123 X`009errno = ENOMEM; X`009return NULL; X `125 X dd->pattern = malloc((unsigned int)(strlen(name) + sizeof "*.*" + 1)); X if (dd->pattern == NULL) `123 X`009free((char *)dd); X`009errno = ENOMEM; X`009return NULL; X `125 X X /* Fill in the fields; mainly playing with the descriptor. */ X (void)sprintf(dd->pattern, "%s*.*", name); X dd->context = 0; X dd->vms_wantversions = 0; X dd->pat.dsc$a_pointer = dd->pattern; X dd->pat.dsc$w_length = strlen(dd->pattern); X dd->pat.dsc$b_dtype = DSC$K_DTYPE_T; X dd->pat.dsc$b_class = DSC$K_CLASS_S; X X return dd; X`125 X X X/* X** Set the flag to indicate we want versions or not. X*/ Xvoid Xvmsreaddirversions(dd, flag) X DIR`009`009*dd; X int`009`009flag; X`123 X dd->vms_wantversions = flag; X`125 X X X/* X** Free up an opened directory. X*/ Xvoid Xclosedir(dd) X DIR`009`009*dd; X`123 X free(dd->pattern); X free((char *)dd); X`125 X X X/* X** Collect all the version numbers for the current file. X*/ Xstatic void Xcollectversions(dd) X DIR`009`009`009`009*dd; X`123 X struct dsc$descriptor_s`009pat; X struct dsc$descriptor_s`009res; X struct dirent`009`009*e; X char`009`009`009*p; X char`009`009`009buff`091sizeof dd->entry.d_name`093; X int`009`009`009`009i; X char`009`009`009*text; X long`009`009`009context; X X /* Convenient shorthand. */ X e = &dd->entry; X X /* Add the version wildcard, ignoring the "*.*" put on before */ X i = strlen(dd->pattern); X text = malloc((unsigned int)(i + strlen(e->d_name)+ 2 + 1)); X if (text == NULL) X`009return; X (void)strcpy(text, dd->pattern); X (void)sprintf(&text`091i - 3`093, "%s;*", e->d_name); X X /* Set up the pattern descriptor. */ X pat.dsc$a_pointer = text; X pat.dsc$w_length = strlen(text); X pat.dsc$b_dtype = DSC$K_DTYPE_T; X pat.dsc$b_class = DSC$K_CLASS_S; X X /* Set up result descriptor. */ X res.dsc$a_pointer = buff; X res.dsc$w_length = sizeof buff - 2; X res.dsc$b_dtype = DSC$K_DTYPE_T; X res.dsc$b_class = DSC$K_CLASS_S; X X /* Read files, collecting versions. */ X for (context = 0; e->vms_verscount < VERSIZE(e); e->vms_verscount++) `12 V3 X`009if (lib$find_file(&pat, &res, &context) == RMS$_NMF `124`124 context == V 0) X`009 break; X`009buff`091sizeof buff - 1`093 = '\0'; X`009if (p = strchr(buff, ';')) X`009 e->vms_versions`091e->vms_verscount`093 = atoi(p + 1); X`009else X`009 e->vms_versions`091e->vms_verscount`093 = -1; X `125 X X free(text); X`125 X X X/* X** Read the next entry from the directory. X*/ Xstruct dirent * Xreaddir(dd) X DIR`009`009`009`009*dd; X`123 X struct dsc$descriptor_s`009res; X char`009`009`009*p; X char`009`009`009buff`091sizeof dd->entry.d_name`093; X int`009`009`009`009i; X X /* Set up result descriptor, and get next file. */ X res.dsc$a_pointer = buff; X res.dsc$w_length = sizeof buff - 2; X res.dsc$b_dtype = DSC$K_DTYPE_T; X res.dsc$b_class = DSC$K_CLASS_S; X if (lib$find_file(&dd->pat, &res, &dd->context) == RMS$_NMF X `124`124 dd->context == 0L) X`009/* None left... */ X`009return NULL; X X /* Force the buffer to end with a NUL. */ X buff`091sizeof buff - 1`093 = '\0'; X for (p = buff; !isspace(*p); p++) X`009; X *p = '\0'; X X /* Skip any directory component and just copy the name. */ X if (p = strchr(buff, '`093')) X`009(void)strcpy(dd->entry.d_name, p + 1); X else X`009(void)strcpy(dd->entry.d_name, buff); X X /* Clobber the version. */ X if (p = strchr(dd->entry.d_name, ';')) X`009*p = '\0'; X X dd->entry.vms_verscount = 0; X if (dd->vms_wantversions) X`009collectversions(dd); X return &dd->entry; X`125 X X X/* X** Return something that can be used in a seekdir later. X*/ Xlong Xtelldir(dd) X DIR`009`009*dd; X`123 X return dd->context; X`125 X X X/* X** Return to a spot where we used to be. X*/ Xvoid Xseekdir(dd, pos) X DIR`009`009*dd; X long`009pos; X`123 X dd->context = pos; X`125 X X X#ifdef`009TEST Xmain() X`123 X char`009`009buff`091256`093; X DIR`009`009`009*dd; X struct dirent`009*dp; X int`009`009`009i; X int`009`009`009j; X X for ( ; ; ) `123 X`009printf("\n\nEnter dir: "); X`009(void)fflush(stdout); X`009(void)gets(buff); X`009if (buff`0910`093 == '\0') X`009 break; X`009if ((dd = opendir(buff)) == NULL) `123 X`009 perror(buff); X`009 continue; X`009`125 X X`009/* Print the directory contents twice, the second time print X`009 * the versions. */ X`009for (i = 0; i < 2; i++) `123 X`009 while (dp = readdir(dd)) `123 X`009`009printf("%s%s", i ? "\t" : " ", dp->d_name); X`009`009for (j = 0; j < dp->vms_verscount; j++) X`009`009 printf(" %d", dp->vms_versions`091j`093); X`009`009printf("\n"); X`009 `125 X`009 rewinddir(dd); X`009 vmsreaddirversions(dd, 1); X`009`125 X`009closedir(dd); X `125 X exit(0); X`125 X#endif`009/* TEST */ $ CALL UNPACK VMSREADDIR.C;1 1616695178 $ EXIT