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-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel), 12 install(88-10-12,MR12.2-1160): 13 Documentation additions only. Added header comments to all routines. 14 3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel), 15 install(88-10-12,MR12.2-1160): 16 Fix references to include files; "wstdefs.h" was split into 17 "wstdefs.h" and "wsttype.h" to avoid declaration clash; also, 18 various constants defined to descriptive names. 19 END HISTORY COMMENTS */ 20 21 #include <dos.h> 22 #include <ctype.h> 23 #include "wstdefs.h" 24 #include "wstglob.h" 25 26 /*^L 27 ********************************************************************** 28 29 Routine: CURSOR_BOL 30 31 Function: 32 This routine moves the cursor to the beginning of the line. 33 Since the entire input line may span several rows on the screen, 34 this routine may be required to handle the case where the beginning 35 of the line has scrolled off the top of the screen. 36 37 Parameters: 38 (input/output) line - pointer to the structure containing the 39 line and information about the line being 40 edited in edit mode 41 42 Returns: NONE 43 44 **********************************************************************/ 45 46 cursor_bol(line) 47 EDIT_LINE *line; 48 { 49 int i; 50 51 /* check that line is not empty */ 52 if (line->index > 0) { 53 54 /* check if beginning of line displayed has scrolled */ 55 if (line->scrolled_flag) { 56 57 /* need to redraw from beginning of display screen */ 58 set_cursor(ss.top,ss.left); 59 60 /* blank pad to original display column */ 61 for (i = ss.left; i < line->orig_col; i++) 62 putch(' '); 63 64 /* start coordinates now beginning of screen */ 65 line->orig_row = ss.top; 66 67 /* no longer scrolled, redisplaying the beginning */ 68 line->scrolled_flag = FALSE; 69 70 /* set current cursor coordinates */ 71 line->cur_row = ss.top; 72 line->cur_col = line->orig_col; 73 74 /* update the physical cursor location */ 75 set_cursor(line->cur_row,line->cur_col); 76 line->index = 0; 77 78 /* redisplay from beginning of line */ 79 redisplay(line,line->index,&(line->max_row),&(line->max_col)); 80 } 81 82 /* no, beginning of line still on display */ 83 else { 84 85 /* set keyboard buffer index to beginning of line */ 86 line->index = 0; 87 88 /* move the physical cursor to the beginning of line on 89 the display 90 */ 91 line->cur_row = line->orig_row; 92 line->cur_col = line->orig_col; 93 set_cursor(line->cur_row,line->cur_col); 94 } 95 } 96 } 97 98 99 /*^L 100 ********************************************************************** 101 102 Routine: CURSOR_EOL 103 104 Function: 105 This routine moves the cursor to the end of the line in edit 106 mode. Since it is possible for the end of the line to be shifted 107 past the end of the screen due to inserting text, this routine has 108 to determine and handle scrolling in this case. 109 110 Parameters: 111 (input/output) line - pointer to the structure containing the 112 line and information about the line being 113 edited in edit mode 114 115 Returns: NONE 116 117 Note 1 - Some care must be taken to maintain consistency in the 118 appearance of the screen when using this and other cursor 119 movement routines. Going to the end of the line using a series 120 of commands to move the cursor to the right or going directly 121 to the end of the line using this routine should yield the same 122 display of the line being edited. 123 **********************************************************************/ 124 125 cursor_eol(line) 126 EDIT_LINE *line; 127 { 128 int cnt; 129 int row; 130 int col; 131 int screen_width; 132 int screen_height; 133 int chars_to_pad; 134 int i; 135 char *ptr, *display_char_str(); 136 int offset; 137 int lines_scrolled; 138 139 /* determine screen width */ 140 screen_width = ss.right - ss.left + 1; 141 screen_height = ss.bottom - ss.top + 1; 142 143 /* get absolute row coordinate */ 144 row = line->cur_row - ss.top; 145 146 /* get absolute column coordinate */ 147 col = line->cur_col - ss.left; 148 cnt = 0; 149 150 /* determine number of character positions needed to 151 display from current cursor position (index) to end of line (in cnt); 152 keep track of where the cursor will end up when all text to end 153 of line is displayed (in row, col). 154 */ 155 for (i = line->index; i < line->length; i++) { 156 cnt += line->size[i]; 157 row += (col + line->size[i]) / screen_width; 158 col = (col + line->size[i]) % screen_width; 159 } 160 161 /* if cursor would still be within screen boundary */ 162 if (row < screen_height) { 163 164 /* just move the cursor to the calculated position */ 165 line->cur_row = row + ss.top; 166 line->cur_col = col + ss.left; 167 set_cursor(line->cur_row,line->cur_col); 168 169 /* set current position (index) to end of line position */ 170 line->index = line->length; 171 return; 172 } 173 174 else { 175 lines_scrolled = row - screen_height + 1; 176 177 /* We want to cursor to end up at the column position 178 calculated above (in col) but displayed at the bottom row of the 179 screen; determine number of character positions needed 180 to fill from the beginning of the screen 181 */ 182 chars_to_pad = (screen_height - 1) * screen_width; 183 chars_to_pad += col; 184 185 /* "cnt" contains the number of display locations 186 required to display from the end of the line to 187 the "i"th character 188 */ 189 cnt = 0; 190 for (i = line->length-1; i >= 0; i--) { 191 cnt += line->size[i]; 192 if (cnt >= chars_to_pad) 193 break; 194 } 195 196 /* if the character locations needed to display the 197 entire line is less than that needed to pad to the 198 beginning of the line, then line starts within the 199 screen display but part of the line extends beyond 200 what is displayed on the screen 201 */ 202 if (i < 0 || cnt < chars_to_pad) { 203 204 /* scroll enough lines for the last line to be displayed */ 205 for (i = 0; i < lines_scrolled; i++) 206 wst_scroll(); 207 208 /* calculate where the cursor should end up */ 209 i = 0; 210 offset = ((screen_height - 1) * screen_width) + col; 211 offset -= cnt; 212 row = offset / screen_width; 213 col = offset % screen_width; 214 215 row += ss.top; 216 col += ss.left; 217 218 /* move the physical cursor to the calculated location */ 219 set_cursor(row,col); 220 221 } 222 223 /* enough character to pad from the beginning of display to 224 end of line starting from the "i"th position 225 */ 226 else { 227 228 /* move physical cursor to start of display screen */ 229 row = ss.top; 230 col = ss.left; 231 set_cursor(row,col); 232 233 /* if total display locations starting from character the 234 "i"th position is more than that needed to pad to the 235 beginning of the screen, then only part of the "i"th 236 character displayed needs to be displayed at the beginning 237 of the display screen 238 */ 239 if (cnt > chars_to_pad) { 240 241 /* get a pointer to the display string of that character */ 242 ptr = display_char_str(line->line[i]); 243 244 /* index into the portion of the display string 245 needed to pad to fill the screen 246 */ 247 ptr += strlen(ptr) - (cnt - chars_to_pad); 248 249 /* display that portion of the character string */ 250 while (*ptr) { 251 putch(*ptr); 252 ptr++; 253 col++; 254 } 255 256 /* start redisplay from next character */ 257 i++; 258 } 259 } 260 261 262 /* move keyboard buffer index to end of line */ 263 line->index = line->length; 264 265 /* initialize coordinates values to where to begin redisplay */ 266 line->cur_row = row; 267 line->cur_col = col; 268 269 /* do the redisplay */ 270 redisplay(line,i,&(line->max_row),&(line->max_col)); 271 272 /* update the start and current cursor coordinates */ 273 line->cur_row = line->max_row; 274 line->cur_col = line->max_col; 275 276 /* check if screen has scrolled */ 277 line->orig_row -= lines_scrolled; 278 if (line->orig_row < ss.top) 279 line->scrolled_flag = TRUE; 280 281 /* update location of physical cursor */ 282 set_cursor(line->cur_row,line->cur_col); 283 } 284 } 285 286 287 /*^L 288 ********************************************************************** 289 290 Routine: CURSOR_LEFT 291 292 Function: 293 This routine moves the physical and logical cursor to the 294 previous character in the edit mode line, if that character exists 295 (i.e. when not at the beginning of the line). Since it is possible 296 for part of the line to have scrolled off the top of the screen, 297 this routine has to detect and handle scrolling the line back down. 298 299 Parameters: 300 (input/output) line - pointer to the structure containing the 301 line and information about the line being 302 edited in edit mode 303 (input) n_times - specifies the number of character 304 locations to move the cursor backwards (to 305 the left) 306 307 Returns: The actual number of characters that the cursor 308 was moved back. 309 310 Note 1 - If the number of characters from the current cursor 311 location to the beginning of the line is less than value 312 specified by 'n_times', the cursor is moved to the beginning of 313 the line. This condition may be checked by the caller by 314 checking if the value passed for 'n_times' is less than the 315 return value. 316 **********************************************************************/ 317 318 cursor_left(line,n_times) 319 EDIT_LINE *line; 320 int n_times; 321 { 322 int i; 323 int size; 324 int row_diff; 325 int col_diff; 326 int chars_to_bos; 327 int screen_width; 328 int chars_to_pad; 329 int new_index; 330 int pad; 331 int new_col; 332 char *ptr, *display_char_str(); 333 int actual_times; 334 335 /* don't do anything if at beginning of line or moving left 0 times */ 336 if (line->index < 1 || n_times < 1) 337 return(0); 338 339 /* limit the number of times to move to the number number of */ 340 /* characters from current position to beginning of line */ 341 if (n_times > line->index) 342 actual_times = line->index; 343 else 344 actual_times = n_times; 345 346 /* determine the number of display characters to move left from the 347 current location and position the line index there 348 */ 349 size = 0; 350 for (i = 0; i < actual_times; i++) { 351 line->index--; 352 size += line->size[line->index]; 353 } 354 355 /* determine the number of display characters from the current location 356 to the beginning of the display window 357 */ 358 row_diff = line->cur_row - ss.top; 359 col_diff = line->cur_col - ss.left; 360 screen_width = ss.right - ss.left + 1; 361 chars_to_bos = (row_diff * screen_width) + col_diff; 362 363 /* handle case for moving left beyond display window origin: 364 redisplay() will automatically update to the right of 365 the cursor if the current coordinates in line->cur_row 366 and line->cur_col are set and the index into the actual 367 line buffer is given. The cursor will be on the first 368 row of the display window. We need to calculate the column 369 position based on the number of times moved left. Also, 370 we need to fill the beginning of the first line up to the 371 calculated column position since redisplay() won't do it. 372 */ 373 374 if (chars_to_bos < size) { 375 376 /* need to scroll back, so redraw always start at window origin */ 377 378 line->cur_row = ss.top; 379 line->cur_col = ss.left; 380 set_cursor(line->cur_row,line->cur_col); 381 382 /* determine which column on the starting row that cursor 383 should be positioned at 384 */ 385 386 chars_to_pad = screen_width - 387 ((size - chars_to_bos) % screen_width); 388 389 /* handle wrap around case */ 390 if (chars_to_pad == screen_width) chars_to_pad = 0; 391 392 /* calculate absolute screen coordinates */ 393 new_col = ss.left + chars_to_pad; 394 395 /* check if updating to the left of cursor is necessary */ 396 if (chars_to_pad > 0) { 397 398 new_index = line->index - 1; 399 400 pad = 0; 401 for (i = new_index; i >= 0; i--) { 402 pad += line->size[i]; 403 if (pad >= chars_to_pad) 404 break; 405 } 406 407 /* if not enough characters to pad to beginning of line, then 408 line must have started somewhere in the middle of the display 409 window, just blank fill the beginning of the line and then 410 redisplay 411 */ 412 if (i < 0) { 413 414 for (i = 0; i < chars_to_pad - pad; i++) { 415 line->cur_col++; 416 putch(' '); 417 } 418 redisplay(line,0,&(line->max_row),&(line->max_col)); 419 420 /* set cursor to the column position determined */ 421 line->cur_col = new_col; 422 set_cursor(line->cur_row,line->cur_col); 423 424 return(actual_times); 425 } 426 427 /* a single character may need 2 or more characters to display 428 the character, e.g. 10 blanks for a tab or \ 0 0 0 429 for a NUL. Check if line starts in the middle of 430 one of these and if so, print out the portion needed to 431 pad the beginning of the line 432 */ 433 if (pad > chars_to_pad) { 434 435 /* get the string representing the current character */ 436 ptr = display_char_str(line->line[i]); 437 438 /* index into the string the portion needed to pad the line */ 439 ptr += (strlen(ptr) - (pad - chars_to_pad)); 440 441 /* display this portion of the string */ 442 while (*ptr) { 443 putch(*ptr); 444 ptr++; 445 line->cur_col++; 446 } 447 /* start redisplaying at the next character in buffer */ 448 i++; 449 } 450 } 451 452 /* no padding at beginning of line necessary, redisplay at current 453 index position */ 454 else 455 i = line->index; 456 457 redisplay(line,i,&(line->max_row),&(line->max_col)); 458 459 /* position the cursor to the calculated location */ 460 line->cur_row = ss.top; 461 line->cur_col = new_col; 462 set_cursor(line->cur_row,line->cur_col); 463 464 return(actual_times); 465 466 } 467 468 /* final location is still on the screen, back up and reposition there */ 469 else { 470 for (i = 0; i < size; i++) { 471 line->cur_col--; 472 if (line->cur_col < ss.left) { 473 line->cur_col = ss.right; 474 line->cur_row--; 475 } 476 } 477 set_cursor(line->cur_row,line->cur_col); 478 return(actual_times); 479 } 480 } 481 482 483 /*^L 484 ********************************************************************** 485 486 Routine: CURSOR_RIGHT 487 488 Function: 489 This routine moves the physical and logical cursor one 490 character forward (to the right). The routine detects and handles 491 the case of scrolling the screen when the end of the screen is 492 reached. 493 494 Parameters: 495 (input/output) line - specifies the structure containing the 496 line and information about the line being 497 edited in edit mode 498 (input) n_times - specifies the number of times to the 499 cursor a character position to the right 500 501 Returns: The actual number of times the cursor was moved 502 forward (to the right) 503 504 Note 1 - If the number of characters from the current cursor 505 location to the end of the line is less than the value 506 specified by 'n_times', the cursor is moved to the end of the 507 line. This condition may be checked by the caller by checking 508 if the value passed for 'n_times' is less than the return 509 value. 510 **********************************************************************/ 511 512 cursor_right(line,n_times) 513 EDIT_LINE *line; 514 int n_times; 515 { 516 int i; 517 int size; 518 int row_diff; 519 int col_diff; 520 int chars_to_eos; 521 CURPOS tpos; 522 int actual_times; 523 int chars_to_eol; 524 525 /* check that we're not already at the end of the line */ 526 if (line->index >= line->length) 527 return(0); 528 529 /* determine the number of characters from current cursor position to 530 the end of the line 531 */ 532 chars_to_eol = line->length - line->index; 533 534 /* if number of times to move cursor right exceeds number of 535 characters to the right of the cursor, set the actual number 536 of times to move to the number of characters to the right of cursor 537 */ 538 if (chars_to_eol > n_times) 539 actual_times = n_times; 540 else 541 actual_times = chars_to_eol; 542 543 /* calculate the display columns to move to the right (a character 544 may require more than one display column, e.g. tab may require 10) 545 */ 546 size = 0; 547 for (i = 0; i < actual_times; i++) 548 size += line->size[line->index+i]; 549 550 /* calculate the number of display columns to end of screen */ 551 row_diff = ss.bottom - line->cur_row; 552 col_diff = ss.right - line->cur_col; 553 chars_to_eos = (row_diff * (ss.right - ss.left + 1)) + col_diff; 554 555 /* determine if new cursor location passes end of screen */ 556 if (chars_to_eos >= size) { 557 558 /* no, just move calculate where the cursor will end up */ 559 for (i = 0; i < size; i++) { 560 line->cur_col++; 561 if (line->cur_col > ss.right) { 562 line->cur_col = ss.left; 563 line->cur_row++; 564 } 565 } 566 567 /* move the physical cursor there */ 568 set_cursor(line->cur_row,line->cur_col); 569 570 /* move keyboard buffer index to the right */ 571 line->index += actual_times; 572 } 573 574 /* new cursor location passes end of screen */ 575 else { 576 577 /* initialize structure for keeping track of cursor */ 578 init_temp_curpos(&tpos,line); 579 580 /* display each character (scrolling if necessary) 581 until the specified number of characters to the right 582 has been displayed 583 */ 584 for (i = 0; i < actual_times; i++) { 585 display_char(&tpos,line->line[line->index]); 586 line->index++; 587 } 588 589 /* update current cursor coordinate values */ 590 line->cur_row = tpos.cur_row; 591 line->cur_col = tpos.cur_col; 592 line->orig_row -= tpos.scroll_flag; 593 594 if (line->orig_row < ss.top) 595 line->scrolled_flag = TRUE; 596 597 /* redisplay rest of line to end of screen */ 598 redisplay(line,line->index,&(line->max_row),&(line->max_col)); 599 } 600 601 /* return the actual amount moved to the right */ 602 return(actual_times); 603 } 604 605 606 607 /*^L 608 ********************************************************************** 609 610 Routine: FORWARD_WORD 611 612 Function: 613 This routine moves the physical and logical cursor forward 614 until the end of a word is reached. The number of times this 615 operation is repeated may be specified. 616 617 Parameters: 618 (input/output) line - pointer to the structure containing the 619 line and information about the line being 620 edited in edit mode 621 (input) n_times - specifies the number of times to move 622 the cursor forward a word 623 624 Returns: NONE 625 626 **********************************************************************/ 627 628 forward_word(line,n_times) 629 EDIT_LINE *line; 630 int n_times; 631 { 632 int i; 633 int tmp_index; 634 int loop_cnt; 635 636 /* do nothing if already at end of line */ 637 if (line->index >= line->length) return; 638 639 /* get copy of keyboard buffer index */ 640 i = line->index; 641 642 loop_cnt = 0; 643 644 /* perform the specified number of times or until end of line reached */ 645 while (loop_cnt < n_times && i < line->length) { 646 647 /* save index in case no words skipped */ 648 tmp_index = i; 649 650 /* skip any word delimiters */ 651 while (i < line->length && is_word_delim(line->line[i])) 652 i++; 653 654 /* no next word, do nothing */ 655 if (i >= line->length) { 656 /* restore to position before word delimiters skipped */ 657 i = tmp_index; 658 break; 659 } 660 661 /* skip any characters until word delimiter reached */ 662 while (i < line->length && !is_word_delim(line->line[i])) 663 i++; 664 665 /* tally the word skipped */ 666 loop_cnt++; 667 668 } 669 670 /* move and update cursor only if moved forward at least 1 word */ 671 if (loop_cnt > 0) { 672 /* if keyboard buffer did not change, just return */ 673 if (i == line->index) 674 return; 675 676 /* move the keyboard right the calculated number of times */ 677 cursor_right(line,i-line->index); 678 } 679 } 680 681 682 683 /*^L 684 ********************************************************************** 685 686 Routine: BACKWARD_WORD 687 688 Function: 689 This routine moves the physical and logical cursor to the 690 beginning of the previous word. The number of times this operation 691 is repeated may be specified. 692 693 Parameters: 694 (input/output) line - pointer to the structure containing the 695 line and information about the line being 696 edited in edit mode 697 (input) n_times - specifies the number of times to move 698 the cursor backward a word 699 700 Returns: NONE 701 702 **********************************************************************/ 703 704 backward_word(line,n_times) 705 EDIT_LINE *line; 706 int n_times; 707 { 708 int i; 709 int tmp_index; 710 int loop_cnt; 711 712 /* do nothing if already at beginning of line */ 713 if (line->index < 1) return; 714 715 /* assume starting at one character before cursor */ 716 i = line->index - 1; 717 718 loop_cnt = 0; 719 /* move specified number of words back or until beginning of line reached */ 720 while (loop_cnt < n_times && i >= 0) { 721 722 /* save index in case no words skipped */ 723 tmp_index = i; 724 725 /* skip over any word delimiters */ 726 while (i >= 0 && is_word_delim(line->line[i])) 727 i--; 728 729 /* do nothing if no previous word */ 730 if (i < 0) { 731 /* don't move cursor position if just word delimiters */ 732 i = tmp_index; 733 break; 734 } 735 736 /* skip until a word delimiter is reached */ 737 while (i >= 0 && !is_word_delim(line->line[i])) 738 i--; 739 740 /* tally the word skipped */ 741 loop_cnt++; 742 } 743 744 /* move and update cursor only if moved backwards least one word */ 745 if (loop_cnt > 0) { 746 /* restore index position from delimiter reached (or past beginning 747 of line) to beginning of word (or start of line) 748 */ 749 i++; 750 751 /* move the cursor left the calculated number of times */ 752 cursor_left(line,line->index-i); 753 } 754 } 755 756 757 758 /*^L 759 ********************************************************************** 760 761 Routine: IS_WORD_DELIM 762 763 Function: 764 This function, given an ASCII character, specifies whether that 765 character is a word delimiter or not. This function is used by the 766 forward_word and backward_word routines. 767 768 Parameters: 769 (input) ch - specifies the ASCII character being 770 checked as a word delimiter character 771 772 Returns: TRUE if the specifies character is a word 773 delimiter 774 FALSE if the character is NOT a word delimiter 775 776 **********************************************************************/ 777 778 is_word_delim(ch) 779 int ch; 780 { 781 /* if valid ASCII character and is a space character, then word delimter */ 782 if (ch < ASCII_DEL && isspace(ch)) return(TRUE); 783 784 /* check for special punctuations that are not word delimiters */ 785 if (ch < ASCII_DEL && ispunct(ch)) { 786 if (ch == '_' || ch == '$' || ch == '-') 787 return(FALSE); 788 return(TRUE); 789 } 790 return(FALSE); 791 } 792 793 794 795 /*^L 796 ********************************************************************** 797 798 Routine: BACKUP_CURSOR 799 800 Function: 801 This routine just moves the physical cursor backwards a 802 specified number of character positions on the screen and updates 803 the cursor position fields in the structure containing the line and 804 information about the line being edited in edit mode. 805 806 Parameters: 807 (input/output) line - pointer to the structure containing the 808 line and information about the line being 809 edited in edit mode 810 (input) n_times - specifies the number of times to move 811 the cursor backwards a character 812 813 Returns: NONE 814 815 **********************************************************************/ 816 817 backup_cursor(line,n_times) 818 EDIT_LINE *line; 819 int n_times; 820 { 821 int i; 822 823 /* perform the specified number of times */ 824 for (i = 0; i < n_times; i++) { 825 826 /* decrement cursor column value */ 827 line->cur_col--; 828 829 /* past left edge? */ 830 if (line->cur_col < ss.left) { 831 832 /* go to end of previous line */ 833 line->cur_col = ss.right; 834 line->cur_row--; 835 } 836 } 837 838 /* update the physical cursor location */ 839 set_cursor(line->cur_row,line->cur_col); 840 }