xref: /netbsd-src/external/bsd/less/dist/edit.c (revision 838f5788460f0f133b15d706e644d692a9d4d6ec)
1*838f5788Ssimonb /*	$NetBSD: edit.c,v 1.5 2023/10/06 05:49:49 simonb Exp $	*/
220006a0bStron 
320006a0bStron /*
4*838f5788Ssimonb  * Copyright (C) 1984-2023  Mark Nudelman
520006a0bStron  *
620006a0bStron  * You may distribute under the terms of either the GNU General Public
720006a0bStron  * License or the Less License, as specified in the README file.
820006a0bStron  *
9ec18bca0Stron  * For more information, see the README file.
1020006a0bStron  */
1120006a0bStron 
1220006a0bStron 
1320006a0bStron #include "less.h"
14*838f5788Ssimonb #include "position.h"
1520006a0bStron #if HAVE_STAT
1620006a0bStron #include <sys/stat.h>
1720006a0bStron #endif
18*838f5788Ssimonb #if HAVE_SYS_WAIT_H
19*838f5788Ssimonb #include <sys/wait.h>
20*838f5788Ssimonb #endif
21*838f5788Ssimonb /* #if OS2     XXX should add a HAVE_SIGNAL_H */
22*838f5788Ssimonb #include <signal.h>
23*838f5788Ssimonb /* #endif      XXX should add a HAVE_SIGNAL_H */
2420006a0bStron 
2520006a0bStron public int fd0 = 0;
2620006a0bStron 
2720006a0bStron extern int new_file;
2820006a0bStron extern int cbufs;
2920006a0bStron extern char *every_first_cmd;
3020006a0bStron extern int force_open;
3120006a0bStron extern int is_tty;
3220006a0bStron extern int sigs;
33*838f5788Ssimonb extern int hshift;
34*838f5788Ssimonb extern int want_filesize;
35*838f5788Ssimonb extern int consecutive_nulls;
36*838f5788Ssimonb extern int modelines;
37*838f5788Ssimonb extern int show_preproc_error;
3820006a0bStron extern IFILE curr_ifile;
3920006a0bStron extern IFILE old_ifile;
4020006a0bStron extern struct scrpos initial_scrpos;
41*838f5788Ssimonb extern void *ml_examine;
4220006a0bStron #if SPACES_IN_FILENAMES
4320006a0bStron extern char openquote;
4420006a0bStron extern char closequote;
4520006a0bStron #endif
4620006a0bStron 
4720006a0bStron #if LOGFILE
4820006a0bStron extern int logfile;
4920006a0bStron extern int force_logfile;
5020006a0bStron extern char *namelogfile;
5120006a0bStron #endif
5220006a0bStron 
5320006a0bStron #if HAVE_STAT_INO
5420006a0bStron public dev_t curr_dev;
5520006a0bStron public ino_t curr_ino;
5620006a0bStron #endif
5720006a0bStron 
5820006a0bStron /*
5920006a0bStron  * Textlist functions deal with a list of words separated by spaces.
6020006a0bStron  * init_textlist sets up a textlist structure.
6120006a0bStron  * forw_textlist uses that structure to iterate thru the list of
6220006a0bStron  * words, returning each one as a standard null-terminated string.
6320006a0bStron  * back_textlist does the same, but runs thru the list backwards.
6420006a0bStron  */
init_textlist(struct textlist * tlist,char * str)65*838f5788Ssimonb public void init_textlist(struct textlist *tlist, char *str)
6620006a0bStron {
6720006a0bStron 	char *s;
6820006a0bStron #if SPACES_IN_FILENAMES
6920006a0bStron 	int meta_quoted = 0;
7020006a0bStron 	int delim_quoted = 0;
7120006a0bStron 	char *esc = get_meta_escape();
72*838f5788Ssimonb 	int esclen = (int) strlen(esc);
7320006a0bStron #endif
7420006a0bStron 
7520006a0bStron 	tlist->string = skipsp(str);
7620006a0bStron 	tlist->endstring = tlist->string + strlen(tlist->string);
7720006a0bStron 	for (s = str;  s < tlist->endstring;  s++)
7820006a0bStron 	{
7920006a0bStron #if SPACES_IN_FILENAMES
8020006a0bStron 		if (meta_quoted)
8120006a0bStron 		{
8220006a0bStron 			meta_quoted = 0;
8320006a0bStron 		} else if (esclen > 0 && s + esclen < tlist->endstring &&
8420006a0bStron 		           strncmp(s, esc, esclen) == 0)
8520006a0bStron 		{
8620006a0bStron 			meta_quoted = 1;
8720006a0bStron 			s += esclen - 1;
8820006a0bStron 		} else if (delim_quoted)
8920006a0bStron 		{
9020006a0bStron 			if (*s == closequote)
9120006a0bStron 				delim_quoted = 0;
9220006a0bStron 		} else /* (!delim_quoted) */
9320006a0bStron 		{
9420006a0bStron 			if (*s == openquote)
9520006a0bStron 				delim_quoted = 1;
9620006a0bStron 			else if (*s == ' ')
9720006a0bStron 				*s = '\0';
9820006a0bStron 		}
9920006a0bStron #else
10020006a0bStron 		if (*s == ' ')
10120006a0bStron 			*s = '\0';
10220006a0bStron #endif
10320006a0bStron 	}
10420006a0bStron }
10520006a0bStron 
forw_textlist(struct textlist * tlist,char * prev)106*838f5788Ssimonb public char * forw_textlist(struct textlist *tlist, char *prev)
10720006a0bStron {
10820006a0bStron 	char *s;
10920006a0bStron 
11020006a0bStron 	/*
11120006a0bStron 	 * prev == NULL means return the first word in the list.
11220006a0bStron 	 * Otherwise, return the word after "prev".
11320006a0bStron 	 */
11420006a0bStron 	if (prev == NULL)
11520006a0bStron 		s = tlist->string;
11620006a0bStron 	else
11720006a0bStron 		s = prev + strlen(prev);
11820006a0bStron 	if (s >= tlist->endstring)
11920006a0bStron 		return (NULL);
12020006a0bStron 	while (*s == '\0')
12120006a0bStron 		s++;
12220006a0bStron 	if (s >= tlist->endstring)
12320006a0bStron 		return (NULL);
12420006a0bStron 	return (s);
12520006a0bStron }
12620006a0bStron 
back_textlist(struct textlist * tlist,char * prev)127*838f5788Ssimonb public char * back_textlist(struct textlist *tlist, char *prev)
12820006a0bStron {
12920006a0bStron 	char *s;
13020006a0bStron 
13120006a0bStron 	/*
13220006a0bStron 	 * prev == NULL means return the last word in the list.
13320006a0bStron 	 * Otherwise, return the word before "prev".
13420006a0bStron 	 */
13520006a0bStron 	if (prev == NULL)
13620006a0bStron 		s = tlist->endstring;
13720006a0bStron 	else if (prev <= tlist->string)
13820006a0bStron 		return (NULL);
13920006a0bStron 	else
14020006a0bStron 		s = prev - 1;
14120006a0bStron 	while (*s == '\0')
14220006a0bStron 		s--;
14320006a0bStron 	if (s <= tlist->string)
14420006a0bStron 		return (NULL);
14520006a0bStron 	while (s[-1] != '\0' && s > tlist->string)
14620006a0bStron 		s--;
14720006a0bStron 	return (s);
14820006a0bStron }
14920006a0bStron 
15020006a0bStron /*
151*838f5788Ssimonb  * Parse a single option setting in a modeline.
152*838f5788Ssimonb  */
modeline_option(char * str,int opt_len)153*838f5788Ssimonb static void modeline_option(char *str, int opt_len)
154*838f5788Ssimonb {
155*838f5788Ssimonb 	struct mloption { char *opt_name; void (*opt_func)(char*,int); };
156*838f5788Ssimonb 	struct mloption options[] = {
157*838f5788Ssimonb 		{ "ts=",         set_tabs },
158*838f5788Ssimonb 		{ "tabstop=",    set_tabs },
159*838f5788Ssimonb 		{ NULL, NULL }
160*838f5788Ssimonb 	};
161*838f5788Ssimonb 	struct mloption *opt;
162*838f5788Ssimonb 	for (opt = options;  opt->opt_name != NULL;  opt++)
163*838f5788Ssimonb 	{
164*838f5788Ssimonb 		int name_len = strlen(opt->opt_name);
165*838f5788Ssimonb 		if (opt_len > name_len && strncmp(str, opt->opt_name, name_len) == 0)
166*838f5788Ssimonb 		{
167*838f5788Ssimonb 			(*opt->opt_func)(str + name_len, opt_len - name_len);
168*838f5788Ssimonb 			break;
169*838f5788Ssimonb 		}
170*838f5788Ssimonb 	}
171*838f5788Ssimonb }
172*838f5788Ssimonb 
173*838f5788Ssimonb /*
174*838f5788Ssimonb  * String length, terminated by option separator (space or colon).
175*838f5788Ssimonb  * Space/colon can be escaped with backspace.
176*838f5788Ssimonb  */
modeline_option_len(char * str)177*838f5788Ssimonb static int modeline_option_len(char *str)
178*838f5788Ssimonb {
179*838f5788Ssimonb 	int esc = FALSE;
180*838f5788Ssimonb 	char *s;
181*838f5788Ssimonb 	for (s = str;  *s != '\0';  s++)
182*838f5788Ssimonb 	{
183*838f5788Ssimonb 		if (esc)
184*838f5788Ssimonb 			esc = FALSE;
185*838f5788Ssimonb 		else if (*s == '\\')
186*838f5788Ssimonb 			esc = TRUE;
187*838f5788Ssimonb 		else if (*s == ' ' || *s == ':') /* separator */
188*838f5788Ssimonb 			break;
189*838f5788Ssimonb 	}
190*838f5788Ssimonb 	return (s - str);
191*838f5788Ssimonb }
192*838f5788Ssimonb 
193*838f5788Ssimonb /*
194*838f5788Ssimonb  * Parse colon- or space-separated option settings in a modeline.
195*838f5788Ssimonb  */
modeline_options(char * str,char end_char)196*838f5788Ssimonb static void modeline_options(char *str, char end_char)
197*838f5788Ssimonb {
198*838f5788Ssimonb 	for (;;)
199*838f5788Ssimonb 	{
200*838f5788Ssimonb 		int opt_len;
201*838f5788Ssimonb 		str = skipsp(str);
202*838f5788Ssimonb 		if (*str == '\0' || *str == end_char)
203*838f5788Ssimonb 			break;
204*838f5788Ssimonb 		opt_len = modeline_option_len(str);
205*838f5788Ssimonb 		modeline_option(str, opt_len);
206*838f5788Ssimonb 		str += opt_len;
207*838f5788Ssimonb 		if (*str != '\0')
208*838f5788Ssimonb 			str += 1; /* skip past the separator */
209*838f5788Ssimonb 	}
210*838f5788Ssimonb }
211*838f5788Ssimonb 
212*838f5788Ssimonb /*
213*838f5788Ssimonb  * See if there is a modeline string in a line.
214*838f5788Ssimonb  */
check_modeline(char * line)215*838f5788Ssimonb static void check_modeline(char *line)
216*838f5788Ssimonb {
217*838f5788Ssimonb #if HAVE_STRSTR
218*838f5788Ssimonb 	static char *pgms[] = { "less:", "vim:", "vi:", "ex:", NULL };
219*838f5788Ssimonb 	char **pgm;
220*838f5788Ssimonb 	for (pgm = pgms;  *pgm != NULL;  ++pgm)
221*838f5788Ssimonb 	{
222*838f5788Ssimonb 		char *pline = line;
223*838f5788Ssimonb 		for (;;)
224*838f5788Ssimonb 		{
225*838f5788Ssimonb 			char *str;
226*838f5788Ssimonb 			pline = strstr(pline, *pgm);
227*838f5788Ssimonb 			if (pline == NULL) /* pgm is not in this line */
228*838f5788Ssimonb 				break;
229*838f5788Ssimonb 			str = skipsp(pline + strlen(*pgm));
230*838f5788Ssimonb 			if (pline == line || pline[-1] == ' ')
231*838f5788Ssimonb 			{
232*838f5788Ssimonb 				if (strncmp(str, "set ", 4) == 0)
233*838f5788Ssimonb 					modeline_options(str+4, ':');
234*838f5788Ssimonb 				else if (pgm != &pgms[0]) /* "less:" requires "set" */
235*838f5788Ssimonb 					modeline_options(str, '\0');
236*838f5788Ssimonb 				break;
237*838f5788Ssimonb 			}
238*838f5788Ssimonb 			/* Continue searching the rest of the line. */
239*838f5788Ssimonb 			pline = str;
240*838f5788Ssimonb 		}
241*838f5788Ssimonb 	}
242*838f5788Ssimonb #endif /* HAVE_STRSTR */
243*838f5788Ssimonb }
244*838f5788Ssimonb 
245*838f5788Ssimonb /*
246*838f5788Ssimonb  * Read lines from start of file and check if any are modelines.
247*838f5788Ssimonb  */
check_modelines(void)248*838f5788Ssimonb static void check_modelines(void)
249*838f5788Ssimonb {
250*838f5788Ssimonb 	POSITION pos = ch_zero();
251*838f5788Ssimonb 	int i;
252*838f5788Ssimonb 	for (i = 0;  i < modelines;  i++)
253*838f5788Ssimonb 	{
254*838f5788Ssimonb 		char *line;
255*838f5788Ssimonb 		int line_len;
256*838f5788Ssimonb 		if (ABORT_SIGS())
257*838f5788Ssimonb 			return;
258*838f5788Ssimonb 		pos = forw_raw_line(pos, &line, &line_len);
259*838f5788Ssimonb 		if (pos == NULL_POSITION)
260*838f5788Ssimonb 			break;
261*838f5788Ssimonb 		check_modeline(line);
262*838f5788Ssimonb 	}
263*838f5788Ssimonb }
264*838f5788Ssimonb 
265*838f5788Ssimonb /*
266*838f5788Ssimonb  * Close a pipe opened via popen.
267*838f5788Ssimonb  */
close_pipe(FILE * pipefd)268*838f5788Ssimonb static void close_pipe(FILE *pipefd)
269*838f5788Ssimonb {
270*838f5788Ssimonb 	int status;
271*838f5788Ssimonb 	PARG parg;
272*838f5788Ssimonb 
273*838f5788Ssimonb 	if (pipefd == NULL)
274*838f5788Ssimonb 		return;
275*838f5788Ssimonb #if OS2
276*838f5788Ssimonb 	/*
277*838f5788Ssimonb 	 * The pclose function of OS/2 emx sometimes fails.
278*838f5788Ssimonb 	 * Send SIGINT to the piped process before closing it.
279*838f5788Ssimonb 	 */
280*838f5788Ssimonb 	kill(pipefd->_pid, SIGINT);
281*838f5788Ssimonb #endif
282*838f5788Ssimonb 	status = pclose(pipefd);
283*838f5788Ssimonb 	if (status == -1)
284*838f5788Ssimonb 	{
285*838f5788Ssimonb 		/* An internal error in 'less', not a preprocessor error.  */
286*838f5788Ssimonb 		parg.p_string = errno_message("pclose");
287*838f5788Ssimonb 		error("%s", &parg);
288*838f5788Ssimonb 		free(parg.p_string);
289*838f5788Ssimonb 		return;
290*838f5788Ssimonb 	}
291*838f5788Ssimonb 	if (!show_preproc_error)
292*838f5788Ssimonb 		return;
293*838f5788Ssimonb #if defined WIFEXITED && defined WEXITSTATUS
294*838f5788Ssimonb 	if (WIFEXITED(status))
295*838f5788Ssimonb 	{
296*838f5788Ssimonb 		int s = WEXITSTATUS(status);
297*838f5788Ssimonb 		if (s != 0)
298*838f5788Ssimonb 		{
299*838f5788Ssimonb 			parg.p_int = s;
300*838f5788Ssimonb 			error("Input preprocessor failed (status %d)", &parg);
301*838f5788Ssimonb 		}
302*838f5788Ssimonb 		return;
303*838f5788Ssimonb 	}
304*838f5788Ssimonb #endif
305*838f5788Ssimonb #if defined WIFSIGNALED && defined WTERMSIG && HAVE_STRSIGNAL
306*838f5788Ssimonb 	if (WIFSIGNALED(status))
307*838f5788Ssimonb 	{
308*838f5788Ssimonb 		int sig = WTERMSIG(status);
309*838f5788Ssimonb 		if (sig != SIGPIPE || ch_length() != NULL_POSITION)
310*838f5788Ssimonb 		{
311*838f5788Ssimonb 			parg.p_string = signal_message(sig);
312*838f5788Ssimonb 			error("Input preprocessor terminated: %s", &parg);
313*838f5788Ssimonb 		}
314*838f5788Ssimonb 		return;
315*838f5788Ssimonb 	}
316*838f5788Ssimonb #endif
317*838f5788Ssimonb 	if (status != 0)
318*838f5788Ssimonb 	{
319*838f5788Ssimonb 		parg.p_int = status;
320*838f5788Ssimonb 		error("Input preprocessor exited with status %x", &parg);
321*838f5788Ssimonb 	}
322*838f5788Ssimonb }
323*838f5788Ssimonb 
324*838f5788Ssimonb /*
325*838f5788Ssimonb  * Drain and close an input pipe if needed.
326*838f5788Ssimonb  */
close_altpipe(IFILE ifile)327*838f5788Ssimonb public void close_altpipe(IFILE ifile)
328*838f5788Ssimonb {
329*838f5788Ssimonb 	FILE *altpipe = get_altpipe(ifile);
330*838f5788Ssimonb 	if (altpipe != NULL && !(ch_getflags() & CH_KEEPOPEN))
331*838f5788Ssimonb 	{
332*838f5788Ssimonb 		close_pipe(altpipe);
333*838f5788Ssimonb 		set_altpipe(ifile, NULL);
334*838f5788Ssimonb 	}
335*838f5788Ssimonb }
336*838f5788Ssimonb 
337*838f5788Ssimonb /*
338*838f5788Ssimonb  * Check for error status from the current altpipe.
339*838f5788Ssimonb  * May or may not close the pipe.
340*838f5788Ssimonb  */
check_altpipe_error(void)341*838f5788Ssimonb public void check_altpipe_error(void)
342*838f5788Ssimonb {
343*838f5788Ssimonb 	if (!show_preproc_error)
344*838f5788Ssimonb 		return;
345*838f5788Ssimonb 	if (curr_ifile != NULL_IFILE && get_altfilename(curr_ifile) != NULL)
346*838f5788Ssimonb 		close_altpipe(curr_ifile);
347*838f5788Ssimonb }
348*838f5788Ssimonb 
349*838f5788Ssimonb /*
35020006a0bStron  * Close the current input file.
35120006a0bStron  */
close_file(void)352*838f5788Ssimonb static void close_file(void)
35320006a0bStron {
35420006a0bStron 	struct scrpos scrpos;
355*838f5788Ssimonb 	char *altfilename;
35620006a0bStron 
35720006a0bStron 	if (curr_ifile == NULL_IFILE)
35820006a0bStron 		return;
35920006a0bStron 
36020006a0bStron 	/*
36120006a0bStron 	 * Save the current position so that we can return to
36220006a0bStron 	 * the same position if we edit this file again.
36320006a0bStron 	 */
364*838f5788Ssimonb 	get_scrpos(&scrpos, TOP);
36520006a0bStron 	if (scrpos.pos != NULL_POSITION)
36620006a0bStron 	{
36720006a0bStron 		store_pos(curr_ifile, &scrpos);
36820006a0bStron 		lastmark();
36920006a0bStron 	}
37020006a0bStron 	/*
37120006a0bStron 	 * Close the file descriptor, unless it is a pipe.
37220006a0bStron 	 */
37320006a0bStron 	ch_close();
37420006a0bStron 	/*
37520006a0bStron 	 * If we opened a file using an alternate name,
37620006a0bStron 	 * do special stuff to close it.
37720006a0bStron 	 */
378*838f5788Ssimonb 	altfilename = get_altfilename(curr_ifile);
379*838f5788Ssimonb 	if (altfilename != NULL)
38020006a0bStron 	{
381*838f5788Ssimonb 		close_altpipe(curr_ifile);
382*838f5788Ssimonb 		close_altfile(altfilename, get_filename(curr_ifile));
383*838f5788Ssimonb 		set_altfilename(curr_ifile, NULL);
38420006a0bStron 	}
38520006a0bStron 	curr_ifile = NULL_IFILE;
38620006a0bStron #if HAVE_STAT_INO
38720006a0bStron 	curr_ino = curr_dev = 0;
38820006a0bStron #endif
38920006a0bStron }
39020006a0bStron 
39120006a0bStron /*
39220006a0bStron  * Edit a new file (given its name).
39320006a0bStron  * Filename == "-" means standard input.
39420006a0bStron  * Filename == NULL means just close the current file.
39520006a0bStron  */
edit(char * filename)396*838f5788Ssimonb public int edit(char *filename)
39720006a0bStron {
39820006a0bStron 	if (filename == NULL)
39920006a0bStron 		return (edit_ifile(NULL_IFILE));
40020006a0bStron 	return (edit_ifile(get_ifile(filename, curr_ifile)));
40120006a0bStron }
40220006a0bStron 
40320006a0bStron /*
404*838f5788Ssimonb  * Clean up what edit_ifile did before error return.
405*838f5788Ssimonb  */
edit_error(char * filename,char * alt_filename,void * altpipe,IFILE ifile,IFILE was_curr_ifile)406*838f5788Ssimonb static int edit_error(char *filename, char *alt_filename, void *altpipe, IFILE ifile, IFILE was_curr_ifile)
407*838f5788Ssimonb {
408*838f5788Ssimonb 	if (alt_filename != NULL)
409*838f5788Ssimonb 	{
410*838f5788Ssimonb 		close_pipe(altpipe);
411*838f5788Ssimonb 		close_altfile(alt_filename, filename);
412*838f5788Ssimonb 		free(alt_filename);
413*838f5788Ssimonb 	}
414*838f5788Ssimonb 	del_ifile(ifile);
415*838f5788Ssimonb 	free(filename);
416*838f5788Ssimonb 	/*
417*838f5788Ssimonb 	 * Re-open the current file.
418*838f5788Ssimonb 	 */
419*838f5788Ssimonb 	if (was_curr_ifile == ifile)
420*838f5788Ssimonb 	{
421*838f5788Ssimonb 		/*
422*838f5788Ssimonb 		 * Whoops.  The "current" ifile is the one we just deleted.
423*838f5788Ssimonb 		 * Just give up.
424*838f5788Ssimonb 		 */
425*838f5788Ssimonb 		quit(QUIT_ERROR);
426*838f5788Ssimonb 	}
427*838f5788Ssimonb 	reedit_ifile(was_curr_ifile);
428*838f5788Ssimonb 	return (1);
429*838f5788Ssimonb }
430*838f5788Ssimonb 
431*838f5788Ssimonb /*
43220006a0bStron  * Edit a new file (given its IFILE).
43320006a0bStron  * ifile == NULL means just close the current file.
43420006a0bStron  */
edit_ifile(IFILE ifile)435*838f5788Ssimonb public int edit_ifile(IFILE ifile)
43620006a0bStron {
43720006a0bStron 	int f;
43820006a0bStron 	int answer;
43920006a0bStron 	int chflags;
44020006a0bStron 	char *filename;
44120006a0bStron 	char *open_filename;
44220006a0bStron 	char *alt_filename;
443*838f5788Ssimonb 	void *altpipe;
44420006a0bStron 	IFILE was_curr_ifile;
44520006a0bStron 	PARG parg;
44620006a0bStron 
44720006a0bStron 	if (ifile == curr_ifile)
44820006a0bStron 	{
44920006a0bStron 		/*
45020006a0bStron 		 * Already have the correct file open.
45120006a0bStron 		 */
45220006a0bStron 		return (0);
45320006a0bStron 	}
45420006a0bStron 
45520006a0bStron 	/*
45620006a0bStron 	 * We must close the currently open file now.
45720006a0bStron 	 * This is necessary to make the open_altfile/close_altfile pairs
45820006a0bStron 	 * nest properly (or rather to avoid nesting at all).
45920006a0bStron 	 * {{ Some stupid implementations of popen() mess up if you do:
46020006a0bStron 	 *    fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
46120006a0bStron 	 */
46220006a0bStron #if LOGFILE
46320006a0bStron 	end_logfile();
46420006a0bStron #endif
46520006a0bStron 	was_curr_ifile = save_curr_ifile();
46620006a0bStron 	if (curr_ifile != NULL_IFILE)
46720006a0bStron 	{
46820006a0bStron 		chflags = ch_getflags();
46920006a0bStron 		close_file();
47020006a0bStron 		if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
47120006a0bStron 		{
47220006a0bStron 			/*
47320006a0bStron 			 * Don't keep the help file in the ifile list.
47420006a0bStron 			 */
47520006a0bStron 			del_ifile(was_curr_ifile);
47620006a0bStron 			was_curr_ifile = old_ifile;
47720006a0bStron 		}
47820006a0bStron 	}
47920006a0bStron 
48020006a0bStron 	if (ifile == NULL_IFILE)
48120006a0bStron 	{
48220006a0bStron 		/*
48320006a0bStron 		 * No new file to open.
48420006a0bStron 		 * (Don't set old_ifile, because if you call edit_ifile(NULL),
48520006a0bStron 		 *  you're supposed to have saved curr_ifile yourself,
48620006a0bStron 		 *  and you'll restore it if necessary.)
48720006a0bStron 		 */
48820006a0bStron 		unsave_ifile(was_curr_ifile);
48920006a0bStron 		return (0);
49020006a0bStron 	}
49120006a0bStron 
49220006a0bStron 	filename = save(get_filename(ifile));
493*838f5788Ssimonb 
49420006a0bStron 	/*
49520006a0bStron 	 * See if LESSOPEN specifies an "alternate" file to open.
49620006a0bStron 	 */
497*838f5788Ssimonb 	altpipe = get_altpipe(ifile);
498*838f5788Ssimonb 	if (altpipe != NULL)
499*838f5788Ssimonb 	{
500*838f5788Ssimonb 		/*
501*838f5788Ssimonb 		 * File is already open.
502*838f5788Ssimonb 		 * chflags and f are not used by ch_init if ifile has
503*838f5788Ssimonb 		 * filestate which should be the case if we're here.
504*838f5788Ssimonb 		 * Set them here to avoid uninitialized variable warnings.
505*838f5788Ssimonb 		 */
506*838f5788Ssimonb 		chflags = 0;
507*838f5788Ssimonb 		f = -1;
508*838f5788Ssimonb 		alt_filename = get_altfilename(ifile);
50920006a0bStron 		open_filename = (alt_filename != NULL) ? alt_filename : filename;
510*838f5788Ssimonb 	} else
511*838f5788Ssimonb 	{
512*838f5788Ssimonb 		if (strcmp(filename, FAKE_HELPFILE) == 0 ||
513*838f5788Ssimonb 			 strcmp(filename, FAKE_EMPTYFILE) == 0)
514*838f5788Ssimonb 			alt_filename = NULL;
515*838f5788Ssimonb 		else
516*838f5788Ssimonb 			alt_filename = open_altfile(filename, &f, &altpipe);
517*838f5788Ssimonb 
518*838f5788Ssimonb 		open_filename = (alt_filename != NULL) ? alt_filename : filename;
51920006a0bStron 
52020006a0bStron 		chflags = 0;
521*838f5788Ssimonb 		if (altpipe != NULL)
52220006a0bStron 		{
52320006a0bStron 			/*
52420006a0bStron 			 * The alternate "file" is actually a pipe.
52520006a0bStron 			 * f has already been set to the file descriptor of the pipe
52620006a0bStron 			 * in the call to open_altfile above.
52720006a0bStron 			 * Keep the file descriptor open because it was opened
52820006a0bStron 			 * via popen(), and pclose() wants to close it.
52920006a0bStron 			 */
53020006a0bStron 			chflags |= CH_POPENED;
531*838f5788Ssimonb 			if (strcmp(filename, "-") == 0)
532*838f5788Ssimonb 				chflags |= CH_KEEPOPEN;
533*838f5788Ssimonb 		} else if (strcmp(filename, "-") == 0)
53420006a0bStron 		{
53520006a0bStron 			/*
53620006a0bStron 			 * Use standard input.
53720006a0bStron 			 * Keep the file descriptor open because we can't reopen it.
53820006a0bStron 			 */
53920006a0bStron 			f = fd0;
54020006a0bStron 			chflags |= CH_KEEPOPEN;
54120006a0bStron 			/*
54220006a0bStron 			 * Must switch stdin to BINARY mode.
54320006a0bStron 			 */
54420006a0bStron 			SET_BINARY(f);
54520006a0bStron #if MSDOS_COMPILER==DJGPPC
54620006a0bStron 			/*
54720006a0bStron 			 * Setting stdin to binary by default causes
54820006a0bStron 			 * Ctrl-C to not raise SIGINT.  We must undo
54920006a0bStron 			 * that side-effect.
55020006a0bStron 			 */
55120006a0bStron 			__djgpp_set_ctrl_c(1);
55220006a0bStron #endif
553ec18bca0Stron 		} else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0)
554ec18bca0Stron 		{
555ec18bca0Stron 			f = -1;
556ec18bca0Stron 			chflags |= CH_NODATA;
55720006a0bStron 		} else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
55820006a0bStron 		{
55920006a0bStron 			f = -1;
56020006a0bStron 			chflags |= CH_HELPFILE;
56120006a0bStron 		} else if ((parg.p_string = bad_file(open_filename)) != NULL)
56220006a0bStron 		{
56320006a0bStron 			/*
56420006a0bStron 			 * It looks like a bad file.  Don't try to open it.
56520006a0bStron 			 */
56620006a0bStron 			error("%s", &parg);
567*838f5788Ssimonb 			free(parg.p_string);
568*838f5788Ssimonb 			return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
569*838f5788Ssimonb 		} else if ((f = open(open_filename, OPEN_READ)) < 0)
57020006a0bStron 		{
57120006a0bStron 			/*
57220006a0bStron 			 * Got an error trying to open it.
57320006a0bStron 			 */
57420006a0bStron 			parg.p_string = errno_message(filename);
57520006a0bStron 			error("%s", &parg);
576*838f5788Ssimonb 			free(parg.p_string);
577*838f5788Ssimonb 			return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
57820006a0bStron 		} else
57920006a0bStron 		{
58020006a0bStron 			chflags |= CH_CANSEEK;
58120006a0bStron 			if (!force_open && !opened(ifile) && bin_file(f))
58220006a0bStron 			{
58320006a0bStron 				/*
58420006a0bStron 				 * Looks like a binary file.
58520006a0bStron 				 * Ask user if we should proceed.
58620006a0bStron 				 */
58720006a0bStron 				parg.p_string = filename;
58820006a0bStron 				answer = query("\"%s\" may be a binary file.  See it anyway? ",
58920006a0bStron 					&parg);
59020006a0bStron 				if (answer != 'y' && answer != 'Y')
59120006a0bStron 				{
59220006a0bStron 					close(f);
593*838f5788Ssimonb 					return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
59420006a0bStron 				}
59520006a0bStron 			}
59620006a0bStron 		}
597*838f5788Ssimonb 	}
598*838f5788Ssimonb 	if (!force_open && f >= 0 && isatty(f))
599*838f5788Ssimonb 	{
600*838f5788Ssimonb 		PARG parg;
601*838f5788Ssimonb 		parg.p_string = filename;
602*838f5788Ssimonb 		error("%s is a terminal (use -f to open it)", &parg);
603*838f5788Ssimonb 		return edit_error(filename, alt_filename, altpipe, ifile, was_curr_ifile);
604*838f5788Ssimonb 	}
60520006a0bStron 
60620006a0bStron 	/*
60720006a0bStron 	 * Get the new ifile.
60820006a0bStron 	 * Get the saved position for the file.
60920006a0bStron 	 */
61020006a0bStron 	if (was_curr_ifile != NULL_IFILE)
61120006a0bStron 	{
61220006a0bStron 		old_ifile = was_curr_ifile;
61320006a0bStron 		unsave_ifile(was_curr_ifile);
61420006a0bStron 	}
61520006a0bStron 	curr_ifile = ifile;
616*838f5788Ssimonb 	set_altfilename(curr_ifile, alt_filename);
617*838f5788Ssimonb 	set_altpipe(curr_ifile, altpipe);
61820006a0bStron 	set_open(curr_ifile); /* File has been opened */
61920006a0bStron 	get_pos(curr_ifile, &initial_scrpos);
62020006a0bStron 	new_file = TRUE;
62120006a0bStron 	ch_init(f, chflags);
622*838f5788Ssimonb 	consecutive_nulls = 0;
623*838f5788Ssimonb 	check_modelines();
62420006a0bStron 
62520006a0bStron 	if (!(chflags & CH_HELPFILE))
62620006a0bStron 	{
62720006a0bStron #if LOGFILE
62820006a0bStron 		if (namelogfile != NULL && is_tty)
62920006a0bStron 			use_logfile(namelogfile);
63020006a0bStron #endif
63120006a0bStron #if HAVE_STAT_INO
63220006a0bStron 		/* Remember the i-number and device of the opened file. */
633*838f5788Ssimonb 		if (strcmp(open_filename, "-") != 0)
63420006a0bStron 		{
63520006a0bStron 			struct stat statbuf;
636*838f5788Ssimonb 			int r = stat(open_filename, &statbuf);
63720006a0bStron 			if (r == 0)
63820006a0bStron 			{
63920006a0bStron 				curr_ino = statbuf.st_ino;
64020006a0bStron 				curr_dev = statbuf.st_dev;
64120006a0bStron 			}
64220006a0bStron 		}
64320006a0bStron #endif
64420006a0bStron 		if (every_first_cmd != NULL)
645*838f5788Ssimonb 		{
64620006a0bStron 			ungetsc(every_first_cmd);
647*838f5788Ssimonb 			ungetcc_back(CHAR_END_COMMAND);
648*838f5788Ssimonb 		}
64920006a0bStron 	}
65020006a0bStron 
65120006a0bStron 	flush();
65220006a0bStron 
65320006a0bStron 	if (is_tty)
65420006a0bStron 	{
65520006a0bStron 		/*
65620006a0bStron 		 * Output is to a real tty.
65720006a0bStron 		 */
65820006a0bStron 
65920006a0bStron 		/*
66020006a0bStron 		 * Indicate there is nothing displayed yet.
66120006a0bStron 		 */
66220006a0bStron 		pos_clear();
66320006a0bStron 		clr_linenum();
66420006a0bStron #if HILITE_SEARCH
66520006a0bStron 		clr_hilite();
66620006a0bStron #endif
667*838f5788Ssimonb 		hshift = 0;
668*838f5788Ssimonb 		if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
66920006a0bStron 		{
670*838f5788Ssimonb 			char *qfilename = shell_quote(filename);
671*838f5788Ssimonb 			cmd_addhist(ml_examine, qfilename, 1);
672*838f5788Ssimonb 			free(qfilename);
67320006a0bStron 		}
674*838f5788Ssimonb 		if (want_filesize)
675*838f5788Ssimonb 			scan_eof();
67620006a0bStron 	}
67720006a0bStron 	free(filename);
67820006a0bStron 	return (0);
67920006a0bStron }
68020006a0bStron 
68120006a0bStron /*
68220006a0bStron  * Edit a space-separated list of files.
68320006a0bStron  * For each filename in the list, enter it into the ifile list.
68420006a0bStron  * Then edit the first one.
68520006a0bStron  */
edit_list(char * filelist)686*838f5788Ssimonb public int edit_list(char *filelist)
68720006a0bStron {
68820006a0bStron 	IFILE save_ifile;
68920006a0bStron 	char *good_filename;
69020006a0bStron 	char *filename;
69120006a0bStron 	char *gfilelist;
69220006a0bStron 	char *gfilename;
693*838f5788Ssimonb 	char *qfilename;
69420006a0bStron 	struct textlist tl_files;
69520006a0bStron 	struct textlist tl_gfiles;
69620006a0bStron 
69720006a0bStron 	save_ifile = save_curr_ifile();
69820006a0bStron 	good_filename = NULL;
69920006a0bStron 
70020006a0bStron 	/*
70120006a0bStron 	 * Run thru each filename in the list.
70220006a0bStron 	 * Try to glob the filename.
70320006a0bStron 	 * If it doesn't expand, just try to open the filename.
70420006a0bStron 	 * If it does expand, try to open each name in that list.
70520006a0bStron 	 */
70620006a0bStron 	init_textlist(&tl_files, filelist);
70720006a0bStron 	filename = NULL;
70820006a0bStron 	while ((filename = forw_textlist(&tl_files, filename)) != NULL)
70920006a0bStron 	{
71020006a0bStron 		gfilelist = lglob(filename);
71120006a0bStron 		init_textlist(&tl_gfiles, gfilelist);
71220006a0bStron 		gfilename = NULL;
71320006a0bStron 		while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
71420006a0bStron 		{
715*838f5788Ssimonb 			qfilename = shell_unquote(gfilename);
716*838f5788Ssimonb 			if (edit(qfilename) == 0 && good_filename == NULL)
71720006a0bStron 				good_filename = get_filename(curr_ifile);
718*838f5788Ssimonb 			free(qfilename);
71920006a0bStron 		}
72020006a0bStron 		free(gfilelist);
72120006a0bStron 	}
72220006a0bStron 	/*
72320006a0bStron 	 * Edit the first valid filename in the list.
72420006a0bStron 	 */
72520006a0bStron 	if (good_filename == NULL)
72620006a0bStron 	{
72720006a0bStron 		unsave_ifile(save_ifile);
72820006a0bStron 		return (1);
72920006a0bStron 	}
73020006a0bStron 	if (get_ifile(good_filename, curr_ifile) == curr_ifile)
73120006a0bStron 	{
73220006a0bStron 		/*
73320006a0bStron 		 * Trying to edit the current file; don't reopen it.
73420006a0bStron 		 */
73520006a0bStron 		unsave_ifile(save_ifile);
73620006a0bStron 		return (0);
73720006a0bStron 	}
73820006a0bStron 	reedit_ifile(save_ifile);
73920006a0bStron 	return (edit(good_filename));
74020006a0bStron }
74120006a0bStron 
74220006a0bStron /*
74320006a0bStron  * Edit the first file in the command line (ifile) list.
74420006a0bStron  */
edit_first(void)745*838f5788Ssimonb public int edit_first(void)
74620006a0bStron {
747*838f5788Ssimonb 	if (nifile() == 0)
748*838f5788Ssimonb 		return (edit_stdin());
74920006a0bStron 	curr_ifile = NULL_IFILE;
75020006a0bStron 	return (edit_next(1));
75120006a0bStron }
75220006a0bStron 
75320006a0bStron /*
75420006a0bStron  * Edit the last file in the command line (ifile) list.
75520006a0bStron  */
edit_last(void)756*838f5788Ssimonb public int edit_last(void)
75720006a0bStron {
75820006a0bStron 	curr_ifile = NULL_IFILE;
75920006a0bStron 	return (edit_prev(1));
76020006a0bStron }
76120006a0bStron 
76220006a0bStron 
76320006a0bStron /*
76420006a0bStron  * Edit the n-th next or previous file in the command line (ifile) list.
76520006a0bStron  */
edit_istep(IFILE h,int n,int dir)766*838f5788Ssimonb static int edit_istep(IFILE h, int n, int dir)
76720006a0bStron {
76820006a0bStron 	IFILE next;
76920006a0bStron 
77020006a0bStron 	/*
77120006a0bStron 	 * Skip n filenames, then try to edit each filename.
77220006a0bStron 	 */
77320006a0bStron 	for (;;)
77420006a0bStron 	{
77520006a0bStron 		next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
77620006a0bStron 		if (--n < 0)
77720006a0bStron 		{
77820006a0bStron 			if (edit_ifile(h) == 0)
77920006a0bStron 				break;
78020006a0bStron 		}
78120006a0bStron 		if (next == NULL_IFILE)
78220006a0bStron 		{
78320006a0bStron 			/*
78420006a0bStron 			 * Reached end of the ifile list.
78520006a0bStron 			 */
78620006a0bStron 			return (1);
78720006a0bStron 		}
78820006a0bStron 		if (ABORT_SIGS())
78920006a0bStron 		{
79020006a0bStron 			/*
79120006a0bStron 			 * Interrupt breaks out, if we're in a long
79220006a0bStron 			 * list of files that can't be opened.
79320006a0bStron 			 */
79420006a0bStron 			return (1);
79520006a0bStron 		}
79620006a0bStron 		h = next;
79720006a0bStron 	}
79820006a0bStron 	/*
79920006a0bStron 	 * Found a file that we can edit.
80020006a0bStron 	 */
80120006a0bStron 	return (0);
80220006a0bStron }
80320006a0bStron 
edit_inext(IFILE h,int n)804*838f5788Ssimonb static int edit_inext(IFILE h, int n)
80520006a0bStron {
80620006a0bStron 	return (edit_istep(h, n, +1));
80720006a0bStron }
80820006a0bStron 
edit_next(int n)809*838f5788Ssimonb public int edit_next(int n)
81020006a0bStron {
81120006a0bStron 	return edit_istep(curr_ifile, n, +1);
81220006a0bStron }
81320006a0bStron 
edit_iprev(IFILE h,int n)814*838f5788Ssimonb static int edit_iprev(IFILE h, int n)
81520006a0bStron {
81620006a0bStron 	return (edit_istep(h, n, -1));
81720006a0bStron }
81820006a0bStron 
edit_prev(int n)819*838f5788Ssimonb public int edit_prev(int n)
82020006a0bStron {
82120006a0bStron 	return edit_istep(curr_ifile, n, -1);
82220006a0bStron }
82320006a0bStron 
82420006a0bStron /*
82520006a0bStron  * Edit a specific file in the command line (ifile) list.
82620006a0bStron  */
edit_index(int n)827*838f5788Ssimonb public int edit_index(int n)
82820006a0bStron {
82920006a0bStron 	IFILE h;
83020006a0bStron 
83120006a0bStron 	h = NULL_IFILE;
83220006a0bStron 	do
83320006a0bStron 	{
83420006a0bStron 		if ((h = next_ifile(h)) == NULL_IFILE)
83520006a0bStron 		{
83620006a0bStron 			/*
83720006a0bStron 			 * Reached end of the list without finding it.
83820006a0bStron 			 */
83920006a0bStron 			return (1);
84020006a0bStron 		}
84120006a0bStron 	} while (get_index(h) != n);
84220006a0bStron 
84320006a0bStron 	return (edit_ifile(h));
84420006a0bStron }
84520006a0bStron 
save_curr_ifile(void)846*838f5788Ssimonb public IFILE save_curr_ifile(void)
84720006a0bStron {
84820006a0bStron 	if (curr_ifile != NULL_IFILE)
84920006a0bStron 		hold_ifile(curr_ifile, 1);
85020006a0bStron 	return (curr_ifile);
85120006a0bStron }
85220006a0bStron 
unsave_ifile(IFILE save_ifile)853*838f5788Ssimonb public void unsave_ifile(IFILE save_ifile)
85420006a0bStron {
85520006a0bStron 	if (save_ifile != NULL_IFILE)
85620006a0bStron 		hold_ifile(save_ifile, -1);
85720006a0bStron }
85820006a0bStron 
85920006a0bStron /*
86020006a0bStron  * Reedit the ifile which was previously open.
86120006a0bStron  */
reedit_ifile(IFILE save_ifile)862*838f5788Ssimonb public void reedit_ifile(IFILE save_ifile)
86320006a0bStron {
86420006a0bStron 	IFILE next;
86520006a0bStron 	IFILE prev;
86620006a0bStron 
86720006a0bStron 	/*
86820006a0bStron 	 * Try to reopen the ifile.
86920006a0bStron 	 * Note that opening it may fail (maybe the file was removed),
87020006a0bStron 	 * in which case the ifile will be deleted from the list.
87120006a0bStron 	 * So save the next and prev ifiles first.
87220006a0bStron 	 */
87320006a0bStron 	unsave_ifile(save_ifile);
87420006a0bStron 	next = next_ifile(save_ifile);
87520006a0bStron 	prev = prev_ifile(save_ifile);
87620006a0bStron 	if (edit_ifile(save_ifile) == 0)
87720006a0bStron 		return;
87820006a0bStron 	/*
87920006a0bStron 	 * If can't reopen it, open the next input file in the list.
88020006a0bStron 	 */
88120006a0bStron 	if (next != NULL_IFILE && edit_inext(next, 0) == 0)
88220006a0bStron 		return;
88320006a0bStron 	/*
88420006a0bStron 	 * If can't open THAT one, open the previous input file in the list.
88520006a0bStron 	 */
88620006a0bStron 	if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
88720006a0bStron 		return;
88820006a0bStron 	/*
88920006a0bStron 	 * If can't even open that, we're stuck.  Just quit.
89020006a0bStron 	 */
89120006a0bStron 	quit(QUIT_ERROR);
89220006a0bStron }
89320006a0bStron 
reopen_curr_ifile(void)894*838f5788Ssimonb public void reopen_curr_ifile(void)
89520006a0bStron {
89620006a0bStron 	IFILE save_ifile = save_curr_ifile();
89720006a0bStron 	close_file();
89820006a0bStron 	reedit_ifile(save_ifile);
89920006a0bStron }
90020006a0bStron 
90120006a0bStron /*
90220006a0bStron  * Edit standard input.
90320006a0bStron  */
edit_stdin(void)904*838f5788Ssimonb public int edit_stdin(void)
90520006a0bStron {
90620006a0bStron 	if (isatty(fd0))
90720006a0bStron 	{
90820006a0bStron 		error("Missing filename (\"less --help\" for help)", NULL_PARG);
90920006a0bStron 		quit(QUIT_OK);
91020006a0bStron 	}
91120006a0bStron 	return (edit("-"));
91220006a0bStron }
91320006a0bStron 
91420006a0bStron /*
91520006a0bStron  * Copy a file directly to standard output.
91620006a0bStron  * Used if standard output is not a tty.
91720006a0bStron  */
cat_file(void)918*838f5788Ssimonb public void cat_file(void)
91920006a0bStron {
920*838f5788Ssimonb 	int c;
92120006a0bStron 
92220006a0bStron 	while ((c = ch_forw_get()) != EOI)
92320006a0bStron 		putchr(c);
92420006a0bStron 	flush();
92520006a0bStron }
92620006a0bStron 
92720006a0bStron #if LOGFILE
92820006a0bStron 
929*838f5788Ssimonb #define OVERWRITE_OPTIONS "Overwrite, Append, Don't log, or Quit?"
930*838f5788Ssimonb 
93120006a0bStron /*
93220006a0bStron  * If the user asked for a log file and our input file
93320006a0bStron  * is standard input, create the log file.
93420006a0bStron  * We take care not to blindly overwrite an existing file.
93520006a0bStron  */
use_logfile(char * filename)936*838f5788Ssimonb public void use_logfile(char *filename)
93720006a0bStron {
938*838f5788Ssimonb 	int exists;
939*838f5788Ssimonb 	int answer;
94020006a0bStron 	PARG parg;
94120006a0bStron 
94220006a0bStron 	if (ch_getflags() & CH_CANSEEK)
94320006a0bStron 		/*
94420006a0bStron 		 * Can't currently use a log file on a file that can seek.
94520006a0bStron 		 */
94620006a0bStron 		return;
94720006a0bStron 
94820006a0bStron 	/*
94920006a0bStron 	 * {{ We could use access() here. }}
95020006a0bStron 	 */
95120006a0bStron 	exists = open(filename, OPEN_READ);
952824a88bbStron 	if (exists >= 0)
95320006a0bStron 		close(exists);
95420006a0bStron 	exists = (exists >= 0);
95520006a0bStron 
95620006a0bStron 	/*
95720006a0bStron 	 * Decide whether to overwrite the log file or append to it.
95820006a0bStron 	 * If it doesn't exist we "overwrite" it.
95920006a0bStron 	 */
96020006a0bStron 	if (!exists || force_logfile)
96120006a0bStron 	{
96220006a0bStron 		/*
96320006a0bStron 		 * Overwrite (or create) the log file.
96420006a0bStron 		 */
96520006a0bStron 		answer = 'O';
96620006a0bStron 	} else
96720006a0bStron 	{
96820006a0bStron 		/*
96920006a0bStron 		 * Ask user what to do.
97020006a0bStron 		 */
97120006a0bStron 		parg.p_string = filename;
972*838f5788Ssimonb 		answer = query("Warning: \"%s\" exists; "OVERWRITE_OPTIONS" ", &parg);
97320006a0bStron 	}
97420006a0bStron 
97520006a0bStron loop:
97620006a0bStron 	switch (answer)
97720006a0bStron 	{
97820006a0bStron 	case 'O': case 'o':
97920006a0bStron 		/*
98020006a0bStron 		 * Overwrite: create the file.
98120006a0bStron 		 */
982*838f5788Ssimonb 		logfile = creat(filename, CREAT_RW);
98320006a0bStron 		break;
98420006a0bStron 	case 'A': case 'a':
98520006a0bStron 		/*
98620006a0bStron 		 * Append: open the file and seek to the end.
98720006a0bStron 		 */
98820006a0bStron 		logfile = open(filename, OPEN_APPEND);
98920006a0bStron 		if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
99020006a0bStron 		{
99120006a0bStron 			close(logfile);
99220006a0bStron 			logfile = -1;
99320006a0bStron 		}
99420006a0bStron 		break;
99520006a0bStron 	case 'D': case 'd':
99620006a0bStron 		/*
99720006a0bStron 		 * Don't do anything.
99820006a0bStron 		 */
99920006a0bStron 		return;
100020006a0bStron 	default:
100120006a0bStron 		/*
100220006a0bStron 		 * Eh?
100320006a0bStron 		 */
1004*838f5788Ssimonb 
1005*838f5788Ssimonb 		answer = query(OVERWRITE_OPTIONS" (Type \"O\", \"A\", \"D\" or \"Q\") ", NULL_PARG);
100620006a0bStron 		goto loop;
100720006a0bStron 	}
100820006a0bStron 
100920006a0bStron 	if (logfile < 0)
101020006a0bStron 	{
101120006a0bStron 		/*
101220006a0bStron 		 * Error in opening logfile.
101320006a0bStron 		 */
101420006a0bStron 		parg.p_string = filename;
101520006a0bStron 		error("Cannot write to \"%s\"", &parg);
101620006a0bStron 		return;
101720006a0bStron 	}
101820006a0bStron 	SET_BINARY(logfile);
101920006a0bStron }
102020006a0bStron 
102120006a0bStron #endif
1022