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

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