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

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