1238730Sdelphij/* 2330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps#include "less.h" 12330571Sdelphij#include "position.h" 13173682Sdelphij#if HAVE_STAT 14173682Sdelphij#include <sys/stat.h> 15173682Sdelphij#endif 16330571Sdelphij#if OS2 17330571Sdelphij#include <signal.h> 18330571Sdelphij#endif 1960786Sps 2060786Spspublic int fd0 = 0; 2160786Sps 2260786Spsextern int new_file; 2360786Spsextern int errmsgs; 2460786Spsextern int cbufs; 2560786Spsextern char *every_first_cmd; 2660786Spsextern int any_display; 2760786Spsextern int force_open; 2860786Spsextern int is_tty; 2960786Spsextern int sigs; 3060786Spsextern IFILE curr_ifile; 3160786Spsextern IFILE old_ifile; 3260786Spsextern struct scrpos initial_scrpos; 33330571Sdelphijextern void *ml_examine; 3460786Sps#if SPACES_IN_FILENAMES 3560786Spsextern char openquote; 3660786Spsextern char closequote; 3760786Sps#endif 3860786Sps 3960786Sps#if LOGFILE 4060786Spsextern int logfile; 4160786Spsextern int force_logfile; 4260786Spsextern char *namelogfile; 4360786Sps#endif 4460786Sps 45173682Sdelphij#if HAVE_STAT_INO 46173682Sdelphijpublic dev_t curr_dev; 47173682Sdelphijpublic ino_t curr_ino; 48173682Sdelphij#endif 49173682Sdelphij 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(); 68294286Sdelphij int esclen = (int) 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/* 153330571Sdelphij * Close a pipe opened via popen. 154330571Sdelphij */ 155330571Sdelphij static void 156330571Sdelphijclose_pipe(FILE *pipefd) 157330571Sdelphij{ 158330571Sdelphij if (pipefd == NULL) 159330571Sdelphij return; 160330571Sdelphij#if OS2 161330571Sdelphij /* 162330571Sdelphij * The pclose function of OS/2 emx sometimes fails. 163330571Sdelphij * Send SIGINT to the piped process before closing it. 164330571Sdelphij */ 165330571Sdelphij kill(pipefd->_pid, SIGINT); 166330571Sdelphij#endif 167330571Sdelphij pclose(pipefd); 168330571Sdelphij} 169330571Sdelphij 170330571Sdelphij/* 17160786Sps * Close the current input file. 17260786Sps */ 17360786Sps static void 17460786Spsclose_file() 17560786Sps{ 17660786Sps struct scrpos scrpos; 177330571Sdelphij int chflags; 178330571Sdelphij FILE *altpipe; 179330571Sdelphij char *altfilename; 18060786Sps 18160786Sps if (curr_ifile == NULL_IFILE) 18260786Sps return; 18360786Sps 18460786Sps /* 18560786Sps * Save the current position so that we can return to 18660786Sps * the same position if we edit this file again. 18760786Sps */ 188330571Sdelphij get_scrpos(&scrpos, TOP); 18960786Sps if (scrpos.pos != NULL_POSITION) 19060786Sps { 19160786Sps store_pos(curr_ifile, &scrpos); 19260786Sps lastmark(); 19360786Sps } 19460786Sps /* 19560786Sps * Close the file descriptor, unless it is a pipe. 19660786Sps */ 197330571Sdelphij chflags = ch_getflags(); 19860786Sps ch_close(); 19960786Sps /* 20060786Sps * If we opened a file using an alternate name, 20160786Sps * do special stuff to close it. 20260786Sps */ 203330571Sdelphij altfilename = get_altfilename(curr_ifile); 204330571Sdelphij if (altfilename != NULL) 20560786Sps { 206330571Sdelphij altpipe = get_altpipe(curr_ifile); 207330571Sdelphij if (altpipe != NULL && !(chflags & CH_KEEPOPEN)) 208330571Sdelphij { 209330571Sdelphij close_pipe(altpipe); 210330571Sdelphij set_altpipe(curr_ifile, NULL); 211330571Sdelphij } 212330571Sdelphij close_altfile(altfilename, get_filename(curr_ifile)); 213330571Sdelphij set_altfilename(curr_ifile, NULL); 21460786Sps } 21560786Sps curr_ifile = NULL_IFILE; 216173682Sdelphij#if HAVE_STAT_INO 217173682Sdelphij curr_ino = curr_dev = 0; 218173682Sdelphij#endif 21960786Sps} 22060786Sps 22160786Sps/* 22260786Sps * Edit a new file (given its name). 22360786Sps * Filename == "-" means standard input. 22460786Sps * Filename == NULL means just close the current file. 22560786Sps */ 22660786Sps public int 22760786Spsedit(filename) 22860786Sps char *filename; 22960786Sps{ 23060786Sps if (filename == NULL) 23160786Sps return (edit_ifile(NULL_IFILE)); 23260786Sps return (edit_ifile(get_ifile(filename, curr_ifile))); 23360786Sps} 23460786Sps 23560786Sps/* 23660786Sps * Edit a new file (given its IFILE). 23760786Sps * ifile == NULL means just close the current file. 23860786Sps */ 23960786Sps public int 24060786Spsedit_ifile(ifile) 24160786Sps IFILE ifile; 24260786Sps{ 24360786Sps int f; 24460786Sps int answer; 24560786Sps int no_display; 24660786Sps int chflags; 24760786Sps char *filename; 24860786Sps char *open_filename; 24960786Sps char *alt_filename; 250330571Sdelphij void *altpipe; 25160786Sps IFILE was_curr_ifile; 25260786Sps PARG parg; 25360786Sps 25460786Sps if (ifile == curr_ifile) 25560786Sps { 25660786Sps /* 25760786Sps * Already have the correct file open. 25860786Sps */ 25960786Sps return (0); 26060786Sps } 26160786Sps 26260786Sps /* 26360786Sps * We must close the currently open file now. 26460786Sps * This is necessary to make the open_altfile/close_altfile pairs 26560786Sps * nest properly (or rather to avoid nesting at all). 26660786Sps * {{ Some stupid implementations of popen() mess up if you do: 26760786Sps * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }} 26860786Sps */ 26960786Sps#if LOGFILE 27060786Sps end_logfile(); 27160786Sps#endif 27260786Sps was_curr_ifile = save_curr_ifile(); 27360786Sps if (curr_ifile != NULL_IFILE) 27460786Sps { 27560786Sps chflags = ch_getflags(); 27660786Sps close_file(); 27760786Sps if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1) 27860786Sps { 27960786Sps /* 28060786Sps * Don't keep the help file in the ifile list. 28160786Sps */ 28260786Sps del_ifile(was_curr_ifile); 28360786Sps was_curr_ifile = old_ifile; 28460786Sps } 28560786Sps } 28660786Sps 28760786Sps if (ifile == NULL_IFILE) 28860786Sps { 28960786Sps /* 29060786Sps * No new file to open. 29160786Sps * (Don't set old_ifile, because if you call edit_ifile(NULL), 29260786Sps * you're supposed to have saved curr_ifile yourself, 29360786Sps * and you'll restore it if necessary.) 29460786Sps */ 29560786Sps unsave_ifile(was_curr_ifile); 29660786Sps return (0); 29760786Sps } 29860786Sps 299128345Stjr filename = save(get_filename(ifile)); 300330571Sdelphij 30160786Sps /* 30260786Sps * See if LESSOPEN specifies an "alternate" file to open. 30360786Sps */ 304330571Sdelphij altpipe = get_altpipe(ifile); 305330571Sdelphij if (altpipe != NULL) 30660786Sps { 30760786Sps /* 308330571Sdelphij * File is already open. 309330571Sdelphij * chflags and f are not used by ch_init if ifile has 310330571Sdelphij * filestate which should be the case if we're here. 311330571Sdelphij * Set them here to avoid uninitialized variable warnings. 31260786Sps */ 313330571Sdelphij chflags = 0; 314330571Sdelphij f = -1; 315330571Sdelphij alt_filename = get_altfilename(ifile); 316330571Sdelphij open_filename = (alt_filename != NULL) ? alt_filename : filename; 317330571Sdelphij } else 31860786Sps { 319330571Sdelphij if (strcmp(filename, FAKE_HELPFILE) == 0 || 320330571Sdelphij strcmp(filename, FAKE_EMPTYFILE) == 0) 321330571Sdelphij alt_filename = NULL; 322330571Sdelphij else 323330571Sdelphij alt_filename = open_altfile(filename, &f, &altpipe); 324330571Sdelphij 325330571Sdelphij open_filename = (alt_filename != NULL) ? alt_filename : filename; 326330571Sdelphij 327330571Sdelphij chflags = 0; 328330571Sdelphij if (altpipe != NULL) 329330571Sdelphij { 330330571Sdelphij /* 331330571Sdelphij * The alternate "file" is actually a pipe. 332330571Sdelphij * f has already been set to the file descriptor of the pipe 333330571Sdelphij * in the call to open_altfile above. 334330571Sdelphij * Keep the file descriptor open because it was opened 335330571Sdelphij * via popen(), and pclose() wants to close it. 336330571Sdelphij */ 337330571Sdelphij chflags |= CH_POPENED; 338330571Sdelphij if (strcmp(filename, "-") == 0) 339330571Sdelphij chflags |= CH_KEEPOPEN; 340330571Sdelphij } else if (strcmp(filename, "-") == 0) 341330571Sdelphij { 342330571Sdelphij /* 343330571Sdelphij * Use standard input. 344330571Sdelphij * Keep the file descriptor open because we can't reopen it. 345330571Sdelphij */ 346330571Sdelphij f = fd0; 347330571Sdelphij chflags |= CH_KEEPOPEN; 348330571Sdelphij /* 349330571Sdelphij * Must switch stdin to BINARY mode. 350330571Sdelphij */ 351330571Sdelphij SET_BINARY(f); 35260786Sps#if MSDOS_COMPILER==DJGPPC 353330571Sdelphij /* 354330571Sdelphij * Setting stdin to binary by default causes 355330571Sdelphij * Ctrl-C to not raise SIGINT. We must undo 356330571Sdelphij * that side-effect. 357330571Sdelphij */ 358330571Sdelphij __djgpp_set_ctrl_c(1); 35960786Sps#endif 360330571Sdelphij } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0) 36160786Sps { 362330571Sdelphij f = -1; 363330571Sdelphij chflags |= CH_NODATA; 364330571Sdelphij } else if (strcmp(open_filename, FAKE_HELPFILE) == 0) 365161475Sdelphij { 366330571Sdelphij f = -1; 367330571Sdelphij chflags |= CH_HELPFILE; 368330571Sdelphij } else if ((parg.p_string = bad_file(open_filename)) != NULL) 369330571Sdelphij { 370161475Sdelphij /* 371330571Sdelphij * It looks like a bad file. Don't try to open it. 372161475Sdelphij */ 373330571Sdelphij error("%s", &parg); 374330571Sdelphij free(parg.p_string); 375330571Sdelphij err1: 376330571Sdelphij if (alt_filename != NULL) 377330571Sdelphij { 378330571Sdelphij close_pipe(altpipe); 379330571Sdelphij close_altfile(alt_filename, filename); 380330571Sdelphij free(alt_filename); 381330571Sdelphij } 382330571Sdelphij del_ifile(ifile); 383330571Sdelphij free(filename); 384330571Sdelphij /* 385330571Sdelphij * Re-open the current file. 386330571Sdelphij */ 387330571Sdelphij if (was_curr_ifile == ifile) 388330571Sdelphij { 389330571Sdelphij /* 390330571Sdelphij * Whoops. The "current" ifile is the one we just deleted. 391330571Sdelphij * Just give up. 392330571Sdelphij */ 393330571Sdelphij quit(QUIT_ERROR); 394330571Sdelphij } 395330571Sdelphij reedit_ifile(was_curr_ifile); 396330571Sdelphij return (1); 397330571Sdelphij } else if ((f = open(open_filename, OPEN_READ)) < 0) 39860786Sps { 39960786Sps /* 400330571Sdelphij * Got an error trying to open it. 40160786Sps */ 402330571Sdelphij parg.p_string = errno_message(filename); 403330571Sdelphij error("%s", &parg); 404330571Sdelphij free(parg.p_string); 405330571Sdelphij goto err1; 406330571Sdelphij } else 407330571Sdelphij { 408330571Sdelphij chflags |= CH_CANSEEK; 409330571Sdelphij if (!force_open && !opened(ifile) && bin_file(f)) 41060786Sps { 411330571Sdelphij /* 412330571Sdelphij * Looks like a binary file. 413330571Sdelphij * Ask user if we should proceed. 414330571Sdelphij */ 415330571Sdelphij parg.p_string = filename; 416330571Sdelphij answer = query("\"%s\" may be a binary file. See it anyway? ", 417330571Sdelphij &parg); 418330571Sdelphij if (answer != 'y' && answer != 'Y') 419330571Sdelphij { 420330571Sdelphij close(f); 421330571Sdelphij goto err1; 422330571Sdelphij } 42360786Sps } 42460786Sps } 42560786Sps } 42660786Sps 42760786Sps /* 42860786Sps * Get the new ifile. 42960786Sps * Get the saved position for the file. 43060786Sps */ 43160786Sps if (was_curr_ifile != NULL_IFILE) 43260786Sps { 43360786Sps old_ifile = was_curr_ifile; 43460786Sps unsave_ifile(was_curr_ifile); 43560786Sps } 43660786Sps curr_ifile = ifile; 437330571Sdelphij set_altfilename(curr_ifile, alt_filename); 438330571Sdelphij set_altpipe(curr_ifile, altpipe); 43960786Sps set_open(curr_ifile); /* File has been opened */ 44060786Sps get_pos(curr_ifile, &initial_scrpos); 44160786Sps new_file = TRUE; 44260786Sps ch_init(f, chflags); 44360786Sps 44460786Sps if (!(chflags & CH_HELPFILE)) 44560786Sps { 44660786Sps#if LOGFILE 44760786Sps if (namelogfile != NULL && is_tty) 44860786Sps use_logfile(namelogfile); 44960786Sps#endif 450173682Sdelphij#if HAVE_STAT_INO 451173682Sdelphij /* Remember the i-number and device of the opened file. */ 452330571Sdelphij if (strcmp(open_filename, "-") != 0) 453173682Sdelphij { 454173682Sdelphij struct stat statbuf; 455330571Sdelphij int r = stat(open_filename, &statbuf); 456173682Sdelphij if (r == 0) 457173682Sdelphij { 458173682Sdelphij curr_ino = statbuf.st_ino; 459173682Sdelphij curr_dev = statbuf.st_dev; 460173682Sdelphij } 461173682Sdelphij } 462173682Sdelphij#endif 46360786Sps if (every_first_cmd != NULL) 464294286Sdelphij { 465294286Sdelphij ungetcc(CHAR_END_COMMAND); 46660786Sps ungetsc(every_first_cmd); 467294286Sdelphij } 46860786Sps } 46960786Sps 47060786Sps no_display = !any_display; 47160786Sps flush(); 47260786Sps any_display = TRUE; 47360786Sps 47460786Sps if (is_tty) 47560786Sps { 47660786Sps /* 47760786Sps * Output is to a real tty. 47860786Sps */ 47960786Sps 48060786Sps /* 48160786Sps * Indicate there is nothing displayed yet. 48260786Sps */ 48360786Sps pos_clear(); 48460786Sps clr_linenum(); 48560786Sps#if HILITE_SEARCH 48660786Sps clr_hilite(); 48760786Sps#endif 488294286Sdelphij if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE)) 489294286Sdelphij cmd_addhist(ml_examine, filename, 1); 49060786Sps if (no_display && errmsgs > 0) 49160786Sps { 49260786Sps /* 49360786Sps * We displayed some messages on error output 49460786Sps * (file descriptor 2; see error() function). 49560786Sps * Before erasing the screen contents, 49660786Sps * display the file name and wait for a keystroke. 49760786Sps */ 49860786Sps parg.p_string = filename; 49960786Sps error("%s", &parg); 50060786Sps } 50160786Sps } 50260786Sps free(filename); 50360786Sps return (0); 50460786Sps} 50560786Sps 50660786Sps/* 50760786Sps * Edit a space-separated list of files. 50860786Sps * For each filename in the list, enter it into the ifile list. 50960786Sps * Then edit the first one. 51060786Sps */ 51160786Sps public int 51260786Spsedit_list(filelist) 51360786Sps char *filelist; 51460786Sps{ 51560786Sps IFILE save_ifile; 51660786Sps char *good_filename; 51760786Sps char *filename; 51860786Sps char *gfilelist; 51960786Sps char *gfilename; 520330571Sdelphij char *qfilename; 52160786Sps struct textlist tl_files; 52260786Sps struct textlist tl_gfiles; 52360786Sps 52460786Sps save_ifile = save_curr_ifile(); 52560786Sps good_filename = NULL; 52660786Sps 52760786Sps /* 52860786Sps * Run thru each filename in the list. 52960786Sps * Try to glob the filename. 53060786Sps * If it doesn't expand, just try to open the filename. 53160786Sps * If it does expand, try to open each name in that list. 53260786Sps */ 53360786Sps init_textlist(&tl_files, filelist); 53460786Sps filename = NULL; 53560786Sps while ((filename = forw_textlist(&tl_files, filename)) != NULL) 53660786Sps { 53760786Sps gfilelist = lglob(filename); 53860786Sps init_textlist(&tl_gfiles, gfilelist); 53960786Sps gfilename = NULL; 54060786Sps while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) 54160786Sps { 542330571Sdelphij qfilename = shell_unquote(gfilename); 543330571Sdelphij if (edit(qfilename) == 0 && good_filename == NULL) 54460786Sps good_filename = get_filename(curr_ifile); 545330571Sdelphij free(qfilename); 54660786Sps } 54760786Sps free(gfilelist); 54860786Sps } 54960786Sps /* 55060786Sps * Edit the first valid filename in the list. 55160786Sps */ 55260786Sps if (good_filename == NULL) 55360786Sps { 55460786Sps unsave_ifile(save_ifile); 55560786Sps return (1); 55660786Sps } 55760786Sps if (get_ifile(good_filename, curr_ifile) == curr_ifile) 55860786Sps { 55960786Sps /* 56060786Sps * Trying to edit the current file; don't reopen it. 56160786Sps */ 56260786Sps unsave_ifile(save_ifile); 56360786Sps return (0); 56460786Sps } 56560786Sps reedit_ifile(save_ifile); 56660786Sps return (edit(good_filename)); 56760786Sps} 56860786Sps 56960786Sps/* 57060786Sps * Edit the first file in the command line (ifile) list. 57160786Sps */ 57260786Sps public int 57360786Spsedit_first() 57460786Sps{ 57560786Sps curr_ifile = NULL_IFILE; 57660786Sps return (edit_next(1)); 57760786Sps} 57860786Sps 57960786Sps/* 58060786Sps * Edit the last file in the command line (ifile) list. 58160786Sps */ 58260786Sps public int 58360786Spsedit_last() 58460786Sps{ 58560786Sps curr_ifile = NULL_IFILE; 58660786Sps return (edit_prev(1)); 58760786Sps} 58860786Sps 58960786Sps 59060786Sps/* 591161475Sdelphij * Edit the n-th next or previous file in the command line (ifile) list. 59260786Sps */ 59360786Sps static int 59460786Spsedit_istep(h, n, dir) 59560786Sps IFILE h; 59660786Sps int n; 59760786Sps int dir; 59860786Sps{ 59960786Sps IFILE next; 60060786Sps 60160786Sps /* 60260786Sps * Skip n filenames, then try to edit each filename. 60360786Sps */ 60460786Sps for (;;) 60560786Sps { 60660786Sps next = (dir > 0) ? next_ifile(h) : prev_ifile(h); 60760786Sps if (--n < 0) 60860786Sps { 60960786Sps if (edit_ifile(h) == 0) 61060786Sps break; 61160786Sps } 61260786Sps if (next == NULL_IFILE) 61360786Sps { 61460786Sps /* 61560786Sps * Reached end of the ifile list. 61660786Sps */ 61760786Sps return (1); 61860786Sps } 61960786Sps if (ABORT_SIGS()) 62060786Sps { 62160786Sps /* 62260786Sps * Interrupt breaks out, if we're in a long 62360786Sps * list of files that can't be opened. 62460786Sps */ 62560786Sps return (1); 62660786Sps } 62760786Sps h = next; 62860786Sps } 62960786Sps /* 63060786Sps * Found a file that we can edit. 63160786Sps */ 63260786Sps return (0); 63360786Sps} 63460786Sps 63560786Sps static int 63660786Spsedit_inext(h, n) 63760786Sps IFILE h; 63860786Sps int n; 63960786Sps{ 640161475Sdelphij return (edit_istep(h, n, +1)); 64160786Sps} 64260786Sps 64360786Sps public int 64460786Spsedit_next(n) 64560786Sps int n; 64660786Sps{ 647161475Sdelphij return edit_istep(curr_ifile, n, +1); 64860786Sps} 64960786Sps 65060786Sps static int 65160786Spsedit_iprev(h, n) 65260786Sps IFILE h; 65360786Sps int n; 65460786Sps{ 65560786Sps return (edit_istep(h, n, -1)); 65660786Sps} 65760786Sps 65860786Sps public int 65960786Spsedit_prev(n) 66060786Sps int n; 66160786Sps{ 66260786Sps return edit_istep(curr_ifile, n, -1); 66360786Sps} 66460786Sps 66560786Sps/* 66660786Sps * Edit a specific file in the command line (ifile) list. 66760786Sps */ 66860786Sps public int 66960786Spsedit_index(n) 67060786Sps int n; 67160786Sps{ 67260786Sps IFILE h; 67360786Sps 67460786Sps h = NULL_IFILE; 67560786Sps do 67660786Sps { 67760786Sps if ((h = next_ifile(h)) == NULL_IFILE) 67860786Sps { 67960786Sps /* 68060786Sps * Reached end of the list without finding it. 68160786Sps */ 68260786Sps return (1); 68360786Sps } 68460786Sps } while (get_index(h) != n); 68560786Sps 68660786Sps return (edit_ifile(h)); 68760786Sps} 68860786Sps 68960786Sps public IFILE 69060786Spssave_curr_ifile() 69160786Sps{ 69260786Sps if (curr_ifile != NULL_IFILE) 69360786Sps hold_ifile(curr_ifile, 1); 69460786Sps return (curr_ifile); 69560786Sps} 69660786Sps 69760786Sps public void 69860786Spsunsave_ifile(save_ifile) 69960786Sps IFILE save_ifile; 70060786Sps{ 70160786Sps if (save_ifile != NULL_IFILE) 70260786Sps hold_ifile(save_ifile, -1); 70360786Sps} 70460786Sps 70560786Sps/* 70660786Sps * Reedit the ifile which was previously open. 70760786Sps */ 70860786Sps public void 70960786Spsreedit_ifile(save_ifile) 71060786Sps IFILE save_ifile; 71160786Sps{ 71260786Sps IFILE next; 71360786Sps IFILE prev; 71460786Sps 71560786Sps /* 71660786Sps * Try to reopen the ifile. 71760786Sps * Note that opening it may fail (maybe the file was removed), 71860786Sps * in which case the ifile will be deleted from the list. 71960786Sps * So save the next and prev ifiles first. 72060786Sps */ 72160786Sps unsave_ifile(save_ifile); 72260786Sps next = next_ifile(save_ifile); 72360786Sps prev = prev_ifile(save_ifile); 72460786Sps if (edit_ifile(save_ifile) == 0) 72560786Sps return; 72660786Sps /* 72760786Sps * If can't reopen it, open the next input file in the list. 72860786Sps */ 72960786Sps if (next != NULL_IFILE && edit_inext(next, 0) == 0) 73060786Sps return; 73160786Sps /* 73260786Sps * If can't open THAT one, open the previous input file in the list. 73360786Sps */ 73460786Sps if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0) 73560786Sps return; 73660786Sps /* 73760786Sps * If can't even open that, we're stuck. Just quit. 73860786Sps */ 73960786Sps quit(QUIT_ERROR); 74060786Sps} 74160786Sps 742173682Sdelphij public void 743173682Sdelphijreopen_curr_ifile() 744173682Sdelphij{ 745173682Sdelphij IFILE save_ifile = save_curr_ifile(); 746173682Sdelphij close_file(); 747173682Sdelphij reedit_ifile(save_ifile); 748173682Sdelphij} 749173682Sdelphij 75060786Sps/* 75160786Sps * Edit standard input. 75260786Sps */ 75360786Sps public int 75460786Spsedit_stdin() 75560786Sps{ 75660786Sps if (isatty(fd0)) 75760786Sps { 75860786Sps error("Missing filename (\"less --help\" for help)", NULL_PARG); 75960786Sps quit(QUIT_OK); 76060786Sps } 76160786Sps return (edit("-")); 76260786Sps} 76360786Sps 76460786Sps/* 76560786Sps * Copy a file directly to standard output. 76660786Sps * Used if standard output is not a tty. 76760786Sps */ 76860786Sps public void 76960786Spscat_file() 77060786Sps{ 771330571Sdelphij int c; 77260786Sps 77360786Sps while ((c = ch_forw_get()) != EOI) 77460786Sps putchr(c); 77560786Sps flush(); 77660786Sps} 77760786Sps 77860786Sps#if LOGFILE 77960786Sps 78060786Sps/* 78160786Sps * If the user asked for a log file and our input file 78260786Sps * is standard input, create the log file. 78360786Sps * We take care not to blindly overwrite an existing file. 78460786Sps */ 78560786Sps public void 78660786Spsuse_logfile(filename) 78760786Sps char *filename; 78860786Sps{ 789330571Sdelphij int exists; 790330571Sdelphij int answer; 79160786Sps PARG parg; 79260786Sps 79360786Sps if (ch_getflags() & CH_CANSEEK) 79460786Sps /* 79560786Sps * Can't currently use a log file on a file that can seek. 79660786Sps */ 79760786Sps return; 79860786Sps 79960786Sps /* 80060786Sps * {{ We could use access() here. }} 80160786Sps */ 80260786Sps exists = open(filename, OPEN_READ); 803294286Sdelphij if (exists >= 0) 804294286Sdelphij close(exists); 80560786Sps exists = (exists >= 0); 80660786Sps 80760786Sps /* 80860786Sps * Decide whether to overwrite the log file or append to it. 80960786Sps * If it doesn't exist we "overwrite" it. 81060786Sps */ 81160786Sps if (!exists || force_logfile) 81260786Sps { 81360786Sps /* 81460786Sps * Overwrite (or create) the log file. 81560786Sps */ 81660786Sps answer = 'O'; 81760786Sps } else 81860786Sps { 81960786Sps /* 82060786Sps * Ask user what to do. 82160786Sps */ 82260786Sps parg.p_string = filename; 82360786Sps answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg); 82460786Sps } 82560786Sps 82660786Spsloop: 82760786Sps switch (answer) 82860786Sps { 82960786Sps case 'O': case 'o': 83060786Sps /* 83160786Sps * Overwrite: create the file. 83260786Sps */ 83360786Sps logfile = creat(filename, 0644); 83460786Sps break; 83560786Sps case 'A': case 'a': 83660786Sps /* 83760786Sps * Append: open the file and seek to the end. 83860786Sps */ 83960786Sps logfile = open(filename, OPEN_APPEND); 840173682Sdelphij if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK) 84160786Sps { 84260786Sps close(logfile); 84360786Sps logfile = -1; 84460786Sps } 84560786Sps break; 84660786Sps case 'D': case 'd': 84760786Sps /* 84860786Sps * Don't do anything. 84960786Sps */ 85060786Sps free(filename); 85160786Sps return; 85260786Sps case 'q': 85360786Sps quit(QUIT_OK); 85460786Sps /*NOTREACHED*/ 85560786Sps default: 85660786Sps /* 85760786Sps * Eh? 85860786Sps */ 85960786Sps answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG); 86060786Sps goto loop; 86160786Sps } 86260786Sps 86360786Sps if (logfile < 0) 86460786Sps { 86560786Sps /* 86660786Sps * Error in opening logfile. 86760786Sps */ 86860786Sps parg.p_string = filename; 86960786Sps error("Cannot write to \"%s\"", &parg); 87060786Sps return; 87160786Sps } 87260786Sps SET_BINARY(logfile); 87360786Sps} 87460786Sps 87560786Sps#endif 876