edit.c revision 161475
160786Sps/* 2161475Sdelphij * Copyright (C) 1984-2005 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps#include "less.h" 1360786Sps 1460786Spspublic int fd0 = 0; 1560786Sps 1660786Spsextern int new_file; 1760786Spsextern int errmsgs; 1860786Spsextern int cbufs; 1960786Spsextern char *every_first_cmd; 2060786Spsextern int any_display; 2160786Spsextern int force_open; 2260786Spsextern int is_tty; 2360786Spsextern int sigs; 2460786Spsextern IFILE curr_ifile; 2560786Spsextern IFILE old_ifile; 2660786Spsextern struct scrpos initial_scrpos; 2760786Spsextern void constant *ml_examine; 2860786Sps#if SPACES_IN_FILENAMES 2960786Spsextern char openquote; 3060786Spsextern char closequote; 3160786Sps#endif 3260786Sps 3360786Sps#if LOGFILE 3460786Spsextern int logfile; 3560786Spsextern int force_logfile; 3660786Spsextern char *namelogfile; 3760786Sps#endif 3860786Sps 3960786Spschar *curr_altfilename = NULL; 4060786Spsstatic void *curr_altpipe; 4160786Sps 4260786Sps 4360786Sps/* 4460786Sps * Textlist functions deal with a list of words separated by spaces. 4560786Sps * init_textlist sets up a textlist structure. 4660786Sps * forw_textlist uses that structure to iterate thru the list of 4760786Sps * words, returning each one as a standard null-terminated string. 4860786Sps * back_textlist does the same, but runs thru the list backwards. 4960786Sps */ 5060786Sps public void 5160786Spsinit_textlist(tlist, str) 5260786Sps struct textlist *tlist; 5360786Sps char *str; 5460786Sps{ 5560786Sps char *s; 5660786Sps#if SPACES_IN_FILENAMES 57128345Stjr int meta_quoted = 0; 58128345Stjr int delim_quoted = 0; 59128345Stjr char *esc = get_meta_escape(); 60128345Stjr int esclen = strlen(esc); 6160786Sps#endif 6260786Sps 6360786Sps tlist->string = skipsp(str); 6460786Sps tlist->endstring = tlist->string + strlen(tlist->string); 6560786Sps for (s = str; s < tlist->endstring; s++) 6660786Sps { 6760786Sps#if SPACES_IN_FILENAMES 68128345Stjr if (meta_quoted) 69128345Stjr { 70128345Stjr meta_quoted = 0; 71128345Stjr } else if (esclen > 0 && s + esclen < tlist->endstring && 72128345Stjr strncmp(s, esc, esclen) == 0) 73128345Stjr { 74128345Stjr meta_quoted = 1; 75128345Stjr s += esclen - 1; 76128345Stjr } else if (delim_quoted) 77128345Stjr { 78128345Stjr if (*s == closequote) 79128345Stjr delim_quoted = 0; 80128345Stjr } else /* (!delim_quoted) */ 81128345Stjr { 82128345Stjr if (*s == openquote) 83128345Stjr delim_quoted = 1; 84128345Stjr else if (*s == ' ') 85128345Stjr *s = '\0'; 86128345Stjr } 8760786Sps#else 8860786Sps if (*s == ' ') 8960786Sps *s = '\0'; 9060786Sps#endif 9160786Sps } 9260786Sps} 9360786Sps 9460786Sps public char * 9560786Spsforw_textlist(tlist, prev) 9660786Sps struct textlist *tlist; 9760786Sps char *prev; 9860786Sps{ 9960786Sps char *s; 10060786Sps 10160786Sps /* 10260786Sps * prev == NULL means return the first word in the list. 10360786Sps * Otherwise, return the word after "prev". 10460786Sps */ 10560786Sps if (prev == NULL) 10660786Sps s = tlist->string; 10760786Sps else 10860786Sps s = prev + strlen(prev); 10960786Sps if (s >= tlist->endstring) 11060786Sps return (NULL); 11160786Sps while (*s == '\0') 11260786Sps s++; 11360786Sps if (s >= tlist->endstring) 11460786Sps return (NULL); 11560786Sps return (s); 11660786Sps} 11760786Sps 11860786Sps public char * 11960786Spsback_textlist(tlist, prev) 12060786Sps struct textlist *tlist; 12160786Sps char *prev; 12260786Sps{ 12360786Sps char *s; 12460786Sps 12560786Sps /* 12660786Sps * prev == NULL means return the last word in the list. 12760786Sps * Otherwise, return the word before "prev". 12860786Sps */ 12960786Sps if (prev == NULL) 13060786Sps s = tlist->endstring; 13160786Sps else if (prev <= tlist->string) 13260786Sps return (NULL); 13360786Sps else 13460786Sps s = prev - 1; 13560786Sps while (*s == '\0') 13660786Sps s--; 13760786Sps if (s <= tlist->string) 13860786Sps return (NULL); 13960786Sps while (s[-1] != '\0' && s > tlist->string) 14060786Sps s--; 14160786Sps return (s); 14260786Sps} 14360786Sps 14460786Sps/* 14560786Sps * Close the current input file. 14660786Sps */ 14760786Sps static void 14860786Spsclose_file() 14960786Sps{ 15060786Sps struct scrpos scrpos; 15160786Sps 15260786Sps if (curr_ifile == NULL_IFILE) 15360786Sps return; 15460786Sps 15560786Sps /* 15660786Sps * Save the current position so that we can return to 15760786Sps * the same position if we edit this file again. 15860786Sps */ 15960786Sps get_scrpos(&scrpos); 16060786Sps if (scrpos.pos != NULL_POSITION) 16160786Sps { 16260786Sps store_pos(curr_ifile, &scrpos); 16360786Sps lastmark(); 16460786Sps } 16560786Sps /* 16660786Sps * Close the file descriptor, unless it is a pipe. 16760786Sps */ 16860786Sps ch_close(); 16960786Sps /* 17060786Sps * If we opened a file using an alternate name, 17160786Sps * do special stuff to close it. 17260786Sps */ 17360786Sps if (curr_altfilename != NULL) 17460786Sps { 175128345Stjr close_altfile(curr_altfilename, get_filename(curr_ifile), 176128345Stjr curr_altpipe); 17760786Sps free(curr_altfilename); 17860786Sps curr_altfilename = NULL; 17960786Sps } 18060786Sps curr_ifile = NULL_IFILE; 18160786Sps} 18260786Sps 18360786Sps/* 18460786Sps * Edit a new file (given its name). 18560786Sps * Filename == "-" means standard input. 18660786Sps * Filename == NULL means just close the current file. 18760786Sps */ 18860786Sps public int 18960786Spsedit(filename) 19060786Sps char *filename; 19160786Sps{ 19260786Sps if (filename == NULL) 19360786Sps return (edit_ifile(NULL_IFILE)); 19460786Sps return (edit_ifile(get_ifile(filename, curr_ifile))); 19560786Sps} 19660786Sps 19760786Sps/* 19860786Sps * Edit a new file (given its IFILE). 19960786Sps * ifile == NULL means just close the current file. 20060786Sps */ 20160786Sps public int 20260786Spsedit_ifile(ifile) 20360786Sps IFILE ifile; 20460786Sps{ 20560786Sps int f; 20660786Sps int answer; 20760786Sps int no_display; 20860786Sps int chflags; 20960786Sps char *filename; 21060786Sps char *open_filename; 211128345Stjr char *qopen_filename; 21260786Sps char *alt_filename; 21360786Sps void *alt_pipe; 21460786Sps IFILE was_curr_ifile; 21560786Sps PARG parg; 21660786Sps 21760786Sps if (ifile == curr_ifile) 21860786Sps { 21960786Sps /* 22060786Sps * Already have the correct file open. 22160786Sps */ 22260786Sps return (0); 22360786Sps } 22460786Sps 22560786Sps /* 22660786Sps * We must close the currently open file now. 22760786Sps * This is necessary to make the open_altfile/close_altfile pairs 22860786Sps * nest properly (or rather to avoid nesting at all). 22960786Sps * {{ Some stupid implementations of popen() mess up if you do: 23060786Sps * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }} 23160786Sps */ 23260786Sps#if LOGFILE 23360786Sps end_logfile(); 23460786Sps#endif 23560786Sps was_curr_ifile = save_curr_ifile(); 23660786Sps if (curr_ifile != NULL_IFILE) 23760786Sps { 23860786Sps chflags = ch_getflags(); 23960786Sps close_file(); 24060786Sps if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1) 24160786Sps { 24260786Sps /* 24360786Sps * Don't keep the help file in the ifile list. 24460786Sps */ 24560786Sps del_ifile(was_curr_ifile); 24660786Sps was_curr_ifile = old_ifile; 24760786Sps } 24860786Sps } 24960786Sps 25060786Sps if (ifile == NULL_IFILE) 25160786Sps { 25260786Sps /* 25360786Sps * No new file to open. 25460786Sps * (Don't set old_ifile, because if you call edit_ifile(NULL), 25560786Sps * you're supposed to have saved curr_ifile yourself, 25660786Sps * and you'll restore it if necessary.) 25760786Sps */ 25860786Sps unsave_ifile(was_curr_ifile); 25960786Sps return (0); 26060786Sps } 26160786Sps 262128345Stjr filename = save(get_filename(ifile)); 26360786Sps /* 26460786Sps * See if LESSOPEN specifies an "alternate" file to open. 26560786Sps */ 26660786Sps alt_pipe = NULL; 26760786Sps alt_filename = open_altfile(filename, &f, &alt_pipe); 26860786Sps open_filename = (alt_filename != NULL) ? alt_filename : filename; 269128345Stjr qopen_filename = shell_unquote(open_filename); 27060786Sps 27160786Sps chflags = 0; 27260786Sps if (alt_pipe != NULL) 27360786Sps { 27460786Sps /* 27560786Sps * The alternate "file" is actually a pipe. 27660786Sps * f has already been set to the file descriptor of the pipe 27760786Sps * in the call to open_altfile above. 27860786Sps * Keep the file descriptor open because it was opened 27960786Sps * via popen(), and pclose() wants to close it. 28060786Sps */ 28160786Sps chflags |= CH_POPENED; 28260786Sps } else if (strcmp(open_filename, "-") == 0) 28360786Sps { 28460786Sps /* 28560786Sps * Use standard input. 28660786Sps * Keep the file descriptor open because we can't reopen it. 28760786Sps */ 28860786Sps f = fd0; 28960786Sps chflags |= CH_KEEPOPEN; 29060786Sps /* 29160786Sps * Must switch stdin to BINARY mode. 29260786Sps */ 29360786Sps SET_BINARY(f); 29460786Sps#if MSDOS_COMPILER==DJGPPC 29560786Sps /* 29660786Sps * Setting stdin to binary by default causes 29760786Sps * Ctrl-C to not raise SIGINT. We must undo 29860786Sps * that side-effect. 29960786Sps */ 30060786Sps __djgpp_set_ctrl_c(1); 30160786Sps#endif 30260786Sps } else if (strcmp(open_filename, FAKE_HELPFILE) == 0) 30360786Sps { 30460786Sps f = -1; 30560786Sps chflags |= CH_HELPFILE; 30660786Sps } else if ((parg.p_string = bad_file(open_filename)) != NULL) 30760786Sps { 30860786Sps /* 30960786Sps * It looks like a bad file. Don't try to open it. 31060786Sps */ 31160786Sps error("%s", &parg); 31260786Sps free(parg.p_string); 31360786Sps err1: 31460786Sps if (alt_filename != NULL) 31560786Sps { 31660786Sps close_altfile(alt_filename, filename, alt_pipe); 31760786Sps free(alt_filename); 31860786Sps } 31960786Sps del_ifile(ifile); 320128345Stjr free(qopen_filename); 32160786Sps free(filename); 32260786Sps /* 32360786Sps * Re-open the current file. 32460786Sps */ 325161475Sdelphij if (was_curr_ifile == ifile) 326161475Sdelphij { 327161475Sdelphij /* 328161475Sdelphij * Whoops. The "current" ifile is the one we just deleted. 329161475Sdelphij * Just give up. 330161475Sdelphij */ 331161475Sdelphij quit(QUIT_ERROR); 332161475Sdelphij } 33360786Sps reedit_ifile(was_curr_ifile); 33460786Sps return (1); 335128345Stjr } else if ((f = open(qopen_filename, OPEN_READ)) < 0) 33660786Sps { 33760786Sps /* 33860786Sps * Got an error trying to open it. 33960786Sps */ 34060786Sps parg.p_string = errno_message(filename); 34160786Sps error("%s", &parg); 34260786Sps free(parg.p_string); 34360786Sps goto err1; 34460786Sps } else 34560786Sps { 34660786Sps chflags |= CH_CANSEEK; 34760786Sps if (!force_open && !opened(ifile) && bin_file(f)) 34860786Sps { 34960786Sps /* 35060786Sps * Looks like a binary file. 35160786Sps * Ask user if we should proceed. 35260786Sps */ 35360786Sps parg.p_string = filename; 35460786Sps answer = query("\"%s\" may be a binary file. See it anyway? ", 35560786Sps &parg); 35660786Sps if (answer != 'y' && answer != 'Y') 35760786Sps { 35860786Sps close(f); 35960786Sps goto err1; 36060786Sps } 36160786Sps } 36260786Sps } 363128345Stjr free(qopen_filename); 36460786Sps 36560786Sps /* 36660786Sps * Get the new ifile. 36760786Sps * Get the saved position for the file. 36860786Sps */ 36960786Sps if (was_curr_ifile != NULL_IFILE) 37060786Sps { 37160786Sps old_ifile = was_curr_ifile; 37260786Sps unsave_ifile(was_curr_ifile); 37360786Sps } 37460786Sps curr_ifile = ifile; 37560786Sps curr_altfilename = alt_filename; 37660786Sps curr_altpipe = alt_pipe; 37760786Sps set_open(curr_ifile); /* File has been opened */ 37860786Sps get_pos(curr_ifile, &initial_scrpos); 37960786Sps new_file = TRUE; 38060786Sps ch_init(f, chflags); 38160786Sps 38260786Sps if (!(chflags & CH_HELPFILE)) 38360786Sps { 38460786Sps#if LOGFILE 38560786Sps if (namelogfile != NULL && is_tty) 38660786Sps use_logfile(namelogfile); 38760786Sps#endif 38860786Sps if (every_first_cmd != NULL) 38960786Sps ungetsc(every_first_cmd); 39060786Sps } 39160786Sps 39260786Sps no_display = !any_display; 39360786Sps flush(); 39460786Sps any_display = TRUE; 39560786Sps 39660786Sps if (is_tty) 39760786Sps { 39860786Sps /* 39960786Sps * Output is to a real tty. 40060786Sps */ 40160786Sps 40260786Sps /* 40360786Sps * Indicate there is nothing displayed yet. 40460786Sps */ 40560786Sps pos_clear(); 40660786Sps clr_linenum(); 40760786Sps#if HILITE_SEARCH 40860786Sps clr_hilite(); 40960786Sps#endif 41060786Sps cmd_addhist(ml_examine, filename); 41160786Sps if (no_display && errmsgs > 0) 41260786Sps { 41360786Sps /* 41460786Sps * We displayed some messages on error output 41560786Sps * (file descriptor 2; see error() function). 41660786Sps * Before erasing the screen contents, 41760786Sps * display the file name and wait for a keystroke. 41860786Sps */ 41960786Sps parg.p_string = filename; 42060786Sps error("%s", &parg); 42160786Sps } 42260786Sps } 42360786Sps free(filename); 42460786Sps return (0); 42560786Sps} 42660786Sps 42760786Sps/* 42860786Sps * Edit a space-separated list of files. 42960786Sps * For each filename in the list, enter it into the ifile list. 43060786Sps * Then edit the first one. 43160786Sps */ 43260786Sps public int 43360786Spsedit_list(filelist) 43460786Sps char *filelist; 43560786Sps{ 43660786Sps IFILE save_ifile; 43760786Sps char *good_filename; 43860786Sps char *filename; 43960786Sps char *gfilelist; 44060786Sps char *gfilename; 44160786Sps struct textlist tl_files; 44260786Sps struct textlist tl_gfiles; 44360786Sps 44460786Sps save_ifile = save_curr_ifile(); 44560786Sps good_filename = NULL; 44660786Sps 44760786Sps /* 44860786Sps * Run thru each filename in the list. 44960786Sps * Try to glob the filename. 45060786Sps * If it doesn't expand, just try to open the filename. 45160786Sps * If it does expand, try to open each name in that list. 45260786Sps */ 45360786Sps init_textlist(&tl_files, filelist); 45460786Sps filename = NULL; 45560786Sps while ((filename = forw_textlist(&tl_files, filename)) != NULL) 45660786Sps { 45760786Sps gfilelist = lglob(filename); 45860786Sps init_textlist(&tl_gfiles, gfilelist); 45960786Sps gfilename = NULL; 46060786Sps while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) 46160786Sps { 46260786Sps if (edit(gfilename) == 0 && good_filename == NULL) 46360786Sps good_filename = get_filename(curr_ifile); 46460786Sps } 46560786Sps free(gfilelist); 46660786Sps } 46760786Sps /* 46860786Sps * Edit the first valid filename in the list. 46960786Sps */ 47060786Sps if (good_filename == NULL) 47160786Sps { 47260786Sps unsave_ifile(save_ifile); 47360786Sps return (1); 47460786Sps } 47560786Sps if (get_ifile(good_filename, curr_ifile) == curr_ifile) 47660786Sps { 47760786Sps /* 47860786Sps * Trying to edit the current file; don't reopen it. 47960786Sps */ 48060786Sps unsave_ifile(save_ifile); 48160786Sps return (0); 48260786Sps } 48360786Sps reedit_ifile(save_ifile); 48460786Sps return (edit(good_filename)); 48560786Sps} 48660786Sps 48760786Sps/* 48860786Sps * Edit the first file in the command line (ifile) list. 48960786Sps */ 49060786Sps public int 49160786Spsedit_first() 49260786Sps{ 49360786Sps curr_ifile = NULL_IFILE; 49460786Sps return (edit_next(1)); 49560786Sps} 49660786Sps 49760786Sps/* 49860786Sps * Edit the last file in the command line (ifile) list. 49960786Sps */ 50060786Sps public int 50160786Spsedit_last() 50260786Sps{ 50360786Sps curr_ifile = NULL_IFILE; 50460786Sps return (edit_prev(1)); 50560786Sps} 50660786Sps 50760786Sps 50860786Sps/* 509161475Sdelphij * Edit the n-th next or previous file in the command line (ifile) list. 51060786Sps */ 51160786Sps static int 51260786Spsedit_istep(h, n, dir) 51360786Sps IFILE h; 51460786Sps int n; 51560786Sps int dir; 51660786Sps{ 51760786Sps IFILE next; 51860786Sps 51960786Sps /* 52060786Sps * Skip n filenames, then try to edit each filename. 52160786Sps */ 52260786Sps for (;;) 52360786Sps { 52460786Sps next = (dir > 0) ? next_ifile(h) : prev_ifile(h); 52560786Sps if (--n < 0) 52660786Sps { 52760786Sps if (edit_ifile(h) == 0) 52860786Sps break; 52960786Sps } 53060786Sps if (next == NULL_IFILE) 53160786Sps { 53260786Sps /* 53360786Sps * Reached end of the ifile list. 53460786Sps */ 53560786Sps return (1); 53660786Sps } 53760786Sps if (ABORT_SIGS()) 53860786Sps { 53960786Sps /* 54060786Sps * Interrupt breaks out, if we're in a long 54160786Sps * list of files that can't be opened. 54260786Sps */ 54360786Sps return (1); 54460786Sps } 54560786Sps h = next; 54660786Sps } 54760786Sps /* 54860786Sps * Found a file that we can edit. 54960786Sps */ 55060786Sps return (0); 55160786Sps} 55260786Sps 55360786Sps static int 55460786Spsedit_inext(h, n) 55560786Sps IFILE h; 55660786Sps int n; 55760786Sps{ 558161475Sdelphij return (edit_istep(h, n, +1)); 55960786Sps} 56060786Sps 56160786Sps public int 56260786Spsedit_next(n) 56360786Sps int n; 56460786Sps{ 565161475Sdelphij return edit_istep(curr_ifile, n, +1); 56660786Sps} 56760786Sps 56860786Sps static int 56960786Spsedit_iprev(h, n) 57060786Sps IFILE h; 57160786Sps int n; 57260786Sps{ 57360786Sps return (edit_istep(h, n, -1)); 57460786Sps} 57560786Sps 57660786Sps public int 57760786Spsedit_prev(n) 57860786Sps int n; 57960786Sps{ 58060786Sps return edit_istep(curr_ifile, n, -1); 58160786Sps} 58260786Sps 58360786Sps/* 58460786Sps * Edit a specific file in the command line (ifile) list. 58560786Sps */ 58660786Sps public int 58760786Spsedit_index(n) 58860786Sps int n; 58960786Sps{ 59060786Sps IFILE h; 59160786Sps 59260786Sps h = NULL_IFILE; 59360786Sps do 59460786Sps { 59560786Sps if ((h = next_ifile(h)) == NULL_IFILE) 59660786Sps { 59760786Sps /* 59860786Sps * Reached end of the list without finding it. 59960786Sps */ 60060786Sps return (1); 60160786Sps } 60260786Sps } while (get_index(h) != n); 60360786Sps 60460786Sps return (edit_ifile(h)); 60560786Sps} 60660786Sps 60760786Sps public IFILE 60860786Spssave_curr_ifile() 60960786Sps{ 61060786Sps if (curr_ifile != NULL_IFILE) 61160786Sps hold_ifile(curr_ifile, 1); 61260786Sps return (curr_ifile); 61360786Sps} 61460786Sps 61560786Sps public void 61660786Spsunsave_ifile(save_ifile) 61760786Sps IFILE save_ifile; 61860786Sps{ 61960786Sps if (save_ifile != NULL_IFILE) 62060786Sps hold_ifile(save_ifile, -1); 62160786Sps} 62260786Sps 62360786Sps/* 62460786Sps * Reedit the ifile which was previously open. 62560786Sps */ 62660786Sps public void 62760786Spsreedit_ifile(save_ifile) 62860786Sps IFILE save_ifile; 62960786Sps{ 63060786Sps IFILE next; 63160786Sps IFILE prev; 63260786Sps 63360786Sps /* 63460786Sps * Try to reopen the ifile. 63560786Sps * Note that opening it may fail (maybe the file was removed), 63660786Sps * in which case the ifile will be deleted from the list. 63760786Sps * So save the next and prev ifiles first. 63860786Sps */ 63960786Sps unsave_ifile(save_ifile); 64060786Sps next = next_ifile(save_ifile); 64160786Sps prev = prev_ifile(save_ifile); 64260786Sps if (edit_ifile(save_ifile) == 0) 64360786Sps return; 64460786Sps /* 64560786Sps * If can't reopen it, open the next input file in the list. 64660786Sps */ 64760786Sps if (next != NULL_IFILE && edit_inext(next, 0) == 0) 64860786Sps return; 64960786Sps /* 65060786Sps * If can't open THAT one, open the previous input file in the list. 65160786Sps */ 65260786Sps if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0) 65360786Sps return; 65460786Sps /* 65560786Sps * If can't even open that, we're stuck. Just quit. 65660786Sps */ 65760786Sps quit(QUIT_ERROR); 65860786Sps} 65960786Sps 66060786Sps/* 66160786Sps * Edit standard input. 66260786Sps */ 66360786Sps public int 66460786Spsedit_stdin() 66560786Sps{ 66660786Sps if (isatty(fd0)) 66760786Sps { 66860786Sps error("Missing filename (\"less --help\" for help)", NULL_PARG); 66960786Sps quit(QUIT_OK); 67060786Sps } 67160786Sps return (edit("-")); 67260786Sps} 67360786Sps 67460786Sps/* 67560786Sps * Copy a file directly to standard output. 67660786Sps * Used if standard output is not a tty. 67760786Sps */ 67860786Sps public void 67960786Spscat_file() 68060786Sps{ 68160786Sps register int c; 68260786Sps 68360786Sps while ((c = ch_forw_get()) != EOI) 68460786Sps putchr(c); 68560786Sps flush(); 68660786Sps} 68760786Sps 68860786Sps#if LOGFILE 68960786Sps 69060786Sps/* 69160786Sps * If the user asked for a log file and our input file 69260786Sps * is standard input, create the log file. 69360786Sps * We take care not to blindly overwrite an existing file. 69460786Sps */ 69560786Sps public void 69660786Spsuse_logfile(filename) 69760786Sps char *filename; 69860786Sps{ 69960786Sps register int exists; 70060786Sps register int answer; 70160786Sps PARG parg; 70260786Sps 70360786Sps if (ch_getflags() & CH_CANSEEK) 70460786Sps /* 70560786Sps * Can't currently use a log file on a file that can seek. 70660786Sps */ 70760786Sps return; 70860786Sps 70960786Sps /* 71060786Sps * {{ We could use access() here. }} 71160786Sps */ 712128345Stjr filename = shell_unquote(filename); 71360786Sps exists = open(filename, OPEN_READ); 71460786Sps close(exists); 71560786Sps exists = (exists >= 0); 71660786Sps 71760786Sps /* 71860786Sps * Decide whether to overwrite the log file or append to it. 71960786Sps * If it doesn't exist we "overwrite" it. 72060786Sps */ 72160786Sps if (!exists || force_logfile) 72260786Sps { 72360786Sps /* 72460786Sps * Overwrite (or create) the log file. 72560786Sps */ 72660786Sps answer = 'O'; 72760786Sps } else 72860786Sps { 72960786Sps /* 73060786Sps * Ask user what to do. 73160786Sps */ 73260786Sps parg.p_string = filename; 73360786Sps answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg); 73460786Sps } 73560786Sps 73660786Spsloop: 73760786Sps switch (answer) 73860786Sps { 73960786Sps case 'O': case 'o': 74060786Sps /* 74160786Sps * Overwrite: create the file. 74260786Sps */ 74360786Sps logfile = creat(filename, 0644); 74460786Sps break; 74560786Sps case 'A': case 'a': 74660786Sps /* 74760786Sps * Append: open the file and seek to the end. 74860786Sps */ 74960786Sps logfile = open(filename, OPEN_APPEND); 75060786Sps if (lseek(logfile, (off_t)0, 2) == BAD_LSEEK) 75160786Sps { 75260786Sps close(logfile); 75360786Sps logfile = -1; 75460786Sps } 75560786Sps break; 75660786Sps case 'D': case 'd': 75760786Sps /* 75860786Sps * Don't do anything. 75960786Sps */ 76060786Sps free(filename); 76160786Sps return; 76260786Sps case 'q': 76360786Sps quit(QUIT_OK); 76460786Sps /*NOTREACHED*/ 76560786Sps default: 76660786Sps /* 76760786Sps * Eh? 76860786Sps */ 76960786Sps answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG); 77060786Sps goto loop; 77160786Sps } 77260786Sps 77360786Sps if (logfile < 0) 77460786Sps { 77560786Sps /* 77660786Sps * Error in opening logfile. 77760786Sps */ 77860786Sps parg.p_string = filename; 77960786Sps error("Cannot write to \"%s\"", &parg); 78060786Sps free(filename); 78160786Sps return; 78260786Sps } 78360786Sps free(filename); 78460786Sps SET_BINARY(logfile); 78560786Sps} 78660786Sps 78760786Sps#endif 788