1 /* ********************************************
   2    *                                          *
   3    * Copyright, (C) Honeywell Bull Inc., 1988 *
   4    *                                          *
   5    ******************************************** */
   6 
   7 /* HISTORY COMMENTS:
   8   1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
   9      install(88-10-12,MR12.2-1160):
  10      Created.
  11   2) change(88-07-22,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
  12      install(88-10-12,MR12.2-1160):
  13      Added support routines to capitalize, uppercase, lowercase
  14      and transpose words; added support routine to transpose characters.
  15   3) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
  16      install(88-10-12,MR12.2-1160):
  17      Documentation additions only. Added header comments to all routines.
  18   4) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
  19      install(88-10-12,MR12.2-1160):
  20      Fix references to include files; "wstdefs.h" was split into
  21      "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
  22      various constants defined to descriptive names.
  23   5) change(88-09-16,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
  24      install(88-10-12,MR12.2-1160):
  25      Modified line terminator to be always a linefeed for edit-mode;
  26      lfecho and crecho only applies to fullduplex modes.
  27   6) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
  28      install(89-04-24,MR12.3-1033):
  29      phx21233 - Modified to save only echoed input when items are killed to the
  30      kill buffer and when lines are saved to history buffer, kill buffer and
  31      audit buffers.
  32                                                    END HISTORY COMMENTS */
  33 
  34 #include <stdio.h>
  35 #include <dos.h>
  36 #include <ctype.h>
  37 #include "wstdefs.h"
  38 #include "wstglob.h"
  39 #include <wsmincap.h>
  40 
  41 /*^L
  42 **********************************************************************
  43 
  44   Routine:            DELETE_CHARS
  45 
  46   Function:
  47       This routine will delete a specified number of characters at
  48   the logical cursor position on the line and force the line to be
  49   updated on the screen.
  50 
  51   Parameters:
  52      (input/output)   line - pointer to the structure containing the
  53                           line and information about the line being
  54                           edited
  55      (input)          n_chars - specifies the number of characters to
  56                           delete at the current cursor position
  57      (input)          save_sw - if TRUE, specifies that the deleted
  58                           characters are to be put into the kill buffer
  59 
  60   Returns:            NONE
  61 
  62 **********************************************************************/
  63 
  64 delete_chars(line,n_chars,save_sw)
  65 EDIT_LINE *line;
  66 int n_chars;
  67 {
  68     int chars_to_eol;
  69     int chars_to_del;
  70     int i, j;
  71     char *echoed_input;
  72     int echoed_length;
  73 
  74     /* determine number of characters from logical cursor position  */
  75     /* to end of line                                               */
  76     chars_to_eol = line->length - line->index;
  77 
  78     /* make sure number of characters to delete does not exceed     */
  79     /* number of characters to the end of line                      */
  80     if (chars_to_eol < n_chars)
  81         chars_to_del = chars_to_eol;
  82     else
  83         chars_to_del = n_chars;
  84 
  85     /* save item to killbuffer if save switch is on */
  86     if (save_sw && chars_to_del > 0 && kb.echo) {
  87         /* phx21233 R.L. - save only echoed input to kill buffer */
  88         get_echoed_input(line,line->index,chars_to_del,&echoed_input,
  89             &echoed_length);
  90         save_to_killbuff(echoed_input,echoed_length);
  91     }
  92 
  93     /* copy rest of line over the deleted part of the line */
  94     for (i = line->index, j = line->index+chars_to_del;
  95         j < line->length; i++,j++) {
  96 
  97         /* copy over text in line buffer */
  98         line->line[i] = line->line[j];
  99 
 100         /* copy over count of display chars for text characters */
 101         line->size[i] = line->size[j];
 102     }
 103 
 104     /* update line length */
 105     line->length -= chars_to_del;
 106 
 107     /* force redraw from logical cursor position to end of line */
 108     redisplay(line,line->index,&(line->max_row),&(line->max_col));
 109 }
 110 
 111 
 112 
 113 /*^L
 114 **********************************************************************
 115 
 116   Routine:            KILL_TO_BOL
 117 
 118   Function:
 119       This routine deletes all text from the current cursor position
 120   to the end of the line and then updates the screen.
 121 
 122   Parameters:
 123      (input/output)   line - pointer to the structure containing the
 124                           line and information about the line being
 125                           edited
 126 
 127   Returns:            NONE
 128 
 129 **********************************************************************/
 130 
 131 kill_to_bol(line)
 132 EDIT_LINE *line;
 133 {
 134     int i;
 135     int n_chars;
 136 
 137     /* do only if logical cursor not already at beginning of line */
 138     if (line->index > 0) {
 139 
 140         /* number of characters to delete is logical cursor         */
 141         /* position                                                 */
 142         n_chars = line->index;
 143 
 144         /* check if beginning of line has scrolled off top of       */
 145         /* screen                                                   */
 146         if (line->scrolled_flag) {
 147 
 148             /* redisplay line from top of the screen */
 149             set_cursor(ss.top,ss.left);
 150 
 151             /* pad over to original display column */
 152             for (i = ss.left; i < line->orig_col; i++)
 153                 putch(' ');
 154 
 155             /* update line cursor position information */
 156             line->orig_row = ss.top;
 157             line->scrolled_flag = FALSE;
 158 
 159             /* move physical and logical cursor to beginning of     */
 160             /* line                                                 */
 161             line->cur_row = ss.top;
 162             line->cur_col = line->orig_col;
 163             set_cursor(line->cur_row,line->cur_col);
 164             line->index = 0;
 165 
 166             /* delete the characters and force a redraw */
 167             delete_chars(line,n_chars,KILLBUFF_SAVE);
 168         }
 169 
 170         /* coordinates for beginning of line on screen */
 171         else {
 172 
 173             /* move logical and physical cursor to beginning of     */
 174             /* line                                                 */
 175             line->index = 0;
 176             line->cur_row = line->orig_row;
 177             line->cur_col = line->orig_col;
 178             set_cursor(line->cur_row,line->cur_col);
 179 
 180             /* perform the delete and force a screen update */
 181             delete_chars(line,n_chars,KILLBUFF_SAVE);
 182         }
 183     }
 184 }
 185 
 186 
 187 /*^L
 188 **********************************************************************
 189 
 190   Routine:            KILL_TO_EOL
 191 
 192   Function:
 193       This routine deletes all text from the current cursor position
 194   to the end of the line, updating the screen.
 195 
 196   Parameters:
 197      (input/output)   line - pointer to the structure containing the
 198                           line and information about the line being
 199                           edited
 200 
 201   Returns:            NONE
 202 
 203 **********************************************************************/
 204 
 205 kill_to_eol(line)
 206 EDIT_LINE *line;
 207 {
 208 
 209     /* if not already at end of the line */
 210     if (line->index < line->length)
 211 
 212         /* delete the number of characters from the end of the      */
 213         /* line to the current logical cursor position              */
 214 
 215         delete_chars(line,line->length-line->index,KILLBUFF_SAVE);
 216 }
 217 
 218 
 219 
 220 /*^L
 221 **********************************************************************
 222 
 223   Routine:            ADD_TEXT
 224 
 225   Function:
 226       This routine adds text into the line being edited
 227 
 228   Parameters:
 229      (input/output)   line - pointer to the structure containing the
 230                           line and information about the line
 231      (input)          ch - specifies the character to add as text to
 232                           the line being edited
 233      (input)          n_times - specifies the number of times that
 234                           the text character is to be added
 235 
 236   Returns:            NONE
 237 
 238 **********************************************************************/
 239 
 240 add_text(line,ch,n_times)
 241 EDIT_LINE *line;
 242 int ch;
 243 int n_times;
 244 {
 245 
 246     /* determine if editing is in replace mode */
 247     if (!line->mode)
 248         replace_text(line,ch,n_times);
 249 
 250     /* if not, then is in insert mode */
 251     else
 252         insert_text(line,ch,n_times);
 253 }
 254 
 255 
 256 
 257 /*^L
 258 **********************************************************************
 259 
 260   Routine:            INSERT_TEXT
 261 
 262   Function:
 263       This routine displays and inserts one or more characters into
 264   the edit line buffer and updates the screen.
 265 
 266   Parameters:
 267      (input/output)   line - pointer to the structure containing the
 268                           line and information about the line
 269      (input)          ch - specifies the ASCII character to insert
 270                           into the line edited as text
 271      (input)          n_times - specifies the number of times that
 272                           the specified character is to be inserted
 273 
 274   Returns:            TRUE if successful
 275                       FALSE if unsuccessful
 276 
 277 **********************************************************************/
 278 
 279 insert_text(line,ch,n_times)
 280 EDIT_LINE *line;
 281 int ch;
 282 int n_times;
 283 {
 284     CURPOS tpos;
 285     int i, j;
 286     int actual_times;
 287     int chars_to_eol;
 288 
 289     /* determine how much space is available to insert text */
 290     chars_to_eol = MAX_LINE_SIZE - line->length;
 291 
 292     /* check for 0 or less characters to insert */
 293     if (n_times < 1)
 294         return(FALSE);
 295 
 296     /* check for no more space in edit line buffer for insert */
 297     if (chars_to_eol < 1) {
 298         beep();
 299         return(FALSE);
 300     }
 301 
 302     /* make sure number of characters to insert does not exceed     */
 303     /* space available for insert                                   */
 304     if (n_times > chars_to_eol) {
 305         actual_times = chars_to_eol;
 306         beep();
 307     }
 308     else
 309         actual_times = n_times;
 310 
 311     /* initialize cursor position information */
 312     init_temp_curpos(&tpos,line);
 313 
 314     /* make a gap in the line buffer for the insert */
 315     for (i = line->length+actual_times, j = line->length;
 316         j >= line->index; i--, j--) {
 317         line->line[i] = line->line[j];
 318         line->size[i] = line->size[j];
 319     }
 320 
 321     /* copy the text into the gap */
 322     for (i = line->index, j = 0; j < actual_times; i++, j++) {
 323         line->line[i] = ch;
 324         line->size[i] = display_char(&tpos,ch);
 325     }
 326 
 327     /* update the line length and logical cursor position */
 328     line->length += actual_times;
 329     line->index += actual_times;
 330 
 331     /* update cursor position information */
 332     line->cur_row = tpos.cur_row;
 333     line->cur_col = tpos.cur_col;
 334     line->orig_row -= tpos.scroll_flag;
 335     if (line->orig_row < ss.top)
 336         line->scrolled_flag = TRUE;
 337 
 338     /* update the changes to the screen */
 339     redisplay(line,line->index,&(line->max_row),&(line->max_col));
 340     return(TRUE);
 341 }
 342 
 343 
 344 
 345 /*^L
 346 **********************************************************************
 347 
 348   Routine:            REPLACE_TEXT
 349 
 350   Function:
 351       This routine replaces the character(s) at the cursor position
 352   in the edit line and updates the screen
 353 
 354   Parameters:
 355      (input/output)   line - specifies the structure containing the
 356                           line and information about the line being
 357                           edited
 358      (input)          key - specifies the ASCII character to replace
 359                           the current character(s) with
 360      (input)          n_times - specifies the number of characters to
 361                           replace with the specified ASCII character
 362 
 363   Returns:            FALSE if unsuccessful
 364                       TRUE if successful
 365 
 366 **********************************************************************/
 367 
 368 replace_text(line,key,n_times)
 369 EDIT_LINE *line;
 370 int key;
 371 int n_times;
 372 {
 373     CURPOS tpos;
 374     int i;
 375     int ch;
 376     int actual_times;
 377     int chars_to_eol;
 378 
 379     /* determine space available for adding text */
 380     chars_to_eol = MAX_LINE_SIZE - line->index;
 381 
 382     /* do nothing if replacing 0 or less characters */
 383     if (n_times < 1)
 384         return(FALSE);
 385 
 386     /* beep and return if no more space available to add text */
 387     if (chars_to_eol < 1) {
 388         beep();
 389         return(FALSE);
 390     }
 391 
 392     /* make sure number of characters to replace does not exceed    */
 393     /* space available; beep if it does                             */
 394     if (n_times > chars_to_eol) {
 395         actual_times = chars_to_eol;
 396         beep();
 397     }
 398     else
 399         actual_times = n_times;
 400 
 401     /* get character to replace */
 402     ch = key;
 403 
 404     /* initialize structure for keeping track of cursor position */
 405     init_temp_curpos(&tpos,line);
 406 
 407     /* perform the replace and display the character(s) being       */
 408     /* added                                                        */
 409     for (i = 0; i < actual_times; i++) {
 410         line->line[line->index] = ch;
 411         line->size[line->index] = display_char(&tpos,ch);
 412         line->index++;
 413     }
 414 
 415     /* update line length if line got extended */
 416     if (line->index > line->length) line->length = line->index;
 417 
 418     /* update cursor position information in line structure */
 419     line->cur_row = tpos.cur_row;
 420     line->cur_col = tpos.cur_col;
 421     line->orig_row -= tpos.scroll_flag;
 422     if (line->orig_row < ss.top)
 423         line->scrolled_flag = TRUE;
 424 
 425     /* update the changes to the screen */
 426     redisplay(line,line->index,&(line->max_row),&(line->max_col));
 427 
 428     return(TRUE);
 429 }
 430 
 431 
 432 
 433 /*^L
 434 **********************************************************************
 435 
 436   Routine:            FORWARD_DELETE_WORD
 437 
 438   Function:
 439       This routine deletes text to the right of the cursor up to the
 440   end of the next word in the line. The screen is then updated.
 441 
 442   Parameters:
 443      (input/output)   line - specifies the structure containing the
 444                           line and information about the line being
 445                           edited
 446      (input)          n_times - specifies the number of times to
 447                           repeat this delete function
 448 
 449   Returns:            NONE
 450 
 451 **********************************************************************/
 452 
 453 forward_delete_word(line,n_times)
 454 EDIT_LINE *line;
 455 int n_times;
 456 {
 457     int i;
 458 
 459     /* do nothing if already at end of the line */
 460     if (line->index >= line->length) return;
 461 
 462     /* get current logical cursor position */
 463     i = line->index;
 464 
 465     /* perform for the specified number of times or until end of    */
 466     /* line reached                                                 */
 467     while (n_times > 0 && i < line->length) {
 468 
 469         /* skip any word delimiters */
 470         while (i < line->length && is_word_delim(line->line[i]))
 471             i++;
 472 
 473         /* skip until word delimiter reached */
 474         while (i < line->length && !is_word_delim(line->line[i]))
 475             i++;
 476 
 477         /* tally number of times performed */
 478         n_times--;
 479 
 480     }
 481 
 482     /* check if new position is different */
 483     if (i == line->index)
 484         return;
 485 
 486     /* delete the difference in positions and update the screen */
 487     delete_chars(line,i-line->index,KILLBUFF_SAVE);
 488 }
 489 
 490 
 491 /*^L
 492 **********************************************************************
 493 
 494   Routine:            BACKWARD_DELETE_WORD
 495 
 496   Function:
 497       This routine deletes text to the left of the cursor up to the
 498   beginning of the previous word. The screen is updated.
 499 
 500   Parameters:
 501      (input/output)   line - specifies the structure containing the
 502                           line and information about the line being
 503                           edited
 504      (input)          n_times - specifies the number of times to
 505                           perform this function
 506 
 507   Returns:            NONE
 508 
 509 **********************************************************************/
 510 
 511 backward_delete_word(line,n_times)
 512 EDIT_LINE *line;
 513 int n_times;
 514 {
 515     int i;
 516     int n_chars;
 517 
 518     /* do only if not at beginning of line */
 519     if (line->index < 1) return;
 520 
 521     /* begin at one position before the cursor */
 522     i = line->index - 1;
 523 
 524     /* do the specified number of times or until beginning of line  */
 525     /* reached                                                      */
 526     while (n_times > 0 && i >= 0) {
 527 
 528         /* skip word delimiters to the left */
 529         while (i >= 0 && is_word_delim(line->line[i]))
 530             i--;
 531 
 532         /* skip word to the left */
 533         while (i >= 0 && !is_word_delim(line->line[i]))
 534             i--;
 535 
 536         /* tally the times performed */
 537         n_times--;
 538     }
 539 
 540     /* restore cursor position one position to the right */
 541     i++;
 542 
 543     /* determine the number of characters to the left to delete */
 544     n_chars = line->index - i;
 545 
 546     /* move the physical and logical cursor there, updating the     */
 547     /* screen                                                       */
 548     cursor_left(line,n_chars);
 549 
 550     /* perform the delete and update the screen */
 551     delete_chars(line,n_chars,KILLBUFF_SAVE);
 552 }
 553 
 554 
 555 
 556 /*^L
 557 **********************************************************************
 558 
 559   Routine:            ADD_CHAR
 560 
 561   Function:
 562       This routine adds a character into the line being edited and
 563   updates the screen without moving the cursor forward. This routine
 564   is used for handling literal escaping of characters.
 565 
 566   Parameters:
 567      (input/output)   line - specifies the structure containing the
 568                           line and information about the line being
 569                           edited
 570      (input)          ch - specifies the ASCII character to add into
 571                           the line
 572 
 573   Returns:            TRUE if successful
 574                       FALSE if unsuccessful
 575 
 576 **********************************************************************/
 577 
 578 add_char(line,ch)
 579 EDIT_LINE *line;
 580 int ch;
 581 {
 582     int code;
 583 
 584     /* determine if in edit replace mode */
 585     if (!line->mode)
 586         code = replace_char(line,ch);
 587 
 588     /* no, in edit insert mode */
 589     else
 590         code = insert_char(line,ch);
 591 
 592     /* return the status to caller */
 593     return(code);
 594 }
 595 
 596 
 597 
 598 /*^L
 599 **********************************************************************
 600 
 601   Routine:            REPLACE_CHAR
 602 
 603   Function:
 604       This routine will replace the current character of the line
 605   being edited. The cursor position is NOT changed.
 606 
 607   Parameters:
 608      (input/output)   line - specifies the structure containing the
 609                           line and information about the line being
 610                           edited
 611      (input)          key - specifies the ASCII character to replace
 612                           the current character with
 613 
 614   Returns:            FALSE if unsuccessful
 615                       TRUE if successful
 616 
 617 **********************************************************************/
 618 
 619 replace_char(line,key)
 620 EDIT_LINE *line;
 621 int key;
 622 {
 623     CURPOS tpos;
 624     int ch;
 625     int chars_to_eol;
 626 
 627     /* determine space available for replacing line buffer text */
 628     chars_to_eol = MAX_LINE_SIZE - line->index;
 629 
 630     /* if no more space left, beep and return */
 631     if (chars_to_eol < 1) {
 632         beep();
 633         return(FALSE);
 634     }
 635 
 636     /* get character to insert */
 637     ch = key;
 638 
 639     /* initialize cursor positioning information */
 640     init_temp_curpos(&tpos,line);
 641 
 642     /* do the replace and display the new character */
 643     line->line[line->index] = ch;
 644     line->size[line->index] = display_char(&tpos,ch);
 645 
 646     /* update the line length if line is extended */
 647     if (line->index+1 > line->length) line->length = line->index+1;
 648 
 649     /* update cursor position */
 650     line->cur_row = tpos.cur_row;
 651     line->cur_col = tpos.cur_col;
 652     line->orig_row -= tpos.scroll_flag;
 653     if (line->orig_row < ss.top)
 654         line->scrolled_flag = TRUE;
 655 
 656     /* update the line to the screen */
 657     redisplay(line,line->index+1,&(line->max_row),&(line->max_col));
 658 
 659     return(TRUE);
 660 }
 661 
 662 
 663 
 664 /*^L
 665 **********************************************************************
 666 
 667   Routine:            INSERT_CHAR
 668 
 669   Function:
 670       This routine inserts a character into the line being edited.
 671   The cursor position is not moved forward.
 672 
 673   Parameters:
 674      (input/output)   line - specifies the structure containing the
 675                           line and information about the line being
 676                           edited
 677      (input)          ch - specifies the ASCII character to insert
 678                           into the line
 679 
 680   Returns:            TRUE if successful
 681                       FALSE if unsuccessful
 682 
 683 **********************************************************************/
 684 
 685 insert_char(line,ch)
 686 EDIT_LINE *line;
 687 int ch;
 688 {
 689     CURPOS tpos;
 690     int i, j;
 691 
 692     int chars_to_eol;
 693 
 694     /* determine space available in line for inserting */
 695     chars_to_eol = MAX_LINE_SIZE - line->length;
 696 
 697     /* beep and return if no space for insert */
 698     if (chars_to_eol < 1) {
 699         beep();
 700         return(FALSE);
 701     }
 702 
 703     /* initialize cursor position information */
 704     init_temp_curpos(&tpos,line);
 705 
 706     /* create gap in line buffer for the character to insert */
 707     for (i = line->length+1, j = line->length;
 708         j >= line->index; i--, j--) {
 709         line->line[i] = line->line[j];
 710         line->size[i] = line->size[j];
 711     }
 712 
 713     /* copy in the character */
 714     line->line[line->index] = ch;
 715     line->size[line->index] = display_char(&tpos,ch);
 716 
 717     /* update the line length */
 718     line->length++;
 719 
 720     /* update the cursor position information */
 721     line->cur_row = tpos.cur_row;
 722     line->cur_col = tpos.cur_col;
 723     line->orig_row -= tpos.scroll_flag;
 724     if (line->orig_row < ss.top)
 725         line->scrolled_flag = TRUE;
 726 
 727     /* update the line to the screen */
 728     redisplay(line,line->index+1,&(line->max_row),&(line->max_col));
 729     return(TRUE);
 730 }
 731 
 732 
 733 
 734 /*^L
 735 **********************************************************************
 736 
 737   Routine:            INSERT_DISPLAY_CHAR
 738 
 739   Function:
 740       This routine inserts characters on the screen only. It allows
 741   partial input of a backslash sequence to be displayed before it is
 742   entered into the line being edited.
 743 
 744   Parameters:
 745      (input/output)   line - specifies the structure containing the
 746                           line and information about the line being
 747                           edited
 748      (input)          ch - specifies the character to insert at the
 749                           cursor position in the screen
 750 
 751   Returns:            NONE
 752 
 753 **********************************************************************/
 754 
 755 insert_display_char(line,ch)
 756 EDIT_LINE *line;
 757 int ch;
 758 {
 759     CURPOS tpos;
 760 
 761     /* initialize cursor position information */
 762     init_temp_curpos(&tpos,line);
 763 
 764     /* store the character in the buffer for handling literal       */
 765     /* escaping                                                     */
 766     line->literal_buff[line->literal_dex++] = ch;
 767 
 768     /* display the character */
 769     display_char(&tpos,ch);
 770 
 771     /* update the line structure with cursor position information */
 772     line->cur_row = tpos.cur_row;
 773     line->cur_col = tpos.cur_col;
 774     line->orig_row -= tpos.scroll_flag;
 775     if (line->orig_row < ss.top)
 776         line->scrolled_flag = TRUE;
 777 
 778     /* update the line to the screen */
 779     redisplay(line,line->index+1,&(line->max_row),&(line->max_col));
 780 }
 781 
 782 
 783 
 784 /*^L
 785 **********************************************************************
 786 
 787   Routine:            CHANGE_CASE_WORD
 788 
 789   Function:
 790       This routine converts all alphabetic characters in the current
 791   word of the line being edited (in edit mode) to a specified case. If
 792   the cursor is not on a word, the word to the left of the cursor is
 793   converted to the specified case. The screen is then updated and the
 794   cursor is positioned at the end of the word that has been converted.
 795   The cases specified may be upper case, lower case or capitalized.
 796 
 797   Parameters:
 798      (input/output)   line - pointer to the structure containing the
 799                           line and information about the line being
 800                           edited (in edit mode)
 801      (input)          case_flag - specifies the case to convert the
 802                           word(s) to:
 803                           KB_UPPER_CASE for upper case,
 804                           KB_LOWER_CASE for lower case,
 805                           KB_CAPITALIZED for first letter of word
 806                               in upper case, and rest in lower case
 807 
 808   Returns:            NONE
 809 
 810 **********************************************************************/
 811 
 812 change_case_word(line,case_flag)
 813 EDIT_LINE *line;
 814 int case_flag;
 815 {
 816     int i;
 817     int orig_index;
 818 
 819     /* get copy of keyboard buffer index */
 820     i = line->index;
 821     if (i >= line->length) i--;
 822     orig_index = i;
 823 
 824     /* cursor on word delimiter or space? */
 825     if (is_word_delim(line->line[i])) {
 826 
 827         /* go left to previous word */
 828         while (i >= 0 && is_word_delim(line->line[i])) i--;
 829 
 830         /* check for no word on left */
 831         if (i < 0) {
 832 
 833             /* no previous word, move right to use next word */
 834             i = orig_index;
 835             while (i < line->length && is_word_delim(line->line[i])) i++;
 836 
 837             /* past end of line, is a blank line, do nothing */
 838             if (i >= line->length)
 839                 return;
 840         }
 841     }
 842 
 843     /* make sure is at beginning of word */
 844     while (i >= 0 && !is_word_delim(line->line[i])) i--;
 845     i++;
 846 
 847     /* move physical cursor to beginning of the word for case change */
 848     if (i < line->index)
 849         cursor_left(line,line->index-i);
 850     else if (i > line->index)
 851         cursor_right(line,i-line->index);
 852 
 853     /* lower case first character if LOWER CASE specified */
 854     if (case_flag == KB_LOWER_CASE)
 855         line->line[i] = tolower(line->line[i]);
 856 
 857     /* upper case first character for UPPER CASE or CAPITALIZE */
 858     else
 859         line->line[i] = toupper(line->line[i]);
 860     i++;
 861 
 862     /* handle rest of word */
 863     while (i < line->length && !is_word_delim(line->line[i])) {
 864 
 865         /* upper case rest of word if UPPER CASE */
 866         if (case_flag == KB_UPPER_CASE)
 867             line->line[i] = toupper(line->line[i]);
 868 
 869         /* lower case rest of word if LOWER CASE or CAPITALIZE */
 870         else
 871             line->line[i] = tolower(line->line[i]);
 872 
 873         i++;
 874 
 875     }
 876 
 877     /* update the screen */
 878     redisplay(line,line->index,&(line->max_row),&(line->max_col));
 879 
 880     /* position cursor to end of last word upper cased */
 881     cursor_right(line,i-line->index);
 882 }
 883 
 884 
 885 
 886 /*^L
 887 **********************************************************************
 888 
 889   Routine:            TRANSPOSE_CHARS
 890 
 891   Function:
 892       This routine exchanges the positions of the two characters to
 893   the left of the cursor. If there isn't two characters to the left
 894   of the cursor, the routine will sound a beep and do nothing. The
 895   screen is updated and the cursor position is unchanged.
 896 
 897   Parameters:
 898      (input/output)   line - specifies the structure containing the
 899                           line and information about the line being
 900                           edited (in edit mode)
 901 
 902   Returns:            NONE
 903 
 904 **********************************************************************/
 905 
 906 transpose_chars(line)
 907 EDIT_LINE *line;
 908 {
 909     int i;
 910     int tmp_ch;
 911 
 912     /* check if two characters exist to left of cursor */
 913     if (line->length < 2 || line->index < 2) {
 914         beep();
 915         return;
 916     }
 917 
 918     /* position temporary index to two positions before cursor */
 919     i = line->index - 2;
 920 
 921     /* move cursor two characters back */
 922     cursor_left(line,2);
 923 
 924     /* swap the two characters */
 925     tmp_ch = line->line[i];
 926     line->line[i] = line->line[i+1];
 927     line->line[i+1] = tmp_ch;
 928 
 929     /* update the screen */
 930     redisplay(line,line->index,&(line->max_row),&(line->max_col));
 931 
 932     /* restore cursor position */
 933     cursor_right(line,2);
 934 }
 935 
 936 
 937 
 938 /*^L
 939 **********************************************************************
 940 
 941   Routine:            TRANSPOSE_WORDS
 942 
 943   Function:
 944       This routine interchanges the positions of the current word
 945   (under the cursor) and the word to its left. If the cursor is not
 946   on a word, the two words to the left of the cursor are
 947   interchanged. The screen is updated and the cursor is positioned at
 948   the end of the interchanged words. If there are no words to
 949   interchange (e.g. at beginning of the line), the routine will beep
 950   and do nothing.
 951 
 952   Parameters:
 953      (input/output)   line - specifies the structure containing the
 954                           line and information about the line being
 955                           edited (in edit mode)
 956 
 957   Returns:            NONE
 958 
 959 **********************************************************************/
 960 
 961 transpose_words(line)
 962 EDIT_LINE *line;
 963 {
 964     int i;
 965     int word1_index, word1_len;
 966     int word2_index, word2_len;
 967     int delim_len;
 968     char *tmp_buff, *malloc();
 969     int tmp_index;
 970     int final_index;
 971 
 972     /* get cursor position and make sure it points to valid data */
 973     /* if at end of line */
 974     i = line->index;
 975     if (i >= line->length) i--;
 976 
 977     /* check if in middle of a word */
 978     if (!is_word_delim(line->line[i]))
 979         /* go to end of word */
 980         while (i < line->length && !is_word_delim(line->line[i]))
 981             i++;
 982 
 983     /* go left to right, skip trailing blanks */
 984     i--;
 985     while (i >= 0 && is_word_delim(line->line[i]))
 986        i--;
 987 
 988     /* save the index to the end of this second word */
 989     final_index = i+1;
 990 
 991     /* determine length and starting position of this second word */
 992     word2_len = 0;
 993     while (i >= 0 && !is_word_delim(line->line[i])) {
 994         i--;
 995         word2_len++;
 996     }
 997     word2_index = i+1;
 998 
 999     /* no word to transpose with if past beginning of line */
1000     if (i < 0) {
1001         beep();
1002         return;
1003     }
1004 
1005     /* determine number of delimiter characters to left of second word */
1006     delim_len = 0;
1007     while (i >= 0 && is_word_delim(line->line[i])) {
1008        delim_len++;
1009        i--;
1010     }
1011 
1012     /* no words to transpose with if past beginning of line */
1013     if (i < 0) {
1014         beep();
1015         return;
1016     }
1017 
1018     /* determine length and position of first word */
1019     word1_len = 0;
1020     while (i >= 0 && !is_word_delim(line->line[i])) {
1021         i--;
1022         word1_len++;
1023     }
1024     word1_index = i+1;
1025 
1026     /* allocate buffer big enough to hold both words and delimiter */
1027     tmp_buff = malloc(word1_len+delim_len+word2_len+1);
1028     if (tmp_buff == NULL) return;
1029 
1030     /* move cursor to beginning of first word */
1031     i = line->index - word1_index;
1032     cursor_left(line,i);
1033 
1034     /* copy the two words and delimiter in between with the word positions
1035        interchanged to temporary buffer
1036     */
1037     tmp_index = 0;
1038     for (i = 0; i < word2_len; i++)
1039         tmp_buff[tmp_index++] = line->line[word2_index+i];
1040     for (i = 0; i < delim_len; i++)
1041         tmp_buff[tmp_index++] = line->line[word1_index+word1_len+i];
1042     for (i = 0; i < word1_len; i++)
1043         tmp_buff[tmp_index++] = line->line[word1_index+i];
1044 
1045     /* copy back from temporary buffer to line buffer */
1046     for (i = 0; i < tmp_index; i++)
1047         line->line[word1_index+i] = tmp_buff[i];
1048 
1049     /* deallocate temporary buffer */
1050     free(tmp_buff);
1051 
1052     /* update the screen */
1053     redisplay(line,line->index,&(line->max_row),&(line->max_col));
1054 
1055     /* position cursor at end of words */
1056     cursor_right(line,final_index-line->index);
1057 }
1058 
1059 
1060 
1061 /*^L
1062 **********************************************************************
1063 
1064   Routine:            KB_EDIT_LF_RETURN
1065 
1066   Function:
1067       This function passes processes a line in edit-mode when a
1068   linefeed or carriage return is entered, before the line is to
1069   be sent to the host. Processing includes moving the cursor to
1070   the end of the line, saving the line in the history and kill
1071   buffer, file or printer audit the lines if auditing is enabled,
1072   and updating any cursor position variables. The line is then
1073   sent to the host.
1074 
1075   Parameters:
1076      (input/output)   line - pointer to the structure containing the
1077                           line and information about the line to be
1078                           saved and sent to the host
1079      (input)          key - specifies the line terminator key that
1080                           was entered
1081 
1082   Returns:            NONE
1083 
1084 **********************************************************************/
1085 
1086 kb_edit_lf_return(line,key)
1087 EDIT_LINE *line;
1088 int key;
1089 {
1090     char *dptr;
1091     char *echoed_input;
1092     int  echoed_length;
1093 
1094     /* position cursor to end of line (to prevent incoming messages
1095        from overwriting the input
1096     */
1097     cursor_eol(line);
1098 
1099     /* Handle moving the cursor to the next line. */
1100     /* Don't move to beginning of next line if CR hit and mowse is */
1101     /* not active; in glass tty mode, when using edit mode, */
1102     /* the terminal modes should be ^echoplex,lfecho. A linefeed */
1103     /* will be echoed from Multics anyways. */
1104 
1105     if (!mowse_active && key == CR)
1106         line->cur_col = ss.left;
1107 
1108     else if (line->cur_row >= ss.bottom) {
1109         wst_scroll();
1110         line->cur_row = ss.bottom;
1111         line->cur_col = ss.left;
1112     }
1113     else {
1114         line->cur_row++;
1115         line->cur_col = ss.left;
1116     }
1117 
1118     cursor_move(line->cur_row,line->cur_col);
1119 
1120     /* re-initialize screen information */
1121     screen.curlin = line->cur_row;
1122     screen.curcol = line->cur_col;
1123     screen.EOP_ct = 0;                 /* input resets page line counter */
1124 
1125     /* phx21233 R.L. - saved only echoed input to history and kill buffers */
1126     get_echoed_input(line,0,line->length,&echoed_input,&echoed_length);
1127 
1128     /* non-empty lines saved to history buffer */
1129     if (echoed_length > 0) {
1130         save_to_histbuff(echoed_input,echoed_length);
1131         save_to_killbuff(echoed_input,echoed_length);
1132     }
1133 
1134     if (mowse_active)
1135 
1136         /* terminate line with line delimiter; a linefeed character is */
1137         /* always used so the line gets interpreted by the host; the */
1138         /* modes lfecho and crecho do not affect edit-mode since */
1139         /* characters are echoed locally, and not by the host. The lfecho */
1140         /* and crecho modes are meaningful in full duplex */
1141 
1142         line->line[line->length++] = LF;
1143 
1144     /* otherwise send whatever line terminator was entered */
1145     else
1146         line->line[line->length++] = key;
1147 
1148     /* terminate string */
1149     line->line[line->length] = NUL_TERMINATOR;
1150 
1151     /* phx21233 R.L. - LF terminate echoed input and audit only echoed input */
1152     echoed_input[echoed_length++] = LF;
1153 
1154     /* audit input if necessary */
1155     if (wst_f_audit)
1156         f_audit_msg(echoed_input,echoed_length);
1157 
1158     if (wst_p_audit)
1159         p_audit_msg(echoed_input,echoed_length,NULL);
1160 
1161     /* just send the message to host if not in glass tty mode */
1162     if (mowse_active)
1163         puttdata (FG_TERMINAL_DATA, line->line, line->length);
1164 
1165     /* kludge to minimize line overrun for long input lines when */
1166     /* Multics is echoing; this problems shows up when the user */
1167     /* is in non-packet (glass tty) mode and long input lines are */
1168     /* echoed. The echoed input from Multics sometimes causes the PC */
1169     /* to stall, resulting in a Multics interpreting a QUIT signal. */
1170     /* This fix slows long input from being sent too quickly so that */
1171     /* echoed characters are received less quickly. */
1172     else {
1173         /* send characters out in 4 character chunks, delaying in between */
1174         dptr = line->line;
1175         while (line->length > 4) {
1176 
1177             puttdata(FG_TERMINAL_DATA, dptr, 4);
1178             dptr += 4;
1179             line->length -= 4;
1180             delay();
1181         }
1182 
1183         puttdata(FG_TERMINAL_DATA, dptr, line->length);
1184     }
1185 
1186     /* reset edit mode line length and buffer index to indicate 0 length */
1187     line->length = 0;
1188     line->index = 0;
1189 }