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

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