MFC corrected printing of the slice number when adding a GPT partition.
[dragonfly.git] / contrib / ncurses-5.4 / tack / output.c
blob208210a267d3b38e41ef4c99f97d4bcbe81a5acf
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., 59 Temple Place - Suite 330,
19 ** Boston, MA 02111-1307, USA.
21 /* screen formatting and I/O utility functions */
23 #include <tack.h>
24 #include <time.h>
26 MODULE_ID("$Id: output.c,v 1.8 2003/10/25 20:43:43 tom Exp $")
28 /* globals */
29 long char_sent; /* number of characters sent */
30 int char_count; /* counts characters */
31 int line_count; /* counts line feeds */
32 int expand_chars; /* length of expand() string */
33 int replace_mode; /* used to output replace mode padding */
34 int can_go_home; /* TRUE if we can fashion a home command */
35 int can_clear_screen; /* TRUE if we can somehow clear the screen */
36 int raw_characters_sent; /* Total output characters */
37 int log_count; /* Number of characters on a log line */
39 /* translate mode default strings */
40 #define TM_carriage_return TM_string[0].value
41 #define TM_cursor_down TM_string[1].value
42 #define TM_scroll_forward TM_string[2].value
43 #define TM_newline TM_string[3].value
44 #define TM_cursor_left TM_string[4].value
45 #define TM_bell TM_string[5].value
46 #define TM_form_feed TM_string[6].value
47 #define TM_tab TM_string[7].value
49 struct default_string_list TM_string[TM_last] = {
50 {"cr", "\r", 0},
51 {"cud1", "\n", 0},
52 {"ind", "\n", 0},
53 {"nel", "\r\n", 0},
54 {"cub1", "\b", 0},
55 {"bel", "\007", 0},
56 {"ff", "\f", 0},
57 {"ht", "\t", 0}
60 static const char *c0[32] = {
61 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK",
62 "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
63 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
64 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
67 static const char *c1[32] = {
68 "", "", "", "", "IND", "NEL", "SSA", "ESA",
69 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
70 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
71 "", "", "", "CSI", "ST", "OSC", "PM", "APC"
74 int
75 getnext(int mask)
76 { /* get the next character without scan mode
77 conversion */
78 int ch;
79 unsigned char buf;
81 tc_putp(req_for_input);
82 fflush(stdout);
83 if (nodelay_read)
84 while (1) {
85 ch = read(fileno(stdin), &buf, 1);
86 if (ch == -1)
87 return EOF;
88 if (ch == 1)
89 return buf;
91 ch = getchar();
92 if (ch == EOF)
93 return EOF;
94 return ch & mask;
98 int
99 getchp(int mask)
100 { /* read a character with scan mode conversion */
101 if (scan_mode) {
102 tc_putp(req_for_input);
103 fflush(stdout);
104 return scan_key();
105 } else
106 return getnext(mask);
110 ** tc_putch(c)
112 ** Output one character
115 tc_putch(int c)
117 char_sent++;
118 raw_characters_sent++;
119 putchar(c);
120 if ((raw_characters_sent & 31) == 31) {
121 fflush(stdout);
123 if (log_fp) {
124 /* terminal output logging */
125 c = UChar(c);
126 if (c < 32) {
127 fprintf(log_fp, "<%s>", c0[c]);
128 log_count += 5;
129 } else
130 if (c < 127) {
131 fprintf(log_fp, "%c", c);
132 log_count += 1;
133 } else {
134 fprintf(log_fp, "<%02x>", c);
135 log_count += 4;
137 if (c == '\n' || log_count >= 80) {
138 fprintf(log_fp, "\n");
139 log_count = 0;
142 return (c);
146 ** tt_tputs(string, reps)
148 ** Output a string with tputs() translation.
149 ** Use this function inside timing tests.
151 void
152 tt_tputs(const char *string, int reps)
154 int i;
156 if (string) {
157 for (i = 0; i < TT_MAX; i++) {
158 if (i >= ttp) {
159 tt_cap[i] = string;
160 tt_affected[i] = reps;
161 tt_count[i] = 1;
162 tt_delay[i] = msec_cost(string, reps);
163 ttp++;
164 break;
166 if (string == tt_cap[i] && reps == tt_affected[i]) {
167 tt_count[i]++;
168 tt_delay_used += tt_delay[i];
169 break;
172 (void) tputs(string, reps, tc_putch);
177 ** tt_putp(string)
179 ** Output a string with tputs() translation.
180 ** Use this function inside timing tests.
182 void
183 tt_putp(const char *string)
185 tt_tputs(string, 1);
189 ** tt_putparm(string, reps, arg1, arg2)
191 ** Send tt_tputs(tparm(string, args1, arg2), reps)
192 ** Use this function inside timing tests.
194 void
195 tt_putparm(
196 NCURSES_CONST char *string,
197 int reps,
198 int arg1,
199 int arg2)
201 int i;
203 if (string) {
204 for (i = 0; i < TT_MAX; i++) {
205 if (i >= ttp) {
206 tt_cap[i] = string;
207 tt_affected[i] = reps;
208 tt_count[i] = 1;
209 tt_delay[i] = msec_cost(string, reps);
210 ttp++;
211 break;
213 if (string == tt_cap[i] && reps == tt_affected[i]) {
214 tt_count[i]++;
215 tt_delay_used += tt_delay[i];
216 break;
219 (void) tputs(tparm((NCURSES_CONST char *)string, arg1, arg2), reps, tc_putch);
224 ** tc_putp(string)
226 ** Output a string with tputs() translation.
227 ** Use this function instead of putp() so we can track
228 ** the actual number of characters sent.
231 tc_putp(const char *string)
233 return tputs(string, 1, tc_putch);
237 void
238 put_this(int c)
239 { /* output one character (with padding) */
240 tc_putch(c);
241 if (char_padding && replace_mode)
242 tt_putp(char_padding);
246 void
247 put_cr(void)
249 if (translate_mode && carriage_return) {
250 tt_putp(carriage_return);
251 } else {
252 tt_putp(TM_carriage_return);
254 char_count = 0;
258 void
259 put_lf(void)
260 { /* send a linefeed (only works in RAW or
261 CBREAK mode) */
262 if (translate_mode && cursor_down) {
263 tt_putp(cursor_down);
264 } else {
265 tt_putp(TM_cursor_down);
267 line_count++;
271 void
272 put_ind(void)
273 { /* scroll forward (only works in RAW or
274 CBREAK mode) */
275 if (translate_mode && scroll_forward) {
276 tt_putp(scroll_forward);
277 } else {
278 tt_putp(TM_scroll_forward);
280 line_count++;
284 ** put_crlf()
286 ** Send (nel) or <cr> <lf>
288 void
289 put_crlf(void)
291 if (translate_mode && newline) {
292 tt_putp(newline);
293 } else {
294 tt_putp(TM_newline);
296 char_count = 0;
297 line_count++;
301 ** put_new_lines(count)
303 ** Send a number of newlines. (nel)
305 void
306 put_newlines(int n)
308 while (n-- > 0) {
309 put_crlf();
314 ** putchp(character)
316 ** Send one character to the terminal.
317 ** This function does translation of control characters.
319 void
320 putchp(int c)
322 switch (c) {
323 case '\b':
324 if (translate_mode && cursor_left) {
325 tt_putp(cursor_left);
326 } else {
327 tt_putp(TM_cursor_left);
329 char_count--;
330 break;
331 case 7:
332 if (translate_mode && bell) {
333 tt_putp(bell);
334 } else {
335 tt_putp(TM_bell);
337 break;
338 case '\f':
339 if (translate_mode && form_feed) {
340 tt_putp(form_feed);
341 } else {
342 tt_putp(TM_form_feed);
344 char_count = 0;
345 line_count++;
346 break;
347 case '\n':
348 put_crlf();
349 break;
350 case '\r':
351 put_cr();
352 break;
353 case '\t':
354 if (translate_mode && tab) {
355 tt_putp(tab);
356 } else {
357 tt_putp(TM_tab);
359 char_count = ((char_count / 8) + 1) * 8;
360 break;
361 default:
362 put_this(c);
363 char_count++;
364 break;
369 void
370 put_str(const char *s)
371 { /* send the string to the terminal */
372 for (; *s; putchp(*s++));
376 void
377 putln(const char *s)
378 { /* output a string followed by a CR LF */
379 for (; *s; putchp(*s++));
380 put_crlf();
384 void
385 put_columns(const char *s, int len, int w)
386 { /* put out s in column format */
387 int l;
389 if (char_count + w > columns) {
390 put_crlf();
392 l = char_count % w;
393 if (l) {
394 while (l < w) {
395 putchp(' ');
396 l++;
399 if (char_count && char_count + len >= columns) {
400 put_crlf();
402 l = char_count;
403 put_str(s);
404 char_count = l + len;
409 ** ptext(string)
411 ** Output a string but do not assume the terminal will wrap to a
412 ** new line. Break the line at a word boundary then send a CR LF.
413 ** This is more esthetic on 40 column terminals.
415 void
416 ptext(const char *s)
418 const char *t;
420 while (*s) {
421 for (t = s + 1; *t > ' '; t++);
422 if ((char_count != 0) && ((t - s) + char_count >= columns)) {
423 put_crlf();
424 while (*s == ' ')
425 s++;
427 while (s < t) {
428 putchp(*s++);
434 void
435 put_dec(char *f, int i)
436 { /* print a line with a decimal number in it */
437 char tm[128];
439 sprintf(tm, f, i / 10, i % 10);
440 ptext(tm);
444 void
445 three_digit(char *tx, int i)
446 { /* convert the decimal number to a string of
447 at least 3 digits */
448 if (i < 1000)
449 sprintf(tx, "%d.%d", i / 10, i % 10);
450 else
451 sprintf(tx, "%d", i / 10);
455 void
456 ptextln(const char *s)
457 { /* print the text using ptext() then add a CR
458 LF */
459 ptext(s);
460 put_crlf();
464 static void
465 expand_one(int ch, char **v)
466 { /* expand one character */
467 char *t = *v;
469 if (ch & 0x80) { /* dump it in octal (yuck) */
470 *t++ = '\\';
471 *t++ = '0' + ((ch >> 6) & 3);
472 *t++ = '0' + ((ch >> 3) & 7);
473 *t++ = '0' + (ch & 7);
474 expand_chars += 4;
475 } else if (ch == 127) { /* DEL */
476 *t++ = '^';
477 *t++ = '?';
478 expand_chars += 2;
479 } else if (ch >= ' ') {
480 *t++ = ch;
481 expand_chars++;
482 } else { /* control characters */
483 *t++ = '^';
484 *t++ = ch + '@';
485 expand_chars += 2;
487 *v = t;
491 char *
492 expand(const char *s)
493 { /* convert the string to printable form */
494 static char buf[4096];
495 char *t, *v;
496 int ch;
498 if (magic_cookie_glitch <= 0 && exit_attribute_mode) {
499 v = enter_reverse_mode;
500 } else {
501 v = NULL;
503 expand_chars = 0;
504 t = buf;
505 if (s) {
506 for (; (ch = *s); s++) {
507 if ((ch & 0x80) && v) { /* print it in reverse video
508 mode */
509 strcpy(t, liberated(tparm(v)));
510 for (; *t; t++);
511 expand_one(ch & 0x7f, &t);
512 strcpy(t, liberated(tparm(exit_attribute_mode)));
513 for (; *t; t++);
514 } else {
515 expand_one(ch, &t);
519 *t = '\0';
520 return buf;
524 char *
525 print_expand(char *s)
526 { /* convert the string to 7-bit printable form */
527 static char buf[4096];
528 char *t;
529 int ch;
531 expand_chars = 0;
532 t = buf;
533 if (s) {
534 for (; (ch = *s); s++) {
535 expand_one(ch, &t);
538 *t = '\0';
539 return buf;
543 char *
544 expand_to(char *s, int l)
545 { /* expand s to length l */
546 char *t;
548 for (s = t = expand(s); *t; t++);
549 for (; expand_chars < l; expand_chars++) {
550 *t++ = ' ';
552 *t = '\0';
553 return s;
557 char *
558 hex_expand_to(char *s, int l)
559 { /* expand s to length l in hex */
560 static char buf[4096];
561 char *t;
563 for (t = buf; *s; s++) {
564 sprintf(t, "%02X ", UChar(*s));
565 t += 3;
566 if (t - buf > (int) sizeof(buf) - 4) {
567 break;
570 for (; t - buf < l;) {
571 *t++ = ' ';
573 *t = '\0';
574 expand_chars = t - buf;
575 return buf;
579 char *
580 expand_command(const char *c)
581 { /* expand an ANSI escape sequence */
582 static char buf[256];
583 int i, j, ch;
584 char *s;
586 s = buf;
587 for (i = FALSE; (ch = UChar(*c)) != 0; c++) {
588 if (i) {
589 *s++ = ' ';
591 i = TRUE;
592 if (ch < 32) {
593 j = UChar(c[1]);
594 if (ch == '\033' && j >= '@' && j <= '_') {
595 ch = j - '@';
596 c++;
597 for (j = 0; (*s = c1[ch][j++]); s++);
598 } else
599 for (j = 0; (*s = c0[ch][j++]); s++);
600 } else {
601 *s++ = ch;
602 j = UChar(c[1]);
603 if (ch >= '0' && ch <= '9' &&
604 j >= '0' && j <= '9') {
605 i = FALSE;
609 *s = '\0';
610 return buf;
614 ** go_home()
616 ** Move the cursor to the home position
618 void
619 go_home(void)
621 int i;
623 if (cursor_home)
624 tt_putp(cursor_home);
625 else if (cursor_address)
626 tt_putparm(cursor_address, lines, 0, 0);
627 else if (row_address) { /* use (vpa) */
628 put_cr();
629 tt_putparm(row_address, 1, 0, 0);
630 } else if (cursor_up && cursor_to_ll) {
631 tt_putp(cursor_to_ll);
632 for (i = 1; i < lines; i++) {
633 tt_putp(cursor_up);
635 } else {
636 can_go_home = FALSE;
637 return;
639 char_count = line_count = 0;
640 can_go_home = TRUE;
644 void
645 home_down(void)
646 { /* move the cursor to the lower left hand
647 corner */
648 int i;
650 if (cursor_to_ll)
651 tt_putp(cursor_to_ll);
652 else if (cursor_address)
653 tt_putparm(cursor_address, lines, lines - 1, 0);
654 else if (row_address) { /* use (vpa) */
655 put_cr();
656 tt_putparm(row_address, 1, lines - 1, 0);
657 } else if (cursor_down && cursor_home) {
658 tt_putp(cursor_home);
659 for (i = 1; i < lines; i++)
660 tt_putp(cursor_down);
661 } else
662 return;
663 char_count = 0;
664 line_count = lines - 1;
668 void
669 put_clear(void)
670 { /* clear the screen */
671 int i;
673 if (clear_screen)
674 tt_tputs(clear_screen, lines);
675 else if (clr_eos && can_go_home) {
676 go_home();
677 tt_tputs(clr_eos, lines);
678 } else if (scroll_forward && !over_strike && (can_go_home || cursor_up)) {
679 /* clear the screen by scrolling */
680 put_cr();
681 if (cursor_to_ll) {
682 tt_putp(cursor_to_ll);
683 } else if (cursor_address) {
684 tt_putparm(cursor_address, lines, lines - 1, 0);
685 } else if (row_address) {
686 tt_putparm(row_address, 1, lines - 1, 0);
687 } else {
688 for (i = 1; i < lines; i++) {
689 tt_putp(scroll_forward);
692 for (i = 1; i < lines; i++) {
693 tt_putp(scroll_forward);
695 if (can_go_home) {
696 go_home();
697 } else {
698 for (i = 1; i < lines; i++) {
699 tt_putp(cursor_up);
702 } else {
703 can_clear_screen = FALSE;
704 return;
706 char_count = line_count = 0;
707 can_clear_screen = TRUE;
711 ** wait_here()
713 ** read one character from the input stream
714 ** If the terminal is not in RAW mode then this function will
715 ** wait for a <cr> or <lf>.
718 wait_here(void)
720 char ch, cc[64];
721 char message[16];
722 int i, j;
724 for (i = 0; i < (int) sizeof(cc); i++) {
725 cc[i] = ch = getchp(STRIP_PARITY);
726 if (ch == '\r' || ch == '\n') {
727 put_crlf();
728 char_sent = 0;
729 return cc[i ? i - 1 : 0];
731 if (ch >= ' ') {
732 if (stty_query(TTY_CHAR_MODE)) {
733 put_crlf();
734 char_sent = 0;
735 return ch;
737 continue;
739 if (ch == 023) { /* Control S */
740 /* ignore control S, but tell me about it */
741 while (ch == 023 || ch == 021) {
742 ch = getchp(STRIP_PARITY);
743 if (i < (int) sizeof(cc))
744 cc[++i] = ch;
746 put_str("\nThe terminal sent a ^S -");
747 for (j = 0; j <= i; j++) {
748 sprintf(message, " %02X", cc[j] & 0xFF);
749 put_str(message);
751 put_crlf();
752 i = -1;
753 } else if (ch != 021) { /* Not Control Q */
754 /* could be abort character */
755 spin_flush();
756 if (tty_can_sync == SYNC_TESTED) {
757 (void) tty_sync_error();
758 } else {
759 put_str("\n? ");
763 return '?';
768 ** read_string(buffer, length)
770 ** Read a string of characters from the input stream.
772 void
773 read_string(
774 char *buf,
775 int length)
777 int ch, i;
779 for (i = 0; i < length - 1; ) {
780 ch = getchp(STRIP_PARITY);
781 if (ch == '\r' || ch == '\n') {
782 break;
784 if (ch == '\b' || ch == 127) {
785 if (i) {
786 putchp('\b');
787 putchp(' ');
788 putchp('\b');
789 i--;
791 } else {
792 buf[i++] = ch;
793 putchp(ch);
796 buf[i] = '\0';
797 put_crlf();
798 char_sent = 0;
802 ** maybe_wait(lines)
804 ** wait if near the end of the screen, then clear screen
806 void
807 maybe_wait(int n)
809 if (line_count + n >= lines) {
810 if (char_sent != 0) {
811 ptext("Go? ");
812 (void) wait_here();
814 put_clear();
815 } else {
816 put_crlf();