[comp.os.vms] VI in TPU part 11/14

gregg@a.cs.okstate.edu (Gregg Wonderly) (10/21/87)

$!=============================================================================
$! VAX/VMS archive file created by VMS_SHAR V-4.03 05-Aug-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by GREGG
$!      on Tuesday 20-OCT-1987 22:45:39.68
$!
$! It contains the following 1 file:
$! VI.9
$!=============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set (Output_File,b,o);
Position (Beginning_of(b));Loop x:=Erase_Character(1); Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;Move_Horizontal
(-Current_Offset);EndLoop;Move_Vertical(1);ExitIf Mark(None)=End_of(b)
EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="VI.9"
$ Check_Sum_is=290560531
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X    vi$active_count := 0;
XENDPROCEDURE;
X
X!
X!   Move to line in file.  vi$active_count holds the line number to GO TO.
X!   If VI$ACTIVE_COUNT is zero, we move to the end of the file.
X!
XPROCEDURE vi$to_line (cnt)
X
X    LOCAL
X        this_pos,           ! Saved position in case of botch
X        last_line,          ! Last line in the buffer
X        win_len;            ! Length of CURRENT_WINDOW
X
X    ON_ERROR
X        vi$message (FAO ("No such line: !SL", VI$ACTIVE_COUNT));
X        POSITION (this_pos);
X        cnt := 0;
X        RETURN;
X    ENDON_ERROR;
X
X    this_pos := MARK(NONE);
X    MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    vi$start_pos := MARK (NONE);
X
X    IF cnt = 0 THEN
X        POSITION (END_OF (CURRENT_BUFFER));
X    ELSE
X        last_line := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
X
X        IF cnt > last_line THEN
X            IF last_line > 0 THEN
X                vi$message ("Not that many lines in buffer");
X                POSITION (this_pos);
X                RETURN (0);
X            ENDIF;
X        ELSE
X            POSITION (BEGINNING_OF (CURRENT_BUFFER));
X            win_len := GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH");
X            MOVE_VERTICAL (cnt - 1);
X            cnt := 0;
X        ENDIF;
X    ENDIF;
X
X    IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN
X        MOVE_VERTICAL (1);
X        MOVE_HORIZONTAL (-1);
X        vi$new_endpos := MARK (NONE);
X        MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    ENDIF;
X
X    vi$yank_mode := VI$LINE_MODE;
X    RETURN (vi$retpos (this_pos));
XENDPROCEDURE;
X
X!
X!   Set a marker in the current buffer.
X!
XPROCEDURE vi$_set_mark
X
X    LOCAL
X        mark_char,
X        mark_name,
X        key_pressed;
X
X    key_pressed := vi$read_a_key;
X
X    mark_char := ASCII (key_pressed);
X    IF (INDEX (vi$_lower_chars, mark_char) <> 0) THEN
X        mark_name := "vi$mark_" + mark_char;
X        EXECUTE (COMPILE (mark_name + " := MARK(NONE);"));
X    ELSE
X        vi$MESSAGE ("Invalid marker key!");
X    ENDIF;
X
XENDPROCEDURE;
X
X!
X!   Function mapped to "'" and "`".
X!
XPROCEDURE vi$_go_to_marker
X    IF (vi$position (vi$to_marker, 1) <> 0) THEN
X        vi$pos_in_middle (MARK (NONE));
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Function to move the marker indicated by the next keystroke.
X!
XPROCEDURE vi$to_marker
X
X    LOCAL
X        mode_key,
X        pos,
X        mark_name,
X        mark_char,
X        key_pressed;
X
X    ON_ERROR;
X        vi$message ("Mark not set!");
X        RETURN (0);
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X    mode_key := vi$last_key;
X    key_pressed := vi$read_a_key;
X
X    mark_char := ASCII (key_pressed);
X    IF (INDEX (vi$_lower_chars+"'`", mark_char) = 0) THEN
X        vi$MESSAGE ("Invalid marker key!");
X        RETURN (0);
X    ENDIF;
X
X    IF (key_pressed <> F11) THEN
X        IF (mark_char = "'") OR (mark_char = "`") THEN
X            IF (vi$old_place <> 0) THEN
X                IF (GET_INFO (vi$old_place, "BUFFER") = CURRENT_BUFFER) THEN
X                    POSITION (vi$old_place);
X                ELSE
X                    MESSAGE ("Previous place not in this buffer!");
X                    RETURN (0);
X                ENDIF;
X            ELSE
X                MESSAGE ("No previous mark to return to!");
X                RETURN (0);
X            ENDIF;
X        ELSE
X            mark_name := "vi$mark_" + mark_char;
X            EXECUTE (COMPILE ("vi$global_mark := "+mark_name+";"));
X
V            IF (vi$global_mark <> 0) AND (GET_INFO (vi$global_mark, "BUFFER") 
X=
V                                                            CURRENT_BUFFER) TH
XEN
X                POSITION (vi$global_mark);
X                vi$yank_mode := VI$LINE_MODE;
X            ELSE
X                vi$message ("Invalid mark for this buffer!");
X                RETURN (0);
X            ENDIF;
X        ENDIF;
X
X        IF ASCII (mode_key) = "'" THEN
X            MOVE_HORIZONTAL (-CURRENT_OFFSET);
X            POSITION (vi$first_no_space);
X        ENDIF;
X
X        IF (MARK (NONE) <> END_OF (CURRENT_BUFFER)) THEN
X            MOVE_VERTICAL (1);
X            vi$new_endpos := MARK (NONE);
X            MOVE_VERTICAL (-1);
X        ENDIF;
X
X        RETURN (vi$retpos (pos));
X    ENDIF;
X
X    POSITION (pos);
X    RETURN (0);
XENDPROCEDURE;
X
X!
X!   Maintain the repeat count in vi$active_count.  If VI$ACTIVE_COUNT is ZERO,
X!   and '0' is typed, this means move to beginning of the line.
X!
XPROCEDURE vi$repeat_count
X
X    IF VI$ACTIVE_COUNT = 0 THEN
X        vi$active_count := INT (ASCII (KEY_NAME (vi$last_key)));
X        IF vi$active_count = 0 THEN
X            vi$position (vi$fol, 0);
X        ENDIF;
X    ELSE
X        vi$active_count := vi$active_count * 10 +
X                                    INT (ASCII (KEY_NAME (vi$last_key)));
X    ENDIF;
X
XENDPROCEDURE;
X
X!
X!   The function mapped to <CR>.
X!
XPROCEDURE vi$_next_line
X    POSITION (vi$beg_next);
XENDPROCEDURE;
X
X!
X!   Move the cursor to the beginning of the next line
X!
XPROCEDURE vi$beg_next
X    LOCAL
X        pos;
X
X    ON_ERROR
X        RETURN (MARK (NONE));
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X    MOVE_VERTICAL (vi$cur_active_count);
X    MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    POSITION (vi$first_no_space);
X    vi$yank_mode := VI$LINE_MODE;
X    vi$new_offset := 1;
X    RETURN (vi$retpos (pos));
X
XENDPROCEDURE;
X
X!
X!   This function moves to the first non-blank character of a line
X!
XPROCEDURE vi$first_no_space
X
X    LOCAL
X        pos,
X        t_range;
X
X    ON_ERROR
X        ! Ignore string not found messages.
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X    MOVE_HORIZONTAL (- CURRENT_OFFSET);
X
X    IF (LENGTH (CURRENT_LINE) > 0) THEN
X        IF t_range = 0 THEN
X            t_range :=
X                SEARCH (ANCHOR & SPAN (vi$no_space) &
X                                        NOTANY(vi$no_space), FORWARD);
X        ENDIF;
X
X        IF t_range <> 0 THEN
X            POSITION (END_OF (t_range));
X        ELSE
X            ! If that fails, then search for a blank line with extra white
X            ! space, and move to the end of the white space.
X
X            t_range := SEARCH (ANCHOR & SPAN (vi$no_space), FORWARD);
X
X            IF t_range <> 0 THEN
X                POSITION (END_OF (t_range));
X            ENDIF;
X        ENDIF;
X    ENDIF;
X
X    vi$yank_mode := VI$IN_LINE_MODE;
X    RETURN (vi$retpos (pos));
XENDPROCEDURE;
X
X!
X!   Move by a section in the indicated direction
X!
XPROCEDURE vi$_section (dir)
X    LOCAL
X        ch;
X
X    ch := vi$read_a_key;
X    IF ((ASCII(ch) = "]") AND (dir = 1)) OR
X        ((ASCII(ch) = "[") AND (dir = -1)) THEN
X        vi$position (vi$section (dir), 1);
X    ELSE
X        vi$beep;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   Sound a bell.
X!
XPROCEDURE vi$beep
X    LOCAL
X        pos;
X
X    IF (vi$error_bells = 0) THEN
X        RETURN;
X    ENDIF;
X
X    pos := CURRENT_WINDOW;
X    SET (BELL, ALL, ON);
X    MESSAGE ("");
X    SET (BELL, ALL, OFF);
X    SET (BELL, BROADCAST, ON);
X    POSITION (pos);
XENDPROCEDURE;
X
X!
X!   Mapped to '}' and '{', moves by a paragraph in the indicated direction.
X!
XPROCEDURE vi$_paragraph(dir)
X    vi$position (vi$paragraph(dir), 1);
XENDPROCEDURE;
X
X!
X!   Mapped to ( moves backward a sentence
X!
XPROCEDURE vi$_begin_sentence
X    vi$position (vi$begin_sentence, 1);
XENDPROCEDURE;
X
X!
X!   Mapped to ) moves forward a sentence
X!
XPROCEDURE vi$_end_sentence
X    vi$position (vi$end_sentence, 1);
XENDPROCEDURE;
X
X!
X!   Move backward a sentence.
X!
XPROCEDURE vi$begin_sentence
X    LOCAL
X        rng,
X        spos,
X        pos;
X
X    ON_ERROR;
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X
X    MOVE_HORIZONTAL (-1);
X
X    LOOP;
X        rng := SEARCH (
X            (("" | " " | "  ") & ANY (vi$_upper_chars)),
X            REVERSE, EXACT);
X
X        EXITIF rng = 0;
X
X        POSITION (BEGINNING_OF (rng));
X        IF INDEX ("     ", CURRENT_CHARACTER) = 0 THEN
X            MOVE_HORIZONTAL (-1);
X        ENDIF;
X        IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
X            IF (CURRENT_CHARACTER = " ") THEN
X                MOVE_HORIZONTAL (-1);
X                IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
X                    MOVE_HORIZONTAL (-1);
X                    IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN
X                        MOVE_HORIZONTAL (3);
X                        RETURN (vi$retpos (pos));
X                    ENDIF;
X                ENDIF;
X            ELSE
X                MOVE_HORIZONTAL (1);
X                RETURN (vi$retpos (pos));
X            ENDIF;
X        ENDIF;
X        POSITION (BEGINNING_OF (rng));
X        MOVE_HORIZONTAL (-1);
X    ENDLOOP;
X
X    RETURN (0);
XENDPROCEDURE;
X
X!
X!   Move to next paragraph
X!
XPROCEDURE vi$paragraph (dir)
X    RETURN (vi$para_sect (dir, vi$para_pat));
XENDPROCEDURE;
X
X!
X!   Find next paragraph or section.
X!
XPROCEDURE vi$para_sect (dir, pat)
X    LOCAL
X        loc,
X        direct,
X        pos;
X
X    pos := MARK (NONE);
X
X    IF (dir < 0) THEN
X        direct := REVERSE;
X        MOVE_VERTICAL (-1);
X    ELSE
X        direct := FORWARD;
X        MOVE_VERTICAL (1);
X    ENDIF;
X
X    SET (TIMER, ON, "Searching...");
X    loc := SEARCH (pat, direct, NO_EXACT);
X    SET (TIMER, OFF);
X
X    IF (loc <> 0) THEN
X        RETURN (BEGINNING_OF (loc));
X    ELSE
X        SET (TIMER, ON, "Searching...");
X        loc := SEARCH (vi$next_blank, direct, NO_EXACT);
X        SET (TIMER, OFF);
X        IF (loc <> 0) THEN
X            RETURN (BEGINNING_OF (loc));
X        ENDIF;
X    ENDIF;
X
X    POSITION (pos);
X    RETURN (0);
XENDPROCEDURE;
X
X!
X!   Move to next section
X!
XPROCEDURE vi$section (dir)
X    RETURN (vi$para_sect (dir, vi$sect_pat));
XENDPROCEDURE;
X
X!
X!   Move forward a sentence.
X!
XPROCEDURE vi$end_sentence
X    LOCAL
X        rng,
X        spos,
X        pos;
X
X    ON_ERROR;
X    ENDON_ERROR;
X
X    pos := MARK (NONE);
X
X    MOVE_HORIZONTAL (1);
X
X    LOOP;
X        rng := SEARCH (ANY (vi$_upper_chars), FORWARD, EXACT);
X
X        EXITIF rng = 0;
X
X        POSITION (BEGINNING_OF (rng));
X        IF INDEX ("     ", CURRENT_CHARACTER) = 0 THEN
X            MOVE_HORIZONTAL (-1);
X        ENDIF;
X        IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
X            IF (CURRENT_CHARACTER = " ") THEN
X                MOVE_HORIZONTAL (-1);
X                IF INDEX ("     ", CURRENT_CHARACTER) <> 0 THEN
X                    MOVE_HORIZONTAL (-1);
X                    IF INDEX ("?.!", CURRENT_CHARACTER) <> 0 THEN
X                        MOVE_HORIZONTAL (3);
X                        RETURN (vi$retpos (pos));
X                    ENDIF;
X                ENDIF;
X            ELSE
X                MOVE_HORIZONTAL (1);
X                RETURN (vi$retpos (pos));
X            ENDIF;
X        ENDIF;
X        POSITION (BEGINNING_OF (rng));
X        MOVE_HORIZONTAL (1);
X    ENDLOOP;
X
X    RETURN (0);
XENDPROCEDURE;
X
X!
X!   This function returns the value in vi$active count.  It takes into
X!   account that when vi$active_count is zero, it should really be
X!   one.
X!
XPROCEDURE vi$cur_active_count
X    LOCAL
X        resp,
X        old_cnt;
X
X    old_cnt := vi$active_count;
X    vi$active_count := 0;
X    IF old_cnt <= 0 THEN
X        old_cnt := 1;
X    ENDIF;
X
X    RETURN (old_cnt);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'p'.
X!
XPROCEDURE vi$put_after (dest_buf)
X
X    LOCAL
X        source,
X        pos;
X
X    source := vi$cur_text;
X
X    IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN
X        source := dest_buf;
X    ENDIF;
X
X    IF (GET_INFO (source, "TYPE") = BUFFER) THEN
X        pos := MARK (NONE);
X        POSITION (BEGINNING_OF (source));
X        vi$yank_mode := INT (vi$current_line);
X        POSITION (pos);
X    ENDIF;
X
X    IF (source = "") THEN
X        RETURN;
X    ENDIF;
X
X    IF (vi$yank_mode = VI$LINE_MODE) THEN
X        IF (MARK(NONE) <> END_OF (CURRENT_BUFFER)) THEN
X            MOVE_VERTICAL (1);
X        ENDIF;
X    ELSE
X        IF (LENGTH (CURRENT_LINE) > 0) THEN
X            MOVE_HORIZONTAL (1);
X        ENDIF;
X    ENDIF;
X
X    vi$put_here (VI$AFTER, source);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'P'.
X!
XPROCEDURE vi$put_here (here_or_below, dest_buf)
X    LOCAL
X        olen,
X        source,
X        pos;
X
X    source := vi$cur_text;
X    olen := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
X
X    IF (GET_INFO (dest_buf, "TYPE") = BUFFER) THEN
X        source := dest_buf;
X    ENDIF;
X
X    IF (GET_INFO (source, "TYPE") = BUFFER) THEN
X        pos := MARK (NONE);
X        POSITION (BEGINNING_OF (source));
X        IF (MARK (NONE) = END_OF (source)) THEN
X            RETURN;
X        ENDIF;
X        vi$yank_mode := INT (vi$current_line);
X        ERASE_LINE;
X        POSITION (pos);
X    ELSE
X        IF (source = "") THEN
X            RETURN;
X        ENDIF;
X    ENDIF;
X
X    IF source = 0 THEN
X        vi$message ("Bad buffer for put!");
X        RETURN;
X    ENDIF;
X
X    IF (vi$yank_mode = VI$LINE_MODE) THEN
X        MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    ENDIF;
X
X    pos := vi$get_undo_start;
X
X    COPY_TEXT (source);
X    APPEND_LINE;
X    MOVE_HORIZONTAL (-1);
X    vi$undo_end := MARK (NONE);
X    MOVE_HORIZONTAL (1);
X
X    vi$kill_undo;
X
X    IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$LINE_MODE) THEN
X        MOVE_HORIZONTAL (-CURRENT_OFFSET);
X    ENDIF;
X
X    vi$undo_start := vi$set_undo_start (pos);
X
X    ! Put the mode back into the buffer.
X
X    IF (GET_INFO (source, "TYPE") = BUFFER) THEN
X        POSITION (BEGINNING_OF (source));
X        COPY_TEXT (STR (vi$yank_mode));
X        SPLIT_LINE;
X        POSITION (vi$undo_start);
X    ENDIF;
X
X    IF (here_or_below = VI$AFTER) AND (vi$yank_mode = VI$IN_LINE_MODE) THEN
X        POSITION (vi$undo_end);
X    ENDIF;
X
X    vi$check_length (olen);
XENDPROCEDURE;
X
X!
X!   Function mapped to 'o'.  Note that this makes undo NOT place
X!   the cursor where is really should be.
X!
XPROCEDURE vi$open_below
X    LOCAL
X        uline;
X
X    ON_ERROR
X        ! Ignore attempt to move past EOB errors
X    ENDON_ERROR;
X
X    uline := vi$cur_line_no;
X    MOVE_VERTICAL (1);
X    vi$open_here;
X    vi$undo_line := uline;
X
XENDPROCEDURE;
X
X!
X!   Function mapped to 'O'
X!
XPROCEDURE vi$open_here
X
X    LOCAL
X        uline,
X        offs,
X        cnt,
X        epos,
X        spos;
X
X    uline := vi$cur_line_no;
X    offs := CURRENT_OFFSET;
X
X    MOVE_HORIZONTAL (- CURRENT_OFFSET);
X
X    IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
X        MOVE_HORIZONTAL (-1);
X        spos := MARK (NONE);
X        MOVE_HORIZONTAL (1);
X    ELSE
X        spos := 0;
X    ENDIF;
X
X    SPLIT_LINE;
X
X    MOVE_VERTICAL (-1);
X
X    cnt := vi$while_not_esc;
X    epos := MARK (NONE);
X
X    IF (cnt <> 0) THEN
X        IF (LENGTH (vi$current_line) > 0) THEN
X            MOVE_HORIZONTAL (1);
X        ENDIF;
X    ENDIF;
X
X    vi$undo_end := MARK (NONE);
X
X    IF spos <> 0 THEN
X        POSITION (spos);
X        MOVE_HORIZONTAL (1);
X    ELSE
X        POSITION (BEGINNING_OF (CURRENT_BUFFER));
X    ENDIF;
X
X    vi$undo_start := MARK (NONE);
X    POSITION (epos);
X
X    vi$kill_undo;
X
X    vi$undo_line := uline;
X    vi$undo_offset := offs;
XENDPROCEDURE;
X
X!
X!   This function guards the right margin, and the end of the buffer so
X!   that the cursor never is displayed past those boundries.
X!
XPROCEDURE vi$check_rmarg
X
X    ON_ERROR;
X        ! ignore "Can't return line and end of buffer" messages
X        RETURN;
X    ENDON_ERROR;
X
X    IF (LENGTH (vi$current_line) > 0) THEN
X        IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN
X            MOVE_HORIZONTAL (-1);
X        ENDIF;
X    ENDIF;
X
X    IF (MARK (NONE) = END_OF (CURRENT_BUFFER)) THEN
X        MOVE_VERTICAL (-1);
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   The function mapped to 'h'.
X!
XPROCEDURE vi$move_left
X    vi$position (vi$left, 0);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'l'.
X!
XPROCEDURE vi$move_right
X    vi$position (vi$right, 0);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'j'
X!
XPROCEDURE vi$move_down
X    LOCAL
X        save_mark;
X
X    save_mark := 0;
X
X    IF (vi$active_count >= vi$report) THEN
X        save_mark := 1;
X    ENDIF;
X
X    vi$position (vi$downline (0), save_mark);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'k'.
X!
XPROCEDURE vi$move_up
X    LOCAL
X        save_mark;
X
X    save_mark := 0;
X
X    IF (vi$active_count >= vi$report) THEN
X        save_mark := 1;
X    ENDIF;
X
X    vi$position (vi$upline, save_mark);
XENDPROCEDURE;
X
X!
X!   The function mapped to 'i'.
X!
XPROCEDURE vi$insert_here
X    LOCAL
X        act_cnt,
X        rnge,
X        ccnt,
X        epos,
X        spos;
X
X    vi$kill_undo;
X
X    IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
X        MOVE_HORIZONTAL (-1);
X        spos := MARK (NONE);
X        MOVE_HORIZONTAL (1);
X    ELSE
X        spos := 0;
X    ENDIF;
X
X    vi$undo_start := MARK (NONE);
X
X    ccnt := vi$while_not_esc;
X
X    vi$undo_end := 0;
X
X    IF (ccnt > 0) THEN
X        IF (CURRENT_OFFSET = 0) AND
X                        ((ccnt > 1) OR (LENGTH (CURRENT_LINE) = 0)) AND
X                        (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
X            MOVE_HORIZONTAL (-1);
X            epos := MARK (NONE);
X            MOVE_HORIZONTAL (1);
X        ELSE
X            epos := MARK (NONE);
X        ENDIF;
X    ELSE
X        epos := 0;
X    ENDIF;
X
X    IF epos <> 0 THEN
X        act_cnt := vi$cur_active_count;
X
X        IF spos <> 0 THEN
X            POSITION (spos);
X            MOVE_HORIZONTAL (1);
X        ELSE
X            POSITION (BEGINNING_OF (CURRENT_BUFFER));
X        ENDIF;
X        vi$undo_start := MARK (NONE);
X
X        POSITION (epos);
X
X        IF (vi$undo_start = 0) OR (epos = 0) THEN
X            vi$message ("Ooops, bad markers in vi$insert_here");
X            RETURN ;
X        ENDIF;
X
X        rnge := CREATE_RANGE (vi$undo_start, epos, NONE);
X
X        LOOP
X            EXITIF act_cnt < 2;
X            MOVE_HORIZONTAL (1);
X
X            IF rnge = 0 THEN
X                vi$message ("Ooops, generated a bad range in vi$insert_here");
X                RETURN ;
X            ENDIF;
X
X            COPY_TEXT (rnge);
X            act_cnt := act_cnt - 1;
X            MOVE_HORIZONTAL (-1);
X        ENDLOOP;
X
X        vi$undo_end := MARK (NONE);
X        IF (CURRENT_OFFSET = LENGTH (vi$current_line)) THEN
X            MOVE_HORIZONTAL (1);
X        ENDIF;
X    ENDIF;
XENDPROCEDURE;
X
X!
X!   The function mapped to 'I'
X!
XPROCEDURE vi$insert_at_begin
X
X    MOVE_HORIZONTAL (- CURRENT_OFFSET);
X    vi$_bol;
X    vi$insert_here;
X
XENDPROCEDURE;
X
X!
X!   The function mapped to 'a'
X!
XPROCEDURE vi$insert_after
X
X    IF (LENGTH (vi$current_line) > 0) THEN
X        IF (CURRENT_OFFSET < LENGTH(vi$current_line)) THEN
X            MOVE_HORIZONTAL (1);
X        ENDIF;
X    ENDIF;
X    vi$insert_here;
X
XENDPROCEDURE;
X
X!
X!  A do nothing function
X!
XPROCEDURE vi$_dummy
XENDPROCEDURE;
X
X!
X!  Do the command line input processing
X!
XPROCEDURE vi$while_not_esc
X
X    LOCAL
X        max_mark,
X        start_pos,
X        max_col;
X
X    max_col := CURRENT_OFFSET;
X    start_pos := max_col;
X    max_mark := MARK(NONE);
X    vi$update (CURRENT_WINDOW);
X
X    RETURN (vi$line_edit (max_col, start_pos, max_mark, 0));
XENDPROCEDURE;
X
X!
X!   Insert text into the buffer using standard VI insertion.
X!   Used by CHANGE, APPEND, INSERT, and REPLACE functions.
X!
XPROCEDURE vi$line_edit (max_col, start_pos, max_mark, replace)
X
X    LOCAL
X        chcnt,
X        offset,
X        seen_eol,
X        col,
X        cnt,
X        tabstops,
X        current_mark,
X        desc,
X        start_ins,
X        ins_text,
X        should_wrap,
X        abbrs,
X        rchar,
X        abbrlen,
X        cabbr,
X        pos,
X        in_char;
X
X    ON_ERROR
X    ENDON_ERROR;
X
X    IF (vi$show_mode) THEN
X        vi$mess_select (BOLD);
X        MESSAGE (FAO ("!7*  INSERT"));
X        vi$mess_select (REVERSE);
X    ENDIF;
X    chcnt := 0;
X    seen_eol := 0;
X
X    abbrs := EXPAND_NAME ("vi$abbr_", VARIABLES) + " ";
X
X    cabbr := "";
X    abbrlen := 0;
X
X    SET (INSERT, CURRENT_BUFFER);
X    IF (max_col > CURRENT_OFFSET) OR (replace <> 0) THEN
X        SET (OVERSTRIKE, CURRENT_BUFFER);
X    ENDIF;
X
X    start_ins := MARK (NONE);
X
X    LOOP
X        LOOP
X            in_char := vi$read_a_key;
X            desc := LOOKUP_KEY (KEY_NAME (in_char), COMMENT, vi$edit_keys);
X            EXITIF (desc <> "reinsert");
X
X            IF max_mark <> MARK (NONE) THEN
X                current_mark := MARK (NONE);
X                POSITION (max_mark);
X                MOVE_HORIZONTAL (-1);
X
X                ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE));
X            ENDIF;
X
X            SET (INSERT, CURRENT_BUFFER);
X            COPY_TEXT (vi$last_insert);
X            APPEND_LINE;
X
X            max_col := CURRENT_OFFSET;
X            start_pos := CURRENT_OFFSET;
X            max_mark := MARK(NONE);
X            chcnt := chcnt + 1;
X        ENDLOOP;
X
X        IF (desc = "active_macro") THEN
X            EXECUTE (LOOKUP_KEY (KEY_NAME (in_char), PROGRAM, vi$edit_keys));
X        ELSE
X            EXITIF desc = "escape";
X
X            should_wrap := (vi$wrap_margin <> 0) AND
V                            ((CURRENT_OFFSET + vi$wrap_margin) > vi$scr_width)
X;
X
X            IF (desc <> "eol") AND (desc <> "bword") AND (desc <> "bs") THEN
X                IF (should_wrap) THEN
X
X                    offset := 0;
X                    MOVE_HORIZONTAL (-1);
X
X                    LOOP
X                        EXITIF (CURRENT_OFFSET = 0);
X                        EXITIF (INDEX ("    ", CURRENT_CHARACTER) <> 0);
X                        MOVE_HORIZONTAL (-1);
X                        offset := offset + 1;
X                    ENDLOOP;
X
X                    IF (offset <> 0) THEN
X                        ERASE_CHARACTER (1);
X                        LOOP
X                            EXITIF (CURRENT_OFFSET = 0);
X                            MOVE_HORIZONTAL (-1);
X                            EXITIF (
X                                INDEX ("    ", CURRENT_CHARACTER) = 0);
X                            ERASE_CHARACTER (1);
X                        ENDLOOP;
X                    ENDIF;
X
X                    IF (CURRENT_OFFSET <> 0) THEN
X                        MOVE_HORIZONTAL (1);
X                        SPLIT_LINE;
X                        max_col := CURRENT_OFFSET;
X                        start_pos := CURRENT_OFFSET;
X                        max_mark := MARK(NONE);
X                        MOVE_HORIZONTAL (offset);
X                    ELSE
X                        MOVE_HORIZONTAL (offset);
X                        SPLIT_LINE;
X                        max_col := CURRENT_OFFSET;
X                        start_pos := CURRENT_OFFSET;
X                        max_mark := MARK(NONE);
X                    ENDIF;
X                ENDIF;
X
X                vi$update (CURRENT_WINDOW);
X
X                IF desc = "vquote" THEN
X                    in_char := vi$read_a_key;
X                ENDIF;
X
X                IF in_char = TAB_KEY THEN
X                    vi$abbr (abbrs, 0, cabbr, abbrlen);
X                    IF (vi$use_tabs = 1) THEN
X                        COPY_TEXT (ASCII (9));
X                    ELSE
X                        cnt := 0;
X                        col := GET_INFO (SCREEN, "CURRENT_COLUMN");
X                        tabstops := GET_INFO (CURRENT_BUFFER, "TAB_STOPS");
X
X                        IF (GET_INFO (tabstops, "TYPE") <> STRING) THEN
X                            LOOP
X                                EXITIF (col - ((col / tabstops) *
V                                                                tabstops) = 0)
X;
X                                cnt := cnt + 1;
X                                col := col + 1;
X                            ENDLOOP;
X
X                            chcnt := chcnt + cnt;
X                            LOOP
X                                EXITIF (cnt < 0);
X                                IF (CURRENT_OFFSET = max_col) AND
V                                                ((replace = 0) OR seen_eol) TH
XEN
X                                    SET (INSERT, CURRENT_BUFFER);
X                                ELSE
X                                    IF CURRENT_OFFSET > max_col THEN
X                                        max_col := CURRENT_OFFSET;
X                                        max_mark := MARK (NONE);;
X                                    ENDIF;
X                                ENDIF;
X                                COPY_TEXT (" ");
X                                cnt := cnt - 1;
X                            ENDLOOP
X                        ELSE
X
X                            ! Give up on windows with weird tab stops.
X
X                            COPY_TEXT (ASCII (9));
X                        ENDIF;
X                    ENDIF;
X                    chcnt := chcnt + 1;
X                ELSE
V                    IF (in_char <= CTRL_Z_KEY) AND (in_char >= CTRL_A_KEY) THE
XN
X                        in_char := (in_char - CTRL_A_KEY) /
X                                    (CTRL_B_KEY - CTRL_A_KEY) + 1;
X                    ENDIF;
X
X                    rchar := vi$ascii(in_char);
X
X                    IF (INDEX (vi$_ws, rchar) <> 0) THEN
V                        chcnt := chcnt + vi$abbr (abbrs, rchar, cabbr, abbrlen
X);
X                    ELSE
X                        COPY_TEXT (rchar);
X                        IF (INDEX(vi$_upper_chars, rchar) <> 0) THEN
X                            cabbr := cabbr + "_";
X                        ENDIF;
X                        cabbr := cabbr + rchar;
X                        abbrlen := abbrlen + 1;
X                        chcnt := chcnt + 1;
X                    ENDIF;
X                ENDIF;
X
X                IF (CURRENT_OFFSET = max_col) AND
X                                    ((replace = 0) OR seen_eol) THEN
X                    SET (INSERT, CURRENT_BUFFER);
X                ELSE
X                    IF CURRENT_OFFSET > max_col THEN
X                        max_col := CURRENT_OFFSET;
X                        max_mark := MARK (NONE);
X                    ENDIF;
X                ENDIF;
X            ELSE
X                IF desc = "bs" THEN
X                    IF start_pos < CURRENT_OFFSET THEN
X                        ! Delete backspace and the character before it.
X                        vi$del_a_key;
X                        vi$del_a_key;
X                        SET (OVERSTRIKE, CURRENT_BUFFER);
X                        MOVE_HORIZONTAL (-1);
X                        chcnt := chcnt - 1;
X                    ENDIF;
X                ELSE
X                    IF desc = "eol" THEN
X                        IF (max_mark <> MARK (NONE)) AND (replace = 0) THEN
X                            current_mark := MARK (NONE);
X                            POSITION (max_mark);
X                            MOVE_HORIZONTAL (-1);
X                            ERASE (CREATE_RANGE (MARK (NONE),
X                                                        current_mark, NONE));
X                        ENDIF;
X                        vi$abbr (abbrs, 0, cabbr, abbrlen);
X                        SPLIT_LINE;
X                        chcnt := chcnt + 1;
X                        seen_eol := 1;
V                        IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THE
XN
X                            MOVE_VERTICAL (-1);
X                            vi$send_to_dcl (CURRENT_LINE);
X                            MOVE_VERTICAL (1);
X                        ENDIF;
X                        max_col := CURRENT_OFFSET;
X                        start_pos := CURRENT_OFFSET;
X                        SET (INSERT, CURRENT_BUFFER);
X                        max_mark := MARK(NONE);
V                        IF (CURRENT_BUFFER = vi$dcl_buf) AND (vi$send_dcl) THE
XN
X                            EXITIF (1);
X                        ENDIF;
X                    ELSE
X                        IF (desc = "bword") THEN
X
X                            ! Backup over whitespace.
X
X                            LOOP
X                                EXITIF start_pos = CURRENT_OFFSET;
X                                MOVE_HORIZONTAL (-1);
X                                chcnt := chcnt - 1;
V                                EXITIF (INDEX ("    ", CURRENT_CHARACTER) = 0)
X;
X                                SET (OVERSTRIKE, CURRENT_BUFFER);
X                            ENDLOOP;
X
X                            ! Backup over noblank words.
X
X                            LOOP
X                                EXITIF start_pos = CURRENT_OFFSET;
X                                SET (OVERSTRIKE, CURRENT_BUFFER);
V                                IF (INDEX ("    ", CURRENT_CHARACTER) <> 0) TH
XEN
X                                    chcnt := chcnt + 1;
X                                    MOVE_HORIZONTAL (1);
X                                    EXITIF (1);
X                                ENDIF;
X                                MOVE_HORIZONTAL (-1);
X                                chcnt := chcnt - 1;
X                            ENDLOOP;
X                        ENDIF;
X                    ENDIF;
X                ENDIF;
X            ENDIF;
X        ENDIF;
X
X        vi$update (CURRENT_WINDOW);
X    ENDLOOP;
X
X    IF max_mark <> MARK (NONE) THEN
X        current_mark := MARK (NONE);
X        IF (NOT seen_eol) AND (replace <> 0) THEN
X            SET (OVERSTRIKE, CURRENT_BUFFER);
X            COPY_TEXT (SUBSTR (replace, CURRENT_OFFSET + 1,
X                                                max_col - CURRENT_OFFSET));
X            POSITION (current_mark);
X        ELSE
X            POSITION (max_mark);
X            IF (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
X                MOVE_HORIZONTAL (-1);
X            ENDIF;
X            ERASE (CREATE_RANGE (MARK (NONE), current_mark, NONE));
X        ENDIF;
X    ENDIF;
X
X    IF (CURRENT_OFFSET > 0) AND
X                            (MARK(NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
X        MOVE_HORIZONTAL (-1);
X    ENDIF;
X
X    ins_text := CREATE_RANGE (start_ins, MARK (NONE), NONE);
X
X    ! Save last inserted text to buffer.
X
X    ERASE (vi$last_insert);
X    pos := MARK (NONE);
X
X    POSITION (vi$last_insert);
X    COPY_TEXT (ins_text);
X    SPLIT_LINE;
X    POSITION (BEGINNING_OF (vi$last_insert));
X
X    POSITION (pos);
X
X    SET (INSERT, CURRENT_BUFFER);
X
X    IF (vi$show_mode) THEN
X        MESSAGE ("");
X    ENDIF;
X    RETURN (chcnt);
XENDPROCEDURE;
X
X!
X!   Check to see if 'cabbr' is a known abbreviation, and substitute the
X!   proper text if it is.
X!
XPROCEDURE vi$abbr (abbrs, rchar, cabbr, abbrlen)
X    LOCAL
X        strg;
X
X    strg := "";
X
X    IF (abbrlen > 0) THEN
X        EDIT (cabbr, UPPER);
X        IF (INDEX (abbrs, "VI$ABBR_"+cabbr+" ") <> 0) THEN
X            vi$global_var := 0;
X            EXECUTE (COMPILE ("vi$global_var := vi$abbr_"+cabbr+";"));
X            IF (vi$global_var <> 0) THEN
X                ERASE_CHARACTER (-abbrlen);
X                strg := vi$global_var;
X                COPY_TEXT (strg);
X            ENDIF;
X        ENDIF;
X        cabbr := "";
X        abbrlen := 0;
X    ENDIF;
X    IF (rchar <> 0) THEN
X        COPY_TEXT (rchar);
X    ENDIF;
X    RETURN (LENGTH (strg) + (rchar <> 0));
XENDPROCEDURE;
X
X!
X!   Return a string describing the KEY_NAME passed.  For control characters,
X!   it is "^?" where the '?' is A-Z.  Otherwise, the value returned by the
X!   ASCII() builtin is used.
X!
XPROCEDURE vi$ascii_name (key_n)
X    LOCAL
X        key;
X
X    key := (key_n - CTRL_A_KEY) / (CTRL_B_KEY - CTRL_A_KEY);
X    IF (key > 31) OR (key < 0) THEN
X        key := ASCII (key_n);
X    ELSE
X        key := "^" + ASCII(key+65);
X    ENDIF;
X
X    RETURN (key);
XENDPROCEDURE;
X
X!
X!   Perform some mapping of keys to different ASCII values.
X!
XPROCEDURE vi$ascii (key_n)
X    IF key_n = F12 THEN
X        RETURN (ASCII (8));
X    ENDIF;
X    IF key_n = F11 THEN
X        RETURN (ASCII (27));
X    ENDIF;
X    IF key_n = PF1 THEN
X        RETURN (ASCII (27));
X    ENDIF;
X    IF key_n = RET_KEY THEN
X        RETURN (ASCII (13));
X    ENDIF;
X    IF key_n = TAB_KEY THEN
X        RETURN (ASCII (9));
X    ENDIF;
X    RETURN (ASCII (key_n));
XENDPROCEDURE;
X
X!
X!   Move up by screens
X!
XPROCEDURE vi$prev_screen
X    ON_ERROR
X    ENDON_ERROR;
X
X    MOVE_VERTICAL (-vi$cur_active_count *
X                        GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH"));
X
X    vi$position (vi$first_no_space, 0);
XENDPROCEDURE;
X
X!
X!   Move down by screens
X!
XPROCEDURE vi$next_screen
X    ON_ERROR
X    ENDON_ERROR;
X
X    MOVE_VERTICAL (vi$cur_active_count *
X                        (GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH") + 2));
X
X    vi$position (vi$first_no_space, 0);
XENDPROCEDURE;
X
X!
X! Scroll forward one screen
X!
XPROCEDURE vi$screen_forward
X
X    vi$scroll_screen (1);
X
XENDPROCEDURE;
X
X!
X! Scroll back one screen
X!
XPROCEDURE vi$screen_backward
X
X    vi$scroll_screen (-1);
X
XENDPROCEDURE;
X
X!
X!   Scroll the screen up or down depending on the sign of "how_many_screens"
X!   The magnitude actually has effect as well, but is never greater than 1
X!   in this use.
X!
XPROCEDURE vi$scroll_screen (how_many_screens)
X
X    LOCAL
X        scroll_window,          ! Window to be scrolled
X        this_window,            ! Current window
X        this_column,            ! Current column in scroll_window
X        this_row,               ! Current row in scroll_window
X        old_scroll_top,         ! Original value of scroll_top
X        old_scroll_bottom,      ! Original value of scroll_bottom
X        old_scroll_amount;      ! Original value of scroll_amount
X
X    ! Trap and ignore messages about move beyond buffer boundaries -
X    ! just move to top or bottom line of buffer
X
X    ON_ERROR
X    ENDON_ERROR;
X
X    this_window := CURRENT_WINDOW;
X
X    scroll_window := this_window;
X
X    IF vi$active_count <> 0 THEN
X        vi$how_much_scroll := vi$cur_active_count;
X    ENDIF;
X
X    this_row := GET_INFO (scroll_window, "CURRENT_ROW");
X
X    IF this_row = 0 THEN
X        this_row := GET_INFO (scroll_window, "VISIBLE_TOP");
X    ENDIF;
X
X    this_column := GET_INFO (scroll_window, "CURRENT_COLUMN");
X    MOVE_HORIZONTAL (-CURRENT_OFFSET);
X
X    old_scroll_top := GET_INFO (scroll_window, "SCROLL_TOP");
X    old_scroll_bottom := GET_INFO (scroll_window, "SCROLL_BOTTOM");
X    old_scroll_amount := GET_INFO (scroll_window, "SCROLL_AMOUNT");
X
X    SET (SCROLLING, scroll_window, ON,
X                    this_row - GET_INFO (scroll_window, "VISIBLE_TOP"),
X                    GET_INFO (scroll_window, "VISIBLE_BOTTOM") - this_row, 0);
X
X    MOVE_VERTICAL (how_many_screens * vi$how_much_scroll);
X    vi$update (scroll_window);
X
X    IF this_window <> CURRENT_WINDOW THEN
X        POSITION (this_window);
X    ENDIF;
X
X    SET (SCROLLING, scroll_window, ON, old_scroll_top, old_scroll_bottom,
V                                                            old_scroll_amount)
X;
XENDPROCEDURE;
X
X!
X!   Move forward logical words
X!
XPROCEDURE vi$_word_forward
X    vi$position (vi$word_move (1), 0);
XENDPROCEDURE;
X
X!
X!   Move backward logical words
X!
XPROCEDURE vi$_word_back
X    vi$position (vi$word_move(-1), 0);
XENDPROCEDURE;
X
X!
X!   Move by logical word taking into account the repeat count
X!
XPROCEDURE vi$word_move(dir)
X    LOCAL
X        old_pos,
X        pos;
X
X    old_pos := MARK (NONE);
X
X    IF vi$active_count <= 0 THEN
X        vi$active_count := 1;
X    ENDIF;
X
X    LOOP
X        pos := vi$move_logical_word (dir);
X        EXITIF pos = 0;
X        POSITION (pos);
X        vi$active_count := vi$active_count - 1;
X        EXITIF vi$active_count = 0;
X    ENDLOOP;
X
X    vi$yank_mode := VI$IN_LINE_MODE;
X    RETURN (vi$retpos (old_pos));
XENDPROCEDURE;
X
X!
X!   Move to end of logical word
X!
XPROCEDURE vi$_word_end
X    vi$position (vi$word_end, 0);
XENDPROCEDURE;
X
X!
X!   Move to end of physical word
X!
XPROCEDURE vi$_full_word_end
X    vi$position (vi$full_word_end, 0);
XENDPROCEDURE;
X
X!
X!   Move to the end of the current word.
X!
XPROCEDURE vi$word_end
X    LOCAL
X        old_pos,
X        pos;
X
X    old_pos := MARK (NONE);
X
X    IF vi$active_count <= 0 THEN
X        vi$active_count := 1;
X    ENDIF;
X
X    LOOP
X        pos := vi$move_logical_end;
X        EXITIF pos = 0;
X        POSITION (pos);
X        vi$active_count := vi$active_count - 1;
X        EXITIF vi$active_count = 0;
X    ENDLOOP;
X
X    vi$yank_mode := VI$IN_LINE_MODE;
X    RETURN (vi$retpos (old_pos));
XENDPROCEDURE;
X
X!
X!   Move to the end of a blank (eol is also considered blank) terminated word.
X!
XPROCEDURE vi$full_word_end
X
X    LOCAL
X        old_pos,
X        pos;
X
X    old_pos := MARK (NONE);
X
X    IF vi$active_count <= 0 THEN
X        vi$active_count := 1;
X    ENDIF;
X
X    LOOP
X        pos := vi$move_full_end;
X        EXITIF pos = 0;
X        POSITION (pos);
X        vi$active_count := vi$active_count - 1;
X        EXITIF vi$active_count = 0;
X    ENDLOOP;
X
X    vi$yank_mode := VI$IN_LINE_MODE;
X    RETURN (vi$retpos (old_pos));
XENDPROCEDURE;
X
X!
X!   Move forward by ONE white-space delimited word
X!
XPROCEDURE vi$_full_word_forward
X    vi$position (vi$full_word_move (1), 0);
XENDPROCEDURE;
X
X!
X!
X!   Move backward by ONE white-space delimited word
X!
XPROCEDURE vi$_full_word_back
X    vi$position (vi$full_word_move (-1), 0);
XENDPROCEDURE;
X
X!
X!   Move by physical word taking the repeat count into account
X!
XPROCEDURE vi$full_word_move (dir)
X
X    LOCAL
X        old_pos,
X        pos;
X
X    old_pos := MARK (NONE);
X
X    IF vi$active_count <= 0 THEN
X        vi$active_count := 1;
X    ENDIF;
X
X    LOOP
X        pos := vi$move_full_word (dir);
X        EXITIF pos = 0;
X        POSITION (pos);
X        vi$active_count := vi$active_count - 1;
X        EXITIF vi$active_count = 0;
X    ENDLOOP;
X
X    vi$yank_mode := VI$IN_LINE_MODE;
X    RETURN (vi$retpos (old_pos));
XENDPROCEDURE;
X
X!
X!   Move the cursor by BLANK separated words.  DIRECTION is either
X!   +1, or -1 to indicate the direction (forward, or backword respectfully)
X!   to move
X!
XPROCEDURE vi$move_full_word (direction)
X
X    LOCAL
X        pos;
X
X    pos := MARK (NONE);
X
$ GoSub Convert_Filemark);
n