Copyright 1989-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 May, 1989 By Kevin G. Barkes An EXIT Exegesis If the DCL Dictionary had been produced in high school yearbook format, the caption under EXIT would read "command most likely to be ignored." Poor EXIT gets no respect. It is omitted from many command files, particularly those of the "straight-line" variety which do not contain multiple command paths. DCL supplies a sort of implicit EXIT when the command interpreter reaches the end of file in a procedure. Many DCL command procedure writers view EXIT in the same manner in which most people think of an appendix: a relatively useless construct which hangs idly by at the end of a command file. Still, EXIT serves several legitimate purposes, all of which worth examining. EXIT vs STOP - To steal a phrase from the new administration, EXIT affords a "kinder, gentler" way of terminating an interrupted image or a command procedure than the related STOP command. EXIT, when entered interactively after a program has been interrupted with a control-y, causes the image to terminate normally. Any exit handlers in the program are executed. (RUNning another image also causes the interruped program to perform a normal rundown.) STOP, on the other hand, halts the image immediately. Exit handlers are not run, and the program terminates abnormally. When encountered in a command file, EXIT terminates the currently-executing procedure and returns to the command level from which the procedure was called. The following code demonstrates EXIT's operation. Procedure1 is executed interactively; it calls procedure2, which in turn calls procedure 3. Each procedure ends with an EXIT command: $ @procedure1.com (command level 0) Procedure 1 executing (command level 1) Invoking procedure2.com: Procedure 2 executing (command level 2) Invoking procedure3.com: Procedure 3 executing (command level 3) EXITing procedure3 Back in procedure2 (command level 2) EXITing procedure2 Back in procedure1 (command level 1) EXITing back to DCL (user $ prompt) $ (command level 0) Conversely, STOP acts like an "emergency brake". When encountered, the process breaks out of all procedures and returns immediately to command level 0: $ @procedure1.com (command level 0) Procedure 1 executing (command level 1) Invoking procedure2.com: Procedure 2 executing (command level 2) Invoking procedure3.com: Procedure 3 executing (command level 3) STOP reached in procedure 3 $ (command level 0) When executed in a job running in noninteractive mode, STOP causes the process to terminate immediately. EXIT causes noninteractive process termination only if encountered at command level 0 (that is, the original .COM file). ON AND IF TARGETS Both EXIT and STOP can be the targets of ON and IF commands: $ ON ERROR THEN EXIT $ IF $SEVERITY .NE. 1 THEN STOP Note that you can have labels named EXIT: and STOP: - $ ON ERROR THEN GOTO EXIT . . . $ EXIT: $ WRITE SYS$OUTPUT "Error encountered." $ EXIT Using EXIT and STOP as labels is mentioned only because it's frequently a source of confusion for beginning DCL procedure writers. Bear in mind there's a big difference between $ ON ERROR THEN GOTO EXIT and $ ON ERROR THEN EXIT As a rule, it's not a bad idea to avoid using labels having the same name as DCL commands. However, it's mostly a matter of personal discretion. Many DEC-supplied procedures use EXIT: labels. THE EXIT PARAMETER During my training seminars, I'm always surprised by the number of persons who are unaware that EXIT can have a command parameter, namely a value which gets placed in the reserved global symbol $STATUS. This value can be tested by the next highest command level using standard DCL error handling techniques. Consider the following command procedures: $! Procedure1 $ SAY := WRITE SYS$OUTPUT $ ON WARNING THEN GOTO ERROR $ @PROCEDURE2 $ SAY "No warnings." $ EXIT $ ERROR: $ SAY "Called procedure had error." $ EXIT $! Procedure2 $ NOCOMMAND $ EXIT Watch what happens when we execute procedure1: $@PROCEDURE1 %DCL-W-IVVERB, unrecognized command verb - check validity and spelling \NOCOMMAND\ Called procedure had error. When PROCEDURE2 exited, the warning condition was passed back to PROCEDURE1, which branched to the ERROR: label. If we modify PROCEDURE2 to read: $! Procedure2 $ NOCOMMAND $ EXIT 1 and execute PROCEDURE1: $ @PROCEDURE1 %DCL-W-IVVERB, unrecognized command verb - check validity and spelling \NOCOMMAND\ No warnings. The usefulness of EXIT's optional status code parameter is obvious. We can use it to force the calling procedure to perform any type of ON error handling, $STATUS or $SEVERITY checking we want. It's another method of "bullet-proofing" DCL procedures... no matter what happens to the called procedure, we can always be certain the calling procedure performs predictably. One other point: in the above example, you may have noted that even though the error was passed from PROCEDURE2 to PROCEDURE1, the warning only appeared once. That's because DCL changes the high order digit of $STATUS to 1 while keeping the rest of the symbol's value intact. This eliminates error messages generated by both the command and the procedure. So, should you go through all your .COM files and add EXITs to them? Probably not. But it certainly couldn't hurt, and it may surprise you to find the number of procedures you have which could become even more useful if you exploited EXIT's parameter passing ability. VANCOUVER POST SCRIPT: To those sharp individuals attending my DCL session at the DECUS Canada Symposium at Vancouver in February, here's the answer to your question regarding exceptions to the $STATUS and $SEVERITY rule. Certain commands don't update those symbols when they execute successfully. CONTINUE, DECK, DEPOSIT, EOD, EXAMINE, GOTO, IF, SET SYMBOL/SCOPE, SHOW STATUS, SHOW SYMBOL, STOP and WAIT change the values of $STATUS and $SEVERITY only if an error is generated when they run. Consider: $ TYPE NOFILE.HERE %TYPE-W-SEARCHFAIL, error searching for DUA0:[USER]NOFILE.HERE; -RMS-E-FNF, file not found $ CONTINUE $ WRITE SYS$OUTPUT F$MESSAGE($STATUS) %TYPE-W-SEARCHFAIL, error searching for !AS Aside from the fact the ascii string (!AS) is not available to F$MESSAGE(), the intervening CONTINUE command did not change the content of $STATUS. I plead severe jet lag, and misplaced session notes. ---------- Kevin G. Barkes is an independent consultant. 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.