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

Annotation of src/usr.bin/more/line.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[] = "@(#)line.c    5.5 (Berkeley) 7/24/91"; */
        !            37: static char *rcsid = "$Id: line.c,v 1.2 1993/11/09 05:09:49 cgd Exp $";
        !            38: #endif /* not lint */
        !            39:
        !            40: /*
        !            41:  * Routines to manipulate the "line buffer".
        !            42:  * The line buffer holds a line of output as it is being built
        !            43:  * in preparation for output to the screen.
        !            44:  * We keep track of the PRINTABLE length of the line as it is being built.
        !            45:  */
        !            46:
        !            47: #include <sys/types.h>
        !            48: #include <ctype.h>
        !            49: #include <less.h>
        !            50:
        !            51: static char linebuf[1024];     /* Buffer which holds the current output line */
        !            52: static char *curr;             /* Pointer into linebuf */
        !            53: static int column;             /* Printable length, accounting for
        !            54:                                   backspaces, etc. */
        !            55: /*
        !            56:  * A ridiculously complex state machine takes care of backspaces.  The
        !            57:  * complexity arises from the attempt to deal with all cases, especially
        !            58:  * involving long lines with underlining, boldfacing or whatever.  There
        !            59:  * are still some cases which will break it.
        !            60:  *
        !            61:  * There are four states:
        !            62:  *     LN_NORMAL is the normal state (not in underline mode).
        !            63:  *     LN_UNDERLINE means we are in underline mode.  We expect to get
        !            64:  *             either a sequence like "_\bX" or "X\b_" to continue
        !            65:  *             underline mode, or anything else to end underline mode.
        !            66:  *     LN_BOLDFACE means we are in boldface mode.  We expect to get sequences
        !            67:  *             like "X\bX\b...X\bX" to continue boldface mode, or anything
        !            68:  *             else to end boldface mode.
        !            69:  *     LN_UL_X means we are one character after LN_UNDERLINE
        !            70:  *             (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
        !            71:  *     LN_UL_XB means we are one character after LN_UL_X
        !            72:  *             (we have gotten the backspace in "_\bX" or "X\b_";
        !            73:  *             we expect one more ordinary character,
        !            74:  *             which will put us back in state LN_UNDERLINE).
        !            75:  *     LN_BO_X means we are one character after LN_BOLDFACE
        !            76:  *             (we have gotten the 'X' in "X\bX").
        !            77:  *     LN_BO_XB means we are one character after LN_BO_X
        !            78:  *             (we have gotten the backspace in "X\bX";
        !            79:  *             we expect one more 'X' which will put us back
        !            80:  *             in LN_BOLDFACE).
        !            81:  */
        !            82: static int ln_state;           /* Currently in normal/underline/bold/etc mode? */
        !            83: #define        LN_NORMAL       0       /* Not in underline, boldface or whatever mode */
        !            84: #define        LN_UNDERLINE    1       /* In underline, need next char */
        !            85: #define        LN_UL_X         2       /* In underline, got char, need \b */
        !            86: #define        LN_UL_XB        3       /* In underline, got char & \b, need one more */
        !            87: #define        LN_BOLDFACE     4       /* In boldface, need next char */
        !            88: #define        LN_BO_X         5       /* In boldface, got char, need \b */
        !            89: #define        LN_BO_XB        6       /* In boldface, got char & \b, need same char */
        !            90:
        !            91: char *line;                    /* Pointer to the current line.
        !            92:                                   Usually points to linebuf. */
        !            93:
        !            94: extern int bs_mode;
        !            95: extern int tabstop;
        !            96: extern int bo_width, be_width;
        !            97: extern int ul_width, ue_width;
        !            98: extern int sc_width, sc_height;
        !            99:
        !           100: /*
        !           101:  * Rewind the line buffer.
        !           102:  */
        !           103: prewind()
        !           104: {
        !           105:        line = curr = linebuf;
        !           106:        ln_state = LN_NORMAL;
        !           107:        column = 0;
        !           108: }
        !           109:
        !           110: /*
        !           111:  * Append a character to the line buffer.
        !           112:  * Expand tabs into spaces, handle underlining, boldfacing, etc.
        !           113:  * Returns 0 if ok, 1 if couldn't fit in buffer.
        !           114:  */
        !           115: #define        NEW_COLUMN(addon) \
        !           116:        if (column + addon + (ln_state ? ue_width : 0) > sc_width) \
        !           117:                return(1); \
        !           118:        else \
        !           119:                column += addon
        !           120:
        !           121: pappend(c)
        !           122:        int c;
        !           123: {
        !           124:        if (c == '\0') {
        !           125:                /*
        !           126:                 * Terminate any special modes, if necessary.
        !           127:                 * Append a '\0' to the end of the line.
        !           128:                 */
        !           129:                switch (ln_state) {
        !           130:                case LN_UL_X:
        !           131:                        curr[0] = curr[-1];
        !           132:                        curr[-1] = UE_CHAR;
        !           133:                        curr++;
        !           134:                        break;
        !           135:                case LN_BO_X:
        !           136:                        curr[0] = curr[-1];
        !           137:                        curr[-1] = BE_CHAR;
        !           138:                        curr++;
        !           139:                        break;
        !           140:                case LN_UL_XB:
        !           141:                case LN_UNDERLINE:
        !           142:                        *curr++ = UE_CHAR;
        !           143:                        break;
        !           144:                case LN_BO_XB:
        !           145:                case LN_BOLDFACE:
        !           146:                        *curr++ = BE_CHAR;
        !           147:                        break;
        !           148:                }
        !           149:                ln_state = LN_NORMAL;
        !           150:                *curr = '\0';
        !           151:                return(0);
        !           152:        }
        !           153:
        !           154:        if (curr > linebuf + sizeof(linebuf) - 12)
        !           155:                /*
        !           156:                 * Almost out of room in the line buffer.
        !           157:                 * Don't take any chances.
        !           158:                 * {{ Linebuf is supposed to be big enough that this
        !           159:                 *    will never happen, but may need to be made
        !           160:                 *    bigger for wide screens or lots of backspaces. }}
        !           161:                 */
        !           162:                return(1);
        !           163:
        !           164:        if (!bs_mode) {
        !           165:                /*
        !           166:                 * Advance the state machine.
        !           167:                 */
        !           168:                switch (ln_state) {
        !           169:                case LN_NORMAL:
        !           170:                        if (curr <= linebuf + 1
        !           171:                            || curr[-1] != (char)('H' | 0200))
        !           172:                                break;
        !           173:                        column -= 2;
        !           174:                        if (c == curr[-2])
        !           175:                                goto enter_boldface;
        !           176:                        if (c == '_' || curr[-2] == '_')
        !           177:                                goto enter_underline;
        !           178:                        curr -= 2;
        !           179:                        break;
        !           180:
        !           181: enter_boldface:
        !           182:                        /*
        !           183:                         * We have "X\bX" (including the current char).
        !           184:                         * Switch into boldface mode.
        !           185:                         */
        !           186:                        column--;
        !           187:                        if (column + bo_width + be_width + 1 >= sc_width)
        !           188:                                /*
        !           189:                                 * Not enough room left on the screen to
        !           190:                                 * enter and exit boldface mode.
        !           191:                                 */
        !           192:                                return (1);
        !           193:
        !           194:                        if (bo_width > 0 && curr > linebuf + 2
        !           195:                            && curr[-3] == ' ') {
        !           196:                                /*
        !           197:                                 * Special case for magic cookie terminals:
        !           198:                                 * if the previous char was a space, replace
        !           199:                                 * it with the "enter boldface" sequence.
        !           200:                                 */
        !           201:                                curr[-3] = BO_CHAR;
        !           202:                                column += bo_width-1;
        !           203:                        } else {
        !           204:                                curr[-1] = curr[-2];
        !           205:                                curr[-2] = BO_CHAR;
        !           206:                                column += bo_width;
        !           207:                                curr++;
        !           208:                        }
        !           209:                        goto ln_bo_xb_case;
        !           210:
        !           211: enter_underline:
        !           212:                        /*
        !           213:                         * We have either "_\bX" or "X\b_" (including
        !           214:                         * the current char).  Switch into underline mode.
        !           215:                         */
        !           216:                        column--;
        !           217:                        if (column + ul_width + ue_width + 1 >= sc_width)
        !           218:                                /*
        !           219:                                 * Not enough room left on the screen to
        !           220:                                 * enter and exit underline mode.
        !           221:                                 */
        !           222:                                return (1);
        !           223:
        !           224:                        if (ul_width > 0 &&
        !           225:                            curr > linebuf + 2 && curr[-3] == ' ')
        !           226:                        {
        !           227:                                /*
        !           228:                                 * Special case for magic cookie terminals:
        !           229:                                 * if the previous char was a space, replace
        !           230:                                 * it with the "enter underline" sequence.
        !           231:                                 */
        !           232:                                curr[-3] = UL_CHAR;
        !           233:                                column += ul_width-1;
        !           234:                        } else
        !           235:                        {
        !           236:                                curr[-1] = curr[-2];
        !           237:                                curr[-2] = UL_CHAR;
        !           238:                                column += ul_width;
        !           239:                                curr++;
        !           240:                        }
        !           241:                        goto ln_ul_xb_case;
        !           242:                        /*NOTREACHED*/
        !           243:                case LN_UL_XB:
        !           244:                        /*
        !           245:                         * Termination of a sequence "_\bX" or "X\b_".
        !           246:                         */
        !           247:                        if (c != '_' && curr[-2] != '_' && c == curr[-2])
        !           248:                        {
        !           249:                                /*
        !           250:                                 * We seem to have run on from underlining
        !           251:                                 * into boldfacing - this is a nasty fix, but
        !           252:                                 * until this whole routine is rewritten as a
        !           253:                                 * real DFA, ...  well ...
        !           254:                                 */
        !           255:                                curr[0] = curr[-2];
        !           256:                                curr[-2] = UE_CHAR;
        !           257:                                curr[-1] = BO_CHAR;
        !           258:                                curr += 2; /* char & non-existent backspace */
        !           259:                                ln_state = LN_BO_XB;
        !           260:                                goto ln_bo_xb_case;
        !           261:                        }
        !           262: ln_ul_xb_case:
        !           263:                        if (c == '_')
        !           264:                                c = curr[-2];
        !           265:                        curr -= 2;
        !           266:                        ln_state = LN_UNDERLINE;
        !           267:                        break;
        !           268:                case LN_BO_XB:
        !           269:                        /*
        !           270:                         * Termination of a sequnce "X\bX".
        !           271:                         */
        !           272:                        if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
        !           273:                        {
        !           274:                                /*
        !           275:                                 * We seem to have run on from
        !           276:                                 * boldfacing into underlining.
        !           277:                                 */
        !           278:                                curr[0] = curr[-2];
        !           279:                                curr[-2] = BE_CHAR;
        !           280:                                curr[-1] = UL_CHAR;
        !           281:                                curr += 2; /* char & non-existent backspace */
        !           282:                                ln_state = LN_UL_XB;
        !           283:                                goto ln_ul_xb_case;
        !           284:                        }
        !           285: ln_bo_xb_case:
        !           286:                        curr -= 2;
        !           287:                        ln_state = LN_BOLDFACE;
        !           288:                        break;
        !           289:                case LN_UNDERLINE:
        !           290:                        if (column + ue_width + bo_width + 1 + be_width >= sc_width)
        !           291:                                /*
        !           292:                                 * We have just barely enough room to
        !           293:                                 * exit underline mode and handle a possible
        !           294:                                 * underline/boldface run on mixup.
        !           295:                                 */
        !           296:                                return (1);
        !           297:                        ln_state = LN_UL_X;
        !           298:                        break;
        !           299:                case LN_BOLDFACE:
        !           300:                        if (c == '\b')
        !           301:                        {
        !           302:                                ln_state = LN_BO_XB;
        !           303:                                break;
        !           304:                        }
        !           305:                        if (column + be_width + ul_width + 1 + ue_width >= sc_width)
        !           306:                                /*
        !           307:                                 * We have just barely enough room to
        !           308:                                 * exit underline mode and handle a possible
        !           309:                                 * underline/boldface run on mixup.
        !           310:                                 */
        !           311:                                return (1);
        !           312:                        ln_state = LN_BO_X;
        !           313:                        break;
        !           314:                case LN_UL_X:
        !           315:                        if (c == '\b')
        !           316:                                ln_state = LN_UL_XB;
        !           317:                        else
        !           318:                        {
        !           319:                                /*
        !           320:                                 * Exit underline mode.
        !           321:                                 * We have to shuffle the chars a bit
        !           322:                                 * to make this work.
        !           323:                                 */
        !           324:                                curr[0] = curr[-1];
        !           325:                                curr[-1] = UE_CHAR;
        !           326:                                column += ue_width;
        !           327:                                if (ue_width > 0 && curr[0] == ' ')
        !           328:                                        /*
        !           329:                                         * Another special case for magic
        !           330:                                         * cookie terminals: if the next
        !           331:                                         * char is a space, replace it
        !           332:                                         * with the "exit underline" sequence.
        !           333:                                         */
        !           334:                                        column--;
        !           335:                                else
        !           336:                                        curr++;
        !           337:                                ln_state = LN_NORMAL;
        !           338:                        }
        !           339:                        break;
        !           340:                case LN_BO_X:
        !           341:                        if (c == '\b')
        !           342:                                ln_state = LN_BO_XB;
        !           343:                        else
        !           344:                        {
        !           345:                                /*
        !           346:                                 * Exit boldface mode.
        !           347:                                 * We have to shuffle the chars a bit
        !           348:                                 * to make this work.
        !           349:                                 */
        !           350:                                curr[0] = curr[-1];
        !           351:                                curr[-1] = BE_CHAR;
        !           352:                                column += be_width;
        !           353:                                if (be_width > 0 && curr[0] == ' ')
        !           354:                                        /*
        !           355:                                         * Another special case for magic
        !           356:                                         * cookie terminals: if the next
        !           357:                                         * char is a space, replace it
        !           358:                                         * with the "exit boldface" sequence.
        !           359:                                         */
        !           360:                                        column--;
        !           361:                                else
        !           362:                                        curr++;
        !           363:                                ln_state = LN_NORMAL;
        !           364:                        }
        !           365:                        break;
        !           366:                }
        !           367:        }
        !           368:
        !           369:        if (c == '\t') {
        !           370:                /*
        !           371:                 * Expand a tab into spaces.
        !           372:                 */
        !           373:                do {
        !           374:                        NEW_COLUMN(1);
        !           375:                } while ((column % tabstop) != 0);
        !           376:                *curr++ = '\t';
        !           377:                return (0);
        !           378:        }
        !           379:
        !           380:        if (c == '\b') {
        !           381:                if (ln_state == LN_NORMAL)
        !           382:                        NEW_COLUMN(2);
        !           383:                else
        !           384:                        column--;
        !           385:                *curr++ = ('H' | 0200);
        !           386:                return(0);
        !           387:        }
        !           388:
        !           389:        if (CONTROL_CHAR(c)) {
        !           390:                /*
        !           391:                 * Put a "^X" into the buffer.  The 0200 bit is used to tell
        !           392:                 * put_line() to prefix the char with a ^.  We don't actually
        !           393:                 * put the ^ in the buffer because we sometimes need to move
        !           394:                 * chars around, and such movement might separate the ^ from
        !           395:                 * its following character.
        !           396:                 */
        !           397:                NEW_COLUMN(2);
        !           398:                *curr++ = (CARAT_CHAR(c) | 0200);
        !           399:                return(0);
        !           400:        }
        !           401:
        !           402:        /*
        !           403:         * Ordinary character.  Just put it in the buffer.
        !           404:         */
        !           405:        NEW_COLUMN(1);
        !           406:        *curr++ = c;
        !           407:        return (0);
        !           408: }
        !           409:
        !           410: /*
        !           411:  * Analogous to forw_line(), but deals with "raw lines":
        !           412:  * lines which are not split for screen width.
        !           413:  * {{ This is supposed to be more efficient than forw_line(). }}
        !           414:  */
        !           415: off_t
        !           416: forw_raw_line(curr_pos)
        !           417:        off_t curr_pos;
        !           418: {
        !           419:        register char *p;
        !           420:        register int c;
        !           421:        off_t new_pos, ch_tell();
        !           422:
        !           423:        if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
        !           424:                (c = ch_forw_get()) == EOI)
        !           425:                return (NULL_POSITION);
        !           426:
        !           427:        p = linebuf;
        !           428:
        !           429:        for (;;)
        !           430:        {
        !           431:                if (c == '\n' || c == EOI)
        !           432:                {
        !           433:                        new_pos = ch_tell();
        !           434:                        break;
        !           435:                }
        !           436:                if (p >= &linebuf[sizeof(linebuf)-1])
        !           437:                {
        !           438:                        /*
        !           439:                         * Overflowed the input buffer.
        !           440:                         * Pretend the line ended here.
        !           441:                         * {{ The line buffer is supposed to be big
        !           442:                         *    enough that this never happens. }}
        !           443:                         */
        !           444:                        new_pos = ch_tell() - 1;
        !           445:                        break;
        !           446:                }
        !           447:                *p++ = c;
        !           448:                c = ch_forw_get();
        !           449:        }
        !           450:        *p = '\0';
        !           451:        line = linebuf;
        !           452:        return (new_pos);
        !           453: }
        !           454:
        !           455: /*
        !           456:  * Analogous to back_line(), but deals with "raw lines".
        !           457:  * {{ This is supposed to be more efficient than back_line(). }}
        !           458:  */
        !           459: off_t
        !           460: back_raw_line(curr_pos)
        !           461:        off_t curr_pos;
        !           462: {
        !           463:        register char *p;
        !           464:        register int c;
        !           465:        off_t new_pos, ch_tell();
        !           466:
        !           467:        if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
        !           468:                ch_seek(curr_pos-1))
        !           469:                return (NULL_POSITION);
        !           470:
        !           471:        p = &linebuf[sizeof(linebuf)];
        !           472:        *--p = '\0';
        !           473:
        !           474:        for (;;)
        !           475:        {
        !           476:                c = ch_back_get();
        !           477:                if (c == '\n')
        !           478:                {
        !           479:                        /*
        !           480:                         * This is the newline ending the previous line.
        !           481:                         * We have hit the beginning of the line.
        !           482:                         */
        !           483:                        new_pos = ch_tell() + 1;
        !           484:                        break;
        !           485:                }
        !           486:                if (c == EOI)
        !           487:                {
        !           488:                        /*
        !           489:                         * We have hit the beginning of the file.
        !           490:                         * This must be the first line in the file.
        !           491:                         * This must, of course, be the beginning of the line.
        !           492:                         */
        !           493:                        new_pos = (off_t)0;
        !           494:                        break;
        !           495:                }
        !           496:                if (p <= linebuf)
        !           497:                {
        !           498:                        /*
        !           499:                         * Overflowed the input buffer.
        !           500:                         * Pretend the line ended here.
        !           501:                         */
        !           502:                        new_pos = ch_tell() + 1;
        !           503:                        break;
        !           504:                }
        !           505:                *--p = c;
        !           506:        }
        !           507:        line = p;
        !           508:        return (new_pos);
        !           509: }