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   4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
 20      install(89-04-24,MR12.3-1033):
 21      phx21233 - Converted display_char() to display_char_prim() for handling
 22      primitive display function; new display_char() added which calls the
 23      primitive and displays only when keyboard echoing is enabled. Added
 24      routine get_echoed_input() for extracting only echoed input from line
 25      buffer.
 26                                                    END HISTORY COMMENTS */
 27 
 28 #include <dos.h>
 29 #include "wstdefs.h"
 30 #include "wstglob.h"
 31 
 32 /*^L
 33 ***********************************************************************
 34 
 35   Routine:            DISPLAY_CHAR_STR
 36 
 37   Function:
 38       This routine returns the display string for a character
 39   displayed in line editing. In particular, it determines how
 40   non-printable characters are displayed.
 41 
 42   Parameters:
 43      (input)          ch - specifies the ASCII character being
 44                           displayed
 45 
 46   Returns:            a pointer to a static string containing the
 47                           displayed form of the ASCII character
 48 
 49 **********************************************************************/
 50 
 51 char *display_char_str(ch)
 52 int ch;  /* character to display */
 53 {
 54     static char display_string[MAX_DISPLAY_CHAR_SIZE+1];     /* string to pass back result */
 55     int octval;
 56 
 57     /* check for non-printable control character */
 58     if (ch < MIN_PRINTABLE_ASCII) {
 59         octval = ch;
 60         display_string[0] = '\\';
 61         display_string[3] = (ch & 07) + '0';
 62         ch >>= 3;
 63         display_string[2] = (ch & 07) + '0';
 64         ch >>= 3;
 65         display_string[1] = (ch & 07) + '0';
 66         display_string[4] = NUL_TERMINATOR;
 67     }
 68 
 69     /* check for printable ASCII */
 70     else if (ch < ASCII_DEL) {
 71         display_string[0] = ch;
 72         display_string[1] = NUL_TERMINATOR;
 73     }
 74 
 75     /* check for ASCII DEL character */
 76     else if (ch == ASCII_DEL) {
 77         strcpy(display_string,"\\177");
 78     }
 79 
 80     /* extended ASCII character */
 81     else {
 82         sprintf(display_string,"<%d>", ch);
 83     }
 84 
 85     return(display_string);
 86 }
 87 
 88 
 89 /*^L
 90 ***********************************************************************
 91 
 92   Routine:            DISPLAY_TAB_STR
 93 
 94   Function:
 95       This routine returns a string filled with enough blanks to pad
 96   to the next tab column.
 97 
 98   Parameters:
 99      (input)          cur_col - specifies the current column on the
100                           screen to tab from
101 
102   Returns:            a pointer to a static string containing enough
103                           spaces to pad to the next tab position on
104                           the screen
105 
106 **********************************************************************/
107 
108 char *display_tab_str(cur_col)
109 int cur_col;  /* specifies current cursor column coordinate */
110 {
111     static char display_string[TAB_SIZE+1];  /* result string to pass back */
112     int n_spaces;                       /* number of spaces to pad */
113     register int i;                     /* working index */
114 
115     /* if column exceeds right screen edge, assume wrap around to
116        leftmost edge on next line
117     */
118     if (cur_col >= ss.right)
119         n_spaces = TAB_SIZE;
120 
121     /* handle current column within screen */
122     else {
123         /* calculate padding to next tab column */
124         n_spaces = TAB_SIZE - ((cur_col - ss.left) % TAB_SIZE);
125 
126         /* if exceeds right edge, truncate to get to leftmost
127            column on next line; this handles the case where the
128            screen width is not a multiple of the tab size and
129            guarantees wrap around to the leftmost column
130         */
131         if (cur_col + n_spaces >= ss.right)
132             n_spaces = ss.right - cur_col + 1;
133     }
134 
135     /* initialize the string with the correct number of spaces */
136     for (i = 0; i < n_spaces; i++)
137         display_string[i] = ' ';
138 
139     /* null-terminate the string */
140     display_string[i] = NUL_TERMINATOR;
141 
142     return(display_string);
143 }
144 
145 
146 /*^L
147 ***********************************************************************
148 
149   Routine:            DISPLAY_CHAR_PRIM
150 
151   Function:
152       This routine displays a character entered from the keyboard in
153   an appropriate representation. It keeps track of cursor position,
154   line wrap arounds and scrolling.
155 
156   Parameters:
157      (input/output)   pos - pointer to a structure which maintains
158                           cursor position information; information is
159                           updated after the display
160      (input)          ch - specifies the ASCII character to display
161 
162   Returns:            The number of characters displayed to represent
163                           the keyboard character
164 
165 **********************************************************************/
166 
167 display_char_prim(pos,ch)
168 CURPOS *pos;   /* pointer to structure for keeping track of cursor position */
169 int ch;        /* character to display */
170 {
171     char *display_char_str();
172     char *ptr;            /* pointer to display string */
173     int  display_length;  /* holds length of display string */
174 
175     /* character is the TAB character ? */
176     if (ch == TAB)
177         /* get the string to display for the tab */
178         ptr = display_tab_str(pos->cur_col);
179 
180     /* not tab, get the string to display for the character */
181     else
182         ptr = display_char_str(ch);
183 
184     /* determine the length of the display string */
185     display_length = strlen(ptr);
186 
187     /* display the display string, keeping track of cursor position */
188     while (TRUE) {
189 
190         /* cursor column past right screen edge */
191         if (pos->cur_col > ss.right) {
192 
193             /* wrap around to left edge */
194             pos->cur_col = ss.left;
195 
196             /* at bottom of screen? */
197             if (pos->cur_row >= ss.bottom) {
198 
199                 /* scroll and tally the scroll */
200                 pos->scroll_flag++;
201                 wst_scroll();
202             }
203 
204             /* not at bottom of screen, at next line */
205             else
206                 pos->cur_row++;
207 
208             /* update the physical cursor */
209             set_cursor(pos->cur_row,pos->cur_col);
210         }
211 
212         /* if NUL terminator reached, exit print loop */
213         if (!*ptr) break;
214 
215         /* display the character */
216         putch(*ptr);
217 
218         /* point to next character in display string */
219         ptr++;
220 
221         /* move the cursor forward */
222         pos->cur_col++;
223 
224     }
225 
226     return(display_length);
227 }
228 
229 
230 /*^L
231 ***********************************************************************
232 
233   Routine:            REDISPLAY
234 
235   Function:
236       This routine redisplays the edited line from a particular
237   position in the line until the end or the end of the screen is
238   reached, whichever is reached first. The fields in the line
239   structure passed to this routine are not directly altered.
240 
241   Parameters:
242      (input)          line - pointer to the structure containing the
243                           line and information about the line being
244                           edited
245      (input)          pos - specifies what position in the line to
246                           begin redisplaying
247      (output)         max_row - specifies the integer to pass back
248                           the ending row coordinate after the
249                           redisplay
250      (output)         max_col - specifies the integer to pass back
251                           the ending column coordinate after the
252                           redisplay
253 
254   Returns:            NONE
255 
256   Note 1 - It is assumed that the physical cursor on the screen is at
257       the line position specified by the parameter 'pos'.
258 **********************************************************************/
259 
260 redisplay(line,pos,max_row,max_col)
261 EDIT_LINE *line;
262 int pos;
263 int *max_row;
264 int *max_col;
265 {
266     char *display_char_str();
267     char *display_tab_str();
268     char *ptr;
269     int row;
270     int col;
271     int i;
272     int tmp_row;
273     int tmp_col;
274 
275     /* get a working copy of current cursor row and column coordinates */
276     row = line->cur_row;
277     col = line->cur_col;
278 
279     /* check that position in line buffer to start redisplay is valid */
280     if (pos >= 0 && pos < line->length) {
281 
282         /* display each character until end of line */
283         for (i = pos; i < line->length; i++) {
284 
285             /* check if character is a tab */
286             if (line->line[i] == TAB)
287                 /* get tab string and update size of tab */
288                 ptr = display_tab_str(col);
289 
290             /* otherwise just get character string */
291             else
292                 ptr = display_char_str(line->line[i]);
293 
294             /* phx21233 R.L. - size of 0 means character not echoed and */
295             /*      should not be displayed  */
296             if (line->size[i])
297                 line->size[i] = strlen(ptr);
298 
299             else
300                 continue;
301 
302             /* display character string until NUL terminator reached */
303             while (*ptr) {
304 
305                 /* check for wrap around past right edge of screen */
306                 if (check_line_wrap(line,&row,&col,max_row,max_col) < 0)
307                     return;
308 
309                 /* display the current character in the string */
310                 putch(*ptr);
311 
312                 /* point to next character in the string */
313                 ptr++;
314 
315                 /* increment cursor position */
316                 col++;
317 
318                 /* check if a text key was hit */
319                 if (stop_display(line)) {
320 
321                     /* stop redisplay routine because another character
322                        has been entered from the keyboard which will
323                        call redisplay again to finish updating the screen
324                     */
325                     set_cursor(line->cur_row,line->cur_col);
326                     return;
327                 }
328             }
329         }
330 
331         /* check for wrap around past right edge of screen */
332         if (check_line_wrap(line,&row,&col,max_row,max_col) < 0)
333             return;
334     }
335 
336     /* save ending coordinates (coordinates of where line
337        displayed ends)
338     */
339     tmp_row = row;
340     tmp_col = col;
341 
342     /* reached the end of line, but must pad to ending
343        coordinates with blanks to erase leftover characters
344     */
345     while (row < line->max_row) {
346         if (col > ss.right) {
347             col = ss.left;
348             row++;
349             set_cursor(row,col);
350         }
351         else {
352             putch(' ');
353             col++;
354         }
355     }
356 
357     if (row == line->max_row) {
358         while (col <= line->max_col) {
359             putch(' ');
360             col++;
361         }
362     }
363 
364     /* update the physical location of the cursor */
365     set_cursor(line->cur_row,line->cur_col);
366     *max_row = tmp_row;
367     *max_col = tmp_col;
368 }
369 
370 
371 
372 /*^L
373 ***********************************************************************
374 
375   Routine:            CHECK_LINE_WRAP
376 
377   Function:
378       This routine checks to see if the cursor has gone past the
379   defined right edge of the screen and moves the cursor to the left
380   most column of the next line. If the line is wrapped at the bottom
381   most line of the defined screen area, a flag in the line structure
382   is set and the maximum row and col coordinates of the screen are
383   past back to the caller.
384 
385   Parameters:
386      (input)          line - pointer to the structure containing the
387                           line and information about the line being
388                           edited
389      (input/output)   row - contains the address of the variable containing
390                           the current row coordinates of the cursor
391      (input/output)   col - contains the address of the variable containing
392                           the current column coordinates of the cursor
393      (output)         max_row - this variable is initialized to the
394                           maximum screen row coordinate if the line
395                           wraps on the last row
396      (output)         max_col - this variable is initialized to the
397                           maximum screen column coordinate if the
398                           line wraps on the last row
399 
400   Returns:             0 if screen not completely filled
401                       -1 if the line extends beyond the end of the
402                          screen
403 
404 **********************************************************************/
405 
406 check_line_wrap(line,row,col,max_row,max_col)
407 EDIT_LINE *line;
408 int *row;
409 int *col;
410 int *max_row;
411 int *max_col;
412 {
413     /* check for wrap around past right edge of screen */
414     if (*col > ss.right) {
415         /* wrap around to left side of screen */
416         *col = ss.left;
417 
418         /* reached bottom of screen? */
419         if (*row >= ss.bottom) {
420 
421             /* update max row and col variables */
422             *max_row = ss.bottom;
423             *max_col = ss.right;
424 
425             /* flag not all characters displayed */
426             line->off_screen = TRUE;
427 
428             /* restore physical cursor position */
429             set_cursor(line->cur_row,line->cur_col);
430             return(-1);
431         }
432 
433         /* not bottom of screen, go to next line */
434         else
435             (*row)++;
436 
437         /* update location of physical cursor */
438         set_cursor(*row,*col);
439     }
440     return(0);
441 }
442 
443 
444 /*^L
445 ***********************************************************************
446 
447   Routine:            STOP_DISPLAY
448 
449   Function:
450       This routine is used to optimize screen updates by checking to
451   see if updating of the screen may be stopped before it is
452   completed. This is possible if another key is detected that
453   guarantees the redisplay routine will be called again to update the
454   screen.
455 
456   Parameters:
457      (input)          line - pointer to the structure containing the
458                           line and information about the line being
459                           edited
460 
461   Returns:            TRUE if a key was detected that guarantees a
462                           subsequent screen update
463                       FALSE otherwise
464 
465 **********************************************************************/
466 
467 stop_display(line)
468 EDIT_LINE *line;
469 {
470     int ch;
471 
472     /* don't stop update if no key hit or key is not ASCII */
473     if ((ch = checkkey()) < 0 || ch > ASCII_EXTEND_CODE) return(FALSE);
474 
475     switch (ch) {
476         /* kill to beginning of line will update if not already at  */
477         /* beginning of line                                        */
478         case '@':
479             if (line->index > ZERO_INDEX_VALUE) return(TRUE);
480             return(FALSE);
481 
482         /* literal escape or escape does not guarantee subsequent   */
483         /* redisplay                                                */
484         case '\\':
485         case ESC:
486             return(FALSE);
487 
488         /* backspace and delete key redisplays if a character is    */
489         /* deleted                                                  */
490         case BACKSPACE:
491         case DEL_KEY:
492             if (line->index > ZERO_INDEX_VALUE) return(TRUE);
493             return(FALSE);
494 
495         /* delete character key redisplays if cursor is before end  */
496         /* of line                                                  */
497         case CTRL_D:
498             if (line->index < line->length) return(TRUE);
499             return(FALSE);
500 
501         /* kill to end of line redisplays if not already at end of  */
502         /* line                                                     */
503         case CTRL_K:
504             if (line->index < line->length) return(TRUE);
505             return(FALSE);
506 
507         default:
508 
509             /* if not a tab and not a printable character, may not  */
510             /* force a redraw                                       */
511             if (ch != TAB &&
512                 (ch < MIN_PRINTABLE_ASCII || ch > MAX_PRINTABLE_ASCII))
513                 return(FALSE);
514 
515             /* a printable character; if in replace mode, redraws   */
516             /* if not at end of line                                */
517             if (line->mode) {
518                 if (line->length < MAX_LINE_SIZE) return(TRUE);
519                 return(FALSE);
520             }
521 
522             /* in insert mode, redraws if maximum line size has     */
523             /* not been reached                                     */
524             else {
525                 if (line->index < MAX_LINE_SIZE) return(TRUE);
526                 return(FALSE);
527             }
528     }
529 }
530 
531 
532 /*^L
533 ***********************************************************************
534 
535   Routine:            GET_ECHOED_INPUT
536 
537   Function:
538       This routine is used to extract echoed input from a specified
539   part of the edit-mode input line buffer. Only characters echoed will
540   be extracted. The results are passed back in a static string, along
541   with the length of the extracted input item.
542 
543   Parameters:
544      (input)          line - pointer to the structure containing the
545                           line and information about the line being
546                           edited
547      (input)          item_pos - index to position in line buffer
548                           to begin extracting
549      (input)          item_size - number of characters in line buffer
550                           from which to extract
551      (output)         display_str - pointer to the string extracted
552      (output)         display_len - length of string extract
553 
554   Returns:            None
555 
556 **********************************************************************/
557 
558 get_echoed_input(line,item_pos,item_size,display_str,display_len)
559 EDIT_LINE *line;
560 int item_pos;
561 int item_size;
562 char **display_str;
563 int *display_len;
564 {
565     static char echoed_str[MAX_LINE_SIZE+1];
566     register int i;
567     register int count;
568 
569     /* ensure specified position for extraction is valid */
570     if (item_pos > line->length) item_pos = line->length;
571     else if (item_pos < 0) item_pos = 0;
572 
573     /* ensure specified number of chars for extraction is valid */
574     if (item_pos+item_size > line->length)
575         item_size = line->length - item_pos;
576 
577     /* tally and copy over the echoed input characters from input buffer */
578     count = 0;
579     for (i = item_pos; i < item_size; i++)
580         /* if represented by at least 1 character */
581         if (line->size[i] > 0)
582             echoed_str[count++] = line->line[i];
583     echoed_str[count] = 0;
584 
585     /* pass back the results */
586     *display_str = echoed_str;
587     *display_len = count;
588 }
589 
590 
591 
592 /*^L
593 ***********************************************************************
594 
595   Routine:            DISPLAY_CHAR
596 
597   Function:
598       This routine displays a character entered from the keyboard in
599   an appropriate representation by calling display_char_prim() if
600   keyboard echoing is enabled. If echoing is disabled, nothing is
601   displayed and 0 is returned.
602 
603   Parameters:
604      (input/output)   pos - pointer to a structure which maintains
605                           cursor position information; information is
606                           updated after the display
607      (input)          ch - specifies the ASCII character to display
608 
609   Returns:            The number of characters displayed to represent
610                           the keyboard character if keyboard echoing enabled
611                       0 if keyboard character echoing is disabled
612 
613 **********************************************************************/
614 
615 display_char(pos,ch)
616 CURPOS *pos;   /* pointer to structure for keeping track of cursor position */
617 int ch;        /* character to display */
618 {
619     if (!kb.echo)
620         return(0);
621 
622     return(display_char_prim(pos,ch));
623 }
624