[BACK]Return to output.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/output.c, Revision 1.14

1.1       etheisen    1: /*
1.9       shadchin    2:  * Copyright (C) 1984-2012  Mark Nudelman
1.12      nicm        3:  * Modified for use with illumos by Garrett D'Amore.
                      4:  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1       etheisen    5:  *
1.5       millert     6:  * You may distribute under the terms of either the GNU General Public
                      7:  * License or the Less License, as specified in the README file.
1.1       etheisen    8:  *
1.9       shadchin    9:  * For more information, see the README file.
1.10      nicm       10:  */
1.1       etheisen   11:
                     12: /*
                     13:  * High level routines dealing with the output to the screen.
                     14:  */
                     15:
                     16: #include "less.h"
1.10      nicm       17:
                     18: int errmsgs;   /* Count of messages displayed by error() */
1.1       etheisen   19:
1.7       millert    20: extern volatile sig_atomic_t sigs;
1.1       etheisen   21: extern int sc_width;
                     22: extern int so_s_width, so_e_width;
                     23: extern int screen_trashed;
                     24: extern int any_display;
1.5       millert    25: extern int is_tty;
1.6       shadchin   26: extern int oldbot;
1.5       millert    27:
1.10      nicm       28: static int need_clr;
1.1       etheisen   29:
                     30: /*
                     31:  * Display the line which is in the line buffer.
                     32:  */
1.10      nicm       33: void
                     34: put_line(void)
1.1       etheisen   35: {
1.10      nicm       36:        int c;
                     37:        int i;
1.1       etheisen   38:        int a;
                     39:
1.10      nicm       40:        if (ABORT_SIGS()) {
1.1       etheisen   41:                /*
                     42:                 * Don't output if a signal is pending.
                     43:                 */
                     44:                screen_trashed = 1;
                     45:                return;
                     46:        }
                     47:
1.10      nicm       48:        for (i = 0;  (c = gline(i, &a)) != '\0';  i++) {
1.6       shadchin   49:                at_switch(a);
1.1       etheisen   50:                if (c == '\b')
                     51:                        putbs();
                     52:                else
1.10      nicm       53:                        (void) putchr(c);
1.1       etheisen   54:        }
                     55:
1.6       shadchin   56:        at_exit();
1.1       etheisen   57: }
                     58:
1.5       millert    59: static char obuf[OUTBUF_SIZE];
1.1       etheisen   60: static char *ob = obuf;
                     61:
                     62: /*
                     63:  * Flush buffered output.
                     64:  *
                     65:  * If we haven't displayed any file data yet,
                     66:  * output messages on error output (file descriptor 2),
                     67:  * otherwise output on standard output (file descriptor 1).
                     68:  *
                     69:  * This has the desirable effect of producing all
                     70:  * error messages on error output if standard output
                     71:  * is directed to a file.  It also does the same if
                     72:  * we never produce any real output; for example, if
                     73:  * the input file(s) cannot be opened.  If we do
                     74:  * eventually produce output, code in edit() makes
                     75:  * sure these messages can be seen before they are
                     76:  * overwritten or scrolled away.
                     77:  */
1.10      nicm       78: void
1.13      nicm       79: flush(int ignore_errors)
1.1       etheisen   80: {
1.10      nicm       81:        int n;
                     82:        int fd;
1.8       millert    83:        ssize_t nwritten;
1.1       etheisen   84:
1.10      nicm       85:        n = (intptr_t)ob - (intptr_t)obuf;
1.1       etheisen   86:        if (n == 0)
                     87:                return;
1.5       millert    88:
1.6       shadchin   89:        fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
1.8       millert    90:        nwritten = write(fd, obuf, n);
                     91:        if (nwritten != n) {
1.13      nicm       92:                if (nwritten == -1 && !ignore_errors)
1.8       millert    93:                        quit(QUIT_ERROR);
1.1       etheisen   94:                screen_trashed = 1;
1.8       millert    95:        }
1.1       etheisen   96:        ob = obuf;
                     97: }
                     98:
                     99: /*
                    100:  * Output a character.
                    101:  */
1.10      nicm      102: int
                    103: putchr(int c)
1.1       etheisen  104: {
1.10      nicm      105:        if (need_clr) {
1.1       etheisen  106:                need_clr = 0;
                    107:                clear_bot();
                    108:        }
1.5       millert   109:        /*
                    110:         * Some versions of flush() write to *ob, so we must flush
                    111:         * when we are still one char from the end of obuf.
                    112:         */
1.10      nicm      113:        if (ob >= &obuf[sizeof (obuf)-1])
1.13      nicm      114:                flush(0);
1.10      nicm      115:        *ob++ = (char)c;
1.1       etheisen  116:        return (c);
                    117: }
                    118:
                    119: /*
                    120:  * Output a string.
                    121:  */
1.10      nicm      122: void
                    123: putstr(const char *s)
1.1       etheisen  124: {
                    125:        while (*s != '\0')
1.10      nicm      126:                (void) putchr(*s++);
1.1       etheisen  127: }
                    128:
                    129:
                    130: /*
1.5       millert   131:  * Convert an integral type to a string.
                    132:  */
1.10      nicm      133: #define        TYPE_TO_A_FUNC(funcname, type)          \
                    134: void                                           \
                    135: funcname(type num, char *buf, size_t len)      \
                    136: {                                              \
                    137:        int neg = (num < 0);                    \
                    138:        char tbuf[INT_STRLEN_BOUND(num)+2];     \
                    139:        char *s = tbuf + sizeof (tbuf);         \
                    140:        if (neg)                                \
                    141:                num = -num;                     \
                    142:        *--s = '\0';                            \
                    143:        do {                                    \
                    144:                *--s = (num % 10) + '0';        \
                    145:        } while ((num /= 10) != 0);             \
                    146:        if (neg)                                \
                    147:                 *--s = '-';                    \
                    148:        (void) strlcpy(buf, s, len);            \
1.5       millert   149: }
                    150:
1.10      nicm      151: TYPE_TO_A_FUNC(postoa, off_t)
1.14    ! mmcc      152: TYPE_TO_A_FUNC(linenumtoa, off_t)
1.5       millert   153: TYPE_TO_A_FUNC(inttoa, int)
                    154:
                    155: /*
1.1       etheisen  156:  * Output an integer in a given radix.
                    157:  */
1.10      nicm      158: static int
                    159: iprint_int(int num)
1.1       etheisen  160: {
1.5       millert   161:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  162:
1.10      nicm      163:        inttoa(num, buf, sizeof (buf));
1.5       millert   164:        putstr(buf);
                    165:        return (strlen(buf));
                    166: }
1.1       etheisen  167:
1.5       millert   168: /*
                    169:  * Output a line number in a given radix.
                    170:  */
1.10      nicm      171: static int
1.14    ! mmcc      172: iprint_linenum(off_t num)
1.5       millert   173: {
                    174:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  175:
1.10      nicm      176:        linenumtoa(num, buf, sizeof (buf));
1.5       millert   177:        putstr(buf);
                    178:        return (strlen(buf));
1.1       etheisen  179: }
                    180:
                    181: /*
                    182:  * This function implements printf-like functionality
                    183:  * using a more portable argument list mechanism than printf's.
                    184:  */
1.10      nicm      185: static int
                    186: less_printf(const char *fmt, PARG *parg)
1.1       etheisen  187: {
1.11      tedu      188:        char *s;
                    189:        int col;
1.1       etheisen  190:
                    191:        col = 0;
1.10      nicm      192:        while (*fmt != '\0') {
                    193:                if (*fmt != '%') {
                    194:                        (void) putchr(*fmt++);
1.1       etheisen  195:                        col++;
1.10      nicm      196:                } else {
1.1       etheisen  197:                        ++fmt;
1.10      nicm      198:                        switch (*fmt++) {
1.1       etheisen  199:                        case 's':
                    200:                                s = parg->p_string;
                    201:                                parg++;
1.10      nicm      202:                                while (*s != '\0') {
                    203:                                        (void) putchr(*s++);
1.1       etheisen  204:                                        col++;
                    205:                                }
                    206:                                break;
                    207:                        case 'd':
1.5       millert   208:                                col += iprint_int(parg->p_int);
                    209:                                parg++;
                    210:                                break;
                    211:                        case 'n':
                    212:                                col += iprint_linenum(parg->p_linenum);
1.1       etheisen  213:                                parg++;
                    214:                                break;
                    215:                        }
                    216:                }
                    217:        }
                    218:        return (col);
                    219: }
                    220:
                    221: /*
1.5       millert   222:  * Get a RETURN.
                    223:  * If some other non-trivial char is pressed, unget it, so it will
                    224:  * become the next command.
                    225:  */
1.10      nicm      226: void
                    227: get_return(void)
1.5       millert   228: {
                    229:        int c;
                    230:
                    231:        c = getchr();
                    232:        if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
                    233:                ungetcc(c);
                    234: }
                    235:
                    236: /*
1.1       etheisen  237:  * Output a message in the lower left corner of the screen
                    238:  * and wait for carriage return.
                    239:  */
1.10      nicm      240: void
                    241: error(const char *fmt, PARG *parg)
1.1       etheisen  242: {
                    243:        int col = 0;
                    244:        static char return_to_continue[] = "  (press RETURN)";
                    245:
                    246:        errmsgs++;
                    247:
1.10      nicm      248:        if (any_display && is_tty) {
1.6       shadchin  249:                if (!oldbot)
                    250:                        squish_check();
                    251:                at_exit();
1.1       etheisen  252:                clear_bot();
1.6       shadchin  253:                at_enter(AT_STANDOUT);
1.1       etheisen  254:                col += so_s_width;
                    255:        }
                    256:
1.5       millert   257:        col += less_printf(fmt, parg);
1.1       etheisen  258:
1.10      nicm      259:        if (!(any_display && is_tty)) {
                    260:                (void) putchr('\n');
1.1       etheisen  261:                return;
                    262:        }
                    263:
                    264:        putstr(return_to_continue);
1.6       shadchin  265:        at_exit();
1.10      nicm      266:        col += sizeof (return_to_continue) + so_e_width;
1.1       etheisen  267:
1.5       millert   268:        get_return();
1.1       etheisen  269:        lower_left();
1.10      nicm      270:        clear_eol();
1.1       etheisen  271:
                    272:        if (col >= sc_width)
                    273:                /*
                    274:                 * Printing the message has probably scrolled the screen.
                    275:                 * {{ Unless the terminal doesn't have auto margins,
                    276:                 *    in which case we just hammered on the right margin. }}
                    277:                 */
                    278:                screen_trashed = 1;
                    279:
1.13      nicm      280:        flush(0);
1.1       etheisen  281: }
                    282:
                    283: static char intr_to_abort[] = "... (interrupt to abort)";
                    284:
                    285: /*
                    286:  * Output a message in the lower left corner of the screen
                    287:  * and don't wait for carriage return.
                    288:  * Usually used to warn that we are beginning a potentially
                    289:  * time-consuming operation.
                    290:  */
1.10      nicm      291: void
                    292: ierror(const char *fmt, PARG *parg)
1.1       etheisen  293: {
1.6       shadchin  294:        at_exit();
1.1       etheisen  295:        clear_bot();
1.6       shadchin  296:        at_enter(AT_STANDOUT);
1.5       millert   297:        (void) less_printf(fmt, parg);
1.1       etheisen  298:        putstr(intr_to_abort);
1.6       shadchin  299:        at_exit();
1.13      nicm      300:        flush(0);
1.1       etheisen  301:        need_clr = 1;
                    302: }
                    303:
                    304: /*
                    305:  * Output a message in the lower left corner of the screen
                    306:  * and return a single-character response.
                    307:  */
1.10      nicm      308: int
                    309: query(const char *fmt, PARG *parg)
1.1       etheisen  310: {
1.11      tedu      311:        int c;
1.1       etheisen  312:        int col = 0;
                    313:
1.5       millert   314:        if (any_display && is_tty)
1.1       etheisen  315:                clear_bot();
                    316:
1.5       millert   317:        (void) less_printf(fmt, parg);
1.1       etheisen  318:        c = getchr();
                    319:
1.10      nicm      320:        if (!(any_display && is_tty)) {
                    321:                (void) putchr('\n');
1.1       etheisen  322:                return (c);
                    323:        }
                    324:
                    325:        lower_left();
                    326:        if (col >= sc_width)
                    327:                screen_trashed = 1;
1.13      nicm      328:        flush(0);
1.1       etheisen  329:
                    330:        return (c);
                    331: }