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

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