abbes@usl.UUCP ( ) (05/20/86)
I am posting in the next article a command interpreter for Vax/VMS, offering facilities such as those found in the Unix C- shell. It is a simple (1647 lines) program, written as a collection of DCL procedures. The doc is under the form of help files. You can certainly make it faster if you rewrite it in a compiled language such as "C" or Ada, though it works as is and is not so slow.
abbes@usl.UUCP ( ) (05/20/86)
The source (and doc) follows: 1700 lines. =============================================================== INSTALLATION GUIDE 1) This command interpreter consists of a lot of small command procedures, organized into directories. Find a place to put it, such as a directory "tools" or the home directory of a dedicated user. Create a directory "bin" for the general purpose command files (profile.com, def0.com, etc.) and a directory "vmx" with three subdirectories: "bin" for the .com files, "help" for the help files, "users" for the init files of all the users. 2) Make sure that any user willing to use it has correct logical assignments in his login.com (and other init files run at login). > !--> file LOGIN.COM > set noverify > assign disk0:[root.z.bin] bin > @bin:profile -- other logical assignments > vmx -- on the last line > !<-- end LOGIN.COM 3) When you install this set of procedures for the first time, make sure to comment out the lines !on control_y then goto ... So that if anything goes wrong, you can still abort everything by ^Y. 4) After you have tried all possible sorts of commands, remove the exclam marks so that control_y is handled. 5) There is a command that any user can use to create his init file. ================================================================= --> list of the files that make up VMX and SHELL ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z]BIN.DIR 2 DISK0:[ROOT.Z]LOGIN.COM 1 DISK0:[ROOT.Z]VMX.DIR 1 Total of 3 files, 4 blocks. ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z.BIN]CD.COM 1 DISK0:[ROOT.Z.BIN]COPY1.PAS 1 DISK0:[ROOT.Z.BIN]COPY2.PAS 1 DISK0:[ROOT.Z.BIN]CWD.COM 1 DISK0:[ROOT.Z.BIN]DEF0.COM 1 DISK0:[ROOT.Z.BIN]DEF1.COM 3 DISK0:[ROOT.Z.BIN]DEF2.COM 1 DISK0:[ROOT.Z.BIN]DEF3.COM 1 DISK0:[ROOT.Z.BIN]EDTINI.EDT 1 DISK0:[ROOT.Z.BIN]MKDIR.COM 1 DISK0:[ROOT.Z.BIN]PROFILE.COM 1 DISK0:[ROOT.Z.BIN]RM.COM 1 DISK0:[ROOT.Z.BIN]RMDIR.COM 1 DISK0:[ROOT.Z.BIN]SLEEP.COM 1 DISK0:[ROOT.Z.BIN]UP.COM 1 Total of 15 files, 17 blocks. ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z.VMX]BIN.DIR 1 DISK0:[ROOT.Z.VMX]HELP.DIR 1 DISK0:[ROOT.Z.VMX]USERS.DIR 1 Total of 3 files, 3 blocks. ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z.VMX.BIN]DEBUG.COM 1 DISK0:[ROOT.Z.VMX.BIN]DELETE.COM 1 DISK0:[ROOT.Z.VMX.BIN]ECHERR.COM 3 DISK0:[ROOT.Z.VMX.BIN]ECHO.COM 3 DISK0:[ROOT.Z.VMX.BIN]EDIX.COM 2 DISK0:[ROOT.Z.VMX.BIN]EDTINI.EDT 1 DISK0:[ROOT.Z.VMX.BIN]EXEC.COM 2 DISK0:[ROOT.Z.VMX.BIN]FORK.COM 6 DISK0:[ROOT.Z.VMX.BIN]HELP.COM 2 DISK0:[ROOT.Z.VMX.BIN]HISTORY.COM 2 DISK0:[ROOT.Z.VMX.BIN]INITVMX.COM 4 DISK0:[ROOT.Z.VMX.BIN]NODEBUG.COM 1 DISK0:[ROOT.Z.VMX.BIN]PIPE.COM 13 DISK0:[ROOT.Z.VMX.BIN]SEND.COM 5 DISK0:[ROOT.Z.VMX.BIN]SH.COM 1 DISK0:[ROOT.Z.VMX.BIN]SHELL.COM 12 DISK0:[ROOT.Z.VMX.BIN]VMX.COM 10 DISK0:[ROOT.Z.VMX.BIN]VMXSHELL.COM 1 Total of 18 files, 70 blocks. ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z.VMX.HELP]DEBUG.HLP 2 DISK0:[ROOT.Z.VMX.HELP]ECHO.HLP 1 DISK0:[ROOT.Z.VMX.HELP]EDIX.HLP 2 DISK0:[ROOT.Z.VMX.HELP]FILES.HLP 2 DISK0:[ROOT.Z.VMX.HELP]FORK.HLP 2 DISK0:[ROOT.Z.VMX.HELP]GRAMMAR.HLP 2 DISK0:[ROOT.Z.VMX.HELP]HELP.HLP 1 DISK0:[ROOT.Z.VMX.HELP]HS.HLP 2 DISK0:[ROOT.Z.VMX.HELP]NICE.HLP 2 DISK0:[ROOT.Z.VMX.HELP]PIPE.HLP 2 DISK0:[ROOT.Z.VMX.HELP]SEMANTIX.HLP 1 DISK0:[ROOT.Z.VMX.HELP]SEND.HLP 1 DISK0:[ROOT.Z.VMX.HELP]SH.HLP 2 DISK0:[ROOT.Z.VMX.HELP]SHELL.HLP 2 DISK0:[ROOT.Z.VMX.HELP]SYMBOL.HLP 2 DISK0:[ROOT.Z.VMX.HELP]TOPICS.HLP 1 DISK0:[ROOT.Z.VMX.HELP]VMX.HLP 3 DISK0:[ROOT.Z.VMX.HELP]VMXSHELL.HLP 2 Total of 18 files, 32 blocks. ========== ========== ========== ========== ========== ========== DISK0:[ROOT.Z.VMX.USERS]JACK.INI 4 DISK0:[ROOT.Z.VMX.USERS]JEAN.INI 4 DISK0:[ROOT.Z.VMX.USERS]JOHN.INI 4 Total of 3 files, 12 blocks. ========== ========== ========== ========== ========== ========== Grand total of 6 directories, 60 files, 138 blocks. ========== ========== ========== ========== ========== ========== <-- end of list !--> file LOGIN.COM ---------- ---------- ---------- ---------> $ set noverify set term/dev=vt100 $ assign disk0:[root.z.bin] bin @bin:profile vmx !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DEBUG.COM ---------- ---------- ---------- ---------> is_debug_'p1' :== true !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DELETE.COM ---------- ---------- ---------- ---------> if f$search(p1) - .nes. "" then delete 'p1' $ !<-- end ---------- ---------- ---------- ---------- <--------- !--> file ECHERR.COM ---------- ---------- ---------- ---------> arg_string = "''p1' ''p2' ''p3' ''p4' ''p5' ''p6' ''p7' ''p8'" argument_line := 'arg_string LOOP_ON_BLANK: length = f$length(argument_line) position = f$locate("\B", argument_line) exists_blank = position .ne. length if .not. exists_blank then goto EXIT_LOOP_ON_BLANK argument_line = f$extract(0, position, argument_line) + " " + - f$extract(2 + position, length, argument_line) END_LOOP_ON_BLANK: goto LOOP_ON_BLANK EXIT_LOOP_ON_BLANK: LOOP_ON_NEWLINE: length = f$length(argument_line) position = f$locate("\N", argument_line) exists_newline = position .ne. length first_line = f$extract(0, position, argument_line) argument_line = f$extract(2 + position, length, argument_line) write sys$error first_line if .not. exists_newline then exit END_LOOP_ON_NEWLINE: goto LOOP_ON_NEWLINE !<-- end ---------- ---------- ---------- ---------- <--------- !--> file ECHO.COM ---------- ---------- ---------- ---------> arg_string = "''p1' ''p2' ''p3' ''p4' ''p5' ''p6' ''p7' ''p8'" argument_line := 'arg_string LOOP_ON_BLANK: length = f$length(argument_line) position = f$locate("\B", argument_line) exists_blank = position .ne. length if .not. exists_blank then goto EXIT_LOOP_ON_BLANK argument_line = f$extract(0, position, argument_line) + " " + - f$extract(2 + position, length, argument_line) END_LOOP_ON_BLANK: goto LOOP_ON_BLANK EXIT_LOOP_ON_BLANK: LOOP_ON_NEWLINE: length = f$length(argument_line) position = f$locate("\N", argument_line) exists_newline = position .ne. length first_line = f$extract(0, position, argument_line) argument_line = f$extract(2 + position, length, argument_line) write sys$output first_line if .not. exists_newline then exit END_LOOP_ON_NEWLINE: goto LOOP_ON_NEWLINE !<-- end ---------- ---------- ---------- ---------- <--------- !--> file EDIX.COM ---------- ---------- ---------- ---------> user_id = f$getjpi("", "username") user_name := 'user_id user_init_file = "vmx_users_dir:" + user_name + ini_extension if f$search(user_init_file) - .eqs. "" then vmx_put_line "edix: creating ''user_init_file'" if f$search(user_init_file) - .eqs. "" then wait 0:0:3 if f$search(user_init_file) - .eqs. "" then vmx_copy vmx_dir:initvmx.com 'user_init_file' $ vmx_put_line "edix: opening ''user_init_file'" vmx_put_line " type ^Z, then QUIT or EXIT to exit the editor" wait 0:0:3 input_mode = f$logical("sys$input") if input_mode .nes. "SYS$COMMAND:" then - define/user_mode sys$input sys$command: vmx_edit 'user_init_file' !<-- end ---------- ---------- ---------- ---------- <--------- !--> file EDTINI.EDT ---------- ---------- ---------- ---------> set mode change !<-- end ---------- ---------- ---------- ---------- <--------- !--> file EXEC.COM ---------- ---------- ---------- ---------> is_verify = f$verify(is_debug_exec) $! procedure EXEC (P1 : STRING := "") is on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y argument_string := 'p1' command_line = 'argument_string 'command_line 'p2' 'p3' 'p4' 'p5' 'p6' 'p7' 'p8' $ EXCEPTION: goto RETURN WHEN_WARNING: vmx_put_error "exec: warning" exit WHEN_ERROR: vmx_put_error "exec: error" exit WHEN_SEVERE_ERROR: vmx_put_error "exec: severe_error" exit WHEN_CONTROL_Y: vmx_put_error "exec: control_y" $! end EXEC; RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file FORK.COM ---------- ---------- ---------- ---------> is_verify = f$verify(is_debug_fork) $! procedure FORK (P1 : STRING := ""; $! P2 : NATURAL := 0) is is_new_input = false is_new_output = false is_to_fork = false on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y argument_string := 'p1' fork_line = 'argument_string second_argument = 'p2 if p2 .eqs. "" then second_argument = "000" count_string := 'second_argument initial_name = "fork" + count_string fork_out_file = initial_name + out_extension fork_com_file = initial_name + vmx_extension message_in = "fork: <" + in_file message_out = "fork: >" + fork_out_file LOOP: first_char = f$extract(0, 1, fork_line) is_special = first_char .eqs. "<" .or. first_char .eqs. ">" .or. - first_char .eqs. "&" .or. first_char .eqs. " " if .not. is_special then goto EXIT_LOOP if first_char .eqs. "<" then is_new_input = true if first_char .eqs. ">" then is_new_output = true if first_char .eqs. "&" then is_to_fork = true fork_line = f$extract(1, f$length(fork_line), fork_line) if first_char .eqs. "&" then goto EXIT_LOOP END_LOOP: goto LOOP EXIT_LOOP: if .not. is_to_fork then goto RETURN if is_new_input then vmx_put_line message_in if is_new_output then vmx_put_line message_out first_def = "first_argument := " + """""""" + fork_line + """""""" first_arg = "line_arg = 'first_argument" second_def = "second_argument = " + count_string second_arg = "count_arg := 'second_argument" shell_call = "vmx_shell line_arg count_arg" open/write logical_file 'fork_com_file write logical_file first_def write logical_file first_arg write logical_file second_def write logical_file second_arg write logical_file shell_call close logical_file fork_line := 'vmx_spawn if is_new_input then fork_line = fork_line + "/input=" + in_file if is_new_output then fork_line = fork_line + "/output=" + fork_out_file fork_line = fork_line + " @" + fork_com_file vmx_exec fork_line $ vmx_delete 'fork_com_file.* $ EXCEPTION: goto RETURN WHEN_WARNING: vmx_put_error "fork: warning" goto RETURN WHEN_ERROR: vmx_put_error "fork: error" goto RETURN WHEN_SEVERE_ERROR: vmx_put_error "fork: severe_error" goto RETURN WHEN_CONTROL_Y: vmx_put_error "fork: control_y" $! end FORK; RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file HELP.COM ---------- ---------- ---------- ---------> reply = p1 if reply .nes. "" then goto HAS_REPLY ty vmx_help_dir:help.hlp $ LOOP: ty vmx_help_dir:topics.hlp $ inquire/nopunctuation reply "Topic? " if reply .eqs. "" then exit HAS_REPLY: help_file = "vmx_help_dir:" + reply + ".hlp" if f$search(help_file) - .nes. "" then ty 'help_file' $ if f$search(help_file) - .eqs. "" then vmx_put_line " Sorry, no documentation on ''reply'" $ END_LOOP: goto LOOP !<-- end ---------- ---------- ---------- ---------- <--------- !--> file HISTORY.COM --------- ---------- ---------- ---------> is_verify = f$verify(is_debug_history) $! procedure HISTORY (P1 : NATURAL) is index = count - p1 if p1 .eqs. "" .or. p1 .gt. count then index = init_count - 1 if p1 .eqs. "" .and. count .ge. max_lines_for_hs - 1 then - index = count - max_lines_for_hs if p1 .nes. "" .and. 0 .ge. p1 then goto RETURN LOOP_HISTORY: index = 1 + index history_string = tab + "when " + f$string(index) + - " => " + tab + string_array'index vmx_put_line history_string modulo = index - modulo_for_hs * (index / modulo_for_hs) if modulo .eq. modulo_for_hs - 1 then vmx_put_line "" if index .ge. count then goto RETURN END_LOOP_HISTORY: goto LOOP_HISTORY $! end HISTORY; RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file INITVMX.COM --------- ---------- ---------- ---------> vmx_extension :== ".vmx" ini_extension :== ".ini" com_extension :== ".com" job_extension :== ".job" in_file :== "temp.in" out_extension :== ".out" err_extension :== ".err" res_extension :== ".res" hx :== @vmx_dir:help hs :== @vmx_dir:history edix :== @vmx_dir:edix debug :== @vmx_dir:debug no_debug :== @vmx_dir:nodebug sh :== @vmx_dir:sh vmx_shell :== @vmx_dir:vmxshell vmx_send :== @vmx_dir:send vmx_fork :== @vmx_dir:fork vmx_pipe :== @vmx_dir:pipe vmx_exec :== @vmx_dir:exec vmx_delete :== @vmx_dir:delete vmx_nice :== submit/noprinter/delete/noid/log_file=[]'res_extension vmx_spawn :== spawn/nowait/nolog vmx_rename :== rename vmx_copy :== copy vmx_edit :== edit/edt/command=vmx_dir:edtini.edt vmx_put_line :== write sys$error vmx_put_help :== if is_help_message then write sys$error vmx_put_warning :== if is_warning_message then write sys$error vmx_put_error :== if is_error_message then write sys$error max_control_y :== 3 max_count :== 333 init_count :== 0 max_lines_for_hs :== 15 constant_ps1 :== "_" ps1 :== "''constant_ps1'" constant_tab :== " " tab :== "''constant_tab'" false :== 0 true :== 1 is_help_message :== true is_warning_message :== true is_error_message :== true is_vmx_wanted :== true is_debug_vmx :== false is_debug_shell :== false is_debug_pipe :== false is_debug_fork :== false is_debug_send :== false is_debug_nice :== false is_debug_exec :== false is_debug_history :== false !<-- end ---------- ---------- ---------- ---------- <--------- !--> file NODEBUG.COM --------- ---------- ---------- ---------> is_debug_'p1' :== false !<-- end ---------- ---------- ---------- ---------- <--------- !--> file PIPE.COM ---------- ---------- ---------- ---------> is_verify = f$verify(is_debug_pipe) $! procedure PIPE (P1 : STRING := ""; $! P2 : NATURAL := 0) is pipe_max_control_y = 3 control_y_count = 0 pipe_count = -1 on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y argument_string := 'p1' command_line = 'argument_string second_argument = 'p2 if p2 .eqs. "" then second_argument = "000" count_string := 'second_argument initial_name = "pip" + count_string + "x" message_in = "pipe: <" + in_file in_pipe = "inpip" + count_string + vmx_extension out_pipe = "outpip" + count_string + vmx_extension com_pipe = "compip" + count_string + vmx_extension deassign_sys_input = "deassign sys$input" pipe_sys_command = "assign/user_mode " + in_pipe + " sys$command" assign_sys_command = "assign/user_mode " + in_file + " sys$command" assign_sys_input = "assign/user_mode sys$command: sys$input" open_sys_error = "open/write sys$error: " define_sys_error = "define sys$error sys$error:" deassign_sys_error = "$deassign sys$error" close_sys_error = "$close sys$error:" is_a_pipe = false LOOP: was_a_pipe = is_a_pipe length_line = f$length(command_line) position_pipe = f$locate("|", command_line) is_a_pipe = position_pipe .ne. length_line p = length_line - position_pipe - 1 first_command = f$extract(0, position_pipe, command_line) command_line = f$extract(1 + position_pipe, p, command_line) if first_command .eqs. "" then goto END_EXEC_COM open/write pipe_file 'com_pipe if was_a_pipe then write pipe_file pipe_sys_command write pipe_file deassign_sys_input write pipe_file assign_sys_input command_all = first_command OUTER_LOOP: is_new_input = false is_new_output = false is_new_error = false is_a_job = false pipe_count = 1 + pipe_count prefix_file = initial_name + f$string(pipe_count) com_file = prefix_file + vmx_extension job_file = prefix_file + job_extension out_file = prefix_file + out_extension err_file = prefix_file + err_extension open_sys_error_string = open_sys_error + err_file length_all = f$length(command_all) position = f$locate(";", command_all) is_multiple = position .ne. length_all p = length_line - position - 1 command_one = f$extract(0, position, command_all) command_all = f$extract(1 + position, p, command_all) if command_one .eqs. "" then goto END_MULTIPLE_COMMAND INNER_LOOP: first_char = f$extract(0, 1, command_one) is_special = first_char .eqs. "<" .or. first_char .eqs. ">" .or. - first_char .eqs. "?" .or. first_char .eqs. "+" .or. - first_char .eqs. " " if .not. is_special then goto EXIT_INNER_LOOP if first_char .eqs. "<" then is_new_input = true if first_char .eqs. ">" then is_new_output = true if first_char .eqs. "?" then is_new_error = true if first_char .eqs. "+" then is_a_job = true command_one = f$extract(1, f$length(command_one), command_one) END_INNER_LOOP: goto INNER_LOOP EXIT_INNER_LOOP: if .not. is_new_output .and. .not. is_a_job then goto STANDARD_OUTPUT REDIRECT_OUTPUT: change_dir = "$set def " + f$logical("sys$disk") + f$directory() open/write logical_file 'com_file if is_a_job then write logical_file change_dir write logical_file "$''command_one'" close logical_file if is_new_output then command_one = "@" + com_file + "/out=" + out_file if is_a_job then vmx_rename 'com_file 'job_file $ if is_a_job then command_one = "vmx_nice " + job_file STANDARD_OUTPUT: message_out = "pipe: >" + out_file message_err = "pipe: ?" + err_file if is_new_input then deassign sys$input if is_new_input then assign/user_mode in_file sys$input if is_new_input then vmx_put_line message_in if is_new_output then vmx_put_line message_out if is_new_error then vmx_put_line message_err if is_new_error then write pipe_file open_sys_error_string if is_new_error then write pipe_file define_sys_error write pipe_file "$''command_one'" if is_new_error then write pipe_file deassign_sys_error if is_new_error then write pipe_file close_sys_error if .not. is_multiple then goto EXIT_OUTER_LOOP END_MULTIPLE_COMMAND: if command_all .eqs. "" then goto EXIT_OUTER_LOOP END_OUTER_LOOP: goto OUTER_LOOP EXIT_OUTER_LOOP: close pipe_file EXEC_COM: command_one = "@''com_pipe'" if is_a_pipe then command_one = command_one + "/out=''out_pipe'" vmx_exec command_one $ if is_a_pipe then vmx_rename 'out_pipe 'in_pipe $ vmx_delete 'initial_name'*'vmx_extension'.* $ vmx_delete 'com_pipe.* $ if .not. is_a_pipe then vmx_delete 'in_pipe.* $ if .not. is_a_pipe then goto RETURN END_EXEC_COM: if command_line .eqs. "" then goto RETURN EXCEPTION: goto END_LOOP WHEN_WARNING: vmx_put_error "pipe: warning" goto END_LOOP WHEN_ERROR: vmx_put_error "pipe: error" goto END_LOOP WHEN_SEVERE_ERROR: vmx_put_error "pipe: severe_error" goto END_LOOP WHEN_CONTROL_Y: control_y_string = "pipe: control_y" control_y_count = 1 + control_y_count if control_y_count .eq. 1 then - control_y_string = control_y_string + " (only " + - pipe_max_control_y + " allowed)" if control_y_count .eq. pipe_max_control_y - 1 then - control_y_string = control_y_string + " (next is last)" if control_y_count .eq. pipe_max_control_y then - control_y_string = control_y_string + " (last)" if control_y_count .gt. pipe_max_control_y then - control_y_string = control_y_string + " (exit)" vmx_put_error control_y_string if control_y_count .gt. pipe_max_control_y then goto RETURN END_LOOP: goto LOOP $! end PIPE; RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file SEND.COM ---------- ---------- ---------- ---------> is_verify = f$verify(is_debug_send) $! procedure SEND (P1 : STRING := ""; $! P2 : NATURAL := 0) is on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y argument_string := 'p1' send_line = 'argument_string second_argument = 'p2 if p2 .eqs. "" then second_argument = "000" count_string := 'second_argument is_to_send = false initial_name = "send" + count_string send_com_file = initial_name + vmx_extension LOOP: first_char = f$extract(0, 1, send_line) is_special = first_char .eqs. "^" .or. first_char .eqs. " " if .not. is_special then goto EXIT_LOOP if first_char .eqs. "^" then is_to_send = true send_line = f$extract(1, f$length(send_line), send_line) END_LOOP: goto LOOP EXIT_LOOP: if .not. is_to_send then goto RETURN change_dir = "set def " + f$logical("sys$disk") + f$directory() first_def = "first_argument := " + """""""" + send_line + """""""" first_arg = "line_arg = 'first_argument" second_def = "second_argument = " + count_string second_arg = "count_arg := 'second_argument" shell_call = "vmx_shell line_arg count_arg" open/write logical_file 'send_com_file write logical_file change_dir write logical_file first_def write logical_file first_arg write logical_file second_def write logical_file second_arg write logical_file shell_call close logical_file send_line := "vmx_nice ''send_com_file'" vmx_exec send_line $ EXCEPTION: goto RETURN WHEN_WARNING: vmx_put_error "send: warning" goto RETURN WHEN_ERROR: vmx_put_error "send: error" goto RETURN WHEN_SEVERE_ERROR: vmx_put_error "send: severe_error" goto RETURN WHEN_CONTROL_Y: vmx_put_error "send: control_y" $! end SEND; RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file SH.COM ---------- ---------- ---------- ---------> from_vmx = 0 @vmx_dir:shell 'p1' 'from_vmx' 'p2' !<-- end ---------- ---------- ---------- ---------- <--------- !--> file SHELL.COM ---------- ---------- ---------- ---------> is_verify = f$verify(is_debug_shell) $! procedure SHELL (P1 : STRING := ""; $! P2 : BOOLEAN; $! P3 : NATURAL := 0) is on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y shell_max_control_y = 3 control_y_count = 0 shell_count = -1 argument_string := 'p1' if p2 then command_line = 'argument_string if .not. p2 then command_line := 'p1' if p3 .nes. "" then second_argument = 'p3 if p3 .eqs. "" then second_argument = "0" count_string := 'second_argument initial_name = count_string message_in = "shell: <" + in_file LOOP_ON_SPACE: length = f$length(command_line) position = f$locate("\S", command_line) exists_space = position .ne. length if .not. exists_space then goto EXIT_LOOP_ON_SPACE command_line = f$extract(0, position, command_line) + " " + - f$extract(2 + position, length, command_line) END_LOOP_ON_SPACE: goto LOOP_ON_SPACE EXIT_LOOP_ON_SPACE: length_line = f$length(command_line) SEND_A_JOB: position = f$locate("^", command_line) is_a_job = position .ne. length_line if is_a_job then vmx_send command_line count_string if is_a_job then goto RETURN FORK_A_PROCESS: position = f$locate("&", command_line) is_a_process = position .ne. length_line if is_a_process then vmx_fork command_line count_string if is_a_process then goto RETURN RUN_A_PIPE: position = f$locate("|", command_line) is_a_pipe = position .ne. length_line if is_a_pipe then vmx_pipe command_line count_string if is_a_pipe then goto RETURN LOOP: on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y is_new_input = false is_new_output = false is_new_error = false is_a_job = false shell_count = 1 + shell_count prefix_file = initial_name + "x" + f$string(shell_count) com_file = prefix_file + vmx_extension out_file = prefix_file + out_extension err_file = prefix_file + err_extension length_line = f$length(command_line) position = f$locate(";", command_line) is_multiple = position .ne. length_line p = length_line - position - 1 first_command = f$extract(0, position, command_line) command_line = f$extract(1 + position, p, command_line) if first_command .eqs. "" then goto END_EXEC_COM INNER_LOOP: first_char = f$extract(0, 1, first_command) is_special = first_char .eqs. "<" .or. first_char .eqs. ">" .or. - first_char .eqs. "?" .or. first_char .eqs. "+" .or. - first_char .eqs. " " if .not. is_special then goto EXIT_INNER_LOOP if first_char .eqs. "<" then is_new_input = true if first_char .eqs. ">" then is_new_output = true if first_char .eqs. "?" then is_new_error = true if first_char .eqs. "+" then is_a_job = true first_command = f$extract(1, f$length(first_command), first_command) END_INNER_LOOP: goto INNER_LOOP EXIT_INNER_LOOP: if .not. is_new_output .and. .not. is_a_job then goto STANDARD_OUTPUT REDIRECT_OUTPUT: change_dir = "set def " + f$logical("sys$disk") + f$directory() open/write logical_file 'com_file if is_a_job then write logical_file change_dir write logical_file first_command close logical_file if is_new_output then first_command = "@" + com_file + "/out=" + out_file if is_a_job then first_command = "vmx_nice " + com_file STANDARD_OUTPUT: message_out = "shell: >" + out_file message_err = "shell: ?" + err_file if is_new_input then deassign sys$input if is_new_input then assign/user_mode in_file sys$input if is_new_input then vmx_put_line message_in if is_new_output then vmx_put_line message_out if is_new_error then vmx_put_line message_err if is_new_error then open/write sys$error: 'err_file' if is_new_error then define sys$error sys$error: EXEC_COM: vmx_exec first_command $ if is_new_error then deassign sys$error if is_new_error then close sys$error: if is_new_output .and. .not. is_a_job then vmx_delete 'com_file.* $ if .not. is_multiple then goto RETURN END_EXEC_COM: if command_line .eqs. "" then goto RETURN EXCEPTION: goto END_LOOP WHEN_WARNING: vmx_put_error "shell: warning" goto END_LOOP WHEN_ERROR: vmx_put_error "shell: error" goto END_LOOP WHEN_SEVERE_ERROR: vmx_put_error "shell: severe_error" goto END_LOOP WHEN_CONTROL_Y: control_y_string = "shell: control_y" control_y_count = 1 + control_y_count if control_y_count .eq. 1 then - control_y_string = control_y_string + " (only " + - shell_max_control_y + " allowed)" if control_y_count .eq. shell_max_control_y - 1 then - control_y_string = control_y_string + " (next is last)" if control_y_count .eq. shell_max_control_y then - control_y_string = control_y_string + " (last)" if control_y_count .gt. shell_max_control_y then - control_y_string = control_y_string + " (exit)" vmx_put_error control_y_string if control_y_count .gt. shell_max_control_y then goto RETURN END_LOOP: goto LOOP RETURN: $! end SHELL; is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file VMX.COM ---------- ---------- ---------- ---------> INIT: vmx_init_file = "vmx_dir:initvmx.com" if f$search(vmx_init_file) - .eqs. "" then exit @'vmx_init_file $ user_id = f$getjpi("", "username") user_name := 'user_id user_init_file = "vmx_users_dir:" + user_name + ini_extension if f$search(user_init_file) - .eqs. "" then - vmx_put_warning "vmx: can't open ''user_init_file'; use EDIX" if f$search(user_init_file) - .nes. "" then @'user_init_file $ END_INIT: modulo_for_hs = max_lines_for_hs / 5 control_y_count = 0 count = init_count - 1 if f$mode() .nes. "INTERACTIVE" then exit if .not. is_vmx_wanted then exit vmx_put_help "vmx: type HX for help, EX to exit" LOOP: is_verify = f$verify(is_debug_vmx) $! procedure VMX is on warning then goto WHEN_WARNING on error then goto WHEN_ERROR on severe_error then goto WHEN_SEVERE_ERROR on control_y then goto WHEN_CONTROL_Y if count .ge. max_count then count = init_count - 1 count = 1 + count count_string = f$string(count) input_mode = f$logical("sys$input") if input_mode .nes. "SYS$COMMAND:" then - define/user_mode sys$input sys$command: global_prompt = f$string('count) + PS1 prompt := 'global_prompt string_array'count = "control_y" inquire/nopunctuation command_line "''prompt' " string_array'count = command_line first_char = f$extract(0, 1, command_line) is_a_digit = "0" .les. first_char .and. first_char .les. "9" is_to_edit = first_char .eqs. "/" is_previous = first_char .eqs. "\" if is_previous then index = count - 1 if is_previous then command_line = string_array'index if is_a_digit then command_line = string_array'command_line if is_a_digit .or. is_previous then string_array'count = command_line if is_a_digit .or. is_previous then vmx_put_line "''prompt' ''command_line'" if .not. is_to_edit then goto NOT_TO_EDIT BLOCK_EDIT: old_com = "oldcom''count_string'" + vmx_extension new_com = "newcom''count_string'" + vmx_extension command_line = f$extract(1, f$length(command_line), command_line) if command_line .eqs. "" then position = count - 1 if command_line .nes. "" then position = command_line command_line = string_array'position open/write logical_file 'new_com close logical_file open/write logical_file 'old_com write logical_file command_line close logical_file command_line = "" vmx_edit/nojournal/output='new_com 'old_com $ open/read logical_file 'new_com read logical_file command_line /end_of_file=WHEN_END_OF_FILE input_mode = f$logical("sys$input") if input_mode .nes. "SYS$COMMAND:" then - define/user_mode sys$input sys$command: EXCEPTION: WHEN_END_OF_FILE: close logical_file string_array'count = command_line vmx_delete 'old_com.* $ vmx_delete 'new_com.* $ vmx_put_line "''prompt' ''command_line'" END_BLOCK_EDIT: NOT_TO_EDIT: length_line = f$length(command_line) position_semicolon = f$locate(";", command_line) exists_semicolon = position_semicolon .ne. length_line is_for_shell = exists_semicolon if is_for_shell then goto CALL_THE_SHELL if command_line .eqs. "EX" then goto RETURN if command_line .eqs. "INIX" then count = INIT_COUNT - 1 if command_line .eqs. "INYX" then control_y_count = 0 if command_line .eqs. "INIX" .or. - command_line .eqs. "INYX" then goto END_LOOP VMS_COMMAND: vmx_exec command_line $END_VMS_COMMAND: goto END_LOOP CALL_THE_SHELL: vmx_shell command_line count_string END_CALL_THE_SHELL: goto END_LOOP EXCEPTION: WHEN_WARNING: vmx_put_error "vmx: warning" goto END_LOOP WHEN_ERROR: vmx_put_error "vmx: error" goto END_LOOP WHEN_SEVERE_ERROR: vmx_put_error "vmx: severe_error" goto END_LOOP WHEN_CONTROL_Y: control_y_string = "vmx: control_y" control_y_count = 1 + control_y_count if control_y_count .eq. 1 then - control_y_string = control_y_string + " (only " + - max_control_y + " allowed)" if control_y_count .eq. max_control_y - 1 then - control_y_string = control_y_string + " (next is last)" if control_y_count .eq. max_control_y then - control_y_string = control_y_string + " (last)" if control_y_count .gt. max_control_y then - control_y_string = control_y_string + " (exit) vmx_put_error control_y_string if control_y_count .gt. max_control_y then goto RETURN END_LOOP: $! end VMX; goto LOOP RETURN: is_verify = f$verify(is_verify) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file VMXSHELL.COM -------- ---------- ---------- ---------> from_vmx = true @vmx_dir:shell 'p1' 'from_vmx' 'p2' !<-- end ---------- ---------- ---------- ---------- <--------- (help DEBUG) DEBUG turns the trace on in the command procedures that implementVMX and SHELL. NO_DEBUG turns the trace off. This is useful to locate the problem if anything goes wrong. It also helps understand the behaviour of the command procedures. Note that you can change the symbol DEBUG to, for instance, DEBUG_ON in your init file. The argument is one of: VMX SHELL PIPE FORK SEND NICE EXEC HISTORY Note that you can set, for instance, is_debug_vmx :== true in your init file. (end help) (help ECHO) ECHO echoes its arguments (up to 8) on sys$output. ECHERR does the same on sys$error. To echo more than 8 arguments, use \b as a blank, and \n as a newline to separate arguments. ECHO is most useful as the first command in a pipe, as in: echo send \n John \n\n How are you today\b? | mail; -- sends a short message to user John. (end help) (help EDIX) EDIX edits the file vmx_users_dir:USER_NAME.ini, if you're user USER_NAME. The editor used is vmx_edit, EDT by default. If the file doesn't exit, EDIX creates it, as a copy of the file vmx_dir:initvmx.com. Once the file exists, it is executed every time vmx is invoked. It allows you to tailor the environment, including values or symbols used by vmx. res_extension :== ".ext" -- changes extension for batch log files debux :== @vmx_dir:debug vmx_nice :== submit/printer/delete/id/log_file=[]'res_extension vmx_spawn :== spawn/nowait/log vmx_edit :== edit/edt/command=MY_OWN_DIRECTORY:edtini.edt max_count :== 99 -- maximum number of a command constant_ps1 :== "%" -- changes prompt is_help_message :== false -- gets rid of initial message is_vmx_wanted :== false -- doesn't run vmx, but allows use of SH (end help) (help FILES) SHELL creates temporary files (removed by vmx_delete) and output files when IO redirection is specified. VMX also creates temporary files when a previous command is being edited for modification. To preserve the temporary files, simply define vmx_delete :== "!" in your init file. Note that you can modify the file extensions. Their meaning is as follows: vmx_extension : used by VMX and SHELL for various files ini_extension : used for the users init files (in vmx_users_dir) com_extension : used for command files job_extension : used by PIPE for batch jobs command files in_file : used for input redirection out_extension : used for output redirection err_extension : used for error redirection res_extension : used for the result file of a batch job (end help) (help FORK) FORK creates parallel processes, which names are USER_NAME_1, USER_NAME_2 etc. if you're user USER_NAME. The input and/or output of the process can be redirected, as in: >&command_line; <&command_line; <>&command_line; The process can be created by a batch job, in which case its output must be redirected: ^>&command_line; ^<>&command_line; vmx_spawn can be changed in your init_file to: vmx_spawn :== spawn/nowait/log so as to notify you of the creation of the process. use CPU (:== monitor processes/topcpu) to see which processes are currently executing. use STOP USER_NAME_1 to kill process USER_NAME_1. (end help) (help GRAMMAR) command_line ::= new_command | old_command new_command ::= fork_command | pipe_command | vmx_command fork_command ::= [^] {<, >} [&] pipe_command pipe_command ::= shell_command [ | pipe_command] shell_command ::= next_command ; next_command next_command ::= {<, >, ?, +} single_command [ ; shell_command] single_command ::= "" | any VMS command vmx_command ::= EDIX | INIX | INYX | HS | HX | EX old_command ::= repeat_command | edit_command | single_command repeat_command ::= "\" | number of a previous command edit_command ::= "/" [number of a previous command] (end help) (help HELP) Format: ^ command_line; + command; & command_line; < command; command_1 | command_2; > command; command_1 ; command_2; ? command; [/] [number] \ HX (help) INIX (inits count) HS [number] (history) EX (exit) INYX (inits control_y) EDIX (edits init_file) (end help) (help HS) HS [number] prints the history of command lines. By default, number is min (max_lines_for_hs, current_number) INIX brings current_number back to init_count, 0 by default. This also happens if current_number exceeds max_count. Otherwise you might get the error message "Too many symbols defined" INYX brings control_y_count back to 0. You are logged out of vmx when you have typed more than max_control_y (3 by default) ^Ys. This feature is there to prevent looping when vmx is recently installed. EX is to exit vmx (the inner invocation only) HX is the help for vmx. (end help) (help NICE) NICE and SEND are used to send batch jobs. NICE sends a job consisting of a single command: +command; To submit a command file in batch, simply use: +@command_file; You can change vmx_nice in your init_file, so as to be notified of the job being sent: vmx_nice :== submit/id/log_file=[].res And the extension of the log file: res_extension :== ".log" Use RMJOB (:== del sys$batch/entry=) to abort a job. Use B (:== show queue sys$batch) to see the batch queue. (end help) (help PIPE) PIPE creates a pipe between a group of command; the operator | has lower precedence than ^ and &, but higher precedence than ; + < > ? Several pipes can link filters, as in this batch process: ^ <>& echo hello, world | copy | reverse | copy; Any command can appear in a group of commands, as in: com_1 ; com_2 | <com_3 ; >?com_4 ; com_5 | com_6 ; +com_7 Don't forget a semicolon somewhere on the line: echo send\n John \n\n How are you? | mail; -- sends mail to John but echo send\n John \n\n How are you? | mail -- no semicolon, will echo "send John How are you today ? | mail" (end help) (help SEMANTIX) Any command line submitted to the shell from vmx, ie any command line containing special characters, must contain at least one semicolon ";" The semicolon serves to recognize which command lines are to be interpreted by the shell. The period "." must be used instead of the semicolon to indicate the version number, as in file.dat.1 (end help) (help SEND) NICE and SEND are used to send batch jobs. SEND sends an entire command_line: ^command_line; You can change vmx_nice in your init_file, so as to be notified of the job being sent: vmx_nice :== submit/id/log_file=[].res And the extension of the log file: res_extension :== ".log" Use RMJOB (:== del sys$batch/entry=) to abort a job. Use B (:== show queue sys$batch) to see the batch queue. (end help) (help SH) SH is the interface to the shell, used when command_lines come directly from a user. For instance, if you are using the VMS history mechanism rather than VMX, you may wish to use the shell to interpret a complicated (but powerful) command_line. First solution: Call VMX, wait for a prompt, enter a command_line, and exit with EX. Second solution: Use SH. Only one string argument, no space allowed. Use \s as a space, except maybe for ECHO (use \b). Semicolon not required. An optional numeric second argument (equivalent to current_number in VMX.) Exemple: SH DIR/DATE SH ECHO\sHello,\bWorld! SH ECHO\sSEND\n\sJohn\s\n\n\sHow\sAre\sYou\sToday\b?\s|\sMail; -- a pipe Third solution: Use VMX_SHELL (in general from a command procedure) (end help) (help SHELL) SHELL is an interpreter that accepts a command_line from a user (see SH) or from VMX (if it contains a semicolon) and runs it according to the special characters used (see GRAMMAR and SEMANTIX) Exemples of command_lines: <& com_1 | <? com_2 ; + com_3 | >? com_4 -- a process ^ >& command_line; -- a batch job Exemples of groups of commands in pipes: + com_1; com_2 | <>? com_3 ; com_4 | com_5 -- double pipe Exemples of single commands: + command; -- a batch job < command; -- input from temp.in > command; -- output to current_numberXX.out ? command; -- errors to current_numberXX.err To redirect IO from/to a file, use mv (move = rename). This pipe: 23_ com_1 | com_2; is equivalent (only in command number 23) to: 23_ > com_1 ; mv 23x0.out temp.in ; < com_2 (end help) (help SYMBOL) A number of symbols are defined for use by VMX and SHELL. Note that you are free to redefine them if you want to obtain a different behaviour. Examples: out_extension : extension for output files vmx_pipe : the command file that implements pipes vmx_edit : the editor used by EDIX and by VMX to edit a command max_control_y : maximum number of ^Y allowed max_count : maximum number of commands in VMX init_count : number of the first command in VMX max_lines_for_hs : number of previous commands displayed by HS constant_ps1 : the prompt in VMX constant_tab : the tab used in HS false : a boolean constant is_vmx_wanted : a boolean variable, true if you want SHELL but not VMX is_debug_vmx : a boolean variable, changed by DEBUG and NO_DEBUG (end help) (help TOPICS) Additional information available: DEBUG ECHO EDIX FILES FORK GRAMMAR HELP HS NICE PIPE SEMANTIX SEND SH SHELL SYMBOL VMX VMXSHELL (end help) (help VMX) VMX is a command_line interpreter with a history mechanism. It calls the shell to interpret command_lines containing a semicolon. The other command_lines are run directly by VMS. VMX begins its execution by running vmx_dir:initvmx.com. Then, for user user_name, it runs vmx_users_dir:user_name.ini (file created or modified by EDIX.) It then loops accepting command_lines. It catches exceptions such as ^Y, severe_error, etc. It exits on EX, has a help HX, a history HS. To repeat a previous command, number 35 for instance, just type 35. Type /35 to edit command number 35, it will be submitted when you exit the editor with "EXIT" or ignored if you leave it with "QUIT" Use \ to repeat the previous command, / to edit it. VMX serves mainly as a driver for the shell. If you prefer to use the VMS history mechanism, the shell is still available as SH. In any case, the last line of your login.com file should be "vmx". This allows interpretation of batch jobs when they log in. Set the boolean is_vmx_wanted to false if necessary. (end help) (help VMX_SHELL) VMX_SHELL is the interface to the shell used by VMX, or by other command procedures when it is not convenient to use SH, for instance, when it is not desirable to replace a space by \s. The command procedure should include the following lines: first_argument := """THE COMMAND LINE TO INTERPRET""" -- 3 double quotes line_arg = 'first_argument It can also contain the following two lines, otherwise the current_number used by the shell to create temporary and output files will be 0 by default: second_argument = ANY NUMBER BETWEEN 0 and 999 count_arg := 'second_argument The call to shell is then of the form: vmx_shell line_arg [count_arg] Exemple: To avoid IO redirection to files with the same name: ... vmx_shell first_command_line 1 vmx_shell second_command_line 2 (end help) !--> file INITVMX.COM --------- ---------- ---------- ---------> vmx_extension :== ".vmx" ini_extension :== ".ini" com_extension :== ".com" job_extension :== ".job" in_file :== "temp.in" out_extension :== ".out" err_extension :== ".err" res_extension :== ".res" hx :== @vmx_dir:help hs :== @vmx_dir:history edix :== @vmx_dir:edix debug :== @vmx_dir:debug no_debug :== @vmx_dir:nodebug sh :== @vmx_dir:sh vmx_shell :== @vmx_dir:vmxshell vmx_send :== @vmx_dir:send vmx_fork :== @vmx_dir:fork vmx_pipe :== @vmx_dir:pipe vmx_exec :== @vmx_dir:exec vmx_delete :== @vmx_dir:delete vmx_nice :== submit/noprinter/delete/noid/log_file=[]'res_extension vmx_spawn :== spawn/nowait/nolog vmx_rename :== rename vmx_copy :== copy vmx_edit :== edit/edt/command=vmx_dir:edtini.edt vmx_put_line :== write sys$error vmx_put_help :== if is_help_message then write sys$error vmx_put_warning :== if is_warning_message then write sys$error vmx_put_error :== if is_error_message then write sys$error max_control_y :== 3 max_count :== 333 init_count :== 0 max_lines_for_hs :== 15 constant_ps1 :== "_" ps1 :== "''constant_ps1'" constant_tab :== " " tab :== "''constant_tab'" false :== 0 true :== 1 is_help_message :== true is_warning_message :== true is_error_message :== true is_vmx_wanted :== true is_debug_vmx :== false is_debug_shell :== false is_debug_pipe :== false is_debug_fork :== false is_debug_send :== false is_debug_nice :== false is_debug_exec :== false is_debug_history :== false !<-- end ---------- ---------- ---------- ---------- <--------- !--> file INITVMX.COM --------- ---------- ---------- ---------> vmx_extension :== ".vmx" ini_extension :== ".ini" com_extension :== ".com" job_extension :== ".job" in_file :== "temp.in" out_extension :== ".out" err_extension :== ".err" res_extension :== ".res" hx :== @vmx_dir:help hs :== @vmx_dir:history edix :== @vmx_dir:edix debug :== @vmx_dir:debug no_debug :== @vmx_dir:nodebug sh :== @vmx_dir:sh vmx_shell :== @vmx_dir:vmxshell vmx_send :== @vmx_dir:send vmx_fork :== @vmx_dir:fork vmx_pipe :== @vmx_dir:pipe vmx_exec :== @vmx_dir:exec vmx_delete :== @vmx_dir:delete vmx_nice :== submit/noprinter/delete/noid/log_file=[]'res_extension vmx_spawn :== spawn/nowait/nolog vmx_rename :== rename vmx_copy :== copy vmx_edit :== edit/edt/command=vmx_dir:edtini.edt vmx_put_line :== write sys$error vmx_put_help :== if is_help_message then write sys$error vmx_put_warning :== if is_warning_message then write sys$error vmx_put_error :== if is_error_message then write sys$error max_control_y :== 3 max_count :== 333 init_count :== 0 max_lines_for_hs :== 15 constant_ps1 :== "_" ps1 :== "''constant_ps1'" constant_tab :== " " tab :== "''constant_tab'" false :== 0 true :== 1 is_help_message :== true is_warning_message :== true is_error_message :== true is_vmx_wanted :== true is_debug_vmx :== false is_debug_shell :== false is_debug_pipe :== false is_debug_fork :== false is_debug_send :== false is_debug_nice :== false is_debug_exec :== false is_debug_history :== false !<-- end ---------- ---------- ---------- ---------- <--------- !--> file INITVMX.COM --------- ---------- ---------- ---------> vmx_extension :== ".vmx" ini_extension :== ".ini" com_extension :== ".com" job_extension :== ".job" in_file :== "temp.in" out_extension :== ".out" err_extension :== ".err" res_extension :== ".res" hx :== @vmx_dir:help hs :== @vmx_dir:history edix :== @vmx_dir:edix debug :== @vmx_dir:debug no_debug :== @vmx_dir:nodebug sh :== @vmx_dir:sh vmx_shell :== @vmx_dir:vmxshell vmx_send :== @vmx_dir:send vmx_fork :== @vmx_dir:fork vmx_pipe :== @vmx_dir:pipe vmx_exec :== @vmx_dir:exec vmx_delete :== @vmx_dir:delete vmx_nice :== submit/noprinter/delete/noid/log_file=[]'res_extension vmx_spawn :== spawn/nowait/nolog vmx_rename :== rename vmx_copy :== copy vmx_edit :== edit/edt/command=vmx_dir:edtini.edt vmx_put_line :== write sys$error vmx_put_help :== if is_help_message then write sys$error vmx_put_warning :== if is_warning_message then write sys$error vmx_put_error :== if is_error_message then write sys$error max_control_y :== 3 max_count :== 333 init_count :== 0 max_lines_for_hs :== 15 constant_ps1 :== "_" ps1 :== "''constant_ps1'" constant_tab :== " " tab :== "''constant_tab'" false :== 0 true :== 1 is_help_message :== true is_warning_message :== true is_error_message :== true is_vmx_wanted :== true is_debug_vmx :== false is_debug_shell :== false is_debug_pipe :== false is_debug_fork :== false is_debug_send :== false is_debug_nice :== false is_debug_exec :== false is_debug_history :== false !<-- end ---------- ---------- ---------- ---------- <--------- !--> file CD.COM ---------- ---------- ---------- ---------> set def [.'p1'] sho def !<-- end ---------- ---------- ---------- ---------- <--------- (* COPY1.PAS *) program copy1 (input, output); var c : char; begin while not EOF do begin while not EOLN do begin read(c); write('[', c, ']'); end; readln; writeln; end; end. (* END *) (* COPY2.PAS *) program copy2 (input, output); var c : char; begin while not EOF do begin while not EOLN do begin read(c); write('{', c, '}'); end; readln; writeln; end; end. (* END *) !--> file CWD.COM ---------- ---------- ---------- ---------> set def 'p1' sho def !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DEF0.COM ---------- ---------- ---------- ---------> assign disk0:[root.z.vmx.bin] vmx_dir assign disk0:[root.z.vmx.users] vmx_users_dir assign disk0:[root.z.vmx.help] vmx_help_dir !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DEF1.COM ---------- ---------- ---------- ---------> b :== show queue sys$batch q :== show queue sys$print p :== print/feed/header/noflag rmjob :== del sys$batch/entry= rmpri :== del sys$print/entry= e :== edit/edt/command=bin:edtini.edt pwd :== sho def sd :== set def cpu :== monitor processes/topcpu l :== dir ls :== dir lr :== dir [...] ll :== dir/date/size llr :== dir/date/size [...] llp :== dir/date/size/prot sv :== set verify sn :== set noverify st :== sho term stt :== set term/dev=vt100 who :== sho u cp :== copy mv :== rename dl :== delete sym :== sho sym log :== sho log k :== sho time pro :== sho prot sys :== sho syst chmod :== set prot/prot=(system:wred, owner:wred, group:re, world:re) chmid :== set prot/prot=(system:re, owner:re, group:re, world:re) nomod :== set prot/prot=(system:wred, owner:wred, group:, world:) !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DEF2.COM ---------- ---------- ---------- ---------> sleep :== @bin:sleep up :== @bin:up cd :== @bin:cd cwd :== @bin:cwd rmdir :== @bin:rmdir mkdir :== @bin:mkdir rm :== @bin:rm go :== @bin:profile d0 :== @bin:def0 d1 :== @bin:def1 d2 :== @bin:def2 d3 :== @bin:def3 copy_1 :== run bin:copy1 copy_2 :== run bin:copy2 !<-- end ---------- ---------- ---------- ---------- <--------- !--> file DEF3.COM ---------- ---------- ---------- ---------> vmx :== @vmx_dir:vmx sh :== @vmx_dir:sh echo :== @vmx_dir:echo echerr :== @vmx_dir:echerr !<-- end ---------- ---------- ---------- ---------- <--------- set mode change !--> file MKDIR.COM ---------- ---------- ---------- ---------> create/dir [.'p1'] $ dir 'p1' !<-- end ---------- ---------- ---------- ---------- <--------- !--> file PROFILE.COM --------- ---------- ---------- ---------> set protection=(system:wred, owner:wred, group:re, world:re)/default @bin:def0 @bin:def1 @bin:def2 @bin:def3 write sys$error "start_up done" !<-- end ---------- ---------- ---------- ---------- <--------- !--> file RM.COM ---------- ---------- ---------- ---------> del 'p1'.* $ !<-- end ---------- ---------- ---------- ---------- <--------- !--> file RMDIR.COM ---------- ---------- ---------- ---------> set prot=(owner:wred) 'p1'.dir $ del 'p1'.dir.* $ !<-- end ---------- ---------- ---------- ---------- <--------- !--> file SLEEP.COM ---------- ---------- ---------- ---------> if f$locate(":", p1) .ne. f$length(p1) then wait 0:'p1' if f$locate(":", p1) .eq. f$length(p1) then wait 0:0:'p1' !<-- end ---------- ---------- ---------- ---------- <--------- !--> file UP.COM ---------- ---------- ---------- ---------> if p1 .eqs. "" then p1 = 1 index = 0 LOOP: index = 1 + index if index .gt. p1 then goto RETURN set def [-] END_LOOP: goto LOOP RETURN: sho def !<-- end ---------- ---------- ---------- ---------- <---------