head	1.15;
access;
symbols
	perseant-exfatfs-base-20250801:1.15
	perseant-exfatfs-base-20240630:1.15
	perseant-exfatfs:1.15.0.36
	perseant-exfatfs-base:1.15
	cjep_sun2x:1.15.0.34
	cjep_sun2x-base:1.15
	cjep_staticlib_x-base1:1.15
	cjep_staticlib_x:1.15.0.32
	cjep_staticlib_x-base:1.15
	phil-wifi-20200421:1.15
	phil-wifi-20200411:1.15
	phil-wifi-20200406:1.15
	pgoyette-compat-merge-20190127:1.15
	pgoyette-compat-20190127:1.15
	pgoyette-compat-20190118:1.15
	pgoyette-compat-1226:1.15
	pgoyette-compat-1126:1.15
	pgoyette-compat-1020:1.15
	pgoyette-compat-0930:1.15
	pgoyette-compat-0906:1.15
	pgoyette-compat-0728:1.15
	pgoyette-compat-0625:1.15
	pgoyette-compat-0521:1.15
	pgoyette-compat-0502:1.15
	pgoyette-compat-0422:1.15
	pgoyette-compat-0415:1.15
	pgoyette-compat-0407:1.15
	pgoyette-compat-0330:1.15
	pgoyette-compat-0322:1.15
	pgoyette-compat-0315:1.15
	pgoyette-compat:1.15.0.30
	pgoyette-compat-base:1.15
	perseant-stdc-iso10646:1.15.0.28
	perseant-stdc-iso10646-base:1.15
	prg-localcount2-base3:1.15
	prg-localcount2-base2:1.15
	prg-localcount2-base1:1.15
	prg-localcount2:1.15.0.26
	prg-localcount2-base:1.15
	pgoyette-localcount-20170426:1.15
	bouyer-socketcan-base1:1.15
	pgoyette-localcount-20170320:1.15
	bouyer-socketcan:1.15.0.24
	bouyer-socketcan-base:1.15
	pgoyette-localcount-20170107:1.15
	pgoyette-localcount-20161104:1.15
	localcount-20160914:1.15
	pgoyette-localcount-20160806:1.15
	pgoyette-localcount-20160726:1.15
	pgoyette-localcount:1.15.0.22
	pgoyette-localcount-base:1.15
	netbsd-5-2-3-RELEASE:1.15
	netbsd-5-1-5-RELEASE:1.15
	yamt-pagecache-base9:1.15
	yamt-pagecache-tag8:1.15
	tls-earlyentropy:1.15.0.18
	tls-earlyentropy-base:1.15
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.15
	riastradh-drm2-base3:1.15
	netbsd-5-2-2-RELEASE:1.15
	netbsd-5-1-4-RELEASE:1.15
	netbsd-5-2-1-RELEASE:1.15
	netbsd-5-1-3-RELEASE:1.15
	agc-symver:1.15.0.20
	agc-symver-base:1.15
	tls-maxphys-base:1.15
	yamt-pagecache-base8:1.15
	netbsd-5-2:1.15.0.16
	yamt-pagecache-base7:1.15
	netbsd-5-2-RELEASE:1.15
	netbsd-5-2-RC1:1.15
	yamt-pagecache-base6:1.15
	yamt-pagecache-base5:1.15
	yamt-pagecache-base4:1.15
	netbsd-5-1-2-RELEASE:1.15
	netbsd-5-1-1-RELEASE:1.15
	yamt-pagecache-base3:1.15
	yamt-pagecache-base2:1.15
	yamt-pagecache:1.15.0.14
	yamt-pagecache-base:1.15
	bouyer-quota2-nbase:1.15
	bouyer-quota2:1.15.0.12
	bouyer-quota2-base:1.15
	matt-nb5-pq3:1.15.0.10
	matt-nb5-pq3-base:1.15
	netbsd-5-1:1.15.0.8
	netbsd-5-1-RELEASE:1.15
	netbsd-5-1-RC4:1.15
	netbsd-5-1-RC3:1.15
	netbsd-5-1-RC2:1.15
	netbsd-5-1-RC1:1.15
	netbsd-5-0-2-RELEASE:1.15
	netbsd-5-0-1-RELEASE:1.15
	jym-xensuspend-nbase:1.15
	netbsd-5-0:1.15.0.6
	netbsd-5-0-RELEASE:1.15
	netbsd-5-0-RC4:1.15
	netbsd-5-0-RC3:1.15
	netbsd-5-0-RC2:1.15
	jym-xensuspend:1.15.0.4
	jym-xensuspend-base:1.15
	netbsd-5-0-RC1:1.15
	netbsd-5:1.15.0.2
	netbsd-5-base:1.15
	matt-mips64-base2:1.14
	matt-mips64:1.14.0.26
	mjf-devfs2:1.14.0.24
	mjf-devfs2-base:1.14
	netbsd-4-0-1-RELEASE:1.14
	wrstuden-revivesa-base-3:1.14
	wrstuden-revivesa-base-2:1.14
	wrstuden-fixsa-newbase:1.14
	wrstuden-revivesa-base-1:1.14
	yamt-pf42-base4:1.14
	yamt-pf42-base3:1.14
	hpcarm-cleanup-nbase:1.14
	yamt-pf42-baseX:1.14
	yamt-pf42-base2:1.14
	wrstuden-revivesa:1.14.0.22
	wrstuden-revivesa-base:1.14
	yamt-pf42:1.14.0.20
	yamt-pf42-base:1.14
	keiichi-mipv6-nbase:1.14
	keiichi-mipv6:1.14.0.18
	keiichi-mipv6-base:1.14
	matt-armv6-nbase:1.14
	matt-armv6-prevmlocking:1.14
	wrstuden-fixsa-base-1:1.14
	netbsd-4-0:1.14.0.16
	netbsd-4-0-RELEASE:1.14
	cube-autoconf:1.14.0.14
	cube-autoconf-base:1.14
	netbsd-4-0-RC5:1.14
	netbsd-4-0-RC4:1.14
	netbsd-4-0-RC3:1.14
	netbsd-4-0-RC2:1.14
	netbsd-4-0-RC1:1.14
	matt-armv6:1.14.0.12
	matt-armv6-base:1.14
	matt-mips64-base:1.14
	hpcarm-cleanup:1.14.0.10
	hpcarm-cleanup-base:1.14
	netbsd-3-1-1-RELEASE:1.12
	netbsd-3-0-3-RELEASE:1.12
	wrstuden-fixsa:1.14.0.8
	wrstuden-fixsa-base:1.14
	abandoned-netbsd-4-base:1.14
	abandoned-netbsd-4:1.14.0.4
	netbsd-3-1:1.12.0.6
	netbsd-3-1-RELEASE:1.12
	netbsd-3-0-2-RELEASE:1.12
	netbsd-3-1-RC4:1.12
	netbsd-3-1-RC3:1.12
	netbsd-3-1-RC2:1.12
	netbsd-3-1-RC1:1.12
	netbsd-4:1.14.0.6
	netbsd-4-base:1.14
	chap-midi-nbase:1.14
	netbsd-3-0-1-RELEASE:1.12
	chap-midi:1.14.0.2
	chap-midi-base:1.14
	netbsd-3-0:1.12.0.4
	netbsd-3-0-RELEASE:1.12
	netbsd-3-0-RC6:1.12
	netbsd-3-0-RC5:1.12
	netbsd-3-0-RC4:1.12
	netbsd-3-0-RC3:1.12
	netbsd-3-0-RC2:1.12
	netbsd-3-0-RC1:1.12
	netbsd-2-0-3-RELEASE:1.11.4.2
	netbsd-2-1:1.11.6.1.0.2
	netbsd-2-1-RELEASE:1.11.6.1
	netbsd-2-1-RC6:1.11.6.1
	netbsd-2-1-RC5:1.11.6.1
	netbsd-2-1-RC4:1.11.6.1
	netbsd-2-1-RC3:1.11.6.1
	netbsd-2-1-RC2:1.11.6.1
	netbsd-2-1-RC1:1.11.6.1
	netbsd-2-0-2-RELEASE:1.11.4.2
	netbsd-3:1.12.0.2
	netbsd-3-base:1.12
	netbsd-2-0-1-RELEASE:1.11
	netbsd-2:1.11.0.6
	netbsd-2-base:1.11
	netbsd-2-0-RELEASE:1.11
	netbsd-2-0-RC5:1.11
	netbsd-2-0-RC4:1.11
	netbsd-2-0-RC3:1.11
	netbsd-2-0-RC2:1.11
	netbsd-2-0-RC1:1.11
	netbsd-2-0:1.11.0.4
	netbsd-2-0-base:1.11
	netbsd-1-6-PATCH002-RELEASE:1.11
	netbsd-1-6-PATCH002:1.11
	netbsd-1-6-PATCH002-RC4:1.11
	netbsd-1-6-PATCH002-RC3:1.11
	netbsd-1-6-PATCH002-RC2:1.11
	netbsd-1-6-PATCH002-RC1:1.11
	netbsd-1-6-PATCH001:1.11
	netbsd-1-6-PATCH001-RELEASE:1.11
	netbsd-1-6-PATCH001-RC3:1.11
	netbsd-1-6-PATCH001-RC2:1.11
	netbsd-1-6-PATCH001-RC1:1.11
	fvdl_fs64_base:1.11
	netbsd-1-6-RELEASE:1.11
	netbsd-1-6-RC3:1.11
	netbsd-1-6-RC2:1.11
	netbsd-1-6-RC1:1.11
	netbsd-1-6:1.11.0.2
	netbsd-1-6-base:1.11
	netbsd-1-5-PATCH003:1.8.2.1
	netbsd-1-5-PATCH002:1.8.2.1
	netbsd-1-5-PATCH001:1.8.2.1
	nvi_1_79:1.1.1.6
	netbsd-1-5-RELEASE:1.8.2.1
	netbsd-1-5-BETA2:1.8.2.1
	netbsd-1-5-BETA:1.8.2.1
	netbsd-1-4-PATCH003:1.7
	netbsd-1-5-ALPHA2:1.8
	netbsd-1-5:1.8.0.2
	netbsd-1-5-base:1.8
	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.15
date	2008.10.29.16.49.37;	author christos;	state dead;
branches;
next	1.14;

1.14
date	2006.03.19.04.34.19;	author rtr;	state Exp;
branches;
next	1.13;

1.13
date	2005.06.02.04.25.16;	author lukem;	state Exp;
branches;
next	1.12;

1.12
date	2005.02.12.12.53.23;	author aymeric;	state Exp;
branches;
next	1.11;

1.11
date	2002.04.09.01.47.33;	author thorpej;	state Exp;
branches
	1.11.4.1
	1.11.6.1;
next	1.10;

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

1.9
date	2000.10.18.01.42.10;	author tv;	state Exp;
branches;
next	1.8;

1.8
date	2000.05.31.19.49.25;	author jdc;	state Exp;
branches
	1.8.2.1;
next	1.7;

1.7
date	98.01.09.08.07.59;	author perry;	state Exp;
branches
	1.7.8.1;
next	1.6;

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

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

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

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

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

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

1.11.4.1
date	2005.02.12.12.24.13;	author aymeric;	state Exp;
branches;
next	1.11.4.2;

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

1.11.6.1
date	2005.05.06.14.42.07;	author riz;	state Exp;
branches;
next	;

1.8.2.1
date	2000.10.18.01.45.26;	author tv;	state Exp;
branches;
next	;

1.7.8.1
date	2000.06.23.16.40.10;	author minoura;	state Exp;
branches;
next	;

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

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

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

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

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

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

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

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


desc
@@


1.15
log
@bye old vi!
@
text
@/*	$NetBSD: ex_read.c,v 1.14 2006/03/19 04:34:19 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_read.c	10.38 (Berkeley) 8/12/96";
#else
__RCSID("$NetBSD: ex_read.c,v 1.14 2006/03/19 04:34:19 rtr Exp $");
#endif
#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 <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

/*
 * ex_read --	:read [file]
 *		:read [!cmd]
 *	Read from a file or utility.
 *
 * !!!
 * Historical vi wouldn't undo a filter read, for no apparent reason.
 *
 * PUBLIC: int ex_read __P((SCR *, EXCMD *));
 */
int
ex_read(sp, cmdp)
	SCR *sp;
	EXCMD *cmdp;
{
	enum { R_ARG, R_EXPANDARG, R_FILTER } which;
	struct stat sb;
	CHAR_T *arg, *name;
	EX_PRIVATE *exp;
	FILE *fp;
	FREF *frp;
	GS *gp;
	MARK rm;
	recno_t nlines;
	size_t arglen;
	int argc, rval;
	char *p;

	gp = sp->gp;
	arg = NULL;	/* XXXGCC -Wuninitialized */
	arglen = 0;	/* XXXGCC -Wuninitialized */
	name = NULL;	/* XXXGCC -Wuninitialized */

	/*
	 * 0 args: read the current pathname.
	 * 1 args: check for "read !arg".
	 */
	switch (cmdp->argc) {
	case 0:
		which = R_ARG;
		break;
	case 1:
		arg = cmdp->argv[0]->bp;
		arglen = cmdp->argv[0]->len;
		if (*arg == '!') {
			++arg;
			--arglen;
			which = R_FILTER;

			/* Secure means no shell access. */
			if (O_ISSET(sp, O_SECURE)) {
				ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
				return (1);
			}
		} else
			which = R_EXPANDARG;
		break;
	default:
		abort();
		/* NOTREACHED */
	}

	/* Load a temporary file if no file being edited. */
	if (sp->ep == NULL) {
		if ((frp = file_add(sp, NULL)) == NULL)
			return (1);
		if (file_init(sp, frp, NULL, 0))
			return (1);
	}

	switch (which) {
	case R_FILTER:
		/*
		 * File name and bang expand the user's argument.  If
		 * we don't get an additional argument, it's illegal.
		 */
		argc = cmdp->argc;
		if (argv_exp1(sp, cmdp, arg, arglen, 1))
			return (1);
		if (argc == cmdp->argc) {
			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
			return (1);
		}
		argc = cmdp->argc - 1;

		/* Set the last bang command. */
		exp = EXP(sp);
		if (exp->lastbcomm != NULL)
			free(exp->lastbcomm);
		if ((exp->lastbcomm =
		    strdup(cmdp->argv[argc]->bp)) == NULL) {
			msgq(sp, M_SYSERR, NULL);
			return (1);
		}

		/*
		 * Vi redisplayed the user's argument if it changed, ex
		 * always displayed a !, plus the user's argument if it
		 * changed.
		 */
		if (F_ISSET(sp, SC_VI)) {
			if (F_ISSET(cmdp, E_MODIFY))
				(void)vs_update(sp, "!", cmdp->argv[argc]->bp);
		} else {
			if (F_ISSET(cmdp, E_MODIFY))
				(void)ex_printf(sp,
				    "!%s\n", cmdp->argv[argc]->bp);
			else
				(void)ex_puts(sp, "!\n");
			(void)ex_fflush(sp);
		}

		/*
		 * Historically, filter reads as the first ex command didn't
		 * wait for the user. If SC_SCR_EXWROTE not already set, set
		 * the don't-wait flag.
		 */
		if (!F_ISSET(sp, SC_SCR_EXWROTE))
			F_SET(sp, SC_EX_WAIT_NO);

		/*
		 * Switch into ex canonical mode.  The reason to restore the
		 * original terminal modes for read filters is so that users
		 * can do things like ":r! cat /dev/tty".
		 *
		 * !!!
		 * We do not output an extra <newline>, so that we don't touch
		 * the screen on a normal read.
		 */
		if (F_ISSET(sp, SC_VI)) {
			if (gp->scr_screen(sp, SC_EX)) {
				ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
				return (1);
			}
			/*
			 * !!!
			 * Historically, the read command doesn't switch to
			 * the alternate X11 xterm screen, if doing a filter
			 * read -- don't set SA_ALTERNATE.
			 */
			F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
		}

		if (ex_filter(sp, cmdp, &cmdp->addr1,
		    NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
			return (1);

		/* The filter version of read set the autoprint flag. */
		F_SET(cmdp, E_AUTOPRINT);

		/*
		 * If in vi mode, move to the first nonblank.  Might have
		 * switched into ex mode, so saved the original SC_VI value.
		 */
		sp->lno = rm.lno;
		if (F_ISSET(sp, SC_VI)) {
			sp->cno = 0;
			(void)nonblank(sp, sp->lno, &sp->cno);
		}
		return (0);
	case R_ARG:
		name = sp->frp->name;
		break;
	case R_EXPANDARG:
		if (argv_exp2(sp, cmdp, arg, arglen))
			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.
				 */
				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, cmdp->argv[0]->bp, EXM_FILECOUNT);
			return (1);
		
		}
		break;
	}

	/*
	 * !!!
	 * Historically, vi did not permit reads from non-regular files, nor
	 * did it distinguish between "read !" and "read!", so there was no
	 * way to "force" it.  We permit reading from named pipes too, since
	 * they didn't exist when the original implementation of vi was done
	 * and they seem a reasonable addition.
	 */
	if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
		msgq_str(sp, M_SYSERR, name, "%s");
		return (1);
	}
	if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
		(void)fclose(fp);
		msgq(sp, M_ERR,
		    "145|Only regular files and named pipes may be read");
		return (1);
	}

	/* Try and get a lock. */
	if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
		msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);

	rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);

	/*
	 * In vi, set the cursor to the first line read in, if anything read
	 * in, otherwise, the address.  (Historic vi set it to the line after
	 * the address regardless, but since that line may not exist we don't
	 * bother.)
	 *
	 * In ex, set the cursor to the last line read in, if anything read in,
	 * otherwise, the address.
	 */
	if (F_ISSET(sp, SC_VI)) {
		sp->lno = cmdp->addr1.lno;
		if (nlines)
			++sp->lno;
	} else
		sp->lno = cmdp->addr1.lno + nlines;
	return (rval);
}

/*
 * ex_readfp --
 *	Read lines into the file.
 *
 * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
 */
int
ex_readfp(sp, name, fp, fm, nlinesp, silent)
	SCR *sp;
	char *name;
	FILE *fp;
	MARK *fm;
	recno_t *nlinesp;
	int silent;
{
	EX_PRIVATE *exp;
	GS *gp;
	recno_t lcnt, lno;
	size_t len;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	int nf, rval;
	char *p;

	gp = sp->gp;
	exp = EXP(sp);

	/*
	 * Add in the lines from the output.  Insertion starts at the line
	 * following the address.
	 */
	ccnt = 0;
	lcnt = 0;
	p = "147|Reading...";
	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
		if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
			if (INTERRUPTED(sp))
				break;
			if (!silent) {
				gp->scr_busy(sp, p,
				    p == NULL ? BUSY_UPDATE : BUSY_ON);
				p = NULL;
			}
		}
		if (db_append(sp, 1, lno, exp->ibp, len))
			goto err;
		ccnt += len;
	}

	if (ferror(fp))
		goto err;

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

	/* Return the number of lines read in. */
	if (nlinesp != NULL)
		*nlinesp = lcnt;

	if (!silent) {
		p = msg_print(sp, name, &nf);
		msgq(sp, M_INFO,
		    "148|%s: %lu lines, %lu characters", p,
		    (unsigned long) lcnt, ccnt);
		if (nf)
			FREE_SPACE(sp, p, 0);
	}

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

	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);
	return (rval);
}
@


1.14
log
@remove ambiguity in evaluation of conditional expressions and avoid
double fclose().
coverity 2713 / run 6
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.13 2005/06/02 04:25:16 lukem Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD: ex_read.c,v 1.13 2005/06/02 04:25:16 lukem Exp $");
@


1.13
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_read.c,v 1.12 2005/02/12 12:53:23 aymeric Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD: ex_read.c,v 1.12 2005/02/12 12:53:23 aymeric Exp $");
d345 1
a345 1
	if (ferror(fp) || fclose(fp))
d348 5
d369 2
a370 1
		(void)fclose(fp);
@


1.12
log
@Fix the RCSID's to be $NetBSD$ instead of $NetBSD
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.11 2002/04/09 01:47:33 thorpej Exp $	*/
d19 1
a19 1
__RCSID("$NetBSD$");
d68 3
@


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


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


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


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


1.10
log
@merge changes after import of nvi 1.79
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.9 2000/10/18 01:42:10 tv Exp $	*/
d14 1
d16 1
d18 3
@


1.9
log
@Fix %l[du] formats that have int arguments on ILP32; might break LP64.
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.8 2000/05/31 19:49:25 jdc Exp $	*/
d15 1
a15 1
static const char sccsid[] = "@@(#)ex_read.c	10.31 (Berkeley) 5/8/96";
d149 1
a149 1
			F_SET(sp, SC_EX_DONTWAIT);
d161 1
a161 1
			if (sp->gp->scr_screen(sp, SC_EX)) {
d234 1
a234 1
				(void)gp->scr_rename(sp);
d248 5
a252 3
	 * Historically, vi did not permit reads from non-regular files,
	 * nor did it distinguish between "read !" and "read!", so there
	 * was no way to "force" it.
d258 1
a258 1
	if (!S_ISREG(sb.st_mode)) {
d260 2
a261 1
		msgq(sp, M_ERR, "145|Only regular files may be read");
d272 7
a278 4
	 * Set the cursor to the first line read in, if anything read
	 * in, otherwise, the address.  (Historic vi set it to the
	 * line after the address regardless, but since that line may
	 * not exist we don't bother.)
d280 6
a285 4
	sp->lno = cmdp->addr1.lno;
	if (nlines)
		++sp->lno;

d348 1
a348 1
		    (unsigned long)lcnt, (unsigned long)ccnt);
@


1.8
log
@Handle xterm's alternate screen when entering or leaving ex mode, e.g.
":!ls", so that the screen is not changed before the "Press any key"
message.  Taken from v1.79.
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.7 1998/01/09 08:07:59 perry Exp $	*/
d339 2
a340 1
		    "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
@


1.8.2.1
log
@Pullup 1.9 [releng]:
Fix %l[du] formats that have int arguments on ILP32; might break LP64.
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.9 2000/10/18 01:42:10 tv Exp $	*/
d339 1
a339 2
		    "148|%s: %lu lines, %lu characters", p,
		    (unsigned long)lcnt, (unsigned long)ccnt);
@


1.7
log
@RCS Id Police.
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d165 6
@


1.7.8.1
log
@Sync w/ netbsd-1-5-base.
@
text
@d1 1
a1 1
/*	$NetBSD: ex_read.c,v 1.8 2000/05/31 19:49:25 jdc Exp $	*/
a164 6
			/*
			 * !!!
			 * Historically, the read command doesn't switch to
			 * the alternate X11 xterm screen, if doing a filter
			 * read -- don't set SA_ALTERNATE.
			 */
@


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_read.c	8.41 (Berkeley) 8/17/94";
a24 1
#include <signal.h>
a27 5
#include <termios.h>

#include "compat.h"
#include <db.h>
#include <regex.h>
d29 2
a30 2
#include "vi.h"
#include "excmd.h"
d35 1
a35 1
 * Read from a file or utility.
d39 2
d43 1
a43 1
ex_read(sp, ep, cmdp)
d45 1
a45 2
	EXF *ep;
	EXCMDARG *cmdp;
d47 1
d52 2
d56 2
a57 2
	size_t arglen, blen, len;
	int btear, farg, rval;
d60 2
d63 2
a64 4
	 *  0 args: we're done.
	 *  1 args: check for "read !arg".
	 *  2 args: check for "read ! arg".
	 * >2 args: object, too many args.
a65 1
	farg = 0;
d68 1
d76 9
a84 2
			farg = 1;
		}
a85 8
	case 2:
		if (cmdp->argv[0]->len == 1 && cmdp->argv[0]->bp[0] == '!')  {
			arg = cmdp->argv[1]->bp;
			arglen = cmdp->argv[1]->len;
			farg = 2;
			break;
		}
		/* FALLTHROUGH */
d87 2
a88 1
		goto badarg;
d91 5
a95 3
	if (farg != 0) {
		/* File name and bang expand the user's argument. */
		if (argv_exp1(sp, ep, cmdp, arg, arglen, 1))
d97 1
d99 14
a112 3
		/* If argc unchanged, there wasn't anything to expand. */
		if (cmdp->argc == farg)
			goto usage;
d118 2
a119 1
		if ((exp->lastbcomm = strdup(cmdp->argv[farg]->bp)) == NULL) {
d124 15
a138 9
		/* Redisplay the user's argument if it's changed. */
		if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
			len = cmdp->argv[farg]->len;
			GET_SPACE_RET(sp, p, blen, len + 2);
			p[0] = '!';
			memmove(p + 1,
			    cmdp->argv[farg]->bp, cmdp->argv[farg]->len + 1);
			(void)sp->s_busy(sp, p);
			FREE_SPACE(sp, p, blen);
d141 27
a167 2
		if (filtercmd(sp, ep, &cmdp->addr1,
		    NULL, &rm, cmdp->argv[farg]->bp, FILTER_READ))
d171 1
a171 1
		F_SET(EXP(sp), EX_AUTOPRINT);
d173 4
a176 1
		/* If in vi mode, move to the first nonblank. */
d178 1
a178 1
		if (IN_VI_MODE(sp)) {
d180 1
a180 1
			(void)nonblank(sp, ep, sp->lno, &sp->cno);
d183 1
a183 15
	}

	/* Shell and file name expand the user's argument. */
	if (argv_exp2(sp, ep, cmdp, arg, arglen, 0))
		return (1);

	/*
	 *  0 args: no arguments, read the current file, don't set the
	 *	    alternate file name.
	 *  1 args: read it, switching to it or settgin the alternate file
	 *	    name.
	 * >1 args: object, too many args.
	 */
	switch (cmdp->argc) {
	case 1:
d186 3
a188 2
	case 2:
		name = cmdp->argv[1]->bp;
d190 7
a196 3
		 * !!!
		 * Historically, if you had an "unnamed" file, the read command
		 * renamed the file.
d198 37
a234 10
		if (F_ISSET(sp->frp, FR_TMPFILE) &&
		    !F_ISSET(sp->frp, FR_READNAMED)) {
			if ((p = v_strdup(sp,
			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
				free(sp->frp->name);
				sp->frp->name = p;
			}
			F_SET(sp->frp, FR_NAMECHANGE | FR_READNAMED);
		} else
			set_alt_name(sp, name);
a235 5
	default:
badarg:		msgq(sp, M_ERR,
		    "%s expanded into too many file names", cmdp->argv[0]->bp);
usage:		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
		return (1);
d245 1
a245 1
		msgq(sp, M_SYSERR, "%s", name);
d250 1
a250 1
		msgq(sp, M_ERR, "Only regular files may be read");
d254 5
a258 5
	/* Turn on busy message. */
	btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
	rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
	if (btear)
		busy_off(sp);
d276 2
d280 1
a280 1
ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
a281 1
	EXF *ep;
d286 1
a286 1
	int success_msg;
d289 1
d293 2
a294 1
	int rval;
d296 1
a296 1
	rval = 0;
d305 1
d307 8
a314 8
		if (INTERRUPTED(sp)) {
			if (!success_msg)
				msgq(sp, M_INFO, "Interrupted");
			break;
		}
		if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
			rval = 1;
			break;
d316 2
d321 2
a322 12
	if (ferror(fp)) {
		msgq(sp, M_SYSERR, "%s", name);
		rval = 1;
	}

	if (fclose(fp)) {
		msgq(sp, M_SYSERR, "%s", name);
		return (1);
	}

	if (rval)
		return (1);
d328 14
a341 4
	if (success_msg)
		msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters",
		    INTERRUPTED(sp) ? "Interrupted read: " : "",
		    name, lcnt, lcnt == 1 ? "" : "s", ccnt);
d343 3
a345 1
	return (0);
@


1.5.2.1
log
@file ex_read.c was added on branch netbsd-1-0 on 1994-08-17 20:12:48 +0000
@
text
@d1 300
@


1.5.2.2
log
@clean up import.
@
text
@a0 300
/*-
 * 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_read.c	8.41 (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 <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>

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

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

/*
 * ex_read --	:read [file]
 *		:read [!cmd]
 * Read from a file or utility.
 *
 * !!!
 * Historical vi wouldn't undo a filter read, for no apparent reason.
 */
int
ex_read(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	struct stat sb;
	CHAR_T *arg, *name;
	EX_PRIVATE *exp;
	FILE *fp;
	MARK rm;
	recno_t nlines;
	size_t arglen, blen, len;
	int btear, farg, rval;
	char *p;

	/*
	 *  0 args: we're done.
	 *  1 args: check for "read !arg".
	 *  2 args: check for "read ! arg".
	 * >2 args: object, too many args.
	 */
	farg = 0;
	switch (cmdp->argc) {
	case 0:
		break;
	case 1:
		arg = cmdp->argv[0]->bp;
		arglen = cmdp->argv[0]->len;
		if (*arg == '!') {
			++arg;
			--arglen;
			farg = 1;
		}
		break;
	case 2:
		if (cmdp->argv[0]->len == 1 && cmdp->argv[0]->bp[0] == '!')  {
			arg = cmdp->argv[1]->bp;
			arglen = cmdp->argv[1]->len;
			farg = 2;
			break;
		}
		/* FALLTHROUGH */
	default:
		goto badarg;
	}

	if (farg != 0) {
		/* File name and bang expand the user's argument. */
		if (argv_exp1(sp, ep, cmdp, arg, arglen, 1))
			return (1);

		/* If argc unchanged, there wasn't anything to expand. */
		if (cmdp->argc == farg)
			goto usage;

		/* Set the last bang command. */
		exp = EXP(sp);
		if (exp->lastbcomm != NULL)
			free(exp->lastbcomm);
		if ((exp->lastbcomm = strdup(cmdp->argv[farg]->bp)) == NULL) {
			msgq(sp, M_SYSERR, NULL);
			return (1);
		}

		/* Redisplay the user's argument if it's changed. */
		if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
			len = cmdp->argv[farg]->len;
			GET_SPACE_RET(sp, p, blen, len + 2);
			p[0] = '!';
			memmove(p + 1,
			    cmdp->argv[farg]->bp, cmdp->argv[farg]->len + 1);
			(void)sp->s_busy(sp, p);
			FREE_SPACE(sp, p, blen);
		}

		if (filtercmd(sp, ep, &cmdp->addr1,
		    NULL, &rm, cmdp->argv[farg]->bp, FILTER_READ))
			return (1);

		/* The filter version of read set the autoprint flag. */
		F_SET(EXP(sp), EX_AUTOPRINT);

		/* If in vi mode, move to the first nonblank. */
		sp->lno = rm.lno;
		if (IN_VI_MODE(sp)) {
			sp->cno = 0;
			(void)nonblank(sp, ep, sp->lno, &sp->cno);
		}
		return (0);
	}

	/* Shell and file name expand the user's argument. */
	if (argv_exp2(sp, ep, cmdp, arg, arglen, 0))
		return (1);

	/*
	 *  0 args: no arguments, read the current file, don't set the
	 *	    alternate file name.
	 *  1 args: read it, switching to it or settgin the alternate file
	 *	    name.
	 * >1 args: object, too many args.
	 */
	switch (cmdp->argc) {
	case 1:
		name = sp->frp->name;
		break;
	case 2:
		name = cmdp->argv[1]->bp;
		/*
		 * !!!
		 * Historically, if you had an "unnamed" file, the read command
		 * renamed the file.
		 */
		if (F_ISSET(sp->frp, FR_TMPFILE) &&
		    !F_ISSET(sp->frp, FR_READNAMED)) {
			if ((p = v_strdup(sp,
			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
				free(sp->frp->name);
				sp->frp->name = p;
			}
			F_SET(sp->frp, FR_NAMECHANGE | FR_READNAMED);
		} else
			set_alt_name(sp, name);
		break;
	default:
badarg:		msgq(sp, M_ERR,
		    "%s expanded into too many file names", cmdp->argv[0]->bp);
usage:		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
		return (1);
	}

	/*
	 * !!!
	 * Historically, vi did not permit reads from non-regular files,
	 * nor did it distinguish between "read !" and "read!", so there
	 * was no way to "force" it.
	 */
	if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
		msgq(sp, M_SYSERR, "%s", name);
		return (1);
	}
	if (!S_ISREG(sb.st_mode)) {
		(void)fclose(fp);
		msgq(sp, M_ERR, "Only regular files may be read");
		return (1);
	}

	/* Turn on busy message. */
	btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
	rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
	if (btear)
		busy_off(sp);

	/*
	 * Set the cursor to the first line read in, if anything read
	 * in, otherwise, the address.  (Historic vi set it to the
	 * line after the address regardless, but since that line may
	 * not exist we don't bother.)
	 */
	sp->lno = cmdp->addr1.lno;
	if (nlines)
		++sp->lno;

	return (rval);
}

/*
 * ex_readfp --
 *	Read lines into the file.
 */
int
ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
	SCR *sp;
	EXF *ep;
	char *name;
	FILE *fp;
	MARK *fm;
	recno_t *nlinesp;
	int success_msg;
{
	EX_PRIVATE *exp;
	recno_t lcnt, lno;
	size_t len;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	int rval;

	rval = 0;
	exp = EXP(sp);

	/*
	 * Add in the lines from the output.  Insertion starts at the line
	 * following the address.
	 */
	ccnt = 0;
	lcnt = 0;
	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
		if (INTERRUPTED(sp)) {
			if (!success_msg)
				msgq(sp, M_INFO, "Interrupted");
			break;
		}
		if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
			rval = 1;
			break;
		}
		ccnt += len;
	}

	if (ferror(fp)) {
		msgq(sp, M_SYSERR, "%s", name);
		rval = 1;
	}

	if (fclose(fp)) {
		msgq(sp, M_SYSERR, "%s", name);
		return (1);
	}

	if (rval)
		return (1);

	/* Return the number of lines read in. */
	if (nlinesp != NULL)
		*nlinesp = lcnt;

	if (success_msg)
		msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters",
		    INTERRUPTED(sp) ? "Interrupted read: " : "",
		    name, lcnt, lcnt == 1 ? "" : "s", ccnt);

	return (0);
}
@


1.4
log
@clean up import.  still have to hack some things.
@
text
@d35 1
a35 1
static const char sccsid[] = "@@(#)ex_read.c	8.40 (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_read.c	8.26 (Berkeley) 3/23/94";
d62 5
a66 2
 *		:read [! cmd]
 *	Read from a file or utility.
d75 2
d80 3
a82 3
	size_t blen, len;
	int btear, itear, rval;
	char *bp, *name;
d85 4
a88 5
	 * If "read !", it's a pipe from a utility.
	 *
	 * !!!
	 * Historical vi wouldn't undo a filter read, for no apparent
	 * reason.
d90 28
a117 4
	if (F_ISSET(cmdp, E_FORCE)) {
		/* Expand the user's argument. */
		if (argv_exp1(sp, ep,
		    cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
d120 10
a129 3
		/* If argc still 1, there wasn't anything to expand. */
		if (cmdp->argc == 1) {
			msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
d135 7
a141 6
			len = cmdp->argv[1]->len;
			GET_SPACE_RET(sp, bp, blen, len + 2);
			bp[0] = '!';
			memmove(bp + 1, cmdp->argv[1], cmdp->argv[1]->len + 1);
			(void)sp->s_busy(sp, bp);
			FREE_SPACE(sp, bp, blen);
d144 2
a145 2
		if (filtercmd(sp, ep,
		    &cmdp->addr1, NULL, &rm, cmdp->argv[1]->bp, FILTER_READ))
d147 5
d153 4
d160 2
a161 3
	/* Expand the user's argument. */
	if (argv_exp2(sp, ep,
	    cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
d164 7
d173 1
a173 5
		/*
		 * No arguments, read the current file.
		 * Doesn't set the alternate file name.
		 */
		name = FILENAME(sp->frp);
d176 1
d178 3
a180 2
		 * One argument, read it.
		 * Sets the alternate file name.
d182 10
a191 2
		name = cmdp->argv[1]->bp;
		set_alt_name(sp, name);
d194 1
a194 2
		/* If expanded to more than one argument, object. */
		msgq(sp, M_ERR,
d196 1
a196 1
		msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
d207 1
a207 1
		msgq(sp, M_SYSERR, name);
d212 1
a212 1
		msgq(sp, M_ERR, "Only regular files may be read.");
d216 1
a216 5
	/*
	 * Nvi handles the interrupt when reading from a file, but not
	 * when reading from a filter, since the terminal settings have
	 * been reset.
	 */
a217 1
	itear = !intr_init(sp);
a220 2
	if (itear)
		intr_end(sp);
a231 1
	F_SET(EXP(sp), EX_AUTOPRINT);
d265 3
a267 2
		if (F_ISSET(sp, S_INTERRUPTED)) {
			msgq(sp, M_INFO, "Interrupted.");
d278 1
a278 1
		msgq(sp, M_SYSERR, name);
d283 1
a283 1
		msgq(sp, M_SYSERR, name);
d295 2
a296 1
		msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
@


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_read.c	8.21 (Berkeley) 1/23/94"; */
static char *rcsid = "$Id$";
d39 1
d41 1
d43 1
d46 3
d51 5
d76 1
a76 1
	int rval;
d160 7
d168 4
d182 1
a182 1
	
d202 1
a202 1
	u_long ccnt;
d204 1
a204 1
	recno_t lno, nlines;
d207 3
d215 6
a220 3
	rval = 0;
	exp = EXP(sp);
	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
a241 1
	nlines = lno - fm->lno;
d243 1
a243 1
		*nlinesp = nlines;
d247 1
a247 1
		    name, nlines, nlines == 1 ? "" : "s", ccnt);
@


1.1
log
@Initial revision
@
text
@d35 2
a36 1
static char sccsid[] = "@@(#)ex_read.c	8.21 (Berkeley) 1/23/94";
@


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_read.c	8.26 (Berkeley) 3/23/94";
a38 1
#include <sys/queue.h>
a39 1
#include <sys/time.h>
a40 1
#include <bitstring.h>
a42 3
#include <limits.h>
#include <signal.h>
#include <stdio.h>
a44 5
#include <termios.h>

#include "compat.h"
#include <db.h>
#include <regex.h>
d65 1
a65 1
	int btear, itear, rval;
a148 7
	/*
	 * Nvi handles the interrupt when reading from a file, but not
	 * when reading from a filter, since the terminal settings have
	 * been reset.
	 */
	btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Reading...");
	itear = !intr_init(sp);
a149 4
	if (btear)
		busy_off(sp);
	if (itear)
		intr_end(sp);
d160 1
a160 1

d180 1
a180 1
	recno_t lcnt, lno;
d182 1
a182 1
	u_long ccnt;			/* XXX: can't print off_t portably. */
a184 3
	rval = 0;
	exp = EXP(sp);

d190 3
a192 6
	lcnt = 0;
	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
		if (F_ISSET(sp, S_INTERRUPTED)) {
			msgq(sp, M_INFO, "Interrupted.");
			break;
		}
d214 1
d216 1
a216 1
		*nlinesp = lcnt;
d220 1
a220 1
		    name, lcnt, lcnt == 1 ? "" : "s", ccnt);
@


1.1.1.3
log
@new public version of nvi
@
text
@d35 1
a35 1
static const char sccsid[] = "@@(#)ex_read.c	8.40 (Berkeley) 8/17/94";
d62 2
a63 5
 *		:read [!cmd]
 * Read from a file or utility.
 *
 * !!!
 * Historical vi wouldn't undo a filter read, for no apparent reason.
a71 2
	CHAR_T *arg, *name;
	EX_PRIVATE *exp;
d75 3
a77 3
	size_t arglen, blen, len;
	int btear, farg, rval;
	char *p;
d80 5
a84 4
	 *  0 args: we're done.
	 *  1 args: check for "read !arg".
	 *  2 args: check for "read ! arg".
	 * >2 args: object, too many args.
d86 4
a89 28
	farg = 0;
	switch (cmdp->argc) {
	case 0:
		break;
	case 1:
		arg = cmdp->argv[0]->bp;
		arglen = cmdp->argv[0]->len;
		if (*arg == '!') {
			++arg;
			--arglen;
			farg = 1;
		}
		break;
	case 2:
		if (cmdp->argv[0]->len == 1 && cmdp->argv[0]->bp[0] == '!')  {
			arg = cmdp->argv[1]->bp;
			arglen = cmdp->argv[1]->len;
			farg = 2;
			break;
		}
		/* FALLTHROUGH */
	default:
		goto badarg;
	}

	if (farg != 0) {
		/* File name and bang expand the user's argument. */
		if (argv_exp1(sp, ep, cmdp, arg, arglen, 1))
d92 3
a94 10
		/* If argc unchanged, there wasn't anything to expand. */
		if (cmdp->argc == farg)
			goto usage;

		/* Set the last bang command. */
		exp = EXP(sp);
		if (exp->lastbcomm != NULL)
			free(exp->lastbcomm);
		if ((exp->lastbcomm = strdup(cmdp->argv[farg]->bp)) == NULL) {
			msgq(sp, M_SYSERR, NULL);
d100 6
a105 7
			len = cmdp->argv[farg]->len;
			GET_SPACE_RET(sp, p, blen, len + 2);
			p[0] = '!';
			memmove(p + 1,
			    cmdp->argv[farg]->bp, cmdp->argv[farg]->len + 1);
			(void)sp->s_busy(sp, p);
			FREE_SPACE(sp, p, blen);
d108 2
a109 2
		if (filtercmd(sp, ep, &cmdp->addr1,
		    NULL, &rm, cmdp->argv[farg]->bp, FILTER_READ))
a110 5

		/* The filter version of read set the autoprint flag. */
		F_SET(EXP(sp), EX_AUTOPRINT);

		/* If in vi mode, move to the first nonblank. */
a111 4
		if (IN_VI_MODE(sp)) {
			sp->cno = 0;
			(void)nonblank(sp, ep, sp->lno, &sp->cno);
		}
d115 3
a117 2
	/* Shell and file name expand the user's argument. */
	if (argv_exp2(sp, ep, cmdp, arg, arglen, 0))
a119 7
	/*
	 *  0 args: no arguments, read the current file, don't set the
	 *	    alternate file name.
	 *  1 args: read it, switching to it or settgin the alternate file
	 *	    name.
	 * >1 args: object, too many args.
	 */
d122 5
a126 1
		name = sp->frp->name;
a128 1
		name = cmdp->argv[1]->bp;
d130 2
a131 3
		 * !!!
		 * Historically, if you had an "unnamed" file, the read command
		 * renamed the file.
d133 2
a134 10
		if (F_ISSET(sp->frp, FR_TMPFILE) &&
		    !F_ISSET(sp->frp, FR_READNAMED)) {
			if ((p = v_strdup(sp,
			    cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
				free(sp->frp->name);
				sp->frp->name = p;
			}
			F_SET(sp->frp, FR_NAMECHANGE | FR_READNAMED);
		} else
			set_alt_name(sp, name);
d137 2
a138 1
badarg:		msgq(sp, M_ERR,
d140 1
a140 1
usage:		msgq(sp, M_ERR, "Usage: %s", cmdp->cmd->usage);
d151 1
a151 1
		msgq(sp, M_SYSERR, "%s", name);
d156 1
a156 1
		msgq(sp, M_ERR, "Only regular files may be read");
d160 5
a164 1
	/* Turn on busy message. */
d166 1
d170 2
d183 1
d217 2
a218 3
		if (INTERRUPTED(sp)) {
			if (!success_msg)
				msgq(sp, M_INFO, "Interrupted");
d229 1
a229 1
		msgq(sp, M_SYSERR, "%s", name);
d234 1
a234 1
		msgq(sp, M_SYSERR, "%s", name);
d246 1
a246 2
		msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters",
		    INTERRUPTED(sp) ? "Interrupted read: " : "",
@


1.1.1.4
log
@new public version of nvi
@
text
@d35 1
a35 1
static char sccsid[] = "@@(#)ex_read.c	8.41 (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_read.c	10.31 (Berkeley) 5/8/96";
d47 1
d51 5
d57 2
a58 2
#include "../common/common.h"
#include "../vi/vi.h"
d63 1
a63 1
 *	Read from a file or utility.
a66 2
 *
 * PUBLIC: int ex_read __P((SCR *, EXCMD *));
d69 1
a69 1
ex_read(sp, cmdp)
d71 2
a72 1
	EXCMD *cmdp;
a73 1
	enum { R_ARG, R_EXPANDARG, R_FILTER } which;
a77 2
	FREF *frp;
	GS *gp;
d80 2
a81 2
	size_t arglen;
	int argc, rval;
a83 2
	gp = sp->gp;

d85 4
a88 2
	 * 0 args: read the current pathname.
	 * 1 args: check for "read !arg".
d90 1
a92 1
		which = R_ARG;
d100 2
a101 9
			which = R_FILTER;

			/* Secure means no shell access. */
			if (O_ISSET(sp, O_SECURE)) {
				ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
				return (1);
			}
		} else
			which = R_EXPANDARG;
d103 8
d112 1
a112 2
		abort();
		/* NOTREACHED */
d115 3
a117 5
	/* Load a temporary file if no file being edited. */
	if (sp->ep == NULL) {
		if ((frp = file_add(sp, NULL)) == NULL)
			return (1);
		if (file_init(sp, frp, NULL, 0))
a118 1
	}
d120 3
a122 14
	switch (which) {
	case R_FILTER:
		/*
		 * File name and bang expand the user's argument.  If
		 * we don't get an additional argument, it's illegal.
		 */
		argc = cmdp->argc;
		if (argv_exp1(sp, cmdp, arg, arglen, 1))
			return (1);
		if (argc == cmdp->argc) {
			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
			return (1);
		}
		argc = cmdp->argc - 1;
d128 1
a128 2
		if ((exp->lastbcomm =
		    strdup(cmdp->argv[argc]->bp)) == NULL) {
d133 9
a141 15
		/*
		 * Vi redisplayed the user's argument if it changed, ex
		 * always displayed a !, plus the user's argument if it
		 * changed.
		 */
		if (F_ISSET(sp, SC_VI)) {
			if (F_ISSET(cmdp, E_MODIFY))
				(void)vs_update(sp, "!", cmdp->argv[argc]->bp);
		} else {
			if (F_ISSET(cmdp, E_MODIFY))
				(void)ex_printf(sp,
				    "!%s\n", cmdp->argv[argc]->bp);
			else
				(void)ex_puts(sp, "!\n");
			(void)ex_fflush(sp);
d144 2
a145 27
		/*
		 * Historically, filter reads as the first ex command didn't
		 * wait for the user. If SC_SCR_EXWROTE not already set, set
		 * the don't-wait flag.
		 */
		if (!F_ISSET(sp, SC_SCR_EXWROTE))
			F_SET(sp, SC_EX_DONTWAIT);

		/*
		 * Switch into ex canonical mode.  The reason to restore the
		 * original terminal modes for read filters is so that users
		 * can do things like ":r! cat /dev/tty".
		 *
		 * !!!
		 * We do not output an extra <newline>, so that we don't touch
		 * the screen on a normal read.
		 */
		if (F_ISSET(sp, SC_VI)) {
			if (sp->gp->scr_screen(sp, SC_EX)) {
				ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
				return (1);
			}
			F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
		}

		if (ex_filter(sp, cmdp, &cmdp->addr1,
		    NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
d149 1
a149 1
		F_SET(cmdp, E_AUTOPRINT);
d151 1
a151 4
		/*
		 * If in vi mode, move to the first nonblank.  Might have
		 * switched into ex mode, so saved the original SC_VI value.
		 */
d153 1
a153 1
		if (F_ISSET(sp, SC_VI)) {
d155 1
a155 1
			(void)nonblank(sp, sp->lno, &sp->cno);
d158 15
a172 1
	case R_ARG:
d175 2
a176 3
	case R_EXPANDARG:
		if (argv_exp2(sp, cmdp, arg, arglen))
			return (1);
d178 3
a180 7
		 *  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.
d182 10
a191 37
		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.
				 */
				F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
				F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);

				/* Notify the screen. */
				(void)gp->scr_rename(sp);
			} else
				set_alt_name(sp, name);
			break;
		default:
			ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
			return (1);
		
		}
d193 5
d207 1
a207 1
		msgq_str(sp, M_SYSERR, name, "%s");
d212 1
a212 1
		msgq(sp, M_ERR, "145|Only regular files may be read");
d216 5
a220 5
	/* Try and get a lock. */
	if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
		msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);

	rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
a237 2
 *
 * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
d240 1
a240 1
ex_readfp(sp, name, fp, fm, nlinesp, silent)
d242 1
d247 1
a247 1
	int silent;
a249 1
	GS *gp;
d253 1
a253 2
	int nf, rval;
	char *p;
d255 1
a255 1
	gp = sp->gp;
a263 1
	p = "147|Reading...";
d265 8
a272 8
		if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
			if (INTERRUPTED(sp))
				break;
			if (!silent) {
				gp->scr_busy(sp, p,
				    p == NULL ? BUSY_UPDATE : BUSY_ON);
				p = NULL;
			}
a273 2
		if (db_append(sp, 1, lno, exp->ibp, len))
			goto err;
d277 12
a288 2
	if (ferror(fp) || fclose(fp))
		goto err;
d294 4
a297 14
	if (!silent) {
		p = msg_print(sp, name, &nf);
		msgq(sp, M_INFO,
		    "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
		if (nf)
			FREE_SPACE(sp, p, 0);
	}

	rval = 0;
	if (0) {
err:		msgq_str(sp, M_SYSERR, name, "%s");
		(void)fclose(fp);
		rval = 1;
	}
d299 1
a299 3
	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);
	return (rval);
@


1.1.1.6
log
@import of nvi 1.79
@
text
@d13 1
a13 1
static const char sccsid[] = "@@(#)ex_read.c	10.38 (Berkeley) 8/12/96";
d147 1
a147 1
			F_SET(sp, SC_EX_WAIT_NO);
d159 1
a159 1
			if (gp->scr_screen(sp, SC_EX)) {
a162 6
			/*
			 * !!!
			 * Historically, the read command doesn't switch to
			 * the alternate X11 xterm screen, if doing a filter
			 * read -- don't set SA_ALTERNATE.
			 */
d226 1
a226 1
				(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
d240 3
a242 5
	 * Historically, vi did not permit reads from non-regular files, nor
	 * did it distinguish between "read !" and "read!", so there was no
	 * way to "force" it.  We permit reading from named pipes too, since
	 * they didn't exist when the original implementation of vi was done
	 * and they seem a reasonable addition.
d248 1
a248 1
	if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
d250 1
a250 2
		msgq(sp, M_ERR,
		    "145|Only regular files and named pipes may be read");
d261 4
a264 7
	 * In vi, set the cursor to the first line read in, if anything read
	 * in, otherwise, the address.  (Historic vi set it to the line after
	 * the address regardless, but since that line may not exist we don't
	 * bother.)
	 *
	 * In ex, set the cursor to the last line read in, if anything read in,
	 * otherwise, the address.
d266 4
a269 6
	if (F_ISSET(sp, SC_VI)) {
		sp->lno = cmdp->addr1.lno;
		if (nlines)
			++sp->lno;
	} else
		sp->lno = cmdp->addr1.lno + nlines;
@

