Copyright 1991-2016 by Kevin G. Barkes All rights reserved. This article may be duplicated or redistributed provided no alterations of any kind are made to this file. This edition of DCL Dialogue is sponsored by Networking Dynamics, developers and marketers of productivity software for OpenVMS systems. Contact our website www.networkingdynamics.com to download free demos of our software and see how you will save time, money and raise productivity! Be sure to mention DCL Dialogue! DCL DIALOGUE Originally published December, 1991 Even More Stupid DCL Tricks By Kevin G. Barkes It's the end of the year, my desk looks like the remains of a stationery store explosion, and I'm a week behind deadline. So, gentle readers, it's time once again to delve into the wonderfully wacky world of stupid DCL tricks, or Stuff I Would Have Already Known If I Had Read The Release Notes Before Calling The CSC. INSTANT FILE NAME While file i/o in DCL should be avoided due to performance issues, it's sometimes necessary. You may need to write the output of a command to a file for later reference, or generate a temporary command file which is executed and deleted. The creation of temporary files under VMS can be a tricky thing. Multiple users may use the same command file, and if the procedure blindly creates a temporary file in a common directory with a "hard-coded" file name, unpleasantries can result. I use a little one-line .COM file called GENNAME.COM (Program 1) to do my temp file naming for me. The call to the F$GETJPI lexical function returns the ten-digit process identification number of the user process which executes the procedure. For example, something like: 0000005219 The F$CVTIME lexical provides us with the current date and time in the form of: 1991-10-25 14:11:18.06 Of course, the space, colons and period are invalid characters when used in a VMS file name. The hyphens, while legal, can be a bit confusing, and my preference is to eliminate them. We use DCL's string reduction capability to remove the errant characters. The line is a bit hard to read because the hyphen character is used for several purposes. The hyphens following F$CVTIME() and the "." are DCL continuation characters, which tell DCL the command continues on the next lines. The hyphens contained in quotes are characters we wish to remove from the string. Finally, the remaining hyphens (those surrounded by spaces) act as DCL string reduction operators. So, the date and time string returned by F$CVTIME() is reduced to: 1991102514111806 ".TMP" is added to the string using the + concatenation operator, placing in the global symbol GENNAME the file name 00000052191991102514111806.TMP composed of the process id and the date and time at one-hundredth of a second resolution. This provides a pretty much completely unique file name. There are some rather bizarre circumstances under which it wouldn't be totally unique, but thinking about them gives me a headache. Parenthetically, I was discussing string concatenation and reduction during a recent DCL class to whom I'd just explained the marvels of DEC command qualifer syntax. They were somewhat numbed by such usage as /NODISUSER, /NOPAUSE, and /NOSUSPEND. When I asked them what was the opposite of concatenation, one responded "Noconcatenation?" ****************************** SUPER SCOPING The SET SYMBOL command originally surfaced in one of the later "point" releases of VMS Version 4. It permitted the masking of symbols to DCL at the local or global level so that they did not interfere with expected command procedure execution. For example, say you defined the symbol DELETE to equal DELETE/CONFIRM/LOG in your LOGIN.COM file. You executed a command procedure that created several temporary files and later tried to delete them. At each deletion attempt, you'd be prompted to enter a "Y" or "N" to confirm deletion. By using the SET SYMBOL/SCOPE=NOGLOBAL command, you could turn off DCL's ability to access global symbols, thus eliminating the DELETE problem. Unfortunately, it also eliminated the ability to create any new global symbols. Since the last time I looked closely at the DCL Dictionary, DEC added /GENERAL and /VERB qualifiers to SET SYMBOL's /SCOPE qualifier. There are some peculiarities involved with their use (you should read the doc on this one), but basically the concept is simple. When you issue the command $ SET SYMBOL/SCOPE=NOGLOBAL/VERB DCL will not attempt to translate the first word on the command line to see if it's a symbol. It just tries to execute the word as a command. So, in our example, instead of translating DELETE to DELETE/CONFIRM/LOG, it just executes the plain vanilla DELETE command. What makes the /VERB qualifier particularly useful is that it does not affect the way DCL translates other symbols which might exist on the command line. This makes it much more versatile than the plain /SCOPE=NOGLOBAL qualifier, which totally shuts down all global symbol translations and assignments. SET SYMBOL also has a /GENERAL qualifier which causes DCL to translate ONLY the first word on the command line and to inhibit translation of the remaining symbols which may exist on the line; in other words, the reverse of /VERB. Maybe they should have called it /NOVERB. Or /NOUN? *************************** Glen Hoffing of GE Aerospace in Camden, NJ provides a command procedure (Program 2) which makes file "housekeeping" a bit easier. PURGE_MIDDLE.COM deletes all versions of a file except the oldest and the newest, and accepts full wildcarding. "When I make changes to one or more modules in a software application," Glen explains, "it generally takes me several code/compile/debug iterations before I get it right. When I am done, I want to save the oldest (baseline) version of the source, and the newest, and delete all the intermediate versions. This command file allows me to do this automatically." As with all procedures which use the DELETE command, be certain to test it in a directory with expendable scratch files. Otherwise, enjoy. And happy holidays to you all. *************************** Kevin G. Barkes is an independent consultant and occasional reader of DEC documentation. He publishes the KGB Report newsletter, operates the www.kgbreport.com website, lurks on comp.os.vms and can be reached at kgbarkes@gmail.com. ************************** PROGRAM 1: $! GENNAME.COM $ GENNAME == F$GETJPI("","PID") - + F$CVTIME() - - "-" - "-" - " " - ":" - ":" - "." - + ".TMP" ************************** PROGRAM 2: $! PURGE_MIDDLE.COM $ OLD_FN = "" !Initialize previous file name $ OLD_FT = "" !Initialize previous file type $ LOOP: !Loop through each file $ FIL = F$SEARCH(P1+";*",1) !Get file name $ IF (FIL .NES. "") !If file name not blank... $ THEN $ FN = F$PARSE(FIL,,,"NAME") !Get file name $ FT = F$PARSE(FIL,,,"TYPE") !Get file type $ VNO = F$PARSE(FIL,,,"VERSION") !Get file version $! Eliminate the ";" from the version number: $ VNO = F$EXTRACT(1,F$LENGTH(VNO)-1,VNO) $ IF (FN .NES. OLD_FN .OR. FT .NES. OLD_FT) $ THEN !If this is an old file name $! If previous name found $ IF (OLD_FN .NES. "" .OR. OLD_FT .NES. "") $ THEN !if more than 1 version $ IF (VNO_LOW .NES. VNO_HIGH) $ THEN ! Purge middle versions of files $ DEL 'OLD_FN''OLD_FT';*- /EXCL=('OLD_FN''OLD_FT';'VNO_HIGH','- 'OLD_FN''OLD_FT';'VNO_LOW') $ WRITE SYS$OUTPUT - ! Notify user of purge "...Purging file ''OLD_FN'''OLD_FT'",- " (saving versions ''VNO_LOW' and ''VNO_HIGH')" $ ENDIF $ ENDIF $ OLD_FN = FN !save file name as previous file $ OLD_FT = FT !save file type as previous type $ VNO_HIGH = VNO !1st ver of new file is high ver $ ENDIF $ VNO_LOW = VNO !last version found is low ver $ GOTO LOOP !loop-find next file $ ENDIF $! End of loop: process last file $! If no files found: $ IF (OLD_FN .EQS. "" .AND. OLD_FT .EQS. "") $! Notify the user: $ THEN $ WRITE SYS$OUTPUT "Error! No file names match",- " this specification." $ ELSE !else purge last file found $! If more than one version: $ IF (VNO_LOW .NES. VNO_HIGH) $ THEN $! Purge middle versions of files: $ DEL 'FN''FT';*- /EXCL=('FN''FT';'VNO_HIGH','FN''FT';'VNO_LOW') $ WRITE SYS$OUTPUT - !Notify user of purge "...Purging file ''FN'''FT'",- " (saving versions ''VNO_LOW' and ''VNO_HIGH')" $ ENDIF $ WRITE SYS$OUTPUT "File purge complete." $ ENDIF