xref: /dragonfly/usr.bin/top/display.c (revision da0d35cf)
1dc4f0af1Szrj /*
2dc4f0af1Szrj  * Copyright (c) 1984 through 2008, William LeFebvre
3dc4f0af1Szrj  * All rights reserved.
4dc4f0af1Szrj  *
5dc4f0af1Szrj  * Redistribution and use in source and binary forms, with or without
6dc4f0af1Szrj  * modification, are permitted provided that the following conditions are met:
7dc4f0af1Szrj  *
8dc4f0af1Szrj  *     * Redistributions of source code must retain the above copyright
9dc4f0af1Szrj  * notice, this list of conditions and the following disclaimer.
10dc4f0af1Szrj  *
11dc4f0af1Szrj  *     * Redistributions in binary form must reproduce the above
12dc4f0af1Szrj  * copyright notice, this list of conditions and the following disclaimer
13dc4f0af1Szrj  * in the documentation and/or other materials provided with the
14dc4f0af1Szrj  * distribution.
15dc4f0af1Szrj  *
16dc4f0af1Szrj  *     * Neither the name of William LeFebvre nor the names of other
17dc4f0af1Szrj  * contributors may be used to endorse or promote products derived from
18dc4f0af1Szrj  * this software without specific prior written permission.
19dc4f0af1Szrj  *
20dc4f0af1Szrj  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21dc4f0af1Szrj  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22dc4f0af1Szrj  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23dc4f0af1Szrj  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24dc4f0af1Szrj  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25dc4f0af1Szrj  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26dc4f0af1Szrj  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27dc4f0af1Szrj  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28dc4f0af1Szrj  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29dc4f0af1Szrj  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30dc4f0af1Szrj  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31dc4f0af1Szrj  */
32dc4f0af1Szrj 
33dc4f0af1Szrj /*
34dc4f0af1Szrj  *  Top users/processes display for Unix
35dc4f0af1Szrj  *  Version 3
36dc4f0af1Szrj  */
37dc4f0af1Szrj 
38dc4f0af1Szrj /*
39dc4f0af1Szrj  *  This file contains the routines that display information on the screen.
40dc4f0af1Szrj  *  Each section of the screen has two routines:  one for initially writing
41dc4f0af1Szrj  *  all constant and dynamic text, and one for only updating the text that
42dc4f0af1Szrj  *  changes.  The prefix "i_" is used on all the "initial" routines and the
43dc4f0af1Szrj  *  prefix "u_" is used for all the "updating" routines.
44dc4f0af1Szrj  *
45dc4f0af1Szrj  *  ASSUMPTIONS:
46dc4f0af1Szrj  *        None of the "i_" routines use any of the termcap capabilities.
47dc4f0af1Szrj  *        In this way, those routines can be safely used on terminals that
48dc4f0af1Szrj  *        have minimal (or nonexistant) terminal capabilities.
49dc4f0af1Szrj  *
50dc4f0af1Szrj  *        The routines should be called in this order:  *_loadave, *_uptime,
51dc4f0af1Szrj  *        i_timeofday, *_procstates, *_cpustates, *_memory, *_swap,
52dc4f0af1Szrj  *        *_message, *_header, *_process, *_endscreen.
53dc4f0af1Szrj  */
54dc4f0af1Szrj 
55dc4f0af1Szrj #include "os.h"
56dc4f0af1Szrj #include <ctype.h>
57dc4f0af1Szrj #include <stdarg.h>
58dc4f0af1Szrj #include <sys/types.h>
59dc4f0af1Szrj #include <sys/uio.h>
60dc4f0af1Szrj #include <unistd.h>
61dc4f0af1Szrj 
62dc4f0af1Szrj #include "top.h"
63dc4f0af1Szrj #include "machine.h"
64dc4f0af1Szrj #include "screen.h"		/* interface to screen package */
65dc4f0af1Szrj #include "layout.h"		/* defines for screen position layout */
66dc4f0af1Szrj #include "display.h"
67dc4f0af1Szrj #include "boolean.h"
68dc4f0af1Szrj #include "utils.h"
69dc4f0af1Szrj 
70dc4f0af1Szrj #ifdef ENABLE_COLOR
71dc4f0af1Szrj #include "color.h"
72dc4f0af1Szrj #endif
73dc4f0af1Szrj 
74dc4f0af1Szrj #define CURSOR_COST 8
75dc4f0af1Szrj 
76dc4f0af1Szrj #define MESSAGE_DISPLAY_TIME 5
77dc4f0af1Szrj 
78dc4f0af1Szrj /* imported from screen.c */
79dc4f0af1Szrj extern int overstrike;
80dc4f0af1Szrj 
81dc4f0af1Szrj static int lmpid = -1;
82dc4f0af1Szrj static int display_width = MAX_COLS;
83dc4f0af1Szrj 
84dc4f0af1Szrj /* cursor positions of key points on the screen are maintained here */
85dc4f0af1Szrj /* layout.h has static definitions, but we may change our minds on some
86dc4f0af1Szrj    of the positions as we make decisions about what needs to be displayed */
87dc4f0af1Szrj 
88dc4f0af1Szrj static int x_lastpid = X_LASTPID;
89dc4f0af1Szrj static int y_lastpid = Y_LASTPID;
90dc4f0af1Szrj static int x_loadave = X_LOADAVE;
91dc4f0af1Szrj static int y_loadave = Y_LOADAVE;
92dc4f0af1Szrj static int x_minibar = X_MINIBAR;
93dc4f0af1Szrj static int y_minibar = Y_MINIBAR;
94dc4f0af1Szrj static int x_uptime = X_UPTIME;
95dc4f0af1Szrj static int y_uptime = Y_UPTIME;
96dc4f0af1Szrj static int x_procstate = X_PROCSTATE;
97dc4f0af1Szrj static int y_procstate = Y_PROCSTATE;
98dc4f0af1Szrj static int x_cpustates = X_CPUSTATES;
99dc4f0af1Szrj static int y_cpustates = Y_CPUSTATES;
100dc4f0af1Szrj static int x_kernel = X_KERNEL;
101dc4f0af1Szrj static int y_kernel = Y_KERNEL;
102dc4f0af1Szrj static int x_mem = X_MEM;
103dc4f0af1Szrj static int y_mem = Y_MEM;
104dc4f0af1Szrj static int x_swap = X_SWAP;
105dc4f0af1Szrj static int y_swap = Y_SWAP;
106dc4f0af1Szrj static int y_message = Y_MESSAGE;
107dc4f0af1Szrj static int x_header = X_HEADER;
108dc4f0af1Szrj static int y_header = Y_HEADER;
109dc4f0af1Szrj static int x_idlecursor = X_IDLECURSOR;
110dc4f0af1Szrj static int y_idlecursor = Y_IDLECURSOR;
111dc4f0af1Szrj static int y_procs = Y_PROCS;
112dc4f0af1Szrj 
113dc4f0af1Szrj /* buffer and colormask that describes the content of the screen */
114dc4f0af1Szrj /* these are singly dimensioned arrays -- the row boundaries are
115dc4f0af1Szrj    determined on the fly.
116dc4f0af1Szrj */
117dc4f0af1Szrj static char *screenbuf = NULL;
118dc4f0af1Szrj static char *colorbuf = NULL;
119dc4f0af1Szrj static char scratchbuf[MAX_COLS];
120dc4f0af1Szrj static int bufsize = 0;
121dc4f0af1Szrj 
122dc4f0af1Szrj /* lineindex tells us where the beginning of a line is in the buffer */
123dc4f0af1Szrj #define lineindex(l) ((l)*MAX_COLS)
124dc4f0af1Szrj 
125dc4f0af1Szrj /* screen's cursor */
126dc4f0af1Szrj static int curr_x, curr_y;
127dc4f0af1Szrj static int curr_color;
128dc4f0af1Szrj 
129dc4f0af1Szrj /* virtual cursor */
130dc4f0af1Szrj static int virt_x, virt_y;
131dc4f0af1Szrj 
132dc4f0af1Szrj static char **procstate_names;
133dc4f0af1Szrj static char **cpustate_names;
134dc4f0af1Szrj static char **memory_names;
135dc4f0af1Szrj static char **swap_names;
136dc4f0af1Szrj static char **kernel_names;
137dc4f0af1Szrj 
138dc4f0af1Szrj static int num_procstates;
139dc4f0af1Szrj static int num_cpustates;
140dc4f0af1Szrj static int num_memory;
141dc4f0af1Szrj static int num_swap;
142dc4f0af1Szrj static int num_kernel;
143dc4f0af1Szrj 
144dc4f0af1Szrj static int *lprocstates;
145dc4f0af1Szrj static int *lcpustates;
146dc4f0af1Szrj 
147dc4f0af1Szrj static int *cpustate_columns;
148dc4f0af1Szrj static int cpustate_total_length;
149dc4f0af1Szrj 
150dc4f0af1Szrj static int header_status = Yes;
151dc4f0af1Szrj 
152dc4f0af1Szrj /* pending messages are stored in a circular buffer, where message_first
153dc4f0af1Szrj    is the next one to display, and message_last is the last one
154dc4f0af1Szrj    in the buffer.  Counters wrap around at MAX_MESSAGES.  The buffer is
155dc4f0af1Szrj    empty when message_first == message_last and full when
156dc4f0af1Szrj    message_last + 1 == message_first.  The pointer message_current holds
157dc4f0af1Szrj    the message currently being displayed, or "" if there is none.
158dc4f0af1Szrj */
159dc4f0af1Szrj #define MAX_MESSAGES 16
160dc4f0af1Szrj static char *message_buf[MAX_MESSAGES];
161dc4f0af1Szrj static int message_first = 0;
162dc4f0af1Szrj static int message_last = 0;
163dc4f0af1Szrj static struct timeval message_time = {0, 0};
164dc4f0af1Szrj static char *message_current = NULL;
165dc4f0af1Szrj static int message_length = 0;
166dc4f0af1Szrj static int message_hold = 1;
167dc4f0af1Szrj static int message_barrier = No;
168dc4f0af1Szrj 
169dc4f0af1Szrj #ifdef ENABLE_COLOR
170dc4f0af1Szrj static int load_cidx[3];
171dc4f0af1Szrj static int header_cidx;
172dc4f0af1Szrj static int *cpustate_cidx;
173dc4f0af1Szrj static int *memory_cidx;
174dc4f0af1Szrj static int *swap_cidx;
175dc4f0af1Szrj static int *kernel_cidx;
176dc4f0af1Szrj #else
177dc4f0af1Szrj #define memory_cidx NULL
178dc4f0af1Szrj #define swap_cidx NULL
179dc4f0af1Szrj #define kernel_cidx NULL
180dc4f0af1Szrj #endif
181dc4f0af1Szrj 
182dc4f0af1Szrj 
183dc4f0af1Szrj /* internal support routines */
184dc4f0af1Szrj 
185dc4f0af1Szrj /*
186dc4f0af1Szrj  * static int string_count(char **pp)
187dc4f0af1Szrj  *
188dc4f0af1Szrj  * Pointer "pp" points to an array of string pointers, which is
189dc4f0af1Szrj  * terminated by a NULL.  Return the number of string pointers in
190dc4f0af1Szrj  * this array.
191dc4f0af1Szrj  */
192dc4f0af1Szrj 
193dc4f0af1Szrj static int
string_count(char ** pp)194dc4f0af1Szrj string_count(char **pp)
195dc4f0af1Szrj 
196dc4f0af1Szrj {
197dc4f0af1Szrj     register int cnt = 0;
198dc4f0af1Szrj 
199dc4f0af1Szrj     if (pp != NULL)
200dc4f0af1Szrj     {
201dc4f0af1Szrj 	while (*pp++ != NULL)
202dc4f0af1Szrj 	{
203dc4f0af1Szrj 	    cnt++;
204dc4f0af1Szrj 	}
205dc4f0af1Szrj     }
206dc4f0af1Szrj     return(cnt);
207dc4f0af1Szrj }
208dc4f0af1Szrj 
209dc4f0af1Szrj void
display_clear()210dc4f0af1Szrj display_clear()
211dc4f0af1Szrj 
212dc4f0af1Szrj {
213dc4f0af1Szrj     dprintf("display_clear\n");
214dc4f0af1Szrj     screen_clear();
215dc4f0af1Szrj     memzero(screenbuf, bufsize);
216dc4f0af1Szrj     memzero(colorbuf, bufsize);
217dc4f0af1Szrj     curr_x = curr_y = 0;
218dc4f0af1Szrj }
219dc4f0af1Szrj 
220dc4f0af1Szrj /*
221dc4f0af1Szrj  * void display_move(int x, int y)
222dc4f0af1Szrj  *
223dc4f0af1Szrj  * Efficiently move the cursor to x, y.  This assumes the cursor is
224dc4f0af1Szrj  * currently located at curr_x, curr_y, and will only use cursor
225dc4f0af1Szrj  * addressing when it is less expensive than overstriking what's
226dc4f0af1Szrj  * already on the screen.
227dc4f0af1Szrj  */
228dc4f0af1Szrj 
229dc4f0af1Szrj void
display_move(int x,int y)230dc4f0af1Szrj display_move(int x, int y)
231dc4f0af1Szrj 
232dc4f0af1Szrj {
233dc4f0af1Szrj     char buff[128];
234dc4f0af1Szrj     char *p;
235dc4f0af1Szrj     char *bufp;
236dc4f0af1Szrj     char *colorp;
237dc4f0af1Szrj     int cnt = 0;
238dc4f0af1Szrj     int color = curr_color;
239dc4f0af1Szrj 
240dc4f0af1Szrj     dprintf("display_move(%d, %d): curr_x %d, curr_y %d\n", x, y, curr_x, curr_y);
241dc4f0af1Szrj 
242dc4f0af1Szrj     /* are we in a position to do this without cursor addressing? */
243dc4f0af1Szrj     if (curr_y < y || (curr_y == y && curr_x <= x))
244dc4f0af1Szrj     {
245dc4f0af1Szrj 	/* start buffering up what it would take to move there by rewriting
246dc4f0af1Szrj 	   what's on the screen */
247dc4f0af1Szrj 	cnt = CURSOR_COST;
248dc4f0af1Szrj 	p = buff;
249dc4f0af1Szrj 
250dc4f0af1Szrj 	/* one newline for every line */
251dc4f0af1Szrj 	while (cnt > 0 && curr_y < y)
252dc4f0af1Szrj 	{
253dc4f0af1Szrj #ifdef ENABLE_COLOR
254dc4f0af1Szrj 	    if (color != 0)
255dc4f0af1Szrj 	    {
256dc4f0af1Szrj 		p = strcpyend(p, color_setstr(0));
257dc4f0af1Szrj 		color = 0;
258dc4f0af1Szrj 		cnt -= 5;
259dc4f0af1Szrj 	    }
260dc4f0af1Szrj #endif
261dc4f0af1Szrj 	    *p++ = '\n';
262dc4f0af1Szrj 	    curr_y++;
263dc4f0af1Szrj 	    curr_x = 0;
264dc4f0af1Szrj 	    cnt--;
265dc4f0af1Szrj 	}
266dc4f0af1Szrj 
267dc4f0af1Szrj 	/* write whats in the screenbuf */
268dc4f0af1Szrj 	bufp = &screenbuf[lineindex(curr_y) + curr_x];
269dc4f0af1Szrj 	colorp = &colorbuf[lineindex(curr_y) + curr_x];
270dc4f0af1Szrj 	while (cnt > 0 && curr_x < x)
271dc4f0af1Szrj 	{
272dc4f0af1Szrj #ifdef ENABLE_COLOR
273dc4f0af1Szrj 	    if (color != *colorp)
274dc4f0af1Szrj 	    {
275dc4f0af1Szrj 		color = *colorp;
276dc4f0af1Szrj 		p = strcpyend(p, color_setstr(color));
277dc4f0af1Szrj 		cnt -= 5;
278dc4f0af1Szrj 	    }
279dc4f0af1Szrj #endif
280dc4f0af1Szrj 	    if ((*p = *bufp) == '\0')
281dc4f0af1Szrj 	    {
282dc4f0af1Szrj 		/* somwhere on screen we haven't been before */
283dc4f0af1Szrj 		*p = *bufp = ' ';
284dc4f0af1Szrj 	    }
285dc4f0af1Szrj 	    p++;
286dc4f0af1Szrj 	    bufp++;
287dc4f0af1Szrj 	    colorp++;
288dc4f0af1Szrj 	    curr_x++;
289dc4f0af1Szrj 	    cnt--;
290dc4f0af1Szrj 	}
291dc4f0af1Szrj     }
292dc4f0af1Szrj 
293dc4f0af1Szrj     /* move the cursor */
294dc4f0af1Szrj     if (cnt > 0)
295dc4f0af1Szrj     {
296dc4f0af1Szrj 	/* screen rewrite is cheaper */
297dc4f0af1Szrj 	*p = '\0';
298dc4f0af1Szrj 	fputs(buff, stdout);
299dc4f0af1Szrj 	curr_color = color;
300dc4f0af1Szrj     }
301dc4f0af1Szrj     else
302dc4f0af1Szrj     {
303dc4f0af1Szrj 	screen_move(x, y);
304dc4f0af1Szrj     }
305dc4f0af1Szrj 
306dc4f0af1Szrj     /* update our position */
307dc4f0af1Szrj     curr_x = x;
308dc4f0af1Szrj     curr_y = y;
309dc4f0af1Szrj }
310dc4f0af1Szrj 
311dc4f0af1Szrj /*
312dc4f0af1Szrj  * display_write(int x, int y, int newcolor, int eol, char *new)
313dc4f0af1Szrj  *
314dc4f0af1Szrj  * Optimized write to the display.  This writes characters to the
315dc4f0af1Szrj  * screen in a way that optimizes the number of characters actually
316dc4f0af1Szrj  * sent, by comparing what is being written to what is already on
317dc4f0af1Szrj  * the screen (according to screenbuf and colorbuf).  The string to
318dc4f0af1Szrj  * write is "new", the first character of "new" should appear at
319dc4f0af1Szrj  * screen position x, y.  If x is -1 then "new" begins wherever the
320dc4f0af1Szrj  * cursor is currently positioned.  The string is written with color
321dc4f0af1Szrj  * "newcolor".  If "eol" is true then the remainder of the line is
322dc4f0af1Szrj  * cleared.  It is expected that "new" will have no newlines and no
323dc4f0af1Szrj  * escape sequences.
324dc4f0af1Szrj  */
325dc4f0af1Szrj 
326dc4f0af1Szrj void
display_write(int x,int y,int newcolor,int eol,char * new)327dc4f0af1Szrj display_write(int x, int y, int newcolor, int eol, char *new)
328dc4f0af1Szrj 
329dc4f0af1Szrj {
330dc4f0af1Szrj     char *bufp;
331dc4f0af1Szrj     char *colorp;
332dc4f0af1Szrj     int ch;
333dc4f0af1Szrj     int diff;
334dc4f0af1Szrj 
335dc4f0af1Szrj     dprintf("display_write(%d, %d, %d, %d, \"%s\")\n",
336dc4f0af1Szrj 	    x, y, newcolor, eol, new);
337dc4f0af1Szrj 
338dc4f0af1Szrj     /* dumb terminal handling here */
339dc4f0af1Szrj     if (!smart_terminal)
340dc4f0af1Szrj     {
341dc4f0af1Szrj 	if (x != -1)
342dc4f0af1Szrj 	{
343dc4f0af1Szrj 	    /* make sure we are on the right line */
344dc4f0af1Szrj 	    while (curr_y < y)
345dc4f0af1Szrj 	    {
346dc4f0af1Szrj 		putchar('\n');
347dc4f0af1Szrj 		curr_y++;
348dc4f0af1Szrj 		curr_x = 0;
349dc4f0af1Szrj 	    }
350dc4f0af1Szrj 
351dc4f0af1Szrj 	    /* make sure we are on the right column */
352dc4f0af1Szrj 	    while (curr_x < x)
353dc4f0af1Szrj 	    {
354dc4f0af1Szrj 		putchar(' ');
355dc4f0af1Szrj 		curr_x++;
356dc4f0af1Szrj 	    }
357dc4f0af1Szrj 	}
358dc4f0af1Szrj 
359dc4f0af1Szrj 	/* write */
360dc4f0af1Szrj 	fputs(new, stdout);
361dc4f0af1Szrj 	curr_x += strlen(new);
362dc4f0af1Szrj 
363dc4f0af1Szrj 	return;
364dc4f0af1Szrj     }
365dc4f0af1Szrj 
366dc4f0af1Szrj     /* adjust for "here" */
367dc4f0af1Szrj     if (x == -1)
368dc4f0af1Szrj     {
369dc4f0af1Szrj 	x = virt_x;
370dc4f0af1Szrj 	y = virt_y;
371dc4f0af1Szrj     }
372dc4f0af1Szrj     else
373dc4f0af1Szrj     {
374dc4f0af1Szrj 	virt_x = x;
375dc4f0af1Szrj 	virt_y = y;
376dc4f0af1Szrj     }
377dc4f0af1Szrj 
378dc4f0af1Szrj     /* a pointer to where we start */
379dc4f0af1Szrj     bufp = &screenbuf[lineindex(y) + x];
380dc4f0af1Szrj     colorp = &colorbuf[lineindex(y) + x];
381dc4f0af1Szrj 
382dc4f0af1Szrj     /* main loop */
383dc4f0af1Szrj     while ((ch = *new++) != '\0')
384dc4f0af1Szrj     {
385dc4f0af1Szrj 	/* if either character or color are different, an update is needed */
386dc4f0af1Szrj 	/* but only when the screen is wide enough */
387dc4f0af1Szrj 	if (y < (smart_terminal ? screen_length : Largest) && x < display_width &&
388dc4f0af1Szrj 	    (ch != *bufp || newcolor != *colorp))
389dc4f0af1Szrj 	{
390dc4f0af1Szrj 	    /* check cursor */
391dc4f0af1Szrj 	    if (y != curr_y || x != curr_x)
392dc4f0af1Szrj 	    {
393dc4f0af1Szrj 		/* have to move the cursor */
394dc4f0af1Szrj 		display_move(x, y);
395dc4f0af1Szrj 	    }
396dc4f0af1Szrj 
397dc4f0af1Szrj 	    /* write character */
398dc4f0af1Szrj #ifdef ENABLE_COLOR
399dc4f0af1Szrj 	    if (curr_color != newcolor)
400dc4f0af1Szrj 	    {
401dc4f0af1Szrj 		fputs(color_setstr(newcolor), stdout);
402dc4f0af1Szrj 		curr_color = newcolor;
403dc4f0af1Szrj 	    }
404dc4f0af1Szrj #endif
405dc4f0af1Szrj 	    putchar(ch);
406dc4f0af1Szrj 	    *bufp = ch;
407dc4f0af1Szrj 	    *colorp = curr_color;
408dc4f0af1Szrj 	    curr_x++;
409dc4f0af1Szrj 	}
410dc4f0af1Szrj 
411dc4f0af1Szrj 	/* move */
412dc4f0af1Szrj 	x++;
413dc4f0af1Szrj 	virt_x++;
414dc4f0af1Szrj 	bufp++;
415dc4f0af1Szrj 	colorp++;
416dc4f0af1Szrj     }
417dc4f0af1Szrj 
418dc4f0af1Szrj     /* eol handling */
419dc4f0af1Szrj     if (eol && *bufp != '\0')
420dc4f0af1Szrj     {
421dc4f0af1Szrj 	dprintf("display_write: clear-eol (bufp = \"%s\")\n", bufp);
422dc4f0af1Szrj 	/* make sure we are color 0 */
423dc4f0af1Szrj #ifdef ENABLE_COLOR
424dc4f0af1Szrj 	if (curr_color != 0)
425dc4f0af1Szrj 	{
426dc4f0af1Szrj 	    fputs(color_setstr(0), stdout);
427dc4f0af1Szrj 	    curr_color = 0;
428dc4f0af1Szrj 	}
429dc4f0af1Szrj #endif
430dc4f0af1Szrj 
431dc4f0af1Szrj 	/* make sure we are at the end */
432dc4f0af1Szrj 	if (x != curr_x || y != curr_y)
433dc4f0af1Szrj 	{
434dc4f0af1Szrj 	    screen_move(x, y);
435dc4f0af1Szrj 	    curr_x = x;
436dc4f0af1Szrj 	    curr_y = y;
437dc4f0af1Szrj 	}
438dc4f0af1Szrj 
439dc4f0af1Szrj 	/* clear to end */
440dc4f0af1Szrj 	screen_cleareol(strlen(bufp));
441dc4f0af1Szrj 
442dc4f0af1Szrj 	/* clear out whats left of this line's buffer */
443dc4f0af1Szrj 	diff = display_width - x;
444dc4f0af1Szrj 	if (diff > 0)
445dc4f0af1Szrj 	{
446dc4f0af1Szrj 	    memzero(bufp, diff);
447dc4f0af1Szrj 	    memzero(colorp, diff);
448dc4f0af1Szrj 	}
449dc4f0af1Szrj     }
450dc4f0af1Szrj }
451dc4f0af1Szrj 
452dc4f0af1Szrj void
display_fmt(int x,int y,int newcolor,int eol,char * fmt,...)453dc4f0af1Szrj display_fmt(int x, int y, int newcolor, int eol, char *fmt, ...)
454dc4f0af1Szrj 
455dc4f0af1Szrj {
456dc4f0af1Szrj     va_list argp;
457dc4f0af1Szrj 
458dc4f0af1Szrj     va_start(argp, fmt);
459dc4f0af1Szrj 
460dc4f0af1Szrj     vsnprintf(scratchbuf, MAX_COLS, fmt, argp);
461dc4f0af1Szrj     display_write(x, y, newcolor, eol, scratchbuf);
462dc4f0af1Szrj }
463dc4f0af1Szrj 
464dc4f0af1Szrj void
display_cte()465dc4f0af1Szrj display_cte()
466dc4f0af1Szrj 
467dc4f0af1Szrj {
468dc4f0af1Szrj     int len;
469dc4f0af1Szrj     int y;
470dc4f0af1Szrj     char *p;
471dc4f0af1Szrj     int need_clear = 0;
472dc4f0af1Szrj 
473dc4f0af1Szrj     /* is there anything out there that needs to be cleared? */
474dc4f0af1Szrj     p = &screenbuf[lineindex(virt_y) + virt_x];
475dc4f0af1Szrj     if (*p != '\0')
476dc4f0af1Szrj     {
477dc4f0af1Szrj 	need_clear = 1;
478dc4f0af1Szrj     }
479dc4f0af1Szrj     else
480dc4f0af1Szrj     {
481dc4f0af1Szrj 	/* this line is clear, what about the rest? */
482dc4f0af1Szrj 	y = virt_y;
483dc4f0af1Szrj 	while (++y < screen_length)
484dc4f0af1Szrj 	{
485dc4f0af1Szrj 	    if (screenbuf[lineindex(y)] != '\0')
486dc4f0af1Szrj 	    {
487dc4f0af1Szrj 		need_clear = 1;
488dc4f0af1Szrj 		break;
489dc4f0af1Szrj 	    }
490dc4f0af1Szrj 	}
491dc4f0af1Szrj     }
492dc4f0af1Szrj 
493dc4f0af1Szrj     if (need_clear)
494dc4f0af1Szrj     {
495dc4f0af1Szrj 	dprintf("display_cte: clearing\n");
496dc4f0af1Szrj 
497dc4f0af1Szrj 	/* we will need this later */
498dc4f0af1Szrj 	len = lineindex(virt_y) + virt_x;
499dc4f0af1Szrj 
500dc4f0af1Szrj 	/* move to x and y, then clear to end */
501dc4f0af1Szrj 	display_move(virt_x, virt_y);
502dc4f0af1Szrj 	if (!screen_cte())
503dc4f0af1Szrj 	{
504dc4f0af1Szrj 	    /* screen has no clear to end, so do it by hand */
505dc4f0af1Szrj 	    p = &screenbuf[len];
506dc4f0af1Szrj 	    len = strlen(p);
507dc4f0af1Szrj 	    if (len > 0)
508dc4f0af1Szrj 	    {
509dc4f0af1Szrj 		screen_cleareol(len);
510dc4f0af1Szrj 	    }
511dc4f0af1Szrj 	    while (++virt_y < screen_length)
512dc4f0af1Szrj 	    {
513dc4f0af1Szrj 		display_move(0, virt_y);
514dc4f0af1Szrj 		p = &screenbuf[lineindex(virt_y)];
515dc4f0af1Szrj 		len = strlen(p);
516dc4f0af1Szrj 		if (len > 0)
517dc4f0af1Szrj 		{
518dc4f0af1Szrj 		    screen_cleareol(len);
519dc4f0af1Szrj 		}
520dc4f0af1Szrj 	    }
521dc4f0af1Szrj 	}
522dc4f0af1Szrj 
523dc4f0af1Szrj 	/* clear the screenbuf */
524dc4f0af1Szrj 	memzero(&screenbuf[len], bufsize - len);
525dc4f0af1Szrj 	memzero(&colorbuf[len], bufsize - len);
526dc4f0af1Szrj     }
527dc4f0af1Szrj }
528dc4f0af1Szrj 
529dc4f0af1Szrj static void
summary_format(int x,int y,int * numbers,char ** names,int * cidx)530dc4f0af1Szrj summary_format(int x, int y, int *numbers, char **names, int *cidx)
531dc4f0af1Szrj 
532dc4f0af1Szrj {
533dc4f0af1Szrj     register int num;
534dc4f0af1Szrj     register char *thisname;
535dc4f0af1Szrj     register char *lastname = NULL;
536dc4f0af1Szrj     register int color;
537dc4f0af1Szrj 
538dc4f0af1Szrj     /* format each number followed by its string */
539dc4f0af1Szrj     while ((thisname = *names++) != NULL)
540dc4f0af1Szrj     {
541dc4f0af1Szrj 	/* get the number to format */
542dc4f0af1Szrj 	num = *numbers++;
543dc4f0af1Szrj 	color = 0;
544dc4f0af1Szrj 
545dc4f0af1Szrj 	/* display only non-zero numbers */
546dc4f0af1Szrj 	if (num != 0)
547dc4f0af1Szrj 	{
548dc4f0af1Szrj 	    /* write the previous name */
549dc4f0af1Szrj 	    if (lastname != NULL)
550dc4f0af1Szrj 	    {
551dc4f0af1Szrj 		display_write(-1, -1, 0, 0, lastname);
552dc4f0af1Szrj 	    }
553dc4f0af1Szrj 
554dc4f0af1Szrj #ifdef ENABLE_COLOR
555dc4f0af1Szrj 	    if (cidx != NULL)
556dc4f0af1Szrj 	    {
557dc4f0af1Szrj 		/* choose a color */
558dc4f0af1Szrj 		color = color_test(*cidx++, num);
559dc4f0af1Szrj 	    }
560dc4f0af1Szrj #endif
561dc4f0af1Szrj 
562dc4f0af1Szrj 	    /* write this number if positive */
563dc4f0af1Szrj 	    if (num > 0)
564dc4f0af1Szrj 	    {
565dc4f0af1Szrj 		display_write(x, y, color, 0, itoa(num));
566dc4f0af1Szrj 	    }
567dc4f0af1Szrj 
568dc4f0af1Szrj 	    /* defer writing this name */
569dc4f0af1Szrj 	    lastname = thisname;
570dc4f0af1Szrj 
571dc4f0af1Szrj 	    /* next iteration will not start at x, y */
572dc4f0af1Szrj 	    x = y = -1;
573dc4f0af1Szrj 	}
574dc4f0af1Szrj     }
575dc4f0af1Szrj 
576dc4f0af1Szrj     /* if the last string has a separator on the end, it has to be
577dc4f0af1Szrj        written with care */
578dc4f0af1Szrj     if (lastname != NULL)
579dc4f0af1Szrj     {
580dc4f0af1Szrj 	if ((num = strlen(lastname)) > 1 &&
581dc4f0af1Szrj 	    lastname[num-2] == ',' && lastname[num-1] == ' ')
582dc4f0af1Szrj 	{
583dc4f0af1Szrj 	    display_fmt(-1, -1, 0, 1, "%.*s", num-2, lastname);
584dc4f0af1Szrj 	}
585dc4f0af1Szrj 	else
586dc4f0af1Szrj 	{
587dc4f0af1Szrj 	    display_write(-1, -1, 0, 1, lastname);
588dc4f0af1Szrj 	}
589dc4f0af1Szrj     }
590dc4f0af1Szrj }
591dc4f0af1Szrj 
592dc4f0af1Szrj static void
summary_format_memory(int x,int y,long * numbers,char ** names,int * cidx)593dc4f0af1Szrj summary_format_memory(int x, int y, long *numbers, char **names, int *cidx)
594dc4f0af1Szrj 
595dc4f0af1Szrj {
596dc4f0af1Szrj     register long num;
597dc4f0af1Szrj     register int color;
598dc4f0af1Szrj     register char *thisname;
599dc4f0af1Szrj     register char *lastname = NULL;
600dc4f0af1Szrj 
601dc4f0af1Szrj     /* format each number followed by its string */
602dc4f0af1Szrj     while ((thisname = *names++) != NULL)
603dc4f0af1Szrj     {
604dc4f0af1Szrj 	/* get the number to format */
605dc4f0af1Szrj 	num = *numbers++;
606dc4f0af1Szrj 	color = 0;
607dc4f0af1Szrj 
608dc4f0af1Szrj 	/* display only non-zero numbers */
609dc4f0af1Szrj 	if (num != 0)
610dc4f0af1Szrj 	{
611dc4f0af1Szrj 	    /* write the previous name */
612dc4f0af1Szrj 	    if (lastname != NULL)
613dc4f0af1Szrj 	    {
614dc4f0af1Szrj 		display_write(-1, -1, 0, 0, lastname);
615dc4f0af1Szrj 	    }
616dc4f0af1Szrj 
617dc4f0af1Szrj 	    /* defer writing this name */
618dc4f0af1Szrj 	    lastname = thisname;
619dc4f0af1Szrj 
620dc4f0af1Szrj #ifdef ENABLE_COLOR
621dc4f0af1Szrj 	    /* choose a color */
622dc4f0af1Szrj 	    color = color_test(*cidx++, num);
623dc4f0af1Szrj #endif
624dc4f0af1Szrj 
625dc4f0af1Szrj 	    /* is this number in kilobytes? */
626dc4f0af1Szrj 	    if (thisname[0] == 'K')
627dc4f0af1Szrj 	    {
628dc4f0af1Szrj 		display_write(x, y, color, 0, format_k(num));
629dc4f0af1Szrj 		lastname++;
630dc4f0af1Szrj 	    }
631dc4f0af1Szrj 	    else
632dc4f0af1Szrj 	    {
633dc4f0af1Szrj 		display_write(x, y, color, 0, itoa((int)num));
634dc4f0af1Szrj 	    }
635dc4f0af1Szrj 
636dc4f0af1Szrj 	    /* next iteration will not start at x, y */
637dc4f0af1Szrj 	    x = y = -1;
638dc4f0af1Szrj 	}
639dc4f0af1Szrj     }
640dc4f0af1Szrj 
641dc4f0af1Szrj     /* if the last string has a separator on the end, it has to be
642dc4f0af1Szrj        written with care */
643dc4f0af1Szrj     if (lastname != NULL)
644dc4f0af1Szrj     {
645dc4f0af1Szrj 	if ((num = strlen(lastname)) > 1 &&
646dc4f0af1Szrj 	    lastname[num-2] == ',' && lastname[num-1] == ' ')
647dc4f0af1Szrj 	{
648dc4f0af1Szrj 	    display_fmt(-1, -1, 0, 1, "%.*s", num-2, lastname);
649dc4f0af1Szrj 	}
650dc4f0af1Szrj 	else
651dc4f0af1Szrj 	{
652dc4f0af1Szrj 	    display_write(-1, -1, 0, 1, lastname);
653dc4f0af1Szrj 	}
654dc4f0af1Szrj     }
655dc4f0af1Szrj }
656dc4f0af1Szrj 
657dc4f0af1Szrj /*
658dc4f0af1Szrj  * int display_resize()
659dc4f0af1Szrj  *
660dc4f0af1Szrj  * Reallocate buffer space needed by the display package to accomodate
661dc4f0af1Szrj  * a new screen size.  Must be called whenever the screen's size has
662dc4f0af1Szrj  * changed.  Returns the number of lines available for displaying
663dc4f0af1Szrj  * processes or -1 if there was a problem allocating space.
664dc4f0af1Szrj  */
665dc4f0af1Szrj 
666dc4f0af1Szrj int
display_resize()667dc4f0af1Szrj display_resize()
668dc4f0af1Szrj 
669dc4f0af1Szrj {
670dc4f0af1Szrj     register int top_lines;
671dc4f0af1Szrj     register int newsize;
672dc4f0af1Szrj 
673dc4f0af1Szrj     /* calculate the current dimensions */
674dc4f0af1Szrj     /* if operating in "dumb" mode, we only need one line */
675dc4f0af1Szrj     top_lines = smart_terminal ? screen_length : 1;
676dc4f0af1Szrj 
677dc4f0af1Szrj     /* we don't want more than MAX_COLS columns, since the machine-dependent
678dc4f0af1Szrj        modules make static allocations based on MAX_COLS and we don't want
679dc4f0af1Szrj        to run off the end of their buffers */
680dc4f0af1Szrj     display_width = screen_width;
681dc4f0af1Szrj     if (display_width >= MAX_COLS)
682dc4f0af1Szrj     {
683dc4f0af1Szrj 	display_width = MAX_COLS - 1;
684dc4f0af1Szrj     }
685dc4f0af1Szrj 
686dc4f0af1Szrj     /* see how much space we need */
687dc4f0af1Szrj     newsize = top_lines * (MAX_COLS + 1);
688dc4f0af1Szrj 
689dc4f0af1Szrj     /* reallocate only if we need more than we already have */
690dc4f0af1Szrj     if (newsize > bufsize)
691dc4f0af1Szrj     {
692dc4f0af1Szrj 	/* deallocate any previous buffer that may have been there */
693dc4f0af1Szrj 	if (screenbuf != NULL)
694dc4f0af1Szrj 	{
695dc4f0af1Szrj 	    free(screenbuf);
696dc4f0af1Szrj 	}
697dc4f0af1Szrj 	if (colorbuf != NULL)
698dc4f0af1Szrj 	{
699dc4f0af1Szrj 	    free(colorbuf);
700dc4f0af1Szrj 	}
701dc4f0af1Szrj 
702dc4f0af1Szrj 	/* allocate space for the screen and color buffers */
703dc4f0af1Szrj 	bufsize = newsize;
704dc4f0af1Szrj 	screenbuf = (char *)calloc(bufsize, sizeof(char));
705dc4f0af1Szrj 	colorbuf = (char *)calloc(bufsize, sizeof(char));
706dc4f0af1Szrj 	if (screenbuf == NULL || colorbuf == NULL)
707dc4f0af1Szrj 	{
708dc4f0af1Szrj 	    /* oops! */
709dc4f0af1Szrj 	    return(-1);
710dc4f0af1Szrj 	}
711dc4f0af1Szrj     }
712dc4f0af1Szrj     else
713dc4f0af1Szrj     {
714dc4f0af1Szrj 	/* just clear them out */
715dc4f0af1Szrj 	memzero(screenbuf, bufsize);
716dc4f0af1Szrj 	memzero(colorbuf, bufsize);
717dc4f0af1Szrj     }
718dc4f0af1Szrj 
719dc4f0af1Szrj     /* adjust total lines on screen to lines available for procs */
720dc4f0af1Szrj     if (top_lines > y_procs)
721dc4f0af1Szrj 	top_lines -= y_procs;
722dc4f0af1Szrj     else
723dc4f0af1Szrj 	top_lines = 0;
724dc4f0af1Szrj 
725dc4f0af1Szrj     /* return number of lines available */
726dc4f0af1Szrj     /* for dumb terminals, pretend like we can show any amount */
727dc4f0af1Szrj     return(smart_terminal ? top_lines : Largest);
728dc4f0af1Szrj }
729dc4f0af1Szrj 
730dc4f0af1Szrj int
display_lines()731dc4f0af1Szrj display_lines()
732dc4f0af1Szrj 
733dc4f0af1Szrj {
734dc4f0af1Szrj     return(smart_terminal ? screen_length : Largest);
735dc4f0af1Szrj }
736dc4f0af1Szrj 
737dc4f0af1Szrj int
display_columns()738dc4f0af1Szrj display_columns()
739dc4f0af1Szrj 
740dc4f0af1Szrj {
741dc4f0af1Szrj     return(display_width);
742dc4f0af1Szrj }
743dc4f0af1Szrj 
744dc4f0af1Szrj /*
745dc4f0af1Szrj  * int display_init(struct statics *statics)
746dc4f0af1Szrj  *
747dc4f0af1Szrj  * Initialize the display system based on information in the statics
748dc4f0af1Szrj  * structure.  Returns the number of lines available for displaying
749dc4f0af1Szrj  * processes or -1 if there was an error.
750dc4f0af1Szrj  */
751dc4f0af1Szrj 
752dc4f0af1Szrj int
display_init(struct statics * statics)753dc4f0af1Szrj display_init(struct statics *statics)
754dc4f0af1Szrj 
755dc4f0af1Szrj {
756dc4f0af1Szrj     register int top_lines;
757dc4f0af1Szrj     register char **pp;
758dc4f0af1Szrj     register char *p;
759dc4f0af1Szrj     register int *ip;
760dc4f0af1Szrj     register int i;
761dc4f0af1Szrj 
762dc4f0af1Szrj     /* certain things may influence the screen layout,
763dc4f0af1Szrj        so look at those first */
764dc4f0af1Szrj 
765dc4f0af1Szrj 	/* More than one core will shif the parts of the display down */
766dc4f0af1Szrj     if (enable_ncpus != 0 && n_cpus > 1)
767dc4f0af1Szrj     {
768dc4f0af1Szrj        /* adjust screen placements */
769dc4f0af1Szrj        y_mem = y_mem + n_cpus -1;
770dc4f0af1Szrj        y_swap = y_swap + n_cpus -1;
771dc4f0af1Szrj        y_message = y_message + n_cpus -1;
772dc4f0af1Szrj        y_header = y_header + n_cpus -1;
773dc4f0af1Szrj        y_idlecursor = y_idlecursor + n_cpus -1;
774dc4f0af1Szrj        y_procs = y_procs + n_cpus -1;
775dc4f0af1Szrj     }
776dc4f0af1Szrj 
777dc4f0af1Szrj     /* a kernel line shifts parts of the display down */
778dc4f0af1Szrj     kernel_names = statics->kernel_names;
779dc4f0af1Szrj     if ((num_kernel = string_count(kernel_names)) > 0)
780dc4f0af1Szrj     {
781dc4f0af1Szrj 	/* adjust screen placements */
782dc4f0af1Szrj 	y_mem++;
783dc4f0af1Szrj 	y_swap++;
784dc4f0af1Szrj 	y_message++;
785dc4f0af1Szrj 	y_header++;
786dc4f0af1Szrj 	y_idlecursor++;
787dc4f0af1Szrj 	y_procs++;
788dc4f0af1Szrj     }
789dc4f0af1Szrj 
790dc4f0af1Szrj     /* a swap line shifts parts of the display down one */
791dc4f0af1Szrj     swap_names = statics->swap_names;
792dc4f0af1Szrj     if ((num_swap = string_count(swap_names)) > 0)
793dc4f0af1Szrj     {
794dc4f0af1Szrj 	/* adjust screen placements */
795dc4f0af1Szrj 	y_message++;
796dc4f0af1Szrj 	y_header++;
797dc4f0af1Szrj 	y_idlecursor++;
798dc4f0af1Szrj 	y_procs++;
799dc4f0af1Szrj     }
800dc4f0af1Szrj 
801dc4f0af1Szrj     /* call resize to do the dirty work */
802dc4f0af1Szrj     top_lines = display_resize();
803dc4f0af1Szrj 
804dc4f0af1Szrj     /*
805dc4f0af1Szrj      * save pointers and allocate space for names.  Even if top_lines <= -1
806dc4f0af1Szrj      * the code will dereference many of these pointers and arrays.
807dc4f0af1Szrj      */
808dc4f0af1Szrj     procstate_names = statics->procstate_names;
809dc4f0af1Szrj     num_procstates = string_count(procstate_names);
810dc4f0af1Szrj 
811dc4f0af1Szrj     lprocstates = (int *)calloc(num_procstates, sizeof(int));
812dc4f0af1Szrj 
813dc4f0af1Szrj     cpustate_names = statics->cpustate_names;
814dc4f0af1Szrj     num_cpustates = string_count(cpustate_names);
815dc4f0af1Szrj     lcpustates = (int *)calloc(num_cpustates, sizeof(int));
816dc4f0af1Szrj     cpustate_columns = (int *)calloc(num_cpustates, sizeof(int));
817dc4f0af1Szrj     memory_names = statics->memory_names;
818dc4f0af1Szrj     num_memory = string_count(memory_names);
819dc4f0af1Szrj 
820dc4f0af1Szrj     /* calculate starting columns where needed */
821dc4f0af1Szrj     cpustate_total_length = 0;
822dc4f0af1Szrj     pp = cpustate_names;
823dc4f0af1Szrj     ip = cpustate_columns;
824dc4f0af1Szrj     while (*pp != NULL)
825dc4f0af1Szrj     {
826dc4f0af1Szrj 	*ip++ = cpustate_total_length;
827dc4f0af1Szrj 	if ((i = strlen(*pp++)) > 0)
828dc4f0af1Szrj 	{
829dc4f0af1Szrj 	    cpustate_total_length += i + 8;
830dc4f0af1Szrj 	}
831dc4f0af1Szrj     }
832dc4f0af1Szrj 
833dc4f0af1Szrj #ifdef ENABLE_COLOR
834dc4f0af1Szrj     /* set up color tags for loadavg */
835dc4f0af1Szrj     load_cidx[0] = color_tag("1min");
836dc4f0af1Szrj     load_cidx[1] = color_tag("5min");
837dc4f0af1Szrj     load_cidx[2] = color_tag("15min");
838dc4f0af1Szrj 
839dc4f0af1Szrj     /* find header color */
840dc4f0af1Szrj     header_cidx = color_tag("header");
841dc4f0af1Szrj 
842dc4f0af1Szrj     /* color tags for cpu states */
843dc4f0af1Szrj     cpustate_cidx = (int *)malloc(num_cpustates * sizeof(int));
844dc4f0af1Szrj     i = 0;
845dc4f0af1Szrj     p = strcpyend(scratchbuf, "cpu.");
846dc4f0af1Szrj     while (i < num_cpustates)
847dc4f0af1Szrj     {
848dc4f0af1Szrj 	strcpy(p, cpustate_names[i]);
849dc4f0af1Szrj 	cpustate_cidx[i++] = color_tag(scratchbuf);
850dc4f0af1Szrj     }
851dc4f0af1Szrj 
852dc4f0af1Szrj     /* color tags for kernel */
853dc4f0af1Szrj     if (num_kernel > 0)
854dc4f0af1Szrj     {
855dc4f0af1Szrj 	kernel_cidx = (int *)malloc(num_kernel * sizeof(int));
856dc4f0af1Szrj 	i = 0;
857dc4f0af1Szrj 	p = strcpyend(scratchbuf, "kernel.");
858dc4f0af1Szrj 	while (i < num_kernel)
859dc4f0af1Szrj 	{
860dc4f0af1Szrj 	    strcpy(p, homogenize(kernel_names[i]+1));
861dc4f0af1Szrj 	    kernel_cidx[i++] = color_tag(scratchbuf);
862dc4f0af1Szrj 	}
863dc4f0af1Szrj     }
864dc4f0af1Szrj 
865dc4f0af1Szrj     /* color tags for memory */
866dc4f0af1Szrj     memory_cidx = (int *)malloc(num_memory * sizeof(int));
867dc4f0af1Szrj     i = 0;
868dc4f0af1Szrj     p = strcpyend(scratchbuf, "memory.");
869dc4f0af1Szrj     while (i < num_memory)
870dc4f0af1Szrj     {
871dc4f0af1Szrj 	strcpy(p, homogenize(memory_names[i]+1));
872dc4f0af1Szrj 	memory_cidx[i++] = color_tag(scratchbuf);
873dc4f0af1Szrj     }
874dc4f0af1Szrj 
875dc4f0af1Szrj     /* color tags for swap */
876dc4f0af1Szrj     if (num_swap > 0)
877dc4f0af1Szrj     {
878dc4f0af1Szrj 	swap_cidx = (int *)malloc(num_swap * sizeof(int));
879dc4f0af1Szrj 	i = 0;
880dc4f0af1Szrj 	p = strcpyend(scratchbuf, "swap.");
881dc4f0af1Szrj 	while (i < num_swap)
882dc4f0af1Szrj 	{
883dc4f0af1Szrj 	    strcpy(p, homogenize(swap_names[i]+1));
884dc4f0af1Szrj 	    swap_cidx[i++] = color_tag(scratchbuf);
885dc4f0af1Szrj 	}
886dc4f0af1Szrj     }
887dc4f0af1Szrj #endif
888dc4f0af1Szrj 
889dc4f0af1Szrj     /* return number of lines available (or error) */
890dc4f0af1Szrj     return(top_lines);
891dc4f0af1Szrj }
892dc4f0af1Szrj 
893dc4f0af1Szrj static void
pr_loadavg(double avg,int i)894dc4f0af1Szrj pr_loadavg(double avg, int i)
895dc4f0af1Szrj 
896dc4f0af1Szrj {
897dc4f0af1Szrj     int color = 0;
898dc4f0af1Szrj 
899dc4f0af1Szrj #ifdef ENABLE_COLOR
900dc4f0af1Szrj     color = color_test(load_cidx[i], (int)(avg * 100));
901dc4f0af1Szrj #endif
902dc4f0af1Szrj     display_fmt(x_loadave + X_LOADAVEWIDTH * i, y_loadave, color, 0,
903dc4f0af1Szrj 		avg < 10.0 ? " %5.2f" : " %5.1f", avg);
904dc4f0af1Szrj     display_write(-1, -1, 0, 0, (i < 2 ? "," : ";"));
905dc4f0af1Szrj }
906dc4f0af1Szrj 
907dc4f0af1Szrj void
i_loadave(int mpid,double * avenrun)908dc4f0af1Szrj i_loadave(int mpid, double *avenrun)
909dc4f0af1Szrj 
910dc4f0af1Szrj {
911dc4f0af1Szrj     register int i;
912dc4f0af1Szrj 
913dc4f0af1Szrj     /* mpid == -1 implies this system doesn't have an _mpid */
914dc4f0af1Szrj     if (mpid != -1)
915dc4f0af1Szrj     {
916dc4f0af1Szrj 	display_fmt(0, 0, 0, 0,
917dc4f0af1Szrj 		    "last pid: %5d;  load avg:", mpid);
918dc4f0af1Szrj 	x_loadave = X_LOADAVE;
919dc4f0af1Szrj     }
920dc4f0af1Szrj     else
921dc4f0af1Szrj     {
922dc4f0af1Szrj 	display_write(0, 0, 0, 0, "load averages:");
923dc4f0af1Szrj 	x_loadave = X_LOADAVE - X_LASTPIDWIDTH;
924dc4f0af1Szrj     }
925dc4f0af1Szrj     for (i = 0; i < 3; i++)
926dc4f0af1Szrj     {
927dc4f0af1Szrj 	pr_loadavg(avenrun[i], i);
928dc4f0af1Szrj     }
929dc4f0af1Szrj 
930dc4f0af1Szrj     lmpid = mpid;
931dc4f0af1Szrj }
932dc4f0af1Szrj 
933dc4f0af1Szrj void
u_loadave(int mpid,double * avenrun)934dc4f0af1Szrj u_loadave(int mpid, double *avenrun)
935dc4f0af1Szrj 
936dc4f0af1Szrj {
937dc4f0af1Szrj     register int i;
938dc4f0af1Szrj 
939dc4f0af1Szrj     if (mpid != -1)
940dc4f0af1Szrj     {
941dc4f0af1Szrj 	/* change screen only when value has really changed */
942dc4f0af1Szrj 	if (mpid != lmpid)
943dc4f0af1Szrj 	{
944dc4f0af1Szrj 	    display_fmt(x_lastpid, y_lastpid, 0, 0,
945dc4f0af1Szrj 			"%5d", mpid);
946dc4f0af1Szrj 	    lmpid = mpid;
947dc4f0af1Szrj 	}
948dc4f0af1Szrj     }
949dc4f0af1Szrj 
950dc4f0af1Szrj     /* display new load averages */
951dc4f0af1Szrj     for (i = 0; i < 3; i++)
952dc4f0af1Szrj     {
953dc4f0af1Szrj 	pr_loadavg(avenrun[i], i);
954dc4f0af1Szrj     }
955dc4f0af1Szrj }
956dc4f0af1Szrj 
957dc4f0af1Szrj static char minibar_buffer[64];
958dc4f0af1Szrj #define MINIBAR_WIDTH 20
959dc4f0af1Szrj 
960dc4f0af1Szrj void
i_minibar(int (* formatter)(char *,int))961dc4f0af1Szrj i_minibar(int (*formatter)(char *, int))
962dc4f0af1Szrj {
963dc4f0af1Szrj     (void)((*formatter)(minibar_buffer, MINIBAR_WIDTH));
964dc4f0af1Szrj 
965dc4f0af1Szrj     display_write(x_minibar, y_minibar, 0, 0, minibar_buffer);
966dc4f0af1Szrj }
967dc4f0af1Szrj 
968dc4f0af1Szrj void
u_minibar(int (* formatter)(char *,int))969dc4f0af1Szrj u_minibar(int (*formatter)(char *, int))
970dc4f0af1Szrj {
971dc4f0af1Szrj     (void)((*formatter)(minibar_buffer, MINIBAR_WIDTH));
972dc4f0af1Szrj 
973dc4f0af1Szrj     display_write(x_minibar, y_minibar, 0, 0, minibar_buffer);
974dc4f0af1Szrj }
975dc4f0af1Szrj 
976dc4f0af1Szrj static int uptime_days;
977dc4f0af1Szrj static int uptime_hours;
978dc4f0af1Szrj static int uptime_mins;
979dc4f0af1Szrj static int uptime_secs;
980dc4f0af1Szrj 
981dc4f0af1Szrj void
i_uptime(time_t uptime)982*da0d35cfSMatthew Dillon i_uptime(time_t uptime)
983dc4f0af1Szrj {
984dc4f0af1Szrj     uptime += 30;
985dc4f0af1Szrj     uptime_days = uptime / 86400;
986dc4f0af1Szrj     uptime %= 86400;
987dc4f0af1Szrj     uptime_hours = uptime / 3600;
988dc4f0af1Szrj     uptime %= 3600;
989dc4f0af1Szrj     uptime_mins = uptime / 60;
990dc4f0af1Szrj     uptime_secs = uptime % 60;
991dc4f0af1Szrj 
992dc4f0af1Szrj     /*
993dc4f0af1Szrj      *  Display the uptime.
994dc4f0af1Szrj      */
995dc4f0af1Szrj 
996dc4f0af1Szrj     display_fmt(x_uptime, y_uptime, 0, 0,
997dc4f0af1Szrj 		"  up %d+%02d:%02d:%02d",
998dc4f0af1Szrj 		uptime_days, uptime_hours, uptime_mins, uptime_secs);
999dc4f0af1Szrj }
1000dc4f0af1Szrj 
1001dc4f0af1Szrj void
u_uptime(time_t uptime)1002*da0d35cfSMatthew Dillon u_uptime(time_t uptime)
1003dc4f0af1Szrj {
1004*da0d35cfSMatthew Dillon     i_uptime(uptime);
1005dc4f0af1Szrj }
1006dc4f0af1Szrj 
1007dc4f0af1Szrj 
1008dc4f0af1Szrj void
i_timeofday(time_t * tod)1009dc4f0af1Szrj i_timeofday(time_t *tod)
1010dc4f0af1Szrj 
1011dc4f0af1Szrj {
1012dc4f0af1Szrj     /*
1013dc4f0af1Szrj      *  Display the current time.
1014dc4f0af1Szrj      *  "ctime" always returns a string that looks like this:
1015dc4f0af1Szrj      *
1016dc4f0af1Szrj      *	Sun Sep 16 01:03:52 1973
1017dc4f0af1Szrj      *  012345678901234567890123
1018dc4f0af1Szrj      *	          1         2
1019dc4f0af1Szrj      *
1020dc4f0af1Szrj      *  We want indices 11 thru 18 (length 8).
1021dc4f0af1Szrj      */
1022dc4f0af1Szrj 
1023dc4f0af1Szrj     int x;
1024dc4f0af1Szrj 
1025dc4f0af1Szrj     /* where on the screen do we start? */
1026dc4f0af1Szrj     x = (smart_terminal ? screen_width : 79) - 8;
1027dc4f0af1Szrj 
1028dc4f0af1Szrj     /* but don't bump in to uptime */
1029dc4f0af1Szrj     if (x < x_uptime + 19)
1030dc4f0af1Szrj     {
1031dc4f0af1Szrj 	x = x_uptime + 19;
1032dc4f0af1Szrj     }
1033dc4f0af1Szrj 
1034dc4f0af1Szrj     /* display it */
1035dc4f0af1Szrj     display_fmt(x, 0, 0, 1, "%-8.8s", &(ctime(tod)[11]));
1036dc4f0af1Szrj }
1037dc4f0af1Szrj 
1038dc4f0af1Szrj static int ltotal = 0;
1039dc4f0af1Szrj static int lthreads = 0;
1040dc4f0af1Szrj 
1041dc4f0af1Szrj /*
1042dc4f0af1Szrj  *  *_procstates(total, brkdn, names) - print the process summary line
1043dc4f0af1Szrj  */
1044dc4f0af1Szrj 
1045dc4f0af1Szrj 
1046dc4f0af1Szrj void
i_procstates(int total,int * brkdn,int threads)1047dc4f0af1Szrj i_procstates(int total, int *brkdn, int threads)
1048dc4f0af1Szrj 
1049dc4f0af1Szrj {
1050dc4f0af1Szrj     /* write current number of processes and remember the value */
1051dc4f0af1Szrj     display_fmt(0, y_procstate, 0, 0,
1052dc4f0af1Szrj 		"%d %s: ", total, threads ? "threads" : "processes");
1053dc4f0af1Szrj     ltotal = total;
1054dc4f0af1Szrj 
1055dc4f0af1Szrj     /* remember where the summary starts */
1056dc4f0af1Szrj     x_procstate = virt_x;
1057dc4f0af1Szrj 
1058dc4f0af1Szrj     if (total > 0)
1059dc4f0af1Szrj     {
1060dc4f0af1Szrj 	/* format and print the process state summary */
1061dc4f0af1Szrj 	summary_format(-1, -1, brkdn, procstate_names, NULL);
1062dc4f0af1Szrj 
1063dc4f0af1Szrj 	/* save the numbers for next time */
1064dc4f0af1Szrj 	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
1065dc4f0af1Szrj 	lthreads = threads;
1066dc4f0af1Szrj     }
1067dc4f0af1Szrj }
1068dc4f0af1Szrj 
1069dc4f0af1Szrj void
u_procstates(int total,int * brkdn,int threads)1070dc4f0af1Szrj u_procstates(int total, int *brkdn, int threads)
1071dc4f0af1Szrj 
1072dc4f0af1Szrj {
1073dc4f0af1Szrj     /* if threads state has changed, do a full update */
1074dc4f0af1Szrj     if (lthreads != threads)
1075dc4f0af1Szrj     {
1076dc4f0af1Szrj 	i_procstates(total, brkdn, threads);
1077dc4f0af1Szrj 	return;
1078dc4f0af1Szrj     }
1079dc4f0af1Szrj 
1080dc4f0af1Szrj     /* update number of processes only if it has changed */
1081dc4f0af1Szrj     if (ltotal != total)
1082dc4f0af1Szrj     {
1083dc4f0af1Szrj 	display_fmt(0, y_procstate, 0, 0,
1084dc4f0af1Szrj 		    "%d", total);
1085dc4f0af1Szrj 
1086dc4f0af1Szrj 	/* if number of digits differs, rewrite the label */
1087dc4f0af1Szrj 	if (digits(total) != digits(ltotal))
1088dc4f0af1Szrj 	{
1089dc4f0af1Szrj 	    display_fmt(-1, -1, 0, 0, " %s: ", threads ? "threads" : "processes");
1090dc4f0af1Szrj 	    x_procstate = virt_x;
1091dc4f0af1Szrj 	}
1092dc4f0af1Szrj 
1093dc4f0af1Szrj 	/* save new total */
1094dc4f0af1Szrj 	ltotal = total;
1095dc4f0af1Szrj     }
1096dc4f0af1Szrj 
1097dc4f0af1Szrj     /* see if any of the state numbers has changed */
1098dc4f0af1Szrj     if (total > 0 && memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
1099dc4f0af1Szrj     {
1100dc4f0af1Szrj 	/* format and update the line */
1101dc4f0af1Szrj 	summary_format(x_procstate, y_procstate, brkdn, procstate_names, NULL);
1102dc4f0af1Szrj 	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
1103dc4f0af1Szrj     }
1104dc4f0af1Szrj }
1105dc4f0af1Szrj 
1106dc4f0af1Szrj /*
1107dc4f0af1Szrj  *  *_cpustates(states, names) - print the cpu state percentages
1108dc4f0af1Szrj  */
1109dc4f0af1Szrj 
1110dc4f0af1Szrj /* cpustates_tag() calculates the correct tag to use to label the line */
1111dc4f0af1Szrj 
1112dc4f0af1Szrj char *
cpustates_tag()1113dc4f0af1Szrj cpustates_tag()
1114dc4f0af1Szrj 
1115dc4f0af1Szrj {
1116dc4f0af1Szrj     register char *use;
1117dc4f0af1Szrj 
1118dc4f0af1Szrj     static char *short_tag = "CPU: ";
1119dc4f0af1Szrj     static char *long_tag = "CPU states: ";
1120dc4f0af1Szrj 
1121dc4f0af1Szrj     /* if length + strlen(long_tag) >= screen_width, then we have to
1122dc4f0af1Szrj        use the shorter tag (we subtract 2 to account for ": ") */
1123dc4f0af1Szrj     if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
1124dc4f0af1Szrj     {
1125dc4f0af1Szrj 	use = short_tag;
1126dc4f0af1Szrj     }
1127dc4f0af1Szrj     else
1128dc4f0af1Szrj     {
1129dc4f0af1Szrj 	use = long_tag;
1130dc4f0af1Szrj     }
1131dc4f0af1Szrj 
1132dc4f0af1Szrj     /* set x_cpustates accordingly then return result */
1133dc4f0af1Szrj     x_cpustates = strlen(use);
1134dc4f0af1Szrj     return(use);
1135dc4f0af1Szrj }
1136dc4f0af1Szrj 
1137dc4f0af1Szrj void
i_cpustates(int * states)1138dc4f0af1Szrj i_cpustates(int *states)
1139dc4f0af1Szrj 
1140dc4f0af1Szrj {
1141dc4f0af1Szrj     int value;
1142dc4f0af1Szrj     char **names;
1143dc4f0af1Szrj     char *thisname;
1144dc4f0af1Szrj     int *colp;
1145dc4f0af1Szrj     int color = 0;
1146dc4f0af1Szrj     int cpu;
1147dc4f0af1Szrj #ifdef ENABLE_COLOR
1148dc4f0af1Szrj     int *cidx = cpustate_cidx;
1149dc4f0af1Szrj #endif
1150dc4f0af1Szrj 
1151dc4f0af1Szrj     /* initialize */
1152dc4f0af1Szrj     names = cpustate_names;
1153dc4f0af1Szrj     colp = cpustate_columns;
1154dc4f0af1Szrj 
1155dc4f0af1Szrj     /* print tag */
1156dc4f0af1Szrj     if (enable_ncpus !=0 && n_cpus > 1) {
1157dc4f0af1Szrj 		for (cpu = 0; cpu < n_cpus; ++cpu) {
1158dc4f0af1Szrj 			int y_pos = y_cpustates;
1159dc4f0af1Szrj 			y_pos = y_pos + cpu;
1160dc4f0af1Szrj 			colp = cpustate_columns;
1161dc4f0af1Szrj 			names = cpustate_names;
1162dc4f0af1Szrj 			display_write(0, y_cpustates+cpu, 0, 0, cpustates_tag());
1163dc4f0af1Szrj 
1164dc4f0af1Szrj 			/* now walk thru the names and print the line */
1165dc4f0af1Szrj 			while ((thisname = *names++) != NULL) {
1166dc4f0af1Szrj 				if (*thisname != '\0') {
1167dc4f0af1Szrj 					/* retrieve the value and remember it */
1168dc4f0af1Szrj 					value = *states;
1169dc4f0af1Szrj 
1170dc4f0af1Szrj #ifdef ENABLE_COLOR
1171dc4f0af1Szrj 					/* determine color number to use */
1172dc4f0af1Szrj 					color = color_test(*cidx++, value/10);
1173dc4f0af1Szrj #endif
1174dc4f0af1Szrj 					/* if percentage is >= 1000, print it as 100% */
1175dc4f0af1Szrj 					display_fmt(x_cpustates + *colp, y_pos,
1176dc4f0af1Szrj 						color, 0,
1177dc4f0af1Szrj 						(value >= 1000 ? "%4.0f%% %s%s" : "%4.1f%% %s%s"),
1178dc4f0af1Szrj 						((float)value)/10.,
1179dc4f0af1Szrj 						thisname,
1180dc4f0af1Szrj 						*names != NULL ? ", " : "");
1181dc4f0af1Szrj 
1182dc4f0af1Szrj 				}
1183dc4f0af1Szrj 				/* increment */
1184dc4f0af1Szrj 				colp++;
1185dc4f0af1Szrj 				states++;
1186dc4f0af1Szrj 			}
1187dc4f0af1Szrj 			/* copy over values into "last" array */
1188dc4f0af1Szrj 			memcpy(lcpustates, states, num_cpustates * sizeof(int));
1189dc4f0af1Szrj 		}
1190dc4f0af1Szrj     } else {
1191dc4f0af1Szrj     display_write(0, y_cpustates, 0, 0, cpustates_tag());
1192dc4f0af1Szrj 
1193dc4f0af1Szrj     /* now walk thru the names and print the line */
1194dc4f0af1Szrj     while ((thisname = *names++) != NULL)
1195dc4f0af1Szrj     {
1196dc4f0af1Szrj 	if (*thisname != '\0')
1197dc4f0af1Szrj 	{
1198dc4f0af1Szrj 	    /* retrieve the value and remember it */
1199dc4f0af1Szrj 	    value = *states;
1200dc4f0af1Szrj 
1201dc4f0af1Szrj #ifdef ENABLE_COLOR
1202dc4f0af1Szrj 	    /* determine color number to use */
1203dc4f0af1Szrj 	    color = color_test(*cidx++, value/10);
1204dc4f0af1Szrj #endif
1205dc4f0af1Szrj 
1206dc4f0af1Szrj 	    /* if percentage is >= 1000, print it as 100% */
1207dc4f0af1Szrj 	    display_fmt(x_cpustates + *colp, y_cpustates,
1208dc4f0af1Szrj 			color, 0,
1209dc4f0af1Szrj 			(value >= 1000 ? "%4.0f%% %s%s" : "%4.1f%% %s%s"),
1210dc4f0af1Szrj 			((float)value)/10.,
1211dc4f0af1Szrj 			thisname,
1212dc4f0af1Szrj 			*names != NULL ? ", " : "");
1213dc4f0af1Szrj 
1214dc4f0af1Szrj 	}
1215dc4f0af1Szrj 	/* increment */
1216dc4f0af1Szrj 	colp++;
1217dc4f0af1Szrj 	states++;
1218dc4f0af1Szrj     }
1219dc4f0af1Szrj 
1220dc4f0af1Szrj     /* copy over values into "last" array */
1221dc4f0af1Szrj     memcpy(lcpustates, states, num_cpustates * sizeof(int));
1222dc4f0af1Szrj  }
1223dc4f0af1Szrj 
1224dc4f0af1Szrj }
1225dc4f0af1Szrj 
1226dc4f0af1Szrj void
u_cpustates(int * states)1227dc4f0af1Szrj u_cpustates(int *states)
1228dc4f0af1Szrj 
1229dc4f0af1Szrj {
1230dc4f0af1Szrj     int value;
1231dc4f0af1Szrj     char **names = cpustate_names;
1232dc4f0af1Szrj     char *thisname;
1233dc4f0af1Szrj     int *lp;
1234dc4f0af1Szrj     int *colp;
1235dc4f0af1Szrj     int color = 0;
1236dc4f0af1Szrj     int cpu;
1237dc4f0af1Szrj #ifdef ENABLE_COLOR
1238dc4f0af1Szrj     int *cidx = cpustate_cidx;
1239dc4f0af1Szrj #endif
1240dc4f0af1Szrj 
1241dc4f0af1Szrj 
1242dc4f0af1Szrj     if (enable_ncpus != 0 && n_cpus > 1 ) {
1243dc4f0af1Szrj 		for (cpu = 0; cpu < n_cpus; ++cpu) {
1244dc4f0af1Szrj 			lp = lcpustates;
1245dc4f0af1Szrj 			int y_pos = y_cpustates;
1246dc4f0af1Szrj 			y_pos = y_pos + cpu;
1247dc4f0af1Szrj 			colp = cpustate_columns;
1248dc4f0af1Szrj 			char **names = cpustate_names;
1249dc4f0af1Szrj 			/* we could be much more optimal about this */
1250dc4f0af1Szrj 			while ((thisname = *names++) != NULL) {
1251dc4f0af1Szrj 				if (*thisname != '\0') {
1252dc4f0af1Szrj 						/* yes, change it */
1253dc4f0af1Szrj 						/* retrieve value and remember it */
1254dc4f0af1Szrj 						value = *states;
1255dc4f0af1Szrj 
1256dc4f0af1Szrj #ifdef ENABLE_COLOR
1257dc4f0af1Szrj 						/* determine color number to use */
1258dc4f0af1Szrj 						color = color_test(*cidx, value/10);
1259dc4f0af1Szrj #endif
1260dc4f0af1Szrj 						/* if percentage is >= 1000, print it as 100% */
1261dc4f0af1Szrj 						display_fmt(x_cpustates + *colp, y_pos, color, 0,
1262dc4f0af1Szrj 									(value >= 1000 ? "%4.0f" : "%4.1f"),
1263dc4f0af1Szrj 									((double)value)/10.);
1264dc4f0af1Szrj 
1265dc4f0af1Szrj #ifdef ENABLE_COLOR
1266dc4f0af1Szrj 					cidx++;
1267dc4f0af1Szrj #endif
1268dc4f0af1Szrj 				}
1269dc4f0af1Szrj 				/* increment and move on */
1270dc4f0af1Szrj 				lp++;
1271dc4f0af1Szrj 				states++;
1272dc4f0af1Szrj 				colp++;
1273dc4f0af1Szrj 			}
1274dc4f0af1Szrj 		}
1275dc4f0af1Szrj     } else {
1276dc4f0af1Szrj     lp = lcpustates;
1277dc4f0af1Szrj     colp = cpustate_columns;
1278dc4f0af1Szrj 
1279dc4f0af1Szrj     /* we could be much more optimal about this */
1280dc4f0af1Szrj     while ((thisname = *names++) != NULL)
1281dc4f0af1Szrj     {
1282dc4f0af1Szrj 	if (*thisname != '\0')
1283dc4f0af1Szrj 	{
1284dc4f0af1Szrj 	    /* did the value change since last time? */
1285dc4f0af1Szrj 	    if (*lp != *states)
1286dc4f0af1Szrj 	    {
1287dc4f0af1Szrj 		/* yes, change it */
1288dc4f0af1Szrj 		/* retrieve value and remember it */
1289dc4f0af1Szrj 		value = *states;
1290dc4f0af1Szrj 
1291dc4f0af1Szrj #ifdef ENABLE_COLOR
1292dc4f0af1Szrj 		/* determine color number to use */
1293dc4f0af1Szrj 		color = color_test(*cidx, value/10);
1294dc4f0af1Szrj #endif
1295dc4f0af1Szrj 
1296dc4f0af1Szrj 		/* if percentage is >= 1000, print it as 100% */
1297dc4f0af1Szrj 		display_fmt(x_cpustates + *colp, y_cpustates, color, 0,
1298dc4f0af1Szrj 			    (value >= 1000 ? "%4.0f" : "%4.1f"),
1299dc4f0af1Szrj 			    ((double)value)/10.);
1300dc4f0af1Szrj 
1301dc4f0af1Szrj 		/* remember it for next time */
1302dc4f0af1Szrj 		*lp = value;
1303dc4f0af1Szrj 	    }
1304dc4f0af1Szrj #ifdef ENABLE_COLOR
1305dc4f0af1Szrj 	    cidx++;
1306dc4f0af1Szrj #endif
1307dc4f0af1Szrj 	}
1308dc4f0af1Szrj 
1309dc4f0af1Szrj 	/* increment and move on */
1310dc4f0af1Szrj 	lp++;
1311dc4f0af1Szrj 	states++;
1312dc4f0af1Szrj 	colp++;
1313dc4f0af1Szrj     }
1314dc4f0af1Szrj   }
1315dc4f0af1Szrj }
1316dc4f0af1Szrj 
1317dc4f0af1Szrj void
z_cpustates()1318dc4f0af1Szrj z_cpustates()
1319dc4f0af1Szrj 
1320dc4f0af1Szrj {
1321dc4f0af1Szrj     register int i = 0;
1322dc4f0af1Szrj     register char **names = cpustate_names;
1323dc4f0af1Szrj     register char *thisname;
1324dc4f0af1Szrj     register int *lp;
1325dc4f0af1Szrj     int cpu;
1326dc4f0af1Szrj 
1327dc4f0af1Szrj     /* print tag */
1328dc4f0af1Szrj 	if (enable_ncpus != 0 && n_cpus > 1) {
1329dc4f0af1Szrj 		for (cpu = 0; cpu < n_cpus; ++cpu) {
1330dc4f0af1Szrj 			display_write(0, y_cpustates + cpu, 0, 0, cpustates_tag());
1331dc4f0af1Szrj 			char **names = cpustate_names;
1332dc4f0af1Szrj 			i = 0;
1333dc4f0af1Szrj 			while ((thisname = *names++) != NULL) {
1334dc4f0af1Szrj 				if (*thisname != '\0') {
1335dc4f0af1Szrj 					display_fmt(-1, -1, 0, 0, "%s    %% %s", i++ == 0 ? "" : ", ",
1336dc4f0af1Szrj 						thisname);
1337dc4f0af1Szrj 				}
1338dc4f0af1Szrj 			}
1339dc4f0af1Szrj 			/* fill the "last" array with all -1s, to insure correct updating */
1340dc4f0af1Szrj 			lp = lcpustates;
1341dc4f0af1Szrj 			i = num_cpustates;
1342dc4f0af1Szrj 			while (--i >= 0) {
1343dc4f0af1Szrj 				*lp++ = -1;
1344dc4f0af1Szrj 			}
1345dc4f0af1Szrj 		}
1346dc4f0af1Szrj 	} else {
1347dc4f0af1Szrj     display_write(0, y_cpustates, 0, 0, cpustates_tag());
1348dc4f0af1Szrj 
1349dc4f0af1Szrj     while ((thisname = *names++) != NULL)
1350dc4f0af1Szrj     {
1351dc4f0af1Szrj 	if (*thisname != '\0')
1352dc4f0af1Szrj 	{
1353dc4f0af1Szrj 	    display_fmt(-1, -1, 0, 0, "%s    %% %s", i++ == 0 ? "" : ", ",
1354dc4f0af1Szrj 			thisname);
1355dc4f0af1Szrj 	}
1356dc4f0af1Szrj     }
1357dc4f0af1Szrj 
1358dc4f0af1Szrj     /* fill the "last" array with all -1s, to insure correct updating */
1359dc4f0af1Szrj     lp = lcpustates;
1360dc4f0af1Szrj     i = num_cpustates;
1361dc4f0af1Szrj     while (--i >= 0)
1362dc4f0af1Szrj     {
1363dc4f0af1Szrj 	*lp++ = -1;
1364dc4f0af1Szrj     }
1365dc4f0af1Szrj   }
1366dc4f0af1Szrj }
1367dc4f0af1Szrj 
1368dc4f0af1Szrj /*
1369dc4f0af1Szrj  *  *_kernel(stats) - print "Kernel: " followed by the kernel summary string
1370dc4f0af1Szrj  *
1371dc4f0af1Szrj  *  Assumptions:  cursor is on "lastline", the previous line
1372dc4f0af1Szrj  */
1373dc4f0af1Szrj 
1374dc4f0af1Szrj void
i_kernel(int * stats)1375dc4f0af1Szrj i_kernel(int *stats)
1376dc4f0af1Szrj 
1377dc4f0af1Szrj {
1378dc4f0af1Szrj     if (num_kernel > 0)
1379dc4f0af1Szrj     {
1380dc4f0af1Szrj 	display_write(0, y_kernel, 0, 0, "Kernel: ");
1381dc4f0af1Szrj 
1382dc4f0af1Szrj 	/* format and print the kernel summary */
1383dc4f0af1Szrj 	summary_format(x_kernel, y_kernel, stats, kernel_names, kernel_cidx);
1384dc4f0af1Szrj     }
1385dc4f0af1Szrj }
1386dc4f0af1Szrj 
1387dc4f0af1Szrj void
u_kernel(int * stats)1388dc4f0af1Szrj u_kernel(int *stats)
1389dc4f0af1Szrj 
1390dc4f0af1Szrj {
1391dc4f0af1Szrj     if (num_kernel > 0)
1392dc4f0af1Szrj     {
1393dc4f0af1Szrj 	/* format the new line */
1394dc4f0af1Szrj 	summary_format(x_kernel, y_kernel, stats, kernel_names, kernel_cidx);
1395dc4f0af1Szrj     }
1396dc4f0af1Szrj }
1397dc4f0af1Szrj 
1398dc4f0af1Szrj /*
1399dc4f0af1Szrj  *  *_memory(stats) - print "Memory: " followed by the memory summary string
1400dc4f0af1Szrj  *
1401dc4f0af1Szrj  *  Assumptions:  cursor is on "lastline", the previous line
1402dc4f0af1Szrj  */
1403dc4f0af1Szrj 
1404dc4f0af1Szrj void
i_memory(long * stats)1405dc4f0af1Szrj i_memory(long *stats)
1406dc4f0af1Szrj 
1407dc4f0af1Szrj {
1408dc4f0af1Szrj     display_write(0, y_mem, 0, 0, "Memory: ");
1409dc4f0af1Szrj 
1410dc4f0af1Szrj     /* format and print the memory summary */
1411dc4f0af1Szrj     summary_format_memory(x_mem, y_mem, stats, memory_names, memory_cidx);
1412dc4f0af1Szrj }
1413dc4f0af1Szrj 
1414dc4f0af1Szrj void
u_memory(long * stats)1415dc4f0af1Szrj u_memory(long *stats)
1416dc4f0af1Szrj 
1417dc4f0af1Szrj {
1418dc4f0af1Szrj     /* format the new line */
1419dc4f0af1Szrj     summary_format_memory(x_mem, y_mem, stats, memory_names, memory_cidx);
1420dc4f0af1Szrj }
1421dc4f0af1Szrj 
1422dc4f0af1Szrj /*
1423dc4f0af1Szrj  *  *_swap(stats) - print "Swap: " followed by the swap summary string
1424dc4f0af1Szrj  *
1425dc4f0af1Szrj  *  Assumptions:  cursor is on "lastline", the previous line
1426dc4f0af1Szrj  *
1427dc4f0af1Szrj  *  These functions only print something when num_swap > 0
1428dc4f0af1Szrj  */
1429dc4f0af1Szrj 
1430dc4f0af1Szrj void
i_swap(long * stats)1431dc4f0af1Szrj i_swap(long *stats)
1432dc4f0af1Szrj 
1433dc4f0af1Szrj {
1434dc4f0af1Szrj     if (num_swap > 0)
1435dc4f0af1Szrj     {
1436dc4f0af1Szrj 	/* print the tag */
1437dc4f0af1Szrj 	display_write(0, y_swap, 0, 0, "Swap: ");
1438dc4f0af1Szrj 
1439dc4f0af1Szrj 	/* format and print the swap summary */
1440dc4f0af1Szrj 	summary_format_memory(x_swap, y_swap, stats, swap_names, swap_cidx);
1441dc4f0af1Szrj     }
1442dc4f0af1Szrj }
1443dc4f0af1Szrj 
1444dc4f0af1Szrj void
u_swap(long * stats)1445dc4f0af1Szrj u_swap(long *stats)
1446dc4f0af1Szrj 
1447dc4f0af1Szrj {
1448dc4f0af1Szrj     if (num_swap > 0)
1449dc4f0af1Szrj     {
1450dc4f0af1Szrj 	/* format the new line */
1451dc4f0af1Szrj 	summary_format_memory(x_swap, y_swap, stats, swap_names, swap_cidx);
1452dc4f0af1Szrj     }
1453dc4f0af1Szrj }
1454dc4f0af1Szrj 
1455dc4f0af1Szrj /*
1456dc4f0af1Szrj  *  *_message() - print the next pending message line, or erase the one
1457dc4f0af1Szrj  *                that is there.
1458dc4f0af1Szrj  *
1459dc4f0af1Szrj  *  Note that u_message is (currently) the same as i_message.
1460dc4f0af1Szrj  *
1461dc4f0af1Szrj  *  Assumptions:  lastline is consistent
1462dc4f0af1Szrj  */
1463dc4f0af1Szrj 
1464dc4f0af1Szrj /*
1465dc4f0af1Szrj  *  i_message is funny because it gets its message asynchronously (with
1466dc4f0af1Szrj  *	respect to screen updates).  Messages are taken out of the
1467dc4f0af1Szrj  *      circular message_buf and displayed one at a time.
1468dc4f0af1Szrj  */
1469dc4f0af1Szrj 
1470dc4f0af1Szrj void
i_message(struct timeval * now)1471dc4f0af1Szrj i_message(struct timeval *now)
1472dc4f0af1Szrj 
1473dc4f0af1Szrj {
1474dc4f0af1Szrj     struct timeval my_now;
1475dc4f0af1Szrj     int i = 0;
1476dc4f0af1Szrj 
1477dc4f0af1Szrj     dprintf("i_message(%08x)\n", now);
1478dc4f0af1Szrj 
1479dc4f0af1Szrj     /* if now is NULL we have to get it ourselves */
1480dc4f0af1Szrj     if (now == NULL)
1481dc4f0af1Szrj     {
1482dc4f0af1Szrj 	time_get(&my_now);
1483dc4f0af1Szrj 	now = &my_now;
1484dc4f0af1Szrj     }
1485dc4f0af1Szrj 
1486dc4f0af1Szrj     /* now that we have been called, messages no longer need to be held */
1487dc4f0af1Szrj     message_hold = 0;
1488dc4f0af1Szrj 
1489dc4f0af1Szrj     dprintf("i_message: now %d, message_time %d\n",
1490dc4f0af1Szrj 	    now->tv_sec, message_time.tv_sec);
1491dc4f0af1Szrj 
1492dc4f0af1Szrj     if (smart_terminal)
1493dc4f0af1Szrj     {
1494dc4f0af1Szrj 	/* is it time to change the message? */
1495dc4f0af1Szrj 	if (timercmp(now, &message_time, > ))
1496dc4f0af1Szrj 	{
1497dc4f0af1Szrj 	    /* yes, free the current message */
1498dc4f0af1Szrj 	    dprintf("i_message: timer expired\n");
1499dc4f0af1Szrj 	    if (message_current != NULL)
1500dc4f0af1Szrj 	    {
1501dc4f0af1Szrj 		free(message_current);
1502dc4f0af1Szrj 		message_current = NULL;
1503dc4f0af1Szrj 	    }
1504dc4f0af1Szrj 
1505dc4f0af1Szrj 	    /* is there a new message to be displayed? */
1506dc4f0af1Szrj 	    if (message_first != message_last)
1507dc4f0af1Szrj 	    {
1508dc4f0af1Szrj 		/* move index to next message */
1509dc4f0af1Szrj 		if (++message_first == MAX_MESSAGES) message_first = 0;
1510dc4f0af1Szrj 
1511dc4f0af1Szrj 		/* make the next message the current one */
1512dc4f0af1Szrj 		message_current = message_buf[message_first];
1513dc4f0af1Szrj 
1514dc4f0af1Szrj 		/* show it */
1515dc4f0af1Szrj 		dprintf("i_message: showing \"%s\"\n", message_current);
1516dc4f0af1Szrj 		display_move(0, y_message);
1517dc4f0af1Szrj 		screen_standout(message_current);
1518dc4f0af1Szrj 		i = strlen(message_current);
1519dc4f0af1Szrj 
1520dc4f0af1Szrj 		/* set the expiration timer */
1521dc4f0af1Szrj 		message_time = *now;
1522dc4f0af1Szrj 		message_time.tv_sec += MESSAGE_DISPLAY_TIME;
1523dc4f0af1Szrj 
1524dc4f0af1Szrj 		/* clear the rest of the line */
1525dc4f0af1Szrj 		screen_cleareol(message_length - i);
1526dc4f0af1Szrj 		putchar('\r');
1527dc4f0af1Szrj 		message_length = i;
1528dc4f0af1Szrj 	    }
1529dc4f0af1Szrj 	    else
1530dc4f0af1Szrj 	    {
1531dc4f0af1Szrj 		/* just clear what was there before, if anything */
1532dc4f0af1Szrj 		if (message_length > 0)
1533dc4f0af1Szrj 		{
1534dc4f0af1Szrj 		    display_move(0, y_message);
1535dc4f0af1Szrj 		    screen_cleareol(message_length);
1536dc4f0af1Szrj 		    putchar('\r');
1537dc4f0af1Szrj 		    message_length = 0;
1538dc4f0af1Szrj 		}
1539dc4f0af1Szrj 	    }
1540dc4f0af1Szrj 	}
1541dc4f0af1Szrj     }
1542dc4f0af1Szrj }
1543dc4f0af1Szrj 
1544dc4f0af1Szrj void
u_message(struct timeval * now)1545dc4f0af1Szrj u_message(struct timeval *now)
1546dc4f0af1Szrj 
1547dc4f0af1Szrj {
1548dc4f0af1Szrj     i_message(now);
1549dc4f0af1Szrj }
1550dc4f0af1Szrj 
1551dc4f0af1Szrj static int header_length;
1552dc4f0af1Szrj 
1553dc4f0af1Szrj /*
1554dc4f0af1Szrj  *  *_header(text) - print the header for the process area
1555dc4f0af1Szrj  *
1556dc4f0af1Szrj  *  Assumptions:  cursor is on the previous line and lastline is consistent
1557dc4f0af1Szrj  */
1558dc4f0af1Szrj 
1559dc4f0af1Szrj void
i_header(char * text)1560dc4f0af1Szrj i_header(char *text)
1561dc4f0af1Szrj 
1562dc4f0af1Szrj {
1563dc4f0af1Szrj     int header_color = 0;
1564dc4f0af1Szrj 
1565dc4f0af1Szrj #ifdef ENABLE_COLOR
1566dc4f0af1Szrj     header_color = color_test(header_cidx, 0);
1567dc4f0af1Szrj #endif
1568dc4f0af1Szrj     header_length = strlen(text);
1569dc4f0af1Szrj     if (header_status)
1570dc4f0af1Szrj     {
1571dc4f0af1Szrj 	display_write(x_header, y_header, header_color, 1, text);
1572dc4f0af1Szrj     }
1573dc4f0af1Szrj }
1574dc4f0af1Szrj 
1575dc4f0af1Szrj /*ARGSUSED*/
1576dc4f0af1Szrj void
u_header(char * text)1577dc4f0af1Szrj u_header(char *text)
1578dc4f0af1Szrj 
1579dc4f0af1Szrj {
1580dc4f0af1Szrj     int header_color = 0;
1581dc4f0af1Szrj 
1582dc4f0af1Szrj #ifdef ENABLE_COLOR
1583dc4f0af1Szrj     header_color = color_test(header_cidx, 0);
1584dc4f0af1Szrj #endif
1585dc4f0af1Szrj     display_write(x_header, y_header, header_color, 1,
1586dc4f0af1Szrj 		  header_status ? text : "");
1587dc4f0af1Szrj }
1588dc4f0af1Szrj 
1589dc4f0af1Szrj /*
1590dc4f0af1Szrj  *  *_process(line, thisline) - print one process line
1591dc4f0af1Szrj  *
1592dc4f0af1Szrj  *  Assumptions:  lastline is consistent
1593dc4f0af1Szrj  */
1594dc4f0af1Szrj 
1595dc4f0af1Szrj void
i_process(int line,char * thisline)1596dc4f0af1Szrj i_process(int line, char *thisline)
1597dc4f0af1Szrj 
1598dc4f0af1Szrj {
1599dc4f0af1Szrj     /* truncate the line to conform to our current screen width */
1600dc4f0af1Szrj     thisline[display_width] = '\0';
1601dc4f0af1Szrj 
1602dc4f0af1Szrj     /* write the line out */
1603dc4f0af1Szrj     display_write(0, y_procs + line, 0, 1, thisline);
1604dc4f0af1Szrj }
1605dc4f0af1Szrj 
1606dc4f0af1Szrj void
u_process(int line,char * new_line)1607dc4f0af1Szrj u_process(int line, char *new_line)
1608dc4f0af1Szrj 
1609dc4f0af1Szrj {
1610dc4f0af1Szrj     i_process(line, new_line);
1611dc4f0af1Szrj }
1612dc4f0af1Szrj 
1613dc4f0af1Szrj void
i_endscreen()1614dc4f0af1Szrj i_endscreen()
1615dc4f0af1Szrj 
1616dc4f0af1Szrj {
1617dc4f0af1Szrj     if (smart_terminal)
1618dc4f0af1Szrj     {
1619dc4f0af1Szrj 	/* move the cursor to a pleasant place */
1620dc4f0af1Szrj 	display_move(x_idlecursor, y_idlecursor);
1621dc4f0af1Szrj     }
1622dc4f0af1Szrj     else
1623dc4f0af1Szrj     {
1624dc4f0af1Szrj 	/* separate this display from the next with some vertical room */
1625dc4f0af1Szrj 	fputs("\n\n", stdout);
1626dc4f0af1Szrj     }
1627dc4f0af1Szrj     fflush(stdout);
1628dc4f0af1Szrj }
1629dc4f0af1Szrj 
1630dc4f0af1Szrj void
u_endscreen()1631dc4f0af1Szrj u_endscreen()
1632dc4f0af1Szrj 
1633dc4f0af1Szrj {
1634dc4f0af1Szrj     if (smart_terminal)
1635dc4f0af1Szrj     {
1636dc4f0af1Szrj 	/* clear-to-end the display */
1637dc4f0af1Szrj 	display_cte();
1638dc4f0af1Szrj 
1639dc4f0af1Szrj 	/* move the cursor to a pleasant place */
1640dc4f0af1Szrj 	display_move(x_idlecursor, y_idlecursor);
1641dc4f0af1Szrj 	fflush(stdout);
1642dc4f0af1Szrj     }
1643dc4f0af1Szrj     else
1644dc4f0af1Szrj     {
1645dc4f0af1Szrj 	/* separate this display from the next with some vertical room */
1646dc4f0af1Szrj 	fputs("\n\n", stdout);
1647dc4f0af1Szrj     }
1648dc4f0af1Szrj }
1649dc4f0af1Szrj 
1650dc4f0af1Szrj void
display_header(int t)1651dc4f0af1Szrj display_header(int t)
1652dc4f0af1Szrj 
1653dc4f0af1Szrj {
1654dc4f0af1Szrj     header_status = t != 0;
1655dc4f0af1Szrj }
1656dc4f0af1Szrj 
1657dc4f0af1Szrj void
message_mark()1658dc4f0af1Szrj message_mark()
1659dc4f0af1Szrj 
1660dc4f0af1Szrj {
1661dc4f0af1Szrj     message_barrier = Yes;
1662dc4f0af1Szrj }
1663dc4f0af1Szrj 
1664dc4f0af1Szrj void
message_expire()1665dc4f0af1Szrj message_expire()
1666dc4f0af1Szrj 
1667dc4f0af1Szrj {
1668dc4f0af1Szrj     message_time.tv_sec = 0;
1669dc4f0af1Szrj     message_time.tv_usec = 0;
1670dc4f0af1Szrj }
1671dc4f0af1Szrj 
1672dc4f0af1Szrj void
message_flush()1673dc4f0af1Szrj message_flush()
1674dc4f0af1Szrj 
1675dc4f0af1Szrj {
1676dc4f0af1Szrj     message_first = message_last;
1677dc4f0af1Szrj     message_time.tv_sec = 0;
1678dc4f0af1Szrj     message_time.tv_usec = 0;
1679dc4f0af1Szrj }
1680dc4f0af1Szrj 
1681dc4f0af1Szrj /*
1682dc4f0af1Szrj  * void new_message_v(char *msgfmt, va_list ap)
1683dc4f0af1Szrj  *
1684dc4f0af1Szrj  * Display a message in the message area.  This function takes a va_list for
1685dc4f0af1Szrj  * the arguments.  Safe to call before display_init.  This function only
1686dc4f0af1Szrj  * queues a message for display, and allowed for multiple messages to be
1687dc4f0af1Szrj  * queued.  The i_message function drains the queue and actually writes the
1688dc4f0af1Szrj  * messages on the display.
1689dc4f0af1Szrj  */
1690dc4f0af1Szrj 
1691dc4f0af1Szrj 
1692dc4f0af1Szrj void
new_message_v(char * msgfmt,va_list ap)1693dc4f0af1Szrj new_message_v(char *msgfmt, va_list ap)
1694dc4f0af1Szrj 
1695dc4f0af1Szrj {
1696dc4f0af1Szrj     int i;
1697dc4f0af1Szrj     int empty;
1698dc4f0af1Szrj     char msg[MAX_COLS];
1699dc4f0af1Szrj 
1700dc4f0af1Szrj     /* if message_barrier is active, remove all pending messages */
1701dc4f0af1Szrj     if (message_barrier)
1702dc4f0af1Szrj     {
1703dc4f0af1Szrj 	message_flush();
1704dc4f0af1Szrj 	message_barrier = No;
1705dc4f0af1Szrj     }
1706dc4f0af1Szrj 
1707dc4f0af1Szrj     /* first, format the message */
1708dc4f0af1Szrj     (void) vsnprintf(msg, sizeof(msg), msgfmt, ap);
1709dc4f0af1Szrj 
1710dc4f0af1Szrj     /* where in the buffer will it go? */
1711dc4f0af1Szrj     i = message_last + 1;
1712dc4f0af1Szrj     if (i >= MAX_MESSAGES) i = 0;
1713dc4f0af1Szrj 
1714dc4f0af1Szrj     /* make sure the buffer is not full */
1715dc4f0af1Szrj     if (i != message_first)
1716dc4f0af1Szrj     {
1717dc4f0af1Szrj 	/* insert it in to message_buf */
1718dc4f0af1Szrj 	message_buf[i] = strdup(msg);
1719dc4f0af1Szrj 	dprintf("new_message_v: new message inserted in slot %d\n", i);
1720dc4f0af1Szrj 
1721dc4f0af1Szrj 	/* remember if the buffer is empty and set the index */
1722dc4f0af1Szrj 	empty = message_last == message_first;
1723dc4f0af1Szrj 	message_last = i;
1724dc4f0af1Szrj 
1725dc4f0af1Szrj 	/* is message_buf otherwise empty and have we started displaying? */
1726dc4f0af1Szrj 	if (empty && !message_hold)
1727dc4f0af1Szrj 	{
1728dc4f0af1Szrj 	    /* we can display the message now */
1729dc4f0af1Szrj 	    i_message(NULL);
1730dc4f0af1Szrj 	}
1731dc4f0af1Szrj     }
1732dc4f0af1Szrj }
1733dc4f0af1Szrj 
1734dc4f0af1Szrj /*
1735dc4f0af1Szrj  * void new_message(int type, char *msgfmt, ...)
1736dc4f0af1Szrj  *
1737dc4f0af1Szrj  * Display a message in the message area.  It is safe to call this function
1738dc4f0af1Szrj  * before display_init.  Messages logged before the display is drawn will be
1739dc4f0af1Szrj  * held and displayed later.
1740dc4f0af1Szrj  */
1741dc4f0af1Szrj 
1742dc4f0af1Szrj void
new_message(char * msgfmt,...)1743dc4f0af1Szrj new_message(char *msgfmt, ...)
1744dc4f0af1Szrj 
1745dc4f0af1Szrj {
1746dc4f0af1Szrj     va_list ap;
1747dc4f0af1Szrj 
1748dc4f0af1Szrj     va_start(ap, msgfmt);
1749dc4f0af1Szrj     new_message_v(msgfmt, ap);
1750dc4f0af1Szrj     va_end(ap);
1751dc4f0af1Szrj }
1752dc4f0af1Szrj 
1753dc4f0af1Szrj /*
1754dc4f0af1Szrj  * void message_error(char *msgfmt, ...)
1755dc4f0af1Szrj  *
1756dc4f0af1Szrj  * Put an error message in the message area.  It is safe to call this function
1757dc4f0af1Szrj  * before display_init.  Messages logged before the display is drawn will be
1758dc4f0af1Szrj  * held and displayed later.
1759dc4f0af1Szrj  */
1760dc4f0af1Szrj 
1761dc4f0af1Szrj void
message_error(char * msgfmt,...)1762dc4f0af1Szrj message_error(char *msgfmt, ...)
1763dc4f0af1Szrj 
1764dc4f0af1Szrj {
1765dc4f0af1Szrj     va_list ap;
1766dc4f0af1Szrj 
1767dc4f0af1Szrj     va_start(ap, msgfmt);
1768dc4f0af1Szrj     new_message_v(msgfmt, ap);
1769dc4f0af1Szrj     fflush(stdout);
1770dc4f0af1Szrj     va_end(ap);
1771dc4f0af1Szrj }
1772dc4f0af1Szrj 
1773dc4f0af1Szrj /*
1774dc4f0af1Szrj  * void message_clear()
1775dc4f0af1Szrj  *
1776dc4f0af1Szrj  * Clear message area and flush all pending messages.
1777dc4f0af1Szrj  */
1778dc4f0af1Szrj 
1779dc4f0af1Szrj void
message_clear()1780dc4f0af1Szrj message_clear()
1781dc4f0af1Szrj 
1782dc4f0af1Szrj {
1783dc4f0af1Szrj     /* remove any existing message */
1784dc4f0af1Szrj     if (message_current != NULL)
1785dc4f0af1Szrj     {
1786dc4f0af1Szrj 	display_move(0, y_message);
1787dc4f0af1Szrj 	screen_cleareol(message_length);
1788dc4f0af1Szrj 	free(message_current);
17895e83d98bSSascha Wildner 	message_current = NULL;
1790dc4f0af1Szrj     }
1791dc4f0af1Szrj 
1792dc4f0af1Szrj     /* flush all pending messages */
1793dc4f0af1Szrj     message_flush();
1794dc4f0af1Szrj }
1795dc4f0af1Szrj 
1796dc4f0af1Szrj /*
1797dc4f0af1Szrj  * void message_prompt_v(int so, char *msgfmt, va_list ap)
1798dc4f0af1Szrj  *
1799dc4f0af1Szrj  * Place a prompt in the message area.  A prompt is different from a
1800dc4f0af1Szrj  * message as follows: it is displayed immediately, overwriting any
1801dc4f0af1Szrj  * message that may already be there, it may be highlighted in standout
1802dc4f0af1Szrj  * mode (if "so" is true), the cursor is left to rest at the end of the
1803dc4f0af1Szrj  * prompt.  This call causes all pending messages to be flushed.
1804dc4f0af1Szrj  */
1805dc4f0af1Szrj 
1806dc4f0af1Szrj void
message_prompt_v(int so,char * msgfmt,va_list ap)1807dc4f0af1Szrj message_prompt_v(int so, char *msgfmt, va_list ap)
1808dc4f0af1Szrj 
1809dc4f0af1Szrj {
1810dc4f0af1Szrj     char msg[MAX_COLS];
1811dc4f0af1Szrj     int i;
1812dc4f0af1Szrj 
1813dc4f0af1Szrj     /* clear out the message buffer */
1814dc4f0af1Szrj     message_flush();
1815dc4f0af1Szrj 
1816dc4f0af1Szrj     /* format the message */
1817dc4f0af1Szrj     i = vsnprintf(msg, sizeof(msg), msgfmt, ap);
1818dc4f0af1Szrj 
1819dc4f0af1Szrj     /* this goes over any existing message */
1820dc4f0af1Szrj     display_move(0, y_message);
1821dc4f0af1Szrj 
1822dc4f0af1Szrj     /* clear the entire line */
1823dc4f0af1Szrj     screen_cleareol(message_length);
1824dc4f0af1Szrj 
1825dc4f0af1Szrj     /* show the prompt */
1826dc4f0af1Szrj     if (so)
1827dc4f0af1Szrj     {
1828dc4f0af1Szrj 	screen_standout(msg);
1829dc4f0af1Szrj     }
1830dc4f0af1Szrj     else
1831dc4f0af1Szrj     {
1832dc4f0af1Szrj 	fputs(msg, stdout);
1833dc4f0af1Szrj     }
1834dc4f0af1Szrj 
1835dc4f0af1Szrj     /* make it all visible */
1836dc4f0af1Szrj     fflush(stdout);
1837dc4f0af1Szrj 
1838dc4f0af1Szrj     /* even though we dont keep a copy of the prompt, track its length */
1839dc4f0af1Szrj     message_length = i < MAX_COLS ? i : MAX_COLS;
1840dc4f0af1Szrj }
1841dc4f0af1Szrj 
1842dc4f0af1Szrj /*
1843dc4f0af1Szrj  * void message_prompt(char *msgfmt, ...)
1844dc4f0af1Szrj  *
1845dc4f0af1Szrj  * Place a prompt in the message area (see message_prompt_v).
1846dc4f0af1Szrj  */
1847dc4f0af1Szrj 
1848dc4f0af1Szrj void
message_prompt(char * msgfmt,...)1849dc4f0af1Szrj message_prompt(char *msgfmt, ...)
1850dc4f0af1Szrj 
1851dc4f0af1Szrj {
1852dc4f0af1Szrj     va_list ap;
1853dc4f0af1Szrj 
1854dc4f0af1Szrj     va_start(ap, msgfmt);
1855dc4f0af1Szrj     message_prompt_v(Yes, msgfmt, ap);
1856dc4f0af1Szrj     va_end(ap);
1857dc4f0af1Szrj }
1858dc4f0af1Szrj 
1859dc4f0af1Szrj void
message_prompt_plain(char * msgfmt,...)1860dc4f0af1Szrj message_prompt_plain(char *msgfmt, ...)
1861dc4f0af1Szrj 
1862dc4f0af1Szrj {
1863dc4f0af1Szrj     va_list ap;
1864dc4f0af1Szrj 
1865dc4f0af1Szrj     va_start(ap, msgfmt);
1866dc4f0af1Szrj     message_prompt_v(No, msgfmt, ap);
1867dc4f0af1Szrj     va_end(ap);
1868dc4f0af1Szrj }
1869dc4f0af1Szrj 
1870dc4f0af1Szrj /*
1871dc4f0af1Szrj  * int readline(char *buffer, int size, int numeric)
1872dc4f0af1Szrj  *
1873dc4f0af1Szrj  * Read a line of input from the terminal.  The line is placed in
1874dc4f0af1Szrj  * "buffer" not to exceed "size".  If "numeric" is true then the input
1875dc4f0af1Szrj  * can only consist of digits.  This routine handles all character
1876dc4f0af1Szrj  * editing while keeping the terminal in cbreak mode.  If "numeric"
1877dc4f0af1Szrj  * is true then the number entered is returned.  Otherwise the number
1878dc4f0af1Szrj  * of character read in to "buffer" is returned.
1879dc4f0af1Szrj  */
1880dc4f0af1Szrj 
1881dc4f0af1Szrj int
readline(char * buffer,int size,int numeric)1882dc4f0af1Szrj readline(char *buffer, int size, int numeric)
1883dc4f0af1Szrj 
1884dc4f0af1Szrj {
1885dc4f0af1Szrj     register char *ptr = buffer;
1886dc4f0af1Szrj     register char ch;
1887dc4f0af1Szrj     register char cnt = 0;
1888dc4f0af1Szrj 
1889dc4f0af1Szrj     /* allow room for null terminator */
1890dc4f0af1Szrj     size -= 1;
1891dc4f0af1Szrj 
1892dc4f0af1Szrj     /* read loop */
1893dc4f0af1Szrj     while ((fflush(stdout), read(0, ptr, 1) > 0))
1894dc4f0af1Szrj     {
1895dc4f0af1Szrj 	/* newline or return means we are done */
1896dc4f0af1Szrj 	if ((ch = *ptr) == '\n' || ch == '\r')
1897dc4f0af1Szrj 	{
1898dc4f0af1Szrj 	    break;
1899dc4f0af1Szrj 	}
1900dc4f0af1Szrj 
1901dc4f0af1Szrj 	/* handle special editing characters */
1902dc4f0af1Szrj 	if (ch == ch_kill)
1903dc4f0af1Szrj 	{
1904dc4f0af1Szrj 	    /* return null string */
1905dc4f0af1Szrj 	    *buffer = '\0';
1906dc4f0af1Szrj 	    putchar('\r');
1907dc4f0af1Szrj 	    return(-1);
1908dc4f0af1Szrj 	}
1909dc4f0af1Szrj 	else if (ch == ch_werase)
1910dc4f0af1Szrj 	{
1911dc4f0af1Szrj 	    /* erase previous word */
1912dc4f0af1Szrj 	    if (cnt <= 0)
1913dc4f0af1Szrj 	    {
1914dc4f0af1Szrj 		/* none to erase! */
1915dc4f0af1Szrj 		putchar('\7');
1916dc4f0af1Szrj 	    }
1917dc4f0af1Szrj 	    else
1918dc4f0af1Szrj 	    {
1919dc4f0af1Szrj 		/*
1920dc4f0af1Szrj 		 * First: remove all spaces till the first-non-space
1921dc4f0af1Szrj 		 * Second: remove all non-spaces till the first-space
1922dc4f0af1Szrj 		 */
1923dc4f0af1Szrj 		while(cnt > 0 && ptr[-1] == ' ')
1924dc4f0af1Szrj 		{
1925dc4f0af1Szrj 		    fputs("\b \b", stdout);
1926dc4f0af1Szrj 		    ptr--;
1927dc4f0af1Szrj 		    cnt--;
1928dc4f0af1Szrj 		}
1929dc4f0af1Szrj 		while(cnt > 0 && ptr[-1] != ' ')
1930dc4f0af1Szrj 		{
1931dc4f0af1Szrj 		    fputs("\b \b", stdout);
1932dc4f0af1Szrj 		    ptr--;
1933dc4f0af1Szrj 		    cnt--;
1934dc4f0af1Szrj 		}
1935dc4f0af1Szrj 	    }
1936dc4f0af1Szrj 	}
1937dc4f0af1Szrj 	else if (ch == ch_erase)
1938dc4f0af1Szrj 	{
1939dc4f0af1Szrj 	    /* erase previous character */
1940dc4f0af1Szrj 	    if (cnt <= 0)
1941dc4f0af1Szrj 	    {
1942dc4f0af1Szrj 		/* none to erase! */
1943dc4f0af1Szrj 		putchar('\7');
1944dc4f0af1Szrj 	    }
1945dc4f0af1Szrj 	    else
1946dc4f0af1Szrj 	    {
1947dc4f0af1Szrj 		fputs("\b \b", stdout);
1948dc4f0af1Szrj 		ptr--;
1949dc4f0af1Szrj 		cnt--;
1950dc4f0af1Szrj 	    }
1951dc4f0af1Szrj 	}
1952dc4f0af1Szrj 	/* check for character validity and buffer overflow */
1953dc4f0af1Szrj 	else if (cnt == size || (numeric && !isdigit((int)ch)) ||
1954dc4f0af1Szrj 		!isprint((int)ch))
1955dc4f0af1Szrj 	{
1956dc4f0af1Szrj 	    /* not legal */
1957dc4f0af1Szrj 	    putchar('\7');
1958dc4f0af1Szrj 	}
1959dc4f0af1Szrj 	else
1960dc4f0af1Szrj 	{
1961dc4f0af1Szrj 	    /* echo it and store it in the buffer */
1962dc4f0af1Szrj 	    putchar(ch);
1963dc4f0af1Szrj 	    ptr++;
1964dc4f0af1Szrj 	    cnt++;
1965dc4f0af1Szrj 	}
1966dc4f0af1Szrj     }
1967dc4f0af1Szrj 
1968dc4f0af1Szrj     /* all done -- null terminate the string */
1969dc4f0af1Szrj     *ptr = '\0';
1970dc4f0af1Szrj 
1971dc4f0af1Szrj     /* add response length to message_length */
1972dc4f0af1Szrj     message_length += cnt;
1973dc4f0af1Szrj 
1974dc4f0af1Szrj     /* return either inputted number or string length */
1975dc4f0af1Szrj     putchar('\r');
1976dc4f0af1Szrj     return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
1977dc4f0af1Szrj }
1978dc4f0af1Szrj 
1979dc4f0af1Szrj void
display_pagerstart()1980dc4f0af1Szrj display_pagerstart()
1981dc4f0af1Szrj 
1982dc4f0af1Szrj {
1983dc4f0af1Szrj     display_clear();
1984dc4f0af1Szrj }
1985dc4f0af1Szrj 
1986dc4f0af1Szrj void
display_pagerend()1987dc4f0af1Szrj display_pagerend()
1988dc4f0af1Szrj 
1989dc4f0af1Szrj {
1990dc4f0af1Szrj     char ch;
1991dc4f0af1Szrj 
1992dc4f0af1Szrj     screen_standout("Hit any key to continue: ");
1993dc4f0af1Szrj     fflush(stdout);
1994dc4f0af1Szrj     (void) read(0, &ch, 1);
1995dc4f0af1Szrj }
1996dc4f0af1Szrj 
1997dc4f0af1Szrj void
display_pager(char * fmt,...)1998dc4f0af1Szrj display_pager(char *fmt, ...)
1999dc4f0af1Szrj 
2000dc4f0af1Szrj {
2001dc4f0af1Szrj     va_list ap;
2002dc4f0af1Szrj 
2003dc4f0af1Szrj     int ch;
2004dc4f0af1Szrj     char readch;
2005dc4f0af1Szrj     char buffer[MAX_COLS];
2006dc4f0af1Szrj     char *data;
2007dc4f0af1Szrj 
2008dc4f0af1Szrj     /* format into buffer */
2009dc4f0af1Szrj     va_start(ap, fmt);
2010dc4f0af1Szrj     (void) vsnprintf(buffer, MAX_COLS, fmt, ap);
2011dc4f0af1Szrj     va_end(ap);
2012dc4f0af1Szrj     data = buffer;
2013dc4f0af1Szrj 
2014dc4f0af1Szrj     while ((ch = *data++) != '\0')
2015dc4f0af1Szrj     {
2016dc4f0af1Szrj 	putchar(ch);
2017dc4f0af1Szrj 	if (ch == '\n')
2018dc4f0af1Szrj 	{
2019dc4f0af1Szrj 	    if (++curr_y >= screen_length - 1)
2020dc4f0af1Szrj 	    {
2021dc4f0af1Szrj 		screen_standout("...More...");
2022dc4f0af1Szrj 		fflush(stdout);
2023dc4f0af1Szrj 		(void) read(0, &readch, 1);
2024dc4f0af1Szrj 		putchar('\r');
2025dc4f0af1Szrj 		switch(readch)
2026dc4f0af1Szrj 		{
2027dc4f0af1Szrj 		case '\r':
2028dc4f0af1Szrj 		case '\n':
2029dc4f0af1Szrj 		    curr_y--;
2030dc4f0af1Szrj 		    break;
2031dc4f0af1Szrj 
2032dc4f0af1Szrj 		case 'q':
2033dc4f0af1Szrj 		    return;
2034dc4f0af1Szrj 
2035dc4f0af1Szrj 		default:
2036dc4f0af1Szrj 		    curr_y = 0;
2037dc4f0af1Szrj 		}
2038dc4f0af1Szrj 	    }
2039dc4f0af1Szrj 	}
2040dc4f0af1Szrj     }
2041dc4f0af1Szrj }
2042