gregg@a.cs.okstate.edu (Gregg Wonderly) (09/28/88)
Posting-number: Volume 4, Issue 106 Submitted-by: "Gregg Wonderly" <gregg@a.cs.okstate.edu> Archive-name: vms-vi-2/Part15 $ WRITE SYS$OUTPUT "Creating ""VI.11""" $ CREATE VI.11 $ DECK/DOLLARS=$$EOD$$ copy_line, orig_pos, last_pos, pos, exitnow, olen, this_pos, cur_tabs; vi$start_pos := MARK (NONE); pos := MARK (NONE); nchar := vi$init_action (olen); prog := vi$get_prog (nchar); IF prog <> "" THEN vi$do_movement (prog, VI$FILTER_TYPE); IF (vi$endpos <> 0) THEN POSITION (vi$endpos); POSITION (LINE_BEGIN); vi$endpos := MARK (NONE); POSITION (vi$start_pos); POSITION (LINE_BEGIN); IF (MARK (NONE) = vi$endpos) THEN MOVE_VERTICAL (1); vi$endpos := MARK (NONE); ENDIF; POSITION (vi$endpos); vi$move_horizontal (-1); era_range := CREATE_RANGE (vi$start_pos, MARK (NONE), NONE); MOVE_HORIZONTAL (1); IF (era_range <> 0) THEN vi$undo_end := 0; POSITION (vi$start_pos); vi$save_for_undo (era_range, VI$LINE_MODE, 1); POSITION (vi$start_pos); POSITION (LINE_BEGIN); orig_pos := vi$get_undo_start; IF (vi$filter_region (era_range, 0) = 0) THEN vi$kill_undo; vi$undo_end := 0; POSITION (pos); RETURN (vi$abort (0)); ENDIF; IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); ENDIF; vi$undo_end := MARK (NONE); vi$undo_start := vi$set_undo_start (orig_pos); vi$check_length (olen); ELSE vi$info ("Internal error while filtering!"); ENDIF; ELSE vi$abort (0); ENDIF; ELSE vi$abort (0); ENDIF; ENDPROCEDURE; ! ! Filter the region of text indicated by "region", using the command ! given in cmd_parm. ! PROCEDURE vi$filter_region (region, cmd_parm) LOCAL cmd; ON_ERROR vi$info ("ERROR filtering text!"); RETURN (0); ENDON_ERROR; cmd := cmd_parm; IF (vi$filter_buf = 0) THEN vi$filter_buf := vi$init_buffer ("$$filter_buffer$$", ""); IF (vi$filter_buf = 0) THEN vi$info ("Can't create buffer, filter aborted!"); RETURN (0); ENDIF; ELSE ERASE (vi$filter_buf); ENDIF; IF (cmd = 0) THEN IF (vi$read_a_line ("!", cmd) = 0) THEN RETURN (0); ENDIF; ENDIF; vi$info_success_off; IF (vi$filter_proc = 0) THEN IF cmd = "!" THEN cmd := vi$last_filter; IF (cmd = 0) THEN vi$info ("No previous command to use!"); RETURN (0); ENDIF; ELSE vi$last_filter := cmd; ENDIF; vi$filter_proc := CREATE_PROCESS (vi$filter_buf, cmd); IF (vi$filter_proc = 0) THEN vi$info ("Can't create process, filter aborted!"); RETURN (0); ENDIF; ENDIF; SEND (region, vi$filter_proc); IF vi$filter_proc <> 0 THEN DELETE (vi$filter_proc); vi$filter_proc := 0; ENDIF; vi$info_success_on; ERASE (region); COPY_TEXT (vi$filter_buf); RETURN (1); ENDPROCEDURE; ! ! Shift the selected text region one SHIFT_WIDTH to the right. ! PROCEDURE vi$region_right vi$region_shift(1); ENDPROCEDURE ! ! Shift the selected text region one SHIFT_WIDTH to the left. ! PROCEDURE vi$region_left vi$region_shift (0); ENDPROCEDURE ! ! This function shifts the selected region right or left based on ! the mode passed. ! ! Parameters: ! mode 0 indicates a left shift, 1 indicates right. ! PROCEDURE vi$region_shift (mode) LOCAL act_char, needed, era_range, prog, nchar, copy_line, tab_len, oline, nline, state, orig_pos, last_pos, exitnow, this_pos, cur_tabs; ON_ERROR; IF state <> 0 THEN IF (ERROR = TPU$_ENDOFBUF) AND (state = 2) THEN exitnow := 1; ELSE orig_pos := 0; ENDIF; ELSE vi$info ("Error occured during shift, at line: "+ STR(ERROR_LINE)); POSITION (vi$start_pos); RETURN; ENDIF; ENDON_ERROR; vi$start_pos := MARK (NONE); nchar := vi$init_action (state); state := 0; IF ((mode = 1) AND (ASCII (nchar) = '<')) OR ((mode = 0) AND (ASCII (nchar) = '>')) THEN RETURN; ENDIF; prog := vi$get_prog (nchar); IF prog <> "" THEN vi$do_movement (prog, VI$SHIFT_TYPE); oline := vi$cur_line_no; IF (vi$endpos <> 0) THEN POSITION (vi$endpos); POSITION (LINE_BEGIN); nline := vi$abs (vi$cur_line_no - oline); vi$endpos := MARK (NONE); POSITION (vi$start_pos); POSITION (LINE_BEGIN); IF (MARK (NONE) = vi$endpos) THEN MOVE_VERTICAL (1); vi$endpos := MARK (NONE); ENDIF; POSITION (vi$endpos); vi$move_horizontal (-1); era_range := CREATE_RANGE (vi$start_pos, MARK (NONE), NONE); MOVE_HORIZONTAL (1); IF (era_range <> 0) THEN vi$undo_end := 0; POSITION (vi$start_pos); vi$save_for_undo (era_range, vi$yank_mode, 1); POSITION (vi$start_pos); POSITION (LINE_BEGIN); orig_pos := vi$get_undo_start; cur_tabs := GET_INFO (CURRENT_BUFFER, "TAB_STOPS"); IF (GET_INFO (cur_tabs, "TYPE") = STRING) THEN vi$info ("Can't shift region with uneven tabstops."); RETURN; ELSE tab_len := cur_tabs; ENDIF; state := 2; exitnow := 0; LOOP EXITIF MARK (NONE) = vi$endpos; EXITIF MARK (NONE) = END_OF (CURRENT_BUFFER); EXITIF (exitnow = 1); copy_line := vi$current_line; IF (copy_line <> "") THEN ! Copy line is truncated to have no leading spaces. needed := vi$vis_indent (copy_line, tab_len); IF mode = 1 THEN needed := needed + vi$shift_width; ELSE needed := needed - vi$shift_width; ENDIF; IF (needed < 0) THEN needed := 0; ENDIF; ERASE_LINE; COPY_TEXT (vi$get_tabs (needed, tab_len)+copy_line); MOVE_HORIZONTAL (1); IF (MARK (NONE) <> END_OF(CURRENT_BUFFER)) THEN MOVE_HORIZONTAL (-1); SPLIT_LINE; ENDIF; ELSE MOVE_VERTICAL (1); ENDIF; POSITION (LINE_BEGIN); ENDLOOP; MOVE_HORIZONTAL (-1); vi$undo_end := MARK (NONE); vi$undo_start := vi$set_undo_start (orig_pos); POSITION (vi$undo_start); IF (nline >= vi$report) THEN act_char := ">"; IF mode = 0 THEN act_char := "<"; ENDIF; vi$info (STR (nline) + " lines " + act_char + "'d"); ENDIF; ELSE vi$info ("Internal error while shifting!"); ENDIF; ELSE vi$abort (0); ENDIF; ELSE vi$abort (0); ENDIF; ENDPROCEDURE; ! ! This procedure is called to calculate the number of spaces ! occupied on the screen by the leading white space of "line". "tabstops" ! holds the number of spaces a tab displays as obtained with a call to ! GET_INFO (CURRENT_BUFFER, "TAB_STOPS"). Line is stripped of the leading ! space on return, and the function returns the number of spaces occupied ! on the screen. ! PROCEDURE vi$vis_indent (line, tabstops) LOCAL idx, cur_ch, cnt; idx := 1; cnt := 0; LOOP cur_ch := SUBSTR (line, idx, 1); EXITIF (cur_ch = ""); EXITIF (INDEX (vi$_space_tab, cur_ch) = 0); IF (cur_ch = " ") THEN cnt := cnt + 1; ELSE cnt := cnt + (tabstops - (cnt - ((cnt / tabstops) * tabstops))); ENDIF; idx := idx + 1; ENDLOOP; ! Truncate the line removing the leading whitespace. line := SUBSTR (line, idx, LENGTH (line) - idx + 1); RETURN (cnt); ENDPROCEDURE; ! ! This procedure builds a string with as many tabs as possible to create ! the indentation level given by "len". "tabstops" is the number of spaces ! a tab produces on the screen. ! PROCEDURE vi$get_tabs (len, tabstops) LOCAL tab_text, rstr; rstr := ""; ! Select the proper tabbing text based on the setting of vi$use_tabs tab_text := ASCII (9); IF (vi$use_tabs = 0) THEN tab_text := SUBSTR (vi$spaces, 1, tabstops); ENDIF; LOOP EXITIF (len = 0); IF (len >= tabstops) THEN len := len - tabstops; rstr := rstr + tab_text; ELSE rstr := rstr + SUBSTR (vi$spaces, 1, len); len := 0; ENDIF; ENDLOOP; RETURN (rstr); ENDPROCEDURE; ! ! This function should be used to abort the current keyboard stream. ! It will assure that a macro does not continue to operate after a ! failure. ! PROCEDURE vi$abort (n) vi$key_buf := 0; RETURN (n); ENDPROCEDURE; ! ! Decide what the current line number is. ! PROCEDURE vi$cur_line_no LOCAL pos, cnt, val, opos; ON_ERROR POSITION (pos); IF (val > 1) THEN val := val / 2; cnt := cnt - val; ELSE POSITION (opos); RETURN (cnt); ENDIF; ENDON_ERROR; opos := MARK (NONE); val := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT") * 2 / 3; IF (val = 0) THEN val := 1; ENDIF; cnt := 1; LOOP pos := MARK (NONE); MOVE_VERTICAL (-val); cnt := cnt + val; ENDLOOP; ENDPROCEDURE; ! ! Copy a buffer of keys for use later. This routine is used mostly to ! make a copy of the last series of keystrokes from repeating when '.' ! is typed. ! PROCEDURE vi$copy_keys (to_keys, from_keys) LOCAL pos; pos := MARK (NONE); ERASE (to_keys); POSITION (to_keys); COPY_TEXT (from_keys); POSITION (BEGINNING_OF (to_keys)); POSITION (pos); ENDPROCEDURE; ! ! Convert a string of characters into a buffer of key strokes. ! PROCEDURE vi$str_to_keybuf (tstring, tbuf) LOCAL pos, idx; idx := 1; pos := MARK (NONE); POSITION (BEGINNING_OF (tbuf)); ! Note that a bug in TPU causes ill behavior if you try to ERASE ! a buffer that TPU has never written anything into. SPLIT_LINE; APPEND_LINE; ERASE (tbuf); LOOP EXITIF idx > LENGTH (tstring); COPY_TEXT (STR (INT (KEY_NAME (SUBSTR (tstring, idx, 1))))); ! Move to EOB so next COPY_TEXT will insert a new line. MOVE_HORIZONTAL (1); idx := idx + 1; ENDLOOP; ! There must be 2 lines (the first should be blank) at the end of the ! buffer to make it appear exactly as a key mapping. SPLIT_LINE; SPLIT_LINE; POSITION (pos); ENDPROCEDURE; ! ! Save the key passed into the push back buffer. ! PROCEDURE vi$push_a_key (ch) LOCAL pos; pos := MARK (NONE); POSITION (vi$cur_keys); COPY_TEXT (STR (INT (ch))); MOVE_HORIZONTAL (1); POSITION (pos); ENDPROCEDURE; ! ! Insert the buffer passed into the stream of key_board characters so ! that they act as a macro. ! PROCEDURE vi$insert_macro_keys (key_buf) LOCAL spos, pos; IF vi$push_key_buf = 0 THEN vi$push_key_buf := vi$init_buffer ("$$push_key_buf$$", ""); ENDIF; pos := MARK (NONE); IF (vi$key_buf <> 0) THEN IF (vi$key_buf = vi$push_key_buf) THEN POSITION (vi$push_key_buf); MOVE_HORIZONTAL (-1); spos := MARK (NONE); MOVE_HORIZONTAL (1); SET (INSERT, CURRENT_BUFFER); COPY_TEXT (key_buf); ! Remove blank line at end, and possible DEFINE_KEY mapping. MOVE_VERTICAL (-1); ERASE_LINE; MOVE_VERTICAL (-1); ERASE_LINE; POSITION (spos); MOVE_HORIZONTAL (1); ELSE POSITION (vi$key_buf); spos := MARK (NONE); ERASE (vi$push_key_buf); POSITION (vi$push_key_buf); SET (INSERT, CURRENT_BUFFER); COPY_TEXT (CREATE_RANGE (spos, END_OF (vi$key_buf), NONE)); ! Remove blank line at end, and possible DEFINE_KEY mapping. MOVE_VERTICAL (-1); ERASE_LINE; MOVE_VERTICAL (-1); ERASE_LINE; COPY_TEXT (key_buf); POSITION (BEGINNING_OF (vi$push_key_buf)); vi$key_buf := vi$push_key_buf; ENDIF; ELSE ERASE (vi$push_key_buf); POSITION (vi$push_key_buf); SET (INSERT, CURRENT_BUFFER); COPY_TEXT (key_buf); vi$key_buf := vi$push_key_buf; POSITION (BEGINNING_OF (vi$push_key_buf)); ENDIF; POSITION (pos); ENDPROCEDURE; ! ! Erase a the last key pushed back. ! PROCEDURE vi$del_a_key LOCAL pos; pos := MARK (NONE); POSITION (vi$cur_keys); IF MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER) THEN MOVE_VERTICAL (-1); ERASE_LINE; ENDIF; POSITION (pos); ENDPROCEDURE; ! ! Read a single keystroke from either the keyboard, or from the push ! back buffer if it is non-zero. ! PROCEDURE vi$read_a_key LOCAL read_a_key, pos, ch; read_a_key := 0; ! If there are no keys pushed, then read the keyboard. IF (vi$key_buf = 0) OR (GET_INFO (vi$key_buf, "TYPE") <> BUFFER) THEN read_a_key := 1; vi$m_level := 0; IF vi$term_vt200 THEN ch := READ_KEY; ELSE ch := READ_CHAR; ENDIF; ELSE ! Otherwise extract the next key from the buffer. pos := MARK (NONE); POSITION (vi$key_buf); ! Get the key code. ch := INT (vi$current_line); MOVE_VERTICAL (1); ! Check for the end of the buffer. IF (LENGTH (vi$current_line) = 0) THEN vi$key_buf := 0; ENDIF; POSITION (pos); ENDIF; ! If we are not running on a VT200, then do some key translations IF NOT vi$term_vt200 THEN IF ch = ASCII(27) THEN ch := F11; ENDIF; ENDIF; ch := KEY_NAME (ch); ! If a key was read from the keyboard, then push it back. IF read_a_key THEN vi$push_a_key (ch); ENDIF; ! Save the last key read. vi$last_key := ch; ! Return the keycode of the character RETURN (ch); ENDPROCEDURE; ! ! Turn pasthru on, on the terminal ! PROCEDURE vi$pasthru_on LOCAL junk; junk := CALL_USER (vi$cu_pasthru_on, ""); ENDPROCEDURE; ! ! Turn pasthru off, on the terminal ! PROCEDURE vi$pasthru_off LOCAL junk; junk := CALL_USER (vi$cu_pasthru_off, ""); ENDPROCEDURE; ! ! Spawn with pasthru off ! PROCEDURE vi$spawn (cmd) LOCAL junk; vi$pasthru_off; IF (cmd = 0) THEN SPAWN; ELSE SPAWN (cmd); ENDIF; vi$pasthru_on; ENDPROCEDURE ! ! Quit with pasthru off ! PROCEDURE vi$quit vi$pasthru_off; QUIT; vi$pasthru_on; ENDPROCEDURE ! ! Perform read_line with pasthru off ! PROCEDURE vi$read_line (prompt) LOCAL junk; vi$pasthru_off; junk := READ_LINE (prompt); vi$pasthru_on; RETURN (junk); ENDPROCEDURE; ! ! Initialize things by creating buffers and windows and perform other ! assorted operations. ! PROCEDURE tpu$init_procedure LOCAL journal_file, default_journal_name, aux_journal_name, cnt, input_file; ! Flag to indicate status of editor during startup. vi$starting_up := 1; vi$readonly := 0; IF (GET_INFO (COMMAND_LINE, "READ_ONLY") = 1) THEN vi$readonly := 1; ENDIF; vi$info_success_off; SET (MESSAGE_FLAGS, 1); SET (BELL, BROADCAST, ON); ! Set the variables to their initial values. vi$init_vars; ! Get some other information. vi$term_vt200 := GET_INFO (SCREEN, "vt200"); vi$scr_width := GET_INFO (SCREEN, "WIDTH"); vi$scr_length := GET_INFO (SCREEN, "VISIBLE_LENGTH"); ! Create the message buffer and window. message_buffer := vi$init_buffer ("Messages", ""); message_window := CREATE_WINDOW (vi$scr_length - 1, 2, ON); MAP (message_window, message_buffer); SET (STATUS_LINE, message_window, NONE, ""); SET (MAX_LINES, message_buffer, 500); ADJUST_WINDOW (message_window, 1, 0); vi$mess_select (REVERSE); ! Command prompt area. command_buffer := vi$init_buffer ("Commands", ""); command_window := CREATE_WINDOW (vi$scr_length, 1, OFF); ! Buffer for SHOW (xxx) stuff. show_buffer := vi$init_buffer ("Show", ""); info_window := CREATE_WINDOW (1, vi$scr_length - 1, ON); SET (STATUS_LINE, info_window, NONE, ""); ! A buffer for the tags file(s). vi$tag_buf := vi$init_buffer ("Tags buffer", ""); vi$load_tags; vi$dcl_buf := vi$init_buffer ("DCL buffer", "[End of DCL buffer]"); vi$info_success_off; ! A buffer and a window to start editing in. main_buffer := CREATE_BUFFER ("Main"); main_window := CREATE_WINDOW (1, vi$scr_length - 1, ON); SET (EOB_TEXT, main_buffer, "[EOB]"); SET (STATUS_LINE, main_window, NONE, ""); ! A buffer for wild carding and such. choice_buffer := vi$init_buffer ("Choices", ""); ! A buffer for the list of files we are currently editing. vi$file_names := vi$init_buffer ("file_names", ""); ! Buffer to hold last text inserted into a buffer. vi$last_insert := vi$init_buffer ("$$last_insert$$", ""); ! Buffer to hold KEY_NAME values of last key sequence. vi$cur_keys := vi$init_buffer ("$$current_keys$$", ""); ! Buffer to hold keys to be performed when '.' is pressed. vi$last_keys := vi$init_buffer ("$$last_keys$$", ""); ! Get a buffer to hold yank and deletes that are not aimed at named ! buffers. vi$temp_buf := vi$init_buffer ("$$temp_buffer$$", ""); ! Set up some more stuff. SET (PROMPT_AREA, vi$scr_length, 1, BOLD); SET (JOURNALING, 7); SET (FACILITY_NAME, "VI"); ! Move to the initial buffer. MAP (main_window, main_buffer); POSITION (main_buffer); ! Get the filename to edit. input_file := GET_INFO (COMMAND_LINE, "FILE_NAME"); IF input_file = "" THEN IF (GET_INFO (COMMAND_LINE, "OUTPUT")) THEN input_file := GET_INFO (COMMAND_LINE, "OUTPUT_FILE"); ENDIF; ENDIF; ! If there is an input file, then get it for editing. IF input_file <> "" THEN cnt := vi$get_file (input_file); ELSE vi$bmode_main := vi$readonly; ENDIF; ! Delete the unused main buffer if it is not used. IF (CURRENT_BUFFER <> main_buffer) AND (main_buffer <> 0) THEN DELETE (main_buffer); ENDIF; ! Start journaling if requested. IF (GET_INFO (COMMAND_LINE, "JOURNAL") = 1) THEN aux_journal_name := GET_INFO (CURRENT_BUFFER, "FILE_NAME"); IF aux_journal_name = "" THEN aux_journal_name := GET_INFO (CURRENT_BUFFER, "OUTPUT_FILE"); ENDIF; IF aux_journal_name = 0 THEN aux_journal_name := ""; ENDIF; IF aux_journal_name = "" THEN default_journal_name := "MAIN.TJL"; ELSE default_journal_name := ".TJL"; ENDIF; journal_file := GET_INFO (COMMAND_LINE, "JOURNAL_FILE"); journal_file := FILE_PARSE (journal_file, default_journal_name, aux_journal_name); JOURNAL_OPEN (journal_file); ENDIF; ! Force undefined keystrokes ("all of them") to call vi$command_mode. SET (UNDEFINED_KEY, "tpu$key_map_list", COMPILE ("vi$command_mode (LAST_KEY)")); SET (SELF_INSERT, "tpu$key_map_list", OFF); vi$info_success_on; ! Change PF1 so that it is NOT a shift key. SET (SHIFT_KEY, KEY_NAME (PF1, SHIFT_KEY)); ! Do any user added local initialization. tpu$local_init; ! Do the INI file. IF FILE_SEARCH ("EXRC") = "" THEN vi$do_file ("SYS$LOGIN:VI.INI", 0); ELSE vi$do_file ("EXRC", 0); ENDIF; vi$do_exinit; ! Enable passthru on the terminal so that ^Y does 'Push screen'. vi$pasthru_on; ! Say we are no longer starting up. vi$starting_up := 0; ENDPROCEDURE; ! ! Process the EXINIT environment variable (Process Logical actually). ! PROCEDURE vi$do_exinit LOCAL exinit; ON_ERROR RETURN; ENDON_ERROR; exinit := call_user (vi$cu_trnlnm_job, "EXINIT"); vi$do_cmd_line (exinit); ENDPROCEDURE; ! ! Load the file given in fn, into a buffer and execute the contents as ! a series of EX mode commands. "complain" is boolean, and determines ! whether or not we complain about a non existant file. ! PROCEDURE vi$do_file (rfn, complain) LOCAL fn, ini_buffer, ini_file; fn := rfn; ini_file := FILE_SEARCH (""); fn := FILE_PARSE (fn); ini_file := FILE_SEARCH (fn); IF (ini_file = "") THEN IF (complain) THEN vi$info ("Can't find file """+fn+"""!"); ENDIF; RETURN (1); ENDIF; vi$info_success_off; ini_buffer := CREATE_BUFFER ("VI$CMD$INI$$", ini_file); IF ini_buffer = 0 THEN IF (complain) THEN vi$info ("can't process file """+ini_file+"""!"); ENDIF; vi$info_success_on; RETURN(1); ENDIF; vi$process_buffer (ini_buffer); DELETE (ini_buffer); vi$info_success_on; RETURN (1); ENDPROCEDURE; ! ! Execute the contents of the passed buffer as EX mode commands ! PROCEDURE vi$process_buffer (buffer_parm) LOCAL line, old_pos, cur_pos; old_pos := MARK (NONE); POSITION (BEGINNING_OF (buffer_parm)); LOOP cur_pos := MARK (NONE); EXITIF (cur_pos = END_OF (buffer_parm)); line := CURRENT_LINE; IF (LENGTH (line) > 0) AND (SUBSTR (line, 1, 1) <> '!') THEN POSITION (old_pos); vi$do_cmd_line (line); old_pos := MARK (NONE); POSITION (cur_pos); ENDIF; MOVE_VERTICAL (1); ENDLOOP; POSITION (old_pos); ENDPROCEDURE; ! ! Initialize a system/nowrite buffer. ! PROCEDURE vi$init_buffer (new_buffer_name, new_eob_text) LOCAL new_buffer; ! New buffer new_buffer := CREATE_BUFFER (new_buffer_name); SET (EOB_TEXT, new_buffer, new_eob_text); SET (NO_WRITE, new_buffer); SET (SYSTEM, new_buffer); RETURN (new_buffer); ENDPROCEDURE; ! ! Expand the list of filenames given in "get_file_list" and return ! the count of names found as the function value. The file names will ! be in the vi$file_names buffer, one per line. ! PROCEDURE vi$expand_file_list (get_file_list) LOCAL num_names, fres, fn, fl, comma_pos, pos; fl := get_file_list; ERASE (choice_buffer); IF (vi$file_names = 0) THEN vi$file_names := vi$init_buffer ("file_names", ""); ELSE ERASE (vi$file_names); ENDIF; ! Expand the wild cards. Note that this also eliminates non-existant ! files from the list of files to edit. LOOP ! Protect against earlier file_search. fres := FILE_SEARCH (""); EXITIF fl = ""; comma_pos := INDEX (fl, ","); IF (comma_pos > 0) THEN fn := SUBSTR (fl, 1, comma_pos - 1); fl := SUBSTR (fl, comma_pos + 1, LENGTH (fl) - comma_pos); ELSE fn := fl; fl := ""; ENDIF; LOOP fres := FILE_SEARCH (fn); EXITIF fres = ""; vi$add_choice (fres); ENDLOOP; ENDLOOP; ! Save current position. pos := MARK (NONE); ! Save a copy of the filenames list POSITION (vi$file_names); COPY_TEXT (choice_buffer); POSITION (BEGINNING_OF (vi$file_names)); ! Move back to where we were. POSITION (pos); ! Save the count of file names. num_names := GET_INFO (choice_buffer, "RECORD_COUNT"); RETURN (num_names); ENDPROCEDURE; ! ! Put a file in the current window. If the file is already in a buffer, ! use the old buffer. If not, create a new buffer. ! ! Parameters: ! ! file_parameter String containing file name - input ! PROCEDURE vi$get_file (file_parameter) LOCAL pos, obuf, get_file_parm, outfile, filename, file_read, get_file_name, ! Local copy of get_file_parameter get_file_list, ! Possible comma separated list temp_buffer_name, ! String for buffer name based on get_file_name file_search_result, ! Latest string returned by file_search temp_file_name, ! First file name string returned by file_search loop_cnt, ! Number of files left to process in loop file_cnt, ! Actual number of files found with FILE_SEARCH loop_buffer, ! Buffer currently being checked in loop new_buffer, ! New buffer created if needed found_a_buffer, ! True if buffer found with same name want_new_buffer; ! True if file should go into a new buffer ON_ERROR IF ERROR = TPU$_PARSEFAIL THEN vi$info (FAO ("Don't understand file name: !AS", get_file_name)); RETURN (0); ENDIF; ENDON_ERROR; obuf := CURRENT_BUFFER; get_file_parm := file_parameter; IF (get_file_parm = 0) OR (get_file_parm = "") THEN vi$info ("File name must be supplied!"); RETURN (0); ENDIF; get_file_list := get_file_parm; get_file_name := get_file_parm; temp_file_name := 0; loop_cnt := vi$expand_file_list (get_file_list); ! If none were found, then set up to enter the loop and get a new buffer IF (loop_cnt = 0) THEN loop_cnt := 1; POSITION (BEGINNING_OF (choice_buffer)); ELSE IF loop_cnt > 1 THEN vi$info (FAO ("!UL files to edit!", loop_cnt)); ENDIF; POSITION (BEGINNING_OF (choice_buffer)); temp_file_name := vi$current_line; ERASE_LINE; ENDIF; file_cnt := loop_cnt; LOOP IF (GET_INFO (obuf, "TYPE") = BUFFER) THEN POSITION (obuf); ENDIF; ! See if we already have a buffer by that name IF temp_file_name = 0 THEN temp_buffer_name := FILE_PARSE (get_file_name, "", "", NAME) + FILE_PARSE (get_file_name, "", "", TYPE); ELSE temp_buffer_name := FILE_PARSE (temp_file_name, "", "", NAME) + FILE_PARSE (temp_file_name, "", "", TYPE); ENDIF; IF get_file_parm <> 0 THEN ! Trim the trailing dot off. EDIT (get_file_parm, UPPER, COLLAPSE); IF (SUBSTR (get_file_parm, LENGTH(get_file_parm), 1) <> '.') THEN IF (SUBSTR (temp_buffer_name, LENGTH(temp_buffer_name), 1) = '.') THEN temp_buffer_name := SUBSTR (temp_buffer_name, 1, LENGTH(temp_buffer_name)-1); ENDIF; ENDIF; ENDIF; loop_buffer := GET_INFO (BUFFERS, "FIRST"); found_a_buffer := 0; LOOP EXITIF loop_buffer = 0; IF temp_buffer_name = GET_INFO (loop_buffer, "NAME") THEN found_a_buffer := 1; EXITIF 1; ENDIF; loop_buffer := GET_INFO (BUFFERS, "NEXT"); ENDLOOP; ! If there is a buffer by that name, is it the same file? ! We ignore version numbers to keep our sanity IF found_a_buffer THEN ! Have a buffer with the same name IF temp_file_name = 0 THEN ! No file on disk IF get_file_name = GET_INFO (loop_buffer, "OUTPUT_FILE") THEN want_new_buffer := 0; ELSE ! If the buffer is empty, then throw it ! away. IF (GET_INFO (loop_buffer, "RECORD_COUNT") > 0) THEN want_new_buffer := 0; ELSE IF (temp_file_name <> 0) and (temp_file_name <> "") THEN vi$info ("Buffer empty, reading file"); POSITION (loop_buffer); vi$info (FAO ('Reading "!AS"', temp_file_name)); file_read := READ_FILE (temp_file_name); IF file_read <> "" THEN SET (OUTPUT_FILE, loop_buffer, file_read); vi$status_lines (loop_buffer); ENDIF; ENDIF; want_new_buffer := 2; POSITION (BEGINNING_OF (loop_buffer)); MAP (CURRENT_WINDOW, loop_buffer); obuf := loop_buffer; ENDIF; ENDIF; ELSE ! Check to see if the same file outfile := GET_INFO (loop_buffer, "OUTPUT_FILE"); filename := GET_INFO (loop_buffer, "FILE_NAME"); ! Trim version numbers off all of the names. IF (outfile <> 0) THEN outfile := FILE_PARSE (outfile, "", "", DEVICE) + FILE_PARSE (outfile, "", "", DIRECTORY) + FILE_PARSE (outfile, "", "", NAME) + FILE_PARSE (outfile, "", "", TYPE); ENDIF; IF (filename <> 0) THEN filename := FILE_PARSE (filename, "", "", DEVICE) + FILE_PARSE (filename, "", "", DIRECTORY) + FILE_PARSE (filename, "", "", NAME) + FILE_PARSE (filename, "", "", TYPE); ENDIF; temp_file_name := FILE_PARSE (temp_file_name, "", "", DEVICE) + FILE_PARSE (temp_file_name, "", "", DIRECTORY) + FILE_PARSE (temp_file_name, "", "", NAME) + FILE_PARSE (temp_file_name, "", "", TYPE); ! If the buffer is empty, then throw it away. IF (GET_INFO (loop_buffer, "RECORD_COUNT") > 0) THEN IF (outfile = temp_file_name) OR (filename = temp_file_name) THEN want_new_buffer := 0; ELSE want_new_buffer := 1; ENDIF; ELSE IF temp_file_name <> 0 THEN vi$info ("Buffer empty, reading file"); POSITION (loop_buffer); vi$info (FAO ('Reading "!AS"', temp_file_name)); file_read := READ_FILE (temp_file_name); IF (file_read <> "") THEN SET (OUTPUT_FILE, loop_buffer, file_read); vi$status_lines (loop_buffer); ENDIF; ENDIF; want_new_buffer := 2; POSITION (BEGINNING_OF (loop_buffer)); MAP (CURRENT_WINDOW, loop_buffer); obuf := loop_buffer; ENDIF; ENDIF; IF want_new_buffer = 1 THEN vi$info (FAO ( "Buffer name !AS is in use", temp_buffer_name)); temp_buffer_name := vi$read_line ( "Type new buffer name or press Return to cancel: "); IF temp_buffer_name = "" THEN vi$info ("No new buffer created"); ELSE new_buffer := vi$_create_buffer (temp_buffer_name, get_file_name, temp_file_name); ENDIF; ELSE IF (want_new_buffer = 0) and (CURRENT_BUFFER = loop_buffer) THEN vi$info (FAO ( "Already editing file !AS", get_file_name)); ELSE IF (want_new_buffer = 0) THEN IF (vi$check_auto_write) THEN RETURN; ENDIF; MAP (CURRENT_WINDOW, loop_buffer); obuf := loop_buffer; ENDIF; ENDIF; ENDIF; ELSE ! No buffer with the same name, so create a new buffer new_buffer := vi$_create_buffer (temp_buffer_name, get_file_name, temp_file_name); ENDIF; IF new_buffer <> 0 THEN SET (EOB_TEXT, new_buffer, "[EOB]"); SET (TAB_STOPS, new_buffer, vi$tab_amount); ENDIF; loop_cnt := loop_cnt - 1; EXITIF loop_cnt <= 0; POSITION (BEGINNING_OF (choice_buffer)); temp_file_name := vi$current_line; ERASE_LINE; ENDLOOP; IF (file_cnt > 1) THEN vi$_first_file (0); ENDIF; vi$set_status_line (CURRENT_WINDOW); RETURN (file_cnt); ENDPROCEDURE; ! ! This procedure collects the names of all buffers that are leading ! derivatives of "buffer_name". The function value is the boolean ! value telling whether or not the name matched exactly. The other ! parameters are return values. ! PROCEDURE vi$choose_buffer (buffer_name, how_many_buffers, possible_buffer, possible_buffer_name, loop_buffer) LOCAL this_buffer, ! Current buffer loop_buffer_name, ! String containing name of loop_buffer found_a_buffer; ! True if buffer found with same exact name found_a_buffer := 0; EDIT (buffer_name, COLLAPSE); possible_buffer := 0; possible_buffer_name := 0; how_many_buffers := 0; ! See if we already have a buffer by that name this_buffer := CURRENT_BUFFER; loop_buffer := GET_INFO (BUFFERS, "FIRST"); CHANGE_CASE (buffer_name, UPPER); ! buffer names are uppercase ERASE (choice_buffer); LOOP EXITIF loop_buffer = 0; loop_buffer_name := GET_INFO (loop_buffer, "NAME"); IF buffer_name = loop_buffer_name THEN found_a_buffer := 1; how_many_buffers := 1; EXITIF 1; ELSE IF buffer_name = SUBSTR (loop_buffer_name, 1, LENGTH (buffer_name)) THEN vi$add_choice (loop_buffer_name); possible_buffer := loop_buffer; possible_buffer_name := loop_buffer_name; how_many_buffers := how_many_buffers + 1; ENDIF; ENDIF; loop_buffer := GET_INFO (BUFFERS, "NEXT"); ENDLOOP; RETURN (found_a_buffer); ENDPROCEDURE; ! ! Return current line or empty string if at EOB ! PROCEDURE vi$current_line IF (MARK (NONE) = END_OF (CURRENT_BUFFER)) THEN RETURN (""); ELSE RETURN (CURRENT_LINE); ENDIF; ENDPROCEDURE; ! ! If autowrite is active, then write the current buffer out. ! PROCEDURE vi$check_auto_write LOCAL buf, win, owin, mod; mod := GET_INFO (CURRENT_BUFFER, "MODIFIED") AND (NOT GET_INFO (CURRENT_BUFFER, "SYSTEM")) AND (NOT GET_INFO (CURRENT_BUFFER, "NO_WRITE")); buf := CURRENT_BUFFER; IF mod AND vi$auto_write THEN IF (vi$can_write (CURRENT_BUFFER)) THEN vi$info ("Writing out """+GET_INFO (buf, "NAME")+""""); WRITE_FILE (buf); ELSE RETURN (1); ENDIF; ENDIF; IF (NOT mod) AND (NOT GET_INFO (CURRENT_BUFFER, "SYSTEM")) AND (NOT GET_INFO (CURRENT_BUFFER, "NO_WRITE")) AND (GET_INFO (buf, "RECORD_COUNT") = 0) THEN IF (vi$delete_empty) THEN vi$info ("Deleting empty buffer: "+GET_INFO (buf, "NAME")); MAP (CURRENT_WINDOW, message_buffer); owin := CURRENT_WINDOW; win := GET_INFO (WINDOWS, "FIRST"); LOOP EXITIF win = 0; IF (GET_INFO (win, "BUFFER") = buf) THEN MAP (win, message_buffer); vi$set_status_line (win); ENDIF; win := GET_INFO (WINDOWS, "NEXT"); ENDLOOP; POSITION (owin); DELETE (buf); ELSE vi$last_mapped := buf; ENDIF; ELSE vi$last_mapped := buf; ENDIF; RETURN (0); ENDPROCEDURE; ! ! Only perform an update if there is not a keyboard macro in progress. ! PROCEDURE vi$update (win) IF (vi$key_buf = 0) AND (vi$playing_back = 0) THEN UPDATE (win); ENDIF; ENDPROCEDURE; ! ! This procedure should be envoked after a wild card edit. It will allow ! a list of files that have been created due to a wildcard filespec to be ! processed sequentially. ! PROCEDURE vi$_next_file (bang) LOCAL win, fn, pos, found_one, btype, bn, how_many_buffers, possible_buffer, possible_buffer_name, loop_buffer, line; ON_ERROR ! Ignore errors ENDON_ERROR; IF (NOT bang) AND (vi$check_auto_write) THEN RETURN; ENDIF; pos := MARK (NONE); win := CURRENT_WINDOW; POSITION (vi$file_names); IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN MOVE_VERTICAL (1); IF (MARK (NONE) = END_OF (CURRENT_BUFFER)) THEN vi$info ("No more files!"); MOVE_VERTICAL (-1); POSITION (win); RETURN (1); ENDIF; ELSE vi$info ("No more files!"); POSITION (win); RETURN (1); ENDIF; fn := vi$current_line; bn := FILE_PARSE (fn, "", "", NAME); btype := FILE_PARSE (fn, "", "", TYPE); IF btype = "" THEN btype := "."; $$EOD$$