home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / src / top / display.c < prev    next >
C/C++ Source or Header  |  1992-02-01  |  19KB  |  990 lines

  1. /*
  2.  *  Top - a top users display for Berkeley Unix
  3.  *
  4.  *  This file contains the routines that display information on the screen.
  5.  *  Each section of the screen has two routines:  one for initially writing
  6.  *  all constant and dynamic text, and one for only updating the text that
  7.  *  changes.  The prefix "i_" is used on all the "initial" routines and the
  8.  *  prefix "u_" is used for all the "updating" routines.  NOTE:  it is
  9.  *  assumed that none of the "i_" routines use any of the termcap
  10.  *  capabilities.  In this way, those routines can be safely used on
  11.  *  terminals that have minimal (or nonexistant) terminal capabilities.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <strings.h>
  17. #ifdef sunos4
  18. #define KERNEL        /* to get definition for PZERO */
  19. #include <sys/param.h>
  20. #undef KERNEL
  21. #else
  22. #include <sys/param.h>
  23. #endif
  24. #include <sys/dir.h>
  25. #include <sys/user.h>
  26. #ifdef scs
  27. # define FLOAT        /* for pctcpu in proc.h */
  28. # include <sys/vm.h>    /* for struct spt */
  29. #endif
  30. #include <sys/proc.h>
  31. #include <sys/dk.h>
  32. #include "screen.h"        /* interface to screen package */
  33. #include "layout.h"        /* defines for screen position layout */
  34. #include "top.h"
  35. #include "top.local.h"
  36. #include "boolean.h"
  37.  
  38. /* imported from screen.c */
  39. extern int overstrike;
  40.  
  41. static int lmpid = 0;
  42. static struct user u;
  43.  
  44. #ifdef scs
  45. static struct spt pspt;        /* for get_spt call */
  46. #endif scs
  47.  
  48. char *sprintf();
  49. char *printable();
  50.  
  51. /* Verbose process state names */
  52.  
  53. char *state_name[] =
  54. {
  55.     "", "sleeping", "ABANDONED", "running", "starting", "zombie", "stopped"
  56. };
  57.  
  58. /* process state names for the "STATE" column of the display */
  59.  
  60. char *state_abbrev[] =
  61. {
  62.     "", "sleep", "WAIT", "run", "start", "zomb", "stop"
  63. };
  64.  
  65. /* cpu state names for percentages */
  66.  
  67. char *cpu_state[] =
  68. {
  69.     "user", "nice", "system", "idle"
  70. };
  71.  
  72. /* screen positions for cpustate figures */
  73. char x_cpustates[] = { 12, 24, 36, 50 };
  74.  
  75. i_loadave(mpid, avenrun)
  76.  
  77. int mpid;
  78. #ifdef sun
  79. long *avenrun;
  80. #else
  81. double *avenrun;
  82. #endif sun
  83.  
  84. {
  85.     register int i;
  86.  
  87.     /* i_loadave also clears the screen, since it is first */
  88.     clear();
  89.  
  90.     printf("last pid: %5d;  load averages", mpid);
  91.  
  92.     for (i = 0; i < 3; i++)
  93.     {
  94.     printf("%c %5.2f",
  95.         i == 0 ? ':' : ',',
  96. #ifdef sun
  97.         (double)avenrun[i] / FSCALE);
  98. #else
  99.         avenrun[i]);
  100. #endif
  101.     }
  102.     lmpid = mpid;
  103. }
  104.  
  105. u_loadave(mpid, avenrun)
  106.  
  107. int mpid;
  108. #ifdef sun
  109. long *avenrun;
  110. #else
  111. double *avenrun;
  112. #endif sun
  113.  
  114. {
  115.     register int i;
  116.  
  117.     if (mpid != lmpid);
  118.     {
  119.     Move_to(x_lastpid, y_lastpid);
  120.     printf("%5d", mpid);
  121.     lmpid = mpid;
  122.     }
  123.  
  124.     Move_to(x_loadave, y_loadave);
  125.     for (i = 0; i < 3; i++)
  126.     {
  127.     printf("%s%5.2f",
  128.         i == 0 ? "" : ", ",
  129. #ifdef sun
  130.         (double)avenrun[i] / FSCALE);
  131. #else
  132.         avenrun[i]);
  133. #endif
  134.     }
  135. }
  136.  
  137. static int ltotal = 0;
  138. static int llength = 0;
  139. static int lbrkdn[7];
  140.  
  141. i_procstates(total, brkdn)
  142.  
  143. int total;
  144. int *brkdn;
  145.  
  146. {
  147.     register int i;
  148.     register int position;
  149.  
  150.     /* write current number of processes and remember the value */
  151.     printf("%d processes:", total);
  152.     ltotal = total;
  153.  
  154.     /* put out enough spaces to get to column 15 */
  155.     i = digits(total);
  156.     while (i++ < 4)
  157.     {
  158.     putchar(' ');
  159.     }
  160.  
  161.     /* remember where we are to get length of the breakdown area */
  162.     position = fileptr(stdout);
  163.  
  164.     /* write the breakdowns */
  165.     for (i = 1; i < 7; i++)
  166.     {
  167.     if (brkdn[i] != 0)
  168.     {
  169.         printf("%s%d %s%s",
  170.             i == 1 ? "" : ", ",
  171.             brkdn[i],
  172.             state_name[i],
  173.             (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
  174.     }
  175.     }
  176.  
  177.     /* calculate length of breakdown area */
  178.     llength = fileptr(stdout) - position;
  179.  
  180.     /* remember breakdown figures */
  181.     bcopy((char *)brkdn, (char *)lbrkdn, sizeof(lbrkdn));
  182. }
  183.  
  184. u_procstates(total, brkdn)
  185.  
  186. int total;
  187. int *brkdn;
  188.  
  189. {
  190.     register int i;
  191.     register int position = No;        /* does double duty */
  192.  
  193.     /* update number of processes only if it has changed */
  194.     if (ltotal != total)
  195.     {
  196.     /* move and overwrite */
  197.     Move_to(x_procstate, y_procstate);
  198.     printf("%d", total);
  199.  
  200.     /* if number of digits differs, rewrite the label */
  201.     if (digits(total) != digits(ltotal))
  202.     {
  203.         fputs(" processes:", stdout);
  204.         /* put out enough spaces to get to column 15 */
  205.         i = digits(total);
  206.         while (i++ < 4)
  207.         {
  208.         putchar(' ');
  209.         }
  210.         /* and remember that we are already there */
  211.         position = Yes;
  212.     }
  213.  
  214.     /* save new total */
  215.     ltotal = total;
  216.     }
  217.     else if (bcmp((char *)brkdn, (char *)lbrkdn, sizeof(lbrkdn)) == 0)
  218.     {
  219.     /* nothing has changed -- don't bother */
  220.     return;
  221.     }
  222.  
  223.     /* move to the right screen position for breakdown list */
  224.     if (!position)
  225.     {
  226.     Move_to(x_brkdn, y_brkdn);
  227.     }
  228.  
  229.     /* keep track of how many characters are written */
  230.     position = fileptr(stdout);
  231.  
  232.     /* write summary line */
  233.     for (i = 1; i < 7; i++)
  234.     {
  235.     if (brkdn[i] != 0)
  236.     {
  237.         printf("%s%d %s%s",
  238.             i == 1 ? "" : ", ",
  239.             brkdn[i],
  240.             state_name[i],
  241.             (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
  242.     }
  243.     }
  244.  
  245.     /* calculate new length of line */
  246.     position = fileptr(stdout) - position;
  247.  
  248.     /* clear to end and remember new line length */
  249.     (void) clear_eol(llength - position);
  250.     llength = position;
  251.  
  252.     /* save new data for next time through */
  253.     bcopy((char *)brkdn, (char *)lbrkdn, sizeof(lbrkdn));
  254. }
  255.  
  256. i_cpustates(changes, total)
  257.  
  258. int *changes;
  259. int total;
  260.  
  261. {
  262.     register int i;
  263.     register double percent;
  264.  
  265.     printf("\nCpu states: ");
  266.     for (i = 0; i < CPUSTATES; i++)
  267.     {
  268.     percent = ((double)changes[i] / (double)total) * 100.0;
  269.     /* if (100.0 - percent <= 0.05) then it will print as 100% */
  270.     /* so we select the format accordingly */
  271.     printf((100.0 - percent <= 0.05) ? "%s%4.0f%% %s" : "%s%4.1f%% %s",
  272.         i == 0 ? "" : ", ",
  273.         percent,
  274.         cpu_state[i]);
  275.     }
  276.     printf("\n");
  277. }
  278.  
  279. u_cpustates(changes, total)
  280.  
  281. int *changes;
  282. int total;
  283.  
  284. {
  285.     register int i;
  286.     register double percent;
  287.  
  288.     for (i = 0; i < CPUSTATES; i++)
  289.     {
  290.     Move_to(x_cpustates[i], y_cpustates);
  291.     percent = ((double)changes[i] / (double)total) * 100.0;
  292.     /* if (100.0 - percent <= 0.05) then it will print as 100% */
  293.     /* so we select the format accordingly */
  294.     printf((100.0 - percent <= 0.05) ? "%4.0f" : "%4.1f", percent);
  295.     }
  296. }
  297.  
  298. z_cpustates()
  299.  
  300. {
  301.     register int i;
  302.  
  303.     printf("\nCpu states: ");
  304.     for (i = 0; i < CPUSTATES; i++)
  305.     {
  306.     printf("%s    %% %s", i == 0 ? "" : ", ", cpu_state[i]);
  307.     }
  308.     printf("\n");
  309. }
  310.  
  311. static int lmem1, lmem2, lmem3, lmem4, lmem5;
  312.  
  313. i_memory(mem1, mem2, mem3, mem4, mem5)
  314.  
  315. int mem1, mem2, mem3, mem4, mem5;
  316.  
  317. {
  318.     register char *p;
  319.  
  320.     /* mem2 and mem4 will be in parentheses and need special handling */
  321.     p = itoa(mem2);
  322.     *--p = '(';
  323.  
  324.     /* print first half of the line */
  325.     printf("Memory: %5dK %6sK) real, ", mem1, p);
  326.  
  327. #ifndef sunos4
  328.     /* format mem4 for parentheses */
  329.     p = itoa(mem4);
  330.     *--p = '(';
  331.  
  332.     /* print second half of line */
  333.     printf("%5dK %6sK) virtual, %5dK free", mem3, p, mem5);
  334. #else
  335.     printf("%5dK free", mem5);
  336. #endif
  337.  
  338.     /* save "last" values */
  339.     lmem1 = mem1;
  340.     lmem2 = mem2;
  341.     lmem3 = mem3;
  342.     lmem4 = mem4;
  343.     lmem5 = mem5;
  344. }
  345.  
  346. u_memory(mem1, mem2, mem3, mem4, mem5)
  347.  
  348. int mem1, mem2, mem3, mem4, mem5;
  349.  
  350. {
  351.     register int newp;
  352.     register char *p;
  353.     register char cursor_on_line = No;
  354.  
  355.     /* preformat string if mem2 is different */
  356.     if ((newp = lmem2 != mem2))
  357.     {
  358.     p = itoa(mem2);
  359.     *--p = '(';
  360.     lmem2 = mem2;
  361.     }
  362.  
  363.     /* handle mem1 and mem2 */
  364.     if (lmem1 != mem1)
  365.     {
  366.     Move_to(x_realmem, y_mem);
  367.     cursor_on_line = Yes;
  368.     printf("%5d", mem1);
  369.     lmem1 = mem1;
  370.     if (newp)
  371.     {
  372.         printf("K %6s", p);
  373.     }
  374.     }
  375.     else if (newp)
  376.     {
  377.     Move_to(x_realmem + 7, y_mem);
  378.     cursor_on_line = Yes;
  379.     printf("%6s", p);
  380.     }
  381.  
  382. #ifndef sunos4
  383.     /* preformat mem4 if different */
  384.     if ((newp = lmem4 != mem4))
  385.     {
  386.     p = itoa(mem4);
  387.     *--p = '(';
  388.     lmem4 = mem4;
  389.     }
  390.  
  391.     /* handle mem3 and mem4 */
  392.     if (lmem3 != mem3)
  393.     {
  394.     Move_to(x_virtmem, y_mem);
  395.     cursor_on_line = Yes;
  396.     printf("%5d", mem3);
  397.     lmem3 = mem3;
  398.     if (newp)
  399.     {
  400.         printf("K %6s", p);
  401.     }
  402.     }
  403.     else if (newp)
  404.     {
  405.     Move_to(x_virtmem + 7, y_mem);
  406.     cursor_on_line = Yes;
  407.     printf("%6s", p);
  408.     }
  409. #endif
  410.  
  411.     /* handle mem5 */
  412.     if (lmem5 != mem5)
  413.     {
  414.     Move_to(x_free, y_mem);
  415.     cursor_on_line = Yes;
  416.     printf("%5d", mem5);
  417.     lmem5 = mem5;
  418.     }
  419.  
  420.     /* make sure the cursor is on this line in an optimal way */
  421.     if (!cursor_on_line)
  422.     {
  423.     putchar('\n');
  424.     }
  425. }
  426.  
  427. /*
  428.  *  i_message is funny because it gets its message asynchrnously (with
  429.  *    respect to screen updates).
  430.  */
  431.  
  432. static char next_msg[85];
  433. static int msglen = 0;
  434.  
  435. i_message()
  436.  
  437. {
  438.     putchar('\n');
  439.     if (next_msg[0] != '\0')
  440.     {
  441.     standout(next_msg);
  442.     next_msg[0] = '\0';
  443.     }
  444.     else if (msglen > 0)
  445.     {
  446.     (void) clear_eol(msglen);
  447.     msglen = 0;
  448.     }
  449. }
  450.  
  451. u_message()
  452.  
  453. {
  454.     putchar('\n');
  455.     if (msglen > 0)
  456.     {
  457.     (void) clear_eol(msglen);
  458.     msglen = 0;
  459.     }
  460. }
  461.  
  462. static char header_text[] =
  463.   "\n  PID XXXXXXXX PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  464. /*  01234567  -- starts at header_text+7 */
  465. #define header_length    (sizeof(header_text) - 2)
  466.  
  467. i_header(part2)
  468.  
  469. char *part2;
  470.  
  471. {
  472.     /* copy parameter into appropriate place in the header */
  473.     (void) strncpy(header_text+7, part2, 8);
  474.     fputs(header_text, stdout);
  475. }
  476.  
  477. /*ARGSUSED*/
  478. u_header(part2)
  479.  
  480. char *part2;        /* ignored */
  481.  
  482. {
  483.     Move_to(0, y_header);
  484. }
  485.  
  486. #ifdef sun
  487. #define percent_cpu(pp) ((double)(pp)->p_pctcpu / FSCALE)
  488. #else
  489. #define percent_cpu(pp) ((pp)->p_pctcpu)
  490. #endif
  491.  
  492. #define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  493.              ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  494.  
  495. #ifdef DEBUG
  496. FILE *debug;
  497. #endif
  498.  
  499. static void
  500. fmt_proc(thisline, pp, get_userid)
  501.  
  502. char        *thisline;
  503. struct proc *pp;
  504. char        *(*get_userid)();
  505.  
  506. {
  507.     register long cputime;
  508.     register double pctcpu;
  509.  
  510.     /* get the cpu usage and calculate the cpu percentages */
  511.     cputime = get_ucpu(pp);
  512.     pctcpu = percent_cpu(pp);
  513.  
  514.     /* format for the line */
  515. #define Proc_format \
  516.     "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  517.  
  518. /* memory usage is calculated differently for different architectures, */
  519. /* we define Size and Resident appropriately: */
  520. #ifdef pyr
  521. #define Size      pp->p_tsize + pp->p_dsize + pp->p_cssize + pp->p_ussize
  522. #define Resident  pp->p_rssize
  523.  
  524. #else
  525. #ifdef scs
  526.     get_spt(pp->p_spti, &pspt);    /* scs also needs this */
  527. #define Size      pspt.spt_usedpages
  528. #define Resident  pspt.spt_mempages
  529.  
  530. #else (everything else)
  531. #define Size      pp->p_tsize + pp->p_dsize + pp->p_ssize
  532. #define Resident  pp->p_rssize
  533. #endif !scs
  534.  
  535. #endif !pyr
  536.  
  537.     sprintf(thisline, Proc_format,
  538.         pp->p_pid,
  539.         (*get_userid)(pp->p_uid),
  540.         pp->p_pri - PZERO,
  541.         pp->p_nice - NZERO,
  542.         pagetok(Size),
  543.         pagetok(Resident),
  544.         state_abbrev[pp->p_stat],
  545.         cputime / 60l,
  546.         cputime % 60l,
  547.         100.0 * weighted_cpu(pctcpu, pp),
  548.         100.0 * pctcpu,
  549.         printable(u.u_comm));
  550. }
  551.  
  552. i_process(line, pp, get_userid)
  553.  
  554. int line;
  555. struct proc *pp;
  556. char *(*get_userid)();
  557.  
  558. {
  559.     register char *thisline;
  560.     int len;
  561.  
  562. #ifdef DEBUG
  563.     debug = fopen("debug", "w");
  564. #endif
  565.  
  566.     /* calculate a pointer to the buffer for this line */
  567.     thisline = screenbuf[line];
  568.  
  569.     /* format the line into our buffer */
  570.     fmt_proc(thisline, pp, get_userid);
  571.  
  572.     /* write the line out */
  573.     putchar('\n');
  574.     fputs(thisline, stdout);
  575.  
  576.     /* zero fill the rest of it */
  577.     len = strlen(thisline);
  578.     bzero(thisline + len, Display_width - len);
  579. }
  580.  
  581. static int lastline = 0;
  582.  
  583. u_process(line, pp, get_userid)
  584.  
  585. int line;
  586. struct proc *pp;
  587. char *(*get_userid)();
  588.  
  589. {
  590.     register char *optr;
  591.     register char *nptr;
  592.     register int ch;
  593.     register int diff;
  594.     register int newcol = 1;
  595.     register int lastcol = 0;
  596.     char cursor_on_line = No;
  597.     char *thisline;
  598.     int screen_line = line + Header_lines;
  599.     static char newline[Display_width];
  600.  
  601.     /* get a pointer to the old text for this line */
  602.     optr = thisline = screenbuf[line];
  603.  
  604.     /* format the line into a temporary buffer */
  605.     fmt_proc(newline, pp, get_userid);
  606.  
  607.     /* compare the two strings and only rewrite what has changed */
  608.     nptr = newline;
  609. #ifdef DEBUG
  610.     fputs(optr, debug);
  611.     fputc('\n', debug);
  612.     fputs(nptr, debug);
  613.     fputs("\n-\n", debug);
  614. #endif
  615.  
  616.     /* start things off on the right foot            */
  617.     /* this is to make sure the invariants get set up right */
  618.     if ((ch = *nptr++) != *optr)
  619.     {
  620.     if (screen_line - lastline == 1)
  621.     {
  622.         putchar('\n');
  623.     }
  624.     else
  625.     {
  626.         Move_to(0, screen_line);
  627.     }
  628.     cursor_on_line = Yes;
  629.     putchar(ch);
  630.     *optr = ch;
  631.     lastcol = 1;
  632.     }
  633.     optr++;
  634.  
  635.     /*
  636.      *  main loop -- check each character.  If the old and new aren't the
  637.      *    same, then update the display.  When the distance from the current
  638.      *    cursor position to the new change is small enough, the characters
  639.      *    that belong there are written to move the cursor over.
  640.      *
  641.      *    Invariants:
  642.      *        lastcol is the column where the cursor currently is sitting
  643.      *        (always one beyond the end of the last mismatch).
  644.      */
  645.     do        /* yes, a do...while */
  646.     {
  647.     if ((ch = *nptr++) != *optr)
  648.     {
  649.         /* new character is different from old      */
  650.         /* make sure the cursor is on top of this character */
  651.         diff = newcol - lastcol;
  652.         if (diff > 0)
  653.         {
  654.         /* some motion is required--figure out which is shorter */
  655.         if (diff < 6 && cursor_on_line)
  656.         {
  657.             /* overwrite old stuff--get it out of the screen buffer */
  658.             printf("%.*s", diff, &thisline[lastcol]);
  659.         }
  660.         else
  661.         {
  662.             /* use cursor addressing */
  663.             Move_to(newcol, screen_line);
  664.             cursor_on_line = Yes;
  665.         }
  666.         /* remember where the cursor is */
  667.         lastcol = newcol + 1;
  668.         }
  669.         else
  670.         {
  671.         /* already there, update position */
  672.         lastcol++;
  673.         }
  674.  
  675.         /* write what we need to */
  676.         if (ch == '\0')
  677.         {
  678.         /* at the end--terminate with a clear-to-end-of-line */
  679.         (void) clear_eol(strlen(optr));
  680.         }
  681.         else
  682.         {
  683.         /* write the new character */
  684.         putchar(ch);
  685.         }
  686.         /* put the new character in the screen buffer */
  687.         *optr = ch;
  688.     }
  689.  
  690.     /* update working column and screen buffer pointer */
  691.     newcol++;
  692.     optr++;
  693.  
  694.     } while (ch != '\0');
  695.  
  696.     /* zero out the rest of the line buffer -- MUST BE DONE! */
  697.     bzero(optr, Display_width - newcol);
  698.  
  699.     /* remember where the current line is */
  700.     if (cursor_on_line)
  701.     {
  702.     lastline = screen_line;
  703.     }
  704. }
  705.  
  706. static int last_hi = 0;
  707.  
  708. u_endscreen(hi)
  709.  
  710. register int hi;
  711.  
  712. {
  713.     register int screen_line = hi + Header_lines;
  714.     register int i;
  715.  
  716.     if (smart_terminal)
  717.     {
  718.     if (hi < last_hi)
  719.     {
  720.         if (clear_to_end)
  721.         {
  722.         /* we can do this the easy way */
  723.         if (hi == 0)
  724.         {
  725.             /* extra positioning required */
  726.             putchar('\n');
  727.         }
  728.         else if (screen_line - lastline == 1)
  729.         {
  730.             putchar('\n');
  731.         }
  732.         else
  733.         {
  734.             Move_to(0, screen_line);
  735.         }
  736.     
  737.         putcap(clear_to_end);
  738.         }
  739.         else
  740.         {
  741.         if (hi == 0)
  742.         {
  743.             putchar('\n');
  744.             (void) clear_eol(header_length);
  745.             putchar('\n');
  746.         }
  747.         else if (screen_line - lastline == 1)
  748.         {
  749.             putchar('\n');
  750.         }
  751.         else
  752.         {
  753.             Move_to(0, screen_line);
  754.         }
  755.     
  756.         i = hi;
  757.         while ((void) clear_eol(strlen(screenbuf[i++])), i < last_hi)
  758.         {
  759.             putchar('\n');
  760.         }
  761.         }
  762.     }
  763.     last_hi = hi;
  764.  
  765.     /* move the cursor to a pleasant place */
  766.     Move_to(x_idlecursor, y_idlecursor);
  767.     }
  768.     else
  769.     {
  770.     /* separate this display from the next with some vertical room */
  771.     fputs("\n\n", stdout);
  772.     }
  773. }
  774.  
  775. /*VARARGS2*/
  776. new_message(type, msgfmt, a1, a2, a3)
  777.  
  778. int type;
  779. char *msgfmt;
  780. int a1, a2, a3;
  781.  
  782. {
  783.     register int i;
  784.  
  785.     /* first, format the message */
  786.     (void) sprintf(next_msg, msgfmt, a1, a2, a3);
  787.  
  788.     if (msglen > 0)
  789.     {
  790.     /* message there already -- can we clear it? */
  791.     if (!overstrike)
  792.     {
  793.         /* yes -- write it and clear to end */
  794.         type ? standout(next_msg) : fputs(next_msg, stdout);
  795.         i = strlen(next_msg);
  796.         (void) clear_eol(msglen - i);
  797.         msglen = i;
  798.         next_msg[0] = '\0';
  799.     }
  800.     }
  801.     else
  802.     {
  803.     type ? standout(next_msg) : fputs(next_msg, stdout);
  804.     msglen = strlen(next_msg);
  805.     next_msg[0] = '\0';
  806.     }
  807. }
  808.  
  809. clear_message()
  810.  
  811. {
  812.     if (clear_eol(msglen) == 1)
  813.     {
  814.     putchar('\r');
  815.     }
  816. }
  817.  
  818. readline(buffer, size, numeric)
  819.  
  820. char *buffer;
  821. int  size;
  822. int  numeric;
  823.  
  824. {
  825.     register char *ptr = buffer;
  826.     register char ch;
  827.     register char cnt = 0;
  828.     register char maxcnt = 0;
  829.  
  830.     /* allow room for null terminator */
  831.     size -= 1;
  832.  
  833.     /* read loop */
  834.     while ((fflush(stdout), read(0, ptr, 1) > 0))
  835.     {
  836.     /* newline means we are done */
  837.     if ((ch = *ptr) == '\n')
  838.     {
  839.         break;
  840.     }
  841.  
  842.     /* handle special editing characters */
  843.     if (ch == ch_kill)
  844.     {
  845.         /* kill line -- account for overstriking */
  846.         if (overstrike)
  847.         {
  848.         msglen += maxcnt;
  849.         }
  850.  
  851.         /* return null string */
  852.         *buffer = '\0';
  853.         putchar('\r');
  854.         return(-1);
  855.     }
  856.     else if (ch == ch_erase)
  857.     {
  858.         /* erase previous character */
  859.         if (cnt <= 0)
  860.         {
  861.         /* none to erase! */
  862.         putchar('\7');
  863.         }
  864.         else
  865.         {
  866.         fputs("\b \b", stdout);
  867.         ptr--;
  868.         cnt--;
  869.         }
  870.     }
  871.     /* check for character validity and buffer overflow */
  872.     else if (cnt == size || (numeric && !isdigit(ch)) ||
  873.         !isprint(ch))
  874.     {
  875.         /* not legal */
  876.         putchar('\7');
  877.     }
  878.     else
  879.     {
  880.         /* echo it and store it in the buffer */
  881.         putchar(ch);
  882.         ptr++;
  883.         cnt++;
  884.         if (cnt > maxcnt)
  885.         {
  886.         maxcnt = cnt;
  887.         }
  888.     }
  889.     }
  890.  
  891.     /* all done -- null terminate the string */
  892.     *ptr = '\0';
  893.  
  894.     /* account for the extra characters in the message area */
  895.     /* (if terminal overstrikes, remember the furthest they went) */
  896.     msglen += overstrike ? maxcnt : cnt;
  897.  
  898.     /* return either inputted number or string length */
  899.     putchar('\r');
  900.     return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
  901. }
  902.  
  903. /*
  904.  *  get_ucpu(pp) - retrieve the user structure associated with the proc
  905.  *    structure pointed to by pp and return the cpu usage.  The user
  906.  *    structure is stored in the global structure "u" for later use.
  907.  *    Since the user structure isn't always set up well when we try to get
  908.  *    it, this routine also makes sure that the values it gets are
  909.  *    reasonably sane so that they don't overflow any sprintf's.
  910.  */
  911.  
  912. #define Max_cputime  (10000*60 - 1)  /* format for cputime is %4d:%02d */
  913.  
  914. get_ucpu(pp)
  915.  
  916. struct proc *pp;
  917.  
  918. {
  919.     register int retval;
  920.  
  921. #ifdef scs
  922.     (void) strcpy(u.u_comm, pp->p_infoname);
  923.     retval = pp->p_infotime.tv_sec;
  924. #else !scs
  925.     if (getu(pp, &u) == -1)
  926.     {
  927.     (void) strcpy(u.u_comm, "<swapped>");
  928.     retval = 0;
  929.     }
  930.     else
  931.     {
  932.     /* set u_comm for system processes */
  933.     if (u.u_comm[0] == '\0')
  934.     {
  935.         if (pp->p_pid == 0)
  936.         {
  937.         (void) strcpy(u.u_comm, "Swapper");
  938.         }
  939.         else if (pp->p_pid == 2)
  940.         {
  941.         (void) strcpy(u.u_comm, "Pager");
  942.         }
  943.     }
  944.  
  945. #ifdef FOUR_ONE
  946.     retval = (int)((float)(u.u_vm.vm_utime + u.u_vm.vm_stime)/hz);
  947. #else
  948.     retval = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  949. #endif
  950.  
  951.     }
  952.  
  953. #endif !scs
  954.  
  955.     /* make sure cputime returned is a reasonable value */
  956.     if (retval > Max_cputime)
  957.     {
  958.     retval = Max_cputime;
  959.     }
  960.  
  961.     return (retval);
  962. }
  963.  
  964. /*
  965.  *  printable(str) - make the string pointed to by "str" into one that is
  966.  *    printable (i.e.: all ascii), by converting all non-printable
  967.  *    characters into '?'.  Replacements are done in place and a pointer
  968.  *    to the original buffer is returned.
  969.  */
  970.  
  971. char *printable(str)
  972.  
  973. char *str;
  974.  
  975. {
  976.     register char *ptr;
  977.     register char ch;
  978.  
  979.     ptr = str;
  980.     while ((ch = *ptr) != '\0')
  981.     {
  982.     if (!isprint(ch))
  983.     {
  984.         *ptr = '?';
  985.     }
  986.     ptr++;
  987.     }
  988.     return(str);
  989. }
  990.