source: trunk/ncurses/tack/control.c@ 2622

Last change on this file since 2622 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

File size: 13.8 KB
Line 
1/*
2** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
3**
4** This file is part of TACK.
5**
6** TACK is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2, or (at your option)
9** any later version.
10**
11** TACK is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with TACK; see the file COPYING. If not, write to
18** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19** Boston, MA 02110-1301, USA
20*/
21
22#include <tack.h>
23
24#if HAVE_SYS_TIME_H
25#include <sys/time.h>
26#endif
27
28MODULE_ID("$Id: control.c,v 1.8 2005/09/17 19:49:16 tom Exp $")
29
30/* terminfo test program control subroutines */
31
32#if HAVE_GETTIMEOFDAY
33#define MY_TIMER struct timeval
34#else
35#define MY_TIMER time_t
36#endif
37
38/* globals */
39int test_complete; /* counts number of tests completed */
40
41char txt_longer_test_time[80]; /* +) use longer time */
42char txt_shorter_test_time[80]; /* -) use shorter time */
43static int pad_test_duration = 1; /* number of seconds for a pad test */
44int auto_pad_mode; /* run the time tests */
45int no_alarm_event; /* TRUE if the alarm has not gone off yet */
46unsigned long usec_run_time; /* length of last test in microseconds */
47static MY_TIMER stop_watch[MAX_TIMERS]; /* Hold the start timers */
48
49char txt_longer_augment[80]; /* >) use bigger augment */
50char txt_shorter_augment[80]; /* <) use smaller augment */
51
52/* caps under test data base */
53int tt_delay_max; /* max number of milliseconds we can delay */
54int tt_delay_used; /* number of milliseconds consumed in delay */
55const char *tt_cap[TT_MAX]; /* value of string */
56int tt_affected[TT_MAX]; /* lines or columns effected (repetition factor) */
57int tt_count[TT_MAX]; /* Number of times sent */
58int tt_delay[TT_MAX]; /* Number of milliseconds delay */
59int ttp; /* number of entries used */
60
61/* Saved value of the above data base */
62const char *tx_cap[TT_MAX]; /* value of string */
63int tx_affected[TT_MAX]; /* lines or columns effected (repetition factor) */
64int tx_count[TT_MAX]; /* Number of times sent */
65int tx_index[TT_MAX]; /* String index */
66int tx_delay[TT_MAX]; /* Number of milliseconds delay */
67int txp; /* number of entries used */
68int tx_characters; /* printing characters sent by test */
69unsigned long tx_cps; /* characters per second */
70static struct test_list *tx_source; /* The test that generated this data */
71
72#define RESULT_BLOCK 1024
73static int blocks; /* number of result blocks available */
74static struct test_results *results; /* pointer to next available */
75static struct test_results *pads[STRCOUNT]; /* save pad results here */
76
77/*
78** event_start(number)
79**
80** Begin the stopwatch at the current time-of-day.
81*/
82void
83event_start(int n)
84{
85#if HAVE_GETTIMEOFDAY
86 (void) gettimeofday(&stop_watch[n], (struct timezone *)0);
87#else
88 stop_watch[n] = time((time_t *)0);
89#endif
90}
91
92/*
93** event_time(number)
94**
95** Return the number of milliseconds since this stop watch began.
96*/
97long
98event_time(int n)
99{
100#if HAVE_GETTIMEOFDAY
101 MY_TIMER current_time;
102
103 (void) gettimeofday(&current_time, (struct timezone *)0);
104 return ((current_time.tv_sec - stop_watch[n].tv_sec) * 1000000)
105 + current_time.tv_usec - stop_watch[n].tv_usec;
106#else
107 return (time((time_t *)0) - stop_watch[n]) * 1000;
108#endif
109}
110
111/*****************************************************************************
112 *
113 * Execution control for string capability tests
114 *
115 *****************************************************************************/
116
117/*
118** get_next_block()
119**
120** Get a results block for pad test data.
121*/
122static struct test_results *
123get_next_block(void)
124{
125 if (blocks <= 0) {
126 results = (struct test_results *)
127 malloc(sizeof(struct test_results) * RESULT_BLOCK);
128 if (!results) {
129 ptextln("Malloc failed");
130 return (struct test_results *) 0;
131 }
132 blocks = RESULT_BLOCK;
133 }
134 blocks--;
135 return results++;
136}
137
138/*
139** set_augment_txt()
140**
141** Initialize the augment menu selections
142*/
143void
144set_augment_txt(void)
145{
146 sprintf(txt_longer_augment,
147 ">) Change lines/characters effected to %d", augment << 1);
148 sprintf(txt_shorter_augment,
149 "<) Change lines/characters effected to %d", augment >> 1);
150}
151
152void
153control_init(void)
154{
155 sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
156 pad_test_duration + 1);
157 sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
158 pad_test_duration - 1);
159 set_augment_txt();
160}
161
162/*
163** msec_cost(cap, affected-count)
164**
165** Return the number of milliseconds delay needed by the cap.
166*/
167int
168msec_cost(
169 const char *const cap,
170 int affcnt)
171{
172 int dec, value, total, star, ch;
173 const char *cp;
174
175 if (!cap) {
176 return 0;
177 }
178 total = 0;
179 for (cp = cap; *cp; cp++) {
180 if (*cp == '$' && cp[1] == '<') {
181 star = 1;
182 value = dec = 0;
183 for (cp += 2; (ch = *cp); cp++) {
184 if (ch >= '0' && ch <= '9') {
185 value = value * 10 + (ch - '0');
186 dec *= 10;
187 } else
188 if (ch == '.') {
189 dec = 1;
190 } else
191 if (ch == '*') {
192 star = affcnt;
193 } else
194 if (ch == '>') {
195 break;
196 }
197 }
198 if (dec > 1) {
199 total += (value * star) / dec;
200 } else {
201 total += (value * star);
202 }
203 }
204 }
205 return total;
206}
207
208/*
209** liberated(cap)
210**
211** Return the cap without padding
212*/
213char *
214liberated(char *cap)
215{
216 static char cb[1024];
217 char *ts, *ls;
218
219 cb[0] = '\0';
220 ls = NULL;
221 if (cap) {
222 for (ts = cb; (*ts = *cap); ++cap) {
223 if (*cap == '$' && cap[1] == '<') {
224 ls = ts;
225 }
226 ++ts;
227 if (*cap == '>') {
228 if (ls) {
229 ts = ls;
230 ls = NULL;
231 }
232 }
233 }
234 }
235 return cb;
236}
237
238/*
239** page_loop()
240**
241** send CR/LF or go home and bump letter
242*/
243void
244page_loop(void)
245{
246 if (line_count + 2 >= lines) {
247 NEXT_LETTER;
248 go_home();
249 } else {
250 put_crlf();
251 }
252}
253
254/*
255** skip_pad_test(test-list-entry, state, ch, text)
256**
257** Print the start test line. Handle start up commands.
258** Return TRUE if a return is requested.
259*/
260int
261skip_pad_test(
262 struct test_list *test,
263 int *state,
264 int *ch,
265 const char *text)
266{
267 char rep_text[16];
268
269 while(1) {
270 if (text) {
271 ptext(text);
272 }
273 if ((test->flags & MENU_LC_MASK)) {
274 sprintf(rep_text, " *%d", augment);
275 ptext(rep_text);
276 }
277 ptext(" [n] > ");
278 *ch = wait_here();
279 if (*ch == 's') {
280 /* Skip is converted to next */
281 *ch = 'n';
282 return TRUE;
283 }
284 if (*ch == 'q') {
285 /* Quit is converted to help */
286 *ch = '?';
287 return TRUE;
288 }
289 if (*ch == '\r' || *ch == '\n' || *ch == 'n' || *ch == 'r') {
290 /* this is the only response that allows the test to run */
291 *ch = 0;
292 }
293 if (subtest_menu(pad_test_list, state, ch)) {
294 continue;
295 }
296 return (*ch != 0);
297 }
298}
299
300/*
301** pad_done_message(test_list)
302**
303** Print the Done message and request input.
304*/
305void
306pad_done_message(
307 struct test_list *test,
308 int *state,
309 int *ch)
310{
311 int default_action = 0;
312 char done_message[128];
313 char rep_text[16];
314
315 while (1) {
316 if ((test->flags & MENU_LC_MASK)) {
317 sprintf(rep_text, "*%d", augment);
318 } else {
319 rep_text[0] = '\0';
320 }
321 if (test->caps_done) {
322 sprintf(done_message, "(%s)%s Done ", test->caps_done,
323 rep_text);
324 ptext(done_message);
325 } else {
326 if (rep_text[0]) {
327 ptext(rep_text);
328 ptext(" ");
329 }
330 ptext("Done ");
331 }
332 if (debug_level & 2) {
333 dump_test_stats(test, state, ch);
334 } else {
335 *ch = wait_here();
336 }
337 if (*ch == '\r' || *ch == '\n') {
338 *ch = default_action;
339 return;
340 }
341 if (*ch == 's' || *ch == 'n') {
342 *ch = 0;
343 return;
344 }
345 if (strchr(pad_repeat_test, *ch)) {
346 /* default action is now repeat */
347 default_action = 'r';
348 }
349 if (subtest_menu(pad_test_list, state, ch)) {
350 continue;
351 }
352 return;
353 }
354}
355
356/*
357** sliding_scale(dividend, factor, divisor)
358**
359** Return (dividend * factor) / divisor
360*/
361int
362sliding_scale(
363 int dividend,
364 int factor,
365 unsigned long divisor)
366{
367 double d = dividend;
368
369 if (divisor) {
370 d = (d * (double) factor) / (double) divisor;
371 return (int) (d + 0.5);
372 }
373 return 0;
374}
375
376/*
377** pad_test_startup()
378**
379** Do the stuff needed to begin a test.
380*/
381void
382pad_test_startup(
383 int do_clear)
384{
385 if (do_clear) {
386 put_clear();
387 }
388 repeats = augment;
389 raw_characters_sent = 0;
390 test_complete = ttp = char_count = tt_delay_used = 0;
391 letter = letters[letter_number = 0];
392 if (pad_test_duration <= 0) {
393 pad_test_duration = 1;
394 }
395 tt_delay_max = pad_test_duration * 1000;
396 set_alarm_clock(pad_test_duration);
397 event_start(TIME_TEST);
398}
399
400/*
401** still_testing()
402**
403** This function is called to see if the test loop should be terminated.
404*/
405int
406still_testing(void)
407{
408 fflush(stdout);
409 test_complete++;
410 return EXIT_CONDITION;
411}
412
413/*
414** pad_test_shutdown()
415**
416** Do the stuff needed to end a test.
417*/
418void
419pad_test_shutdown(
420 struct test_list *t,
421 int crlf)
422{
423 int i;
424 int counts; /* total counts */
425 int ss; /* Save string index */
426 int cpo; /* characters per operation */
427 int delta; /* difference in characters */
428 int bogus; /* Time is inaccurate */
429 struct test_results *r; /* Results of current test */
430 int ss_index[TT_MAX]; /* String index */
431
432 if (tty_can_sync == SYNC_TESTED) {
433 bogus = tty_sync_error();
434 } else {
435 bogus = 1;
436 }
437 usec_run_time = event_time(TIME_TEST);
438 tx_source = t;
439 tx_characters = raw_characters_sent;
440 tx_cps = sliding_scale(tx_characters, 1000000, usec_run_time);
441
442 /* save the data base */
443 for (txp = ss = counts = 0; txp < ttp; txp++) {
444 tx_cap[txp] = tt_cap[txp];
445 tx_count[txp] = tt_count[txp];
446 tx_delay[txp] = tt_delay[txp];
447 tx_affected[txp] = tt_affected[txp];
448 tx_index[txp] = get_string_cap_byvalue(tt_cap[txp]);
449 if (tx_index[txp] >= 0) {
450 if (cap_match(t->caps_done, strnames[tx_index[txp]])) {
451 ss_index[ss++] = txp;
452 counts += tx_count[txp];
453 }
454 }
455 }
456
457 if (crlf) {
458 put_crlf();
459 }
460 if (counts == 0 || tty_cps == 0 || bogus) {
461 /* nothing to do */
462 return;
463 }
464 /* calculate the suggested pad times */
465 delta = usec_run_time - sliding_scale(tx_characters, 1000000, tty_cps);
466 if (delta < 0) {
467 /* probably should bump tx_characters */
468 delta = 0;
469 }
470 cpo = delta / counts;
471 for (i = 0; i < ss; i++) {
472 if (!(r = get_next_block())) {
473 return;
474 }
475 r->next = pads[tx_index[ss_index[i]]];
476 pads[tx_index[ss_index[i]]] = r;
477 r->test = t;
478 r->reps = tx_affected[ss_index[i]];
479 r->delay = cpo;
480 }
481}
482
483/*
484** show_cap_results(index)
485**
486** Display the previous results
487*/
488static void
489show_cap_results(
490 int x)
491{
492 struct test_results *r; /* a result */
493 int delay;
494
495 if ((r = pads[x])) {
496 sprintf(temp, "(%s)", strnames[x]);
497 ptext(temp);
498 while (r) {
499 sprintf(temp, "$<%d>", r->delay / 1000);
500 put_columns(temp, (int) strlen(temp), 10);
501 r = r->next;
502 }
503 r = pads[x];
504 while (r) {
505 if (r->reps > 1) {
506 delay = r->delay / (r->reps * 100);
507 sprintf(temp, "$<%d.%d*>", delay / 10, delay % 10);
508 put_columns(temp, (int) strlen(temp), 10);
509 }
510 r = r->next;
511 }
512 put_crlf();
513 }
514}
515
516/*
517** dump_test_stats(test_list, status, ch)
518**
519** Dump the statistics about the last test
520*/
521void
522dump_test_stats(
523 struct test_list *t,
524 int *state,
525 int *ch)
526{
527 int i, j;
528 char tbuf[32];
529 int x[32];
530
531 put_crlf();
532 if (tx_source && tx_source->caps_done) {
533 cap_index(tx_source->caps_done, x);
534 if (x[0] >= 0) {
535 sprintf(temp, "Caps summary for (%s)",
536 tx_source->caps_done);
537 ptextln(temp);
538 for (i = 0; x[i] >= 0; i++) {
539 show_cap_results(x[i]);
540 }
541 put_crlf();
542 }
543 }
544 sprintf(tbuf, "%011lu", usec_run_time);
545 sprintf(temp, "Test time: %lu.%s, characters per second %lu, characters %d",
546 usec_run_time / 1000000UL, &tbuf[5], tx_cps, tx_characters);
547 ptextln(temp);
548 for (i = 0; i < txp; i++) {
549 if ((j = get_string_cap_byvalue(tx_cap[i])) >= 0) {
550 sprintf(tbuf, "(%s)", strnames[j]);
551 } else {
552 strcpy(tbuf, "(?)");
553 }
554 sprintf(temp, "%8d %3d $<%3d> %8s %s",
555 tx_count[i], tx_affected[i], tx_delay[i],
556 tbuf, expand(tx_cap[i]));
557 putln(temp);
558 }
559 generic_done_message(t, state, ch);
560}
561
562/*
563** longer_test_time(test_list, status, ch)
564**
565** Extend the number of seconds for each test.
566*/
567void
568longer_test_time(
569 struct test_list *t GCC_UNUSED,
570 int *state GCC_UNUSED,
571 int *ch)
572{
573 pad_test_duration += 1;
574 sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
575 pad_test_duration + 1);
576 sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
577 pad_test_duration - 1);
578 sprintf(temp, "Tests will run for %d seconds", pad_test_duration);
579 ptext(temp);
580 *ch = REQUEST_PROMPT;
581}
582
583/*
584** shorter_test_time(test_list, status, ch)
585**
586** Shorten the number of seconds for each test.
587*/
588void
589shorter_test_time(
590 struct test_list *t GCC_UNUSED,
591 int *state GCC_UNUSED,
592 int *ch)
593{
594 if (pad_test_duration > 1) {
595 pad_test_duration -= 1;
596 sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
597 pad_test_duration + 1);
598 sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
599 pad_test_duration - 1);
600 }
601 sprintf(temp, "Tests will run for %d second%s", pad_test_duration,
602 pad_test_duration > 1 ? "s" : "");
603 ptext(temp);
604 *ch = REQUEST_PROMPT;
605}
606
607/*
608** longer_augment(test_list, status, ch)
609**
610** Lengthen the number of lines/characters effected
611*/
612void
613longer_augment(
614 struct test_list *t,
615 int *state GCC_UNUSED,
616 int *ch)
617{
618 augment <<= 1;
619 set_augment_txt();
620 if (augment_test) {
621 t = augment_test;
622 }
623 sprintf(temp, "The pad tests will effect %d %s.", augment,
624 ((t->flags & MENU_LC_MASK) == MENU_lines) ?
625 "lines" : "characters");
626 ptextln(temp);
627 *ch = REQUEST_PROMPT;
628}
629
630/*
631** shorter_augment(test_list, status, ch)
632**
633** Shorten the number of lines/characters effected
634*/
635void
636shorter_augment(
637 struct test_list *t,
638 int *state GCC_UNUSED,
639 int *ch)
640{
641 if (augment > 1) {
642 /* don't let the augment go to zero */
643 augment >>= 1;
644 }
645 set_augment_txt();
646 if (augment_test) {
647 t = augment_test;
648 }
649 sprintf(temp, "The pad tests will effect %d %s.", augment,
650 ((t->flags & MENU_LC_MASK) == MENU_lines) ?
651 "lines" : "characters");
652 ptextln(temp);
653 *ch = REQUEST_PROMPT;
654}
Note: See TracBrowser for help on using the repository browser.