head	1.13;
access;
symbols
	perseant-exfatfs-base-20250801:1.13
	perseant-exfatfs-base-20240630:1.13
	perseant-exfatfs:1.13.0.36
	perseant-exfatfs-base:1.13
	cjep_sun2x:1.13.0.34
	cjep_sun2x-base:1.13
	cjep_staticlib_x-base1:1.13
	cjep_staticlib_x:1.13.0.32
	cjep_staticlib_x-base:1.13
	phil-wifi-20200421:1.13
	phil-wifi-20200411:1.13
	phil-wifi-20200406:1.13
	pgoyette-compat-merge-20190127:1.13
	pgoyette-compat-20190127:1.13
	pgoyette-compat-20190118:1.13
	pgoyette-compat-1226:1.13
	pgoyette-compat-1126:1.13
	pgoyette-compat-1020:1.13
	pgoyette-compat-0930:1.13
	pgoyette-compat-0906:1.13
	pgoyette-compat-0728:1.13
	pgoyette-compat-0625:1.13
	pgoyette-compat-0521:1.13
	pgoyette-compat-0502:1.13
	pgoyette-compat-0422:1.13
	pgoyette-compat-0415:1.13
	pgoyette-compat-0407:1.13
	pgoyette-compat-0330:1.13
	pgoyette-compat-0322:1.13
	pgoyette-compat-0315:1.13
	pgoyette-compat:1.13.0.30
	pgoyette-compat-base:1.13
	perseant-stdc-iso10646:1.13.0.28
	perseant-stdc-iso10646-base:1.13
	prg-localcount2-base3:1.13
	prg-localcount2-base2:1.13
	prg-localcount2-base1:1.13
	prg-localcount2:1.13.0.26
	prg-localcount2-base:1.13
	pgoyette-localcount-20170426:1.13
	bouyer-socketcan-base1:1.13
	pgoyette-localcount-20170320:1.13
	bouyer-socketcan:1.13.0.24
	bouyer-socketcan-base:1.13
	pgoyette-localcount-20170107:1.13
	pgoyette-localcount-20161104:1.13
	localcount-20160914:1.13
	pgoyette-localcount-20160806:1.13
	pgoyette-localcount-20160726:1.13
	pgoyette-localcount:1.13.0.22
	pgoyette-localcount-base:1.13
	netbsd-5-2-3-RELEASE:1.13
	netbsd-5-1-5-RELEASE:1.13
	yamt-pagecache-base9:1.13
	yamt-pagecache-tag8:1.13
	tls-earlyentropy:1.13.0.18
	tls-earlyentropy-base:1.13
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.13
	riastradh-drm2-base3:1.13
	netbsd-5-2-2-RELEASE:1.13
	netbsd-5-1-4-RELEASE:1.13
	netbsd-5-2-1-RELEASE:1.13
	netbsd-5-1-3-RELEASE:1.13
	agc-symver:1.13.0.20
	agc-symver-base:1.13
	tls-maxphys-base:1.13
	yamt-pagecache-base8:1.13
	netbsd-5-2:1.13.0.16
	yamt-pagecache-base7:1.13
	netbsd-5-2-RELEASE:1.13
	netbsd-5-2-RC1:1.13
	yamt-pagecache-base6:1.13
	yamt-pagecache-base5:1.13
	yamt-pagecache-base4:1.13
	netbsd-5-1-2-RELEASE:1.13
	netbsd-5-1-1-RELEASE:1.13
	yamt-pagecache-base3:1.13
	yamt-pagecache-base2:1.13
	yamt-pagecache:1.13.0.14
	yamt-pagecache-base:1.13
	bouyer-quota2-nbase:1.13
	bouyer-quota2:1.13.0.12
	bouyer-quota2-base:1.13
	matt-nb5-pq3:1.13.0.10
	matt-nb5-pq3-base:1.13
	netbsd-5-1:1.13.0.8
	netbsd-5-1-RELEASE:1.13
	netbsd-5-1-RC4:1.13
	netbsd-5-1-RC3:1.13
	netbsd-5-1-RC2:1.13
	netbsd-5-1-RC1:1.13
	netbsd-5-0-2-RELEASE:1.13
	netbsd-5-0-1-RELEASE:1.13
	jym-xensuspend-nbase:1.13
	netbsd-5-0:1.13.0.6
	netbsd-5-0-RELEASE:1.13
	netbsd-5-0-RC4:1.13
	netbsd-5-0-RC3:1.13
	netbsd-5-0-RC2:1.13
	jym-xensuspend:1.13.0.4
	jym-xensuspend-base:1.13
	netbsd-5-0-RC1:1.13
	netbsd-5:1.13.0.2
	netbsd-5-base:1.13
	matt-mips64-base2:1.12
	matt-mips64:1.12.0.26
	mjf-devfs2:1.12.0.24
	mjf-devfs2-base:1.12
	netbsd-4-0-1-RELEASE:1.12
	wrstuden-revivesa-base-3:1.12
	wrstuden-revivesa-base-2:1.12
	wrstuden-fixsa-newbase:1.12
	wrstuden-revivesa-base-1:1.12
	yamt-pf42-base4:1.12
	yamt-pf42-base3:1.12
	hpcarm-cleanup-nbase:1.12
	yamt-pf42-baseX:1.12
	yamt-pf42-base2:1.12
	wrstuden-revivesa:1.12.0.22
	wrstuden-revivesa-base:1.12
	yamt-pf42:1.12.0.20
	yamt-pf42-base:1.12
	keiichi-mipv6-nbase:1.12
	keiichi-mipv6:1.12.0.18
	keiichi-mipv6-base:1.12
	matt-armv6-nbase:1.12
	matt-armv6-prevmlocking:1.12
	wrstuden-fixsa-base-1:1.12
	netbsd-4-0:1.12.0.16
	netbsd-4-0-RELEASE:1.12
	cube-autoconf:1.12.0.14
	cube-autoconf-base:1.12
	netbsd-4-0-RC5:1.12
	netbsd-4-0-RC4:1.12
	netbsd-4-0-RC3:1.12
	netbsd-4-0-RC2:1.12
	netbsd-4-0-RC1:1.12
	matt-armv6:1.12.0.12
	matt-armv6-base:1.12
	matt-mips64-base:1.12
	hpcarm-cleanup:1.12.0.10
	hpcarm-cleanup-base:1.12
	netbsd-3-1-1-RELEASE:1.10
	netbsd-3-0-3-RELEASE:1.10
	wrstuden-fixsa:1.12.0.8
	wrstuden-fixsa-base:1.12
	abandoned-netbsd-4-base:1.12
	abandoned-netbsd-4:1.12.0.4
	netbsd-3-1:1.10.0.6
	netbsd-3-1-RELEASE:1.10
	netbsd-3-0-2-RELEASE:1.10
	netbsd-3-1-RC4:1.10
	netbsd-3-1-RC3:1.10
	netbsd-3-1-RC2:1.10
	netbsd-3-1-RC1:1.10
	netbsd-4:1.12.0.6
	netbsd-4-base:1.12
	chap-midi-nbase:1.12
	netbsd-3-0-1-RELEASE:1.10
	chap-midi:1.12.0.2
	chap-midi-base:1.12
	netbsd-3-0:1.10.0.4
	netbsd-3-0-RELEASE:1.10
	netbsd-3-0-RC6:1.10
	netbsd-3-0-RC5:1.10
	netbsd-3-0-RC4:1.10
	netbsd-3-0-RC3:1.10
	netbsd-3-0-RC2:1.10
	netbsd-3-0-RC1:1.10
	netbsd-2-0-3-RELEASE:1.9.4.2
	netbsd-2-1:1.9.6.1.0.2
	netbsd-2-1-RELEASE:1.9.6.1
	netbsd-2-1-RC6:1.9.6.1
	netbsd-2-1-RC5:1.9.6.1
	netbsd-2-1-RC4:1.9.6.1
	netbsd-2-1-RC3:1.9.6.1
	netbsd-2-1-RC2:1.9.6.1
	netbsd-2-1-RC1:1.9.6.1
	netbsd-2-0-2-RELEASE:1.9.4.2
	netbsd-3:1.10.0.2
	netbsd-3-base:1.10
	netbsd-2-0-1-RELEASE:1.9
	netbsd-2:1.9.0.6
	netbsd-2-base:1.9
	netbsd-2-0-RELEASE:1.9
	netbsd-2-0-RC5:1.9
	netbsd-2-0-RC4:1.9
	netbsd-2-0-RC3:1.9
	netbsd-2-0-RC2:1.9
	netbsd-2-0-RC1:1.9
	netbsd-2-0:1.9.0.4
	netbsd-2-0-base:1.9
	netbsd-1-6-PATCH002-RELEASE:1.9
	netbsd-1-6-PATCH002:1.9
	netbsd-1-6-PATCH002-RC4:1.9
	netbsd-1-6-PATCH002-RC3:1.9
	netbsd-1-6-PATCH002-RC2:1.9
	netbsd-1-6-PATCH002-RC1:1.9
	netbsd-1-6-PATCH001:1.9
	netbsd-1-6-PATCH001-RELEASE:1.9
	netbsd-1-6-PATCH001-RC3:1.9
	netbsd-1-6-PATCH001-RC2:1.9
	netbsd-1-6-PATCH001-RC1:1.9
	fvdl_fs64_base:1.9
	netbsd-1-6-RELEASE:1.9
	netbsd-1-6-RC3:1.9
	netbsd-1-6-RC2:1.9
	netbsd-1-6-RC1:1.9
	netbsd-1-6:1.9.0.2
	netbsd-1-6-base:1.9
	netbsd-1-5-PATCH003:1.7
	netbsd-1-5-PATCH002:1.7
	netbsd-1-5-PATCH001:1.7
	nvi_1_79:1.1.1.6
	netbsd-1-5-RELEASE:1.7
	netbsd-1-5-BETA2:1.7
	netbsd-1-5-BETA:1.7
	netbsd-1-4-PATCH003:1.7
	netbsd-1-5-ALPHA2:1.7
	netbsd-1-5:1.7.0.10
	netbsd-1-5-base:1.7
	minoura-xpg4dl-base:1.7
	minoura-xpg4dl:1.7.0.8
	netbsd-1-4-PATCH002:1.7
	wrstuden-devbsize-19991221:1.7
	wrstuden-devbsize:1.7.0.6
	wrstuden-devbsize-base:1.7
	comdex-fall-1999:1.7.0.4
	comdex-fall-1999-base:1.7
	netbsd-1-4-PATCH001:1.7
	netbsd-1-4-RELEASE:1.7
	netbsd-1-4:1.7.0.2
	netbsd-1-4-base:1.7
	netbsd-1-3-PATCH003:1.6
	netbsd-1-3-PATCH003-CANDIDATE2:1.6
	netbsd-1-3-PATCH003-CANDIDATE1:1.6
	netbsd-1-3-PATCH003-CANDIDATE0:1.6
	netbsd-1-3-PATCH002:1.6
	netbsd-1-3-PATCH001:1.6
	netbsd-1-3-RELEASE:1.6
	netbsd-1-3-BETA:1.6
	netbsd-1-3:1.6.0.2
	netbsd-1-3-base:1.6
	netbsd-1-2-PATCH001:1.6
	netbsd-1-2-RELEASE:1.6
	netbsd-1-2-BETA:1.6
	netbsd-1-2:1.6.0.4
	netbsd-1-2-base:1.6
	nvi_1_66:1.1.1.5
	BOSTIC:1.1.1
	netbsd-1-1-PATCH001:1.5
	netbsd-1-1-RELEASE:1.5
	netbsd-1-1:1.5.0.4
	netbsd-1-1-base:1.5
	netbsd-1-0-PATCH06:1.5
	netbsd-1-0-PATCH05:1.5
	netbsd-1-0-PATCH04:1.5
	netbsd-1-0-PATCH03:1.5
	netbsd-1-0-PATCH02:1.5
	netbsd-1-0-PATCH1:1.5
	netbsd-1-0-PATCH0:1.5
	netbsd-1-0-RELEASE:1.5
	netbsd-1-0:1.5.0.2
	nvi-1-34b:1.1.1.4
	nvi-1-33b:1.1.1.3
	netbsd-1-0-base:1.3
	nvi-1-11b:1.1.1.2
	nvi-1-03:1.1.1.1
	bostic-nvi:1.1.1;
locks; strict;
comment	@ * @;


1.13
date	2008.10.29.16.49.37;	author christos;	state dead;
branches;
next	1.12;

1.12
date	2006.03.19.05.01.48;	author rtr;	state Exp;
branches;
next	1.11;

1.11
date	2005.06.02.04.25.16;	author lukem;	state Exp;
branches;
next	1.10;

1.10
date	2005.02.12.12.53.23;	author aymeric;	state Exp;
branches;
next	1.9;

1.9
date	2002.04.09.01.47.34;	author thorpej;	state Exp;
branches
	1.9.4.1
	1.9.6.1;
next	1.8;

1.8
date	2001.03.31.11.37.51;	author aymeric;	state Exp;
branches;
next	1.7;

1.7
date	98.01.09.08.08.12;	author perry;	state Exp;
branches;
next	1.6;

1.6
date	96.05.20.03.48.11;	author mrg;	state Exp;
branches;
next	1.5;

1.5
date	94.08.17.20.13.10;	author cgd;	state Exp;
branches
	1.5.2.1;
next	1.4;

1.4
date	94.08.17.16.36.23;	author cgd;	state Exp;
branches;
next	1.3;

1.3
date	94.03.28.04.29.56;	author cgd;	state Exp;
branches;
next	1.2;

1.2
date	94.01.24.06.40.49;	author cgd;	state Exp;
branches;
next	1.1;

1.1
date	94.01.24.05.53.06;	author cgd;	state Exp;
branches
	1.1.1.1;
next	;

1.9.4.1
date	2005.02.12.12.24.13;	author aymeric;	state Exp;
branches;
next	1.9.4.2;

1.9.4.2
date	2005.02.12.12.46.26;	author aymeric;	state Exp;
branches;
next	;

1.9.6.1
date	2005.05.06.14.42.03;	author riz;	state Exp;
branches;
next	;

1.5.2.1
date	94.08.17.20.13.10;	author cgd;	state dead;
branches;
next	1.5.2.2;

1.5.2.2
date	94.08.17.20.13.11;	author cgd;	state Exp;
branches;
next	;

1.1.1.1
date	94.01.24.05.53.07;	author cgd;	state Exp;
branches;
next	1.1.1.2;

1.1.1.2
date	94.03.28.02.56.33;	author cgd;	state Exp;
branches;
next	1.1.1.3;

1.1.1.3
date	94.08.17.16.17.12;	author cgd;	state Exp;
branches;
next	1.1.1.4;

1.1.1.4
date	94.08.17.19.19.17;	author cgd;	state Exp;
branches;
next	1.1.1.5;

1.1.1.5
date	96.05.20.01.56.04;	author mrg;	state Exp;
branches;
next	1.1.1.6;

1.1.1.6
date	2001.03.31.11.29.49;	author aymeric;	state Exp;
branches;
next	;


desc
@@


1.13
log
@bye old vi!
@
text
@/*	$NetBSD: ex_write.c,v 1.12 2006/03/19 05:01:48 rtr Exp $	*/

/*-
 * Copyright (c) 1992, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
 *	Keith Bostic.  All rights reserved.
 *
 * See the LICENSE file for redistribution information.
 */

#include "config.h"

#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char sccsid[] = "@@(#)ex_write.c	10.30 (Berkeley) 7/12/96";
#else
__RCSID("$NetBSD: ex_write.c,v 1.12 2006/03/19 05:01:48 rtr Exp $");
#endif
#endif /* not lint */

#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>

#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "../common/common.h"

enum which {WN, WQ, WRITE, XIT};
static int exwr __P((SCR *, EXCMD *, enum which));

/*
 * ex_wn --	:wn[!] [>>] [file]
 *	Write to a file and switch to the next one.
 *
 * PUBLIC: int ex_wn __P((SCR *, EXCMD *));
 */
int
ex_wn(sp, cmdp)
	SCR *sp;
	EXCMD *cmdp;
{
	if (exwr(sp, cmdp, WN))
		return (1);
	if (file_m3(sp, 0))
		return (1);

	/* The file name isn't a new file to edit. */
	cmdp->argc = 0;

	return (ex_next(sp, cmdp));
}

/*
 * ex_wq --	:wq[!] [>>] [file]
 *	Write to a file and quit.
 *
 * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
 */
int
ex_wq(sp, cmdp)
	SCR *sp;
	EXCMD *cmdp;
{
	int force;

	if (exwr(sp, cmdp, WQ))
		return (1);
	if (file_m3(sp, 0))
		return (1);

	force = FL_ISSET(cmdp->iflags, E_C_FORCE);

	if (ex_ncheck(sp, force))
		return (1);

	F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
	return (0);
}

/*
 * ex_write --	:write[!] [>>] [file]
 *		:write [!] [cmd]
 *	Write to a file.
 *
 * PUBLIC: int ex_write __P((SCR *, EXCMD *));
 */
int
ex_write(sp, cmdp)
	SCR *sp;
	EXCMD *cmdp;
{
	return (exwr(sp, cmdp, WRITE));
}


/*
 * ex_xit -- :x[it]! [file]
 *	Write out any modifications and quit.
 *
 * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
 */
int
ex_xit(sp, cmdp)
	SCR *sp;
	EXCMD *cmdp;
{
	int force;

	NEEDFILE(sp, cmdp);

	if (F_ISSET(sp->ep, F_MODIFIED) && exwr(sp, cmdp, XIT))
		return (1);
	if (file_m3(sp, 0))
		return (1);

	force = FL_ISSET(cmdp->iflags, E_C_FORCE);

	if (ex_ncheck(sp, force))
		return (1);

	F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
	return (0);
}

/*
 * exwr --
 *	The guts of the ex write commands.
 */
static int
exwr(sp, cmdp, cmd)
	SCR *sp;
	EXCMD *cmdp;
	enum which cmd;
{
	MARK rm;
	int flags;
	char *name, *p;

	p = NULL;	/* XXXGCC -Wuninitialized */
	NEEDFILE(sp, cmdp);

	/* All write commands can have an associated '!'. */
	LF_INIT(FS_POSSIBLE);
	if (FL_ISSET(cmdp->iflags, E_C_FORCE))
		LF_SET(FS_FORCE);

	/* Skip any leading whitespace. */
	if (cmdp->argc != 0)
		for (p = cmdp->argv[0]->bp; *p != '\0' && isblank(*p); ++p);

	/* If "write !" it's a pipe to a utility. */
	if (cmdp->argc != 0 && cmd == WRITE && *p == '!') {
		/* Secure means no shell access. */
		if (O_ISSET(sp, O_SECURE)) {
			ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
			return (1);
		}

		/* Expand the argument. */
		for (++p; *p && isblank(*p); ++p);
		if (*p == '\0') {
			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
			return (1);
		}
		if (argv_exp1(sp, cmdp, p, strlen(p), 1))
			return (1);

		/*
		 * Historically, vi waited after a write filter even if there
		 * wasn't any output from the command.  People complained when
		 * nvi waited only if there was output, wanting the visual cue
		 * that the program hadn't written anything.
		 */
		F_SET(sp, SC_EX_WAIT_YES);

		/*
		 * !!!
		 * Ignore the return cursor position, the cursor doesn't
		 * move.
		 */
		if (ex_filter(sp, cmdp, &cmdp->addr1,
		    &cmdp->addr2, &rm, cmdp->argv[1]->bp, FILTER_WRITE))
			return (1);

		/* Ex terminates with a bang, even if the command fails. */
		if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT))
			(void)ex_puts(sp, "!\n");

		return (0);
	}

	/* Set the FS_ALL flag if we're writing the entire file. */
	if (cmdp->addr1.lno <= 1 && !db_exist(sp, cmdp->addr2.lno + 1))
		LF_SET(FS_ALL);

	/* If "write >>" it's an append to a file. */
	if (cmdp->argc != 0 && cmd != XIT && p[0] == '>' && p[1] == '>') {
		LF_SET(FS_APPEND);

		/* Skip ">>" and whitespace. */
		for (p += 2; *p && isblank(*p); ++p);
	}

	/* If no other arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0')
		return (file_write(sp,
		    &cmdp->addr1, &cmdp->addr2, NULL, flags));

	/* Build an argv so we get an argument count and file expansion. */
	if (argv_exp2(sp, cmdp, p, strlen(p)))
		return (1);

	/*
	 *  0 args: impossible.
	 *  1 args: impossible (I hope).
	 *  2 args: read it.
	 * >2 args: object, too many args.
	 *
	 * The 1 args case depends on the argv_sexp() function refusing
	 * to return success without at least one non-blank character.
	 */
	switch (cmdp->argc) {
	case 0:
	case 1:
		abort();
		/* NOTREACHED */
	case 2:
		name = cmdp->argv[1]->bp;

		/*
		 * !!!
		 * Historically, the read and write commands renamed
		 * "unnamed" files, or, if the file had a name, set
		 * the alternate file name.
		 */
		if (F_ISSET(sp->frp, FR_TMPFILE) &&
		    !F_ISSET(sp->frp, FR_EXNAMED)) {
			if ((p = v_strdup(sp,
			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
				free(sp->frp->name);
				sp->frp->name = p;
			}
			/*
			 * The file has a real name, it's no longer a
			 * temporary, clear the temporary file flags.
			 *
			 * !!!
			 * If we're writing the whole file, FR_NAMECHANGE
			 * will be cleared by the write routine -- this is
			 * historic practice.
			 */
			F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
			F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);

			/* Notify the screen. */
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
		} else
			set_alt_name(sp, name);
		break;
	default:
		ex_emsg(sp, p, EXM_FILECOUNT);
		return (1);
	}

	return (file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags));
}

/*
 * ex_writefp --
 *	Write a range of lines to a FILE *.
 *
 * PUBLIC: int ex_writefp __P((SCR *,
 * PUBLIC:    char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
 */
int
ex_writefp(sp, name, fp, fm, tm, nlno, nch, silent)
	SCR *sp;
	char *name;
	FILE *fp;
	MARK *fm, *tm;
	u_long *nlno, *nch;
	int silent;
{
	struct stat sb;
	GS *gp;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	recno_t fline, tline, lcnt;
	size_t len;
	int rval;
	char *msg, *p;

	gp = sp->gp;
	fline = fm->lno;
	tline = tm->lno;

	if (nlno != NULL) {
		*nch = 0;
		*nlno = 0;
	}

	/*
	 * The vi filter code has multiple processes running simultaneously,
	 * and one of them calls ex_writefp().  The "unsafe" function calls
	 * in this code are to db_get() and msgq().  Db_get() is safe, see
	 * the comment in ex_filter.c:ex_filter() for details.  We don't call
	 * msgq if the multiple process bit in the EXF is set.
	 *
	 * !!!
	 * Historic vi permitted files of 0 length to be written.  However,
	 * since the way vi got around dealing with "empty" files was to
	 * always have a line in the file no matter what, it wrote them as
	 * files of a single, empty line.  We write empty files.
	 *
	 * "Alex, I'll take vi trivia for $1000."
	 */
	ccnt = 0;
	lcnt = 0;
	msg = "253|Writing...";
	if (tline != 0)
		for (; fline <= tline; ++fline, ++lcnt) {
			/* Caller has to provide any interrupt message. */
			if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
				if (INTERRUPTED(sp))
					break;
				if (!silent) {
					gp->scr_busy(sp, msg, msg == NULL ?
					    BUSY_UPDATE : BUSY_ON);
					msg = NULL;
				}
			}
			if (db_get(sp, fline, DBG_FATAL, &p, &len))
				goto err;
			if (fwrite(p, 1, len, fp) != len)
				goto err;
			ccnt += len;
			if (putc('\n', fp) != '\n')
				break;
			++ccnt;
		}

	if (fflush(fp))
		goto err;
	/*
	 * XXX
	 * I don't trust NFS -- check to make sure that we're talking to
	 * a regular file and sync so that NFS is forced to flush.
	 */
	if (!fstat(fileno(fp), &sb) &&
	    S_ISREG(sb.st_mode) && fsync(fileno(fp)))
		goto err;

	if (fclose(fp)) {
		fp = NULL;
		goto err;
	}

	rval = 0;
	if (0) {
err:		if (!F_ISSET(sp->ep, F_MULTILOCK))
			msgq_str(sp, M_SYSERR, name, "%s");
		if (NULL != fp)
			(void)fclose(fp);
		rval = 1;
	}

	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);

	/* Report the possibly partial transfer. */
	if (nlno != NULL) {
		*nch = ccnt;
		*nlno = lcnt;
	}
	return (rval);
}
@


1.12
log
@avoid double fclose()
coverity 2577 / run 6
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.11 2005/06/02 04:25:16 lukem Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD: ex_write.c,v 1.11 2005/06/02 04:25:16 lukem Exp $");
@


1.11
log
@appease gcc -Wuninitialized.
Each is marked with XXXGCC, because in some cases it looks like gcc
isn't correctly detecting that
	for ( ; xxx ; yyy)
		foo = 0;
always sets foo ...
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.10 2005/02/12 12:53:23 aymeric Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD: ex_write.c,v 1.10 2005/02/12 12:53:23 aymeric Exp $");
d363 2
a364 1
	if (fclose(fp))
d366 1
d372 2
a373 1
		(void)fclose(fp);
@


1.10
log
@Fix the RCSID's to be $NetBSD$ instead of $NetBSD
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.9 2002/04/09 01:47:34 thorpej Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD$");
d150 1
@


1.9
log
@Use __RCSID() and __COPYRIGHT().
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.8 2001/03/31 11:37:51 aymeric Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD");
@


1.9.6.1
log
@Pull up revision 1.10 (requested by aymeric in ticket #1195):
Fix the RCSID's to be $NetBSD$ instead of $NetBSD
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.9 2002/04/09 01:47:34 thorpej Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD$");
@


1.9.4.1
log
@Fix the RCSID's to be $NetBSD$ instead of $NetBSD
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.9 2002/04/09 01:47:34 thorpej Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD$");
@


1.9.4.2
log
@Backout previous. Sorry.
@
text
@d19 1
a19 1
__RCSID("$NetBSD");
@


1.8
log
@merge changes after import of nvi 1.79
@
text
@d1 1
a1 1
/*	$NetBSD: ex_write.c,v 1.7 1998/01/09 08:08:12 perry Exp $	*/
d14 1
d16 1
d18 3
@


1.7
log
@RCS Id Police.
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d15 1
a15 1
static const char sccsid[] = "@@(#)ex_write.c	10.25 (Berkeley) 5/8/96";
d164 1
a169 1
		/* Expand the argument. */
d174 8
d197 4
d209 2
a210 4
	/* If no arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0') {
		if (F_ISSET(cmdp, E_ADDR2_ALL))
			LF_SET(FS_ALL);
a212 1
	}
d261 1
a261 1
			(void)sp->gp->scr_rename(sp);
a269 2
	if (F_ISSET(cmdp, E_ADDR2_ALL))
		LF_SET(FS_ALL);
@


1.6
log
@merge in nvi 1.66
@
text
@d1 2
@


1.5
log
@clean up import.
@
text
@d4 2
d7 1
a7 27
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
d10 2
d13 1
a13 1
static char sccsid[] = "@@(#)ex_write.c	8.38 (Berkeley) 8/17/94";
a18 1
#include <sys/time.h>
a24 1
#include <signal.h>
d26 1
a27 1
#include <termios.h>
d30 1
a30 6
#include "compat.h"
#include <db.h>
#include <regex.h>

#include "vi.h"
#include "excmd.h"
d33 1
a33 2

static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));
d38 2
d42 1
a42 1
ex_wn(sp, ep, cmdp)
d44 1
a44 2
	EXF *ep;
	EXCMDARG *cmdp;
d46 1
a46 1
	if (exwr(sp, ep, cmdp, WN))
d48 1
a48 1
	if (file_m3(sp, ep, 0))
d54 1
a54 1
	return (ex_next(sp, ep, cmdp));
d60 2
d64 1
a64 1
ex_wq(sp, ep, cmdp)
d66 1
a66 2
	EXF *ep;
	EXCMDARG *cmdp;
d70 1
a70 1
	if (exwr(sp, ep, cmdp, WQ))
d72 1
a72 1
	if (file_m3(sp, ep, 0))
d75 1
a75 1
	force = F_ISSET(cmdp, E_FORCE);
d80 1
a80 1
	F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
d88 2
d92 1
a92 1
ex_write(sp, ep, cmdp)
d94 1
a94 2
	EXF *ep;
	EXCMDARG *cmdp;
d96 1
a96 1
	return (exwr(sp, ep, cmdp, WRITE));
d102 1
d104 1
a104 1
 *	Write out any modifications and quit.
d107 1
a107 1
ex_xit(sp, ep, cmdp)
d109 1
a109 2
	EXF *ep;
	EXCMDARG *cmdp;
d113 3
a115 1
	if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
d117 1
a117 1
	if (file_m3(sp, ep, 0))
d120 1
a120 1
	force = F_ISSET(cmdp, E_FORCE);
d125 1
a125 1
	F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
d134 1
a134 1
exwr(sp, ep, cmdp, cmd)
d136 1
a136 2
	EXF *ep;
	EXCMDARG *cmdp;
a138 1
	EX_PRIVATE *exp;
d143 2
d147 1
a147 1
	if (F_ISSET(cmdp, E_FORCE))
d152 1
a152 1
		for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);
d154 7
a160 7
	/* If no arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0') {
		if (F_ISSET(cmdp, E_ADDR2_ALL))
			LF_SET(FS_ALL);
		return (file_write(sp, ep,
		    &cmdp->addr1, &cmdp->addr2, NULL, flags));
	}
a161 3
	/* If "write !" it's a pipe to a utility. */
	exp = EXP(sp);
	if (cmd == WRITE && *p == '!') {
d164 1
a164 1
			msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
d168 1
a168 1
		if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
d170 8
a177 2
		if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
		    &rm, cmdp->argv[1]->bp, FILTER_WRITE))
d179 5
a183 1
		sp->lno = rm.lno;
d188 1
a188 1
	if (cmd != XIT && p[0] == '>' && p[1] == '>') {
d195 8
d204 1
a204 1
	if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
d207 9
d217 1
d219 5
d225 4
a228 3
		 * Nothing to expand, write the current file.
		 * XXX
		 * Should never happen, already checked this case.
d230 23
a252 6
		name = NULL;
		break;
	case 2:
		/* One new argument, write it. */
		name = cmdp->argv[exp->argsoff - 1]->bp;
		set_alt_name(sp, name);
d255 1
a255 4
		/* If expanded to more than one argument, object. */
		msgq(sp, M_ERR, "%s expanded into too many file names",
		    cmdp->argv[0]->bp);
		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
d261 1
a261 1
	return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
d267 3
d272 1
a272 1
ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
a273 1
	EXF *ep;
d278 1
d281 1
d285 2
a286 2
	int sv_errno;
	char *p;
d288 1
d300 2
a301 2
	 * in this code are to file_gline() and msgq().  File_gline() is safe,
	 * see the comment in filter.c:filtercmd() for details.  We don't call
d314 2
a315 1
	if (tline != 0) {
d318 8
a325 8
			if (INTERRUPTED(sp))
				break;
			if ((p = file_gline(sp, ep, fline, &len)) == NULL)
				break;
			if (fwrite(p, 1, len, fp) != len) {
				msgq(sp, M_SYSERR, name);
				(void)fclose(fp);
				return (1);
d327 4
a335 1
	}
d337 7
a343 1
	/* If it's a regular file, sync it so that NFS is forced to flush. */
d345 1
a345 4
	    S_ISREG(sb.st_mode) && fsync(fileno(fp))) {
		sv_errno = errno;
		(void)fclose(fp);
		errno = sv_errno;
d347 1
a347 1
	}
d350 13
d367 1
a367 5
	return (0);

err:	if (!F_ISSET(ep, F_MULTILOCK))
		msgq(sp, M_SYSERR, name);
	return (1);
@


1.5.2.1
log
@file ex_write.c was added on branch netbsd-1-0 on 1994-08-17 20:13:11 +0000
@
text
@d1 327
@


1.5.2.2
log
@clean up import.
@
text
@a0 327
/*-
 * Copyright (c) 1992, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@@(#)ex_write.c	8.38 (Berkeley) 8/17/94";
#endif /* not lint */

#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include "compat.h"
#include <db.h>
#include <regex.h>

#include "vi.h"
#include "excmd.h"

enum which {WN, WQ, WRITE, XIT};

static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));

/*
 * ex_wn --	:wn[!] [>>] [file]
 *	Write to a file and switch to the next one.
 */
int
ex_wn(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	if (exwr(sp, ep, cmdp, WN))
		return (1);
	if (file_m3(sp, ep, 0))
		return (1);

	/* The file name isn't a new file to edit. */
	cmdp->argc = 0;

	return (ex_next(sp, ep, cmdp));
}

/*
 * ex_wq --	:wq[!] [>>] [file]
 *	Write to a file and quit.
 */
int
ex_wq(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	int force;

	if (exwr(sp, ep, cmdp, WQ))
		return (1);
	if (file_m3(sp, ep, 0))
		return (1);

	force = F_ISSET(cmdp, E_FORCE);

	if (ex_ncheck(sp, force))
		return (1);

	F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
	return (0);
}

/*
 * ex_write --	:write[!] [>>] [file]
 *		:write [!] [cmd]
 *	Write to a file.
 */
int
ex_write(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	return (exwr(sp, ep, cmdp, WRITE));
}


/*
 * ex_xit -- :x[it]! [file]
 *
 *	Write out any modifications and quit.
 */
int
ex_xit(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	int force;

	if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
		return (1);
	if (file_m3(sp, ep, 0))
		return (1);

	force = F_ISSET(cmdp, E_FORCE);

	if (ex_ncheck(sp, force))
		return (1);

	F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
	return (0);
}

/*
 * exwr --
 *	The guts of the ex write commands.
 */
static int
exwr(sp, ep, cmdp, cmd)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
	enum which cmd;
{
	EX_PRIVATE *exp;
	MARK rm;
	int flags;
	char *name, *p;

	/* All write commands can have an associated '!'. */
	LF_INIT(FS_POSSIBLE);
	if (F_ISSET(cmdp, E_FORCE))
		LF_SET(FS_FORCE);

	/* Skip any leading whitespace. */
	if (cmdp->argc != 0)
		for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);

	/* If no arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0') {
		if (F_ISSET(cmdp, E_ADDR2_ALL))
			LF_SET(FS_ALL);
		return (file_write(sp, ep,
		    &cmdp->addr1, &cmdp->addr2, NULL, flags));
	}

	/* If "write !" it's a pipe to a utility. */
	exp = EXP(sp);
	if (cmd == WRITE && *p == '!') {
		for (++p; *p && isblank(*p); ++p);
		if (*p == '\0') {
			msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
			return (1);
		}
		/* Expand the argument. */
		if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
			return (1);
		if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
		    &rm, cmdp->argv[1]->bp, FILTER_WRITE))
			return (1);
		sp->lno = rm.lno;
		return (0);
	}

	/* If "write >>" it's an append to a file. */
	if (cmd != XIT && p[0] == '>' && p[1] == '>') {
		LF_SET(FS_APPEND);

		/* Skip ">>" and whitespace. */
		for (p += 2; *p && isblank(*p); ++p);
	}

	/* Build an argv so we get an argument count and file expansion. */
	if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
		return (1);

	switch (cmdp->argc) {
	case 1:
		/*
		 * Nothing to expand, write the current file.
		 * XXX
		 * Should never happen, already checked this case.
		 */
		name = NULL;
		break;
	case 2:
		/* One new argument, write it. */
		name = cmdp->argv[exp->argsoff - 1]->bp;
		set_alt_name(sp, name);
		break;
	default:
		/* If expanded to more than one argument, object. */
		msgq(sp, M_ERR, "%s expanded into too many file names",
		    cmdp->argv[0]->bp);
		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
		return (1);
	}

	if (F_ISSET(cmdp, E_ADDR2_ALL))
		LF_SET(FS_ALL);
	return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
}

/*
 * ex_writefp --
 *	Write a range of lines to a FILE *.
 */
int
ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
	SCR *sp;
	EXF *ep;
	char *name;
	FILE *fp;
	MARK *fm, *tm;
	u_long *nlno, *nch;
{
	struct stat sb;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	recno_t fline, tline, lcnt;
	size_t len;
	int sv_errno;
	char *p;

	fline = fm->lno;
	tline = tm->lno;

	if (nlno != NULL) {
		*nch = 0;
		*nlno = 0;
	}

	/*
	 * The vi filter code has multiple processes running simultaneously,
	 * and one of them calls ex_writefp().  The "unsafe" function calls
	 * in this code are to file_gline() and msgq().  File_gline() is safe,
	 * see the comment in filter.c:filtercmd() for details.  We don't call
	 * msgq if the multiple process bit in the EXF is set.
	 *
	 * !!!
	 * Historic vi permitted files of 0 length to be written.  However,
	 * since the way vi got around dealing with "empty" files was to
	 * always have a line in the file no matter what, it wrote them as
	 * files of a single, empty line.  We write empty files.
	 *
	 * "Alex, I'll take vi trivia for $1000."
	 */
	ccnt = 0;
	lcnt = 0;
	if (tline != 0) {
		for (; fline <= tline; ++fline, ++lcnt) {
			/* Caller has to provide any interrupt message. */
			if (INTERRUPTED(sp))
				break;
			if ((p = file_gline(sp, ep, fline, &len)) == NULL)
				break;
			if (fwrite(p, 1, len, fp) != len) {
				msgq(sp, M_SYSERR, name);
				(void)fclose(fp);
				return (1);
			}
			ccnt += len;
			if (putc('\n', fp) != '\n')
				break;
			++ccnt;
		}
	}

	/* If it's a regular file, sync it so that NFS is forced to flush. */
	if (!fstat(fileno(fp), &sb) &&
	    S_ISREG(sb.st_mode) && fsync(fileno(fp))) {
		sv_errno = errno;
		(void)fclose(fp);
		errno = sv_errno;
		goto err;
	}
	if (fclose(fp))
		goto err;
	if (nlno != NULL) {
		*nch = ccnt;
		*nlno = lcnt;
	}
	return (0);

err:	if (!F_ISSET(ep, F_MULTILOCK))
		msgq(sp, M_SYSERR, name);
	return (1);
}
@


1.4
log
@clean up import.  still have to hack some things.
@
text
@d35 1
a35 1
static const char sccsid[] = "@@(#)ex_write.c	8.37 (Berkeley) 8/17/94";
@


1.3
log
@nvi 1.11(beta) from bostic.  reconcile conflicts/kill rcsids.
@
text
@d35 1
a35 1
static char sccsid[] = "@@(#)ex_write.c	8.27 (Berkeley) 3/23/94";
d61 1
a61 1
enum which {WQ, WRITE, XIT};
d66 21
d88 1
a88 1
 *	Write to a file.
d100 2
d104 2
a105 3
	if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
		msgq(sp, M_ERR,
		    "More files to edit; use \":n\" to go to the next file");
a106 1
	}
d142 2
d146 2
a147 3
	if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
		msgq(sp, M_ERR,
		    "More files to edit; use \":n\" to go to the next file");
a148 1
	}
d192 1
a192 1
			msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
d235 1
a235 1
		msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
d291 2
a292 2
			if (F_ISSET(sp, S_INTERRUPTED)) {
				msgq(sp, M_INFO, "Interrupted.");
a293 1
			}
@


1.2
log
@more Ids than you'll ever want.
@
text
@d2 1
a2 1
 * Copyright (c) 1992, 1993
d35 1
a35 2
/* from: static char sccsid[] = "@@(#)ex_write.c	8.19 (Berkeley) 12/18/93"; */
static char *rcsid = "$Id$";
d39 1
d41 1
d43 1
d47 3
d51 1
d54 4
d199 1
a199 1
		 * Nothing to expand, write the current file. 
d236 3
a238 1
	register u_long ccnt, fline, tline;
d240 1
a249 1
	ccnt = 0;
d266 8
a273 2
	if (tline != 0)
		for (; fline <= tline; ++fline) {
a285 4
	if (fclose(fp)) {
		if (!F_ISSET(ep, F_MULTILOCK))
			msgq(sp, M_SYSERR, name);
		return (1);
d287 11
d300 1
a300 1
		*nlno = tm->lno == 0 ? 0 : tm->lno - fm->lno + 1;
d303 4
@


1.1
log
@Initial revision
@
text
@d35 2
a36 1
static char sccsid[] = "@@(#)ex_write.c	8.19 (Berkeley) 12/18/93";
@


1.1.1.1
log
@nvi 1.03, from ftp.cs.berkeley.edu, per keith bostic's permission.
@
text
@@


1.1.1.2
log
@nvi/nex 1.11beta from bostic.
@
text
@d2 1
a2 1
 * Copyright (c) 1992, 1993, 1994
d35 1
a35 1
static char sccsid[] = "@@(#)ex_write.c	8.27 (Berkeley) 3/23/94";
a38 1
#include <sys/queue.h>
a39 1
#include <sys/time.h>
a40 1
#include <bitstring.h>
a43 3
#include <limits.h>
#include <signal.h>
#include <stdio.h>
a44 1
#include <termios.h>
a46 4
#include "compat.h"
#include <db.h>
#include <regex.h>

d188 1
a188 1
		 * Nothing to expand, write the current file.
d225 1
a225 3
	struct stat sb;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	recno_t fline, tline, lcnt;
a226 1
	int sv_errno;
d236 1
d253 2
a254 8
	ccnt = 0;
	lcnt = 0;
	if (tline != 0) {
		for (; fline <= tline; ++fline, ++lcnt) {
			if (F_ISSET(sp, S_INTERRUPTED)) {
				msgq(sp, M_INFO, "Interrupted.");
				break;
			}
d267 4
a271 11

	/* If it's a regular file, sync it so that NFS is forced to flush. */
	if (!fstat(fileno(fp), &sb) &&
	    S_ISREG(sb.st_mode) && fsync(fileno(fp))) {
		sv_errno = errno;
		(void)fclose(fp);
		errno = sv_errno;
		goto err;
	}
	if (fclose(fp))
		goto err;
d274 1
a274 1
		*nlno = lcnt;
a276 4

err:	if (!F_ISSET(ep, F_MULTILOCK))
		msgq(sp, M_SYSERR, name);
	return (1);
@


1.1.1.3
log
@new public version of nvi
@
text
@d35 1
a35 1
static const char sccsid[] = "@@(#)ex_write.c	8.37 (Berkeley) 8/17/94";
d61 1
a61 1
enum which {WN, WQ, WRITE, XIT};
a65 21
 * ex_wn --	:wn[!] [>>] [file]
 *	Write to a file and switch to the next one.
 */
int
ex_wn(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	if (exwr(sp, ep, cmdp, WN))
		return (1);
	if (file_m3(sp, ep, 0))
		return (1);

	/* The file name isn't a new file to edit. */
	cmdp->argc = 0;

	return (ex_next(sp, ep, cmdp));
}

/*
d67 1
a67 1
 *	Write to a file and quit.
a78 2
	if (file_m3(sp, ep, 0))
		return (1);
d81 3
a83 2

	if (ex_ncheck(sp, force))
d85 1
a120 2
	if (file_m3(sp, ep, 0))
		return (1);
d123 3
a125 2

	if (ex_ncheck(sp, force))
d127 1
d171 1
a171 1
			msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
d214 1
a214 1
		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
d270 2
a271 2
			/* Caller has to provide any interrupt message. */
			if (INTERRUPTED(sp))
d273 1
@


1.1.1.4
log
@new public version of nvi
@
text
@d35 1
a35 1
static char sccsid[] = "@@(#)ex_write.c	8.38 (Berkeley) 8/17/94";
@


1.1.1.5
log
@import of nvi 1.66
@
text
@a3 2
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
 *	Keith Bostic.  All rights reserved.
d5 27
a31 1
 * See the LICENSE file for redistribution information.
a33 2
#include "config.h"

d35 1
a35 1
static const char sccsid[] = "@@(#)ex_write.c	10.25 (Berkeley) 5/8/96";
d41 1
d48 1
a49 1
#include <stdlib.h>
d51 1
d54 6
a59 1
#include "../common/common.h"
d62 2
a63 1
static int exwr __P((SCR *, EXCMD *, enum which));
a67 2
 *
 * PUBLIC: int ex_wn __P((SCR *, EXCMD *));
d70 1
a70 1
ex_wn(sp, cmdp)
d72 2
a73 1
	EXCMD *cmdp;
d75 1
a75 1
	if (exwr(sp, cmdp, WN))
d77 1
a77 1
	if (file_m3(sp, 0))
d83 1
a83 1
	return (ex_next(sp, cmdp));
a88 2
 *
 * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
d91 1
a91 1
ex_wq(sp, cmdp)
d93 2
a94 1
	EXCMD *cmdp;
d98 1
a98 1
	if (exwr(sp, cmdp, WQ))
d100 1
a100 1
	if (file_m3(sp, 0))
d103 1
a103 1
	force = FL_ISSET(cmdp->iflags, E_C_FORCE);
d108 1
a108 1
	F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
a115 2
 *
 * PUBLIC: int ex_write __P((SCR *, EXCMD *));
d118 1
a118 1
ex_write(sp, cmdp)
d120 2
a121 1
	EXCMD *cmdp;
d123 1
a123 1
	return (exwr(sp, cmdp, WRITE));
d129 1
a130 2
 *
 * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
d133 1
a133 1
ex_xit(sp, cmdp)
d135 2
a136 1
	EXCMD *cmdp;
d140 1
a140 3
	NEEDFILE(sp, cmdp);

	if (F_ISSET(sp->ep, F_MODIFIED) && exwr(sp, cmdp, XIT))
d142 1
a142 1
	if (file_m3(sp, 0))
d145 1
a145 1
	force = FL_ISSET(cmdp->iflags, E_C_FORCE);
d150 1
a150 1
	F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
d159 1
a159 1
exwr(sp, cmdp, cmd)
d161 2
a162 1
	EXCMD *cmdp;
d165 1
a169 2
	NEEDFILE(sp, cmdp);

d172 1
a172 1
	if (FL_ISSET(cmdp->iflags, E_C_FORCE))
d177 9
a185 1
		for (p = cmdp->argv[0]->bp; *p != '\0' && isblank(*p); ++p);
d188 2
a189 7
	if (cmdp->argc != 0 && cmd == WRITE && *p == '!') {
		/* Secure means no shell access. */
		if (O_ISSET(sp, O_SECURE)) {
			ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
			return (1);
		}

d192 1
a192 1
			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
d196 1
a196 1
		if (argv_exp1(sp, cmdp, p, strlen(p), 1))
d198 2
a199 8

		/*
		 * !!!
		 * Ignore the return cursor position, the cursor doesn't
		 * move.
		 */
		if (ex_filter(sp, cmdp, &cmdp->addr1,
		    &cmdp->addr2, &rm, cmdp->argv[1]->bp, FILTER_WRITE))
d201 1
a201 5

		/* Ex terminates with a bang, even if the command fails. */
		if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT))
			(void)ex_puts(sp, "!\n");

d206 1
a206 1
	if (cmdp->argc != 0 && cmd != XIT && p[0] == '>' && p[1] == '>') {
a212 8
	/* If no arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0') {
		if (F_ISSET(cmdp, E_ADDR2_ALL))
			LF_SET(FS_ALL);
		return (file_write(sp,
		    &cmdp->addr1, &cmdp->addr2, NULL, flags));
	}

d214 1
a214 1
	if (argv_exp2(sp, cmdp, p, strlen(p)))
a216 9
	/*
	 *  0 args: impossible.
	 *  1 args: impossible (I hope).
	 *  2 args: read it.
	 * >2 args: object, too many args.
	 *
	 * The 1 args case depends on the argv_sexp() function refusing
	 * to return success without at least one non-blank character.
	 */
a217 1
	case 0:
a218 5
		abort();
		/* NOTREACHED */
	case 2:
		name = cmdp->argv[1]->bp;

d220 3
a222 4
		 * !!!
		 * Historically, the read and write commands renamed
		 * "unnamed" files, or, if the file had a name, set
		 * the alternate file name.
d224 6
a229 23
		if (F_ISSET(sp->frp, FR_TMPFILE) &&
		    !F_ISSET(sp->frp, FR_EXNAMED)) {
			if ((p = v_strdup(sp,
			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
				free(sp->frp->name);
				sp->frp->name = p;
			}
			/*
			 * The file has a real name, it's no longer a
			 * temporary, clear the temporary file flags.
			 *
			 * !!!
			 * If we're writing the whole file, FR_NAMECHANGE
			 * will be cleared by the write routine -- this is
			 * historic practice.
			 */
			F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
			F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);

			/* Notify the screen. */
			(void)sp->gp->scr_rename(sp);
		} else
			set_alt_name(sp, name);
d232 4
a235 1
		ex_emsg(sp, p, EXM_FILECOUNT);
d241 1
a241 1
	return (file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags));
a246 3
 *
 * PUBLIC: int ex_writefp __P((SCR *,
 * PUBLIC:    char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
d249 1
a249 1
ex_writefp(sp, name, fp, fm, tm, nlno, nch, silent)
d251 1
a255 1
	int silent;
a257 1
	GS *gp;
d261 2
a262 2
	int rval;
	char *msg, *p;
a263 1
	gp = sp->gp;
d275 2
a276 2
	 * in this code are to db_get() and msgq().  Db_get() is safe, see
	 * the comment in ex_filter.c:ex_filter() for details.  We don't call
d289 1
a289 2
	msg = "253|Writing...";
	if (tline != 0)
d292 8
a299 8
			if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
				if (INTERRUPTED(sp))
					break;
				if (!silent) {
					gp->scr_busy(sp, msg, msg == NULL ?
					    BUSY_UPDATE : BUSY_ON);
					msg = NULL;
				}
a300 4
			if (db_get(sp, fline, DBG_FATAL, &p, &len))
				goto err;
			if (fwrite(p, 1, len, fp) != len)
				goto err;
d306 1
d308 1
a308 7
	if (fflush(fp))
		goto err;
	/*
	 * XXX
	 * I don't trust NFS -- check to make sure that we're talking to
	 * a regular file and sync so that NFS is forced to flush.
	 */
d310 4
a313 1
	    S_ISREG(sb.st_mode) && fsync(fileno(fp)))
d315 1
a315 1

a317 13

	rval = 0;
	if (0) {
err:		if (!F_ISSET(sp->ep, F_MULTILOCK))
			msgq_str(sp, M_SYSERR, name, "%s");
		(void)fclose(fp);
		rval = 1;
	}

	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);

	/* Report the possibly partial transfer. */
d322 5
a326 1
	return (rval);
@


1.1.1.6
log
@import of nvi 1.79
@
text
@d13 1
a13 1
static const char sccsid[] = "@@(#)ex_write.c	10.30 (Berkeley) 7/12/96";
a161 1
		/* Expand the argument. */
d167 1
a171 8
		 * Historically, vi waited after a write filter even if there
		 * wasn't any output from the command.  People complained when
		 * nvi waited only if there was output, wanting the visual cue
		 * that the program hadn't written anything.
		 */
		F_SET(sp, SC_EX_WAIT_YES);

		/*
a186 4
	/* Set the FS_ALL flag if we're writing the entire file. */
	if (cmdp->addr1.lno <= 1 && !db_exist(sp, cmdp->addr2.lno + 1))
		LF_SET(FS_ALL);

d195 4
a198 2
	/* If no other arguments, just write the file back. */
	if (cmdp->argc == 0 || *p == '\0')
d201 1
d250 1
a250 1
			(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
d259 2
@

