source: trunk/third/top/display.c @ 9084

Revision 9084, 22.5 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9083, which included commits to RCS files with non-trunk default branches.
RevLine 
[9083]1/*
2 *  Top users/processes display for Unix
3 *  Version 3
4 *
5 *  This program may be freely redistributed,
6 *  but this entire comment MUST remain intact.
7 *
8 *  Copyright (c) 1984, 1989, William LeFebvre, Rice University
9 *  Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
10 */
11
12/*
13 *  This file contains the routines that display information on the screen.
14 *  Each section of the screen has two routines:  one for initially writing
15 *  all constant and dynamic text, and one for only updating the text that
16 *  changes.  The prefix "i_" is used on all the "initial" routines and the
17 *  prefix "u_" is used for all the "updating" routines.
18 *
19 *  ASSUMPTIONS:
20 *        None of the "i_" routines use any of the termcap capabilities.
21 *        In this way, those routines can be safely used on terminals that
22 *        have minimal (or nonexistant) terminal capabilities.
23 *
24 *        The routines are called in this order:  *_loadave, i_timeofday,
25 *        *_procstates, *_cpustates, *_memory, *_message, *_header,
26 *        *_process, u_endscreen.
27 */
28
29#include "os.h"
30#include <ctype.h>
31#include <time.h>
32
33#include "screen.h"             /* interface to screen package */
34#include "layout.h"             /* defines for screen position layout */
35#include "display.h"
36#include "top.h"
37#include "top.local.h"
38#include "boolean.h"
39#include "machine.h"            /* we should eliminate this!!! */
40#include "utils.h"
41
42#ifdef DEBUG
43FILE *debug;
44#endif
45
46/* imported from screen.c */
47extern int overstrike;
48
49static int lmpid = 0;
50static int last_hi = 0;         /* used in u_process and u_endscreen */
51static int lastline = 0;
52static int display_width = MAX_COLS;
53
54#define lineindex(l) ((l)*display_width)
55
56char *printable();
57
58/* things initialized by display_init and used thruout */
59
60/* buffer of proc information lines for display updating */
61char *screenbuf = NULL;
62
63static char **procstate_names;
64static char **cpustate_names;
65static char **memory_names;
66
67static int num_procstates;
68static int num_cpustates;
69static int num_memory;
70
71static int *lprocstates;
72static int *lcpustates;
73static int *lmemory;
74
75static int *cpustate_columns;
76static int cpustate_total_length;
77
78static enum { OFF, ON, ERASE } header_status = ON;
79
80static int string_count();
81static void summary_format();
82static void line_update();
83
84int display_resize()
85
86{
87    register int lines;
88
89    /* first, deallocate any previous buffer that may have been there */
90    if (screenbuf != NULL)
91    {
92        free(screenbuf);
93    }
94
95    /* calculate the current dimensions */
96    /* if operating in "dumb" mode, we only need one line */
97    lines = smart_terminal ? screen_length - Header_lines : 1;
98
99    /* we don't want more than MAX_COLS columns, since the machine-dependent
100       modules make static allocations based on MAX_COLS and we don't want
101       to run off the end of their buffers */
102    display_width = screen_width;
103    if (display_width >= MAX_COLS)
104    {
105        display_width = MAX_COLS - 1;
106    }
107
108    /* now, allocate space for the screen buffer */
109    screenbuf = (char *)malloc(lines * display_width);
110    if (screenbuf == (char *)NULL)
111    {
112        /* oops! */
113        return(-1);
114    }
115
116    /* return number of lines available */
117    /* for dumb terminals, pretend like we can show any amount */
118    return(smart_terminal ? lines : Largest);
119}
120
121int display_init(statics)
122
123struct statics *statics;
124
125{
126    register int lines;
127    register char **pp;
128    register int *ip;
129    register int i;
130
131    /* call resize to do the dirty work */
132    lines = display_resize();
133
134    /* only do the rest if we need to */
135    if (lines > -1)
136    {
137        /* save pointers and allocate space for names */
138        procstate_names = statics->procstate_names;
139        num_procstates = string_count(procstate_names);
140        lprocstates = (int *)malloc(num_procstates * sizeof(int));
141
142        cpustate_names = statics->cpustate_names;
143        num_cpustates = string_count(cpustate_names);
144        lcpustates = (int *)malloc(num_cpustates * sizeof(int));
145        cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
146
147        memory_names = statics->memory_names;
148        num_memory = string_count(memory_names);
149        lmemory = (int *)malloc(num_memory * sizeof(int));
150
151        /* calculate starting columns where needed */
152        cpustate_total_length = 0;
153        pp = cpustate_names;
154        ip = cpustate_columns;
155        while (*pp != NULL)
156        {
157            if ((i = strlen(*pp++)) > 0)
158            {
159                *ip++ = cpustate_total_length;
160                cpustate_total_length += i + 8;
161            }
162        }
163    }
164
165    /* return number of lines available */
166    return(lines);
167}
168
169i_loadave(mpid, avenrun)
170
171int mpid;
172double *avenrun;
173
174{
175    register int i;
176
177    /* i_loadave also clears the screen, since it is first */
178    clear();
179
180    /* mpid == -1 implies this system doesn't have an _mpid */
181    if (mpid != -1)
182    {
183        printf("last pid: %5d;  ", mpid);
184    }
185
186    printf("load averages");
187
188    for (i = 0; i < 3; i++)
189    {
190        printf("%c %5.2f",
191            i == 0 ? ':' : ',',
192            avenrun[i]);
193    }
194    lmpid = mpid;
195}
196
197u_loadave(mpid, avenrun)
198
199int mpid;
200double *avenrun;
201
202{
203    register int i;
204
205    if (mpid != -1)
206    {
207        /* change screen only when value has really changed */
208        if (mpid != lmpid)
209        {
210            Move_to(x_lastpid, y_lastpid);
211            printf("%5d", mpid);
212            lmpid = mpid;
213        }
214
215        /* i remembers x coordinate to move to */
216        i = x_loadave;
217    }
218    else
219    {
220        i = x_loadave_nompid;
221    }
222
223    /* move into position for load averages */
224    Move_to(i, y_loadave);
225
226    /* display new load averages */
227    /* we should optimize this and only display changes */
228    for (i = 0; i < 3; i++)
229    {
230        printf("%s%5.2f",
231            i == 0 ? "" : ", ",
232            avenrun[i]);
233    }
234}
235
236i_timeofday(tod)
237
238time_t *tod;
239
240{
241    /*
242     *  Display the current time.
243     *  "ctime" always returns a string that looks like this:
244     * 
245     *  Sun Sep 16 01:03:52 1973
246     *      012345678901234567890123
247     *            1         2
248     *
249     *  We want indices 11 thru 18 (length 8).
250     */
251
252    if (smart_terminal)
253    {
254        Move_to(screen_width - 8, 0);
255    }
256    else
257    {
258        fputs("    ", stdout);
259    }
260#ifdef DEBUG
261    {
262        char *foo;
263        foo = ctime(tod);
264        fputs(foo, stdout);
265    }
266#endif
267    printf("%-8.8s\n", &(ctime(tod)[11]));
268    lastline = 1;
269}
270
271static int ltotal = 0;
272static char procstates_buffer[128];
273
274/*
275 *  *_procstates(total, brkdn, names) - print the process summary line
276 *
277 *  Assumptions:  cursor is at the beginning of the line on entry
278 *                lastline is valid
279 */
280
281i_procstates(total, brkdn)
282
283int total;
284int *brkdn;
285
286{
287    register int i;
288
289    /* write current number of processes and remember the value */
290    printf("%d processes:", total);
291    ltotal = total;
292
293    /* put out enough spaces to get to column 15 */
294    i = digits(total);
295    while (i++ < 4)
296    {
297        putchar(' ');
298    }
299
300    /* format and print the process state summary */
301    summary_format(procstates_buffer, brkdn, procstate_names);
302    fputs(procstates_buffer, stdout);
303
304    /* save the numbers for next time */
305    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
306}
307
308u_procstates(total, brkdn)
309
310int total;
311int *brkdn;
312
313{
314    static char new[128];
315    register int i;
316
317    /* update number of processes only if it has changed */
318    if (ltotal != total)
319    {
320        /* move and overwrite */
321#if (x_procstate == 0)
322        Move_to(x_procstate, y_procstate);
323#else
324        /* cursor is already there...no motion needed */
325        /* assert(lastline == 1); */
326#endif
327        printf("%d", total);
328
329        /* if number of digits differs, rewrite the label */
330        if (digits(total) != digits(ltotal))
331        {
332            fputs(" processes:", stdout);
333            /* put out enough spaces to get to column 15 */
334            i = digits(total);
335            while (i++ < 4)
336            {
337                putchar(' ');
338            }
339            /* cursor may end up right where we want it!!! */
340        }
341
342        /* save new total */
343        ltotal = total;
344    }
345
346    /* see if any of the state numbers has changed */
347    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
348    {
349        /* format and update the line */
350        summary_format(new, brkdn, procstate_names);
351        line_update(procstates_buffer, new, x_brkdn, y_brkdn);
352        memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
353    }
354}
355
356/*
357 *  *_cpustates(states, names) - print the cpu state percentages
358 *
359 *  Assumptions:  cursor is on the PREVIOUS line
360 */
361
362static int cpustates_column;
363
364/* cpustates_tag() calculates the correct tag to use to label the line */
365
366char *cpustates_tag()
367
368{
369    register char *use;
370
371    static char *short_tag = "CPU: ";
372    static char *long_tag = "CPU states: ";
373
374    /* if length + strlen(long_tag) >= screen_width, then we have to
375       use the shorter tag (we subtract 2 to account for ": ") */
376    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
377    {
378        use = short_tag;
379    }
380    else
381    {
382        use = long_tag;
383    }
384
385    /* set cpustates_column accordingly then return result */
386    cpustates_column = strlen(use);
387    return(use);
388}
389
390i_cpustates(states)
391
392register int *states;
393
394{
395    register int i = 0;
396    register int value;
397    register char **names = cpustate_names;
398    register char *thisname;
399
400    /* print tag and bump lastline */
401    printf("\n%s", cpustates_tag());
402    lastline++;
403
404    /* now walk thru the names and print the line */
405    while ((thisname = *names++) != NULL)
406    {
407        if (*thisname != '\0')
408        {
409            /* retrieve the value and remember it */
410            value = *states++;
411
412            /* if percentage is >= 1000, print it as 100% */
413            printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
414                   i++ == 0 ? "" : ", ",
415                   ((float)value)/10.,
416                   thisname);
417        }
418    }
419
420    /* copy over values into "last" array */
421    memcpy(lcpustates, states, num_cpustates * sizeof(int));
422}
423
424u_cpustates(states)
425
426register int *states;
427
428{
429    register int value;
430    register char **names = cpustate_names;
431    register char *thisname;
432    register int *lp;
433    register int *colp;
434
435    Move_to(cpustates_column, y_cpustates);
436    lastline = y_cpustates;
437    lp = lcpustates;
438    colp = cpustate_columns;
439
440    /* we could be much more optimal about this */
441    while ((thisname = *names++) != NULL)
442    {
443        if (*thisname != '\0')
444        {
445            /* did the value change since last time? */
446            if (*lp != *states)
447            {
448                /* yes, move and change */
449                Move_to(cpustates_column + *colp, y_cpustates);
450                lastline = y_cpustates;
451
452                /* retrieve value and remember it */
453                value = *states;
454
455                /* if percentage is >= 1000, print it as 100% */
456                printf((value >= 1000 ? "%4.0f" : "%4.1f"),
457                       ((double)value)/10.);
458
459                /* remember it for next time */
460                *lp = *states;
461            }
462        }
463
464        /* increment and move on */
465        lp++;
466        states++;
467        colp++;
468    }
469}
470
471z_cpustates()
472
473{
474    register int i = 0;
475    register char **names = cpustate_names;
476    register char *thisname;
477    register int *lp;
478
479    /* show tag and bump lastline */
480    printf("\n%s", cpustates_tag());
481    lastline++;
482
483    while ((thisname = *names++) != NULL)
484    {
485        if (*thisname != '\0')
486        {
487            printf("%s    %% %s", i++ == 0 ? "" : ", ", thisname);
488        }
489    }
490
491    /* fill the "last" array with all -1s, to insure correct updating */
492    lp = lcpustates;
493    i = num_cpustates;
494    while (--i >= 0)
495    {
496        *lp++ = -1;
497    }
498}
499
500/*
501 *  *_memory(stats) - print "Memory: " followed by the memory summary string
502 *
503 *  Assumptions:  cursor is on "lastline"
504 *                for i_memory ONLY: cursor is on the previous line
505 */
506
507char memory_buffer[MAX_COLS];
508
509i_memory(stats)
510
511int *stats;
512
513{
514    fputs("\nMemory: ", stdout);
515    lastline++;
516
517    /* format and print the memory summary */
518    summary_format(memory_buffer, stats, memory_names);
519    fputs(memory_buffer, stdout);
520}
521
522u_memory(stats)
523
524int *stats;
525
526{
527    static char new[MAX_COLS];
528
529    /* format the new line */
530    summary_format(new, stats, memory_names);
531    line_update(memory_buffer, new, x_mem, y_mem);
532}
533
534/*
535 *  *_message() - print the next pending message line, or erase the one
536 *                that is there.
537 *
538 *  Note that u_message is (currently) the same as i_message.
539 *
540 *  Assumptions:  lastline is consistent
541 */
542
543/*
544 *  i_message is funny because it gets its message asynchronously (with
545 *      respect to screen updates).
546 */
547
548static char next_msg[MAX_COLS + 5];
549static int msglen = 0;
550/* Invariant: msglen is always the length of the message currently displayed
551   on the screen (even when next_msg doesn't contain that message). */
552
553i_message()
554
555{
556    while (lastline < y_message)
557    {
558        fputc('\n', stdout);
559        lastline++;
560    }
561    if (next_msg[0] != '\0')
562    {
563        standout(next_msg);
564        msglen = strlen(next_msg);
565        next_msg[0] = '\0';
566    }
567    else if (msglen > 0)
568    {
569        (void) clear_eol(msglen);
570        msglen = 0;
571    }
572}
573
574u_message()
575
576{
577    i_message();
578}
579
580static int header_length;
581
582/*
583 *  *_header(text) - print the header for the process area
584 *
585 *  Assumptions:  cursor is on the previous line and lastline is consistent
586 */
587
588i_header(text)
589
590char *text;
591
592{
593    header_length = strlen(text);
594    if (header_status == ON)
595    {
596        putchar('\n');
597        fputs(text, stdout);
598        lastline++;
599    }
600    else if (header_status == ERASE)
601    {
602        header_status = OFF;
603    }
604}
605
606/*ARGSUSED*/
607u_header(text)
608
609char *text;             /* ignored */
610
611{
612    if (header_status == ERASE)
613    {
614        putchar('\n');
615        lastline++;
616        clear_eol(header_length);
617        header_status = OFF;
618    }
619}
620
621/*
622 *  *_process(line, thisline) - print one process line
623 *
624 *  Assumptions:  lastline is consistent
625 */
626
627i_process(line, thisline)
628
629int line;
630char *thisline;
631
632{
633    register char *p;
634    register char *base;
635
636    /* make sure we are on the correct line */
637    while (lastline < y_procs + line)
638    {
639        putchar('\n');
640        lastline++;
641    }
642
643    /* truncate the line to conform to our current screen width */
644    thisline[display_width] = '\0';
645
646    /* write the line out */
647    fputs(thisline, stdout);
648
649    /* copy it in to our buffer */
650    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
651    p = strecpy(base, thisline);
652
653    /* zero fill the rest of it */
654    memzero(p, display_width - (p - base));
655}
656
657u_process(line, newline)
658
659int line;
660char *newline;
661
662{
663    register char *optr;
664    register int screen_line = line + Header_lines;
665    register char *bufferline;
666
667    /* remember a pointer to the current line in the screen buffer */
668    bufferline = &screenbuf[lineindex(line)];
669
670    /* truncate the line to conform to our current screen width */
671    newline[display_width] = '\0';
672
673    /* is line higher than we went on the last display? */
674    if (line >= last_hi)
675    {
676        /* yes, just ignore screenbuf and write it out directly */
677        /* get positioned on the correct line */
678        if (screen_line - lastline == 1)
679        {
680            putchar('\n');
681            lastline++;
682        }
683        else
684        {
685            Move_to(0, screen_line);
686            lastline = screen_line;
687        }
688
689        /* now write the line */
690        fputs(newline, stdout);
691
692        /* copy it in to the buffer */
693        optr = strecpy(bufferline, newline);
694
695        /* zero fill the rest of it */
696        memzero(optr, display_width - (optr - bufferline));
697    }
698    else
699    {
700        line_update(bufferline, newline, 0, line + Header_lines);
701    }
702}
703
704u_endscreen(hi)
705
706register int hi;
707
708{
709    register int screen_line = hi + Header_lines;
710    register int i;
711
712    if (smart_terminal)
713    {
714        if (hi < last_hi)
715        {
716            /* need to blank the remainder of the screen */
717            /* but only if there is any screen left below this line */
718            if (lastline + 1 < screen_length)
719            {
720                /* efficiently move to the end of currently displayed info */
721                if (screen_line - lastline < 5)
722                {
723                    while (lastline < screen_line)
724                    {
725                        putchar('\n');
726                        lastline++;
727                    }
728                }
729                else
730                {
731                    Move_to(0, screen_line);
732                    lastline = screen_line;
733                }
734
735                if (clear_to_end)
736                {
737                    /* we can do this the easy way */
738                    putcap(clear_to_end);
739                }
740                else
741                {
742                    /* use clear_eol on each line */
743                    i = hi;
744                    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
745                    {
746                        putchar('\n');
747                    }
748                }
749            }
750        }
751        last_hi = hi;
752
753        /* move the cursor to a pleasant place */
754        Move_to(x_idlecursor, y_idlecursor);
755        lastline = y_idlecursor;
756    }
757    else
758    {
759        /* separate this display from the next with some vertical room */
760        fputs("\n\n", stdout);
761    }
762}
763
764display_header(t)
765
766int t;
767
768{
769    if (t)
770    {
771        header_status = ON;
772    }
773    else if (header_status == ON)
774    {
775        header_status = ERASE;
776    }
777}
778
779/*VARARGS2*/
780new_message(type, msgfmt, a1, a2, a3)
781
782int type;
783char *msgfmt;
784caddr_t a1, a2, a3;
785
786{
787    register int i;
788
789    /* first, format the message */
790    (void) sprintf(next_msg, msgfmt, a1, a2, a3);
791
792    if (msglen > 0)
793    {
794        /* message there already -- can we clear it? */
795        if (!overstrike)
796        {
797            /* yes -- write it and clear to end */
798            i = strlen(next_msg);
799            if ((type & MT_delayed) == 0)
800            {
801                type & MT_standout ? standout(next_msg) :
802                                     fputs(next_msg, stdout);
803                (void) clear_eol(msglen - i);
804                msglen = i;
805                next_msg[0] = '\0';
806            }
807        }
808    }
809    else
810    {
811        if ((type & MT_delayed) == 0)
812        {
813            type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
814            msglen = strlen(next_msg);
815            next_msg[0] = '\0';
816        }
817    }
818}
819
820clear_message()
821
822{
823    if (clear_eol(msglen) == 1)
824    {
825        putchar('\r');
826    }
827}
828
829readline(buffer, size, numeric)
830
831char *buffer;
832int  size;
833int  numeric;
834
835{
836    register char *ptr = buffer;
837    register char ch;
838    register char cnt = 0;
839    register char maxcnt = 0;
840
841    /* allow room for null terminator */
842    size -= 1;
843
844    /* read loop */
845    while ((fflush(stdout), read(0, ptr, 1) > 0))
846    {
847        /* newline means we are done */
848        if ((ch = *ptr) == '\n')
849        {
850            break;
851        }
852
853        /* handle special editing characters */
854        if (ch == ch_kill)
855        {
856            /* kill line -- account for overstriking */
857            if (overstrike)
858            {
859                msglen += maxcnt;
860            }
861
862            /* return null string */
863            *buffer = '\0';
864            putchar('\r');
865            return(-1);
866        }
867        else if (ch == ch_erase)
868        {
869            /* erase previous character */
870            if (cnt <= 0)
871            {
872                /* none to erase! */
873                putchar('\7');
874            }
875            else
876            {
877                fputs("\b \b", stdout);
878                ptr--;
879                cnt--;
880            }
881        }
882        /* check for character validity and buffer overflow */
883        else if (cnt == size || (numeric && !isdigit(ch)) ||
884                !isprint(ch))
885        {
886            /* not legal */
887            putchar('\7');
888        }
889        else
890        {
891            /* echo it and store it in the buffer */
892            putchar(ch);
893            ptr++;
894            cnt++;
895            if (cnt > maxcnt)
896            {
897                maxcnt = cnt;
898            }
899        }
900    }
901
902    /* all done -- null terminate the string */
903    *ptr = '\0';
904
905    /* account for the extra characters in the message area */
906    /* (if terminal overstrikes, remember the furthest they went) */
907    msglen += overstrike ? maxcnt : cnt;
908
909    /* return either inputted number or string length */
910    putchar('\r');
911    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
912}
913
914/* internal support routines */
915
916static int string_count(pp)
917
918register char **pp;
919
920{
921    register int cnt;
922
923    cnt = 0;
924    while (*pp++ != NULL)
925    {
926        cnt++;
927    }
928    return(cnt);
929}
930
931static void summary_format(str, numbers, names)
932
933char *str;
934int *numbers;
935register char **names;
936
937{
938    register char *p;
939    register int num;
940    register char *thisname;
941    register int useM = No;
942
943    /* format each number followed by its string */
944    p = str;
945    while ((thisname = *names++) != NULL)
946    {
947        /* get the number to format */
948        num = *numbers++;
949
950        /* display only non-zero numbers */
951        if (num > 0)
952        {
953            /* is this number in kilobytes? */
954            if (thisname[0] == 'K')
955            {
956                /* yes: format it as a memory value */
957                p = strecpy(p, format_k(num));
958
959                /* skip over the K, since it was included by format_k */
960                p = strecpy(p, thisname+1);
961            }
962            else
963            {
964                p = strecpy(p, itoa(num));
965                p = strecpy(p, thisname);
966            }
967        }
968
969        /* ignore negative numbers, but display corresponding string */
970        else if (num < 0)
971        {
972            p = strecpy(p, thisname);
973        }
974    }
975
976    /* if the last two characters in the string are ", ", delete them */
977    p -= 2;
978    if (p >= str && p[0] == ',' && p[1] == ' ')
979    {
980        *p = '\0';
981    }
982}
983
984static void line_update(old, new, start, line)
985
986register char *old;
987register char *new;
988int start;
989int line;
990
991{
992    register int ch;
993    register int diff;
994    register int newcol = start + 1;
995    register int lastcol = start;
996    char cursor_on_line = No;
997    char *current;
998
999    /* compare the two strings and only rewrite what has changed */
1000    current = old;
1001#ifdef DEBUG
1002    fprintf(debug, "line_update, starting at %d\n", start);
1003    fputs(old, debug);
1004    fputc('\n', debug);
1005    fputs(new, debug);
1006    fputs("\n-\n", debug);
1007#endif
1008
1009    /* start things off on the right foot                   */
1010    /* this is to make sure the invariants get set up right */
1011    if ((ch = *new++) != *old)
1012    {
1013        if (line - lastline == 1 && start == 0)
1014        {
1015            putchar('\n');
1016        }
1017        else
1018        {
1019            Move_to(start, line);
1020        }
1021        cursor_on_line = Yes;
1022        putchar(ch);
1023        *old = ch;
1024        lastcol = 1;
1025    }
1026    old++;
1027       
1028    /*
1029     *  main loop -- check each character.  If the old and new aren't the
1030     *  same, then update the display.  When the distance from the
1031     *  current cursor position to the new change is small enough,
1032     *  the characters that belong there are written to move the
1033     *  cursor over.
1034     *
1035     *  Invariants:
1036     *      lastcol is the column where the cursor currently is sitting
1037     *          (always one beyond the end of the last mismatch).
1038     */
1039    do          /* yes, a do...while */
1040    {
1041        if ((ch = *new++) != *old)
1042        {
1043            /* new character is different from old        */
1044            /* make sure the cursor is on top of this character */
1045            diff = newcol - lastcol;
1046            if (diff > 0)
1047            {
1048                /* some motion is required--figure out which is shorter */
1049                if (diff < 6 && cursor_on_line)
1050                {
1051                    /* overwrite old stuff--get it out of the old buffer */
1052                    printf("%.*s", diff, &current[lastcol-start]);
1053                }
1054                else
1055                {
1056                    /* use cursor addressing */
1057                    Move_to(newcol, line);
1058                    cursor_on_line = Yes;
1059                }
1060                /* remember where the cursor is */
1061                lastcol = newcol + 1;
1062            }
1063            else
1064            {
1065                /* already there, update position */
1066                lastcol++;
1067            }
1068               
1069            /* write what we need to */
1070            if (ch == '\0')
1071            {
1072                /* at the end--terminate with a clear-to-end-of-line */
1073                (void) clear_eol(strlen(old));
1074            }
1075            else
1076            {
1077                /* write the new character */
1078                putchar(ch);
1079            }
1080            /* put the new character in the screen buffer */
1081            *old = ch;
1082        }
1083           
1084        /* update working column and screen buffer pointer */
1085        newcol++;
1086        old++;
1087           
1088    } while (ch != '\0');
1089
1090    /* zero out the rest of the line buffer -- MUST BE DONE! */
1091    diff = display_width - newcol;
1092    if (diff > 0)
1093    {
1094        memzero(old, diff);
1095    }
1096
1097    /* remember where the current line is */
1098    if (cursor_on_line)
1099    {
1100        lastline = line;
1101    }
1102}
1103
1104/*
1105 *  printable(str) - make the string pointed to by "str" into one that is
1106 *      printable (i.e.: all ascii), by converting all non-printable
1107 *      characters into '?'.  Replacements are done in place and a pointer
1108 *      to the original buffer is returned.
1109 */
1110
1111char *printable(str)
1112
1113char *str;
1114
1115{
1116    register char *ptr;
1117    register char ch;
1118
1119    ptr = str;
1120    while ((ch = *ptr) != '\0')
1121    {
1122        if (!isprint(ch))
1123        {
1124            *ptr = '?';
1125        }
1126        ptr++;
1127    }
1128    return(str);
1129}
Note: See TracBrowser for help on using the repository browser.