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

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:
                     26: extern int sigs;
                     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.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;
        !           177:                                                WIN32setcolors(nm_fg_color, nm_bg_color);
        !           178:                                                continue;
        !           179:                                        }
1.5       millert   180:                                        p_next = p;
1.6     ! shadchin  181:
        !           182:                                        /*
        !           183:                                         * Select foreground/background colors
        !           184:                                         * based on the escape sequence.
        !           185:                                         */
        !           186:                                        fg = nm_fg_color;
        !           187:                                        bg = nm_bg_color;
1.5       millert   188:                                        while (!is_ansi_end(*p))
                    189:                                        {
                    190:                                                char *q;
                    191:                                                long code = strtol(p, &q, 10);
                    192:
1.6     ! shadchin  193:                                                if (*q == '\0')
1.5       millert   194:                                                {
                    195:                                                        /*
                    196:                                                         * Incomplete sequence.
                    197:                                                         * Leave it unprocessed
                    198:                                                         * in the buffer.
                    199:                                                         */
                    200:                                                        int slop = q - anchor;
1.6     ! shadchin  201:                                                        /* {{ strlcpy args overlap! }} */
1.5       millert   202:                                                        strlcpy(obuf, anchor,
                    203:                                                            sizeof(obuf));
                    204:                                                        ob = &obuf[slop];
                    205:                                                        return;
                    206:                                                }
                    207:
1.6     ! shadchin  208:                                                if (q == p ||
        !           209:                                                    code > 49 || code < 0 ||
        !           210:                                                    (!is_ansi_end(*q) && *q != ';'))
1.5       millert   211:                                                {
                    212:                                                        p_next = q;
                    213:                                                        break;
                    214:                                                }
                    215:                                                if (*q == ';')
                    216:                                                        q++;
                    217:
                    218:                                                switch (code)
                    219:                                                {
1.6     ! shadchin  220:                                                default:
        !           221:                                                /* case 0: all attrs off */
        !           222:                                                        fg = nm_fg_color;
        !           223:                                                        bg = nm_bg_color;
        !           224:                                                        at = 0;
        !           225:                                                        break;
1.5       millert   226:                                                case 1: /* bold on */
1.6     ! shadchin  227:                                                        at |= 1;
1.5       millert   228:                                                        break;
                    229:                                                case 3: /* italic on */
1.6     ! shadchin  230:                                                case 7: /* inverse on */
        !           231:                                                        at |= 2;
1.5       millert   232:                                                        break;
                    233:                                                case 4: /* underline on */
1.6     ! shadchin  234:                                                        at |= 4;
        !           235:                                                        break;
        !           236:                                                case 5: /* slow blink on */
        !           237:                                                case 6: /* fast blink on */
        !           238:                                                        at |= 8;
1.5       millert   239:                                                        break;
                    240:                                                case 8: /* concealed on */
                    241:                                                        fg = (bg & 7) | 8;
                    242:                                                        break;
1.6     ! shadchin  243:                                                case 22: /* bold off */
        !           244:                                                        at &= ~1;
        !           245:                                                        break;
        !           246:                                                case 23: /* italic off */
        !           247:                                                case 27: /* inverse off */
        !           248:                                                        at &= ~2;
        !           249:                                                        break;
        !           250:                                                case 24: /* underline off */
        !           251:                                                        at &= ~4;
1.5       millert   252:                                                        break;
                    253:                                                case 30: case 31: case 32:
                    254:                                                case 33: case 34: case 35:
                    255:                                                case 36: case 37:
                    256:                                                        fg = (fg & 8) | (screen_color[code - 30]);
                    257:                                                        break;
                    258:                                                case 39: /* default fg */
                    259:                                                        fg = nm_fg_color;
                    260:                                                        break;
                    261:                                                case 40: case 41: case 42:
                    262:                                                case 43: case 44: case 45:
                    263:                                                case 46: case 47:
                    264:                                                        bg = (bg & 8) | (screen_color[code - 40]);
                    265:                                                        break;
                    266:                                                case 49: /* default fg */
                    267:                                                        bg = nm_bg_color;
                    268:                                                        break;
                    269:                                                }
                    270:                                                p = q;
                    271:                                        }
1.6     ! shadchin  272:                                        if (!is_ansi_end(*p) || p == p_next)
        !           273:                                                break;
        !           274:                                        if (at & 1)
        !           275:                                        {
        !           276:                                                        fg = bo_fg_color;
        !           277:                                                        bg = bo_bg_color;
        !           278:                                        } else if (at & 2)
        !           279:                                        {
        !           280:                                                        fg = so_fg_color;
        !           281:                                                        bg = so_bg_color;
        !           282:                                        } else if (at & 4)
        !           283:                                        {
        !           284:                                                        fg = ul_fg_color;
        !           285:                                                        bg = ul_bg_color;
        !           286:                                        } else if (at & 8)
1.5       millert   287:                                        {
1.6     ! shadchin  288:                                                        fg = bl_fg_color;
        !           289:                                                        bg = bl_bg_color;
        !           290:                                        }
        !           291:                                        fg &= 0xf;
        !           292:                                        bg &= 0xf;
        !           293:                                        WIN32setcolors(fg, bg);
        !           294:                                        p_next = anchor = p + 1;
1.5       millert   295:                                } else
                    296:                                        p_next++;
                    297:                        }
                    298:
                    299:                        /* Output what's left in the buffer.  */
1.6     ! shadchin  300:                        WIN32textout(anchor, ob - anchor);
1.5       millert   301:                }
                    302:                ob = obuf;
                    303:                return;
                    304:        }
                    305: #endif
                    306: #endif
1.6     ! shadchin  307:        fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO;
1.1       etheisen  308:        if (write(fd, obuf, n) != n)
                    309:                screen_trashed = 1;
                    310:        ob = obuf;
                    311: }
                    312:
                    313: /*
                    314:  * Output a character.
                    315:  */
                    316:        public int
                    317: putchr(c)
                    318:        int c;
                    319: {
1.6     ! shadchin  320: #if 0 /* fake UTF-8 output for testing */
        !           321:        extern int utf_mode;
        !           322:        if (utf_mode)
        !           323:        {
        !           324:                static char ubuf[MAX_UTF_CHAR_LEN];
        !           325:                static int ubuf_len = 0;
        !           326:                static int ubuf_index = 0;
        !           327:                if (ubuf_len == 0)
        !           328:                {
        !           329:                        ubuf_len = utf_len(c);
        !           330:                        ubuf_index = 0;
        !           331:                }
        !           332:                ubuf[ubuf_index++] = c;
        !           333:                if (ubuf_index < ubuf_len)
        !           334:                        return c;
        !           335:                c = get_wchar(ubuf) & 0xFF;
        !           336:                ubuf_len = 0;
        !           337:        }
        !           338: #endif
1.1       etheisen  339:        if (need_clr)
                    340:        {
                    341:                need_clr = 0;
                    342:                clear_bot();
                    343:        }
1.5       millert   344: #if MSDOS_COMPILER
                    345:        if (c == '\n' && is_tty)
                    346:        {
                    347:                /* remove_top(1); */
1.1       etheisen  348:                putchr('\r');
1.5       millert   349:        }
                    350: #else
                    351: #ifdef _OSK
                    352:        if (c == '\n' && is_tty)  /* In OS-9, '\n' == 0x0D */
                    353:                putchr(0x0A);
1.1       etheisen  354: #endif
1.5       millert   355: #endif
                    356:        /*
                    357:         * Some versions of flush() write to *ob, so we must flush
                    358:         * when we are still one char from the end of obuf.
                    359:         */
                    360:        if (ob >= &obuf[sizeof(obuf)-1])
                    361:                flush();
1.1       etheisen  362:        *ob++ = c;
1.6     ! shadchin  363:        at_prompt = 0;
1.1       etheisen  364:        return (c);
                    365: }
                    366:
                    367: /*
                    368:  * Output a string.
                    369:  */
                    370:        public void
                    371: putstr(s)
1.5       millert   372:        register char *s;
1.1       etheisen  373: {
                    374:        while (*s != '\0')
                    375:                putchr(*s++);
                    376: }
                    377:
                    378:
                    379: /*
1.5       millert   380:  * Convert an integral type to a string.
                    381:  */
                    382: #define TYPE_TO_A_FUNC(funcname, type) \
                    383: void funcname(num, buf, len) \
                    384:        type num; \
                    385:        char *buf; \
                    386:        size_t len; \
                    387: { \
                    388:        int neg = (num < 0); \
                    389:        char tbuf[INT_STRLEN_BOUND(num)+2]; \
                    390:        register char *s = tbuf + sizeof(tbuf); \
                    391:        if (neg) num = -num; \
                    392:        *--s = '\0'; \
                    393:        do { \
                    394:                *--s = (num % 10) + '0'; \
                    395:        } while ((num /= 10) != 0); \
                    396:        if (neg) *--s = '-'; \
                    397:        strlcpy(buf, s, len); \
                    398: }
                    399:
                    400: TYPE_TO_A_FUNC(postoa, POSITION)
                    401: TYPE_TO_A_FUNC(linenumtoa, LINENUM)
                    402: TYPE_TO_A_FUNC(inttoa, int)
                    403:
                    404: /*
1.1       etheisen  405:  * Output an integer in a given radix.
                    406:  */
                    407:        static int
1.5       millert   408: iprint_int(num)
1.1       etheisen  409:        int num;
                    410: {
1.5       millert   411:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  412:
1.5       millert   413:        inttoa(num, buf, sizeof(buf));
                    414:        putstr(buf);
                    415:        return (strlen(buf));
                    416: }
1.1       etheisen  417:
1.5       millert   418: /*
                    419:  * Output a line number in a given radix.
                    420:  */
                    421:        static int
                    422: iprint_linenum(num)
                    423:        LINENUM num;
                    424: {
                    425:        char buf[INT_STRLEN_BOUND(num)];
1.1       etheisen  426:
1.5       millert   427:        linenumtoa(num, buf, sizeof(buf));
                    428:        putstr(buf);
                    429:        return (strlen(buf));
1.1       etheisen  430: }
                    431:
                    432: /*
                    433:  * This function implements printf-like functionality
                    434:  * using a more portable argument list mechanism than printf's.
                    435:  */
                    436:        static int
1.5       millert   437: less_printf(fmt, parg)
                    438:        register char *fmt;
1.1       etheisen  439:        PARG *parg;
                    440: {
1.5       millert   441:        register char *s;
                    442:        register int col;
1.1       etheisen  443:
                    444:        col = 0;
                    445:        while (*fmt != '\0')
                    446:        {
                    447:                if (*fmt != '%')
                    448:                {
                    449:                        putchr(*fmt++);
                    450:                        col++;
                    451:                } else
                    452:                {
                    453:                        ++fmt;
1.5       millert   454:                        switch (*fmt++)
                    455:                        {
1.1       etheisen  456:                        case 's':
                    457:                                s = parg->p_string;
                    458:                                parg++;
                    459:                                while (*s != '\0')
                    460:                                {
                    461:                                        putchr(*s++);
                    462:                                        col++;
                    463:                                }
                    464:                                break;
                    465:                        case 'd':
1.5       millert   466:                                col += iprint_int(parg->p_int);
                    467:                                parg++;
                    468:                                break;
                    469:                        case 'n':
                    470:                                col += iprint_linenum(parg->p_linenum);
1.1       etheisen  471:                                parg++;
                    472:                                break;
                    473:                        }
                    474:                }
                    475:        }
                    476:        return (col);
                    477: }
                    478:
                    479: /*
1.5       millert   480:  * Get a RETURN.
                    481:  * If some other non-trivial char is pressed, unget it, so it will
                    482:  * become the next command.
                    483:  */
                    484:        public void
                    485: get_return()
                    486: {
                    487:        int c;
                    488:
                    489: #if ONLY_RETURN
                    490:        while ((c = getchr()) != '\n' && c != '\r')
                    491:                bell();
                    492: #else
                    493:        c = getchr();
                    494:        if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
                    495:                ungetcc(c);
                    496: #endif
                    497: }
                    498:
                    499: /*
1.1       etheisen  500:  * Output a message in the lower left corner of the screen
                    501:  * and wait for carriage return.
                    502:  */
                    503:        public void
                    504: error(fmt, parg)
                    505:        char *fmt;
                    506:        PARG *parg;
                    507: {
                    508:        int col = 0;
                    509:        static char return_to_continue[] = "  (press RETURN)";
                    510:
                    511:        errmsgs++;
                    512:
1.5       millert   513:        if (any_display && is_tty)
1.1       etheisen  514:        {
1.6     ! shadchin  515:                if (!oldbot)
        !           516:                        squish_check();
        !           517:                at_exit();
1.1       etheisen  518:                clear_bot();
1.6     ! shadchin  519:                at_enter(AT_STANDOUT);
1.1       etheisen  520:                col += so_s_width;
                    521:        }
                    522:
1.5       millert   523:        col += less_printf(fmt, parg);
1.1       etheisen  524:
1.5       millert   525:        if (!(any_display && is_tty))
1.1       etheisen  526:        {
                    527:                putchr('\n');
                    528:                return;
                    529:        }
                    530:
                    531:        putstr(return_to_continue);
1.6     ! shadchin  532:        at_exit();
1.1       etheisen  533:        col += sizeof(return_to_continue) + so_e_width;
                    534:
1.5       millert   535:        get_return();
1.1       etheisen  536:        lower_left();
1.6     ! shadchin  537:     clear_eol();
1.1       etheisen  538:
                    539:        if (col >= sc_width)
                    540:                /*
                    541:                 * Printing the message has probably scrolled the screen.
                    542:                 * {{ Unless the terminal doesn't have auto margins,
                    543:                 *    in which case we just hammered on the right margin. }}
                    544:                 */
                    545:                screen_trashed = 1;
                    546:
                    547:        flush();
                    548: }
                    549:
                    550: static char intr_to_abort[] = "... (interrupt to abort)";
                    551:
                    552: /*
                    553:  * Output a message in the lower left corner of the screen
                    554:  * and don't wait for carriage return.
                    555:  * Usually used to warn that we are beginning a potentially
                    556:  * time-consuming operation.
                    557:  */
                    558:        public void
                    559: ierror(fmt, parg)
                    560:        char *fmt;
                    561:        PARG *parg;
                    562: {
1.6     ! shadchin  563:        at_exit();
1.1       etheisen  564:        clear_bot();
1.6     ! shadchin  565:        at_enter(AT_STANDOUT);
1.5       millert   566:        (void) less_printf(fmt, parg);
1.1       etheisen  567:        putstr(intr_to_abort);
1.6     ! shadchin  568:        at_exit();
1.1       etheisen  569:        flush();
                    570:        need_clr = 1;
                    571: }
                    572:
                    573: /*
                    574:  * Output a message in the lower left corner of the screen
                    575:  * and return a single-character response.
                    576:  */
                    577:        public int
                    578: query(fmt, parg)
                    579:        char *fmt;
                    580:        PARG *parg;
                    581: {
1.5       millert   582:        register int c;
1.1       etheisen  583:        int col = 0;
                    584:
1.5       millert   585:        if (any_display && is_tty)
1.1       etheisen  586:                clear_bot();
                    587:
1.5       millert   588:        (void) less_printf(fmt, parg);
1.1       etheisen  589:        c = getchr();
                    590:
1.5       millert   591:        if (!(any_display && is_tty))
1.1       etheisen  592:        {
                    593:                putchr('\n');
                    594:                return (c);
                    595:        }
                    596:
                    597:        lower_left();
                    598:        if (col >= sc_width)
                    599:                screen_trashed = 1;
                    600:        flush();
                    601:
                    602:        return (c);
                    603: }