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