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

Annotation of src/usr.bin/less/input.c, Revision 1.10

1.1       etheisen    1: /*
1.7       shadchin    2:  * Copyright (C) 1984-2012  Mark Nudelman
1.10    ! nicm        3:  * Modified for use with illumos by Garrett D'Amore.
        !             4:  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1       etheisen    5:  *
1.4       millert     6:  * You may distribute under the terms of either the GNU General Public
                      7:  * License or the Less License, as specified in the README file.
1.1       etheisen    8:  *
1.7       shadchin    9:  * For more information, see the README file.
1.8       nicm       10:  */
1.1       etheisen   11:
                     12: /*
1.8       nicm       13:  * High level routines dealing with getting lines of input
1.1       etheisen   14:  * from the file being viewed.
                     15:  *
                     16:  * When we speak of "lines" here, we mean PRINTABLE lines;
                     17:  * lines processed with respect to the screen width.
                     18:  * We use the term "raw line" to refer to lines simply
                     19:  * delimited by newlines; not processed with respect to screen width.
                     20:  */
                     21:
                     22: #include "less.h"
                     23:
                     24: extern int squeeze;
                     25: extern int chopline;
1.4       millert    26: extern int hshift;
                     27: extern int quit_if_one_screen;
1.6       millert    28: extern volatile sig_atomic_t sigs;
1.4       millert    29: extern int ignore_eoi;
1.5       shadchin   30: extern int status_col;
1.8       nicm       31: extern off_t start_attnpos;
                     32: extern off_t end_attnpos;
1.1       etheisen   33: extern int hilite_search;
                     34: extern int size_linebuf;
                     35:
                     36: /*
                     37:  * Get the next line.
                     38:  * A "current" position is passed and a "new" position is returned.
                     39:  * The current position is the position of the first character of
                     40:  * a line.  The new position is the position of the first character
                     41:  * of the NEXT line.  The line obtained is the line starting at curr_pos.
                     42:  */
1.8       nicm       43: off_t
                     44: forw_line(off_t curr_pos)
1.1       etheisen   45: {
1.8       nicm       46:        off_t base_pos;
                     47:        off_t new_pos;
1.9       tedu       48:        int c;
1.1       etheisen   49:        int blankline;
                     50:        int endline;
1.5       shadchin   51:        int backchars;
1.1       etheisen   52:
1.5       shadchin   53: get_forw_line:
1.8       nicm       54:        if (curr_pos == -1) {
1.1       etheisen   55:                null_line();
1.8       nicm       56:                return (-1);
1.1       etheisen   57:        }
1.5       shadchin   58:        if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.4       millert    59:                /*
                     60:                 * If we are ignoring EOI (command F), only prepare
                     61:                 * one line ahead, to avoid getting stuck waiting for
                     62:                 * slow data without displaying the data we already have.
                     63:                 * If we're not ignoring EOI, we *could* do the same, but
                     64:                 * for efficiency we prepare several lines ahead at once.
                     65:                 */
1.8       nicm       66:                prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
                     67:                    ignore_eoi ? 1 : -1);
                     68:        if (ch_seek(curr_pos)) {
1.1       etheisen   69:                null_line();
1.8       nicm       70:                return (-1);
1.1       etheisen   71:        }
                     72:
1.5       shadchin   73:        /*
                     74:         * Step back to the beginning of the line.
                     75:         */
                     76:        base_pos = curr_pos;
1.8       nicm       77:        for (;;) {
                     78:                if (ABORT_SIGS()) {
1.5       shadchin   79:                        null_line();
1.8       nicm       80:                        return (-1);
1.5       shadchin   81:                }
                     82:                c = ch_back_get();
                     83:                if (c == EOI)
                     84:                        break;
1.8       nicm       85:                if (c == '\n') {
1.5       shadchin   86:                        (void) ch_forw_get();
                     87:                        break;
                     88:                }
                     89:                --base_pos;
                     90:        }
                     91:
                     92:        /*
                     93:         * Read forward again to the position we should start at.
                     94:         */
1.8       nicm       95:        prewind();
1.5       shadchin   96:        plinenum(base_pos);
                     97:        (void) ch_seek(base_pos);
                     98:        new_pos = base_pos;
1.8       nicm       99:        while (new_pos < curr_pos) {
                    100:                if (ABORT_SIGS()) {
1.5       shadchin  101:                        null_line();
1.8       nicm      102:                        return (-1);
1.5       shadchin  103:                }
                    104:                c = ch_forw_get();
                    105:                backchars = pappend(c, new_pos);
                    106:                new_pos++;
1.8       nicm      107:                if (backchars > 0) {
1.5       shadchin  108:                        pshift_all();
                    109:                        new_pos -= backchars;
                    110:                        while (--backchars >= 0)
                    111:                                (void) ch_back_get();
                    112:                }
                    113:        }
                    114:        (void) pflushmbc();
                    115:        pshift_all();
1.1       etheisen  116:
1.5       shadchin  117:        /*
                    118:         * Read the first character to display.
                    119:         */
1.1       etheisen  120:        c = ch_forw_get();
1.8       nicm      121:        if (c == EOI) {
1.1       etheisen  122:                null_line();
1.8       nicm      123:                return (-1);
1.1       etheisen  124:        }
                    125:        blankline = (c == '\n' || c == '\r');
                    126:
1.5       shadchin  127:        /*
                    128:         * Read each character in the line and append to the line buffer.
                    129:         */
1.8       nicm      130:        for (;;) {
                    131:                if (ABORT_SIGS()) {
1.1       etheisen  132:                        null_line();
1.8       nicm      133:                        return (-1);
1.1       etheisen  134:                }
1.8       nicm      135:                if (c == '\n' || c == EOI) {
1.1       etheisen  136:                        /*
                    137:                         * End of the line.
                    138:                         */
1.5       shadchin  139:                        backchars = pflushmbc();
1.1       etheisen  140:                        new_pos = ch_tell();
1.8       nicm      141:                        if (backchars > 0 && !chopline && hshift == 0) {
1.5       shadchin  142:                                new_pos -= backchars + 1;
                    143:                                endline = FALSE;
                    144:                        } else
                    145:                                endline = TRUE;
1.1       etheisen  146:                        break;
                    147:                }
1.5       shadchin  148:                if (c != '\r')
                    149:                        blankline = 0;
1.1       etheisen  150:
                    151:                /*
                    152:                 * Append the char to the line and get the next char.
                    153:                 */
1.5       shadchin  154:                backchars = pappend(c, ch_tell()-1);
1.8       nicm      155:                if (backchars > 0) {
1.1       etheisen  156:                        /*
                    157:                         * The char won't fit in the line; the line
                    158:                         * is too long to print in the screen width.
                    159:                         * End the line here.
                    160:                         */
1.8       nicm      161:                        if (chopline || hshift > 0) {
                    162:                                do {
                    163:                                        if (ABORT_SIGS()) {
1.5       shadchin  164:                                                null_line();
1.8       nicm      165:                                                return (-1);
1.5       shadchin  166:                                        }
1.1       etheisen  167:                                        c = ch_forw_get();
                    168:                                } while (c != '\n' && c != EOI);
                    169:                                new_pos = ch_tell();
1.4       millert   170:                                endline = TRUE;
                    171:                                quit_if_one_screen = FALSE;
1.8       nicm      172:                        } else {
1.5       shadchin  173:                                new_pos = ch_tell() - backchars;
1.4       millert   174:                                endline = FALSE;
1.1       etheisen  175:                        }
                    176:                        break;
                    177:                }
                    178:                c = ch_forw_get();
                    179:        }
1.5       shadchin  180:
                    181:        pdone(endline, 1);
                    182:
1.8       nicm      183:        if (is_filtered(base_pos)) {
1.5       shadchin  184:                /*
                    185:                 * We don't want to display this line.
                    186:                 * Get the next line.
                    187:                 */
                    188:                curr_pos = new_pos;
                    189:                goto get_forw_line;
                    190:        }
                    191:
                    192:        if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
                    193:                set_status_col('*');
1.1       etheisen  194:
1.8       nicm      195:        if (squeeze && blankline) {
1.1       etheisen  196:                /*
                    197:                 * This line is blank.
                    198:                 * Skip down to the last contiguous blank line
                    199:                 * and pretend it is the one which we are returning.
                    200:                 */
                    201:                while ((c = ch_forw_get()) == '\n' || c == '\r')
1.8       nicm      202:                        if (ABORT_SIGS()) {
1.1       etheisen  203:                                null_line();
1.8       nicm      204:                                return (-1);
1.1       etheisen  205:                        }
                    206:                if (c != EOI)
                    207:                        (void) ch_back_get();
                    208:                new_pos = ch_tell();
                    209:        }
                    210:
                    211:        return (new_pos);
                    212: }
                    213:
                    214: /*
                    215:  * Get the previous line.
                    216:  * A "current" position is passed and a "new" position is returned.
                    217:  * The current position is the position of the first character of
                    218:  * a line.  The new position is the position of the first character
                    219:  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
                    220:  */
1.8       nicm      221: off_t
                    222: back_line(off_t curr_pos)
1.1       etheisen  223: {
1.8       nicm      224:        off_t new_pos, begin_new_pos, base_pos;
1.1       etheisen  225:        int c;
                    226:        int endline;
1.5       shadchin  227:        int backchars;
1.1       etheisen  228:
1.5       shadchin  229: get_back_line:
1.8       nicm      230:        if (curr_pos == -1 || curr_pos <= ch_zero()) {
1.1       etheisen  231:                null_line();
1.8       nicm      232:                return (-1);
1.1       etheisen  233:        }
1.5       shadchin  234:        if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.8       nicm      235:                prep_hilite((curr_pos < 3*size_linebuf) ?
                    236:                    0 : curr_pos - 3*size_linebuf, curr_pos, -1);
                    237:        if (ch_seek(curr_pos-1)) {
1.1       etheisen  238:                null_line();
1.8       nicm      239:                return (-1);
1.1       etheisen  240:        }
                    241:
1.8       nicm      242:        if (squeeze) {
1.1       etheisen  243:                /*
                    244:                 * Find out if the "current" line was blank.
                    245:                 */
1.8       nicm      246:                (void) ch_forw_get();   /* Skip the newline */
                    247:                c = ch_forw_get();      /* First char of "current" line */
                    248:                (void) ch_back_get();   /* Restore our position */
1.1       etheisen  249:                (void) ch_back_get();
                    250:
1.8       nicm      251:                if (c == '\n' || c == '\r') {
1.1       etheisen  252:                        /*
                    253:                         * The "current" line was blank.
                    254:                         * Skip over any preceding blank lines,
                    255:                         * since we skipped them in forw_line().
                    256:                         */
                    257:                        while ((c = ch_back_get()) == '\n' || c == '\r')
1.8       nicm      258:                                if (ABORT_SIGS()) {
1.1       etheisen  259:                                        null_line();
1.8       nicm      260:                                        return (-1);
1.1       etheisen  261:                                }
1.8       nicm      262:                        if (c == EOI) {
1.1       etheisen  263:                                null_line();
1.8       nicm      264:                                return (-1);
1.1       etheisen  265:                        }
                    266:                        (void) ch_forw_get();
                    267:                }
                    268:        }
                    269:
                    270:        /*
                    271:         * Scan backwards until we hit the beginning of the line.
                    272:         */
1.8       nicm      273:        for (;;) {
                    274:                if (ABORT_SIGS()) {
1.1       etheisen  275:                        null_line();
1.8       nicm      276:                        return (-1);
1.1       etheisen  277:                }
                    278:                c = ch_back_get();
1.8       nicm      279:                if (c == '\n') {
1.1       etheisen  280:                        /*
                    281:                         * This is the newline ending the previous line.
                    282:                         * We have hit the beginning of the line.
                    283:                         */
1.5       shadchin  284:                        base_pos = ch_tell() + 1;
1.1       etheisen  285:                        break;
                    286:                }
1.8       nicm      287:                if (c == EOI) {
1.1       etheisen  288:                        /*
                    289:                         * We have hit the beginning of the file.
                    290:                         * This must be the first line in the file.
                    291:                         * This must, of course, be the beginning of the line.
                    292:                         */
1.5       shadchin  293:                        base_pos = ch_tell();
1.1       etheisen  294:                        break;
                    295:                }
                    296:        }
                    297:
                    298:        /*
                    299:         * Now scan forwards from the beginning of this line.
                    300:         * We keep discarding "printable lines" (based on screen width)
                    301:         * until we reach the curr_pos.
                    302:         *
                    303:         * {{ This algorithm is pretty inefficient if the lines
1.8       nicm      304:         *    are much longer than the screen width,
1.1       etheisen  305:         *    but I don't know of any better way. }}
                    306:         */
1.5       shadchin  307:        new_pos = base_pos;
1.8       nicm      308:        if (ch_seek(new_pos)) {
1.1       etheisen  309:                null_line();
1.8       nicm      310:                return (-1);
1.1       etheisen  311:        }
1.4       millert   312:        endline = FALSE;
1.5       shadchin  313:        prewind();
                    314:        plinenum(new_pos);
1.8       nicm      315: loop:
1.1       etheisen  316:        begin_new_pos = new_pos;
                    317:        (void) ch_seek(new_pos);
                    318:
1.8       nicm      319:        do {
1.1       etheisen  320:                c = ch_forw_get();
1.8       nicm      321:                if (c == EOI || ABORT_SIGS()) {
1.1       etheisen  322:                        null_line();
1.8       nicm      323:                        return (-1);
1.1       etheisen  324:                }
                    325:                new_pos++;
1.8       nicm      326:                if (c == '\n') {
1.5       shadchin  327:                        backchars = pflushmbc();
1.8       nicm      328:                        if (backchars > 0 && !chopline && hshift == 0) {
1.5       shadchin  329:                                backchars++;
                    330:                                goto shift;
                    331:                        }
1.4       millert   332:                        endline = TRUE;
1.1       etheisen  333:                        break;
                    334:                }
1.5       shadchin  335:                backchars = pappend(c, ch_tell()-1);
1.8       nicm      336:                if (backchars > 0) {
1.1       etheisen  337:                        /*
                    338:                         * Got a full printable line, but we haven't
                    339:                         * reached our curr_pos yet.  Discard the line
                    340:                         * and start a new one.
                    341:                         */
1.8       nicm      342:                        if (chopline || hshift > 0) {
1.4       millert   343:                                endline = TRUE;
                    344:                                quit_if_one_screen = FALSE;
1.1       etheisen  345:                                break;
                    346:                        }
1.5       shadchin  347:                shift:
                    348:                        pshift_all();
1.8       nicm      349:                        while (backchars-- > 0) {
1.5       shadchin  350:                                (void) ch_back_get();
                    351:                                new_pos--;
                    352:                        }
1.1       etheisen  353:                        goto loop;
                    354:                }
                    355:        } while (new_pos < curr_pos);
                    356:
1.5       shadchin  357:        pdone(endline, 0);
                    358:
1.8       nicm      359:        if (is_filtered(base_pos)) {
1.5       shadchin  360:                /*
                    361:                 * We don't want to display this line.
                    362:                 * Get the previous line.
                    363:                 */
                    364:                curr_pos = begin_new_pos;
                    365:                goto get_back_line;
                    366:        }
                    367:
1.8       nicm      368:        if (status_col && curr_pos > 0 &&
                    369:            is_hilited(base_pos, curr_pos-1, 1, NULL))
1.5       shadchin  370:                set_status_col('*');
1.1       etheisen  371:
                    372:        return (begin_new_pos);
1.4       millert   373: }
                    374:
                    375: /*
                    376:  * Set attnpos.
                    377:  */
1.8       nicm      378: void
                    379: set_attnpos(off_t pos)
1.4       millert   380: {
                    381:        int c;
                    382:
1.8       nicm      383:        if (pos != -1) {
1.4       millert   384:                if (ch_seek(pos))
                    385:                        return;
1.8       nicm      386:                for (;;) {
1.4       millert   387:                        c = ch_forw_get();
                    388:                        if (c == EOI)
                    389:                                return;
                    390:                        if (c != '\n' && c != '\r')
                    391:                                break;
                    392:                        pos++;
                    393:                }
                    394:        }
                    395:        start_attnpos = pos;
1.8       nicm      396:        for (;;) {
1.4       millert   397:                c = ch_forw_get();
                    398:                pos++;
                    399:                if (c == EOI || c == '\n' || c == '\r')
                    400:                        break;
                    401:        }
                    402:        end_attnpos = pos;
1.1       etheisen  403: }