[BACK]Return to line.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/line.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:  * Routines to manipulate the "line buffer".
                     14:  * The line buffer holds a line of output as it is being built
                     15:  * in preparation for output to the screen.
                     16:  */
                     17:
                     18: #include "less.h"
1.1.1.3 ! shadchin   19: #include "charset.h"
1.1       etheisen   20:
1.1.1.3 ! shadchin   21: static char *linebuf = NULL;   /* Buffer which holds the current output line */
1.1.1.2   millert    22: static char *attr = NULL;      /* Extension of linebuf to hold attributes */
                     23: public int size_linebuf = 0;   /* Size of line buffer (and attr buffer) */
                     24:
1.1.1.3 ! shadchin   25: static int cshift;             /* Current left-shift of output line buffer */
1.1.1.2   millert    26: public int hshift;             /* Desired left-shift of output line buffer */
                     27: public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */
                     28: public int ntabstops = 1;      /* Number of tabstops */
                     29: public int tabdefault = 8;     /* Default repeated tabstops */
1.1       etheisen   30:
                     31: static int curr;               /* Index into linebuf */
                     32: static int column;             /* Printable length, accounting for
                     33:                                   backspaces, etc. */
                     34: static int overstrike;         /* Next char should overstrike previous char */
1.1.1.2   millert    35: static int last_overstrike = AT_NORMAL;
1.1       etheisen   36: static int is_null_line;       /* There is no current line */
1.1.1.2   millert    37: static int lmargin;            /* Left margin */
1.1       etheisen   38: static char pendc;
                     39: static POSITION pendpos;
1.1.1.2   millert    40: static char *end_ansi_chars;
1.1.1.3 ! shadchin   41: static char *mid_ansi_chars;
1.1       etheisen   42:
1.1.1.3 ! shadchin   43: static int attr_swidth();
        !            44: static int attr_ewidth();
1.1       etheisen   45: static int do_append();
                     46:
1.1.1.3 ! shadchin   47: extern int sigs;
1.1       etheisen   48: extern int bs_mode;
                     49: extern int linenums;
                     50: extern int ctldisp;
                     51: extern int twiddle;
                     52: extern int binattr;
1.1.1.2   millert    53: extern int status_col;
1.1       etheisen   54: extern int auto_wrap, ignaw;
                     55: extern int bo_s_width, bo_e_width;
                     56: extern int ul_s_width, ul_e_width;
                     57: extern int bl_s_width, bl_e_width;
                     58: extern int so_s_width, so_e_width;
                     59: extern int sc_width, sc_height;
1.1.1.2   millert    60: extern int utf_mode;
                     61: extern POSITION start_attnpos;
                     62: extern POSITION end_attnpos;
                     63:
1.1.1.3 ! shadchin   64: static char mbc_buf[MAX_UTF_CHAR_LEN];
        !            65: static int mbc_buf_len = 0;
        !            66: static int mbc_buf_index = 0;
        !            67: static POSITION mbc_pos;
        !            68:
1.1.1.2   millert    69: /*
                     70:  * Initialize from environment variables.
                     71:  */
                     72:        public void
                     73: init_line()
                     74: {
                     75:        end_ansi_chars = lgetenv("LESSANSIENDCHARS");
                     76:        if (end_ansi_chars == NULL || *end_ansi_chars == '\0')
                     77:                end_ansi_chars = "m";
1.1.1.3 ! shadchin   78:
        !            79:        mid_ansi_chars = lgetenv("LESSANSIMIDCHARS");
        !            80:        if (mid_ansi_chars == NULL || *mid_ansi_chars == '\0')
        !            81:                mid_ansi_chars = "0123456789;[?!\"'#%()*+ ";
        !            82:
1.1.1.2   millert    83:        linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
                     84:        attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
                     85:        size_linebuf = LINEBUF_SIZE;
                     86: }
                     87:
                     88: /*
                     89:  * Expand the line buffer.
                     90:  */
1.1.1.3 ! shadchin   91:        static int
1.1.1.2   millert    92: expand_linebuf()
                     93: {
1.1.1.3 ! shadchin   94:        /* Double the size of the line buffer. */
        !            95:        int new_size = size_linebuf * 2;
        !            96:
        !            97:        /* Just realloc to expand the buffer, if we can. */
        !            98: #if HAVE_REALLOC
        !            99:        char *new_buf = (char *) realloc(linebuf, new_size);
        !           100:        char *new_attr = (char *) realloc(attr, new_size);
        !           101: #else
1.1.1.2   millert   102:        char *new_buf = (char *) calloc(new_size, sizeof(char));
                    103:        char *new_attr = (char *) calloc(new_size, sizeof(char));
1.1.1.3 ! shadchin  104: #endif
1.1.1.2   millert   105:        if (new_buf == NULL || new_attr == NULL)
                    106:        {
                    107:                if (new_attr != NULL)
                    108:                        free(new_attr);
                    109:                if (new_buf != NULL)
                    110:                        free(new_buf);
                    111:                return 1;
                    112:        }
1.1.1.3 ! shadchin  113: #if HAVE_REALLOC
        !           114:        /*
        !           115:         * We realloc'd the buffers; they already have the old contents.
        !           116:         */
        !           117:        #if 0
        !           118:        memset(new_buf + size_linebuf, 0, new_size - size_linebuf);
        !           119:        memset(new_attr + size_linebuf, 0, new_size - size_linebuf);
        !           120:        #endif
        !           121: #else
        !           122:        /*
        !           123:         * We just calloc'd the buffers; copy the old contents.
        !           124:         */
1.1.1.2   millert   125:        memcpy(new_buf, linebuf, size_linebuf * sizeof(char));
                    126:        memcpy(new_attr, attr, size_linebuf * sizeof(char));
                    127:        free(attr);
                    128:        free(linebuf);
1.1.1.3 ! shadchin  129: #endif
1.1.1.2   millert   130:        linebuf = new_buf;
                    131:        attr = new_attr;
                    132:        size_linebuf = new_size;
                    133:        return 0;
                    134: }
1.1       etheisen  135:
                    136: /*
1.1.1.3 ! shadchin  137:  * Is a character ASCII?
        !           138:  */
        !           139:        public int
        !           140: is_ascii_char(ch)
        !           141:        LWCHAR ch;
        !           142: {
        !           143:        return (ch <= 0x7F);
        !           144: }
        !           145:
        !           146: /*
1.1       etheisen  147:  * Rewind the line buffer.
                    148:  */
                    149:        public void
                    150: prewind()
                    151: {
                    152:        curr = 0;
                    153:        column = 0;
1.1.1.3 ! shadchin  154:        cshift = 0;
1.1       etheisen  155:        overstrike = 0;
1.1.1.3 ! shadchin  156:        last_overstrike = AT_NORMAL;
        !           157:        mbc_buf_len = 0;
1.1       etheisen  158:        is_null_line = 0;
                    159:        pendc = '\0';
1.1.1.2   millert   160:        lmargin = 0;
                    161:        if (status_col)
                    162:                lmargin += 1;
1.1       etheisen  163: }
                    164:
                    165: /*
                    166:  * Insert the line number (of the given position) into the line buffer.
                    167:  */
                    168:        public void
                    169: plinenum(pos)
                    170:        POSITION pos;
                    171: {
1.1.1.2   millert   172:        register LINENUM linenum = 0;
1.1       etheisen  173:        register int i;
1.1.1.2   millert   174:
                    175:        if (linenums == OPT_ONPLUS)
                    176:        {
                    177:                /*
                    178:                 * Get the line number and put it in the current line.
                    179:                 * {{ Note: since find_linenum calls forw_raw_line,
                    180:                 *    it may seek in the input file, requiring the caller
                    181:                 *    of plinenum to re-seek if necessary. }}
                    182:                 * {{ Since forw_raw_line modifies linebuf, we must
                    183:                 *    do this first, before storing anything in linebuf. }}
                    184:                 */
                    185:                linenum = find_linenum(pos);
                    186:        }
1.1       etheisen  187:
                    188:        /*
1.1.1.2   millert   189:         * Display a status column if the -J option is set.
1.1       etheisen  190:         */
1.1.1.2   millert   191:        if (status_col)
                    192:        {
                    193:                linebuf[curr] = ' ';
                    194:                if (start_attnpos != NULL_POSITION &&
                    195:                    pos >= start_attnpos && pos < end_attnpos)
1.1.1.3 ! shadchin  196:                        attr[curr] = AT_NORMAL|AT_HILITE;
1.1.1.2   millert   197:                else
1.1.1.3 ! shadchin  198:                        attr[curr] = AT_NORMAL;
1.1.1.2   millert   199:                curr++;
                    200:                column++;
                    201:        }
1.1       etheisen  202:        /*
1.1.1.2   millert   203:         * Display the line number at the start of each line
                    204:         * if the -N option is set.
1.1       etheisen  205:         */
1.1.1.2   millert   206:        if (linenums == OPT_ONPLUS)
                    207:        {
                    208:                char buf[INT_STRLEN_BOUND(pos) + 2];
                    209:                int n;
1.1       etheisen  210:
1.1.1.2   millert   211:                linenumtoa(linenum, buf);
                    212:                n = strlen(buf);
                    213:                if (n < MIN_LINENUM_WIDTH)
                    214:                        n = MIN_LINENUM_WIDTH;
                    215:                sprintf(linebuf+curr, "%*s ", n, buf);
                    216:                n++;  /* One space after the line number. */
                    217:                for (i = 0; i < n; i++)
                    218:                        attr[curr+i] = AT_NORMAL;
                    219:                curr += n;
                    220:                column += n;
                    221:                lmargin += n;
                    222:        }
1.1       etheisen  223:
                    224:        /*
1.1.1.2   millert   225:         * Append enough spaces to bring us to the lmargin.
1.1       etheisen  226:         */
1.1.1.2   millert   227:        while (column < lmargin)
1.1       etheisen  228:        {
                    229:                linebuf[curr] = ' ';
                    230:                attr[curr++] = AT_NORMAL;
                    231:                column++;
1.1.1.2   millert   232:        }
                    233: }
                    234:
                    235: /*
1.1.1.3 ! shadchin  236:  * Shift the input line left.
        !           237:  * This means discarding N printable chars at the start of the buffer.
1.1.1.2   millert   238:  */
1.1.1.3 ! shadchin  239:        static void
        !           240: pshift(shift)
        !           241:        int shift;
1.1.1.2   millert   242: {
1.1.1.3 ! shadchin  243:        LWCHAR prev_ch = 0;
        !           244:        unsigned char c;
        !           245:        int shifted = 0;
        !           246:        int to;
        !           247:        int from;
        !           248:        int len;
        !           249:        int width;
        !           250:        int prev_attr;
        !           251:        int next_attr;
1.1.1.2   millert   252:
1.1.1.3 ! shadchin  253:        if (shift > column - lmargin)
        !           254:                shift = column - lmargin;
        !           255:        if (shift > curr - lmargin)
        !           256:                shift = curr - lmargin;
        !           257:
        !           258:        to = from = lmargin;
1.1.1.2   millert   259:        /*
1.1.1.3 ! shadchin  260:         * We keep on going when shifted == shift
        !           261:         * to get all combining chars.
1.1.1.2   millert   262:         */
1.1.1.3 ! shadchin  263:        while (shifted <= shift && from < curr)
1.1.1.2   millert   264:        {
1.1.1.3 ! shadchin  265:                c = linebuf[from];
        !           266:                if (ctldisp == OPT_ONPLUS && IS_CSI_START(c))
1.1.1.2   millert   267:                {
1.1.1.3 ! shadchin  268:                        /* Keep cumulative effect.  */
        !           269:                        linebuf[to] = c;
        !           270:                        attr[to++] = attr[from++];
        !           271:                        while (from < curr && linebuf[from])
        !           272:                        {
        !           273:                                linebuf[to] = linebuf[from];
        !           274:                                attr[to++] = attr[from];
        !           275:                                if (!is_ansi_middle(linebuf[from++]))
        !           276:                                        break;
        !           277:                        }
        !           278:                        continue;
        !           279:                }
        !           280:
        !           281:                width = 0;
        !           282:
        !           283:                if (!IS_ASCII_OCTET(c) && utf_mode)
        !           284:                {
        !           285:                        /* Assumes well-formedness validation already done.  */
        !           286:                        LWCHAR ch;
        !           287:
        !           288:                        len = utf_len(c);
        !           289:                        if (from + len > curr)
        !           290:                                break;
        !           291:                        ch = get_wchar(linebuf + from);
        !           292:                        if (!is_composing_char(ch) && !is_combining_char(prev_ch, ch))
        !           293:                                width = is_wide_char(ch) ? 2 : 1;
        !           294:                        prev_ch = ch;
1.1.1.2   millert   295:                } else
                    296:                {
1.1.1.3 ! shadchin  297:                        len = 1;
        !           298:                        if (c == '\b')
        !           299:                                /* XXX - Incorrect if several '\b' in a row.  */
        !           300:                                width = (utf_mode && is_wide_char(prev_ch)) ? -2 : -1;
        !           301:                        else if (!control_char(c))
        !           302:                                width = 1;
        !           303:                        prev_ch = 0;
        !           304:                }
        !           305:
        !           306:                if (width == 2 && shift - shifted == 1) {
        !           307:                        /* Should never happen when called by pshift_all().  */
        !           308:                        attr[to] = attr[from];
        !           309:                        /*
        !           310:                         * Assume a wide_char will never be the first half of a
        !           311:                         * combining_char pair, so reset prev_ch in case we're
        !           312:                         * followed by a '\b'.
        !           313:                         */
        !           314:                        prev_ch = linebuf[to++] = ' ';
        !           315:                        from += len;
        !           316:                        shifted++;
        !           317:                        continue;
        !           318:                }
        !           319:
        !           320:                /* Adjust width for magic cookies. */
        !           321:                prev_attr = (to > 0) ? attr[to-1] : AT_NORMAL;
        !           322:                next_attr = (from + len < curr) ? attr[from + len] : prev_attr;
        !           323:                if (!is_at_equiv(attr[from], prev_attr) &&
        !           324:                        !is_at_equiv(attr[from], next_attr))
        !           325:                {
        !           326:                        width += attr_swidth(attr[from]);
        !           327:                        if (from + len < curr)
        !           328:                                width += attr_ewidth(attr[from]);
        !           329:                        if (is_at_equiv(prev_attr, next_attr))
1.1.1.2   millert   330:                        {
1.1.1.3 ! shadchin  331:                                width += attr_ewidth(prev_attr);
        !           332:                                if (from + len < curr)
        !           333:                                        width += attr_swidth(next_attr);
1.1.1.2   millert   334:                        }
                    335:                }
                    336:
1.1.1.3 ! shadchin  337:                if (shift - shifted < width)
        !           338:                        break;
        !           339:                from += len;
        !           340:                shifted += width;
        !           341:                if (shifted < 0)
        !           342:                        shifted = 0;
        !           343:        }
        !           344:        while (from < curr)
        !           345:        {
        !           346:                linebuf[to] = linebuf[from];
        !           347:                attr[to++] = attr[from++];
        !           348:        }
        !           349:        curr = to;
        !           350:        column -= shifted;
        !           351:        cshift += shifted;
1.1.1.2   millert   352: }
                    353:
                    354: /*
1.1.1.3 ! shadchin  355:  *
1.1.1.2   millert   356:  */
1.1.1.3 ! shadchin  357:        public void
        !           358: pshift_all()
1.1.1.2   millert   359: {
1.1.1.3 ! shadchin  360:        pshift(column);
1.1       etheisen  361: }
                    362:
                    363: /*
                    364:  * Return the printing width of the start (enter) sequence
                    365:  * for a given character attribute.
                    366:  */
1.1.1.2   millert   367:        static int
1.1       etheisen  368: attr_swidth(a)
                    369:        int a;
                    370: {
1.1.1.3 ! shadchin  371:        int w = 0;
        !           372:
        !           373:        a = apply_at_specials(a);
        !           374:
        !           375:        if (a & AT_UNDERLINE)
        !           376:                w += ul_s_width;
        !           377:        if (a & AT_BOLD)
        !           378:                w += bo_s_width;
        !           379:        if (a & AT_BLINK)
        !           380:                w += bl_s_width;
        !           381:        if (a & AT_STANDOUT)
        !           382:                w += so_s_width;
        !           383:
        !           384:        return w;
1.1       etheisen  385: }
                    386:
                    387: /*
                    388:  * Return the printing width of the end (exit) sequence
                    389:  * for a given character attribute.
                    390:  */
1.1.1.2   millert   391:        static int
1.1       etheisen  392: attr_ewidth(a)
                    393:        int a;
                    394: {
1.1.1.3 ! shadchin  395:        int w = 0;
        !           396:
        !           397:        a = apply_at_specials(a);
        !           398:
        !           399:        if (a & AT_UNDERLINE)
        !           400:                w += ul_e_width;
        !           401:        if (a & AT_BOLD)
        !           402:                w += bo_e_width;
        !           403:        if (a & AT_BLINK)
        !           404:                w += bl_e_width;
        !           405:        if (a & AT_STANDOUT)
        !           406:                w += so_e_width;
        !           407:
        !           408:        return w;
1.1       etheisen  409: }
                    410:
                    411: /*
                    412:  * Return the printing width of a given character and attribute,
                    413:  * if the character were added to the current position in the line buffer.
                    414:  * Adding a character with a given attribute may cause an enter or exit
                    415:  * attribute sequence to be inserted, so this must be taken into account.
                    416:  */
                    417:        static int
1.1.1.3 ! shadchin  418: pwidth(ch, a, prev_ch)
        !           419:        LWCHAR ch;
1.1       etheisen  420:        int a;
1.1.1.3 ! shadchin  421:        LWCHAR prev_ch;
1.1       etheisen  422: {
1.1.1.3 ! shadchin  423:        int w;
1.1.1.2   millert   424:
1.1.1.3 ! shadchin  425:        if (ch == '\b')
1.1       etheisen  426:                /*
1.1.1.3 ! shadchin  427:                 * Backspace moves backwards one or two positions.
        !           428:                 * XXX - Incorrect if several '\b' in a row.
1.1       etheisen  429:                 */
1.1.1.3 ! shadchin  430:                return (utf_mode && is_wide_char(prev_ch)) ? -2 : -1;
1.1       etheisen  431:
1.1.1.3 ! shadchin  432:        if (!utf_mode || is_ascii_char(ch))
        !           433:        {
        !           434:                if (control_char((char)ch))
        !           435:                {
        !           436:                        /*
        !           437:                         * Control characters do unpredictable things,
        !           438:                         * so we don't even try to guess; say it doesn't move.
        !           439:                         * This can only happen if the -r flag is in effect.
        !           440:                         */
        !           441:                        return (0);
        !           442:                }
        !           443:        } else
        !           444:        {
        !           445:                if (is_composing_char(ch) || is_combining_char(prev_ch, ch))
        !           446:                {
        !           447:                        /*
        !           448:                         * Composing and combining chars take up no space.
        !           449:                         *
        !           450:                         * Some terminals, upon failure to compose a
        !           451:                         * composing character with the character(s) that
        !           452:                         * precede(s) it will actually take up one column
        !           453:                         * for the composing character; there isn't much
        !           454:                         * we could do short of testing the (complex)
        !           455:                         * composition process ourselves and printing
        !           456:                         * a binary representation when it fails.
        !           457:                         */
        !           458:                        return (0);
        !           459:                }
        !           460:        }
1.1       etheisen  461:
                    462:        /*
1.1.1.3 ! shadchin  463:         * Other characters take one or two columns,
1.1       etheisen  464:         * plus the width of any attribute enter/exit sequence.
                    465:         */
                    466:        w = 1;
1.1.1.3 ! shadchin  467:        if (is_wide_char(ch))
        !           468:                w++;
        !           469:        if (curr > 0 && !is_at_equiv(attr[curr-1], a))
1.1       etheisen  470:                w += attr_ewidth(attr[curr-1]);
1.1.1.3 ! shadchin  471:        if ((apply_at_specials(a) != AT_NORMAL) &&
        !           472:            (curr == 0 || !is_at_equiv(attr[curr-1], a)))
1.1       etheisen  473:                w += attr_swidth(a);
                    474:        return (w);
                    475: }
                    476:
                    477: /*
1.1.1.3 ! shadchin  478:  * Delete to the previous base character in the line buffer.
        !           479:  * Return 1 if one is found.
1.1       etheisen  480:  */
1.1.1.3 ! shadchin  481:        static int
1.1       etheisen  482: backc()
                    483: {
1.1.1.3 ! shadchin  484:        LWCHAR prev_ch;
        !           485:        char *p = linebuf + curr;
        !           486:        LWCHAR ch = step_char(&p, -1, linebuf + lmargin);
        !           487:        int width;
        !           488:
        !           489:        /* This assumes that there is no '\b' in linebuf.  */
        !           490:        while (   curr > lmargin
        !           491:               && column > lmargin
        !           492:               && (!(attr[curr - 1] & (AT_ANSI|AT_BINARY))))
        !           493:        {
        !           494:                curr = p - linebuf;
        !           495:                prev_ch = step_char(&p, -1, linebuf + lmargin);
        !           496:                width = pwidth(ch, attr[curr], prev_ch);
        !           497:                column -= width;
        !           498:                if (width > 0)
        !           499:                        return 1;
        !           500:                ch = prev_ch;
        !           501:        }
        !           502:
        !           503:        return 0;
1.1       etheisen  504: }
                    505:
                    506: /*
1.1.1.2   millert   507:  * Are we currently within a recognized ANSI escape sequence?
                    508:  */
                    509:        static int
                    510: in_ansi_esc_seq()
                    511: {
1.1.1.3 ! shadchin  512:        char *p;
1.1.1.2   millert   513:
                    514:        /*
                    515:         * Search backwards for either an ESC (which means we ARE in a seq);
                    516:         * or an end char (which means we're NOT in a seq).
                    517:         */
1.1.1.3 ! shadchin  518:        for (p = &linebuf[curr];  p > linebuf; )
1.1.1.2   millert   519:        {
1.1.1.3 ! shadchin  520:                LWCHAR ch = step_char(&p, -1, linebuf);
        !           521:                if (IS_CSI_START(ch))
1.1.1.2   millert   522:                        return (1);
1.1.1.3 ! shadchin  523:                if (!is_ansi_middle(ch))
1.1.1.2   millert   524:                        return (0);
                    525:        }
                    526:        return (0);
                    527: }
                    528:
                    529: /*
                    530:  * Is a character the end of an ANSI escape sequence?
                    531:  */
                    532:        public int
1.1.1.3 ! shadchin  533: is_ansi_end(ch)
        !           534:        LWCHAR ch;
1.1.1.2   millert   535: {
1.1.1.3 ! shadchin  536:        if (!is_ascii_char(ch))
        !           537:                return (0);
        !           538:        return (strchr(end_ansi_chars, (char) ch) != NULL);
        !           539: }
        !           540:
        !           541: /*
        !           542:  *
        !           543:  */
        !           544:        public int
        !           545: is_ansi_middle(ch)
        !           546:        LWCHAR ch;
        !           547: {
        !           548:        if (!is_ascii_char(ch))
        !           549:                return (0);
        !           550:        if (is_ansi_end(ch))
        !           551:                return (0);
        !           552:        return (strchr(mid_ansi_chars, (char) ch) != NULL);
1.1.1.2   millert   553: }
                    554:
                    555: /*
1.1       etheisen  556:  * Append a character and attribute to the line buffer.
                    557:  */
1.1.1.3 ! shadchin  558: #define        STORE_CHAR(ch,a,rep,pos) \
        !           559:        do { \
        !           560:                if (store_char((ch),(a),(rep),(pos))) return (1); \
        !           561:        } while (0)
1.1.1.2   millert   562:
1.1       etheisen  563:        static int
1.1.1.3 ! shadchin  564: store_char(ch, a, rep, pos)
        !           565:        LWCHAR ch;
1.1       etheisen  566:        int a;
1.1.1.3 ! shadchin  567:        char *rep;
1.1       etheisen  568:        POSITION pos;
                    569: {
1.1.1.3 ! shadchin  570:        int w;
        !           571:        int replen;
        !           572:        char cs;
        !           573:
        !           574:        w = (a & (AT_UNDERLINE|AT_BOLD));       /* Pre-use w.  */
        !           575:        if (w != AT_NORMAL)
        !           576:                last_overstrike = w;
1.1       etheisen  577:
                    578: #if HILITE_SEARCH
1.1.1.2   millert   579:        {
1.1.1.3 ! shadchin  580:                int matches;
        !           581:                if (is_hilited(pos, pos+1, 0, &matches))
        !           582:                {
        !           583:                        /*
        !           584:                         * This character should be highlighted.
        !           585:                         * Override the attribute passed in.
        !           586:                         */
        !           587:                        if (a != AT_ANSI)
        !           588:                                a |= AT_HILITE;
        !           589:                }
1.1.1.2   millert   590:        }
1.1       etheisen  591: #endif
1.1.1.3 ! shadchin  592:
1.1.1.2   millert   593:        if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq())
1.1.1.3 ! shadchin  594:        {
        !           595:                if (!is_ansi_end(ch) && !is_ansi_middle(ch)) {
        !           596:                        /* Remove whole unrecognized sequence.  */
        !           597:                        char *p = &linebuf[curr];
        !           598:                        LWCHAR bch;
        !           599:                        do {
        !           600:                                bch = step_char(&p, -1, linebuf);
        !           601:                        } while (p > linebuf && !IS_CSI_START(bch));
        !           602:                        curr = p - linebuf;
        !           603:                        return 0;
        !           604:                }
        !           605:                a = AT_ANSI;    /* Will force re-AT_'ing around it.  */
        !           606:                w = 0;
        !           607:        }
        !           608:        else if (ctldisp == OPT_ONPLUS && IS_CSI_START(ch))
        !           609:        {
        !           610:                a = AT_ANSI;    /* Will force re-AT_'ing around it.  */
1.1.1.2   millert   611:                w = 0;
1.1.1.3 ! shadchin  612:        }
1.1.1.2   millert   613:        else
1.1.1.3 ! shadchin  614:        {
        !           615:                char *p = &linebuf[curr];
        !           616:                LWCHAR prev_ch = step_char(&p, -1, linebuf);
        !           617:                w = pwidth(ch, a, prev_ch);
        !           618:        }
        !           619:
1.1.1.2   millert   620:        if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width)
1.1       etheisen  621:                /*
                    622:                 * Won't fit on screen.
                    623:                 */
                    624:                return (1);
                    625:
1.1.1.3 ! shadchin  626:        if (rep == NULL)
        !           627:        {
        !           628:                cs = (char) ch;
        !           629:                rep = &cs;
        !           630:                replen = 1;
        !           631:        } else
        !           632:        {
        !           633:                replen = utf_len(rep[0]);
        !           634:        }
        !           635:        if (curr + replen >= size_linebuf-6)
1.1.1.2   millert   636:        {
1.1       etheisen  637:                /*
                    638:                 * Won't fit in line buffer.
1.1.1.2   millert   639:                 * Try to expand it.
1.1       etheisen  640:                 */
1.1.1.2   millert   641:                if (expand_linebuf())
                    642:                        return (1);
                    643:        }
1.1       etheisen  644:
1.1.1.3 ! shadchin  645:        while (replen-- > 0)
1.1       etheisen  646:        {
1.1.1.3 ! shadchin  647:                linebuf[curr] = *rep++;
        !           648:                attr[curr] = a;
        !           649:                curr++;
1.1       etheisen  650:        }
                    651:        column += w;
                    652:        return (0);
                    653: }
                    654:
                    655: /*
1.1.1.2   millert   656:  * Append a tab to the line buffer.
                    657:  * Store spaces to represent the tab.
                    658:  */
                    659: #define        STORE_TAB(a,pos) \
                    660:        do { if (store_tab((a),(pos))) return (1); } while (0)
                    661:
                    662:        static int
                    663: store_tab(attr, pos)
                    664:        int attr;
                    665:        POSITION pos;
                    666: {
                    667:        int to_tab = column + cshift - lmargin;
                    668:        int i;
                    669:
                    670:        if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1])
                    671:                to_tab = tabdefault -
                    672:                     ((to_tab - tabstops[ntabstops-1]) % tabdefault);
                    673:        else
                    674:        {
                    675:                for (i = ntabstops - 2;  i >= 0;  i--)
                    676:                        if (to_tab >= tabstops[i])
                    677:                                break;
                    678:                to_tab = tabstops[i+1] - to_tab;
                    679:        }
                    680:
1.1.1.3 ! shadchin  681:        if (column + to_tab - 1 + pwidth(' ', attr, 0) + attr_ewidth(attr) > sc_width)
        !           682:                return 1;
        !           683:
1.1.1.2   millert   684:        do {
1.1.1.3 ! shadchin  685:                STORE_CHAR(' ', attr, " ", pos);
1.1.1.2   millert   686:        } while (--to_tab > 0);
                    687:        return 0;
                    688: }
                    689:
1.1.1.3 ! shadchin  690: #define STORE_PRCHAR(c, pos) \
        !           691:        do { if (store_prchar((c), (pos))) return 1; } while (0)
        !           692:
        !           693:        static int
        !           694: store_prchar(c, pos)
        !           695:        char c;
        !           696:        POSITION pos;
        !           697: {
        !           698:        char *s;
        !           699:
        !           700:        /*
        !           701:         * Convert to printable representation.
        !           702:         */
        !           703:        s = prchar(c);
        !           704:
        !           705:        /*
        !           706:         * Make sure we can get the entire representation
        !           707:         * of the character on this line.
        !           708:         */
        !           709:        if (column + (int) strlen(s) - 1 +
        !           710:             pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width)
        !           711:                return 1;
        !           712:
        !           713:        for ( ;  *s != 0;  s++)
        !           714:                STORE_CHAR(*s, AT_BINARY, NULL, pos);
        !           715:
        !           716:        return 0;
        !           717: }
        !           718:
        !           719:        static int
        !           720: flush_mbc_buf(pos)
        !           721:        POSITION pos;
        !           722: {
        !           723:        int i;
        !           724:
        !           725:        for (i = 0; i < mbc_buf_index; i++)
        !           726:                if (store_prchar(mbc_buf[i], pos))
        !           727:                        return mbc_buf_index - i;
        !           728:
        !           729:        return 0;
        !           730: }
        !           731:
1.1.1.2   millert   732: /*
1.1       etheisen  733:  * Append a character to the line buffer.
                    734:  * Expand tabs into spaces, handle underlining, boldfacing, etc.
                    735:  * Returns 0 if ok, 1 if couldn't fit in buffer.
                    736:  */
                    737:        public int
                    738: pappend(c, pos)
1.1.1.3 ! shadchin  739:        char c;
1.1       etheisen  740:        POSITION pos;
                    741: {
1.1.1.2   millert   742:        int r;
                    743:
1.1       etheisen  744:        if (pendc)
                    745:        {
1.1.1.3 ! shadchin  746:                if (do_append(pendc, NULL, pendpos))
1.1       etheisen  747:                        /*
                    748:                         * Oops.  We've probably lost the char which
                    749:                         * was in pendc, since caller won't back up.
                    750:                         */
                    751:                        return (1);
                    752:                pendc = '\0';
                    753:        }
                    754:
                    755:        if (c == '\r' && bs_mode == BS_SPECIAL)
                    756:        {
1.1.1.3 ! shadchin  757:                if (mbc_buf_len > 0)  /* utf_mode must be on. */
        !           758:                {
        !           759:                        /* Flush incomplete (truncated) sequence. */
        !           760:                        r = flush_mbc_buf(mbc_pos);
        !           761:                        mbc_buf_index = r + 1;
        !           762:                        mbc_buf_len = 0;
        !           763:                        if (r)
        !           764:                                return (mbc_buf_index);
        !           765:                }
        !           766:
1.1       etheisen  767:                /*
                    768:                 * Don't put the CR into the buffer until we see
                    769:                 * the next char.  If the next char is a newline,
                    770:                 * discard the CR.
                    771:                 */
                    772:                pendc = c;
                    773:                pendpos = pos;
                    774:                return (0);
                    775:        }
                    776:
1.1.1.3 ! shadchin  777:        if (!utf_mode)
        !           778:        {
        !           779:                r = do_append((LWCHAR) c, NULL, pos);
        !           780:        } else
        !           781:        {
        !           782:                /* Perform strict validation in all possible cases. */
        !           783:                if (mbc_buf_len == 0)
        !           784:                {
        !           785:                retry:
        !           786:                        mbc_buf_index = 1;
        !           787:                        *mbc_buf = c;
        !           788:                        if (IS_ASCII_OCTET(c))
        !           789:                                r = do_append((LWCHAR) c, NULL, pos);
        !           790:                        else if (IS_UTF8_LEAD(c))
        !           791:                        {
        !           792:                                mbc_buf_len = utf_len(c);
        !           793:                                mbc_pos = pos;
        !           794:                                return (0);
        !           795:                        } else
        !           796:                                /* UTF8_INVALID or stray UTF8_TRAIL */
        !           797:                                r = flush_mbc_buf(pos);
        !           798:                } else if (IS_UTF8_TRAIL(c))
        !           799:                {
        !           800:                        mbc_buf[mbc_buf_index++] = c;
        !           801:                        if (mbc_buf_index < mbc_buf_len)
        !           802:                                return (0);
        !           803:                        if (is_utf8_well_formed(mbc_buf))
        !           804:                                r = do_append(get_wchar(mbc_buf), mbc_buf, mbc_pos);
        !           805:                        else
        !           806:                                /* Complete, but not shortest form, sequence. */
        !           807:                                mbc_buf_index = r = flush_mbc_buf(mbc_pos);
        !           808:                        mbc_buf_len = 0;
        !           809:                } else
        !           810:                {
        !           811:                        /* Flush incomplete (truncated) sequence.  */
        !           812:                        r = flush_mbc_buf(mbc_pos);
        !           813:                        mbc_buf_index = r + 1;
        !           814:                        mbc_buf_len = 0;
        !           815:                        /* Handle new char.  */
        !           816:                        if (!r)
        !           817:                                goto retry;
        !           818:                }
        !           819:        }
        !           820:
1.1.1.2   millert   821:        /*
                    822:         * If we need to shift the line, do it.
                    823:         * But wait until we get to at least the middle of the screen,
                    824:         * so shifting it doesn't affect the chars we're currently
                    825:         * pappending.  (Bold & underline can get messed up otherwise.)
                    826:         */
                    827:        if (cshift < hshift && column > sc_width / 2)
                    828:        {
                    829:                linebuf[curr] = '\0';
                    830:                pshift(hshift - cshift);
                    831:        }
1.1.1.3 ! shadchin  832:        if (r)
        !           833:        {
        !           834:                /* How many chars should caller back up? */
        !           835:                r = (!utf_mode) ? 1 : mbc_buf_index;
        !           836:        }
1.1.1.2   millert   837:        return (r);
1.1       etheisen  838: }
                    839:
                    840:        static int
1.1.1.3 ! shadchin  841: do_append(ch, rep, pos)
        !           842:        LWCHAR ch;
        !           843:        char *rep;
1.1       etheisen  844:        POSITION pos;
                    845: {
                    846:        register int a;
1.1.1.3 ! shadchin  847:        LWCHAR prev_ch;
1.1       etheisen  848:
1.1.1.3 ! shadchin  849:        a = AT_NORMAL;
1.1       etheisen  850:
1.1.1.3 ! shadchin  851:        if (ch == '\b')
1.1.1.2   millert   852:        {
1.1.1.3 ! shadchin  853:                if (bs_mode == BS_CONTROL)
1.1.1.2   millert   854:                        goto do_control_char;
1.1.1.3 ! shadchin  855:
        !           856:                /*
        !           857:                 * A better test is needed here so we don't
        !           858:                 * backspace over part of the printed
        !           859:                 * representation of a binary character.
        !           860:                 */
        !           861:                if (   curr <= lmargin
        !           862:                    || column <= lmargin
        !           863:                    || (attr[curr - 1] & (AT_ANSI|AT_BINARY)))
        !           864:                        STORE_PRCHAR('\b', pos);
        !           865:                else if (bs_mode == BS_NORMAL)
        !           866:                        STORE_CHAR(ch, AT_NORMAL, NULL, pos);
        !           867:                else if (bs_mode == BS_SPECIAL)
        !           868:                        overstrike = backc();
        !           869:
        !           870:                return 0;
        !           871:        }
        !           872:
        !           873:        if (overstrike > 0)
1.1       etheisen  874:        {
                    875:                /*
                    876:                 * Overstrike the character at the current position
                    877:                 * in the line buffer.  This will cause either
                    878:                 * underline (if a "_" is overstruck),
                    879:                 * bold (if an identical character is overstruck),
                    880:                 * or just deletion of the character in the buffer.
                    881:                 */
1.1.1.3 ! shadchin  882:                overstrike = utf_mode ? -1 : 0;
        !           883:                /* To be correct, this must be a base character.  */
        !           884:                prev_ch = get_wchar(linebuf + curr);
        !           885:                a = attr[curr];
        !           886:                if (ch == prev_ch)
1.1.1.2   millert   887:                {
                    888:                        /*
                    889:                         * Overstriking a char with itself means make it bold.
                    890:                         * But overstriking an underscore with itself is
                    891:                         * ambiguous.  It could mean make it bold, or
                    892:                         * it could mean make it underlined.
                    893:                         * Use the previous overstrike to resolve it.
                    894:                         */
1.1.1.3 ! shadchin  895:                        if (ch == '_')
1.1.1.2   millert   896:                        {
1.1.1.3 ! shadchin  897:                                if ((a & (AT_BOLD|AT_UNDERLINE)) != AT_NORMAL)
        !           898:                                        a |= (AT_BOLD|AT_UNDERLINE);
        !           899:                                else if (last_overstrike != AT_NORMAL)
        !           900:                                        a |= last_overstrike;
        !           901:                                else
        !           902:                                        a |= AT_BOLD;
        !           903:                        } else
        !           904:                                a |= AT_BOLD;
        !           905:                } else if (ch == '_')
1.1.1.2   millert   906:                {
1.1.1.3 ! shadchin  907:                        a |= AT_UNDERLINE;
        !           908:                        ch = prev_ch;
        !           909:                        rep = linebuf + curr;
        !           910:                } else if (prev_ch == '_')
        !           911:                {
        !           912:                        a |= AT_UNDERLINE;
        !           913:                }
        !           914:                /* Else we replace prev_ch, but we keep its attributes.  */
        !           915:        } else if (overstrike < 0)
        !           916:        {
        !           917:                if (   is_composing_char(ch)
        !           918:                    || is_combining_char(get_wchar(linebuf + curr), ch))
        !           919:                        /* Continuation of the same overstrike.  */
        !           920:                        a = last_overstrike;
1.1       etheisen  921:                else
1.1.1.3 ! shadchin  922:                        overstrike = 0;
        !           923:        }
        !           924:
        !           925:        if (ch == '\t')
1.1       etheisen  926:        {
1.1.1.2   millert   927:                /*
                    928:                 * Expand a tab into spaces.
                    929:                 */
1.1       etheisen  930:                switch (bs_mode)
                    931:                {
                    932:                case BS_CONTROL:
                    933:                        goto do_control_char;
1.1.1.2   millert   934:                case BS_NORMAL:
1.1       etheisen  935:                case BS_SPECIAL:
1.1.1.3 ! shadchin  936:                        STORE_TAB(a, pos);
1.1       etheisen  937:                        break;
                    938:                }
1.1.1.3 ! shadchin  939:        } else if ((!utf_mode || is_ascii_char(ch)) && control_char((char)ch))
1.1       etheisen  940:        {
                    941:        do_control_char:
1.1.1.3 ! shadchin  942:                if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && IS_CSI_START(ch)))
1.1       etheisen  943:                {
                    944:                        /*
                    945:                         * Output as a normal character.
                    946:                         */
1.1.1.3 ! shadchin  947:                        STORE_CHAR(ch, AT_NORMAL, rep, pos);
1.1       etheisen  948:                } else
                    949:                {
1.1.1.3 ! shadchin  950:                        STORE_PRCHAR((char) ch, pos);
        !           951:                }
        !           952:        } else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(ch))
        !           953:        {
        !           954:                char *s;
1.1       etheisen  955:
1.1.1.3 ! shadchin  956:                s = prutfchar(ch);
1.1       etheisen  957:
1.1.1.3 ! shadchin  958:                if (column + (int) strlen(s) - 1 +
        !           959:                    pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width)
        !           960:                        return (1);
        !           961:
        !           962:                for ( ;  *s != 0;  s++)
        !           963:                        STORE_CHAR(*s, AT_BINARY, NULL, pos);
        !           964:        } else
1.1       etheisen  965:        {
1.1.1.3 ! shadchin  966:                STORE_CHAR(ch, a, rep, pos);
1.1       etheisen  967:        }
1.1.1.3 ! shadchin  968:        return (0);
        !           969: }
1.1       etheisen  970:
1.1.1.3 ! shadchin  971: /*
        !           972:  *
        !           973:  */
        !           974:        public int
        !           975: pflushmbc()
        !           976: {
        !           977:        int r = 0;
        !           978:
        !           979:        if (mbc_buf_len > 0)
        !           980:        {
        !           981:                /* Flush incomplete (truncated) sequence.  */
        !           982:                r = flush_mbc_buf(mbc_pos);
        !           983:                mbc_buf_len = 0;
        !           984:        }
        !           985:        return r;
1.1       etheisen  986: }
                    987:
                    988: /*
                    989:  * Terminate the line in the line buffer.
                    990:  */
                    991:        public void
1.1.1.3 ! shadchin  992: pdone(endline, forw)
1.1       etheisen  993:        int endline;
1.1.1.3 ! shadchin  994:        int forw;
1.1       etheisen  995: {
1.1.1.3 ! shadchin  996:        (void) pflushmbc();
        !           997:
1.1       etheisen  998:        if (pendc && (pendc != '\r' || !endline))
                    999:                /*
                   1000:                 * If we had a pending character, put it in the buffer.
                   1001:                 * But discard a pending CR if we are at end of line
                   1002:                 * (that is, discard the CR in a CR/LF sequence).
                   1003:                 */
1.1.1.3 ! shadchin 1004:                (void) do_append(pendc, NULL, pendpos);
1.1       etheisen 1005:
                   1006:        /*
1.1.1.2   millert  1007:         * Make sure we've shifted the line, if we need to.
                   1008:         */
                   1009:        if (cshift < hshift)
                   1010:                pshift(hshift - cshift);
                   1011:
1.1.1.3 ! shadchin 1012:        if (ctldisp == OPT_ONPLUS && is_ansi_end('m'))
        !          1013:        {
        !          1014:                /* Switch to normal attribute at end of line. */
        !          1015:                char *p = "\033[m";
        !          1016:                for ( ;  *p != '\0';  p++)
        !          1017:                {
        !          1018:                        linebuf[curr] = *p;
        !          1019:                        attr[curr++] = AT_ANSI;
        !          1020:                }
        !          1021:        }
        !          1022:
1.1.1.2   millert  1023:        /*
1.1       etheisen 1024:         * Add a newline if necessary,
                   1025:         * and append a '\0' to the end of the line.
1.1.1.3 ! shadchin 1026:         * We output a newline if we're not at the right edge of the screen,
        !          1027:         * or if the terminal doesn't auto wrap,
        !          1028:         * or if this is really the end of the line AND the terminal ignores
        !          1029:         * a newline at the right edge.
        !          1030:         * (In the last case we don't want to output a newline if the terminal
        !          1031:         * doesn't ignore it since that would produce an extra blank line.
        !          1032:         * But we do want to output a newline if the terminal ignores it in case
        !          1033:         * the next line is blank.  In that case the single newline output for
        !          1034:         * that blank line would be ignored!)
1.1       etheisen 1035:         */
1.1.1.3 ! shadchin 1036:        if (column < sc_width || !auto_wrap || (endline && ignaw) || ctldisp == OPT_ON)
1.1       etheisen 1037:        {
                   1038:                linebuf[curr] = '\n';
                   1039:                attr[curr] = AT_NORMAL;
                   1040:                curr++;
1.1.1.3 ! shadchin 1041:        }
        !          1042:        else if (ignaw && column >= sc_width && forw)
        !          1043:        {
        !          1044:                /*
        !          1045:                 * Terminals with "ignaw" don't wrap until they *really* need
        !          1046:                 * to, i.e. when the character *after* the last one to fit on a
        !          1047:                 * line is output. But they are too hard to deal with when they
        !          1048:                 * get in the state where a full screen width of characters
        !          1049:                 * have been output but the cursor is sitting on the right edge
        !          1050:                 * instead of at the start of the next line.
        !          1051:                 * So we nudge them into wrapping by outputting a space
        !          1052:                 * character plus a backspace.  But do this only if moving
        !          1053:                 * forward; if we're moving backward and drawing this line at
        !          1054:                 * the top of the screen, the space would overwrite the first
        !          1055:                 * char on the next line.  We don't need to do this "nudge"
        !          1056:                 * at the top of the screen anyway.
        !          1057:                 */
        !          1058:                linebuf[curr] = ' ';
        !          1059:                attr[curr++] = AT_NORMAL;
        !          1060:                linebuf[curr] = '\b';
        !          1061:                attr[curr++] = AT_NORMAL;
1.1       etheisen 1062:        }
                   1063:        linebuf[curr] = '\0';
                   1064:        attr[curr] = AT_NORMAL;
1.1.1.3 ! shadchin 1065: }
1.1.1.2   millert  1066:
1.1.1.3 ! shadchin 1067: /*
        !          1068:  *
        !          1069:  */
        !          1070:        public void
        !          1071: set_status_col(c)
        !          1072:        char c;
        !          1073: {
        !          1074:        linebuf[0] = c;
        !          1075:        attr[0] = AT_NORMAL|AT_HILITE;
1.1       etheisen 1076: }
                   1077:
                   1078: /*
                   1079:  * Get a character from the current line.
                   1080:  * Return the character as the function return value,
                   1081:  * and the character attribute in *ap.
                   1082:  */
                   1083:        public int
                   1084: gline(i, ap)
                   1085:        register int i;
                   1086:        register int *ap;
                   1087: {
                   1088:        if (is_null_line)
                   1089:        {
                   1090:                /*
                   1091:                 * If there is no current line, we pretend the line is
                   1092:                 * either "~" or "", depending on the "twiddle" flag.
                   1093:                 */
1.1.1.3 ! shadchin 1094:                if (twiddle)
        !          1095:                {
        !          1096:                        if (i == 0)
        !          1097:                        {
        !          1098:                                *ap = AT_BOLD;
        !          1099:                                return '~';
        !          1100:                        }
        !          1101:                        --i;
        !          1102:                }
        !          1103:                /* Make sure we're back to AT_NORMAL before the '\n'.  */
        !          1104:                *ap = AT_NORMAL;
        !          1105:                return i ? '\0' : '\n';
1.1       etheisen 1106:        }
                   1107:
                   1108:        *ap = attr[i];
1.1.1.3 ! shadchin 1109:        return (linebuf[i] & 0xFF);
1.1       etheisen 1110: }
                   1111:
                   1112: /*
                   1113:  * Indicate that there is no current line.
                   1114:  */
                   1115:        public void
                   1116: null_line()
                   1117: {
                   1118:        is_null_line = 1;
1.1.1.2   millert  1119:        cshift = 0;
1.1       etheisen 1120: }
                   1121:
                   1122: /*
                   1123:  * Analogous to forw_line(), but deals with "raw lines":
                   1124:  * lines which are not split for screen width.
                   1125:  * {{ This is supposed to be more efficient than forw_line(). }}
                   1126:  */
                   1127:        public POSITION
1.1.1.3 ! shadchin 1128: forw_raw_line(curr_pos, linep, line_lenp)
1.1       etheisen 1129:        POSITION curr_pos;
                   1130:        char **linep;
1.1.1.3 ! shadchin 1131:        int *line_lenp;
1.1       etheisen 1132: {
1.1.1.2   millert  1133:        register int n;
1.1       etheisen 1134:        register int c;
                   1135:        POSITION new_pos;
                   1136:
                   1137:        if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
                   1138:                (c = ch_forw_get()) == EOI)
                   1139:                return (NULL_POSITION);
                   1140:
1.1.1.2   millert  1141:        n = 0;
1.1       etheisen 1142:        for (;;)
                   1143:        {
1.1.1.3 ! shadchin 1144:                if (c == '\n' || c == EOI || ABORT_SIGS())
1.1       etheisen 1145:                {
                   1146:                        new_pos = ch_tell();
                   1147:                        break;
                   1148:                }
1.1.1.2   millert  1149:                if (n >= size_linebuf-1)
1.1       etheisen 1150:                {
1.1.1.2   millert  1151:                        if (expand_linebuf())
                   1152:                        {
                   1153:                                /*
                   1154:                                 * Overflowed the input buffer.
                   1155:                                 * Pretend the line ended here.
                   1156:                                 */
                   1157:                                new_pos = ch_tell() - 1;
                   1158:                                break;
                   1159:                        }
1.1       etheisen 1160:                }
1.1.1.2   millert  1161:                linebuf[n++] = c;
1.1       etheisen 1162:                c = ch_forw_get();
                   1163:        }
1.1.1.2   millert  1164:        linebuf[n] = '\0';
1.1       etheisen 1165:        if (linep != NULL)
                   1166:                *linep = linebuf;
1.1.1.3 ! shadchin 1167:        if (line_lenp != NULL)
        !          1168:                *line_lenp = n;
1.1       etheisen 1169:        return (new_pos);
                   1170: }
                   1171:
                   1172: /*
                   1173:  * Analogous to back_line(), but deals with "raw lines".
                   1174:  * {{ This is supposed to be more efficient than back_line(). }}
                   1175:  */
                   1176:        public POSITION
1.1.1.3 ! shadchin 1177: back_raw_line(curr_pos, linep, line_lenp)
1.1       etheisen 1178:        POSITION curr_pos;
                   1179:        char **linep;
1.1.1.3 ! shadchin 1180:        int *line_lenp;
1.1       etheisen 1181: {
1.1.1.2   millert  1182:        register int n;
1.1       etheisen 1183:        register int c;
                   1184:        POSITION new_pos;
                   1185:
                   1186:        if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() ||
                   1187:                ch_seek(curr_pos-1))
                   1188:                return (NULL_POSITION);
                   1189:
1.1.1.2   millert  1190:        n = size_linebuf;
                   1191:        linebuf[--n] = '\0';
1.1       etheisen 1192:        for (;;)
                   1193:        {
                   1194:                c = ch_back_get();
1.1.1.3 ! shadchin 1195:                if (c == '\n' || ABORT_SIGS())
1.1       etheisen 1196:                {
                   1197:                        /*
                   1198:                         * This is the newline ending the previous line.
                   1199:                         * We have hit the beginning of the line.
                   1200:                         */
                   1201:                        new_pos = ch_tell() + 1;
                   1202:                        break;
                   1203:                }
                   1204:                if (c == EOI)
                   1205:                {
                   1206:                        /*
                   1207:                         * We have hit the beginning of the file.
                   1208:                         * This must be the first line in the file.
                   1209:                         * This must, of course, be the beginning of the line.
                   1210:                         */
                   1211:                        new_pos = ch_zero();
                   1212:                        break;
                   1213:                }
1.1.1.2   millert  1214:                if (n <= 0)
1.1       etheisen 1215:                {
1.1.1.2   millert  1216:                        int old_size_linebuf = size_linebuf;
                   1217:                        char *fm;
                   1218:                        char *to;
                   1219:                        if (expand_linebuf())
                   1220:                        {
                   1221:                                /*
                   1222:                                 * Overflowed the input buffer.
                   1223:                                 * Pretend the line ended here.
                   1224:                                 */
                   1225:                                new_pos = ch_tell() + 1;
                   1226:                                break;
                   1227:                        }
1.1       etheisen 1228:                        /*
1.1.1.2   millert  1229:                         * Shift the data to the end of the new linebuf.
1.1       etheisen 1230:                         */
1.1.1.3 ! shadchin 1231:                        for (fm = linebuf + old_size_linebuf - 1,
        !          1232:                              to = linebuf + size_linebuf - 1;
1.1.1.2   millert  1233:                             fm >= linebuf;  fm--, to--)
                   1234:                                *to = *fm;
                   1235:                        n = size_linebuf - old_size_linebuf;
1.1       etheisen 1236:                }
1.1.1.2   millert  1237:                linebuf[--n] = c;
1.1       etheisen 1238:        }
                   1239:        if (linep != NULL)
1.1.1.2   millert  1240:                *linep = &linebuf[n];
1.1.1.3 ! shadchin 1241:        if (line_lenp != NULL)
        !          1242:                *line_lenp = size_linebuf - 1 - n;
1.1       etheisen 1243:        return (new_pos);
                   1244: }