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