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

Annotation of src/usr.bin/more/prim.c, Revision 1.1.1.1

1.1       deraadt     1: /*
                      2:  * Copyright (c) 1988 Mark Nudleman
                      3:  * Copyright (c) 1988 Regents of the University of California.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
                     16:  *     This product includes software developed by the University of
                     17:  *     California, Berkeley and its contributors.
                     18:  * 4. Neither the name of the University nor the names of its contributors
                     19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
                     35: #ifndef lint
                     36: /* from: static char sccsid[] = "@(#)prim.c    5.8 (Berkeley) 6/1/90"; */
                     37: static char *rcsid = "$Id: prim.c,v 1.4 1994/12/24 17:17:12 cgd Exp $";
                     38: #endif /* not lint */
                     39:
                     40: /*
                     41:  * Primitives for displaying the file on the screen.
                     42:  */
                     43:
                     44: #include <sys/types.h>
                     45: #include <stdio.h>
                     46: #include <stdlib.h>
                     47: #include <ctype.h>
                     48: #include <less.h>
                     49:
                     50: #ifdef REGEX
                     51: #include <regex.h>
                     52: #endif
                     53:
                     54: int back_scroll = -1;
                     55: int hit_eof;           /* keeps track of how many times we hit end of file */
                     56: int screen_trashed;
                     57:
                     58: static int squished;
                     59:
                     60: extern int sigs;
                     61: extern int top_scroll;
                     62: extern int sc_width, sc_height;
                     63: extern int caseless;
                     64: extern int linenums;
                     65: extern int tagoption;
                     66: extern char *line;
                     67:
                     68: off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line();
                     69: off_t ch_length(), ch_tell();
                     70:
                     71: /*
                     72:  * Check to see if the end of file is currently "displayed".
                     73:  */
                     74: eof_check()
                     75: {
                     76:        off_t pos;
                     77:
                     78:        if (sigs)
                     79:                return;
                     80:        /*
                     81:         * If the bottom line is empty, we are at EOF.
                     82:         * If the bottom line ends at the file length,
                     83:         * we must be just at EOF.
                     84:         */
                     85:        pos = position(BOTTOM_PLUS_ONE);
                     86:        if (pos == NULL_POSITION || pos == ch_length())
                     87:                hit_eof++;
                     88: }
                     89:
                     90: /*
                     91:  * If the screen is "squished", repaint it.
                     92:  * "Squished" means the first displayed line is not at the top
                     93:  * of the screen; this can happen when we display a short file
                     94:  * for the first time.
                     95:  */
                     96: squish_check()
                     97: {
                     98:        if (squished) {
                     99:                squished = 0;
                    100:                repaint();
                    101:        }
                    102: }
                    103:
                    104: /*
                    105:  * Display n lines, scrolling forward, starting at position pos in the
                    106:  * input file.  "only_last" means display only the last screenful if
                    107:  * n > screen size.
                    108:  */
                    109: forw(n, pos, only_last)
                    110:        register int n;
                    111:        off_t pos;
                    112:        int only_last;
                    113: {
                    114:        extern int short_file;
                    115:        static int first_time = 1;
                    116:        int eof = 0, do_repaint;
                    117:
                    118:        squish_check();
                    119:
                    120:        /*
                    121:         * do_repaint tells us not to display anything till the end,
                    122:         * then just repaint the entire screen.
                    123:         */
                    124:        do_repaint = (only_last && n > sc_height-1);
                    125:
                    126:        if (!do_repaint) {
                    127:                if (top_scroll && n >= sc_height - 1) {
                    128:                        /*
                    129:                         * Start a new screen.
                    130:                         * {{ This is not really desirable if we happen
                    131:                         *    to hit eof in the middle of this screen,
                    132:                         *    but we don't yet know if that will happen. }}
                    133:                         */
                    134:                        clear();
                    135:                        home();
                    136:                } else {
                    137:                        lower_left();
                    138:                        clear_eol();
                    139:                }
                    140:
                    141:                /*
                    142:                 * This is not contiguous with what is currently displayed.
                    143:                 * Clear the screen image (position table) and start a new
                    144:                 * screen.
                    145:                 */
                    146:                if (pos != position(BOTTOM_PLUS_ONE)) {
                    147:                        pos_clear();
                    148:                        add_forw_pos(pos);
                    149:                        if (top_scroll) {
                    150:                                clear();
                    151:                                home();
                    152:                        } else if (!first_time)
                    153:                                putstr("...skipping...\n");
                    154:                }
                    155:        }
                    156:
                    157:        for (short_file = 0; --n >= 0;) {
                    158:                /*
                    159:                 * Read the next line of input.
                    160:                 */
                    161:                pos = forw_line(pos);
                    162:                if (pos == NULL_POSITION) {
                    163:                        /*
                    164:                         * end of file; copy the table if the file was
                    165:                         * too small for an entire screen.
                    166:                         */
                    167:                        eof = 1;
                    168:                        if (position(TOP) == NULL_POSITION) {
                    169:                                copytable();
                    170:                                if (!position(TOP))
                    171:                                        short_file = 1;
                    172:                        }
                    173:                        break;
                    174:                }
                    175:                /*
                    176:                 * Add the position of the next line to the position table.
                    177:                 * Display the current line on the screen.
                    178:                 */
                    179:                add_forw_pos(pos);
                    180:                if (do_repaint)
                    181:                        continue;
                    182:                /*
                    183:                 * If this is the first screen displayed and we hit an early
                    184:                 * EOF (i.e. before the requested number of lines), we
                    185:                 * "squish" the display down at the bottom of the screen.
                    186:                 * But don't do this if a -t option was given; it can cause
                    187:                 * us to start the display after the beginning of the file,
                    188:                 * and it is not appropriate to squish in that case.
                    189:                 */
                    190:                if (first_time && line == NULL && !top_scroll && !tagoption) {
                    191:                        squished = 1;
                    192:                        continue;
                    193:                }
                    194:                put_line();
                    195:        }
                    196:
                    197:        if (eof && !sigs)
                    198:                hit_eof++;
                    199:        else
                    200:                eof_check();
                    201:        if (do_repaint)
                    202:                repaint();
                    203:        first_time = 0;
                    204:        (void) currline(BOTTOM);
                    205: }
                    206:
                    207: /*
                    208:  * Display n lines, scrolling backward.
                    209:  */
                    210: back(n, pos, only_last)
                    211:        register int n;
                    212:        off_t pos;
                    213:        int only_last;
                    214: {
                    215:        int do_repaint;
                    216:
                    217:        squish_check();
                    218:        do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
                    219:        hit_eof = 0;
                    220:        while (--n >= 0)
                    221:        {
                    222:                /*
                    223:                 * Get the previous line of input.
                    224:                 */
                    225:                pos = back_line(pos);
                    226:                if (pos == NULL_POSITION)
                    227:                        break;
                    228:                /*
                    229:                 * Add the position of the previous line to the position table.
                    230:                 * Display the line on the screen.
                    231:                 */
                    232:                add_back_pos(pos);
                    233:                if (!do_repaint)
                    234:                {
                    235:                        home();
                    236:                        add_line();
                    237:                        put_line();
                    238:                }
                    239:        }
                    240:
                    241:        eof_check();
                    242:        if (do_repaint)
                    243:                repaint();
                    244:        (void) currline(BOTTOM);
                    245: }
                    246:
                    247: /*
                    248:  * Display n more lines, forward.
                    249:  * Start just after the line currently displayed at the bottom of the screen.
                    250:  */
                    251: forward(n, only_last)
                    252:        int n;
                    253:        int only_last;
                    254: {
                    255:        off_t pos;
                    256:
                    257:        if (hit_eof) {
                    258:                /*
                    259:                 * If we're trying to go forward from end-of-file,
                    260:                 * go on to the next file.
                    261:                 */
                    262:                next_file(1);
                    263:                return;
                    264:        }
                    265:
                    266:        pos = position(BOTTOM_PLUS_ONE);
                    267:        if (pos == NULL_POSITION)
                    268:        {
                    269:                hit_eof++;
                    270:                return;
                    271:        }
                    272:        forw(n, pos, only_last);
                    273: }
                    274:
                    275: /*
                    276:  * Display n more lines, backward.
                    277:  * Start just before the line currently displayed at the top of the screen.
                    278:  */
                    279: backward(n, only_last)
                    280:        int n;
                    281:        int only_last;
                    282: {
                    283:        off_t pos;
                    284:
                    285:        pos = position(TOP);
                    286:        /*
                    287:         * This will almost never happen, because the top line is almost
                    288:         * never empty.
                    289:         */
                    290:        if (pos == NULL_POSITION)
                    291:                return;
                    292:        back(n, pos, only_last);
                    293: }
                    294:
                    295: /*
                    296:  * Repaint the screen, starting from a specified position.
                    297:  */
                    298: prepaint(pos)
                    299:        off_t pos;
                    300: {
                    301:        hit_eof = 0;
                    302:        forw(sc_height-1, pos, 0);
                    303:        screen_trashed = 0;
                    304: }
                    305:
                    306: /*
                    307:  * Repaint the screen.
                    308:  */
                    309: repaint()
                    310: {
                    311:        /*
                    312:         * Start at the line currently at the top of the screen
                    313:         * and redisplay the screen.
                    314:         */
                    315:        prepaint(position(TOP));
                    316: }
                    317:
                    318: /*
                    319:  * Jump to the end of the file.
                    320:  * It is more convenient to paint the screen backward,
                    321:  * from the end of the file toward the beginning.
                    322:  */
                    323: jump_forw()
                    324: {
                    325:        off_t pos;
                    326:
                    327:        if (ch_end_seek())
                    328:        {
                    329:                error("Cannot seek to end of file");
                    330:                return;
                    331:        }
                    332:        lastmark();
                    333:        pos = ch_tell();
                    334:        clear();
                    335:        pos_clear();
                    336:        add_back_pos(pos);
                    337:        back(sc_height - 1, pos, 0);
                    338: }
                    339:
                    340: /*
                    341:  * Jump to line n in the file.
                    342:  */
                    343: jump_back(n)
                    344:        register int n;
                    345: {
                    346:        register int c, nlines;
                    347:
                    348:        /*
                    349:         * This is done the slow way, by starting at the beginning
                    350:         * of the file and counting newlines.
                    351:         *
                    352:         * {{ Now that we have line numbering (in linenum.c),
                    353:         *    we could improve on this by starting at the
                    354:         *    nearest known line rather than at the beginning. }}
                    355:         */
                    356:        if (ch_seek((off_t)0)) {
                    357:                /*
                    358:                 * Probably a pipe with beginning of file no longer buffered.
                    359:                 * If he wants to go to line 1, we do the best we can,
                    360:                 * by going to the first line which is still buffered.
                    361:                 */
                    362:                if (n <= 1 && ch_beg_seek() == 0)
                    363:                        jump_loc(ch_tell());
                    364:                error("Cannot get to beginning of file");
                    365:                return;
                    366:        }
                    367:
                    368:        /*
                    369:         * Start counting lines.
                    370:         */
                    371:        for (nlines = 1;  nlines < n;  nlines++)
                    372:                while ((c = ch_forw_get()) != '\n')
                    373:                        if (c == EOI) {
                    374:                                char message[40];
                    375:                                (void)sprintf(message, "File has only %d lines",
                    376:                                    nlines - 1);
                    377:                                error(message);
                    378:                                return;
                    379:                        }
                    380:        jump_loc(ch_tell());
                    381: }
                    382:
                    383: /*
                    384:  * Jump to a specified percentage into the file.
                    385:  * This is a poor compensation for not being able to
                    386:  * quickly jump to a specific line number.
                    387:  */
                    388: jump_percent(percent)
                    389:        int percent;
                    390: {
                    391:        off_t pos, len, ch_length();
                    392:        register int c;
                    393:
                    394:        /*
                    395:         * Determine the position in the file
                    396:         * (the specified percentage of the file's length).
                    397:         */
                    398:        if ((len = ch_length()) == NULL_POSITION)
                    399:        {
                    400:                error("Don't know length of file");
                    401:                return;
                    402:        }
                    403:        pos = (percent * len) / 100;
                    404:
                    405:        /*
                    406:         * Back up to the beginning of the line.
                    407:         */
                    408:        if (ch_seek(pos) == 0)
                    409:        {
                    410:                while ((c = ch_back_get()) != '\n' && c != EOI)
                    411:                        ;
                    412:                if (c == '\n')
                    413:                        (void) ch_forw_get();
                    414:                pos = ch_tell();
                    415:        }
                    416:        jump_loc(pos);
                    417: }
                    418:
                    419: /*
                    420:  * Jump to a specified position in the file.
                    421:  */
                    422: jump_loc(pos)
                    423:        off_t pos;
                    424: {
                    425:        register int nline;
                    426:        off_t tpos;
                    427:
                    428:        if ((nline = onscreen(pos)) >= 0) {
                    429:                /*
                    430:                 * The line is currently displayed.
                    431:                 * Just scroll there.
                    432:                 */
                    433:                forw(nline, position(BOTTOM_PLUS_ONE), 0);
                    434:                return;
                    435:        }
                    436:
                    437:        /*
                    438:         * Line is not on screen.
                    439:         * Seek to the desired location.
                    440:         */
                    441:        if (ch_seek(pos)) {
                    442:                error("Cannot seek to that position");
                    443:                return;
                    444:        }
                    445:
                    446:        /*
                    447:         * See if the desired line is BEFORE the currently displayed screen.
                    448:         * If so, then move forward far enough so the line we're on will be
                    449:         * at the bottom of the screen, in order to be able to call back()
                    450:         * to make the screen scroll backwards & put the line at the top of
                    451:         * the screen.
                    452:         * {{ This seems inefficient, but it's not so bad,
                    453:         *    since we can never move forward more than a
                    454:         *    screenful before we stop to redraw the screen. }}
                    455:         */
                    456:        tpos = position(TOP);
                    457:        if (tpos != NULL_POSITION && pos < tpos) {
                    458:                off_t npos = pos;
                    459:                /*
                    460:                 * Note that we can't forw_line() past tpos here,
                    461:                 * so there should be no EOI at this stage.
                    462:                 */
                    463:                for (nline = 0;  npos < tpos && nline < sc_height - 1;  nline++)
                    464:                        npos = forw_line(npos);
                    465:
                    466:                if (npos < tpos) {
                    467:                        /*
                    468:                         * More than a screenful back.
                    469:                         */
                    470:                        lastmark();
                    471:                        clear();
                    472:                        pos_clear();
                    473:                        add_back_pos(npos);
                    474:                }
                    475:
                    476:                /*
                    477:                 * Note that back() will repaint() if nline > back_scroll.
                    478:                 */
                    479:                back(nline, npos, 0);
                    480:                return;
                    481:        }
                    482:        /*
                    483:         * Remember where we were; clear and paint the screen.
                    484:         */
                    485:        lastmark();
                    486:        prepaint(pos);
                    487: }
                    488:
                    489: /*
                    490:  * The table of marks.
                    491:  * A mark is simply a position in the file.
                    492:  */
                    493: #define        NMARKS          (27)            /* 26 for a-z plus one for quote */
                    494: #define        LASTMARK        (NMARKS-1)      /* For quote */
                    495: static off_t marks[NMARKS];
                    496:
                    497: /*
                    498:  * Initialize the mark table to show no marks are set.
                    499:  */
                    500: init_mark()
                    501: {
                    502:        int i;
                    503:
                    504:        for (i = 0;  i < NMARKS;  i++)
                    505:                marks[i] = NULL_POSITION;
                    506: }
                    507:
                    508: /*
                    509:  * See if a mark letter is valid (between a and z).
                    510:  */
                    511:        static int
                    512: badmark(c)
                    513:        int c;
                    514: {
                    515:        if (c < 'a' || c > 'z')
                    516:        {
                    517:                error("Choose a letter between 'a' and 'z'");
                    518:                return (1);
                    519:        }
                    520:        return (0);
                    521: }
                    522:
                    523: /*
                    524:  * Set a mark.
                    525:  */
                    526: setmark(c)
                    527:        int c;
                    528: {
                    529:        if (badmark(c))
                    530:                return;
                    531:        marks[c-'a'] = position(TOP);
                    532: }
                    533:
                    534: lastmark()
                    535: {
                    536:        marks[LASTMARK] = position(TOP);
                    537: }
                    538:
                    539: /*
                    540:  * Go to a previously set mark.
                    541:  */
                    542: gomark(c)
                    543:        int c;
                    544: {
                    545:        off_t pos;
                    546:
                    547:        if (c == '\'') {
                    548:                pos = marks[LASTMARK];
                    549:                if (pos == NULL_POSITION)
                    550:                        pos = 0;
                    551:        }
                    552:        else {
                    553:                if (badmark(c))
                    554:                        return;
                    555:                pos = marks[c-'a'];
                    556:                if (pos == NULL_POSITION) {
                    557:                        error("mark not set");
                    558:                        return;
                    559:                }
                    560:        }
                    561:        jump_loc(pos);
                    562: }
                    563:
                    564: /*
                    565:  * Get the backwards scroll limit.
                    566:  * Must call this function instead of just using the value of
                    567:  * back_scroll, because the default case depends on sc_height and
                    568:  * top_scroll, as well as back_scroll.
                    569:  */
                    570: get_back_scroll()
                    571: {
                    572:        if (back_scroll >= 0)
                    573:                return (back_scroll);
                    574:        if (top_scroll)
                    575:                return (sc_height - 2);
                    576:        return (sc_height - 1);
                    577: }
                    578:
                    579: /*
                    580:  * Search for the n-th occurence of a specified pattern,
                    581:  * either forward or backward.
                    582:  */
                    583: search(search_forward, pattern, n, wantmatch)
                    584:        register int search_forward;
                    585:        register char *pattern;
                    586:        register int n;
                    587:        int wantmatch;
                    588: {
                    589:        off_t pos, linepos;
                    590:        register char *p;
                    591:        register char *q;
                    592:        int linenum;
                    593:        int linematch;
                    594: #ifdef REGEX
                    595:        static regex_t *cpattern = NULL;
                    596: #else
                    597: #ifdef RECOMP
                    598:        char *re_comp();
                    599:        char *errmsg;
                    600: #else
                    601: #ifdef REGCMP
                    602:        char *regcmp();
                    603:        static char *cpattern = NULL;
                    604: #else
                    605:        static char lpbuf[100];
                    606:        static char *last_pattern = NULL;
                    607:        char *strcpy();
                    608: #endif
                    609: #endif
                    610: #endif /*REGEX */
                    611:        /*
                    612:         * For a caseless search, convert any uppercase in the pattern to
                    613:         * lowercase.
                    614:         */
                    615:        if (caseless && pattern != NULL)
                    616:                for (p = pattern;  *p;  p++)
                    617:                        if (isupper(*p))
                    618:                                *p = tolower(*p);
                    619: #ifdef REGEX
                    620:        if (pattern == NULL || *pattern == '\0')
                    621:        {
                    622:                /*
                    623:                 * A null pattern means use the previous pattern.
                    624:                 * The compiled previous pattern is in cpattern, so just use it.
                    625:                 */
                    626:                if (cpattern == NULL)
                    627:                {
                    628:                        error("No previous regular expression");
                    629:                        return(0);
                    630:                }
                    631:        } else
                    632:        {
                    633:                /*
                    634:                 * Otherwise compile the given pattern.
                    635:                 */
                    636:                if (cpattern == NULL
                    637:                 && (cpattern = (regex_t *) malloc(sizeof(regex_t))) == NULL) {
                    638:                        error("cannot allocate memory");
                    639:                        quit();
                    640:                }
                    641:                else
                    642:                        regfree(cpattern);
                    643:                if (regcomp(cpattern, pattern, 0))
                    644:                {
                    645:                        error("Invalid pattern");
                    646:                        return(0);
                    647:                }
                    648:        }
                    649: #else
                    650: #ifdef RECOMP
                    651:
                    652:        /*
                    653:         * (re_comp handles a null pattern internally,
                    654:         *  so there is no need to check for a null pattern here.)
                    655:         */
                    656:        if ((errmsg = re_comp(pattern)) != NULL)
                    657:        {
                    658:                error(errmsg);
                    659:                return(0);
                    660:        }
                    661: #else
                    662: #ifdef REGCMP
                    663:        if (pattern == NULL || *pattern == '\0')
                    664:        {
                    665:                /*
                    666:                 * A null pattern means use the previous pattern.
                    667:                 * The compiled previous pattern is in cpattern, so just use it.
                    668:                 */
                    669:                if (cpattern == NULL)
                    670:                {
                    671:                        error("No previous regular expression");
                    672:                        return(0);
                    673:                }
                    674:        } else
                    675:        {
                    676:                /*
                    677:                 * Otherwise compile the given pattern.
                    678:                 */
                    679:                char *s;
                    680:                if ((s = regcmp(pattern, 0)) == NULL)
                    681:                {
                    682:                        error("Invalid pattern");
                    683:                        return(0);
                    684:                }
                    685:                if (cpattern != NULL)
                    686:                        free(cpattern);
                    687:                cpattern = s;
                    688:        }
                    689: #else
                    690:        if (pattern == NULL || *pattern == '\0')
                    691:        {
                    692:                /*
                    693:                 * Null pattern means use the previous pattern.
                    694:                 */
                    695:                if (last_pattern == NULL)
                    696:                {
                    697:                        error("No previous regular expression");
                    698:                        return(0);
                    699:                }
                    700:                pattern = last_pattern;
                    701:        } else
                    702:        {
                    703:                (void)strcpy(lpbuf, pattern);
                    704:                last_pattern = lpbuf;
                    705:        }
                    706: #endif
                    707: #endif
                    708: #endif /* REGEX */
                    709:
                    710:        /*
                    711:         * Figure out where to start the search.
                    712:         */
                    713:
                    714:        if (position(TOP) == NULL_POSITION) {
                    715:                /*
                    716:                 * Nothing is currently displayed.  Start at the beginning
                    717:                 * of the file.  (This case is mainly for searches from the
                    718:                 * command line.
                    719:                 */
                    720:                pos = (off_t)0;
                    721:        } else if (!search_forward) {
                    722:                /*
                    723:                 * Backward search: start just before the top line
                    724:                 * displayed on the screen.
                    725:                 */
                    726:                pos = position(TOP);
                    727:        } else {
                    728:                /*
                    729:                 * Start at the second screen line displayed on the screen.
                    730:                 */
                    731:                pos = position(TOP_PLUS_ONE);
                    732:        }
                    733:
                    734:        if (pos == NULL_POSITION)
                    735:        {
                    736:                /*
                    737:                 * Can't find anyplace to start searching from.
                    738:                 */
                    739:                error("Nothing to search");
                    740:                return(0);
                    741:        }
                    742:
                    743:        linenum = find_linenum(pos);
                    744:        for (;;)
                    745:        {
                    746:                /*
                    747:                 * Get lines until we find a matching one or
                    748:                 * until we hit end-of-file (or beginning-of-file
                    749:                 * if we're going backwards).
                    750:                 */
                    751:                if (sigs)
                    752:                        /*
                    753:                         * A signal aborts the search.
                    754:                         */
                    755:                        return(0);
                    756:
                    757:                if (search_forward)
                    758:                {
                    759:                        /*
                    760:                         * Read the next line, and save the
                    761:                         * starting position of that line in linepos.
                    762:                         */
                    763:                        linepos = pos;
                    764:                        pos = forw_raw_line(pos);
                    765:                        if (linenum != 0)
                    766:                                linenum++;
                    767:                } else
                    768:                {
                    769:                        /*
                    770:                         * Read the previous line and save the
                    771:                         * starting position of that line in linepos.
                    772:                         */
                    773:                        pos = back_raw_line(pos);
                    774:                        linepos = pos;
                    775:                        if (linenum != 0)
                    776:                                linenum--;
                    777:                }
                    778:
                    779:                if (pos == NULL_POSITION)
                    780:                {
                    781:                        /*
                    782:                         * We hit EOF/BOF without a match.
                    783:                         */
                    784:                        error("Pattern not found");
                    785:                        return(0);
                    786:                }
                    787:
                    788:                /*
                    789:                 * If we're using line numbers, we might as well
                    790:                 * remember the information we have now (the position
                    791:                 * and line number of the current line).
                    792:                 */
                    793:                if (linenums)
                    794:                        add_lnum(linenum, pos);
                    795:
                    796:                /*
                    797:                 * If this is a caseless search, convert uppercase in the
                    798:                 * input line to lowercase.
                    799:                 */
                    800:                if (caseless)
                    801:                        for (p = q = line;  *p;  p++, q++)
                    802:                                *q = isupper(*p) ? tolower(*p) : *p;
                    803:
                    804:                /*
                    805:                 * Remove any backspaces along with the preceeding char.
                    806:                 * This allows us to match text which is underlined or
                    807:                 * overstruck.
                    808:                 */
                    809:                for (p = q = line;  *p;  p++, q++)
                    810:                        if (q > line && *p == '\b')
                    811:                                /* Delete BS and preceeding char. */
                    812:                                q -= 2;
                    813:                        else
                    814:                                /* Otherwise, just copy. */
                    815:                                *q = *p;
                    816:
                    817:                /*
                    818:                 * Test the next line to see if we have a match.
                    819:                 * This is done in a variety of ways, depending
                    820:                 * on what pattern matching functions are available.
                    821:                 */
                    822: #ifdef REGEX
                    823:                linematch = !regexec(cpattern, line, 0, NULL, 0);
                    824: #else
                    825: #ifdef REGCMP
                    826:                linematch = (regex(cpattern, line) != NULL);
                    827: #else
                    828: #ifdef RECOMP
                    829:                linematch = (re_exec(line) == 1);
                    830: #else
                    831:                linematch = match(pattern, line);
                    832: #endif
                    833: #endif
                    834: #endif /* REGEX */
                    835:                /*
                    836:                 * We are successful if wantmatch and linematch are
                    837:                 * both true (want a match and got it),
                    838:                 * or both false (want a non-match and got it).
                    839:                 */
                    840:                if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
                    841:                      --n <= 0)
                    842:                        /*
                    843:                         * Found the line.
                    844:                         */
                    845:                        break;
                    846:        }
                    847:        jump_loc(linepos);
                    848:        return(1);
                    849: }
                    850:
                    851: #if !defined(REGCMP) && !defined(RECOMP) && !defined(REGEX)
                    852: /*
                    853:  * We have neither regcmp() nor re_comp().
                    854:  * We use this function to do simple pattern matching.
                    855:  * It supports no metacharacters like *, etc.
                    856:  */
                    857: static
                    858: match(pattern, buf)
                    859:        char *pattern, *buf;
                    860: {
                    861:        register char *pp, *lp;
                    862:
                    863:        for ( ;  *buf != '\0';  buf++)
                    864:        {
                    865:                for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
                    866:                        if (*pp == '\0' || *lp == '\0')
                    867:                                break;
                    868:                if (*pp == '\0')
                    869:                        return (1);
                    870:        }
                    871:        return (0);
                    872: }
                    873: #endif