[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.8

1.1       etheisen    1: /*
1.6       shadchin    2:  * Copyright (C) 1984-2011  Mark Nudelman
1.1       etheisen    3:  *
1.5       millert     4:  * You may distribute under the terms of either the GNU General Public
                      5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.5       millert     7:  * For more information about less, or for information on how to
                      8:  * contact the author, see the README file.
1.1       etheisen    9:  */
                     10:
                     11:
                     12: /*
                     13:  * High level routines dealing with the output to the screen.
                     14:  */
                     15:
                     16: #include "less.h"
1.5       millert    17: #if MSDOS_COMPILER==WIN32C
                     18: #include "windows.h"
                     19: #endif
1.1       etheisen   20:
                     21: public int errmsgs;    /* Count of messages displayed by error() */
                     22: public int need_clr;
1.5       millert    23: public int final_attr;
1.6       shadchin   24: public int at_prompt;
1.1       etheisen   25:
1.7       millert    26: extern volatile sig_atomic_t sigs;
1.1       etheisen   27: extern int sc_width;
                     28: extern int so_s_width, so_e_width;
                     29: extern int screen_trashed;
                     30: extern int any_display;
1.5       millert    31: extern int is_tty;
1.6       shadchin   32: extern int oldbot;
1.5       millert    33:
1.6       shadchin   34: #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
1.5       millert    35: extern int ctldisp;
                     36: extern int nm_fg_color, nm_bg_color;
                     37: extern int bo_fg_color, bo_bg_color;
                     38: extern int ul_fg_color, ul_bg_color;
                     39: extern int so_fg_color, so_bg_color;
                     40: extern int bl_fg_color, bl_bg_color;
                     41: #endif
1.1       etheisen   42:
                     43: /*
                     44:  * Display the line which is in the line buffer.
                     45:  */
                     46:        public void
                     47: put_line()
                     48: {
1.5       millert    49:        register int c;
                     50:        register int i;
1.1       etheisen   51:        int a;
                     52:
                     53:        if (ABORT_SIGS())
                     54:        {
                     55:                /*
                     56:                 * Don't output if a signal is pending.
                     57:                 */
                     58:                screen_trashed = 1;
                     59:                return;
                     60:        }
                     61:
1.6       shadchin   62:        final_attr = AT_NORMAL;
1.1       etheisen   63:
                     64:        for (i = 0;  (c = gline(i, &a)) != '\0';  i++)
                     65:        {
1.6       shadchin   66:                at_switch(a);
                     67:                final_attr = a;
1.1       etheisen   68:                if (c == '\b')
                     69:                        putbs();
                     70:                else
                     71:                        putchr(c);
                     72:        }
                     73:
1.6       shadchin   74:        at_exit();
1.1       etheisen   75: }
                     76:
1.5       millert    77: static char obuf[OUTBUF_SIZE];
1.1       etheisen   78: static char *ob = obuf;
                     79:
                     80: /*
                     81:  * Flush buffered output.
                     82:  *
                     83:  * If we haven't displayed any file data yet,
                     84:  * output messages on error output (file descriptor 2),
                     85:  * otherwise output on standard output (file descriptor 1).
                     86:  *
                     87:  * This has the desirable effect of producing all
                     88:  * error messages on error output if standard output
                     89:  * is directed to a file.  It also does the same if
                     90:  * we never produce any real output; for example, if
                     91:  * the input file(s) cannot be opened.  If we do
                     92:  * eventually produce output, code in edit() makes
                     93:  * sure these messages can be seen before they are
                     94:  * overwritten or scrolled away.
                     95:  */
                     96:        public void
                     97: flush()
                     98: {
1.5       millert    99:        register int n;
                    100:        register int fd;
1.8     ! millert   101:        ssize_t nwritten;
1.1       etheisen  102:
                    103:        n = ob - obuf;
                    104:        if (n == 0)
                    105:                return;
1.5       millert   106:
                    107: #if MSDOS_COMPILER==MSOFTC
                    108:        if (is_tty && any_display)
                    109:        {
                    110:                *ob = '\0';
                    111:                _outtext(obuf);
                    112:                ob = obuf;
                    113:                return;
                    114:        }
                    115: #else
1.6       shadchin  116: #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
1.5       millert   117:        if (is_tty && any_display)
                    118:        {
                    119:                *ob = '\0';
                    120:                if (ctldisp != OPT_ONPLUS)
1.6       shadchin  121:                        WIN32textout(obuf, ob - obuf);
1.5       millert   122:                else
                    123:                {
                    124:                        /*
                    125:                         * Look for SGR escape sequences, and convert them
                    126:                         * to color commands.  Replace bold, underline,
                    127:                         * and italic escapes into colors specified via
                    128:                         * the -D command-line option.
                    129:                         */
                    130:                        char *anchor, *p, *p_next;
1.6       shadchin  131:                        unsigned char fg, bg;
                    132:                        static unsigned char at;
                    133: #if MSDOS_COMPILER==WIN32C
                    134:                        /* Screen colors used by 3x and 4x SGR commands. */
                    135:                        static unsigned char screen_color[] = {
                    136:                                0, /* BLACK */
                    137:                                FOREGROUND_RED,
                    138:                                FOREGROUND_GREEN,
                    139:                                FOREGROUND_RED|FOREGROUND_GREEN,
                    140:                                FOREGROUND_BLUE,
                    141:                                FOREGROUND_BLUE|FOREGROUND_RED,
                    142:                                FOREGROUND_BLUE|FOREGROUND_GREEN,
                    143:                                FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED
                    144:                        };
                    145: #else
1.5       millert   146:                        static enum COLORS screen_color[] = {
                    147:                                BLACK, RED, GREEN, BROWN,
                    148:                                BLUE, MAGENTA, CYAN, LIGHTGRAY
                    149:                        };
1.6       shadchin  150: #endif
1.5       millert   151:
                    152:                        for (anchor = p_next = obuf;
1.6       shadchin  153:                             (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
1.5       millert   154:                        {
                    155:                                p = p_next;
1.6       shadchin  156:                                if (p[1] == '[')  /* "ESC-[" sequence */
1.5       millert   157:                                {
                    158:                                        if (p > anchor)
                    159:                                        {
1.6       shadchin  160:                                                /*
                    161:                                                 * If some chars seen since
                    162:                                                 * the last escape sequence,
                    163:                                                 * write them out to the screen.
                    164:                                                 */
                    165:                                                WIN32textout(anchor, p-anchor);
1.5       millert   166:                                                anchor = p;
                    167:                                        }
1.6       shadchin  168:                                        p += 2;  /* Skip the "ESC-[" */
                    169:                                        if (is_ansi_end(*p))
                    170:                                        {
                    171:                                                /*
                    172:                                                 * Handle null escape sequence
                    173:                                                 * "ESC[m", which restores
                    174:                                                 * the normal color.
                    175:                                                 */
                    176:                                                p++;
                    177:                                                anchor = p_next = p;
                    178:                                                WIN32setcolors(nm_fg_color, nm_bg_color);
                    179:                                                continue;
                    180:                                        }
1.5       millert   181:                                        p_next = p;
1.6       shadchin  182:
                    183:                                        /*
                    184:                                         * Select foreground/background colors
                    185:                                         * based on the escape sequence.
                    186:                                         */
                    187:                                        fg = nm_fg_color;
                    188:                                        bg = nm_bg_color;
1.5       millert   189:                                        while (!is_ansi_end(*p))
                    190:                                        {
                    191:                                                char *q;
                    192:                                                long code = strtol(p, &q, 10);
                    193:
1.6       shadchin  194:                                                if (*q == '\0')
1.5       millert   195:                                                {
                    196:                                                        /*
                    197:                                                         * Incomplete sequence.
                    198:                                                         * Leave it unprocessed
                    199:                                                         * in the buffer.
                    200:                                                         */
                    201:                                                        int slop = q - anchor;
1.6       shadchin  202:                                                        /* {{ strlcpy args overlap! }} */
1.5       millert   203:                                                        strlcpy(obuf, anchor,
                    204:                                                            sizeof(obuf));
                    205:                                                        ob = &obuf[slop];
                    206:                                                        return;
                    207:                                                }
                    208:
1.6       shadchin  209:                                                if (q == p ||
                    210:                                                    code > 49 || code < 0 ||
                    211:                                                    (!is_ansi_end(*q) && *q != ';'))
1.5       millert   212:                                                {
                    213:                                                        p_next = q;
                    214:                                                        break;
                    215:                                                }
                    216:                                                if (*q == ';')
                    217:                                                        q++;
                    218:
                    219:                                                switch (code)
                    220:                                                {
1.6       shadchin  221:                                                default:
                    222:                                                /* case 0: all attrs off */
                    223:                                                        fg = nm_fg_color;
                    224:                                                        bg = nm_bg_color;
                    225:                                                        at = 0;
                    226:                                                        break;
1.5       millert   227:                                                case 1: /* bold on */
1.6       shadchin  228:                                                        at |= 1;
1.5       millert   229:                                                        break;
                    230:                                                case 3: /* italic on */
1.6       shadchin  231:                                                case 7: /* inverse on */
                    232:                                                        at |= 2;
1.5       millert   233:                                                        break;
                    234:                                                case 4: /* underline on */
1.6       shadchin  235:                                                        at |= 4;
                    236:                                                        break;
                    237:                                                case 5: /* slow blink on */
                    238:                                                case 6: /* fast blink on */
                    239:                                                        at |= 8;
1.5       millert   240:                                                        break;
                    241:                                                case 8: /* concealed on */
                    242:                                                        fg = (bg & 7) | 8;
                    243:                                                        break;
1.6       shadchin  244:                                                case 22: /* bold off */
                    245:                                                        at &= ~1;
                    246:                                                        break;
                    247:                                                case 23: /* italic off */
                    248:                                                case 27: /* inverse off */
                    249:                                                        at &= ~2;
                    250:                                                        break;
                    251:                                                case 24: /* underline off */
                    252:                                                        at &= ~4;
1.5       millert   253:                                                        break;
                    254:                                                case 30: case 31: case 32:
                    255:                                                case 33: case 34: case 35:
                    256:                                                case 36: case 37:
                    257:                                                        fg = (fg & 8) | (screen_color[code - 30]);
                    258:                                                        break;
                    259:                                                case 39: /* default fg */
                    260:                                                        fg = nm_fg_color;
                    261:                                                        break;
                    262:                                                case 40: case 41: case 42:
                    263:                                                case 43: case 44: case 45:
                    264:                                                case 46: case 47:
                    265:                                                        bg = (bg & 8) | (screen_color[code - 40]);
                    266:                                                        break;
                    267:                                                case 49: /* default fg */
                    268:                                                        bg = nm_bg_color;
                    269:                                                        break;
                    270:                                                }
                    271:                                                p = q;
                    272:                                        }
1.6       shadchin  273:                                        if (!is_ansi_end(*p) || p == p_next)
                    274:                                                break;
                    275:                                        if (at & 1)
                    276:                                        {
                    277:                                                        fg = bo_fg_color;
                    278:                                                        bg = bo_bg_color;
                    279:                                        } else if (at & 2)
                    280:                                        {
                    281:                                                        fg = so_fg_color;
                    282:                                                        bg = so_bg_color;
                    283:                                        } else if (at & 4)
                    284:                                        {
                    285:                                                        fg = ul_fg_color;
                    286:                                                        bg = ul_bg_color;
                    287:                                        } else if (at & 8)
1.5       millert   288:                                        {
1.6       shadchin  289:                                                        fg = bl_fg_color;
                    290:                                                        bg = bl_bg_color;
                    291:                                        }
                    292:                                        fg &= 0xf;
                    293:                                        bg &= 0xf;
                    294:                                        WIN32setcolors(fg, bg);
                    295:                                        p_next = anchor = p + 1;
1.5       millert   296:                                } else
                    297:                                        p_next++;
                    298:                        }
                    299:
                    300:                        /* Output what's left in the buffer.  */
1.6       shadchin  301:                        WIN32textout(anchor, ob - anchor);
1.5       millert   302:                }
                    303:                ob = obuf;
                    304:                return;
                    305:        }
                    306: #endif
                    307: #endif
1.6       shadchin  308:        fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
1.8     ! millert   309:        nwritten = write(fd, obuf, n);
        !           310:        if (nwritten != n) {
        !           311:                if (nwritten == -1)
        !           312:                        quit(QUIT_ERROR);
1.1       etheisen  313:                screen_trashed = 1;
1.8     ! millert   314:        }
1.1       etheisen  315:        ob = obuf;
                    316: }
                    317:
                    318: /*
                    319:  * Output a character.
                    320:  */
                    321:        public int
                    322: putchr(c)
                    323:        int c;
                    324: {
1.6       shadchin  325: #if 0 /* fake UTF-8 output for testing */
                    326:        extern int utf_mode;
                    327:        if (utf_mode)
                    328:        {
                    329:                static char ubuf[MAX_UTF_CHAR_LEN];
                    330:                static int ubuf_len = 0;
                    331:                static int ubuf_index = 0;
                    332:                if (ubuf_len == 0)
                    333:                {
                    334:                        ubuf_len = utf_len(c);
                    335:                        ubuf_index = 0;
                    336:                }
                    337:                ubuf[ubuf_index++] = c;
                    338:                if (ubuf_index < ubuf_len)
                    339:                        return c;
                    340:                c = get_wchar(ubuf) & 0xFF;
                    341:                ubuf_len = 0;
                    342:        }
                    343: #endif
1.1       etheisen  344:        if (need_clr)
                    345:        {
                    346:                need_clr = 0;
                    347:                clear_bot();
                    348:        }
1.5       millert   349: #if MSDOS_COMPILER
                    350:        if (c == '\n' && is_tty)
                    351:        {
                    352:                /* remove_top(1); */
1.1       etheisen  353:                putchr('\r');
1.5       millert   354:        }
                    355: #else
                    356: #ifdef _OSK
                    357:        if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
                    358:                putchr(0x0A);
1.1       etheisen  359: #endif
1.5       millert   360: #endif
                    361:        /*
                    362:         * Some versions of flush() write to *ob, so we must flush
                    363:         * when we are still one char from the end of obuf.
                    364:         */
                    365:        if (ob >= &obuf[sizeof(obuf)-1])
                    366:                flush();
1.1       etheisen  367:        *ob++ = c;
1.6       shadchin  368:        at_prompt = 0;
1.1       etheisen  369:        return (c);
                    370: }
                    371:
                    372: /*
                    373:  * Output a string.
                    374:  */
                    375:        public void
                    376: putstr(s)
1.5       millert   377:        register char *s;
1.1       etheisen  378: {
                    379:        while (*s != '\0')
                    380:                putchr(*s++);
                    381: }
                    382:
                    383:
                    384: /*
1.5       millert   385:  * Convert an integral type to a string.
                    386:  */
                    387: #define TYPE_TO_A_FUNC(funcname, type) \
                    388: void funcname(num, buf, len) \
                    389:        type num; \
                    390:        char *buf; \
                    391:        size_t len; \
                    392: { \
                    393:        int neg = (num < 0); \
                    394:        char tbuf[INT_STRLEN_BOUND(num)+2]; \
                    395:        register char *s = tbuf + sizeof(tbuf); \
                    396:        if (neg) num = -num; \
                    397:        *--s = '\0'; \
                    398:        do { \
                    399:                *--s = (num % 10) + '0'; \
                    400:        } while ((num /= 10) != 0); \
                    401:        if (neg) *--s = '-'; \
                    402:        strlcpy(buf, s, len); \
                    403: }
                    404:
                    405: TYPE_TO_A_FUNC(postoa, POSITION)
                    406: TYPE_TO_A_FUNC(linenumtoa, LINENUM)
                    407: TYPE_TO_A_FUNC(inttoa, int)
                    408:
                    409: /*
1.1       etheisen  410:  * Output an integer in a given radix.
                    411:  */
                    412:        static int
1.5       millert   413: iprint_int(num)
1.1       etheisen  414:        int num;
                    415: {
1.5       millert   416:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  417:
1.5       millert   418:        inttoa(num, buf, sizeof(buf));
                    419:        putstr(buf);
                    420:        return (strlen(buf));
                    421: }
1.1       etheisen  422:
1.5       millert   423: /*
                    424:  * Output a line number in a given radix.
                    425:  */
                    426:        static int
                    427: iprint_linenum(num)
                    428:        LINENUM num;
                    429: {
                    430:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  431:
1.5       millert   432:        linenumtoa(num, buf, sizeof(buf));
                    433:        putstr(buf);
                    434:        return (strlen(buf));
1.1       etheisen  435: }
                    436:
                    437: /*
                    438:  * This function implements printf-like functionality
                    439:  * using a more portable argument list mechanism than printf's.
                    440:  */
                    441:        static int
1.5       millert   442: less_printf(fmt, parg)
                    443:        register char *fmt;
1.1       etheisen  444:        PARG *parg;
                    445: {
1.5       millert   446:        register char *s;
                    447:        register int col;
1.1       etheisen  448:
                    449:        col = 0;
                    450:        while (*fmt != '\0')
                    451:        {
                    452:                if (*fmt != '%')
                    453:                {
                    454:                        putchr(*fmt++);
                    455:                        col++;
                    456:                } else
                    457:                {
                    458:                        ++fmt;
1.5       millert   459:                        switch (*fmt++)
                    460:                        {
1.1       etheisen  461:                        case 's':
                    462:                                s = parg->p_string;
                    463:                                parg++;
                    464:                                while (*s != '\0')
                    465:                                {
                    466:                                        putchr(*s++);
                    467:                                        col++;
                    468:                                }
                    469:                                break;
                    470:                        case 'd':
1.5       millert   471:                                col += iprint_int(parg->p_int);
                    472:                                parg++;
                    473:                                break;
                    474:                        case 'n':
                    475:                                col += iprint_linenum(parg->p_linenum);
1.1       etheisen  476:                                parg++;
                    477:                                break;
                    478:                        }
                    479:                }
                    480:        }
                    481:        return (col);
                    482: }
                    483:
                    484: /*
1.5       millert   485:  * Get a RETURN.
                    486:  * If some other non-trivial char is pressed, unget it, so it will
                    487:  * become the next command.
                    488:  */
                    489:        public void
                    490: get_return()
                    491: {
                    492:        int c;
                    493:
                    494: #if ONLY_RETURN
                    495:        while ((c = getchr()) != '\n' && c != '\r')
                    496:                bell();
                    497: #else
                    498:        c = getchr();
                    499:        if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
                    500:                ungetcc(c);
                    501: #endif
                    502: }
                    503:
                    504: /*
1.1       etheisen  505:  * Output a message in the lower left corner of the screen
                    506:  * and wait for carriage return.
                    507:  */
                    508:        public void
                    509: error(fmt, parg)
                    510:        char *fmt;
                    511:        PARG *parg;
                    512: {
                    513:        int col = 0;
                    514:        static char return_to_continue[] = "  (press RETURN)";
                    515:
                    516:        errmsgs++;
                    517:
1.5       millert   518:        if (any_display && is_tty)
1.1       etheisen  519:        {
1.6       shadchin  520:                if (!oldbot)
                    521:                        squish_check();
                    522:                at_exit();
1.1       etheisen  523:                clear_bot();
1.6       shadchin  524:                at_enter(AT_STANDOUT);
1.1       etheisen  525:                col += so_s_width;
                    526:        }
                    527:
1.5       millert   528:        col += less_printf(fmt, parg);
1.1       etheisen  529:
1.5       millert   530:        if (!(any_display && is_tty))
1.1       etheisen  531:        {
                    532:                putchr('\n');
                    533:                return;
                    534:        }
                    535:
                    536:        putstr(return_to_continue);
1.6       shadchin  537:        at_exit();
1.1       etheisen  538:        col += sizeof(return_to_continue) + so_e_width;
                    539:
1.5       millert   540:        get_return();
1.1       etheisen  541:        lower_left();
1.6       shadchin  542:     clear_eol();
1.1       etheisen  543:
                    544:        if (col >= sc_width)
                    545:                /*
                    546:                 * Printing the message has probably scrolled the screen.
                    547:                 * {{ Unless the terminal doesn't have auto margins,
                    548:                 *    in which case we just hammered on the right margin. }}
                    549:                 */
                    550:                screen_trashed = 1;
                    551:
                    552:        flush();
                    553: }
                    554:
                    555: static char intr_to_abort[] = "... (interrupt to abort)";
                    556:
                    557: /*
                    558:  * Output a message in the lower left corner of the screen
                    559:  * and don't wait for carriage return.
                    560:  * Usually used to warn that we are beginning a potentially
                    561:  * time-consuming operation.
                    562:  */
                    563:        public void
                    564: ierror(fmt, parg)
                    565:        char *fmt;
                    566:        PARG *parg;
                    567: {
1.6       shadchin  568:        at_exit();
1.1       etheisen  569:        clear_bot();
1.6       shadchin  570:        at_enter(AT_STANDOUT);
1.5       millert   571:        (void) less_printf(fmt, parg);
1.1       etheisen  572:        putstr(intr_to_abort);
1.6       shadchin  573:        at_exit();
1.1       etheisen  574:        flush();
                    575:        need_clr = 1;
                    576: }
                    577:
                    578: /*
                    579:  * Output a message in the lower left corner of the screen
                    580:  * and return a single-character response.
                    581:  */
                    582:        public int
                    583: query(fmt, parg)
                    584:        char *fmt;
                    585:        PARG *parg;
                    586: {
1.5       millert   587:        register int c;
1.1       etheisen  588:        int col = 0;
                    589:
1.5       millert   590:        if (any_display && is_tty)
1.1       etheisen  591:                clear_bot();
                    592:
1.5       millert   593:        (void) less_printf(fmt, parg);
1.1       etheisen  594:        c = getchr();
                    595:
1.5       millert   596:        if (!(any_display && is_tty))
1.1       etheisen  597:        {
                    598:                putchr('\n');
                    599:                return (c);
                    600:        }
                    601:
                    602:        lower_left();
                    603:        if (col >= sc_width)
                    604:                screen_trashed = 1;
                    605:        flush();
                    606:
                    607:        return (c);
                    608: }