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

Annotation of src/usr.bin/less/edit.c, Revision 1.1.1.2

1.1       etheisen    1: /*
1.1.1.2 ! millert     2:  * Copyright (C) 1984-2002  Mark Nudelman
1.1       etheisen    3:  *
1.1.1.2 ! millert     4:  * You may distribute under the terms of either the GNU General Public
        !             5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.1.1.2 ! millert     7:  * For more information about less, or for information on how to
        !             8:  * contact the author, see the README file.
1.1       etheisen    9:  */
                     10:
                     11:
                     12: #include "less.h"
                     13:
                     14: public int fd0 = 0;
                     15:
                     16: extern int new_file;
                     17: extern int errmsgs;
                     18: extern int cbufs;
                     19: extern char *every_first_cmd;
                     20: extern int any_display;
                     21: extern int force_open;
                     22: extern int is_tty;
1.1.1.2 ! millert    23: extern int sigs;
1.1       etheisen   24: extern IFILE curr_ifile;
                     25: extern IFILE old_ifile;
                     26: extern struct scrpos initial_scrpos;
1.1.1.2 ! millert    27: extern void constant *ml_examine;
        !            28: #if SPACES_IN_FILENAMES
        !            29: extern char openquote;
        !            30: extern char closequote;
        !            31: #endif
1.1       etheisen   32:
                     33: #if LOGFILE
                     34: extern int logfile;
                     35: extern int force_logfile;
                     36: extern char *namelogfile;
                     37: #endif
                     38:
                     39: char *curr_altfilename = NULL;
                     40: static void *curr_altpipe;
                     41:
                     42:
                     43: /*
                     44:  * Textlist functions deal with a list of words separated by spaces.
                     45:  * init_textlist sets up a textlist structure.
                     46:  * forw_textlist uses that structure to iterate thru the list of
                     47:  * words, returning each one as a standard null-terminated string.
                     48:  * back_textlist does the same, but runs thru the list backwards.
                     49:  */
                     50:        public void
                     51: init_textlist(tlist, str)
                     52:        struct textlist *tlist;
                     53:        char *str;
                     54: {
                     55:        char *s;
1.1.1.2 ! millert    56: #if SPACES_IN_FILENAMES
        !            57:        int meta_quoted = 0;
        !            58:        int delim_quoted = 0;
        !            59:        char *esc = get_meta_escape();
        !            60:        int esclen = strlen(esc);
        !            61: #endif
1.1       etheisen   62:
                     63:        tlist->string = skipsp(str);
                     64:        tlist->endstring = tlist->string + strlen(tlist->string);
                     65:        for (s = str;  s < tlist->endstring;  s++)
                     66:        {
1.1.1.2 ! millert    67: #if SPACES_IN_FILENAMES
        !            68:                if (meta_quoted)
        !            69:                {
        !            70:                        meta_quoted = 0;
        !            71:                } else if (esclen > 0 && s + esclen < tlist->endstring &&
        !            72:                           strncmp(s, esc, esclen) == 0)
        !            73:                {
        !            74:                        meta_quoted = 1;
        !            75:                        s += esclen - 1;
        !            76:                } else if (delim_quoted)
        !            77:                {
        !            78:                        if (*s == closequote)
        !            79:                                delim_quoted = 0;
        !            80:                } else /* (!delim_quoted) */
        !            81:                {
        !            82:                        if (*s == openquote)
        !            83:                                delim_quoted = 1;
        !            84:                        else if (*s == ' ')
        !            85:                                *s = '\0';
        !            86:                }
        !            87: #else
1.1       etheisen   88:                if (*s == ' ')
                     89:                        *s = '\0';
1.1.1.2 ! millert    90: #endif
1.1       etheisen   91:        }
                     92: }
                     93:
                     94:        public char *
                     95: forw_textlist(tlist, prev)
                     96:        struct textlist *tlist;
                     97:        char *prev;
                     98: {
                     99:        char *s;
                    100:
                    101:        /*
                    102:         * prev == NULL means return the first word in the list.
                    103:         * Otherwise, return the word after "prev".
                    104:         */
                    105:        if (prev == NULL)
                    106:                s = tlist->string;
                    107:        else
                    108:                s = prev + strlen(prev);
                    109:        if (s >= tlist->endstring)
                    110:                return (NULL);
                    111:        while (*s == '\0')
                    112:                s++;
                    113:        if (s >= tlist->endstring)
                    114:                return (NULL);
                    115:        return (s);
                    116: }
                    117:
                    118:        public char *
                    119: back_textlist(tlist, prev)
                    120:        struct textlist *tlist;
                    121:        char *prev;
                    122: {
                    123:        char *s;
                    124:
                    125:        /*
                    126:         * prev == NULL means return the last word in the list.
                    127:         * Otherwise, return the word before "prev".
                    128:         */
                    129:        if (prev == NULL)
                    130:                s = tlist->endstring;
                    131:        else if (prev <= tlist->string)
                    132:                return (NULL);
                    133:        else
                    134:                s = prev - 1;
                    135:        while (*s == '\0')
                    136:                s--;
                    137:        if (s <= tlist->string)
                    138:                return (NULL);
                    139:        while (s[-1] != '\0' && s > tlist->string)
                    140:                s--;
                    141:        return (s);
                    142: }
                    143:
                    144: /*
                    145:  * Close the current input file.
                    146:  */
                    147:        static void
                    148: close_file()
                    149: {
                    150:        struct scrpos scrpos;
                    151:
                    152:        if (curr_ifile == NULL_IFILE)
                    153:                return;
1.1.1.2 ! millert   154:
1.1       etheisen  155:        /*
                    156:         * Save the current position so that we can return to
                    157:         * the same position if we edit this file again.
                    158:         */
                    159:        get_scrpos(&scrpos);
                    160:        if (scrpos.pos != NULL_POSITION)
                    161:        {
                    162:                store_pos(curr_ifile, &scrpos);
                    163:                lastmark();
                    164:        }
                    165:        /*
                    166:         * Close the file descriptor, unless it is a pipe.
                    167:         */
                    168:        ch_close();
                    169:        /*
                    170:         * If we opened a file using an alternate name,
                    171:         * do special stuff to close it.
                    172:         */
                    173:        if (curr_altfilename != NULL)
                    174:        {
                    175:                close_altfile(curr_altfilename, get_filename(curr_ifile),
1.1.1.2 ! millert   176:                                curr_altpipe);
1.1       etheisen  177:                free(curr_altfilename);
                    178:                curr_altfilename = NULL;
                    179:        }
                    180:        curr_ifile = NULL_IFILE;
                    181: }
                    182:
                    183: /*
                    184:  * Edit a new file (given its name).
                    185:  * Filename == "-" means standard input.
                    186:  * Filename == NULL means just close the current file.
                    187:  */
                    188:        public int
                    189: edit(filename)
                    190:        char *filename;
                    191: {
                    192:        if (filename == NULL)
                    193:                return (edit_ifile(NULL_IFILE));
                    194:        return (edit_ifile(get_ifile(filename, curr_ifile)));
                    195: }
                    196:
                    197: /*
                    198:  * Edit a new file (given its IFILE).
                    199:  * ifile == NULL means just close the current file.
                    200:  */
                    201:        public int
                    202: edit_ifile(ifile)
                    203:        IFILE ifile;
                    204: {
                    205:        int f;
                    206:        int answer;
                    207:        int no_display;
                    208:        int chflags;
                    209:        char *filename;
                    210:        char *open_filename;
1.1.1.2 ! millert   211:        char *qopen_filename;
1.1       etheisen  212:        char *alt_filename;
                    213:        void *alt_pipe;
                    214:        IFILE was_curr_ifile;
                    215:        PARG parg;
                    216:
                    217:        if (ifile == curr_ifile)
                    218:        {
                    219:                /*
                    220:                 * Already have the correct file open.
                    221:                 */
                    222:                return (0);
                    223:        }
                    224:
                    225:        /*
                    226:         * We must close the currently open file now.
                    227:         * This is necessary to make the open_altfile/close_altfile pairs
                    228:         * nest properly (or rather to avoid nesting at all).
                    229:         * {{ Some stupid implementations of popen() mess up if you do:
                    230:         *    fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
                    231:         */
                    232: #if LOGFILE
                    233:        end_logfile();
                    234: #endif
1.1.1.2 ! millert   235:        was_curr_ifile = save_curr_ifile();
1.1       etheisen  236:        if (curr_ifile != NULL_IFILE)
                    237:        {
1.1.1.2 ! millert   238:                chflags = ch_getflags();
1.1       etheisen  239:                close_file();
1.1.1.2 ! millert   240:                if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
        !           241:                {
        !           242:                        /*
        !           243:                         * Don't keep the help file in the ifile list.
        !           244:                         */
        !           245:                        del_ifile(was_curr_ifile);
        !           246:                        was_curr_ifile = old_ifile;
        !           247:                }
1.1       etheisen  248:        }
                    249:
                    250:        if (ifile == NULL_IFILE)
                    251:        {
                    252:                /*
                    253:                 * No new file to open.
                    254:                 * (Don't set old_ifile, because if you call edit_ifile(NULL),
                    255:                 *  you're supposed to have saved curr_ifile yourself,
                    256:                 *  and you'll restore it if necessary.)
                    257:                 */
1.1.1.2 ! millert   258:                unsave_ifile(was_curr_ifile);
1.1       etheisen  259:                return (0);
                    260:        }
                    261:
1.1.1.2 ! millert   262:        filename = save(get_filename(ifile));
1.1       etheisen  263:        /*
                    264:         * See if LESSOPEN specifies an "alternate" file to open.
                    265:         */
                    266:        alt_pipe = NULL;
                    267:        alt_filename = open_altfile(filename, &f, &alt_pipe);
                    268:        open_filename = (alt_filename != NULL) ? alt_filename : filename;
1.1.1.2 ! millert   269:        qopen_filename = shell_unquote(open_filename);
1.1       etheisen  270:
                    271:        chflags = 0;
                    272:        if (alt_pipe != NULL)
                    273:        {
                    274:                /*
                    275:                 * The alternate "file" is actually a pipe.
                    276:                 * f has already been set to the file descriptor of the pipe
                    277:                 * in the call to open_altfile above.
                    278:                 * Keep the file descriptor open because it was opened
                    279:                 * via popen(), and pclose() wants to close it.
                    280:                 */
                    281:                chflags |= CH_POPENED;
                    282:        } else if (strcmp(open_filename, "-") == 0)
                    283:        {
                    284:                /*
                    285:                 * Use standard input.
                    286:                 * Keep the file descriptor open because we can't reopen it.
                    287:                 */
                    288:                f = fd0;
                    289:                chflags |= CH_KEEPOPEN;
1.1.1.2 ! millert   290:                /*
        !           291:                 * Must switch stdin to BINARY mode.
        !           292:                 */
        !           293:                SET_BINARY(f);
        !           294: #if MSDOS_COMPILER==DJGPPC
        !           295:                /*
        !           296:                 * Setting stdin to binary by default causes
        !           297:                 * Ctrl-C to not raise SIGINT.  We must undo
        !           298:                 * that side-effect.
        !           299:                 */
        !           300:                __djgpp_set_ctrl_c(1);
        !           301: #endif
        !           302:        } else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
        !           303:        {
        !           304:                f = -1;
        !           305:                chflags |= CH_HELPFILE;
1.1       etheisen  306:        } else if ((parg.p_string = bad_file(open_filename)) != NULL)
                    307:        {
                    308:                /*
                    309:                 * It looks like a bad file.  Don't try to open it.
                    310:                 */
                    311:                error("%s", &parg);
                    312:                free(parg.p_string);
                    313:            err1:
                    314:                if (alt_filename != NULL)
                    315:                {
                    316:                        close_altfile(alt_filename, filename, alt_pipe);
                    317:                        free(alt_filename);
                    318:                }
                    319:                del_ifile(ifile);
1.1.1.2 ! millert   320:                free(qopen_filename);
        !           321:                free(filename);
1.1       etheisen  322:                /*
                    323:                 * Re-open the current file.
                    324:                 */
1.1.1.2 ! millert   325:                reedit_ifile(was_curr_ifile);
1.1       etheisen  326:                return (1);
1.1.1.2 ! millert   327:        } else if ((f = open(qopen_filename, OPEN_READ)) < 0)
1.1       etheisen  328:        {
                    329:                /*
                    330:                 * Got an error trying to open it.
                    331:                 */
                    332:                parg.p_string = errno_message(filename);
                    333:                error("%s", &parg);
                    334:                free(parg.p_string);
                    335:                goto err1;
1.1.1.2 ! millert   336:        } else
1.1       etheisen  337:        {
1.1.1.2 ! millert   338:                chflags |= CH_CANSEEK;
        !           339:                if (!force_open && !opened(ifile) && bin_file(f))
1.1       etheisen  340:                {
1.1.1.2 ! millert   341:                        /*
        !           342:                         * Looks like a binary file.
        !           343:                         * Ask user if we should proceed.
        !           344:                         */
        !           345:                        parg.p_string = filename;
        !           346:                        answer = query("\"%s\" may be a binary file.  See it anyway? ",
        !           347:                                &parg);
        !           348:                        if (answer != 'y' && answer != 'Y')
        !           349:                        {
        !           350:                                close(f);
        !           351:                                goto err1;
        !           352:                        }
1.1       etheisen  353:                }
                    354:        }
1.1.1.2 ! millert   355:        free(qopen_filename);
1.1       etheisen  356:
                    357:        /*
                    358:         * Get the new ifile.
                    359:         * Get the saved position for the file.
                    360:         */
                    361:        if (was_curr_ifile != NULL_IFILE)
1.1.1.2 ! millert   362:        {
1.1       etheisen  363:                old_ifile = was_curr_ifile;
1.1.1.2 ! millert   364:                unsave_ifile(was_curr_ifile);
        !           365:        }
1.1       etheisen  366:        curr_ifile = ifile;
                    367:        curr_altfilename = alt_filename;
                    368:        curr_altpipe = alt_pipe;
                    369:        set_open(curr_ifile); /* File has been opened */
                    370:        get_pos(curr_ifile, &initial_scrpos);
                    371:        new_file = TRUE;
                    372:        ch_init(f, chflags);
1.1.1.2 ! millert   373:
        !           374:        if (!(chflags & CH_HELPFILE))
        !           375:        {
1.1       etheisen  376: #if LOGFILE
1.1.1.2 ! millert   377:                if (namelogfile != NULL && is_tty)
        !           378:                        use_logfile(namelogfile);
1.1       etheisen  379: #endif
1.1.1.2 ! millert   380:                if (every_first_cmd != NULL)
        !           381:                        ungetsc(every_first_cmd);
        !           382:        }
1.1       etheisen  383:
                    384:        no_display = !any_display;
                    385:        flush();
                    386:        any_display = TRUE;
                    387:
                    388:        if (is_tty)
                    389:        {
                    390:                /*
                    391:                 * Output is to a real tty.
                    392:                 */
                    393:
                    394:                /*
                    395:                 * Indicate there is nothing displayed yet.
                    396:                 */
                    397:                pos_clear();
                    398:                clr_linenum();
                    399: #if HILITE_SEARCH
                    400:                clr_hilite();
                    401: #endif
1.1.1.2 ! millert   402:                cmd_addhist(ml_examine, filename);
1.1       etheisen  403:                if (no_display && errmsgs > 0)
                    404:                {
                    405:                        /*
                    406:                         * We displayed some messages on error output
                    407:                         * (file descriptor 2; see error() function).
                    408:                         * Before erasing the screen contents,
                    409:                         * display the file name and wait for a keystroke.
                    410:                         */
                    411:                        parg.p_string = filename;
                    412:                        error("%s", &parg);
                    413:                }
                    414:        }
1.1.1.2 ! millert   415:        free(filename);
1.1       etheisen  416:        return (0);
                    417: }
                    418:
                    419: /*
                    420:  * Edit a space-separated list of files.
                    421:  * For each filename in the list, enter it into the ifile list.
                    422:  * Then edit the first one.
                    423:  */
                    424:        public int
                    425: edit_list(filelist)
                    426:        char *filelist;
                    427: {
1.1.1.2 ! millert   428:        IFILE save_ifile;
1.1       etheisen  429:        char *good_filename;
                    430:        char *filename;
                    431:        char *gfilelist;
                    432:        char *gfilename;
                    433:        struct textlist tl_files;
                    434:        struct textlist tl_gfiles;
                    435:
1.1.1.2 ! millert   436:        save_ifile = save_curr_ifile();
1.1       etheisen  437:        good_filename = NULL;
                    438:
                    439:        /*
                    440:         * Run thru each filename in the list.
                    441:         * Try to glob the filename.
                    442:         * If it doesn't expand, just try to open the filename.
                    443:         * If it does expand, try to open each name in that list.
                    444:         */
                    445:        init_textlist(&tl_files, filelist);
                    446:        filename = NULL;
                    447:        while ((filename = forw_textlist(&tl_files, filename)) != NULL)
                    448:        {
1.1.1.2 ! millert   449:                gfilelist = lglob(filename);
1.1       etheisen  450:                init_textlist(&tl_gfiles, gfilelist);
                    451:                gfilename = NULL;
                    452:                while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
                    453:                {
                    454:                        if (edit(gfilename) == 0 && good_filename == NULL)
                    455:                                good_filename = get_filename(curr_ifile);
                    456:                }
                    457:                free(gfilelist);
                    458:        }
                    459:        /*
                    460:         * Edit the first valid filename in the list.
                    461:         */
                    462:        if (good_filename == NULL)
1.1.1.2 ! millert   463:        {
        !           464:                unsave_ifile(save_ifile);
1.1       etheisen  465:                return (1);
1.1.1.2 ! millert   466:        }
1.1       etheisen  467:        if (get_ifile(good_filename, curr_ifile) == curr_ifile)
1.1.1.2 ! millert   468:        {
1.1       etheisen  469:                /*
                    470:                 * Trying to edit the current file; don't reopen it.
                    471:                 */
1.1.1.2 ! millert   472:                unsave_ifile(save_ifile);
1.1       etheisen  473:                return (0);
1.1.1.2 ! millert   474:        }
        !           475:        reedit_ifile(save_ifile);
1.1       etheisen  476:        return (edit(good_filename));
                    477: }
                    478:
                    479: /*
                    480:  * Edit the first file in the command line (ifile) list.
                    481:  */
                    482:        public int
                    483: edit_first()
                    484: {
                    485:        curr_ifile = NULL_IFILE;
                    486:        return (edit_next(1));
                    487: }
                    488:
                    489: /*
                    490:  * Edit the last file in the command line (ifile) list.
                    491:  */
                    492:        public int
                    493: edit_last()
                    494: {
                    495:        curr_ifile = NULL_IFILE;
                    496:        return (edit_prev(1));
                    497: }
                    498:
                    499:
                    500: /*
1.1.1.2 ! millert   501:  * Edit the next or previous file in the command line (ifile) list.
1.1       etheisen  502:  */
1.1.1.2 ! millert   503:        static int
        !           504: edit_istep(h, n, dir)
        !           505:        IFILE h;
1.1       etheisen  506:        int n;
1.1.1.2 ! millert   507:        int dir;
1.1       etheisen  508: {
                    509:        IFILE next;
                    510:
                    511:        /*
                    512:         * Skip n filenames, then try to edit each filename.
                    513:         */
                    514:        for (;;)
                    515:        {
1.1.1.2 ! millert   516:                next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
1.1       etheisen  517:                if (--n < 0)
                    518:                {
                    519:                        if (edit_ifile(h) == 0)
                    520:                                break;
                    521:                }
                    522:                if (next == NULL_IFILE)
                    523:                {
                    524:                        /*
                    525:                         * Reached end of the ifile list.
                    526:                         */
                    527:                        return (1);
                    528:                }
1.1.1.2 ! millert   529:                if (ABORT_SIGS())
        !           530:                {
        !           531:                        /*
        !           532:                         * Interrupt breaks out, if we're in a long
        !           533:                         * list of files that can't be opened.
        !           534:                         */
        !           535:                        return (1);
        !           536:                }
1.1       etheisen  537:                h = next;
                    538:        }
                    539:        /*
                    540:         * Found a file that we can edit.
                    541:         */
                    542:        return (0);
                    543: }
                    544:
1.1.1.2 ! millert   545:        static int
        !           546: edit_inext(h, n)
        !           547:        IFILE h;
        !           548:        int n;
        !           549: {
        !           550:        return (edit_istep(h, n, 1));
        !           551: }
        !           552:
1.1       etheisen  553:        public int
1.1.1.2 ! millert   554: edit_next(n)
1.1       etheisen  555:        int n;
                    556: {
1.1.1.2 ! millert   557:        return edit_istep(curr_ifile, n, 1);
        !           558: }
        !           559:
        !           560:        static int
        !           561: edit_iprev(h, n)
1.1       etheisen  562:        IFILE h;
1.1.1.2 ! millert   563:        int n;
        !           564: {
        !           565:        return (edit_istep(h, n, -1));
        !           566: }
1.1       etheisen  567:
1.1.1.2 ! millert   568:        public int
        !           569: edit_prev(n)
        !           570:        int n;
        !           571: {
        !           572:        return edit_istep(curr_ifile, n, -1);
1.1       etheisen  573: }
                    574:
                    575: /*
                    576:  * Edit a specific file in the command line (ifile) list.
                    577:  */
                    578:        public int
                    579: edit_index(n)
                    580:        int n;
                    581: {
                    582:        IFILE h;
                    583:
                    584:        h = NULL_IFILE;
                    585:        do
                    586:        {
                    587:                if ((h = next_ifile(h)) == NULL_IFILE)
                    588:                {
                    589:                        /*
                    590:                         * Reached end of the list without finding it.
                    591:                         */
                    592:                        return (1);
                    593:                }
                    594:        } while (get_index(h) != n);
                    595:
                    596:        return (edit_ifile(h));
                    597: }
                    598:
1.1.1.2 ! millert   599:        public IFILE
        !           600: save_curr_ifile()
        !           601: {
        !           602:        if (curr_ifile != NULL_IFILE)
        !           603:                hold_ifile(curr_ifile, 1);
        !           604:        return (curr_ifile);
        !           605: }
        !           606:
        !           607:        public void
        !           608: unsave_ifile(save_ifile)
        !           609:        IFILE save_ifile;
        !           610: {
        !           611:        if (save_ifile != NULL_IFILE)
        !           612:                hold_ifile(save_ifile, -1);
        !           613: }
        !           614:
        !           615: /*
        !           616:  * Reedit the ifile which was previously open.
        !           617:  */
        !           618:        public void
        !           619: reedit_ifile(save_ifile)
        !           620:        IFILE save_ifile;
        !           621: {
        !           622:        IFILE next;
        !           623:        IFILE prev;
        !           624:
        !           625:        /*
        !           626:         * Try to reopen the ifile.
        !           627:         * Note that opening it may fail (maybe the file was removed),
        !           628:         * in which case the ifile will be deleted from the list.
        !           629:         * So save the next and prev ifiles first.
        !           630:         */
        !           631:        unsave_ifile(save_ifile);
        !           632:        next = next_ifile(save_ifile);
        !           633:        prev = prev_ifile(save_ifile);
        !           634:        if (edit_ifile(save_ifile) == 0)
        !           635:                return;
        !           636:        /*
        !           637:         * If can't reopen it, open the next input file in the list.
        !           638:         */
        !           639:        if (next != NULL_IFILE && edit_inext(next, 0) == 0)
        !           640:                return;
        !           641:        /*
        !           642:         * If can't open THAT one, open the previous input file in the list.
        !           643:         */
        !           644:        if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
        !           645:                return;
        !           646:        /*
        !           647:         * If can't even open that, we're stuck.  Just quit.
        !           648:         */
        !           649:        quit(QUIT_ERROR);
        !           650: }
        !           651:
1.1       etheisen  652: /*
                    653:  * Edit standard input.
                    654:  */
                    655:        public int
                    656: edit_stdin()
                    657: {
                    658:        if (isatty(fd0))
                    659:        {
1.1.1.2 ! millert   660:                error("Missing filename (\"less --help\" for help)", NULL_PARG);
1.1       etheisen  661:                quit(QUIT_OK);
                    662:        }
                    663:        return (edit("-"));
                    664: }
                    665:
                    666: /*
                    667:  * Copy a file directly to standard output.
                    668:  * Used if standard output is not a tty.
                    669:  */
                    670:        public void
                    671: cat_file()
                    672: {
                    673:        register int c;
                    674:
                    675:        while ((c = ch_forw_get()) != EOI)
                    676:                putchr(c);
                    677:        flush();
                    678: }
                    679:
                    680: #if LOGFILE
                    681:
                    682: /*
                    683:  * If the user asked for a log file and our input file
                    684:  * is standard input, create the log file.
                    685:  * We take care not to blindly overwrite an existing file.
                    686:  */
                    687:        public void
                    688: use_logfile(filename)
                    689:        char *filename;
                    690: {
                    691:        register int exists;
                    692:        register int answer;
                    693:        PARG parg;
                    694:
                    695:        if (ch_getflags() & CH_CANSEEK)
                    696:                /*
                    697:                 * Can't currently use a log file on a file that can seek.
                    698:                 */
                    699:                return;
                    700:
                    701:        /*
                    702:         * {{ We could use access() here. }}
                    703:         */
1.1.1.2 ! millert   704:        filename = shell_unquote(filename);
1.1       etheisen  705:        exists = open(filename, OPEN_READ);
                    706:        close(exists);
                    707:        exists = (exists >= 0);
                    708:
                    709:        /*
                    710:         * Decide whether to overwrite the log file or append to it.
                    711:         * If it doesn't exist we "overwrite" it.
                    712:         */
                    713:        if (!exists || force_logfile)
                    714:        {
                    715:                /*
                    716:                 * Overwrite (or create) the log file.
                    717:                 */
                    718:                answer = 'O';
                    719:        } else
                    720:        {
                    721:                /*
                    722:                 * Ask user what to do.
                    723:                 */
                    724:                parg.p_string = filename;
                    725:                answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
                    726:        }
                    727:
                    728: loop:
                    729:        switch (answer)
                    730:        {
                    731:        case 'O': case 'o':
                    732:                /*
                    733:                 * Overwrite: create the file.
                    734:                 */
                    735:                logfile = creat(filename, 0644);
                    736:                break;
                    737:        case 'A': case 'a':
                    738:                /*
                    739:                 * Append: open the file and seek to the end.
                    740:                 */
                    741:                logfile = open(filename, OPEN_APPEND);
                    742:                if (lseek(logfile, (off_t)0, 2) == BAD_LSEEK)
                    743:                {
                    744:                        close(logfile);
                    745:                        logfile = -1;
                    746:                }
                    747:                break;
                    748:        case 'D': case 'd':
                    749:                /*
                    750:                 * Don't do anything.
                    751:                 */
1.1.1.2 ! millert   752:                free(filename);
1.1       etheisen  753:                return;
                    754:        case 'q':
                    755:                quit(QUIT_OK);
                    756:                /*NOTREACHED*/
                    757:        default:
                    758:                /*
                    759:                 * Eh?
                    760:                 */
                    761:                answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG);
                    762:                goto loop;
                    763:        }
                    764:
                    765:        if (logfile < 0)
                    766:        {
                    767:                /*
                    768:                 * Error in opening logfile.
                    769:                 */
                    770:                parg.p_string = filename;
                    771:                error("Cannot write to \"%s\"", &parg);
1.1.1.2 ! millert   772:                free(filename);
        !           773:                return;
1.1       etheisen  774:        }
1.1.1.2 ! millert   775:        free(filename);
        !           776:        SET_BINARY(logfile);
1.1       etheisen  777: }
                    778:
                    779: #endif