display.c revision 223342
1151497Sru/* 2151497Sru * Top users/processes display for Unix 3151497Sru * Version 3 4151497Sru * 5151497Sru * This program may be freely redistributed, 6151497Sru * but this entire comment MUST remain intact. 7151497Sru * 8151497Sru * Copyright (c) 1984, 1989, William LeFebvre, Rice University 9151497Sru * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 10151497Sru * 11151497Sru * $FreeBSD: head/contrib/top/display.c 223342 2011-06-20 16:48:00Z delphij $ 12151497Sru */ 13151497Sru 14151497Sru/* 15151497Sru * This file contains the routines that display information on the screen. 16151497Sru * Each section of the screen has two routines: one for initially writing 17151497Sru * all constant and dynamic text, and one for only updating the text that 18151497Sru * changes. The prefix "i_" is used on all the "initial" routines and the 19151497Sru * prefix "u_" is used for all the "updating" routines. 20151497Sru * 21151497Sru * ASSUMPTIONS: 22151497Sru * None of the "i_" routines use any of the termcap capabilities. 23151497Sru * In this way, those routines can be safely used on terminals that 24151497Sru * have minimal (or nonexistant) terminal capabilities. 25151497Sru * 26151497Sru * The routines are called in this order: *_loadave, i_timeofday, 27151497Sru * *_procstates, *_cpustates, *_memory, *_message, *_header, 28151497Sru * *_process, u_endscreen. 29151497Sru */ 30151497Sru 31151497Sru#include "os.h" 32151497Sru#include <ctype.h> 33151497Sru#include <time.h> 34151497Sru#include <sys/time.h> 35151497Sru 36151497Sru#include "screen.h" /* interface to screen package */ 37151497Sru#include "layout.h" /* defines for screen position layout */ 38151497Sru#include "display.h" 39151497Sru#include "top.h" 40151497Sru#include "top.local.h" 41151497Sru#include "boolean.h" 42151497Sru#include "machine.h" /* we should eliminate this!!! */ 43151497Sru#include "utils.h" 44151497Sru 45151497Sru#ifdef DEBUG 46151497SruFILE *debug; 47151497Sru#endif 48151497Sru 49151497Sru/* imported from screen.c */ 50151497Sruextern int overstrike; 51151497Sru 52151497Srustatic int lmpid = 0; 53151497Srustatic int last_hi = 0; /* used in u_process and u_endscreen */ 54151497Srustatic int lastline = 0; 55151497Srustatic int display_width = MAX_COLS; 56151497Sru 57151497Sru#define lineindex(l) ((l)*display_width) 58151497Sru 59151497Sruchar *printable(); 60151497Sru 61151497Sru/* things initialized by display_init and used thruout */ 62151497Sru 63151497Sru/* buffer of proc information lines for display updating */ 64151497Sruchar *screenbuf = NULL; 65151497Sru 66151497Srustatic char **procstate_names; 67151497Srustatic char **cpustate_names; 68151497Srustatic char **memory_names; 69151497Srustatic char **swap_names; 70151497Sru 71151497Srustatic int num_procstates; 72151497Srustatic int num_cpustates; 73151497Srustatic int num_memory; 74151497Srustatic int num_swap; 75151497Sru 76151497Srustatic int *lprocstates; 77151497Srustatic int *lcpustates; 78151497Srustatic int *lmemory; 79151497Srustatic int *lswap; 80151497Sru 81151497Srustatic int num_cpus; 82151497Srustatic int *cpustate_columns; 83151497Srustatic int cpustate_total_length; 84151497Srustatic int cpustates_column; 85151497Sru 86151497Srustatic enum { OFF, ON, ERASE } header_status = ON; 87151497Sru 88151497Srustatic int string_count(); 89151497Srustatic void summary_format(); 90151497Srustatic void line_update(); 91151497Sru 92151497Sruint x_lastpid = 10; 93151497Sruint y_lastpid = 0; 94151497Sruint x_loadave = 33; 95151497Sruint x_loadave_nompid = 15; 96151497Sruint y_loadave = 0; 97151497Sruint x_procstate = 0; 98151497Sruint y_procstate = 1; 99151497Sruint x_brkdn = 15; 100151497Sruint y_brkdn = 1; 101151497Sruint x_mem = 5; 102151497Sruint y_mem = 3; 103151497Sruint x_swap = 6; 104151497Sruint y_swap = 4; 105151497Sruint y_message = 5; 106151497Sruint x_header = 0; 107151497Sruint y_header = 6; 108151497Sruint x_idlecursor = 0; 109151497Sruint y_idlecursor = 5; 110151497Sruint y_procs = 7; 111151497Sru 112151497Sruint y_cpustates = 2; 113151497Sruint Header_lines = 7; 114151497Sru 115151497Sruint display_resize() 116151497Sru 117151497Sru{ 118151497Sru register int lines; 119151497Sru 120151497Sru /* first, deallocate any previous buffer that may have been there */ 121151497Sru if (screenbuf != NULL) 122151497Sru { 123151497Sru free(screenbuf); 124151497Sru } 125151497Sru 126151497Sru /* calculate the current dimensions */ 127151497Sru /* if operating in "dumb" mode, we only need one line */ 128151497Sru lines = smart_terminal ? screen_length - Header_lines : 1; 129151497Sru 130151497Sru if (lines < 0) 131151497Sru lines = 0; 132151497Sru /* we don't want more than MAX_COLS columns, since the machine-dependent 133151497Sru modules make static allocations based on MAX_COLS and we don't want 134151497Sru to run off the end of their buffers */ 135151497Sru display_width = screen_width; 136151497Sru if (display_width >= MAX_COLS) 137151497Sru { 138151497Sru display_width = MAX_COLS - 1; 139151497Sru } 140151497Sru 141151497Sru /* now, allocate space for the screen buffer */ 142151497Sru screenbuf = (char *)malloc(lines * display_width); 143151497Sru if (screenbuf == (char *)NULL) 144151497Sru { 145151497Sru /* oops! */ 146151497Sru return(-1); 147151497Sru } 148151497Sru 149151497Sru /* return number of lines available */ 150151497Sru /* for dumb terminals, pretend like we can show any amount */ 151151497Sru return(smart_terminal ? lines : Largest); 152151497Sru} 153151497Sru 154151497Sruint display_init(statics) 155151497Sru 156151497Srustruct statics *statics; 157151497Sru 158151497Sru{ 159151497Sru register int lines; 160151497Sru register char **pp; 161151497Sru register int *ip; 162151497Sru register int i; 163151497Sru 164151497Sru /* call resize to do the dirty work */ 165151497Sru lines = display_resize(); 166151497Sru num_cpus = statics->ncpus; 167151497Sru cpustates_column = 5; /* CPU: */ 168151497Sru if (num_cpus != 1) 169151497Sru cpustates_column += 2; /* CPU 0: */ 170151497Sru for (i = num_cpus; i > 9; i /= 10) 171151497Sru cpustates_column++; 172151497Sru 173151497Sru /* only do the rest if we need to */ 174151497Sru if (lines > -1) 175151497Sru { 176151497Sru /* save pointers and allocate space for names */ 177151497Sru procstate_names = statics->procstate_names; 178151497Sru num_procstates = string_count(procstate_names); 179151497Sru lprocstates = (int *)malloc(num_procstates * sizeof(int)); 180151497Sru 181151497Sru cpustate_names = statics->cpustate_names; 182151497Sru 183151497Sru swap_names = statics->swap_names; 184151497Sru num_swap = string_count(swap_names); 185151497Sru lswap = (int *)malloc(num_swap * sizeof(int)); 186151497Sru num_cpustates = string_count(cpustate_names); 187151497Sru lcpustates = (int *)malloc(num_cpustates * sizeof(int) * num_cpus); 188151497Sru cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); 189151497Sru 190151497Sru memory_names = statics->memory_names; 191151497Sru num_memory = string_count(memory_names); 192151497Sru lmemory = (int *)malloc(num_memory * sizeof(int)); 193151497Sru 194151497Sru /* calculate starting columns where needed */ 195151497Sru cpustate_total_length = 0; 196151497Sru pp = cpustate_names; 197151497Sru ip = cpustate_columns; 198151497Sru while (*pp != NULL) 199151497Sru { 200151497Sru *ip++ = cpustate_total_length; 201151497Sru if ((i = strlen(*pp++)) > 0) 202151497Sru { 203151497Sru cpustate_total_length += i + 8; 204151497Sru } 205151497Sru } 206151497Sru } 207151497Sru 208151497Sru /* return number of lines available */ 209151497Sru return(lines); 210151497Sru} 211151497Sru 212151497Srui_loadave(mpid, avenrun) 213151497Sru 214151497Sruint mpid; 215151497Srudouble *avenrun; 216151497Sru 217151497Sru{ 218151497Sru register int i; 219151497Sru 220151497Sru /* i_loadave also clears the screen, since it is first */ 221151497Sru clear(); 222151497Sru 223151497Sru /* mpid == -1 implies this system doesn't have an _mpid */ 224151497Sru if (mpid != -1) 225151497Sru { 226151497Sru printf("last pid: %5d; ", mpid); 227151497Sru } 228151497Sru 229151497Sru printf("load averages"); 230151497Sru 231151497Sru for (i = 0; i < 3; i++) 232151497Sru { 233151497Sru printf("%c %5.2f", 234151497Sru i == 0 ? ':' : ',', 235151497Sru avenrun[i]); 236151497Sru } 237151497Sru lmpid = mpid; 238151497Sru} 239151497Sru 240151497Sruu_loadave(mpid, avenrun) 241151497Sru 242151497Sruint mpid; 243151497Srudouble *avenrun; 244151497Sru 245151497Sru{ 246151497Sru register int i; 247151497Sru 248151497Sru if (mpid != -1) 249151497Sru { 250151497Sru /* change screen only when value has really changed */ 251151497Sru if (mpid != lmpid) 252151497Sru { 253151497Sru Move_to(x_lastpid, y_lastpid); 254151497Sru printf("%5d", mpid); 255151497Sru lmpid = mpid; 256151497Sru } 257151497Sru 258151497Sru /* i remembers x coordinate to move to */ 259151497Sru i = x_loadave; 260151497Sru } 261151497Sru else 262151497Sru { 263151497Sru i = x_loadave_nompid; 264151497Sru } 265151497Sru 266151497Sru /* move into position for load averages */ 267151497Sru Move_to(i, y_loadave); 268151497Sru 269151497Sru /* display new load averages */ 270151497Sru /* we should optimize this and only display changes */ 271151497Sru for (i = 0; i < 3; i++) 272151497Sru { 273151497Sru printf("%s%5.2f", 274151497Sru i == 0 ? "" : ", ", 275151497Sru avenrun[i]); 276151497Sru } 277151497Sru} 278151497Sru 279151497Srui_timeofday(tod) 280151497Sru 281151497Srutime_t *tod; 282151497Sru 283151497Sru{ 284151497Sru /* 285151497Sru * Display the current time. 286151497Sru * "ctime" always returns a string that looks like this: 287151497Sru * 288151497Sru * Sun Sep 16 01:03:52 1973 289151497Sru * 012345678901234567890123 290151497Sru * 1 2 291151497Sru * 292151497Sru * We want indices 11 thru 18 (length 8). 293151497Sru */ 294151497Sru 295151497Sru if (smart_terminal) 296151497Sru { 297151497Sru Move_to(screen_width - 8, 0); 298151497Sru } 299151497Sru else 300151497Sru { 301151497Sru fputs(" ", stdout); 302151497Sru } 303151497Sru#ifdef DEBUG 304151497Sru { 305151497Sru char *foo; 306151497Sru foo = ctime(tod); 307151497Sru fputs(foo, stdout); 308151497Sru } 309151497Sru#endif 310151497Sru printf("%-8.8s\n", &(ctime(tod)[11])); 311151497Sru lastline = 1; 312151497Sru} 313151497Sru 314151497Srustatic int ltotal = 0; 315151497Srustatic char procstates_buffer[MAX_COLS]; 316151497Sru 317151497Sru/* 318151497Sru * *_procstates(total, brkdn, names) - print the process summary line 319151497Sru * 320151497Sru * Assumptions: cursor is at the beginning of the line on entry 321151497Sru * lastline is valid 322151497Sru */ 323151497Sru 324151497Srui_procstates(total, brkdn) 325151497Sru 326151497Sruint total; 327151497Sruint *brkdn; 328151497Sru 329151497Sru{ 330151497Sru register int i; 331151497Sru 332151497Sru /* write current number of processes and remember the value */ 333151497Sru printf("%d processes:", total); 334151497Sru ltotal = total; 335151497Sru 336151497Sru /* put out enough spaces to get to column 15 */ 337151497Sru i = digits(total); 338151497Sru while (i++ < 4) 339151497Sru { 340151497Sru putchar(' '); 341151497Sru } 342151497Sru 343151497Sru /* format and print the process state summary */ 344151497Sru summary_format(procstates_buffer, brkdn, procstate_names); 345151497Sru fputs(procstates_buffer, stdout); 346151497Sru 347151497Sru /* save the numbers for next time */ 348151497Sru memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 349151497Sru} 350151497Sru 351151497Sruu_procstates(total, brkdn) 352151497Sru 353151497Sruint total; 354151497Sruint *brkdn; 355151497Sru 356151497Sru{ 357151497Sru static char new[MAX_COLS]; 358151497Sru register int i; 359151497Sru 360151497Sru /* update number of processes only if it has changed */ 361151497Sru if (ltotal != total) 362151497Sru { 363151497Sru /* move and overwrite */ 364151497Sru#if (x_procstate == 0) 365151497Sru Move_to(x_procstate, y_procstate); 366151497Sru#else 367151497Sru /* cursor is already there...no motion needed */ 368151497Sru /* assert(lastline == 1); */ 369151497Sru#endif 370151497Sru printf("%d", total); 371151497Sru 372151497Sru /* if number of digits differs, rewrite the label */ 373151497Sru if (digits(total) != digits(ltotal)) 374151497Sru { 375151497Sru fputs(" processes:", stdout); 376151497Sru /* put out enough spaces to get to column 15 */ 377151497Sru i = digits(total); 378151497Sru while (i++ < 4) 379151497Sru { 380151497Sru putchar(' '); 381151497Sru } 382151497Sru /* cursor may end up right where we want it!!! */ 383151497Sru } 384151497Sru 385151497Sru /* save new total */ 386151497Sru ltotal = total; 387151497Sru } 388151497Sru 389151497Sru /* see if any of the state numbers has changed */ 390151497Sru if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) 391151497Sru { 392151497Sru /* format and update the line */ 393151497Sru summary_format(new, brkdn, procstate_names); 394151497Sru line_update(procstates_buffer, new, x_brkdn, y_brkdn); 395151497Sru memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 396151497Sru } 397151497Sru} 398151497Sru 399151497Sru#ifdef no_more 400151497Sru/* 401151497Sru * *_cpustates(states, names) - print the cpu state percentages 402151497Sru * 403151497Sru * Assumptions: cursor is on the PREVIOUS line 404151497Sru */ 405151497Sru 406151497Sru/* cpustates_tag() calculates the correct tag to use to label the line */ 407151497Sru 408151497Sruchar *cpustates_tag() 409151497Sru 410151497Sru{ 411151497Sru register char *use; 412151497Sru 413151497Sru static char *short_tag = "CPU: "; 414151497Sru static char *long_tag = "CPU states: "; 415151497Sru 416151497Sru /* if length + strlen(long_tag) >= screen_width, then we have to 417151497Sru use the shorter tag (we subtract 2 to account for ": ") */ 418151497Sru if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) 419151497Sru { 420151497Sru use = short_tag; 421151497Sru } 422151497Sru else 423151497Sru { 424151497Sru use = long_tag; 425151497Sru } 426151497Sru 427151497Sru /* set cpustates_column accordingly then return result */ 428151497Sru cpustates_column = strlen(use); 429151497Sru return(use); 430151497Sru} 431151497Sru#endif 432151497Sru 433151497Srui_cpustates(states) 434151497Sru 435151497Sruregister int *states; 436151497Sru 437151497Sru{ 438151497Sru register int i = 0; 439151497Sru register int value; 440151497Sru register char **names; 441151497Sru register char *thisname; 442151497Sru int cpu; 443151497Sru 444151497Srufor (cpu = 0; cpu < num_cpus; cpu++) { 445151497Sru names = cpustate_names; 446151497Sru 447151497Sru /* print tag and bump lastline */ 448151497Sru if (num_cpus == 1) 449151497Sru printf("\nCPU: "); 450151497Sru else { 451151497Sru value = printf("\nCPU %d: ", cpu); 452151497Sru while (value++ <= cpustates_column) 453151497Sru printf(" "); 454151497Sru } 455151497Sru lastline++; 456151497Sru 457151497Sru /* now walk thru the names and print the line */ 458151497Sru while ((thisname = *names++) != NULL) 459151497Sru { 460151497Sru if (*thisname != '\0') 461151497Sru { 462151497Sru /* retrieve the value and remember it */ 463151497Sru value = *states++; 464151497Sru 465151497Sru /* if percentage is >= 1000, print it as 100% */ 466151497Sru printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), 467151497Sru (i++ % num_cpustates) == 0 ? "" : ", ", 468151497Sru ((float)value)/10., 469151497Sru thisname); 470151497Sru } 471151497Sru } 472151497Sru} 473151497Sru 474151497Sru /* copy over values into "last" array */ 475151497Sru memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); 476151497Sru} 477151497Sru 478151497Sruu_cpustates(states) 479151497Sru 480151497Sruregister int *states; 481151497Sru 482151497Sru{ 483151497Sru register int value; 484151497Sru register char **names; 485151497Sru register char *thisname; 486151497Sru register int *lp; 487151497Sru register int *colp; 488151497Sru int cpu; 489151497Sru 490151497Srufor (cpu = 0; cpu < num_cpus; cpu++) { 491151497Sru names = cpustate_names; 492151497Sru 493151497Sru Move_to(cpustates_column, y_cpustates + cpu); 494151497Sru lastline = y_cpustates + cpu; 495151497Sru lp = lcpustates + (cpu * num_cpustates); 496151497Sru colp = cpustate_columns; 497151497Sru 498151497Sru /* we could be much more optimal about this */ 499151497Sru while ((thisname = *names++) != NULL) 500151497Sru { 501151497Sru if (*thisname != '\0') 502151497Sru { 503151497Sru /* did the value change since last time? */ 504151497Sru if (*lp != *states) 505151497Sru { 506151497Sru /* yes, move and change */ 507151497Sru Move_to(cpustates_column + *colp, y_cpustates + cpu); 508151497Sru lastline = y_cpustates + cpu; 509151497Sru 510151497Sru /* retrieve value and remember it */ 511151497Sru value = *states; 512151497Sru 513151497Sru /* if percentage is >= 1000, print it as 100% */ 514151497Sru printf((value >= 1000 ? "%4.0f" : "%4.1f"), 515151497Sru ((double)value)/10.); 516151497Sru 517151497Sru /* remember it for next time */ 518151497Sru *lp = value; 519151497Sru } 520151497Sru } 521151497Sru 522151497Sru /* increment and move on */ 523151497Sru lp++; 524151497Sru states++; 525151497Sru colp++; 526151497Sru } 527151497Sru} 528151497Sru} 529151497Sru 530151497Sruz_cpustates() 531151497Sru 532151497Sru{ 533151497Sru register int i = 0; 534151497Sru register char **names; 535151497Sru register char *thisname; 536151497Sru register int *lp; 537151497Sru int cpu, value; 538151497Sru 539151497Srufor (cpu = 0; cpu < num_cpus; cpu++) { 540151497Sru names = cpustate_names; 541151497Sru 542151497Sru /* show tag and bump lastline */ 543151497Sru if (num_cpus == 1) 544151497Sru printf("\nCPU: "); 545151497Sru else { 546151497Sru value = printf("\nCPU %d: ", cpu); 547151497Sru while (value++ <= cpustates_column) 548151497Sru printf(" "); 549151497Sru } 550151497Sru lastline++; 551151497Sru 552151497Sru while ((thisname = *names++) != NULL) 553151497Sru { 554151497Sru if (*thisname != '\0') 555151497Sru { 556151497Sru printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); 557151497Sru } 558151497Sru } 559151497Sru} 560151497Sru 561151497Sru /* fill the "last" array with all -1s, to insure correct updating */ 562151497Sru lp = lcpustates; 563151497Sru i = num_cpustates * num_cpus; 564151497Sru while (--i >= 0) 565151497Sru { 566151497Sru *lp++ = -1; 567151497Sru } 568151497Sru} 569151497Sru 570151497Sru/* 571151497Sru * *_memory(stats) - print "Memory: " followed by the memory summary string 572151497Sru * 573151497Sru * Assumptions: cursor is on "lastline" 574151497Sru * for i_memory ONLY: cursor is on the previous line 575151497Sru */ 576151497Sru 577151497Sruchar memory_buffer[MAX_COLS]; 578151497Sru 579151497Srui_memory(stats) 580151497Sru 581151497Sruint *stats; 582151497Sru 583151497Sru{ 584151497Sru fputs("\nMem: ", stdout); 585151497Sru lastline++; 586151497Sru 587151497Sru /* format and print the memory summary */ 588151497Sru summary_format(memory_buffer, stats, memory_names); 589151497Sru fputs(memory_buffer, stdout); 590151497Sru} 591151497Sru 592151497Sruu_memory(stats) 593151497Sru 594151497Sruint *stats; 595151497Sru 596151497Sru{ 597151497Sru static char new[MAX_COLS]; 598151497Sru 599151497Sru /* format the new line */ 600151497Sru summary_format(new, stats, memory_names); 601151497Sru line_update(memory_buffer, new, x_mem, y_mem); 602151497Sru} 603151497Sru 604151497Sru/* 605151497Sru * *_swap(stats) - print "Swap: " followed by the swap summary string 606151497Sru * 607151497Sru * Assumptions: cursor is on "lastline" 608151497Sru * for i_swap ONLY: cursor is on the previous line 609151497Sru */ 610151497Sru 611151497Sruchar swap_buffer[MAX_COLS]; 612151497Sru 613151497Srui_swap(stats) 614151497Sru 615151497Sruint *stats; 616151497Sru 617151497Sru{ 618151497Sru fputs("\nSwap: ", stdout); 619151497Sru lastline++; 620151497Sru 621151497Sru /* format and print the swap summary */ 622151497Sru summary_format(swap_buffer, stats, swap_names); 623151497Sru fputs(swap_buffer, stdout); 624151497Sru} 625151497Sru 626151497Sruu_swap(stats) 627151497Sru 628151497Sruint *stats; 629151497Sru 630151497Sru{ 631151497Sru static char new[MAX_COLS]; 632151497Sru 633151497Sru /* format the new line */ 634151497Sru summary_format(new, stats, swap_names); 635151497Sru line_update(swap_buffer, new, x_swap, y_swap); 636151497Sru} 637151497Sru 638151497Sru/* 639151497Sru * *_message() - print the next pending message line, or erase the one 640151497Sru * that is there. 641151497Sru * 642151497Sru * Note that u_message is (currently) the same as i_message. 643151497Sru * 644151497Sru * Assumptions: lastline is consistent 645151497Sru */ 646151497Sru 647151497Sru/* 648151497Sru * i_message is funny because it gets its message asynchronously (with 649151497Sru * respect to screen updates). 650151497Sru */ 651151497Sru 652151497Srustatic char next_msg[MAX_COLS + 5]; 653151497Srustatic int msglen = 0; 654151497Sru/* Invariant: msglen is always the length of the message currently displayed 655151497Sru on the screen (even when next_msg doesn't contain that message). */ 656151497Sru 657151497Srui_message() 658151497Sru 659151497Sru{ 660151497Sru while (lastline < y_message) 661151497Sru { 662151497Sru fputc('\n', stdout); 663151497Sru lastline++; 664151497Sru } 665151497Sru if (next_msg[0] != '\0') 666151497Sru { 667151497Sru standout(next_msg); 668151497Sru msglen = strlen(next_msg); 669151497Sru next_msg[0] = '\0'; 670151497Sru } 671151497Sru else if (msglen > 0) 672151497Sru { 673151497Sru (void) clear_eol(msglen); 674151497Sru msglen = 0; 675151497Sru } 676151497Sru} 677151497Sru 678151497Sruu_message() 679151497Sru 680151497Sru{ 681151497Sru i_message(); 682151497Sru} 683151497Sru 684151497Srustatic int header_length; 685151497Sru 686151497Sru/* 687151497Sru * Trim a header string to the current display width and return a newly 688151497Sru * allocated area with the trimmed header. 689151497Sru */ 690151497Sru 691151497Sruchar * 692151497Srutrim_header(text) 693151497Sru 694151497Sruchar *text; 695151497Sru 696151497Sru{ 697151497Sru char *s; 698151497Sru int width; 699151497Sru 700151497Sru s = NULL; 701151497Sru width = display_width; 702151497Sru header_length = strlen(text); 703151497Sru if (header_length >= width) { 704151497Sru s = malloc((width + 1) * sizeof(char)); 705151497Sru if (s == NULL) 706151497Sru return (NULL); 707151497Sru strncpy(s, text, width); 708151497Sru s[width] = '\0'; 709151497Sru } 710151497Sru return (s); 711151497Sru} 712151497Sru 713151497Sru/* 714151497Sru * *_header(text) - print the header for the process area 715151497Sru * 716151497Sru * Assumptions: cursor is on the previous line and lastline is consistent 717151497Sru */ 718151497Sru 719151497Srui_header(text) 720151497Sru 721151497Sruchar *text; 722151497Sru 723151497Sru{ 724151497Sru char *s; 725151497Sru 726151497Sru s = trim_header(text); 727151497Sru if (s != NULL) 728151497Sru text = s; 729151497Sru 730151497Sru if (header_status == ON) 731151497Sru { 732151497Sru putchar('\n'); 733151497Sru fputs(text, stdout); 734151497Sru lastline++; 735151497Sru } 736151497Sru else if (header_status == ERASE) 737151497Sru { 738151497Sru header_status = OFF; 739151497Sru } 740151497Sru free(s); 741151497Sru} 742151497Sru 743151497Sru/*ARGSUSED*/ 744151497Sruu_header(text) 745151497Sru 746151497Sruchar *text; /* ignored */ 747151497Sru 748151497Sru{ 749151497Sru 750151497Sru if (header_status == ERASE) 751151497Sru { 752151497Sru putchar('\n'); 753151497Sru lastline++; 754151497Sru clear_eol(header_length); 755151497Sru header_status = OFF; 756151497Sru } 757151497Sru} 758151497Sru 759151497Sru/* 760151497Sru * *_process(line, thisline) - print one process line 761151497Sru * 762151497Sru * Assumptions: lastline is consistent 763151497Sru */ 764151497Sru 765151497Srui_process(line, thisline) 766151497Sru 767151497Sruint line; 768151497Sruchar *thisline; 769151497Sru 770151497Sru{ 771151497Sru register char *p; 772151497Sru register char *base; 773151497Sru 774151497Sru /* make sure we are on the correct line */ 775151497Sru while (lastline < y_procs + line) 776151497Sru { 777151497Sru putchar('\n'); 778151497Sru lastline++; 779151497Sru } 780151497Sru 781151497Sru /* truncate the line to conform to our current screen width */ 782151497Sru thisline[display_width] = '\0'; 783151497Sru 784151497Sru /* write the line out */ 785151497Sru fputs(thisline, stdout); 786151497Sru 787151497Sru /* copy it in to our buffer */ 788151497Sru base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; 789151497Sru p = strecpy(base, thisline); 790151497Sru 791151497Sru /* zero fill the rest of it */ 792151497Sru memzero(p, display_width - (p - base)); 793151497Sru} 794151497Sru 795151497Sruu_process(line, newline) 796151497Sru 797151497Sruint line; 798151497Sruchar *newline; 799151497Sru 800151497Sru{ 801151497Sru register char *optr; 802151497Sru register int screen_line = line + Header_lines; 803151497Sru register char *bufferline; 804151497Sru 805151497Sru /* remember a pointer to the current line in the screen buffer */ 806151497Sru bufferline = &screenbuf[lineindex(line)]; 807151497Sru 808151497Sru /* truncate the line to conform to our current screen width */ 809151497Sru newline[display_width] = '\0'; 810151497Sru 811151497Sru /* is line higher than we went on the last display? */ 812151497Sru if (line >= last_hi) 813151497Sru { 814151497Sru /* yes, just ignore screenbuf and write it out directly */ 815151497Sru /* get positioned on the correct line */ 816151497Sru if (screen_line - lastline == 1) 817151497Sru { 818151497Sru putchar('\n'); 819151497Sru lastline++; 820151497Sru } 821151497Sru else 822151497Sru { 823151497Sru Move_to(0, screen_line); 824151497Sru lastline = screen_line; 825151497Sru } 826151497Sru 827151497Sru /* now write the line */ 828151497Sru fputs(newline, stdout); 829151497Sru 830151497Sru /* copy it in to the buffer */ 831151497Sru optr = strecpy(bufferline, newline); 832151497Sru 833151497Sru /* zero fill the rest of it */ 834151497Sru memzero(optr, display_width - (optr - bufferline)); 835151497Sru } 836151497Sru else 837151497Sru { 838151497Sru line_update(bufferline, newline, 0, line + Header_lines); 839151497Sru } 840151497Sru} 841151497Sru 842151497Sruu_endscreen(hi) 843151497Sru 844151497Sruregister int hi; 845151497Sru 846151497Sru{ 847151497Sru register int screen_line = hi + Header_lines; 848151497Sru register int i; 849151497Sru 850151497Sru if (smart_terminal) 851151497Sru { 852151497Sru if (hi < last_hi) 853151497Sru { 854151497Sru /* need to blank the remainder of the screen */ 855151497Sru /* but only if there is any screen left below this line */ 856151497Sru if (lastline + 1 < screen_length) 857151497Sru { 858151497Sru /* efficiently move to the end of currently displayed info */ 859151497Sru if (screen_line - lastline < 5) 860151497Sru { 861151497Sru while (lastline < screen_line) 862151497Sru { 863151497Sru putchar('\n'); 864151497Sru lastline++; 865151497Sru } 866151497Sru } 867151497Sru else 868151497Sru { 869151497Sru Move_to(0, screen_line); 870151497Sru lastline = screen_line; 871151497Sru } 872151497Sru 873151497Sru if (clear_to_end) 874151497Sru { 875151497Sru /* we can do this the easy way */ 876151497Sru putcap(clear_to_end); 877151497Sru } 878151497Sru else 879151497Sru { 880151497Sru /* use clear_eol on each line */ 881151497Sru i = hi; 882151497Sru while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) 883151497Sru { 884151497Sru putchar('\n'); 885151497Sru } 886151497Sru } 887151497Sru } 888151497Sru } 889151497Sru last_hi = hi; 890151497Sru 891151497Sru /* move the cursor to a pleasant place */ 892151497Sru Move_to(x_idlecursor, y_idlecursor); 893151497Sru lastline = y_idlecursor; 894151497Sru } 895151497Sru else 896151497Sru { 897151497Sru /* separate this display from the next with some vertical room */ 898151497Sru fputs("\n\n", stdout); 899151497Sru } 900151497Sru} 901151497Sru 902151497Srudisplay_header(t) 903151497Sru 904151497Sruint t; 905151497Sru 906151497Sru{ 907151497Sru if (t) 908151497Sru { 909151497Sru header_status = ON; 910151497Sru } 911151497Sru else if (header_status == ON) 912151497Sru { 913151497Sru header_status = ERASE; 914151497Sru } 915151497Sru} 916151497Sru 917151497Sru/*VARARGS2*/ 918151497Srunew_message(type, msgfmt, a1, a2, a3) 919151497Sru 920151497Sruint type; 921151497Sruchar *msgfmt; 922151497Srucaddr_t a1, a2, a3; 923151497Sru 924151497Sru{ 925151497Sru register int i; 926151497Sru 927151497Sru /* first, format the message */ 928151497Sru (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); 929151497Sru 930151497Sru if (msglen > 0) 931151497Sru { 932151497Sru /* message there already -- can we clear it? */ 933151497Sru if (!overstrike) 934151497Sru { 935151497Sru /* yes -- write it and clear to end */ 936151497Sru i = strlen(next_msg); 937151497Sru if ((type & MT_delayed) == 0) 938151497Sru { 939151497Sru type & MT_standout ? standout(next_msg) : 940151497Sru fputs(next_msg, stdout); 941151497Sru (void) clear_eol(msglen - i); 942151497Sru msglen = i; 943151497Sru next_msg[0] = '\0'; 944151497Sru } 945151497Sru } 946151497Sru } 947151497Sru else 948151497Sru { 949151497Sru if ((type & MT_delayed) == 0) 950151497Sru { 951151497Sru type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout); 952151497Sru msglen = strlen(next_msg); 953151497Sru next_msg[0] = '\0'; 954151497Sru } 955151497Sru } 956151497Sru} 957151497Sru 958151497Sruclear_message() 959151497Sru 960151497Sru{ 961151497Sru if (clear_eol(msglen) == 1) 962151497Sru { 963151497Sru putchar('\r'); 964151497Sru } 965151497Sru} 966151497Sru 967151497Srureadline(buffer, size, numeric) 968151497Sru 969151497Sruchar *buffer; 970151497Sruint size; 971151497Sruint numeric; 972151497Sru 973151497Sru{ 974151497Sru register char *ptr = buffer; 975151497Sru register char ch; 976151497Sru register char cnt = 0; 977151497Sru register char maxcnt = 0; 978151497Sru 979151497Sru /* allow room for null terminator */ 980151497Sru size -= 1; 981151497Sru 982151497Sru /* read loop */ 983151497Sru while ((fflush(stdout), read(0, ptr, 1) > 0)) 984151497Sru { 985151497Sru /* newline means we are done */ 986151497Sru if ((ch = *ptr) == '\n' || ch == '\r') 987151497Sru { 988151497Sru break; 989151497Sru } 990151497Sru 991151497Sru /* handle special editing characters */ 992151497Sru if (ch == ch_kill) 993151497Sru { 994151497Sru /* kill line -- account for overstriking */ 995151497Sru if (overstrike) 996151497Sru { 997151497Sru msglen += maxcnt; 998151497Sru } 999151497Sru 1000151497Sru /* return null string */ 1001151497Sru *buffer = '\0'; 1002151497Sru putchar('\r'); 1003151497Sru return(-1); 1004151497Sru } 1005151497Sru else if (ch == ch_erase) 1006151497Sru { 1007151497Sru /* erase previous character */ 1008151497Sru if (cnt <= 0) 1009151497Sru { 1010151497Sru /* none to erase! */ 1011151497Sru putchar('\7'); 1012151497Sru } 1013151497Sru else 1014151497Sru { 1015151497Sru fputs("\b \b", stdout); 1016151497Sru ptr--; 1017151497Sru cnt--; 1018151497Sru } 1019151497Sru } 1020151497Sru /* check for character validity and buffer overflow */ 1021151497Sru else if (cnt == size || (numeric && !isdigit(ch)) || 1022151497Sru !isprint(ch)) 1023151497Sru { 1024151497Sru /* not legal */ 1025151497Sru putchar('\7'); 1026151497Sru } 1027151497Sru else 1028151497Sru { 1029151497Sru /* echo it and store it in the buffer */ 1030151497Sru putchar(ch); 1031151497Sru ptr++; 1032151497Sru cnt++; 1033151497Sru if (cnt > maxcnt) 1034151497Sru { 1035151497Sru maxcnt = cnt; 1036151497Sru } 1037151497Sru } 1038151497Sru } 1039151497Sru 1040151497Sru /* all done -- null terminate the string */ 1041151497Sru *ptr = '\0'; 1042151497Sru 1043151497Sru /* account for the extra characters in the message area */ 1044151497Sru /* (if terminal overstrikes, remember the furthest they went) */ 1045151497Sru msglen += overstrike ? maxcnt : cnt; 1046151497Sru 1047151497Sru /* return either inputted number or string length */ 1048151497Sru putchar('\r'); 1049151497Sru return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); 1050151497Sru} 1051151497Sru 1052151497Sru/* internal support routines */ 1053151497Sru 1054151497Srustatic int string_count(pp) 1055151497Sru 1056151497Sruregister char **pp; 1057151497Sru 1058151497Sru{ 1059151497Sru register int cnt; 1060151497Sru 1061151497Sru cnt = 0; 1062151497Sru while (*pp++ != NULL) 1063151497Sru { 1064151497Sru cnt++; 1065151497Sru } 1066151497Sru return(cnt); 1067151497Sru} 1068151497Sru 1069151497Srustatic void summary_format(str, numbers, names) 1070151497Sru 1071151497Sruchar *str; 1072151497Sruint *numbers; 1073151497Sruregister char **names; 1074151497Sru 1075151497Sru{ 1076151497Sru register char *p; 1077151497Sru register int num; 1078151497Sru register char *thisname; 1079151497Sru register int useM = No; 1080151497Sru 1081151497Sru /* format each number followed by its string */ 1082151497Sru p = str; 1083151497Sru while ((thisname = *names++) != NULL) 1084151497Sru { 1085151497Sru /* get the number to format */ 1086151497Sru num = *numbers++; 1087151497Sru 1088151497Sru /* display only non-zero numbers */ 1089151497Sru if (num > 0) 1090151497Sru { 1091151497Sru /* is this number in kilobytes? */ 1092151497Sru if (thisname[0] == 'K') 1093151497Sru { 1094151497Sru /* yes: format it as a memory value */ 1095151497Sru p = strecpy(p, format_k(num)); 1096151497Sru 1097151497Sru /* skip over the K, since it was included by format_k */ 1098151497Sru p = strecpy(p, thisname+1); 1099151497Sru } 1100151497Sru else 1101151497Sru { 1102151497Sru p = strecpy(p, itoa(num)); 1103151497Sru p = strecpy(p, thisname); 1104151497Sru } 1105151497Sru } 1106151497Sru 1107151497Sru /* ignore negative numbers, but display corresponding string */ 1108151497Sru else if (num < 0) 1109151497Sru { 1110151497Sru p = strecpy(p, thisname); 1111151497Sru } 1112151497Sru } 1113151497Sru 1114151497Sru /* if the last two characters in the string are ", ", delete them */ 1115151497Sru p -= 2; 1116151497Sru if (p >= str && p[0] == ',' && p[1] == ' ') 1117151497Sru { 1118151497Sru *p = '\0'; 1119151497Sru } 1120151497Sru} 1121151497Sru 1122151497Srustatic void line_update(old, new, start, line) 1123151497Sru 1124151497Sruregister char *old; 1125151497Sruregister char *new; 1126151497Sruint start; 1127151497Sruint line; 1128151497Sru 1129151497Sru{ 1130151497Sru register int ch; 1131151497Sru register int diff; 1132151497Sru register int newcol = start + 1; 1133151497Sru register int lastcol = start; 1134151497Sru char cursor_on_line = No; 1135151497Sru char *current; 1136151497Sru 1137151497Sru /* compare the two strings and only rewrite what has changed */ 1138151497Sru current = old; 1139151497Sru#ifdef DEBUG 1140151497Sru fprintf(debug, "line_update, starting at %d\n", start); 1141151497Sru fputs(old, debug); 1142151497Sru fputc('\n', debug); 1143151497Sru fputs(new, debug); 1144151497Sru fputs("\n-\n", debug); 1145151497Sru#endif 1146151497Sru 1147151497Sru /* start things off on the right foot */ 1148151497Sru /* this is to make sure the invariants get set up right */ 1149151497Sru if ((ch = *new++) != *old) 1150151497Sru { 1151151497Sru if (line - lastline == 1 && start == 0) 1152151497Sru { 1153151497Sru putchar('\n'); 1154151497Sru } 1155151497Sru else 1156151497Sru { 1157151497Sru Move_to(start, line); 1158151497Sru } 1159151497Sru cursor_on_line = Yes; 1160151497Sru putchar(ch); 1161151497Sru *old = ch; 1162151497Sru lastcol = 1; 1163151497Sru } 1164151497Sru old++; 1165151497Sru 1166151497Sru /* 1167151497Sru * main loop -- check each character. If the old and new aren't the 1168151497Sru * same, then update the display. When the distance from the 1169151497Sru * current cursor position to the new change is small enough, 1170151497Sru * the characters that belong there are written to move the 1171151497Sru * cursor over. 1172151497Sru * 1173151497Sru * Invariants: 1174151497Sru * lastcol is the column where the cursor currently is sitting 1175151497Sru * (always one beyond the end of the last mismatch). 1176151497Sru */ 1177151497Sru do /* yes, a do...while */ 1178151497Sru { 1179151497Sru if ((ch = *new++) != *old) 1180151497Sru { 1181151497Sru /* new character is different from old */ 1182151497Sru /* make sure the cursor is on top of this character */ 1183151497Sru diff = newcol - lastcol; 1184151497Sru if (diff > 0) 1185151497Sru { 1186151497Sru /* some motion is required--figure out which is shorter */ 1187151497Sru if (diff < 6 && cursor_on_line) 1188151497Sru { 1189151497Sru /* overwrite old stuff--get it out of the old buffer */ 1190151497Sru printf("%.*s", diff, ¤t[lastcol-start]); 1191151497Sru } 1192151497Sru else 1193151497Sru { 1194151497Sru /* use cursor addressing */ 1195151497Sru Move_to(newcol, line); 1196151497Sru cursor_on_line = Yes; 1197151497Sru } 1198151497Sru /* remember where the cursor is */ 1199151497Sru lastcol = newcol + 1; 1200151497Sru } 1201151497Sru else 1202151497Sru { 1203151497Sru /* already there, update position */ 1204151497Sru lastcol++; 1205151497Sru } 1206151497Sru 1207151497Sru /* write what we need to */ 1208151497Sru if (ch == '\0') 1209151497Sru { 1210151497Sru /* at the end--terminate with a clear-to-end-of-line */ 1211151497Sru (void) clear_eol(strlen(old)); 1212151497Sru } 1213151497Sru else 1214151497Sru { 1215151497Sru /* write the new character */ 1216151497Sru putchar(ch); 1217151497Sru } 1218151497Sru /* put the new character in the screen buffer */ 1219151497Sru *old = ch; 1220151497Sru } 1221151497Sru 1222151497Sru /* update working column and screen buffer pointer */ 1223151497Sru newcol++; 1224151497Sru old++; 1225151497Sru 1226151497Sru } while (ch != '\0'); 1227151497Sru 1228151497Sru /* zero out the rest of the line buffer -- MUST BE DONE! */ 1229151497Sru diff = display_width - newcol; 1230151497Sru if (diff > 0) 1231151497Sru { 1232151497Sru memzero(old, diff); 1233151497Sru } 1234151497Sru 1235151497Sru /* remember where the current line is */ 1236151497Sru if (cursor_on_line) 1237151497Sru { 1238151497Sru lastline = line; 1239151497Sru } 1240151497Sru} 1241151497Sru 1242151497Sru/* 1243151497Sru * printable(str) - make the string pointed to by "str" into one that is 1244151497Sru * printable (i.e.: all ascii), by converting all non-printable 1245151497Sru * characters into '?'. Replacements are done in place and a pointer 1246151497Sru * to the original buffer is returned. 1247151497Sru */ 1248151497Sru 1249151497Sruchar *printable(str) 1250151497Sru 1251151497Sruchar *str; 1252151497Sru 1253151497Sru{ 1254151497Sru register char *ptr; 1255151497Sru register char ch; 1256151497Sru 1257151497Sru ptr = str; 1258151497Sru while ((ch = *ptr) != '\0') 1259151497Sru { 1260151497Sru if (!isprint(ch)) 1261151497Sru { 1262151497Sru *ptr = '?'; 1263151497Sru } 1264151497Sru ptr++; 1265151497Sru } 1266151497Sru return(str); 1267151497Sru} 1268151497Sru 1269151497Srui_uptime(bt, tod) 1270151497Sru 1271151497Srustruct timeval* bt; 1272151497Srutime_t *tod; 1273151497Sru 1274151497Sru{ 1275151497Sru time_t uptime; 1276151497Sru int days, hrs, mins, secs; 1277151497Sru 1278151497Sru if (bt->tv_sec != -1) { 1279151497Sru uptime = *tod - bt->tv_sec; 1280151497Sru days = uptime / 86400; 1281151497Sru uptime %= 86400; 1282151497Sru hrs = uptime / 3600; 1283151497Sru uptime %= 3600; 1284151497Sru mins = uptime / 60; 1285151497Sru secs = uptime % 60; 1286151497Sru 1287151497Sru /* 1288151497Sru * Display the uptime. 1289151497Sru */ 1290151497Sru 1291151497Sru if (smart_terminal) 1292151497Sru { 1293151497Sru Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); 1294151497Sru } 1295151497Sru else 1296151497Sru { 1297151497Sru fputs(" ", stdout); 1298151497Sru } 1299151497Sru printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); 1300151497Sru } 1301151497Sru} 1302151497Sru