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