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