"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "less-424/edit.c" of archive less-424.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * Copyright (C) 1984-2008  Mark Nudelman
    3  *
    4  * You may distribute under the terms of either the GNU General Public
    5  * License or the Less License, as specified in the README file.
    6  *
    7  * For more information about less, or for information on how to
    8  * contact the author, see the README file.
    9  */
   10 
   11 
   12 #include "less.h"
   13 #if HAVE_STAT
   14 #include <sys/stat.h>
   15 #endif
   16 
   17 public int fd0 = 0;
   18 
   19 extern int new_file;
   20 extern int errmsgs;
   21 extern int cbufs;
   22 extern char *every_first_cmd;
   23 extern int any_display;
   24 extern int force_open;
   25 extern int is_tty;
   26 extern int sigs;
   27 extern IFILE curr_ifile;
   28 extern IFILE old_ifile;
   29 extern struct scrpos initial_scrpos;
   30 extern void constant *ml_examine;
   31 #if SPACES_IN_FILENAMES
   32 extern char openquote;
   33 extern char closequote;
   34 #endif
   35 
   36 #if LOGFILE
   37 extern int logfile;
   38 extern int force_logfile;
   39 extern char *namelogfile;
   40 #endif
   41 
   42 #if HAVE_STAT_INO
   43 public dev_t curr_dev;
   44 public ino_t curr_ino;
   45 #endif
   46 
   47 char *curr_altfilename = NULL;
   48 static void *curr_altpipe;
   49 
   50 
   51 /*
   52  * Textlist functions deal with a list of words separated by spaces.
   53  * init_textlist sets up a textlist structure.
   54  * forw_textlist uses that structure to iterate thru the list of
   55  * words, returning each one as a standard null-terminated string.
   56  * back_textlist does the same, but runs thru the list backwards.
   57  */
   58 	public void
   59 init_textlist(tlist, str)
   60 	struct textlist *tlist;
   61 	char *str;
   62 {
   63 	char *s;
   64 #if SPACES_IN_FILENAMES
   65 	int meta_quoted = 0;
   66 	int delim_quoted = 0;
   67 	char *esc = get_meta_escape();
   68 	int esclen = strlen(esc);
   69 #endif
   70 
   71 	tlist->string = skipsp(str);
   72 	tlist->endstring = tlist->string + strlen(tlist->string);
   73 	for (s = str;  s < tlist->endstring;  s++)
   74 	{
   75 #if SPACES_IN_FILENAMES
   76 		if (meta_quoted)
   77 		{
   78 			meta_quoted = 0;
   79 		} else if (esclen > 0 && s + esclen < tlist->endstring &&
   80 		           strncmp(s, esc, esclen) == 0)
   81 		{
   82 			meta_quoted = 1;
   83 			s += esclen - 1;
   84 		} else if (delim_quoted)
   85 		{
   86 			if (*s == closequote)
   87 				delim_quoted = 0;
   88 		} else /* (!delim_quoted) */
   89 		{
   90 			if (*s == openquote)
   91 				delim_quoted = 1;
   92 			else if (*s == ' ')
   93 				*s = '\0';
   94 		}
   95 #else
   96 		if (*s == ' ')
   97 			*s = '\0';
   98 #endif
   99 	}
  100 }
  101 
  102 	public char *
  103 forw_textlist(tlist, prev)
  104 	struct textlist *tlist;
  105 	char *prev;
  106 {
  107 	char *s;
  108 
  109 	/*
  110 	 * prev == NULL means return the first word in the list.
  111 	 * Otherwise, return the word after "prev".
  112 	 */
  113 	if (prev == NULL)
  114 		s = tlist->string;
  115 	else
  116 		s = prev + strlen(prev);
  117 	if (s >= tlist->endstring)
  118 		return (NULL);
  119 	while (*s == '\0')
  120 		s++;
  121 	if (s >= tlist->endstring)
  122 		return (NULL);
  123 	return (s);
  124 }
  125 
  126 	public char *
  127 back_textlist(tlist, prev)
  128 	struct textlist *tlist;
  129 	char *prev;
  130 {
  131 	char *s;
  132 
  133 	/*
  134 	 * prev == NULL means return the last word in the list.
  135 	 * Otherwise, return the word before "prev".
  136 	 */
  137 	if (prev == NULL)
  138 		s = tlist->endstring;
  139 	else if (prev <= tlist->string)
  140 		return (NULL);
  141 	else
  142 		s = prev - 1;
  143 	while (*s == '\0')
  144 		s--;
  145 	if (s <= tlist->string)
  146 		return (NULL);
  147 	while (s[-1] != '\0' && s > tlist->string)
  148 		s--;
  149 	return (s);
  150 }
  151 
  152 /*
  153  * Close the current input file.
  154  */
  155 	static void
  156 close_file()
  157 {
  158 	struct scrpos scrpos;
  159 
  160 	if (curr_ifile == NULL_IFILE)
  161 		return;
  162 
  163 	/*
  164 	 * Save the current position so that we can return to
  165 	 * the same position if we edit this file again.
  166 	 */
  167 	get_scrpos(&scrpos);
  168 	if (scrpos.pos != NULL_POSITION)
  169 	{
  170 		store_pos(curr_ifile, &scrpos);
  171 		lastmark();
  172 	}
  173 	/*
  174 	 * Close the file descriptor, unless it is a pipe.
  175 	 */
  176 	ch_close();
  177 	/*
  178 	 * If we opened a file using an alternate name,
  179 	 * do special stuff to close it.
  180 	 */
  181 	if (curr_altfilename != NULL)
  182 	{
  183 		close_altfile(curr_altfilename, get_filename(curr_ifile),
  184 				curr_altpipe);
  185 		free(curr_altfilename);
  186 		curr_altfilename = NULL;
  187 	}
  188 	curr_ifile = NULL_IFILE;
  189 #if HAVE_STAT_INO
  190 	curr_ino = curr_dev = 0;
  191 #endif
  192 }
  193 
  194 /*
  195  * Edit a new file (given its name).
  196  * Filename == "-" means standard input.
  197  * Filename == NULL means just close the current file.
  198  */
  199 	public int
  200 edit(filename)
  201 	char *filename;
  202 {
  203 	if (filename == NULL)
  204 		return (edit_ifile(NULL_IFILE));
  205 	return (edit_ifile(get_ifile(filename, curr_ifile)));
  206 }
  207 
  208 /*
  209  * Edit a new file (given its IFILE).
  210  * ifile == NULL means just close the current file.
  211  */
  212 	public int
  213 edit_ifile(ifile)
  214 	IFILE ifile;
  215 {
  216 	int f;
  217 	int answer;
  218 	int no_display;
  219 	int chflags;
  220 	char *filename;
  221 	char *open_filename;
  222 	char *qopen_filename;
  223 	char *alt_filename;
  224 	void *alt_pipe;
  225 	IFILE was_curr_ifile;
  226 	PARG parg;
  227 
  228 	if (ifile == curr_ifile)
  229 	{
  230 		/*
  231 		 * Already have the correct file open.
  232 		 */
  233 		return (0);
  234 	}
  235 
  236 	/*
  237 	 * We must close the currently open file now.
  238 	 * This is necessary to make the open_altfile/close_altfile pairs
  239 	 * nest properly (or rather to avoid nesting at all).
  240 	 * {{ Some stupid implementations of popen() mess up if you do:
  241 	 *    fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }}
  242 	 */
  243 #if LOGFILE
  244 	end_logfile();
  245 #endif
  246 	was_curr_ifile = save_curr_ifile();
  247 	if (curr_ifile != NULL_IFILE)
  248 	{
  249 		chflags = ch_getflags();
  250 		close_file();
  251 		if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1)
  252 		{
  253 			/*
  254 			 * Don't keep the help file in the ifile list.
  255 			 */
  256 			del_ifile(was_curr_ifile);
  257 			was_curr_ifile = old_ifile;
  258 		}
  259 	}
  260 
  261 	if (ifile == NULL_IFILE)
  262 	{
  263 		/*
  264 		 * No new file to open.
  265 		 * (Don't set old_ifile, because if you call edit_ifile(NULL),
  266 		 *  you're supposed to have saved curr_ifile yourself,
  267 		 *  and you'll restore it if necessary.)
  268 		 */
  269 		unsave_ifile(was_curr_ifile);
  270 		return (0);
  271 	}
  272 
  273 	filename = save(get_filename(ifile));
  274 	/*
  275 	 * See if LESSOPEN specifies an "alternate" file to open.
  276 	 */
  277 	alt_pipe = NULL;
  278 	alt_filename = open_altfile(filename, &f, &alt_pipe);
  279 	open_filename = (alt_filename != NULL) ? alt_filename : filename;
  280 	qopen_filename = shell_unquote(open_filename);
  281 
  282 	chflags = 0;
  283 	if (alt_pipe != NULL)
  284 	{
  285 		/*
  286 		 * The alternate "file" is actually a pipe.
  287 		 * f has already been set to the file descriptor of the pipe
  288 		 * in the call to open_altfile above.
  289 		 * Keep the file descriptor open because it was opened
  290 		 * via popen(), and pclose() wants to close it.
  291 		 */
  292 		chflags |= CH_POPENED;
  293 	} else if (strcmp(open_filename, "-") == 0)
  294 	{
  295 		/*
  296 		 * Use standard input.
  297 		 * Keep the file descriptor open because we can't reopen it.
  298 		 */
  299 		f = fd0;
  300 		chflags |= CH_KEEPOPEN;
  301 		/*
  302 		 * Must switch stdin to BINARY mode.
  303 		 */
  304 		SET_BINARY(f);
  305 #if MSDOS_COMPILER==DJGPPC
  306 		/*
  307 		 * Setting stdin to binary by default causes
  308 		 * Ctrl-C to not raise SIGINT.  We must undo
  309 		 * that side-effect.
  310 		 */
  311 		__djgpp_set_ctrl_c(1);
  312 #endif
  313 	} else if (strcmp(open_filename, FAKE_HELPFILE) == 0)
  314 	{
  315 		f = -1;
  316 		chflags |= CH_HELPFILE;
  317 	} else if ((parg.p_string = bad_file(open_filename)) != NULL)
  318 	{
  319 		/*
  320 		 * It looks like a bad file.  Don't try to open it.
  321 		 */
  322 		error("%s", &parg);
  323 		free(parg.p_string);
  324 	    err1:
  325 		if (alt_filename != NULL)
  326 		{
  327 			close_altfile(alt_filename, filename, alt_pipe);
  328 			free(alt_filename);
  329 		}
  330 		del_ifile(ifile);
  331 		free(qopen_filename);
  332 		free(filename);
  333 		/*
  334 		 * Re-open the current file.
  335 		 */
  336 		if (was_curr_ifile == ifile)
  337 		{
  338 			/*
  339 			 * Whoops.  The "current" ifile is the one we just deleted.
  340 			 * Just give up.
  341 			 */
  342 			quit(QUIT_ERROR);
  343 		}
  344 		reedit_ifile(was_curr_ifile);
  345 		return (1);
  346 	} else if ((f = open(qopen_filename, OPEN_READ)) < 0)
  347 	{
  348 		/*
  349 		 * Got an error trying to open it.
  350 		 */
  351 		parg.p_string = errno_message(filename);
  352 		error("%s", &parg);
  353 		free(parg.p_string);
  354 	    	goto err1;
  355 	} else
  356 	{
  357 		chflags |= CH_CANSEEK;
  358 		if (!force_open && !opened(ifile) && bin_file(f))
  359 		{
  360 			/*
  361 			 * Looks like a binary file.
  362 			 * Ask user if we should proceed.
  363 			 */
  364 			parg.p_string = filename;
  365 			answer = query("\"%s\" may be a binary file.  See it anyway? ",
  366 				&parg);
  367 			if (answer != 'y' && answer != 'Y')
  368 			{
  369 				close(f);
  370 				goto err1;
  371 			}
  372 		}
  373 	}
  374 
  375 	/*
  376 	 * Get the new ifile.
  377 	 * Get the saved position for the file.
  378 	 */
  379 	if (was_curr_ifile != NULL_IFILE)
  380 	{
  381 		old_ifile = was_curr_ifile;
  382 		unsave_ifile(was_curr_ifile);
  383 	}
  384 	curr_ifile = ifile;
  385 	curr_altfilename = alt_filename;
  386 	curr_altpipe = alt_pipe;
  387 	set_open(curr_ifile); /* File has been opened */
  388 	get_pos(curr_ifile, &initial_scrpos);
  389 	new_file = TRUE;
  390 	ch_init(f, chflags);
  391 
  392 	if (!(chflags & CH_HELPFILE))
  393 	{
  394 #if LOGFILE
  395 		if (namelogfile != NULL && is_tty)
  396 			use_logfile(namelogfile);
  397 #endif
  398 #if HAVE_STAT_INO
  399 		/* Remember the i-number and device of the opened file. */
  400 		{
  401 			struct stat statbuf;
  402 			int r = stat(qopen_filename, &statbuf);
  403 			if (r == 0)
  404 			{
  405 				curr_ino = statbuf.st_ino;
  406 				curr_dev = statbuf.st_dev;
  407 			}
  408 		}
  409 #endif
  410 		if (every_first_cmd != NULL)
  411 			ungetsc(every_first_cmd);
  412 	}
  413 
  414 	free(qopen_filename);
  415 	no_display = !any_display;
  416 	flush();
  417 	any_display = TRUE;
  418 
  419 	if (is_tty)
  420 	{
  421 		/*
  422 		 * Output is to a real tty.
  423 		 */
  424 
  425 		/*
  426 		 * Indicate there is nothing displayed yet.
  427 		 */
  428 		pos_clear();
  429 		clr_linenum();
  430 #if HILITE_SEARCH
  431 		clr_hilite();
  432 #endif
  433 		cmd_addhist(ml_examine, filename);
  434 		if (no_display && errmsgs > 0)
  435 		{
  436 			/*
  437 			 * We displayed some messages on error output
  438 			 * (file descriptor 2; see error() function).
  439 			 * Before erasing the screen contents,
  440 			 * display the file name and wait for a keystroke.
  441 			 */
  442 			parg.p_string = filename;
  443 			error("%s", &parg);
  444 		}
  445 	}
  446 	free(filename);
  447 	return (0);
  448 }
  449 
  450 /*
  451  * Edit a space-separated list of files.
  452  * For each filename in the list, enter it into the ifile list.
  453  * Then edit the first one.
  454  */
  455 	public int
  456 edit_list(filelist)
  457 	char *filelist;
  458 {
  459 	IFILE save_ifile;
  460 	char *good_filename;
  461 	char *filename;
  462 	char *gfilelist;
  463 	char *gfilename;
  464 	struct textlist tl_files;
  465 	struct textlist tl_gfiles;
  466 
  467 	save_ifile = save_curr_ifile();
  468 	good_filename = NULL;
  469 
  470 	/*
  471 	 * Run thru each filename in the list.
  472 	 * Try to glob the filename.
  473 	 * If it doesn't expand, just try to open the filename.
  474 	 * If it does expand, try to open each name in that list.
  475 	 */
  476 	init_textlist(&tl_files, filelist);
  477 	filename = NULL;
  478 	while ((filename = forw_textlist(&tl_files, filename)) != NULL)
  479 	{
  480 		gfilelist = lglob(filename);
  481 		init_textlist(&tl_gfiles, gfilelist);
  482 		gfilename = NULL;
  483 		while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL)
  484 		{
  485 			if (edit(gfilename) == 0 && good_filename == NULL)
  486 				good_filename = get_filename(curr_ifile);
  487 		}
  488 		free(gfilelist);
  489 	}
  490 	/*
  491 	 * Edit the first valid filename in the list.
  492 	 */
  493 	if (good_filename == NULL)
  494 	{
  495 		unsave_ifile(save_ifile);
  496 		return (1);
  497 	}
  498 	if (get_ifile(good_filename, curr_ifile) == curr_ifile)
  499 	{
  500 		/*
  501 		 * Trying to edit the current file; don't reopen it.
  502 		 */
  503 		unsave_ifile(save_ifile);
  504 		return (0);
  505 	}
  506 	reedit_ifile(save_ifile);
  507 	return (edit(good_filename));
  508 }
  509 
  510 /*
  511  * Edit the first file in the command line (ifile) list.
  512  */
  513 	public int
  514 edit_first()
  515 {
  516 	curr_ifile = NULL_IFILE;
  517 	return (edit_next(1));
  518 }
  519 
  520 /*
  521  * Edit the last file in the command line (ifile) list.
  522  */
  523 	public int
  524 edit_last()
  525 {
  526 	curr_ifile = NULL_IFILE;
  527 	return (edit_prev(1));
  528 }
  529 
  530 
  531 /*
  532  * Edit the n-th next or previous file in the command line (ifile) list.
  533  */
  534 	static int
  535 edit_istep(h, n, dir)
  536 	IFILE h;
  537 	int n;
  538 	int dir;
  539 {
  540 	IFILE next;
  541 
  542 	/*
  543 	 * Skip n filenames, then try to edit each filename.
  544 	 */
  545 	for (;;)
  546 	{
  547 		next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
  548 		if (--n < 0)
  549 		{
  550 			if (edit_ifile(h) == 0)
  551 				break;
  552 		}
  553 		if (next == NULL_IFILE)
  554 		{
  555 			/*
  556 			 * Reached end of the ifile list.
  557 			 */
  558 			return (1);
  559 		}
  560 		if (ABORT_SIGS())
  561 		{
  562 			/*
  563 			 * Interrupt breaks out, if we're in a long
  564 			 * list of files that can't be opened.
  565 			 */
  566 			return (1);
  567 		}
  568 		h = next;
  569 	}
  570 	/*
  571 	 * Found a file that we can edit.
  572 	 */
  573 	return (0);
  574 }
  575 
  576 	static int
  577 edit_inext(h, n)
  578 	IFILE h;
  579 	int n;
  580 {
  581 	return (edit_istep(h, n, +1));
  582 }
  583 
  584 	public int
  585 edit_next(n)
  586 	int n;
  587 {
  588 	return edit_istep(curr_ifile, n, +1);
  589 }
  590 
  591 	static int
  592 edit_iprev(h, n)
  593 	IFILE h;
  594 	int n;
  595 {
  596 	return (edit_istep(h, n, -1));
  597 }
  598 
  599 	public int
  600 edit_prev(n)
  601 	int n;
  602 {
  603 	return edit_istep(curr_ifile, n, -1);
  604 }
  605 
  606 /*
  607  * Edit a specific file in the command line (ifile) list.
  608  */
  609 	public int
  610 edit_index(n)
  611 	int n;
  612 {
  613 	IFILE h;
  614 
  615 	h = NULL_IFILE;
  616 	do
  617 	{
  618 		if ((h = next_ifile(h)) == NULL_IFILE)
  619 		{
  620 			/*
  621 			 * Reached end of the list without finding it.
  622 			 */
  623 			return (1);
  624 		}
  625 	} while (get_index(h) != n);
  626 
  627 	return (edit_ifile(h));
  628 }
  629 
  630 	public IFILE
  631 save_curr_ifile()
  632 {
  633 	if (curr_ifile != NULL_IFILE)
  634 		hold_ifile(curr_ifile, 1);
  635 	return (curr_ifile);
  636 }
  637 
  638 	public void
  639 unsave_ifile(save_ifile)
  640 	IFILE save_ifile;
  641 {
  642 	if (save_ifile != NULL_IFILE)
  643 		hold_ifile(save_ifile, -1);
  644 }
  645 
  646 /*
  647  * Reedit the ifile which was previously open.
  648  */
  649 	public void
  650 reedit_ifile(save_ifile)
  651 	IFILE save_ifile;
  652 {
  653 	IFILE next;
  654 	IFILE prev;
  655 
  656 	/*
  657 	 * Try to reopen the ifile.
  658 	 * Note that opening it may fail (maybe the file was removed),
  659 	 * in which case the ifile will be deleted from the list.
  660 	 * So save the next and prev ifiles first.
  661 	 */
  662 	unsave_ifile(save_ifile);
  663 	next = next_ifile(save_ifile);
  664 	prev = prev_ifile(save_ifile);
  665 	if (edit_ifile(save_ifile) == 0)
  666 		return;
  667 	/*
  668 	 * If can't reopen it, open the next input file in the list.
  669 	 */
  670 	if (next != NULL_IFILE && edit_inext(next, 0) == 0)
  671 		return;
  672 	/*
  673 	 * If can't open THAT one, open the previous input file in the list.
  674 	 */
  675 	if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0)
  676 		return;
  677 	/*
  678 	 * If can't even open that, we're stuck.  Just quit.
  679 	 */
  680 	quit(QUIT_ERROR);
  681 }
  682 
  683 	public void
  684 reopen_curr_ifile()
  685 {
  686 	IFILE save_ifile = save_curr_ifile();
  687 	close_file();
  688 	reedit_ifile(save_ifile);
  689 }
  690 
  691 /*
  692  * Edit standard input.
  693  */
  694 	public int
  695 edit_stdin()
  696 {
  697 	if (isatty(fd0))
  698 	{
  699 		error("Missing filename (\"less --help\" for help)", NULL_PARG);
  700 		quit(QUIT_OK);
  701 	}
  702 	return (edit("-"));
  703 }
  704 
  705 /*
  706  * Copy a file directly to standard output.
  707  * Used if standard output is not a tty.
  708  */
  709 	public void
  710 cat_file()
  711 {
  712 	register int c;
  713 
  714 	while ((c = ch_forw_get()) != EOI)
  715 		putchr(c);
  716 	flush();
  717 }
  718 
  719 #if LOGFILE
  720 
  721 /*
  722  * If the user asked for a log file and our input file
  723  * is standard input, create the log file.
  724  * We take care not to blindly overwrite an existing file.
  725  */
  726 	public void
  727 use_logfile(filename)
  728 	char *filename;
  729 {
  730 	register int exists;
  731 	register int answer;
  732 	PARG parg;
  733 
  734 	if (ch_getflags() & CH_CANSEEK)
  735 		/*
  736 		 * Can't currently use a log file on a file that can seek.
  737 		 */
  738 		return;
  739 
  740 	/*
  741 	 * {{ We could use access() here. }}
  742 	 */
  743 	filename = shell_unquote(filename);
  744 	exists = open(filename, OPEN_READ);
  745 	close(exists);
  746 	exists = (exists >= 0);
  747 
  748 	/*
  749 	 * Decide whether to overwrite the log file or append to it.
  750 	 * If it doesn't exist we "overwrite" it.
  751 	 */
  752 	if (!exists || force_logfile)
  753 	{
  754 		/*
  755 		 * Overwrite (or create) the log file.
  756 		 */
  757 		answer = 'O';
  758 	} else
  759 	{
  760 		/*
  761 		 * Ask user what to do.
  762 		 */
  763 		parg.p_string = filename;
  764 		answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
  765 	}
  766 
  767 loop:
  768 	switch (answer)
  769 	{
  770 	case 'O': case 'o':
  771 		/*
  772 		 * Overwrite: create the file.
  773 		 */
  774 		logfile = creat(filename, 0644);
  775 		break;
  776 	case 'A': case 'a':
  777 		/*
  778 		 * Append: open the file and seek to the end.
  779 		 */
  780 		logfile = open(filename, OPEN_APPEND);
  781 		if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK)
  782 		{
  783 			close(logfile);
  784 			logfile = -1;
  785 		}
  786 		break;
  787 	case 'D': case 'd':
  788 		/*
  789 		 * Don't do anything.
  790 		 */
  791 		free(filename);
  792 		return;
  793 	case 'q':
  794 		quit(QUIT_OK);
  795 		/*NOTREACHED*/
  796 	default:
  797 		/*
  798 		 * Eh?
  799 		 */
  800 		answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG);
  801 		goto loop;
  802 	}
  803 
  804 	if (logfile < 0)
  805 	{
  806 		/*
  807 		 * Error in opening logfile.
  808 		 */
  809 		parg.p_string = filename;
  810 		error("Cannot write to \"%s\"", &parg);
  811 		free(filename);
  812 		return;
  813 	}
  814 	free(filename);
  815 	SET_BINARY(logfile);
  816 }
  817 
  818 #endif