edit.c revision 60786
1351278Sdim/*
2351278Sdim * Copyright (C) 1984-2000  Mark Nudelman
3351278Sdim *
4351278Sdim * You may distribute under the terms of either the GNU General Public
5351278Sdim * License or the Less License, as specified in the README file.
6351278Sdim *
7351278Sdim * For more information about less, or for information on how to
8351278Sdim * contact the author, see the README file.
9351278Sdim */
10351278Sdim
11351278Sdim
12351278Sdim#include "less.h"
13351278Sdim
14351278Sdimpublic int fd0 = 0;
15351278Sdim
16351278Sdimextern int new_file;
17351278Sdimextern int errmsgs;
18351278Sdimextern int cbufs;
19351278Sdimextern char *every_first_cmd;
20351278Sdimextern int any_display;
21351278Sdimextern int force_open;
22351278Sdimextern int is_tty;
23351278Sdimextern int sigs;
24351278Sdimextern IFILE curr_ifile;
25360784Sdimextern IFILE old_ifile;
26351278Sdimextern struct scrpos initial_scrpos;
27351278Sdimextern void constant *ml_examine;
28351278Sdim#if SPACES_IN_FILENAMES
29351278Sdimextern char openquote;
30351278Sdimextern char closequote;
31351278Sdim#endif
32351278Sdim
33351278Sdim#if LOGFILE
34351278Sdimextern int logfile;
35351278Sdimextern int force_logfile;
36351278Sdimextern char *namelogfile;
37351278Sdim#endif
38351278Sdim
39351278Sdimchar *curr_altfilename = NULL;
40351278Sdimstatic void *curr_altpipe;
41351278Sdim
42351278Sdim
43351278Sdim/*
44351278Sdim * Textlist functions deal with a list of words separated by spaces.
45351278Sdim * init_textlist sets up a textlist structure.
46351278Sdim * forw_textlist uses that structure to iterate thru the list of
47351278Sdim * words, returning each one as a standard null-terminated string.
48351278Sdim * back_textlist does the same, but runs thru the list backwards.
49351278Sdim */
50351278Sdim	public void
51351278Sdiminit_textlist(tlist, str)
52351278Sdim	struct textlist *tlist;
53351278Sdim	char *str;
54351278Sdim{
55351278Sdim	char *s;
56351278Sdim#if SPACES_IN_FILENAMES
57351278Sdim	int quoted = 0;
58351278Sdim#endif
59351278Sdim
60351278Sdim	tlist->string = skipsp(str);
61351278Sdim	tlist->endstring = tlist->string + strlen(tlist->string);
62351278Sdim	for (s = str;  s < tlist->endstring;  s++)
63351278Sdim	{
64351278Sdim#if SPACES_IN_FILENAMES
65351278Sdim		if (*s == ' ' && !quoted)
66351278Sdim			*s = '\0';
67351278Sdim		if (!quoted && *s == openquote)
68351278Sdim			quoted = 1;
69351278Sdim		else if (quoted && *s == closequote)
70351278Sdim			quoted = 0;
71351278Sdim#else
72351278Sdim		if (*s == ' ')
73351278Sdim			*s = '\0';
74351278Sdim#endif
75351278Sdim	}
76351278Sdim}
77351278Sdim
78351278Sdim	public char *
79351278Sdimforw_textlist(tlist, prev)
80351278Sdim	struct textlist *tlist;
81351278Sdim	char *prev;
82351278Sdim{
83351278Sdim	char *s;
84351278Sdim
85351278Sdim	/*
86351278Sdim	 * prev == NULL means return the first word in the list.
87351278Sdim	 * Otherwise, return the word after "prev".
88351278Sdim	 */
89351278Sdim	if (prev == NULL)
90351278Sdim		s = tlist->string;
91351278Sdim	else
92351278Sdim		s = prev + strlen(prev);
93351278Sdim	if (s >= tlist->endstring)
94351278Sdim		return (NULL);
95351278Sdim	while (*s == '\0')
96351278Sdim		s++;
97351278Sdim	if (s >= tlist->endstring)
98351278Sdim		return (NULL);
99351278Sdim	return (s);
100351278Sdim}
101351278Sdim
102351278Sdim	public char *
103351278Sdimback_textlist(tlist, prev)
104351278Sdim	struct textlist *tlist;
105351278Sdim	char *prev;
106351278Sdim{
107351278Sdim	char *s;
108351278Sdim
109351278Sdim	/*
110351278Sdim	 * prev == NULL means return the last word in the list.
111351278Sdim	 * Otherwise, return the word before "prev".
112351278Sdim	 */
113351278Sdim	if (prev == NULL)
114351278Sdim		s = tlist->endstring;
115351278Sdim	else if (prev <= tlist->string)
116351278Sdim		return (NULL);
117351278Sdim	else
118351278Sdim		s = prev - 1;
119351278Sdim	while (*s == '\0')
120351278Sdim		s--;
121351278Sdim	if (s <= tlist->string)
122351278Sdim		return (NULL);
123351278Sdim	while (s[-1] != '\0' && s > tlist->string)
124351278Sdim		s--;
125351278Sdim	return (s);
126351278Sdim}
127351278Sdim
128351278Sdim/*
129351278Sdim * Close the current input file.
130351278Sdim */
131351278Sdim	static void
132351278Sdimclose_file()
133351278Sdim{
134351278Sdim	struct scrpos scrpos;
135351278Sdim	char *filename;
136351278Sdim
137351278Sdim	if (curr_ifile == NULL_IFILE)
138351278Sdim		return;
139351278Sdim
140351278Sdim	/*
141351278Sdim	 * Save the current position so that we can return to
142351278Sdim	 * the same position if we edit this file again.
143360784Sdim	 */
144351278Sdim	get_scrpos(&scrpos);
145351278Sdim	if (scrpos.pos != NULL_POSITION)
146351278Sdim	{
147351278Sdim		store_pos(curr_ifile, &scrpos);
148351278Sdim		lastmark();
149351278Sdim	}
150351278Sdim	/*
151351278Sdim	 * Close the file descriptor, unless it is a pipe.
152351278Sdim	 */
153351278Sdim	ch_close();
154351278Sdim	/*
155351278Sdim	 * If we opened a file using an alternate name,
156351278Sdim	 * do special stuff to close it.
157351278Sdim	 */
158351278Sdim	if (curr_altfilename != NULL)
159351278Sdim	{
160351278Sdim		filename = unquote_file(get_filename(curr_ifile));
161351278Sdim		close_altfile(curr_altfilename, filename, curr_altpipe);
162351278Sdim		free(filename);
163351278Sdim		free(curr_altfilename);
164351278Sdim		curr_altfilename = NULL;
165351278Sdim	}
166351278Sdim	curr_ifile = NULL_IFILE;
167351278Sdim}
168351278Sdim
169351278Sdim/*
170351278Sdim * Edit a new file (given its name).
171351278Sdim * Filename == "-" means standard input.
172351278Sdim * Filename == NULL means just close the current file.
173351278Sdim */
174351278Sdim	public int
175351278Sdimedit(filename)
176351278Sdim	char *filename;
177351278Sdim{
178351278Sdim	if (filename == NULL)
179351278Sdim		return (edit_ifile(NULL_IFILE));
180351278Sdim	return (edit_ifile(get_ifile(filename, curr_ifile)));
181351278Sdim}
182351278Sdim
183351278Sdim/*
184360784Sdim * Edit a new file (given its IFILE).
185351278Sdim * ifile == NULL means just close the current file.
186351278Sdim */
187351278Sdim	public int
188351278Sdimedit_ifile(ifile)
189360784Sdim	IFILE ifile;
190351278Sdim{
191351278Sdim	int f;
192351278Sdim	int answer;
193351278Sdim	int no_display;
194351278Sdim	int chflags;
195351278Sdim	char *filename;
196351278Sdim	char *open_filename;
197351278Sdim	char *alt_filename;
198351278Sdim	void *alt_pipe;
199351278Sdim	IFILE was_curr_ifile;
200351278Sdim	PARG parg;
201351278Sdim
202351278Sdim	if (ifile == curr_ifile)
203351278Sdim	{
204351278Sdim		/*
205351278Sdim		 * Already have the correct file open.
206351278Sdim		 */
207351278Sdim		return (0);
208360784Sdim	}
209360784Sdim
210351278Sdim	/*
211351278Sdim	 * We must close the currently open file now.
212351278Sdim	 * This is necessary to make the open_altfile/close_altfile pairs
213351278Sdim	 * nest properly (or rather to avoid nesting at all).
214351278Sdim	 * {{ Some stupid implementations of popen() mess up if you do:
215351278Sdim	 *    fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
216351278Sdim	 */
217351278Sdim#if LOGFILE
218351278Sdim	end_logfile();
219351278Sdim#endif
220351278Sdim	was_curr_ifile = save_curr_ifile();
221351278Sdim	if (curr_ifile != NULL_IFILE)
222351278Sdim	{
223351278Sdim		chflags = ch_getflags();
224351278Sdim		close_file();
225351278Sdim		if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
226351278Sdim		{
227351278Sdim			/*
228351278Sdim			 * Don't keep the help file in the ifile list.
229351278Sdim			 */
230351278Sdim			del_ifile(was_curr_ifile);
231351278Sdim			was_curr_ifile = old_ifile;
232351278Sdim		}
233351278Sdim	}
234351278Sdim
235351278Sdim	if (ifile == NULL_IFILE)
236351278Sdim	{
237351278Sdim		/*
238351278Sdim		 * No new file to open.
239351278Sdim		 * (Don't set old_ifile, because if you call edit_ifile(NULL),
240351278Sdim		 *  you're supposed to have saved curr_ifile yourself,
241351278Sdim		 *  and you'll restore it if necessary.)
242351278Sdim		 */
243351278Sdim		unsave_ifile(was_curr_ifile);
244351278Sdim		return (0);
245351278Sdim	}
246351278Sdim
247351278Sdim	filename = unquote_file(get_filename(ifile));
248351278Sdim	/*
249351278Sdim	 * See if LESSOPEN specifies an "alternate" file to open.
250351278Sdim	 */
251351278Sdim	alt_pipe = NULL;
252351278Sdim	alt_filename = open_altfile(filename, &f, &alt_pipe);
253351278Sdim	open_filename = (alt_filename != NULL) ? alt_filename : filename;
254351278Sdim
255351278Sdim	chflags = 0;
256351278Sdim	if (alt_pipe != NULL)
257351278Sdim	{
258351278Sdim		/*
259351278Sdim		 * The alternate "file" is actually a pipe.
260351278Sdim		 * f has already been set to the file descriptor of the pipe
261351278Sdim		 * in the call to open_altfile above.
262351278Sdim		 * Keep the file descriptor open because it was opened
263351278Sdim		 * via popen(), and pclose() wants to close it.
264351278Sdim		 */
265351278Sdim		chflags |= CH_POPENED;
266351278Sdim	} else if (strcmp(open_filename, "-") == 0)
267351278Sdim	{
268351278Sdim		/*
269351278Sdim		 * Use standard input.
270351278Sdim		 * Keep the file descriptor open because we can't reopen it.
271351278Sdim		 */
272351278Sdim		f = fd0;
273351278Sdim		chflags |= CH_KEEPOPEN;
274351278Sdim		/*
275351278Sdim		 * Must switch stdin to BINARY mode.
276351278Sdim		 */
277351278Sdim		SET_BINARY(f);
278351278Sdim#if MSDOS_COMPILER==DJGPPC
279351278Sdim		/*
280351278Sdim		 * Setting stdin to binary by default causes
281351278Sdim		 * Ctrl-C to not raise SIGINT.  We must undo
282351278Sdim		 * that side-effect.
283351278Sdim		 */
284351278Sdim		__djgpp_set_ctrl_c(1);
285351278Sdim#endif
286351278Sdim	} else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
287360784Sdim	{
288351278Sdim		f = -1;
289351278Sdim		chflags |= CH_HELPFILE;
290351278Sdim	} else if ((parg.p_string = bad_file(open_filename)) != NULL)
291351278Sdim	{
292351278Sdim		/*
293351278Sdim		 * It looks like a bad file.  Don't try to open it.
294351278Sdim		 */
295351278Sdim		error("%s", &parg);
296360784Sdim		free(parg.p_string);
297351278Sdim	    err1:
298351278Sdim		if (alt_filename != NULL)
299351278Sdim		{
300351278Sdim			close_altfile(alt_filename, filename, alt_pipe);
301351278Sdim			free(alt_filename);
302351278Sdim		}
303351278Sdim		del_ifile(ifile);
304351278Sdim		free(filename);
305351278Sdim		/*
306351278Sdim		 * Re-open the current file.
307351278Sdim		 */
308351278Sdim		reedit_ifile(was_curr_ifile);
309351278Sdim		return (1);
310351278Sdim	} else if ((f = open(open_filename, OPEN_READ)) < 0)
311351278Sdim	{
312351278Sdim		/*
313351278Sdim		 * Got an error trying to open it.
314351278Sdim		 */
315351278Sdim		parg.p_string = errno_message(filename);
316351278Sdim		error("%s", &parg);
317351278Sdim		free(parg.p_string);
318351278Sdim	    	goto err1;
319351278Sdim	} else
320351278Sdim	{
321351278Sdim		chflags |= CH_CANSEEK;
322351278Sdim		if (!force_open && !opened(ifile) && bin_file(f))
323351278Sdim		{
324351278Sdim			/*
325351278Sdim			 * Looks like a binary file.
326351278Sdim			 * Ask user if we should proceed.
327351278Sdim			 */
328351278Sdim			parg.p_string = filename;
329351278Sdim			answer = query("\"%s\" may be a binary file.  See it anyway? ",
330351278Sdim				&parg);
331351278Sdim			if (answer != 'y' && answer != 'Y')
332351278Sdim			{
333351278Sdim				close(f);
334351278Sdim				goto err1;
335351278Sdim			}
336351278Sdim		}
337351278Sdim	}
338351278Sdim
339351278Sdim	/*
340351278Sdim	 * Get the new ifile.
341351278Sdim	 * Get the saved position for the file.
342351278Sdim	 */
343351278Sdim	if (was_curr_ifile != NULL_IFILE)
344351278Sdim	{
345351278Sdim		old_ifile = was_curr_ifile;
346351278Sdim		unsave_ifile(was_curr_ifile);
347351278Sdim	}
348351278Sdim	curr_ifile = ifile;
349351278Sdim	curr_altfilename = alt_filename;
350351278Sdim	curr_altpipe = alt_pipe;
351351278Sdim	set_open(curr_ifile); /* File has been opened */
352351278Sdim	get_pos(curr_ifile, &initial_scrpos);
353351278Sdim	new_file = TRUE;
354351278Sdim	ch_init(f, chflags);
355351278Sdim
356351278Sdim	if (!(chflags & CH_HELPFILE))
357351278Sdim	{
358351278Sdim#if LOGFILE
359351278Sdim		if (namelogfile != NULL && is_tty)
360351278Sdim			use_logfile(namelogfile);
361351278Sdim#endif
362351278Sdim		if (every_first_cmd != NULL)
363351278Sdim			ungetsc(every_first_cmd);
364351278Sdim	}
365351278Sdim
366351278Sdim	no_display = !any_display;
367351278Sdim	flush();
368351278Sdim	any_display = TRUE;
369351278Sdim
370351278Sdim	if (is_tty)
371351278Sdim	{
372351278Sdim		/*
373351278Sdim		 * Output is to a real tty.
374351278Sdim		 */
375351278Sdim
376351278Sdim		/*
377351278Sdim		 * Indicate there is nothing displayed yet.
378351278Sdim		 */
379351278Sdim		pos_clear();
380351278Sdim		clr_linenum();
381351278Sdim#if HILITE_SEARCH
382351278Sdim		clr_hilite();
383351278Sdim#endif
384351278Sdim		cmd_addhist(ml_examine, filename);
385351278Sdim		if (no_display && errmsgs > 0)
386351278Sdim		{
387351278Sdim			/*
388351278Sdim			 * We displayed some messages on error output
389351278Sdim			 * (file descriptor 2; see error() function).
390351278Sdim			 * Before erasing the screen contents,
391351278Sdim			 * display the file name and wait for a keystroke.
392351278Sdim			 */
393351278Sdim			parg.p_string = filename;
394351278Sdim			error("%s", &parg);
395351278Sdim		}
396351278Sdim	}
397351278Sdim	free(filename);
398351278Sdim	return (0);
399351278Sdim}
400351278Sdim
401351278Sdim/*
402351278Sdim * Edit a space-separated list of files.
403351278Sdim * For each filename in the list, enter it into the ifile list.
404351278Sdim * Then edit the first one.
405351278Sdim */
406351278Sdim	public int
407351278Sdimedit_list(filelist)
408351278Sdim	char *filelist;
409351278Sdim{
410351278Sdim	IFILE save_ifile;
411351278Sdim	char *good_filename;
412351278Sdim	char *filename;
413351278Sdim	char *gfilelist;
414351278Sdim	char *gfilename;
415351278Sdim	struct textlist tl_files;
416351278Sdim	struct textlist tl_gfiles;
417351278Sdim
418351278Sdim	save_ifile = save_curr_ifile();
419351278Sdim	good_filename = NULL;
420351278Sdim
421351278Sdim	/*
422351278Sdim	 * Run thru each filename in the list.
423351278Sdim	 * Try to glob the filename.
424351278Sdim	 * If it doesn't expand, just try to open the filename.
425351278Sdim	 * If it does expand, try to open each name in that list.
426351278Sdim	 */
427351278Sdim	init_textlist(&tl_files, filelist);
428351278Sdim	filename = NULL;
429351278Sdim	while ((filename = forw_textlist(&tl_files, filename)) != NULL)
430351278Sdim	{
431351278Sdim		gfilelist = lglob(filename);
432351278Sdim		init_textlist(&tl_gfiles, gfilelist);
433351278Sdim		gfilename = NULL;
434351278Sdim		while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
435351278Sdim		{
436351278Sdim			if (edit(gfilename) == 0 && good_filename == NULL)
437351278Sdim				good_filename = get_filename(curr_ifile);
438351278Sdim		}
439351278Sdim		free(gfilelist);
440351278Sdim	}
441351278Sdim	/*
442351278Sdim	 * Edit the first valid filename in the list.
443351278Sdim	 */
444351278Sdim	if (good_filename == NULL)
445351278Sdim	{
446351278Sdim		unsave_ifile(save_ifile);
447351278Sdim		return (1);
448351278Sdim	}
449360784Sdim	if (get_ifile(good_filename, curr_ifile) == curr_ifile)
450351278Sdim	{
451351278Sdim		/*
452351278Sdim		 * Trying to edit the current file; don't reopen it.
453351278Sdim		 */
454351278Sdim		unsave_ifile(save_ifile);
455351278Sdim		return (0);
456351278Sdim	}
457351278Sdim	reedit_ifile(save_ifile);
458351278Sdim	return (edit(good_filename));
459351278Sdim}
460351278Sdim
461351278Sdim/*
462351278Sdim * Edit the first file in the command line (ifile) list.
463351278Sdim */
464351278Sdim	public int
465351278Sdimedit_first()
466351278Sdim{
467351278Sdim	curr_ifile = NULL_IFILE;
468351278Sdim	return (edit_next(1));
469351278Sdim}
470351278Sdim
471351278Sdim/*
472351278Sdim * Edit the last file in the command line (ifile) list.
473351278Sdim */
474351278Sdim	public int
475351278Sdimedit_last()
476351278Sdim{
477351278Sdim	curr_ifile = NULL_IFILE;
478351278Sdim	return (edit_prev(1));
479351278Sdim}
480351278Sdim
481351278Sdim
482351278Sdim/*
483351278Sdim * Edit the next or previous file in the command line (ifile) list.
484351278Sdim */
485351278Sdim	static int
486351278Sdimedit_istep(h, n, dir)
487351278Sdim	IFILE h;
488351278Sdim	int n;
489351278Sdim	int dir;
490351278Sdim{
491351278Sdim	IFILE next;
492351278Sdim
493351278Sdim	/*
494351278Sdim	 * Skip n filenames, then try to edit each filename.
495351278Sdim	 */
496351278Sdim	for (;;)
497351278Sdim	{
498351278Sdim		next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
499351278Sdim		if (--n < 0)
500351278Sdim		{
501351278Sdim			if (edit_ifile(h) == 0)
502351278Sdim				break;
503351278Sdim		}
504351278Sdim		if (next == NULL_IFILE)
505351278Sdim		{
506351278Sdim			/*
507			 * Reached end of the ifile list.
508			 */
509			return (1);
510		}
511		if (ABORT_SIGS())
512		{
513			/*
514			 * Interrupt breaks out, if we're in a long
515			 * list of files that can't be opened.
516			 */
517			return (1);
518		}
519		h = next;
520	}
521	/*
522	 * Found a file that we can edit.
523	 */
524	return (0);
525}
526
527	static int
528edit_inext(h, n)
529	IFILE h;
530	int n;
531{
532	return (edit_istep(h, n, 1));
533}
534
535	public int
536edit_next(n)
537	int n;
538{
539	return edit_istep(curr_ifile, n, 1);
540}
541
542	static int
543edit_iprev(h, n)
544	IFILE h;
545	int n;
546{
547	return (edit_istep(h, n, -1));
548}
549
550	public int
551edit_prev(n)
552	int n;
553{
554	return edit_istep(curr_ifile, n, -1);
555}
556
557/*
558 * Edit a specific file in the command line (ifile) list.
559 */
560	public int
561edit_index(n)
562	int n;
563{
564	IFILE h;
565
566	h = NULL_IFILE;
567	do
568	{
569		if ((h = next_ifile(h)) == NULL_IFILE)
570		{
571			/*
572			 * Reached end of the list without finding it.
573			 */
574			return (1);
575		}
576	} while (get_index(h) != n);
577
578	return (edit_ifile(h));
579}
580
581	public IFILE
582save_curr_ifile()
583{
584	if (curr_ifile != NULL_IFILE)
585		hold_ifile(curr_ifile, 1);
586	return (curr_ifile);
587}
588
589	public void
590unsave_ifile(save_ifile)
591	IFILE save_ifile;
592{
593	if (save_ifile != NULL_IFILE)
594		hold_ifile(save_ifile, -1);
595}
596
597/*
598 * Reedit the ifile which was previously open.
599 */
600	public void
601reedit_ifile(save_ifile)
602	IFILE save_ifile;
603{
604	IFILE next;
605	IFILE prev;
606
607	/*
608	 * Try to reopen the ifile.
609	 * Note that opening it may fail (maybe the file was removed),
610	 * in which case the ifile will be deleted from the list.
611	 * So save the next and prev ifiles first.
612	 */
613	unsave_ifile(save_ifile);
614	next = next_ifile(save_ifile);
615	prev = prev_ifile(save_ifile);
616	if (edit_ifile(save_ifile) == 0)
617		return;
618	/*
619	 * If can't reopen it, open the next input file in the list.
620	 */
621	if (next != NULL_IFILE && edit_inext(next, 0) == 0)
622		return;
623	/*
624	 * If can't open THAT one, open the previous input file in the list.
625	 */
626	if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
627		return;
628	/*
629	 * If can't even open that, we're stuck.  Just quit.
630	 */
631	quit(QUIT_ERROR);
632}
633
634/*
635 * Edit standard input.
636 */
637	public int
638edit_stdin()
639{
640	if (isatty(fd0))
641	{
642		error("Missing filename (\"less --help\" for help)", NULL_PARG);
643		quit(QUIT_OK);
644	}
645	return (edit("-"));
646}
647
648/*
649 * Copy a file directly to standard output.
650 * Used if standard output is not a tty.
651 */
652	public void
653cat_file()
654{
655	register int c;
656
657	while ((c = ch_forw_get()) != EOI)
658		putchr(c);
659	flush();
660}
661
662#if LOGFILE
663
664/*
665 * If the user asked for a log file and our input file
666 * is standard input, create the log file.
667 * We take care not to blindly overwrite an existing file.
668 */
669	public void
670use_logfile(filename)
671	char *filename;
672{
673	register int exists;
674	register int answer;
675	PARG parg;
676
677	if (ch_getflags() & CH_CANSEEK)
678		/*
679		 * Can't currently use a log file on a file that can seek.
680		 */
681		return;
682
683	/*
684	 * {{ We could use access() here. }}
685	 */
686	filename = unquote_file(filename);
687	exists = open(filename, OPEN_READ);
688	close(exists);
689	exists = (exists >= 0);
690
691	/*
692	 * Decide whether to overwrite the log file or append to it.
693	 * If it doesn't exist we "overwrite" it.
694	 */
695	if (!exists || force_logfile)
696	{
697		/*
698		 * Overwrite (or create) the log file.
699		 */
700		answer = 'O';
701	} else
702	{
703		/*
704		 * Ask user what to do.
705		 */
706		parg.p_string = filename;
707		answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
708	}
709
710loop:
711	switch (answer)
712	{
713	case 'O': case 'o':
714		/*
715		 * Overwrite: create the file.
716		 */
717		logfile = creat(filename, 0644);
718		break;
719	case 'A': case 'a':
720		/*
721		 * Append: open the file and seek to the end.
722		 */
723		logfile = open(filename, OPEN_APPEND);
724		if (lseek(logfile, (off_t)0, 2) == BAD_LSEEK)
725		{
726			close(logfile);
727			logfile = -1;
728		}
729		break;
730	case 'D': case 'd':
731		/*
732		 * Don't do anything.
733		 */
734		free(filename);
735		return;
736	case 'q':
737		quit(QUIT_OK);
738		/*NOTREACHED*/
739	default:
740		/*
741		 * Eh?
742		 */
743		answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG);
744		goto loop;
745	}
746
747	if (logfile < 0)
748	{
749		/*
750		 * Error in opening logfile.
751		 */
752		parg.p_string = filename;
753		error("Cannot write to \"%s\"", &parg);
754		free(filename);
755		return;
756	}
757	free(filename);
758	SET_BINARY(logfile);
759}
760
761#endif
762