GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/engine.c Lines: 0 624 0.0 %
Date: 2017-11-07 Branches: 0 455 0.0 %

Line Branch Exec Source
1
/* $Id: engine.c,v 1.21 2017/04/05 15:57:11 deraadt Exp $	 */
2
/*
3
 * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
19
#include <sys/ioctl.h>
20
#include <sys/types.h>
21
#include <sys/queue.h>
22
23
#include <ctype.h>
24
#include <curses.h>
25
#include <signal.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <term.h>
29
#include <unistd.h>
30
#include <err.h>
31
32
/* XXX These are defined in term.h and conflict with our variable names */
33
#ifdef columns
34
#undef columns
35
#endif
36
37
#ifdef lines
38
#undef lines
39
#endif
40
41
#include "engine.h"
42
43
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
44
45
/* circular linked list of views */
46
TAILQ_HEAD(view_list, view_ent) view_head =
47
				  TAILQ_HEAD_INITIALIZER(view_head);
48
struct view_ent {
49
	field_view *view;
50
	TAILQ_ENTRY(view_ent) entries;
51
};
52
53
useconds_t udelay = 5000000;
54
int dispstart = 0;
55
int interactive = 1;
56
int averageonly = 0;
57
int maxprint = 0;
58
int paused = 0;
59
int rawmode = 0;
60
int rawwidth = DEFAULT_WIDTH;
61
int sortdir = 1;
62
int columns, lines;
63
u_int32_t num_disp = 0;
64
int max_disp = -1;
65
66
volatile sig_atomic_t gotsig_close = 0;
67
volatile sig_atomic_t gotsig_resize = 0;
68
volatile sig_atomic_t gotsig_alarm = 0;
69
int need_update = 0;
70
int need_sort = 0;
71
int separate_thousands = 0;
72
73
SCREEN *screen;
74
75
field_view *curr_view = NULL;
76
struct view_ent *curr_view_ent = NULL;
77
struct view_manager *curr_mgr = NULL;
78
79
int curr_line = 0;
80
int home_line = 0;
81
82
/* line buffer for raw mode */
83
char linebuf[MAX_LINE_BUF];
84
int linepos = 0;
85
86
/* temp storage for state printing */
87
char tmp_buf[MAX_LINE_BUF];
88
89
char cmdbuf[MAX_LINE_BUF];
90
int cmd_len = -1;
91
struct command *curr_cmd = NULL;
92
char *curr_message = NULL;
93
94
void print_cmdline(void);
95
96
97
/* screen output functions */
98
99
char * tb_ptr = NULL;
100
int tb_len = 0;
101
102
void
103
tb_start(void)
104
{
105
	tb_ptr = tmp_buf;
106
	tb_len = sizeof(tmp_buf);
107
	tb_ptr[0] = '\0';
108
}
109
110
void
111
tb_end(void)
112
{
113
	tb_ptr = NULL;
114
	tb_len = 0;
115
}
116
117
int
118
tbprintf(char *format, ...)
119
	GCC_PRINTFLIKE(1,2)       /* defined in curses.h */
120
{
121
	int len;
122
	va_list arg;
123
124
	if (tb_ptr == NULL || tb_len <= 0)
125
		return 0;
126
127
	va_start(arg, format);
128
	len = vsnprintf(tb_ptr, tb_len, format, arg);
129
	va_end(arg);
130
131
	if (len > tb_len)
132
		tb_end();
133
	else if (len > 0) {
134
		tb_ptr += len;
135
		tb_len -= len;
136
	}
137
138
	return len;
139
}
140
141
int
142
tbprintft(char *format, ...)
143
	GCC_PRINTFLIKE(1,2)       /* defined in curses.h */
144
{
145
	int len;
146
	va_list arg;
147
	char buf[MAX_LINE_BUF];
148
149
	if (tb_ptr == NULL || tb_len <= 0)
150
		return 0;
151
152
	va_start(arg, format);
153
	len = vsnprintf(buf, tb_len, format, arg);
154
	va_end(arg);
155
156
	if (len > tb_len)
157
		tb_end();
158
	else if (len > 0) {
159
		int d, s;
160
		int digits, curdigit;
161
162
		if (!separate_thousands) {
163
			strlcpy(tb_ptr, buf, tb_len);
164
			return len;
165
		}
166
167
		/* count until we hit a non digit. (e.g. the prefix) */
168
		for (digits = 0; digits < len; digits++)
169
			if (!isdigit((unsigned char)buf[digits]))
170
				break;
171
172
		curdigit = digits;
173
		d = s = 0;
174
		/* insert thousands separators while copying */
175
		while (curdigit && d < tb_len) {
176
			if (curdigit < digits && curdigit % 3 == 0)
177
				tb_ptr[d++] = ',';
178
			tb_ptr[d++] = buf[s++];
179
			curdigit--;
180
		}
181
		/* copy the remaining non-digits */
182
		while (len > digits && d < tb_len) {
183
			tb_ptr[d++] = buf[s++];
184
			digits++;
185
		}
186
		tb_ptr[d] = '\0';
187
		tb_ptr += d;
188
		tb_len -= d;
189
		len = d;
190
	}
191
	return len;
192
}
193
194
void
195
move_horiz(int offset)
196
{
197
	if (rawmode) {
198
		if (offset <= 0)
199
			linepos = 0;
200
		else if (offset >= MAX_LINE_BUF)
201
			linepos = MAX_LINE_BUF - 1;
202
		else
203
			linepos = offset;
204
	} else {
205
		move(curr_line, offset);
206
	}
207
}
208
209
void
210
print_str(int len, const char *str)
211
{
212
	if (len <= 0)
213
		return;
214
215
	if (rawmode) {
216
		int length = MINIMUM(len, MAX_LINE_BUF - linepos);
217
		if (length <= 0)
218
			return;
219
		bcopy(str, &linebuf[linepos], length);
220
		linepos += length;
221
	} else
222
		addnstr(str, len);
223
}
224
225
void
226
clear_linebuf(void)
227
{
228
	memset(linebuf, ' ', MAX_LINE_BUF);
229
}
230
231
void
232
end_line(void)
233
{
234
	if (rawmode) {
235
		linebuf[rawwidth] = '\0';
236
		printf("%s\n", linebuf);
237
		clear_linebuf();
238
	}
239
	curr_line++;
240
}
241
242
void
243
end_page(void)
244
{
245
	if (rawmode) {
246
		linepos = 0;
247
		clear_linebuf();
248
	} else {
249
		move(home_line, 0);
250
		print_cmdline();
251
		refresh();
252
	}
253
	curr_line = 0;
254
}
255
256
/* field output functions */
257
258
void
259
print_fld_str(field_def *fld, const char *str)
260
{
261
	int len, offset;
262
	char *cpos;
263
264
	if (str == NULL || fld == NULL)
265
		return;
266
267
	if (fld->start < 0)
268
		return;
269
270
	len = strlen(str);
271
272
	if (len >= fld->width) {
273
		move_horiz(fld->start);
274
		print_str(fld->width, str);
275
	} else {
276
		switch (fld->align) {
277
		case FLD_ALIGN_RIGHT:
278
			move_horiz(fld->start + (fld->width - len));
279
			break;
280
		case FLD_ALIGN_CENTER:
281
			move_horiz(fld->start + (fld->width - len) / 2);
282
			break;
283
		case FLD_ALIGN_COLUMN:
284
			if ((cpos = strchr(str, ':')) == NULL) {
285
				offset = (fld->width - len) / 2;
286
			} else {
287
				offset = (fld->width / 2) - (cpos - str);
288
				if (offset < 0)
289
					offset = 0;
290
				else if (offset > (fld->width - len))
291
					offset = fld->width - len;
292
			}
293
			move_horiz(fld->start + offset);
294
			break;
295
		default:
296
			move_horiz(fld->start);
297
			break;
298
		}
299
		print_str(len, str);
300
	}
301
}
302
303
void
304
print_bar_title(field_def *fld)
305
{
306
	char buf[16];
307
	int len, i, d, tr, tw, val, pos, cur;
308
309
	int divs[] = {20, 10, 5, 4, 3, 2, 1, 0};
310
311
	if (fld->width < 1)
312
		return;
313
314
	len = snprintf(buf, sizeof(buf), " %d\\", fld->arg);
315
	if (len >= sizeof(buf))
316
		return;
317
318
	for (i = 0; divs[i]; i++)
319
		if (divs[i] * len <= fld->width)
320
			break;
321
322
	if (divs[i] == 0) {
323
		print_fld_str(fld, "*****");
324
		return;
325
	}
326
327
	d = divs[i];
328
329
	val = 0;
330
	pos = 0;
331
	tr = fld->arg % d;
332
	tw = fld->width % d;
333
334
	tb_start();
335
	cur = 0;
336
	for(i = 0; i < d; i++) {
337
		tw += fld->width;
338
		tr += fld->arg;
339
340
		while (tr >= d) {
341
			val++;
342
			tr -= d;
343
		}
344
		while (tw >= d) {
345
			pos++;
346
			tw -= d;
347
		}
348
349
		len = snprintf(buf, sizeof(buf), "%d\\", val);
350
		if (len >= sizeof(buf))
351
			len = strlen(buf);
352
		while (cur < pos - len) {
353
			tbprintf(" ");
354
			cur++;
355
		}
356
		tbprintf("%s", buf);
357
		cur += len;
358
	}
359
360
	print_fld_tb(fld);
361
}
362
363
void
364
print_fld_bar(field_def *fld, int value)
365
{
366
	int i, tw, val;
367
368
	if (fld->width < 1)
369
		return;
370
371
	val = 0;
372
	tw = fld->arg / 2;
373
374
	tb_start();
375
376
	for(i = 0; i < fld->width; i++) {
377
		tw += fld->arg;
378
379
		while (tw >= fld->width) {
380
			val++;
381
			tw -= fld->width;
382
		}
383
		if (val > value)
384
			break;
385
		tbprintf("#");
386
	}
387
388
	print_fld_tb(fld);
389
}
390
391
void
392
print_fld_tb(field_def *fld)
393
{
394
	print_fld_str(fld, tmp_buf);
395
	tb_end();
396
}
397
398
void
399
print_title(void)
400
{
401
	field_def **fp;
402
403
	if (curr_view != NULL && curr_view->view != NULL) {
404
		for (fp = curr_view->view; *fp != NULL; fp++) {
405
			switch((*fp)->align) {
406
			case FLD_ALIGN_LEFT:
407
			case FLD_ALIGN_RIGHT:
408
			case FLD_ALIGN_CENTER:
409
			case FLD_ALIGN_COLUMN:
410
				print_fld_str(*fp, (*fp)->title);
411
				break;
412
			case FLD_ALIGN_BAR:
413
				print_bar_title(*fp);
414
				break;
415
			}
416
		}
417
	}
418
	end_line();
419
}
420
421
/* view related functions */
422
void
423
hide_field(field_def *fld)
424
{
425
	if (fld == NULL)
426
		return;
427
428
	fld->flags |= FLD_FLAG_HIDDEN;
429
}
430
431
void
432
show_field(field_def *fld)
433
{
434
	if (fld == NULL)
435
		return;
436
437
	fld->flags &= ~((unsigned int) FLD_FLAG_HIDDEN);
438
}
439
440
void
441
reset_fields(void)
442
{
443
	field_def **fp;
444
	field_def *fld;
445
446
	if (curr_view == NULL)
447
		return;
448
449
	if (curr_view->view == NULL)
450
		return;
451
452
	for (fp = curr_view->view; *fp != NULL; fp++) {
453
		fld = *fp;
454
		fld->start = -1;
455
		fld->width = fld->norm_width;
456
	}
457
}
458
459
void
460
field_setup(void)
461
{
462
	field_def **fp;
463
	field_def *fld;
464
	int st, fwid, change;
465
	int width = columns;
466
467
	reset_fields();
468
469
	dispstart = 0;
470
	st = 0;
471
472
	for (fp = curr_view->view; *fp != NULL; fp++) {
473
		fld = *fp;
474
		if (fld->flags & FLD_FLAG_HIDDEN)
475
			continue;
476
477
		if (width <= 1)
478
			break;
479
480
		if (st != 1)
481
			width--;
482
483
		fld->start = 1;
484
		fwid = fld->width;
485
		st++;
486
		if (fwid >= width) {
487
			fld->width = width;
488
			width = 0;
489
		} else
490
			width -= fwid;
491
	}
492
493
	while (width > 0) {
494
		change = 0;
495
		for (fp = curr_view->view; *fp != NULL; fp++) {
496
			fld = *fp;
497
			if (fld->flags & FLD_FLAG_HIDDEN)
498
				continue;
499
			if ((fld->width < fld->max_width) &&
500
			    (fld->increment <= width)) {
501
				int w = fld->width + fld->increment;
502
				if (w > fld->max_width)
503
					w = fld->max_width;
504
				width += fld->width - w;
505
				fld->width = w;
506
				change = 1;
507
			}
508
			if (width <= 0) break;
509
		}
510
		if (change == 0) break;
511
	}
512
513
	st = 0;
514
	for (fp = curr_view->view; *fp != NULL; fp++) {
515
		fld = *fp;
516
		if (fld->flags & FLD_FLAG_HIDDEN)
517
			continue;
518
		if (fld->start < 0) break;
519
		fld->start = st;
520
		st += fld->width + 1;
521
	}
522
}
523
524
void
525
set_curr_view(struct view_ent *ve)
526
{
527
	field_view *v;
528
529
	reset_fields();
530
531
	if (ve == NULL) {
532
		curr_view_ent = NULL;
533
		curr_view = NULL;
534
		curr_mgr = NULL;
535
		return;
536
	}
537
538
	v = ve->view;
539
540
	if ((curr_view != NULL) && (curr_mgr != v->mgr)) {
541
		gotsig_alarm = 1;
542
		if (v->mgr != NULL && v->mgr->select_fn != NULL)
543
			v->mgr->select_fn();
544
	}
545
546
	curr_view_ent = ve;
547
	curr_view = v;
548
	curr_mgr = v->mgr;
549
	field_setup();
550
	need_update = 1;
551
}
552
553
void
554
add_view(field_view *fv)
555
{
556
	struct view_ent *ent;
557
558
	if (fv == NULL)
559
		return;
560
561
	if (fv->view == NULL || fv->name == NULL || fv->mgr == NULL)
562
		return;
563
564
	ent = malloc(sizeof(struct view_ent));
565
	if (ent == NULL)
566
		return;
567
568
	ent->view = fv;
569
	TAILQ_INSERT_TAIL(&view_head, ent, entries);
570
571
	if (curr_view == NULL)
572
		set_curr_view(ent);
573
}
574
575
int
576
set_view(const char *opt)
577
{
578
	struct view_ent *ve, *vm = NULL;
579
	field_view *v;
580
	int len;
581
582
	if (opt == NULL || (len = strlen(opt)) == 0)
583
		return 1;
584
585
	TAILQ_FOREACH(ve, &view_head, entries) {
586
		v = ve->view;
587
		if (strncasecmp(opt, v->name, len) == 0) {
588
			if (vm)
589
				return 1;
590
			vm = ve;
591
		}
592
	}
593
594
	if (vm) {
595
		set_curr_view(vm);
596
		return 0;
597
	}
598
599
	return 1;
600
}
601
602
void
603
foreach_view(void (*callback)(field_view *))
604
{
605
	struct view_ent *ve;
606
607
	TAILQ_FOREACH(ve, &view_head, entries) {
608
		callback(ve->view);
609
	}
610
}
611
612
int
613
set_view_hotkey(int ch)
614
{
615
	struct view_ent *ve;
616
	field_view *v;
617
	int key = tolower(ch);
618
619
	TAILQ_FOREACH(ve, &view_head, entries) {
620
		v = ve->view;
621
		if (key == v->hotkey) {
622
			set_curr_view(ve);
623
			return 1;
624
		}
625
	}
626
627
	return 0;
628
}
629
630
void
631
next_view(void)
632
{
633
	struct view_ent *ve;
634
635
	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
636
		return;
637
638
	ve = TAILQ_NEXT(curr_view_ent, entries);
639
	if (ve == NULL)
640
		ve = TAILQ_FIRST(&view_head);
641
642
	set_curr_view(ve);
643
}
644
645
void
646
prev_view(void)
647
{
648
	struct view_ent *ve;
649
650
	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
651
		return;
652
653
	ve = TAILQ_PREV(curr_view_ent, view_list, entries);
654
	if (ve == NULL)
655
		ve = TAILQ_LAST(&view_head, view_list);
656
657
	set_curr_view(ve);
658
}
659
660
/* generic field printing */
661
662
void
663
print_fld_age(field_def *fld, unsigned int age)
664
{
665
	int len;
666
	unsigned int h, m, s;
667
668
	if (fld == NULL)
669
		return;
670
	len = fld->width;
671
672
	if (len < 1)
673
		return;
674
675
	s = age % 60;
676
	m = age / 60;
677
	h = m / 60;
678
	m %= 60;
679
680
	tb_start();
681
	if (tbprintf("%02u:%02u:%02u", h, m, s) <= len)
682
		goto ok;
683
684
	tb_start();
685
	if (tbprintf("%u", age) <= len)
686
		goto ok;
687
688
	tb_start();
689
	age /= 60;
690
	if (tbprintf("%um", age) <= len)
691
		goto ok;
692
	if (age == 0)
693
		goto err;
694
695
	tb_start();
696
	age /= 60;
697
	if (tbprintf("%uh", age) <= len)
698
		goto ok;
699
	if (age == 0)
700
		goto err;
701
702
	tb_start();
703
	age /= 24;
704
	if (tbprintf("%ud", age) <= len)
705
		goto ok;
706
707
err:
708
	print_fld_str(fld, "*");
709
	tb_end();
710
	return;
711
712
ok:
713
	print_fld_tb(fld);
714
}
715
716
void
717
print_fld_sdiv(field_def *fld, u_int64_t size, int d)
718
{
719
	int len;
720
721
	if (fld == NULL)
722
		return;
723
724
	len = fld->width;
725
	if (len < 1)
726
		return;
727
728
	tb_start();
729
	if (tbprintft("%llu", size) <= len)
730
		goto ok;
731
732
	tb_start();
733
	size /= d;
734
	if (tbprintft("%lluK", size) <= len)
735
		goto ok;
736
	if (size == 0)
737
		goto err;
738
739
	tb_start();
740
	size /= d;
741
	if (tbprintft("%lluM", size) <= len)
742
		goto ok;
743
	if (size == 0)
744
		goto err;
745
746
	tb_start();
747
	size /= d;
748
	if (tbprintft("%lluG", size) <= len)
749
		goto ok;
750
	if (size == 0)
751
		goto err;
752
753
	tb_start();
754
	size /= d;
755
	if (tbprintft("%lluT", size) <= len)
756
		goto ok;
757
758
err:
759
	print_fld_str(fld, "*");
760
	tb_end();
761
	return;
762
763
ok:
764
	print_fld_tb(fld);
765
}
766
767
void
768
print_fld_size(field_def *fld, u_int64_t size)
769
{
770
	print_fld_sdiv(fld, size, 1024);
771
}
772
773
void
774
print_fld_ssdiv(field_def *fld, int64_t size, int d)
775
{
776
	int len;
777
778
	if (fld == NULL)
779
		return;
780
781
	len = fld->width;
782
	if (len < 1)
783
		return;
784
785
	tb_start();
786
	if (tbprintft("%lld", size) <= len)
787
		goto ok;
788
789
	tb_start();
790
	size /= d;
791
	if (tbprintft("%lldK", size) <= len)
792
		goto ok;
793
	if (size == 0)
794
		goto err;
795
796
	tb_start();
797
	size /= d;
798
	if (tbprintft("%lldM", size) <= len)
799
		goto ok;
800
	if (size == 0)
801
		goto err;
802
803
	tb_start();
804
	size /= d;
805
	if (tbprintft("%lldG", size) <= len)
806
		goto ok;
807
	if (size == 0)
808
		goto err;
809
810
	tb_start();
811
	size /= d;
812
	if (tbprintft("%lldT", size) <= len)
813
		goto ok;
814
815
err:
816
	print_fld_str(fld, "*");
817
	tb_end();
818
	return;
819
820
ok:
821
	print_fld_tb(fld);
822
}
823
824
void
825
print_fld_ssize(field_def *fld, int64_t size)
826
{
827
	print_fld_ssdiv(fld, size, 1024);
828
}
829
830
void
831
print_fld_rate(field_def *fld, double rate)
832
{
833
	if (rate < 0) {
834
		print_fld_str(fld, "*");
835
	} else {
836
		print_fld_size(fld, rate);
837
	}
838
}
839
840
void
841
print_fld_bw(field_def *fld, double bw)
842
{
843
	if (bw < 0) {
844
		print_fld_str(fld, "*");
845
	} else {
846
		print_fld_sdiv(fld, bw, 1000);
847
	}
848
}
849
850
void
851
print_fld_uint(field_def *fld, unsigned int size)
852
{
853
	int len;
854
855
	if (fld == NULL)
856
		return;
857
858
	len = fld->width;
859
	if (len < 1)
860
		return;
861
862
	tb_start();
863
	if (tbprintft("%u", size) > len)
864
		print_fld_str(fld, "*");
865
	else
866
		print_fld_tb(fld);
867
	tb_end();
868
}
869
870
void
871
print_fld_float(field_def *fld, double f, int prec)
872
{
873
	int len;
874
875
	if (fld == NULL)
876
		return;
877
878
	len = fld->width;
879
	if (len < 1)
880
		return;
881
882
	tb_start();
883
	if (tbprintf("%*.*f", len, prec, f) > len)
884
		print_fld_str(fld, "*");
885
	else
886
		print_fld_tb(fld);
887
	tb_end();
888
}
889
890
891
/* ordering */
892
893
void
894
set_order(const char *opt)
895
{
896
	order_type *o;
897
898
	if (curr_view == NULL || curr_view->mgr == NULL)
899
		return;
900
901
	curr_view->mgr->order_curr = curr_view->mgr->order_list;
902
903
	if (opt == NULL)
904
		return;
905
906
	o = curr_view->mgr->order_list;
907
908
	if (o == NULL)
909
		return;
910
911
	for (;o->name != NULL; o++) {
912
		if (strcasecmp(opt, o->match) == 0) {
913
			curr_view->mgr->order_curr = o;
914
			return;
915
		}
916
	}
917
}
918
919
int
920
set_order_hotkey(int ch)
921
{
922
	order_type *o;
923
	int key = ch;
924
925
	if (curr_view == NULL || curr_view->mgr == NULL)
926
		return 0;
927
928
	o = curr_view->mgr->order_list;
929
930
	if (o == NULL)
931
		return 0;
932
933
	for (;o->name != NULL; o++) {
934
		if (key == o->hotkey) {
935
			if (curr_view->mgr->order_curr == o) {
936
				sortdir *= -1;
937
			} else {
938
				curr_view->mgr->order_curr = o;
939
			}
940
			return 1;
941
		}
942
	}
943
944
	return 0;
945
}
946
947
void
948
next_order(void)
949
{
950
	order_type *o, *oc;
951
952
	if (curr_view->mgr->order_list == NULL)
953
		return;
954
955
	oc = curr_view->mgr->order_curr;
956
957
	for (o = curr_view->mgr->order_list; o->name != NULL; o++) {
958
		if (oc == o) {
959
			o++;
960
			if (o->name == NULL)
961
				break;
962
			curr_view->mgr->order_curr = o;
963
			return;
964
		}
965
	}
966
967
	curr_view->mgr->order_curr = curr_view->mgr->order_list;
968
}
969
970
971
/* main program functions */
972
973
int
974
read_view(void)
975
{
976
	if (curr_mgr == NULL)
977
		return (0);
978
979
	if (paused)
980
		return (0);
981
982
	if (curr_mgr->read_fn != NULL)
983
		return (curr_mgr->read_fn());
984
985
	return (0);
986
}
987
988
989
int
990
disp_update(void)
991
{
992
	int li;
993
994
	if (maxprint < 0)
995
		dispstart = 0;
996
	else if (dispstart + maxprint > num_disp)
997
		dispstart = num_disp - maxprint;
998
999
	if (dispstart < 0)
1000
		dispstart = 0;
1001
1002
	if (curr_view == NULL)
1003
		return 0;
1004
1005
	if (curr_mgr != NULL) {
1006
		curr_line = 0;
1007
1008
		if (curr_mgr->header_fn != NULL) {
1009
			li = curr_mgr->header_fn();
1010
			if (li < 0)
1011
				return (1);
1012
			curr_line = ++li;
1013
			home_line = li + maxprint + 1;
1014
		}
1015
1016
		print_title();
1017
1018
		if (curr_mgr->print_fn != NULL)
1019
			curr_mgr->print_fn();
1020
	}
1021
1022
	return (0);
1023
}
1024
1025
void
1026
sort_view(void)
1027
{
1028
	if (curr_mgr != NULL)
1029
		if (curr_mgr->sort_fn != NULL)
1030
			curr_mgr->sort_fn();
1031
}
1032
1033
void
1034
sig_close(int sig)
1035
{
1036
	gotsig_close = 1;
1037
}
1038
1039
void
1040
sig_resize(int sig)
1041
{
1042
	gotsig_resize = 1;
1043
}
1044
1045
void
1046
sig_alarm(int sig)
1047
{
1048
	gotsig_alarm = 1;
1049
}
1050
1051
void
1052
setup_term(int dmax)
1053
{
1054
	max_disp = dmax;
1055
	maxprint = dmax;
1056
1057
	if (rawmode) {
1058
		columns = rawwidth;
1059
		lines = DEFAULT_HEIGHT;
1060
		clear_linebuf();
1061
	} else {
1062
		if (dmax < 0)
1063
			dmax = 0;
1064
1065
		screen = newterm(NULL, stdout, stdin);
1066
		if (screen == NULL) {
1067
			rawmode = 1;
1068
			interactive = 0;
1069
			setup_term(dmax);
1070
			return;
1071
		}
1072
		columns = COLS;
1073
		lines = LINES;
1074
1075
		if (maxprint > lines - HEADER_LINES)
1076
			maxprint = lines - HEADER_LINES;
1077
1078
		nonl();
1079
		keypad(stdscr, TRUE);
1080
		intrflush(stdscr, FALSE);
1081
1082
		halfdelay(10);
1083
		noecho();
1084
	}
1085
1086
	if (dmax == 0)
1087
		maxprint = lines - HEADER_LINES;
1088
1089
	field_setup();
1090
}
1091
1092
void
1093
do_resize_term(void)
1094
{
1095
	struct winsize ws;
1096
1097
	if (rawmode)
1098
		return;
1099
1100
	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
1101
		return;
1102
1103
	resizeterm(ws.ws_row, ws.ws_col);
1104
1105
	columns = COLS;
1106
	lines = LINES;
1107
1108
	maxprint = max_disp;
1109
1110
	if (maxprint == 0 || maxprint > lines - HEADER_LINES)
1111
		maxprint = lines - HEADER_LINES;
1112
1113
	clear();
1114
1115
	field_setup();
1116
}
1117
1118
struct command *
1119
command_set(struct command *cmd, const char *init)
1120
{
1121
	struct command *prev = curr_cmd;
1122
1123
	if (cmd) {
1124
		if (init) {
1125
			cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf));
1126
			if (cmd_len >= sizeof(cmdbuf)) {
1127
				cmdbuf[0] = '\0';
1128
				cmd_len = 0;
1129
			}
1130
		} else {
1131
			cmd_len = 0;
1132
			cmdbuf[0] = 0;
1133
		}
1134
	}
1135
	curr_message = NULL;
1136
	curr_cmd = cmd;
1137
	need_update = 1;
1138
	return prev;
1139
}
1140
1141
const char *
1142
message_set(const char *msg) {
1143
	char *prev = curr_message;
1144
	if (msg)
1145
		curr_message = strdup(msg);
1146
	else
1147
		curr_message = NULL;
1148
	free(prev);
1149
	return NULL;
1150
}
1151
1152
void
1153
print_cmdline(void)
1154
{
1155
	if (curr_cmd) {
1156
		attron(A_STANDOUT);
1157
		mvprintw(home_line, 0, "%s: ", curr_cmd->prompt);
1158
		attroff(A_STANDOUT);
1159
		printw("%s", cmdbuf);
1160
	} else if (curr_message) {
1161
		mvprintw(home_line, 0, "> %s", curr_message);
1162
	}
1163
	clrtoeol();
1164
}
1165
1166
1167
void
1168
cmd_keyboard(int ch)
1169
{
1170
	if (curr_cmd == NULL)
1171
		return;
1172
1173
	if (ch > 0 && isprint(ch)) {
1174
		if (cmd_len < sizeof(cmdbuf) - 1) {
1175
			cmdbuf[cmd_len++] = ch;
1176
			cmdbuf[cmd_len] = 0;
1177
		} else
1178
			beep();
1179
	}
1180
1181
	switch (ch) {
1182
	case KEY_ENTER:
1183
	case 0x0a:
1184
	case 0x0d:
1185
	{
1186
		struct command * c = command_set(NULL, NULL);
1187
		c->exec(cmdbuf);
1188
		break;
1189
	}
1190
	case KEY_BACKSPACE:
1191
	case KEY_DC:
1192
	case CTRL_H:
1193
		if (cmd_len > 0) {
1194
			cmdbuf[--cmd_len] = 0;
1195
		} else
1196
			beep();
1197
		break;
1198
	case 0x1b:
1199
	case CTRL_G:
1200
		if (cmd_len > 0) {
1201
			cmdbuf[0] = '\0';
1202
			cmd_len = 0;
1203
		} else
1204
			command_set(NULL, NULL);
1205
		break;
1206
	default:
1207
		break;
1208
	}
1209
}
1210
1211
void
1212
keyboard(void)
1213
{
1214
	int ch;
1215
1216
	ch = getch();
1217
1218
	if (curr_cmd) {
1219
		cmd_keyboard(ch);
1220
		print_cmdline();
1221
		return;
1222
	}
1223
1224
	if (curr_mgr != NULL)
1225
		if (curr_mgr->key_fn != NULL)
1226
			if (curr_mgr->key_fn(ch))
1227
				return;
1228
1229
	if (curr_message != NULL) {
1230
		if (ch > 0) {
1231
			curr_message = NULL;
1232
			need_update = 1;
1233
		}
1234
	}
1235
1236
	switch (ch) {
1237
	case ' ':
1238
		gotsig_alarm = 1;
1239
		break;
1240
	case 'o':
1241
		next_order();
1242
		need_sort = 1;
1243
		break;
1244
	case 'p':
1245
		paused = !paused;
1246
		gotsig_alarm = 1;
1247
		break;
1248
	case 'q':
1249
		gotsig_close = 1;
1250
		break;
1251
	case 'r':
1252
		sortdir *= -1;
1253
		need_sort = 1;
1254
		break;
1255
	case 'v':
1256
		/* FALLTHROUGH */
1257
	case KEY_RIGHT:
1258
		/* FALLTHROUGH */
1259
	case CTRL_F:
1260
		next_view();
1261
		break;
1262
	case KEY_LEFT:
1263
		/* FALLTHROUGH */
1264
	case CTRL_B:
1265
		prev_view();
1266
		break;
1267
	case KEY_DOWN:
1268
		/* FALLTHROUGH */
1269
	case CTRL_N:
1270
		dispstart++;
1271
		need_update = 1;
1272
		break;
1273
	case KEY_UP:
1274
		/* FALLTHROUGH */
1275
	case CTRL_P:
1276
		dispstart--;
1277
		need_update = 1;
1278
		break;
1279
	case KEY_NPAGE:
1280
		/* FALLTHROUGH */
1281
	case CTRL_V:
1282
		dispstart += maxprint;
1283
		need_update = 1;
1284
		break;
1285
	case KEY_PPAGE:
1286
		/* FALLTHROUGH */
1287
	case META_V:
1288
		dispstart -= maxprint;
1289
		need_update = 1;
1290
		break;
1291
	case KEY_HOME:
1292
		/* FALLTHROUGH */
1293
	case CTRL_A:
1294
		dispstart = 0;
1295
		need_update = 1;
1296
		break;
1297
	case KEY_END:
1298
		/* FALLTHROUGH */
1299
	case CTRL_E:
1300
		dispstart = num_disp;
1301
		need_update = 1;
1302
		break;
1303
	case CTRL_L:
1304
		clear();
1305
		need_update = 1;
1306
		break;
1307
	default:
1308
		break;
1309
	}
1310
1311
	if (set_order_hotkey(ch))
1312
		need_sort = 1;
1313
	else
1314
		set_view_hotkey(ch);
1315
}
1316
1317
void
1318
engine_initialize(void)
1319
{
1320
	signal(SIGTERM, sig_close);
1321
	signal(SIGINT, sig_close);
1322
	signal(SIGQUIT, sig_close);
1323
	signal(SIGWINCH, sig_resize);
1324
	signal(SIGALRM, sig_alarm);
1325
}
1326
1327
void
1328
engine_loop(int countmax)
1329
{
1330
	int count = 0;
1331
1332
	for (;;) {
1333
		if (gotsig_alarm) {
1334
			read_view();
1335
			need_sort = 1;
1336
			gotsig_alarm = 0;
1337
			ualarm(udelay, 0);
1338
		}
1339
1340
		if (need_sort) {
1341
			sort_view();
1342
			need_sort = 0;
1343
			need_update = 1;
1344
1345
			/* XXX if sort took too long */
1346
			if (gotsig_alarm) {
1347
				gotsig_alarm = 0;
1348
				ualarm(udelay, 0);
1349
			}
1350
		}
1351
1352
		if (need_update) {
1353
			erase();
1354
			if (!averageonly ||
1355
			    (averageonly && count == countmax - 1))
1356
				disp_update();
1357
			end_page();
1358
			need_update = 0;
1359
			if (countmax && ++count >= countmax)
1360
				break;
1361
		}
1362
1363
		if (gotsig_close)
1364
			break;
1365
		if (gotsig_resize) {
1366
			do_resize_term();
1367
			gotsig_resize = 0;
1368
			need_update = 1;
1369
		}
1370
1371
		if (interactive && need_update == 0)
1372
			keyboard();
1373
		else if (interactive == 0)
1374
			usleep(udelay);
1375
	}
1376
1377
	if (rawmode == 0)
1378
		endwin();
1379
}
1380
1381
int
1382
check_termcap(void)
1383
{
1384
	char *term_name;
1385
	int status;
1386
	static struct termios screen_settings;
1387
1388
	if (!interactive)
1389
		/* pretend we have a dumb terminal */
1390
		return(1);
1391
1392
	/* get the terminal name */
1393
	term_name = getenv("TERM");
1394
	if (term_name == NULL)
1395
		return(1);
1396
1397
	/* now get the termcap entry */
1398
	if ((status = tgetent(NULL, term_name)) != 1) {
1399
		if (status == -1)
1400
			warnx("can't open termcap file");
1401
		else
1402
			warnx("no termcap entry for a `%s' terminal",
1403
			    term_name);
1404
1405
		/* pretend it's dumb and proceed */
1406
		return(1);
1407
	}
1408
1409
	/* "hardcopy" immediately indicates a very stupid terminal */
1410
	if (tgetflag("hc"))
1411
		return(1);
1412
1413
        /* get necessary capabilities */
1414
        if (tgetstr("cl", NULL) == NULL || tgetstr("cm", NULL) == NULL)
1415
		return(1);
1416
1417
	/* if stdout is not a terminal, pretend we are a dumb terminal */
1418
	if (tcgetattr(STDOUT_FILENO, &screen_settings) == -1)
1419
		return(1);
1420
1421
	return(0);
1422
}