GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/engine.c Lines: 0 667 0.0 %
Date: 2016-12-06 Branches: 0 448 0.0 %

Line Branch Exec Source
1
/* $Id: engine.c,v 1.19 2016/01/02 20:01:48 benno 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
		while (cur < pos - len) {
351
			tbprintf(" ");
352
			cur++;
353
		}
354
		tbprintf("%s", buf);
355
		cur += len;
356
	}
357
358
	print_fld_tb(fld);
359
}
360
361
void
362
print_fld_bar(field_def *fld, int value)
363
{
364
	int i, tw, val;
365
366
	if (fld->width < 1)
367
		return;
368
369
	val = 0;
370
	tw = fld->arg / 2;
371
372
	tb_start();
373
374
	for(i = 0; i < fld->width; i++) {
375
		tw += fld->arg;
376
377
		while (tw >= fld->width) {
378
			val++;
379
			tw -= fld->width;
380
		}
381
		if (val > value)
382
			break;
383
		tbprintf("#");
384
	}
385
386
	print_fld_tb(fld);
387
}
388
389
void
390
print_fld_tb(field_def *fld)
391
{
392
	print_fld_str(fld, tmp_buf);
393
	tb_end();
394
}
395
396
void
397
print_title(void)
398
{
399
	field_def **fp;
400
401
	if (curr_view != NULL && curr_view->view != NULL) {
402
		for (fp = curr_view->view; *fp != NULL; fp++) {
403
			switch((*fp)->align) {
404
			case FLD_ALIGN_LEFT:
405
			case FLD_ALIGN_RIGHT:
406
			case FLD_ALIGN_CENTER:
407
			case FLD_ALIGN_COLUMN:
408
				print_fld_str(*fp, (*fp)->title);
409
				break;
410
			case FLD_ALIGN_BAR:
411
				print_bar_title(*fp);
412
				break;
413
			}
414
		}
415
	}
416
	end_line();
417
}
418
419
/* view related functions */
420
void
421
hide_field(field_def *fld)
422
{
423
	if (fld == NULL)
424
		return;
425
426
	fld->flags |= FLD_FLAG_HIDDEN;
427
}
428
429
void
430
show_field(field_def *fld)
431
{
432
	if (fld == NULL)
433
		return;
434
435
	fld->flags &= ~((unsigned int) FLD_FLAG_HIDDEN);
436
}
437
438
void
439
reset_fields(void)
440
{
441
	field_def **fp;
442
	field_def *fld;
443
444
	if (curr_view == NULL)
445
		return;
446
447
	if (curr_view->view == NULL)
448
		return;
449
450
	for (fp = curr_view->view; *fp != NULL; fp++) {
451
		fld = *fp;
452
		fld->start = -1;
453
		fld->width = fld->norm_width;
454
	}
455
}
456
457
void
458
field_setup(void)
459
{
460
	field_def **fp;
461
	field_def *fld;
462
	int st, fwid, change;
463
	int width = columns;
464
465
	reset_fields();
466
467
	dispstart = 0;
468
	st = 0;
469
470
	for (fp = curr_view->view; *fp != NULL; fp++) {
471
		fld = *fp;
472
		if (fld->flags & FLD_FLAG_HIDDEN)
473
			continue;
474
475
		if (width <= 1)
476
			break;
477
478
		if (st != 1)
479
			width--;
480
481
		fld->start = 1;
482
		fwid = fld->width;
483
		st++;
484
		if (fwid >= width) {
485
			fld->width = width;
486
			width = 0;
487
		} else
488
			width -= fwid;
489
	}
490
491
	while (width > 0) {
492
		change = 0;
493
		for (fp = curr_view->view; *fp != NULL; fp++) {
494
			fld = *fp;
495
			if (fld->flags & FLD_FLAG_HIDDEN)
496
				continue;
497
			if ((fld->width < fld->max_width) &&
498
			    (fld->increment <= width)) {
499
				int w = fld->width + fld->increment;
500
				if (w > fld->max_width)
501
					w = fld->max_width;
502
				width += fld->width - w;
503
				fld->width = w;
504
				change = 1;
505
			}
506
			if (width <= 0) break;
507
		}
508
		if (change == 0) break;
509
	}
510
511
	st = 0;
512
	for (fp = curr_view->view; *fp != NULL; fp++) {
513
		fld = *fp;
514
		if (fld->flags & FLD_FLAG_HIDDEN)
515
			continue;
516
		if (fld->start < 0) break;
517
		fld->start = st;
518
		st += fld->width + 1;
519
	}
520
}
521
522
void
523
set_curr_view(struct view_ent *ve)
524
{
525
	field_view *v;
526
527
	reset_fields();
528
529
	if (ve == NULL) {
530
		curr_view_ent = NULL;
531
		curr_view = NULL;
532
		curr_mgr = NULL;
533
		return;
534
	}
535
536
	v = ve->view;
537
538
	if ((curr_view != NULL) && (curr_mgr != v->mgr)) {
539
		gotsig_alarm = 1;
540
		if (v->mgr != NULL && v->mgr->select_fn != NULL)
541
			v->mgr->select_fn();
542
	}
543
544
	curr_view_ent = ve;
545
	curr_view = v;
546
	curr_mgr = v->mgr;
547
	field_setup();
548
	need_update = 1;
549
}
550
551
void
552
add_view(field_view *fv)
553
{
554
	struct view_ent *ent;
555
556
	if (fv == NULL)
557
		return;
558
559
	if (fv->view == NULL || fv->name == NULL || fv->mgr == NULL)
560
		return;
561
562
	ent = malloc(sizeof(struct view_ent));
563
	if (ent == NULL)
564
		return;
565
566
	ent->view = fv;
567
	TAILQ_INSERT_TAIL(&view_head, ent, entries);
568
569
	if (curr_view == NULL)
570
		set_curr_view(ent);
571
}
572
573
int
574
set_view(const char *opt)
575
{
576
	struct view_ent *ve, *vm = NULL;
577
	field_view *v;
578
	int len;
579
580
	if (opt == NULL || (len = strlen(opt)) == 0)
581
		return 1;
582
583
	TAILQ_FOREACH(ve, &view_head, entries) {
584
		v = ve->view;
585
		if (strncasecmp(opt, v->name, len) == 0) {
586
			if (vm)
587
				return 1;
588
			vm = ve;
589
		}
590
	}
591
592
	if (vm) {
593
		set_curr_view(vm);
594
		return 0;
595
	}
596
597
	return 1;
598
}
599
600
void
601
foreach_view(void (*callback)(field_view *))
602
{
603
	struct view_ent *ve;
604
605
	TAILQ_FOREACH(ve, &view_head, entries) {
606
		callback(ve->view);
607
	}
608
}
609
610
int
611
set_view_hotkey(int ch)
612
{
613
	struct view_ent *ve;
614
	field_view *v;
615
	int key = tolower(ch);
616
617
	TAILQ_FOREACH(ve, &view_head, entries) {
618
		v = ve->view;
619
		if (key == v->hotkey) {
620
			set_curr_view(ve);
621
			return 1;
622
		}
623
	}
624
625
	return 0;
626
}
627
628
void
629
next_view(void)
630
{
631
	struct view_ent *ve;
632
633
	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
634
		return;
635
636
	ve = TAILQ_NEXT(curr_view_ent, entries);
637
	if (ve == NULL)
638
		ve = TAILQ_FIRST(&view_head);
639
640
	set_curr_view(ve);
641
}
642
643
void
644
prev_view(void)
645
{
646
	struct view_ent *ve;
647
648
	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
649
		return;
650
651
	ve = TAILQ_PREV(curr_view_ent, view_list, entries);
652
	if (ve == NULL)
653
		ve = TAILQ_LAST(&view_head, view_list);
654
655
	set_curr_view(ve);
656
}
657
658
/* generic field printing */
659
660
void
661
print_fld_age(field_def *fld, unsigned int age)
662
{
663
	int len;
664
	unsigned int h, m, s;
665
666
	if (fld == NULL)
667
		return;
668
	len = fld->width;
669
670
	if (len < 1)
671
		return;
672
673
	s = age % 60;
674
	m = age / 60;
675
	h = m / 60;
676
	m %= 60;
677
678
	tb_start();
679
	if (tbprintf("%02u:%02u:%02u", h, m, s) <= len)
680
		goto ok;
681
682
	tb_start();
683
	if (tbprintf("%u", age) <= len)
684
		goto ok;
685
686
	tb_start();
687
	age /= 60;
688
	if (tbprintf("%um", age) <= len)
689
		goto ok;
690
	if (age == 0)
691
		goto err;
692
693
	tb_start();
694
	age /= 60;
695
	if (tbprintf("%uh", age) <= len)
696
		goto ok;
697
	if (age == 0)
698
		goto err;
699
700
	tb_start();
701
	age /= 24;
702
	if (tbprintf("%ud", age) <= len)
703
		goto ok;
704
705
err:
706
	print_fld_str(fld, "*");
707
	tb_end();
708
	return;
709
710
ok:
711
	print_fld_tb(fld);
712
}
713
714
void
715
print_fld_sdiv(field_def *fld, u_int64_t size, int d)
716
{
717
	int len;
718
719
	if (fld == NULL)
720
		return;
721
722
	len = fld->width;
723
	if (len < 1)
724
		return;
725
726
	tb_start();
727
	if (tbprintft("%llu", size) <= len)
728
		goto ok;
729
730
	tb_start();
731
	size /= d;
732
	if (tbprintft("%lluK", size) <= len)
733
		goto ok;
734
	if (size == 0)
735
		goto err;
736
737
	tb_start();
738
	size /= d;
739
	if (tbprintft("%lluM", size) <= len)
740
		goto ok;
741
	if (size == 0)
742
		goto err;
743
744
	tb_start();
745
	size /= d;
746
	if (tbprintft("%lluG", size) <= len)
747
		goto ok;
748
	if (size == 0)
749
		goto err;
750
751
	tb_start();
752
	size /= d;
753
	if (tbprintft("%lluT", size) <= len)
754
		goto ok;
755
756
err:
757
	print_fld_str(fld, "*");
758
	tb_end();
759
	return;
760
761
ok:
762
	print_fld_tb(fld);
763
}
764
765
void
766
print_fld_size(field_def *fld, u_int64_t size)
767
{
768
	print_fld_sdiv(fld, size, 1024);
769
}
770
771
void
772
print_fld_ssdiv(field_def *fld, int64_t size, int d)
773
{
774
	int len;
775
776
	if (fld == NULL)
777
		return;
778
779
	len = fld->width;
780
	if (len < 1)
781
		return;
782
783
	tb_start();
784
	if (tbprintft("%lld", size) <= len)
785
		goto ok;
786
787
	tb_start();
788
	size /= d;
789
	if (tbprintft("%lldK", size) <= len)
790
		goto ok;
791
	if (size == 0)
792
		goto err;
793
794
	tb_start();
795
	size /= d;
796
	if (tbprintft("%lldM", size) <= len)
797
		goto ok;
798
	if (size == 0)
799
		goto err;
800
801
	tb_start();
802
	size /= d;
803
	if (tbprintft("%lldG", size) <= len)
804
		goto ok;
805
	if (size == 0)
806
		goto err;
807
808
	tb_start();
809
	size /= d;
810
	if (tbprintft("%lldT", size) <= len)
811
		goto ok;
812
813
err:
814
	print_fld_str(fld, "*");
815
	tb_end();
816
	return;
817
818
ok:
819
	print_fld_tb(fld);
820
}
821
822
void
823
print_fld_ssize(field_def *fld, int64_t size)
824
{
825
	print_fld_ssdiv(fld, size, 1024);
826
}
827
828
void
829
print_fld_rate(field_def *fld, double rate)
830
{
831
	if (rate < 0) {
832
		print_fld_str(fld, "*");
833
	} else {
834
		print_fld_size(fld, rate);
835
	}
836
}
837
838
void
839
print_fld_bw(field_def *fld, double bw)
840
{
841
	if (bw < 0) {
842
		print_fld_str(fld, "*");
843
	} else {
844
		print_fld_sdiv(fld, bw, 1000);
845
	}
846
}
847
848
void
849
print_fld_uint(field_def *fld, unsigned int size)
850
{
851
	int len;
852
853
	if (fld == NULL)
854
		return;
855
856
	len = fld->width;
857
	if (len < 1)
858
		return;
859
860
	tb_start();
861
	if (tbprintft("%u", size) > len)
862
		print_fld_str(fld, "*");
863
	else
864
		print_fld_tb(fld);
865
	tb_end();
866
}
867
868
void
869
print_fld_float(field_def *fld, double f, int prec)
870
{
871
	int len;
872
873
	if (fld == NULL)
874
		return;
875
876
	len = fld->width;
877
	if (len < 1)
878
		return;
879
880
	tb_start();
881
	if (tbprintf("%*.*f", len, prec, f) > len)
882
		print_fld_str(fld, "*");
883
	else
884
		print_fld_tb(fld);
885
	tb_end();
886
}
887
888
889
/* ordering */
890
891
void
892
set_order(const char *opt)
893
{
894
	order_type *o;
895
896
	if (curr_view == NULL || curr_view->mgr == NULL)
897
		return;
898
899
	curr_view->mgr->order_curr = curr_view->mgr->order_list;
900
901
	if (opt == NULL)
902
		return;
903
904
	o = curr_view->mgr->order_list;
905
906
	if (o == NULL)
907
		return;
908
909
	for (;o->name != NULL; o++) {
910
		if (strcasecmp(opt, o->match) == 0) {
911
			curr_view->mgr->order_curr = o;
912
			return;
913
		}
914
	}
915
}
916
917
int
918
set_order_hotkey(int ch)
919
{
920
	order_type *o;
921
	int key = ch;
922
923
	if (curr_view == NULL || curr_view->mgr == NULL)
924
		return 0;
925
926
	o = curr_view->mgr->order_list;
927
928
	if (o == NULL)
929
		return 0;
930
931
	for (;o->name != NULL; o++) {
932
		if (key == o->hotkey) {
933
			if (curr_view->mgr->order_curr == o) {
934
				sortdir *= -1;
935
			} else {
936
				curr_view->mgr->order_curr = o;
937
			}
938
			return 1;
939
		}
940
	}
941
942
	return 0;
943
}
944
945
void
946
next_order(void)
947
{
948
	order_type *o, *oc;
949
950
	if (curr_view->mgr->order_list == NULL)
951
		return;
952
953
	oc = curr_view->mgr->order_curr;
954
955
	for (o = curr_view->mgr->order_list; o->name != NULL; o++) {
956
		if (oc == o) {
957
			o++;
958
			if (o->name == NULL)
959
				break;
960
			curr_view->mgr->order_curr = o;
961
			return;
962
		}
963
	}
964
965
	curr_view->mgr->order_curr = curr_view->mgr->order_list;
966
}
967
968
969
/* main program functions */
970
971
int
972
read_view(void)
973
{
974
	if (curr_mgr == NULL)
975
		return (0);
976
977
	if (paused)
978
		return (0);
979
980
	if (curr_mgr->read_fn != NULL)
981
		return (curr_mgr->read_fn());
982
983
	return (0);
984
}
985
986
987
int
988
disp_update(void)
989
{
990
	int li;
991
992
	if (maxprint < 0)
993
		dispstart = 0;
994
	else if (dispstart + maxprint > num_disp)
995
		dispstart = num_disp - maxprint;
996
997
	if (dispstart < 0)
998
		dispstart = 0;
999
1000
	if (curr_view == NULL)
1001
		return 0;
1002
1003
	if (curr_mgr != NULL) {
1004
		curr_line = 0;
1005
1006
		if (curr_mgr->header_fn != NULL) {
1007
			li = curr_mgr->header_fn();
1008
			if (li < 0)
1009
				return (1);
1010
			curr_line = ++li;
1011
			home_line = li + maxprint + 1;
1012
		}
1013
1014
		print_title();
1015
1016
		if (curr_mgr->print_fn != NULL)
1017
			curr_mgr->print_fn();
1018
	}
1019
1020
	return (0);
1021
}
1022
1023
void
1024
sort_view(void)
1025
{
1026
	if (curr_mgr != NULL)
1027
		if (curr_mgr->sort_fn != NULL)
1028
			curr_mgr->sort_fn();
1029
}
1030
1031
void
1032
sig_close(int sig)
1033
{
1034
	gotsig_close = 1;
1035
}
1036
1037
void
1038
sig_resize(int sig)
1039
{
1040
	gotsig_resize = 1;
1041
}
1042
1043
void
1044
sig_alarm(int sig)
1045
{
1046
	gotsig_alarm = 1;
1047
}
1048
1049
void
1050
setup_term(int dmax)
1051
{
1052
	max_disp = dmax;
1053
	maxprint = dmax;
1054
1055
	if (rawmode) {
1056
		columns = rawwidth;
1057
		lines = DEFAULT_HEIGHT;
1058
		clear_linebuf();
1059
	} else {
1060
		if (dmax < 0)
1061
			dmax = 0;
1062
1063
		screen = newterm(NULL, stdout, stdin);
1064
		if (screen == NULL) {
1065
			rawmode = 1;
1066
			interactive = 0;
1067
			setup_term(dmax);
1068
			return;
1069
		}
1070
		columns = COLS;
1071
		lines = LINES;
1072
1073
		if (maxprint > lines - HEADER_LINES)
1074
			maxprint = lines - HEADER_LINES;
1075
1076
		nonl();
1077
		keypad(stdscr, TRUE);
1078
		intrflush(stdscr, FALSE);
1079
1080
		halfdelay(10);
1081
		noecho();
1082
	}
1083
1084
	if (dmax == 0)
1085
		maxprint = lines - HEADER_LINES;
1086
1087
	field_setup();
1088
}
1089
1090
void
1091
do_resize_term(void)
1092
{
1093
	struct winsize ws;
1094
1095
	if (rawmode)
1096
		return;
1097
1098
	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
1099
		return;
1100
1101
	resizeterm(ws.ws_row, ws.ws_col);
1102
1103
	columns = COLS;
1104
	lines = LINES;
1105
1106
	maxprint = max_disp;
1107
1108
	if (maxprint == 0 || maxprint > lines - HEADER_LINES)
1109
		maxprint = lines - HEADER_LINES;
1110
1111
	clear();
1112
1113
	field_setup();
1114
}
1115
1116
struct command *
1117
command_set(struct command *cmd, const char *init)
1118
{
1119
	struct command *prev = curr_cmd;
1120
1121
	if (cmd) {
1122
		if (init) {
1123
			cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf));
1124
			if (cmd_len >= sizeof(cmdbuf)) {
1125
				cmdbuf[0] = '\0';
1126
				cmd_len = 0;
1127
			}
1128
		} else {
1129
			cmd_len = 0;
1130
			cmdbuf[0] = 0;
1131
		}
1132
	}
1133
	curr_message = NULL;
1134
	curr_cmd = cmd;
1135
	need_update = 1;
1136
	return prev;
1137
}
1138
1139
const char *
1140
message_set(const char *msg) {
1141
	char *prev = curr_message;
1142
	if (msg)
1143
		curr_message = strdup(msg);
1144
	else
1145
		curr_message = NULL;
1146
	free(prev);
1147
	return NULL;
1148
}
1149
1150
void
1151
print_cmdline(void)
1152
{
1153
	if (curr_cmd) {
1154
		attron(A_STANDOUT);
1155
		mvprintw(home_line, 0, "%s: ", curr_cmd->prompt);
1156
		attroff(A_STANDOUT);
1157
		printw("%s", cmdbuf);
1158
	} else if (curr_message) {
1159
		mvprintw(home_line, 0, "> %s", curr_message);
1160
	}
1161
	clrtoeol();
1162
}
1163
1164
1165
void
1166
cmd_keyboard(int ch)
1167
{
1168
	if (curr_cmd == NULL)
1169
		return;
1170
1171
	if (ch > 0 && isprint(ch)) {
1172
		if (cmd_len < sizeof(cmdbuf) - 1) {
1173
			cmdbuf[cmd_len++] = ch;
1174
			cmdbuf[cmd_len] = 0;
1175
		} else
1176
			beep();
1177
	}
1178
1179
	switch (ch) {
1180
	case KEY_ENTER:
1181
	case 0x0a:
1182
	case 0x0d:
1183
	{
1184
		struct command * c = command_set(NULL, NULL);
1185
		c->exec(cmdbuf);
1186
		break;
1187
	}
1188
	case KEY_BACKSPACE:
1189
	case KEY_DC:
1190
	case CTRL_H:
1191
		if (cmd_len > 0) {
1192
			cmdbuf[--cmd_len] = 0;
1193
		} else
1194
			beep();
1195
		break;
1196
	case 0x1b:
1197
	case CTRL_G:
1198
		if (cmd_len > 0) {
1199
			cmdbuf[0] = '\0';
1200
			cmd_len = 0;
1201
		} else
1202
			command_set(NULL, NULL);
1203
		break;
1204
	default:
1205
		break;
1206
	}
1207
}
1208
1209
void
1210
keyboard(void)
1211
{
1212
	int ch;
1213
1214
	ch = getch();
1215
1216
	if (curr_cmd) {
1217
		cmd_keyboard(ch);
1218
		print_cmdline();
1219
		return;
1220
	}
1221
1222
	if (curr_mgr != NULL)
1223
		if (curr_mgr->key_fn != NULL)
1224
			if (curr_mgr->key_fn(ch))
1225
				return;
1226
1227
	if (curr_message != NULL) {
1228
		if (ch > 0) {
1229
			curr_message = NULL;
1230
			need_update = 1;
1231
		}
1232
	}
1233
1234
	switch (ch) {
1235
	case ' ':
1236
		gotsig_alarm = 1;
1237
		break;
1238
	case 'o':
1239
		next_order();
1240
		need_sort = 1;
1241
		break;
1242
	case 'p':
1243
		paused = !paused;
1244
		gotsig_alarm = 1;
1245
		break;
1246
	case 'q':
1247
		gotsig_close = 1;
1248
		break;
1249
	case 'r':
1250
		sortdir *= -1;
1251
		need_sort = 1;
1252
		break;
1253
	case 'v':
1254
		/* FALLTHROUGH */
1255
	case KEY_RIGHT:
1256
		/* FALLTHROUGH */
1257
	case CTRL_F:
1258
		next_view();
1259
		break;
1260
	case KEY_LEFT:
1261
		/* FALLTHROUGH */
1262
	case CTRL_B:
1263
		prev_view();
1264
		break;
1265
	case KEY_DOWN:
1266
		/* FALLTHROUGH */
1267
	case CTRL_N:
1268
		dispstart++;
1269
		need_update = 1;
1270
		break;
1271
	case KEY_UP:
1272
		/* FALLTHROUGH */
1273
	case CTRL_P:
1274
		dispstart--;
1275
		need_update = 1;
1276
		break;
1277
	case KEY_NPAGE:
1278
		/* FALLTHROUGH */
1279
	case CTRL_V:
1280
		dispstart += maxprint;
1281
		need_update = 1;
1282
		break;
1283
	case KEY_PPAGE:
1284
		/* FALLTHROUGH */
1285
	case META_V:
1286
		dispstart -= maxprint;
1287
		need_update = 1;
1288
		break;
1289
	case KEY_HOME:
1290
		/* FALLTHROUGH */
1291
	case CTRL_A:
1292
		dispstart = 0;
1293
		need_update = 1;
1294
		break;
1295
	case KEY_END:
1296
		/* FALLTHROUGH */
1297
	case CTRL_E:
1298
		dispstart = num_disp;
1299
		need_update = 1;
1300
		break;
1301
	case CTRL_L:
1302
		clear();
1303
		need_update = 1;
1304
		break;
1305
	default:
1306
		break;
1307
	}
1308
1309
	if (set_order_hotkey(ch))
1310
		need_sort = 1;
1311
	else
1312
		set_view_hotkey(ch);
1313
}
1314
1315
void
1316
engine_initialize(void)
1317
{
1318
	signal(SIGTERM, sig_close);
1319
	signal(SIGINT, sig_close);
1320
	signal(SIGQUIT, sig_close);
1321
	signal(SIGWINCH, sig_resize);
1322
	signal(SIGALRM, sig_alarm);
1323
}
1324
1325
void
1326
engine_loop(int countmax)
1327
{
1328
	int count = 0;
1329
1330
	for (;;) {
1331
		if (gotsig_alarm) {
1332
			read_view();
1333
			need_sort = 1;
1334
			gotsig_alarm = 0;
1335
			ualarm(udelay, 0);
1336
		}
1337
1338
		if (need_sort) {
1339
			sort_view();
1340
			need_sort = 0;
1341
			need_update = 1;
1342
1343
			/* XXX if sort took too long */
1344
			if (gotsig_alarm) {
1345
				gotsig_alarm = 0;
1346
				ualarm(udelay, 0);
1347
			}
1348
		}
1349
1350
		if (need_update) {
1351
			erase();
1352
			if (!averageonly ||
1353
			    (averageonly && count == countmax - 1))
1354
				disp_update();
1355
			end_page();
1356
			need_update = 0;
1357
			if (countmax && ++count >= countmax)
1358
				break;
1359
		}
1360
1361
		if (gotsig_close)
1362
			break;
1363
		if (gotsig_resize) {
1364
			do_resize_term();
1365
			gotsig_resize = 0;
1366
			need_update = 1;
1367
		}
1368
1369
		if (interactive && need_update == 0)
1370
			keyboard();
1371
		else if (interactive == 0)
1372
			usleep(udelay);
1373
	}
1374
1375
	if (rawmode == 0)
1376
		endwin();
1377
}
1378
1379
int
1380
check_termcap(void)
1381
{
1382
	char *term_name;
1383
	int status;
1384
	static struct termios screen_settings;
1385
1386
	if (!interactive)
1387
		/* pretend we have a dumb terminal */
1388
		return(1);
1389
1390
	/* get the terminal name */
1391
	term_name = getenv("TERM");
1392
	if (term_name == NULL)
1393
		return(1);
1394
1395
	/* now get the termcap entry */
1396
	if ((status = tgetent(NULL, term_name)) != 1) {
1397
		if (status == -1)
1398
			warnx("can't open termcap file");
1399
		else
1400
			warnx("no termcap entry for a `%s' terminal",
1401
			    term_name);
1402
1403
		/* pretend it's dumb and proceed */
1404
		return(1);
1405
	}
1406
1407
	/* "hardcopy" immediately indicates a very stupid terminal */
1408
	if (tgetflag("hc"))
1409
		return(1);
1410
1411
        /* get necessary capabilities */
1412
        if (tgetstr("cl", NULL) == NULL || tgetstr("cm", NULL) == NULL)
1413
		return(1);
1414
1415
	/* if stdout is not a terminal, pretend we are a dumb terminal */
1416
	if (tcgetattr(STDOUT_FILENO, &screen_settings) == -1)
1417
		return(1);
1418
1419
	return(0);
1420
}