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