예제 #1
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
int zs_accept( int fd ) {
	zsocket_t* zs = zs_get_by_fd( fd );

	if ( !zs || FL_ISSET( zs->general.status, ZS_STAT_CLOSED ) ) {
		errno = EBADF;
		return -1;
	}

	if ( zs->type != ZSOCK_LISTEN ) {
		errno = EINVAL;
		return -1;
	}

	if ( !FL_ISSET( zs->listen.status, ZS_STAT_READABLE ) ) {
		errno = EAGAIN;
		return -1;
	}

	if ( FD_ISSET( fd, &active_read_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_READABLE ) )
		n_selectable--;

	FL_CLR( zs->listen.status, ZS_STAT_READABLE );
	zs_update_fd_state( fd, NULL );

	if ( zs->listen.accepted_errno ) {
		errno = zs->listen.accepted_errno;
		zs->listen.accepted_errno = 0;
	} else
		assert( zs->listen.accepted_fd >= 0 );

	fd = zs->listen.accepted_fd;
	zs->listen.accepted_fd = -1;
	return fd;
}
예제 #2
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
int zs_select() {
	fd_set read_fd_set  = active_read_fd_set;
	fd_set write_fd_set = active_write_fd_set;

//	int rw_still_avail = 0;
	int fd = fd_hash_head( &active_hash );
	while ( fd != -1 ) {
		zsocket_t* zs;
		if ( !( zs = zs_get_by_fd( fd ) ) ) continue;

		if ( FD_ISSET( fd, &read_fd_set ) && FD_ISSET( fd, &active_read_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_READABLE ) ) {
			if ( zs->type == ZSOCK_CONNECT )
				zs->general.event_hdlr( fd, ZS_EVT_READ_READY );
			else
				zs->general.event_hdlr( fd, ZS_EVT_ACCEPT_READY );
		}

		if ( FD_ISSET( fd, &write_fd_set ) && FD_ISSET( fd, &active_write_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) ) {
			assert( zs->type == ZSOCK_CONNECT );
			zs->general.event_hdlr( fd, ZS_EVT_WRITE_READY );
		}

		/*if (
		( FD_ISSET( fd, &active_read_fd_set )  && FL_ISSET( zs->general.status, ZS_STAT_READABLE ) ) ||
		( FD_ISSET( fd, &active_write_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
		)
			rw_still_avail++;*/
		fd = fd_hash_next( &active_hash, fd );
	}

	return zs_need_select();
}
예제 #3
0
/*
 * ex_edit --	:e[dit][!] [+cmd] [file]
 *		:ex[!] [+cmd] [file]
 *		:vi[sual][!] [+cmd] [file]
 *
 * Edit a file; if none specified, re-edit the current file.  The third
 * form of the command can only be executed while in vi mode.  See the
 * hack in ex.c:ex_cmd().
 *
 * !!!
 * Historic vi didn't permit the '+' command form without specifying
 * a file name as well.  This seems unreasonable, so we support it
 * regardless.
 *
 * PUBLIC: int ex_edit __P((SCR *, EXCMD *));
 */
int
ex_edit(SCR *sp, EXCMD *cmdp)
{
	FREF *frp;
	int attach, setalt;
	const char *np;
	size_t nlen;

	switch (cmdp->argc) {
	case 0:
		/*
		 * If the name has been changed, we edit that file, not the
		 * original name.  If the user was editing a temporary file
		 * (or wasn't editing any file), create another one.  The
		 * reason for not reusing temporary files is that there is
		 * special exit processing of them, and reuse is tricky.
		 */
		frp = sp->frp;
		if (sp->ep == NULL || F_ISSET(frp, FR_TMPFILE)) {
			if ((frp = file_add(sp, NULL)) == NULL)
				return (1);
			attach = 0;
		} else
			attach = 1;
		setalt = 0;
		break;
	case 1:
		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, 
			 np, nlen);
		if ((frp = file_add(sp, np)) == NULL)
			return (1);
		attach = 0;
		setalt = 1;
		set_alt_name(sp, np);
		break;
	default:
		abort();
	}

	if (F_ISSET(cmdp, E_NEWSCREEN) || cmdp->cmd == &cmds[C_VSPLIT])
		return (ex_N_edit(sp, cmdp, frp, attach));

	/*
	 * Check for modifications.
	 *
	 * !!!
	 * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit.
	 */
	if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE)))
		return (1);

	/* Switch files. */
	if (file_init(sp, frp, NULL, (setalt ? FS_SETALT : 0) |
	    (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0)))
		return (1);

	F_SET(sp, SC_FSWITCH);
	return (0);
}
예제 #4
0
파일: daemon.c 프로젝트: ianhalpern/zimr
int daemon_detach( int flags ) {

	printf( " * starting daemon..." );
	fflush( stdout );

	void (*prev_sighandler)( int );

	if ( ( prev_sighandler = signal( SIGHUP, empty_sighandler ) ) != SIG_DFL )
		signal( SIGHUP, prev_sighandler );
	if ( ( prev_sighandler = signal( SIGTERM, empty_sighandler ) ) != SIG_DFL )
		signal( SIGTERM, prev_sighandler );
	if ( ( prev_sighandler = signal( SIGINT, empty_sighandler ) ) != SIG_DFL )
		signal( SIGINT, prev_sighandler );
	if ( ( prev_sighandler = signal( SIGQUIT, empty_sighandler ) ) != SIG_DFL )
		signal( SIGQUIT, prev_sighandler );


	/* Our process ID and Session ID */
	pid_t pid, sid;

	/* Fork off the parent process */
	pid = fork();
	if ( pid < 0 )
		return 0;

	/* If we got a good PID, then
	   we can exit the parent process. */
	if ( pid > 0 )
		exit( EXIT_SUCCESS );

	/* Change the file mode mask */
	umask( 0 );

	/* Create a new SID for the child process */
	sid = setsid( );
	if ( sid < 0 )
		return 0;

	/* Change the current working directory */
	if ( !FL_ISSET( flags, D_NOCD ) && chdir( "/" ) < 0 )
		return 0;

	if ( !FL_ISSET( flags, D_NOLOCKFILE ) ) {
		if ( !createlockfile( ) ) {
			printf( "failed: could not set lockfile.\n" );
			return 0;
		}
	}

	is_daemon = true;

	printf( "started.\n" );

	if ( !FL_ISSET( flags, D_KEEPSTDIO ) ) {
		daemon_redirect_stdio( );
	}
	return 1;
}
예제 #5
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
static void zs_accepter( int fd, void* udata ) {
	zsocket_t* zs = zs_get_by_fd( fd );
	zsocket_t* zs_parent = zs_get_by_fd( zs->connect.parent_fd );

/*	printf( "zs_accepter: %d: START\n", zs->general.sockfd );
	ssize_t n;
	if ( zs->connect.ssl ) {
		n = SSL_accept( zs->connect.ssl );
		if ( n < 0 ) {
			int err = SSL_get_error( zs->connect.ssl, n );
			printf("zs_accepter: %d: SSL_accept error %d ( %d, %d )\n", zs->general.sockfd, err, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE );
			switch ( err ) {
				case SSL_ERROR_WANT_READ:
					FL_SET( zs->connect.status, ZS_STAT_WANT_READ_FROM_ACCEPT );
					return;
				case SSL_ERROR_WANT_WRITE:
					FL_SET( zs->connect.status, ZS_STAT_WANT_WRITE_FROM_ACCEPT );
					return;
			}

			ERR_print_errors_fp( stderr );
			zs_close( fd );

			zs_parent->listen.accepted_fd = -1;
			zs_parent->listen.accepted_errno = EPROTO;
		}
		printf( "zs_accepter: %d: SSL_accept accepted!\n", zs->general.sockfd );
	}*/

	if ( FD_ISSET( zs_parent->general.sockfd, &active_read_fd_set ) && !FL_ISSET( zs_parent->general.status, ZS_STAT_READABLE ) )
		n_selectable++;

	FL_SET( zs_parent->general.status, ZS_STAT_READABLE );
	FL_CLR( zs_parent->general.status, ZS_STAT_ACCEPTING );

	if ( zs_parent->listen.accepted_fd != -1 ) {
		if ( FD_ISSET( fd, &active_write_fd_set ) && !FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
			n_selectable++;
		FL_SET( zs->connect.status, ZS_STAT_CONNECTED | ZS_STAT_WRITABLE );
		if ( zs_is_ssl( fd ) )
			FL_SET( zs->connect.status, ZS_STAT_ACCEPTING );
	}

	// Must call this inside zs_accepter because the
	// parent zsocket's state update may not be called by
	// the caller on return from calling zs_accepter,
	// it may only call it for the child
	zs_update_fd_state( zs_parent->general.sockfd, NULL );
}
예제 #6
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
static void zs_connecter( int fd, void* udata ) {
	zsocket_t* zs = zs_get_by_fd( fd );

	ssize_t n;
	if ( zs->connect.ssl ) {
		n = SSL_connect( zs->connect.ssl );
		if ( n < 0 ) {
			int err = SSL_get_error( zs->connect.ssl, n );
			switch ( err ) {
				case SSL_ERROR_WANT_READ:
					FL_SET( zs->connect.status, ZS_STAT_WANT_READ_FROM_CONNECT );
					return;
				case SSL_ERROR_WANT_WRITE:
					FL_SET( zs->connect.status, ZS_STAT_WANT_WRITE_FROM_CONNECT );
					return;
			}

			ERR_print_errors_fp( stderr );

			zs->connect.read.rw_errno = EPROTO;
			zs->connect.write.rw_errno = EPROTO;
		}
	}

	if ( FD_ISSET( fd, &active_write_fd_set ) && !FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
		n_selectable++;

	FL_SET( zs->connect.status, ZS_STAT_CONNECTED | ZS_STAT_WRITABLE );
	FL_CLR( zs->general.status, ZS_STAT_CONNECTING );
}
예제 #7
0
파일: ex_delete.c 프로젝트: Alkzndr/freebsd
/*
 * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags]
 *
 *	Delete lines from the file.
 *
 * PUBLIC: int ex_delete __P((SCR *, EXCMD *));
 */
int
ex_delete(SCR *sp, EXCMD *cmdp)
{
	recno_t lno;

	NEEDFILE(sp, cmdp);

	/*
	 * !!!
	 * Historically, lines deleted in ex were not placed in the numeric
	 * buffers.  We follow historic practice so that we don't overwrite
	 * vi buffers accidentally.
	 */
	if (cut(sp,
	    FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL,
	    &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE))
		return (1);

	/* Delete the lines. */
	if (del(sp, &cmdp->addr1, &cmdp->addr2, 1))
		return (1);

	/* Set the cursor to the line after the last line deleted. */
	sp->lno = cmdp->addr1.lno;

	/* Or the last line in the file if deleted to the end of the file. */
	if (db_last(sp, &lno))
		return (1);
	if (sp->lno > lno)
		sp->lno = lno;
	return (0);
}
예제 #8
0
파일: ex_tag.c 프로젝트: Alkzndr/freebsd
/* 
 * ex_tag_next --
 *	Switch context to the next TAG.
 *
 * PUBLIC: int ex_tag_next __P((SCR *, EXCMD *));
 */
int
ex_tag_next(SCR *sp, EXCMD *cmdp)
{
	EX_PRIVATE *exp;
	TAG *tp;
	TAGQ *tqp;
	char *np;
	size_t nlen;

	exp = EXP(sp);
	if ((tqp = TAILQ_FIRST(exp->tq)) == NULL) {
		tag_msg(sp, TAG_EMPTY, NULL);
		return (1);
	}
	if ((tp = TAILQ_NEXT(tqp->current, q)) == NULL) {
		msgq(sp, M_ERR, "282|Already at the last tag of this group");
		return (1);
	}
	if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE)))
		return (1);
	tqp->current = tp;

	if (F_ISSET(tqp, TAG_CSCOPE))
		(void)cscope_search(sp, tqp, tp);
	else
		(void)ctag_search(sp, tp->search, tp->slen, tqp->tag);
	if (tqp->current->msg) {
	    INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1,
		     np, nlen);
	    msgq(sp, M_INFO, "%s", np);
	}
	return (0);
}
예제 #9
0
/* 
 * ex_tag_prev --
 *	Switch context to the next TAG.
 *
 * PUBLIC: int ex_tag_prev __P((SCR *, EXCMD *));
 */
int
ex_tag_prev(SCR *sp, EXCMD *cmdp)
{
	EX_PRIVATE *exp;
	TAG *tp;
	TAGQ *tqp;
	const char *np;
	size_t nlen;

	exp = EXP(sp);
	if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) {
		tag_msg(sp, TAG_EMPTY, NULL);
		return (0);
	}
	if ((tp = tqp->current->q.cqe_prev) == (void *)&tqp->tagq) {
		msgq(sp, M_ERR, "255|Already at the first tag of this group");
		return (1);
	}
	if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE)))
		return (1);
	tqp->current = tp;

	if (F_ISSET(tqp, TAG_CSCOPE))
		(void)cscope_search(sp, tqp, tp);
	else
		(void)ctag_search(sp, tp->search, tp->slen, tqp->tag);
	if (tqp->current->msg) {
	    INT2CHAR(sp, tqp->current->msg, tqp->current->mlen + 1,
		     np, nlen);
	    msgq(sp, M_INFO, "%s", np);
	}
	return (0);
}
예제 #10
0
/*
 * ex_map -- :map[!] [input] [replacement]
 *	Map a key/string or display mapped keys.
 *
 * Historical note:
 *	Historic vi maps were fairly bizarre, and likely to differ in
 *	very subtle and strange ways from this implementation.  Two
 *	things worth noting are that vi would often hang or drop core
 *	if the map was strange enough (ex: map X "xy$@x^V), or, simply
 *	not work.  One trick worth remembering is that if you put a
 *	mark at the start of the map, e.g. map X mx"xy ...), or if you
 *	put the map in a .exrc file, things would often work much better.
 *	No clue why.
 *
 * PUBLIC: int ex_map __P((SCR *, EXCMD *));
 */
int
ex_map(SCR *sp, EXCMD *cmdp)
{
	seq_t stype;
	CHAR_T *input, *p;

	stype = FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND;

	switch (cmdp->argc) {
	case 0:
		if (seq_dump(sp, stype, 1) == 0)
			msgq(sp, M_INFO, stype == SEQ_INPUT ?
			    "132|No input map entries" :
			    "133|No command map entries");
		return (0);
	case 2:
		input = cmdp->argv[0]->bp;
		break;
	default:
		abort();
	}

	/*
	 * If the mapped string is #[0-9]* (and wasn't quoted) then store the
	 * function key mapping.  If the screen specific routine has been set,
	 * call it as well.  Note, the SEQ_FUNCMAP type is persistent across
	 * screen types, maybe the next screen type will get it right.
	 */
	if (input[0] == '#' && ISDIGIT((UCHAR_T)input[1])) {
		for (p = input + 2; ISDIGIT((UCHAR_T)*p); ++p);
		if (p[0] != '\0')
			goto nofunc;

		if (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len,
		    cmdp->argv[1]->bp, cmdp->argv[1]->len, stype,
		    SEQ_FUNCMAP | SEQ_USERDEF))
			return (1);
		return (sp->gp->scr_fmap == NULL ? 0 :
		    sp->gp->scr_fmap(sp, stype, input, cmdp->argv[0]->len,
		    cmdp->argv[1]->bp, cmdp->argv[1]->len));
	}

	/* Some single keys may not be remapped in command mode. */
nofunc:	if (stype == SEQ_COMMAND && input[1] == '\0')
		switch (KEY_VAL(sp, input[0])) {
		case K_COLON:
		case K_ESCAPE:
		case K_NL:
			msgq(sp, M_ERR,
			    "134|The %s character may not be remapped",
			    KEY_NAME(sp, input[0]));
			return (1);
		default:
			break;
		}
	return (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len,
	    cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_USERDEF));
}
예제 #11
0
파일: daemon.c 프로젝트: ianhalpern/zimr
int daemon_init( int flags ) {

	if ( is_daemon ) {// already daemonized
		printf( "failed: process already daemonized.\n" );
		return 0;
	}

	pid_t pid;
	if ( ( !FL_ISSET( flags, D_NOLOCKFILE ) && !FL_ISSET( flags, D_NOLOCKCHECK ) ) && ( pid = readlockfile() ) ) {// lockfile previously set
		if ( kill( pid, 0 ) == 0 ) { // process running
			printf( "failed: daemon already running.\n" );
			return false;
		} else {
			printf( "warning: previous daemon did not clean up lockfile on exit.\n" );
		}
	}

	return 1;
}
예제 #12
0
/*
 * ex_unmap -- (:unmap[!] key)
 *	Unmap a key.
 *
 * PUBLIC: int ex_unmap __P((SCR *, EXCMD *));
 */
int
ex_unmap(SCR *sp, EXCMD *cmdp)
{
	if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len,
	    FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) {
		msgq_wstr(sp, M_INFO,
		    cmdp->argv[0]->bp, "135|\"%s\" isn't currently mapped");
		return (1);
	}
	return (0);
}
예제 #13
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
void zs_set_write( int fd ) {
	zsocket_t* zs = zs_get_by_fd( fd );
	assert( zs );

	if ( !FD_ISSET( fd, &active_write_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
		n_selectable++;

	FD_SET( fd, &active_write_fd_set );
	fd_hash_add( &active_hash, fd );
	zs_update_fd_state( fd, NULL );
}
예제 #14
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
static void zs_internal_read( int fd, void* udata ) {
	zsocket_t* zs = zs_get_by_fd( fd );
	assert( zs->type == ZSOCK_CONNECT );

	if ( FL_ISSET( zs->connect.status, ZS_STAT_CONNECTED ) ) {

		if ( !FL_ARESOMESET( zs->connect.status, ZS_STAT_WANT_READ_FROM_READ | ZS_STAT_WANT_READ_FROM_WRITE ) ) {
			FL_SET( zs->connect.status, ZS_STAT_READING );
			FL_SET( zs->connect.status, ZS_STAT_WANT_READ_FROM_READ );
		}

		if ( FL_ISSET( zs->connect.status, ZS_STAT_WANT_READ_FROM_READ ) ) {
			// clear write_from_write, if read_from_write is not set clear fd select flag
			FL_CLR( zs->connect.status, ZS_STAT_WANT_READ_FROM_READ );
			zs_reader( fd, udata );
		}

		if ( FL_ISSET( zs->connect.status, ZS_STAT_WANT_READ_FROM_WRITE ) ) {
			// clear write_from_read, if read_from_read is not set and read is not set clear fd select flag
			FL_CLR( zs->connect.status, ZS_STAT_WANT_READ_FROM_WRITE );
			zs_writer( fd, udata );

			// zs_writer sometimes will call zs_close
			if ( !zs_get_by_fd( fd ) ) return;
		}

	} else if ( FL_ISSET( zs->connect.status, ZS_STAT_CONNECTING ) ) {
		FL_CLR( zs->connect.status, ZS_STAT_WANT_READ_FROM_CONNECT );
		zs_connecter( fd, udata );
	} else {
		FL_CLR( zs->connect.status, ZS_STAT_WANT_READ_FROM_ACCEPT );
		zs_accepter( fd, udata );

		// zs_accpeter sometimes will call zclose
		// if this happens we must return before
		// before zs_update_fd_state tries to use it
		if ( !zs_get_by_fd( fd ) ) return;
	}

	zs_update_fd_state( fd, udata );
}
예제 #15
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
void zs_clr_write( int fd ) {
	zsocket_t* zs = zs_get_by_fd( fd );
	assert( zs );

	if ( FD_ISSET( fd, &active_write_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
		n_selectable--;

	FD_CLR( fd, &active_write_fd_set );
	if ( !FD_ISSET( fd, &active_read_fd_set ) && !FD_ISSET( fd, &active_write_fd_set ) )
		fd_hash_remove( &active_hash, fd );
	if ( zs_get_by_fd( fd ) ) zs_update_fd_state( fd, NULL );
}
예제 #16
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
ssize_t zs_write( int fd, const void* buf, size_t nbyte ) {
	zsocket_t* zs = zs_get_by_fd( fd );

	if ( !zs || zs->type != ZSOCK_CONNECT || FL_ISSET( zs->general.status, ZS_STAT_CLOSED ) ) {
		errno = EBADF;
		fprintf( stderr, "%d: %d, bad\n", fd, zs->type );
		return -1;
	}

	if ( !FL_ISSET( zs->connect.status, ZS_STAT_WRITABLE ) ) {
		errno = EAGAIN;
		return -1;
	}

	assert( !zs->connect.write.buffer );

	if ( FD_ISSET( fd, &active_write_fd_set ) && FL_ISSET( zs->general.status, ZS_STAT_WRITABLE ) )
		n_selectable--;

	FL_CLR( zs->connect.status, ZS_STAT_WRITABLE );

	if ( zs->connect.write.rw_errno ) {
		errno = zs->connect.write.rw_errno || zs->connect.read.rw_errno;
		zs->connect.write.rw_errno = 0;
		nbyte = -1;
	} else {

		zs->connect.write.buffer = malloc( nbyte );
		memcpy( zs->connect.write.buffer, buf, nbyte );
		zs->connect.write.size = nbyte;
		zs->connect.write.used = nbyte;
		zs->connect.write.pos = 0;

		FL_SET( zs->connect.status, ZS_STAT_WRITING | ZS_STAT_WANT_WRITE_FROM_WRITE );
	}

	zs_update_fd_state( fd, NULL );

	return nbyte;
}
예제 #17
0
파일: zsocket.c 프로젝트: ianhalpern/zimr
int zs_close( int fd ) {
	zsocket_t* p = zsockets[ fd ];

	if ( !p ) {
		errno = EBADF;
		return -1;
	}

	if ( p->type == ZSOCK_LISTEN ) {
		p->listen.n_open--;

		if ( p->listen.n_open > 0 )
			return 0;
	} else {
		if ( FL_ISSET( p->general.status, ZS_STAT_WRITING ) ) {
			zs_clr_read( fd );
			zs_clr_write( fd );
			FL_SET( p->general.status, ZS_STAT_CLOSED );
			return 0;
		}
	}

	zfd_clr( fd, ZFD_R );
	zfd_clr( fd, ZFD_W );
	zs_clr_read( fd );
	zs_clr_write( fd );

	zsockets[ fd ] = NULL;

	if ( p->type == ZSOCK_LISTEN ) {
		close( p->listen.sockfd );
		if ( p->listen.ssl_ctx )
			SSL_CTX_free( p->listen.ssl_ctx );
	} else if ( p->type == ZSOCK_CONNECT ) {
		// Closing
		if ( p->connect.ssl )
			SSL_shutdown( p->connect.ssl );
		close( p->connect.sockfd );

		// Freeing
		free( p->connect.read.buffer );
		if ( p->connect.ssl )
			SSL_free( p->connect.ssl );
		if ( p->connect.write.buffer )
			free( p->connect.write.buffer );
	}

	free( p );

	return 0;
}
예제 #18
0
/*
 * ex_tag_push -- ^]
 *		  :tag[!] [string]
 *
 * Enter a new TAGQ context based on a ctag string.
 *
 * PUBLIC: int ex_tag_push __P((SCR *, EXCMD *));
 */
int
ex_tag_push(SCR *sp, EXCMD *cmdp)
{
	EX_PRIVATE *exp;
	TAGQ *tqp;
	unsigned long tl;

	exp = EXP(sp);
	switch (cmdp->argc) {
	case 1:
		if (exp->tag_last != NULL)
			free(exp->tag_last);

		if ((exp->tag_last = v_wstrdup(sp, cmdp->argv[0]->bp,
		    cmdp->argv[0]->len)) == NULL) {
			msgq(sp, M_SYSERR, NULL);
			return (1);
		}

		/* Taglength may limit the number of characters. */
		if ((tl =
		    O_VAL(sp, O_TAGLENGTH)) != 0 && STRLEN(exp->tag_last) > tl)
			exp->tag_last[tl] = '\0';
		break;
	case 0:
		if (exp->tag_last == NULL) {
			msgq(sp, M_ERR, "158|No previous tag entered");
			return (1);
		}
		break;
	default:
		abort();
	}

	/* Get the tag information. */
#ifdef GTAGS
	if (O_ISSET(sp, O_GTAGSMODE)) {
		if ((tqp = gtag_slist(sp, exp->tag_last,
		    F_ISSET(cmdp, E_REFERENCE))) == NULL)
			return (1);
	} else
#endif
	if ((tqp = ctag_slist(sp, exp->tag_last)) == NULL)
		return (1);

	if (tagq_push(sp, tqp, F_ISSET(cmdp, E_NEWSCREEN), 
			       FL_ISSET(cmdp->iflags, E_C_FORCE)))
		return 1;

	return 0;
}
예제 #19
0
파일: ex_yank.c 프로젝트: AgamAgarwal/minix
/*
 * ex_yank -- :[line [,line]] ya[nk] [buffer] [count]
 *	Yank the lines into a buffer.
 *
 * PUBLIC: int ex_yank __P((SCR *, EXCMD *));
 */
int
ex_yank(SCR *sp, EXCMD *cmdp)
{
	NEEDFILE(sp, cmdp);

	/*
	 * !!!
	 * Historically, yanking lines in ex didn't count toward the
	 * number-of-lines-yanked report.
	 */
	return (cut(sp,
	    FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL,
	    &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE));
}
예제 #20
0
파일: ex_quit.c 프로젝트: Alkzndr/freebsd
/*
 * ex_quit -- :quit[!]
 *	Quit.
 *
 * PUBLIC: int ex_quit __P((SCR *, EXCMD *));
 */
int
ex_quit(SCR *sp, EXCMD *cmdp)
{
	int force;

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

	/* Check for file modifications, or more files to edit. */
	if (file_m2(sp, force) || ex_ncheck(sp, force))
		return (1);

	F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
	return (0);
}
예제 #21
0
파일: ex_stop.c 프로젝트: fishman/nvi
/*
 * ex_stop -- :stop[!]
 *	      :suspend[!]
 *	Suspend execution.
 *
 * PUBLIC: int ex_stop __P((SCR *, EXCMD *));
 */
int
ex_stop(SCR *sp, EXCMD *cmdp)
{
	int allowed;

	/* For some strange reason, the force flag turns off autowrite. */
	if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && file_aw(sp, FS_ALL))
		return (1);

	if (sp->gp->scr_suspend(sp, &allowed))
		return (1);
	if (!allowed)
		ex_emsg(sp, NULL, EXM_NOSUSPEND);
	return (0);
}
예제 #22
0
파일: ex_put.c 프로젝트: Hooman3/minix
/*
 * ex_put -- [line] pu[t] [buffer]
 *	Append a cut buffer into the file.
 *
 * PUBLIC: int ex_put __P((SCR *, EXCMD *));
 */
int
ex_put(SCR *sp, EXCMD *cmdp)
{
	MARK m;

	NEEDFILE(sp, cmdp);

	m.lno = sp->lno;
	m.cno = sp->cno;
	if (put(sp, NULL,
	    FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL,
	    &cmdp->addr1, &m, 1))
		return (1);
	sp->lno = m.lno;
	sp->cno = m.cno;
	return (0);
}
예제 #23
0
/*
 * ex_wq --	:wq[!] [>>] [file]
 *	Write to a file and quit.
 *
 * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
 */
int
ex_wq(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);
}
예제 #24
0
/*
 * ex_xit -- :x[it]! [file]
 *	Write out any modifications and quit.
 *
 * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
 */
int
ex_xit(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);
}
예제 #25
0
파일: ex_screen.c 프로젝트: Hooman3/minix
/*
 * ex_resize --	:resize [+-]rows
 *	Change the screen size.
 *
 * PUBLIC: int ex_resize __P((SCR *, EXCMD *));
 */
int
ex_resize(SCR *sp, EXCMD *cmdp)
{
	adj_t adj;

	switch (FL_ISSET(cmdp->iflags,
	    E_C_COUNT | E_C_COUNT_NEG | E_C_COUNT_POS)) {
	case E_C_COUNT:
		adj = A_SET;
		break;
	case E_C_COUNT | E_C_COUNT_NEG:
		adj = A_DECREASE;
		break;
	case E_C_COUNT | E_C_COUNT_POS:
		adj = A_INCREASE;
		break;
	default:
		ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
		return (1);
	}
	return (vs_resize(sp, cmdp->count, adj));
}
예제 #26
0
파일: v_search.c 프로젝트: Hooman3/minix
/*
 * v_esearch -- <dialog box>
 *	Search command from the screen.
 *
 * PUBLIC: int v_esearch __P((SCR *, VICMD *));
 */
int
v_esearch(SCR *sp, VICMD *vp)
{
	int flags;

	LF_INIT(SEARCH_NOOPT);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_EXT))
		LF_SET(SEARCH_EXTEND);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_IC))
		LF_SET(SEARCH_IC);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_ICL))
		LF_SET(SEARCH_ICL);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_INCR))
		LF_SET(SEARCH_INCR);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_LIT))
		LF_SET(SEARCH_LITERAL);
	if (FL_ISSET(vp->ev.e_flags, VI_SEARCH_WR))
		LF_SET(SEARCH_WRAP);
	return (v_search(sp, vp, vp->ev.e_csp, vp->ev.e_len, flags,
	    FL_ISSET(vp->ev.e_flags, VI_SEARCH_REV) ? BACKWARD : FORWARD));
}
예제 #27
0
/*
 * ex_txt --
 *	Get lines from the terminal for ex.
 *
 * PUBLIC: int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t));
 */
int
ex_txt(SCR *sp, TEXTH *tiqh, ARG_CHAR_T prompt, u_int32_t flags)
{
	EVENT ev;
	GS *gp;
	TEXT ait, *ntp, *tp;
	carat_t carat_st;
	size_t cnt;
	int rval;

	rval = 0;

	/*
	 * Get a TEXT structure with some initial buffer space, reusing the
	 * last one if it's big enough.  (All TEXT bookkeeping fields default
	 * to 0 -- text_init() handles this.)
	 */
	if (tiqh->cqh_first != (void *)tiqh) {
		tp = tiqh->cqh_first;
		if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) {
			text_lfree(tiqh);
			goto newtp;
		}
		tp->len = 0;
	} else {
newtp:		if ((tp = text_init(sp, NULL, 0, 32)) == NULL)
			goto err;
		CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
	}

	/* Set the starting line number. */
	tp->lno = sp->lno + 1;

	/*
	 * If it's a terminal, set up autoindent, put out the prompt, and
	 * set it up so we know we were suspended.  Otherwise, turn off
	 * the autoindent flag, as that requires less special casing below.
	 *
	 * XXX
	 * Historic practice is that ^Z suspended command mode (but, because
	 * it ran in cooked mode, it was unaffected by the autowrite option.)
	 * On restart, any "current" input was discarded, whether in insert
	 * mode or not, and ex was in command mode.  This code matches historic
	 * practice, but not 'cause it's easier.
	 */
	gp = sp->gp;
	if (F_ISSET(gp, G_SCRIPTED))
		LF_CLR(TXT_AUTOINDENT);
	else {
		if (LF_ISSET(TXT_AUTOINDENT)) {
			LF_SET(TXT_EOFCHAR);
			if (v_txt_auto(sp, sp->lno, NULL, 0, tp))
				goto err;
		}
		txt_prompt(sp, tp, prompt, flags);
	}

	for (carat_st = C_NOTSET;;) {
		if (v_event_get(sp, &ev, 0, 0))
			goto err;

		/* Deal with all non-character events. */
		switch (ev.e_event) {
		case E_CHARACTER:
			break;
		case E_ERR:
			goto err;
		case E_REPAINT:
		case E_WRESIZE:
			continue;
		case E_EOF:
			rval = 1;
			/* FALLTHROUGH */
		case E_INTERRUPT:
			/*
			 * Handle EOF/SIGINT events by discarding partially
			 * entered text and returning.  EOF returns failure,
			 * E_INTERRUPT returns success.
			 */
			goto notlast;
		default:
			v_event_err(sp, &ev);
			goto notlast;
		}

		/*
		 * Deal with character events.
		 *
		 * Check to see if the character fits into the input buffer.
		 * (Use tp->len, ignore overwrite and non-printable chars.)
		 */
		BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1);

		switch (ev.e_value) {
		case K_CR:
			/*
			 * !!!
			 * Historically, <carriage-return>'s in the command
			 * weren't special, so the ex parser would return an
			 * unknown command error message.  However, if they
			 * terminated the command if they were in a map.  I'm
			 * pretty sure this still isn't right, but it handles
			 * what I've seen so far.
			 */
			if (!FL_ISSET(ev.e_flags, CH_MAPPED))
				goto ins_ch;
			/* FALLTHROUGH */
		case K_NL:
			/*
			 * '\' can escape <carriage-return>/<newline>.  We
			 * don't discard the backslash because we need it
			 * to get the <newline> through the ex parser.
			 */
			if (LF_ISSET(TXT_BACKSLASH) &&
			    tp->len != 0 && tp->lb[tp->len - 1] == '\\')
				goto ins_ch;

			/*
			 * CR returns from the ex command line.
			 *
			 * XXX
			 * Terminate with a nul, needed by filter.
			 */
			if (LF_ISSET(TXT_CR)) {
				tp->lb[tp->len] = '\0';
				goto done;
			}

			/*
			 * '.' may terminate text input mode; free the current
			 * TEXT.
			 */
			if (LF_ISSET(TXT_DOTTERM) && tp->len == tp->ai + 1 &&
			    tp->lb[tp->len - 1] == '.') {
notlast:			CIRCLEQ_REMOVE(tiqh, tp, q);
				text_free(tp);
				goto done;
			}

			/* Set up bookkeeping for the new line. */
			if ((ntp = text_init(sp, NULL, 0, 32)) == NULL)
				goto err;
			ntp->lno = tp->lno + 1;

			/*
			 * Reset the autoindent line value.  0^D keeps the ai
			 * line from changing, ^D changes the level, even if
			 * there were no characters in the old line.  Note, if
			 * using the current tp structure, use the cursor as
			 * the length, the autoindent characters may have been
			 * erased.
			 */
			if (LF_ISSET(TXT_AUTOINDENT)) {
				if (carat_st == C_NOCHANGE) {
					if (v_txt_auto(sp,
					    OOBLNO, &ait, ait.ai, ntp))
						goto err;
					free(ait.lb);
				} else
					if (v_txt_auto(sp,
					    OOBLNO, tp, tp->len, ntp))
						goto err;
				carat_st = C_NOTSET;
			}
			txt_prompt(sp, ntp, prompt, flags);

			/*
			 * Swap old and new TEXT's, and insert the new TEXT
			 * into the queue.
			 */
			tp = ntp;
			CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
			break;
		case K_CARAT:			/* Delete autoindent chars. */
			if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
				carat_st = C_CARATSET;
			goto ins_ch;
		case K_ZERO:			/* Delete autoindent chars. */
			if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT))
				carat_st = C_ZEROSET;
			goto ins_ch;
		case K_CNTRLD:			/* Delete autoindent char. */
			/*
			 * !!!
			 * Historically, the ^D command took (but then ignored)
			 * a count.  For simplicity, we don't return it unless
			 * it's the first character entered.  The check for len
			 * equal to 0 is okay, TXT_AUTOINDENT won't be set.
			 */
			if (LF_ISSET(TXT_CNTRLD)) {
				for (cnt = 0; cnt < tp->len; ++cnt)
					if (!isblank(tp->lb[cnt]))
						break;
				if (cnt == tp->len) {
					tp->len = 1;
					tp->lb[0] = ev.e_c;
					tp->lb[1] = '\0';

					/*
					 * Put out a line separator, in case
					 * the command fails.
					 */
					(void)putchar('\n');
					goto done;
				}
			}

			/*
			 * POSIX 1003.1b-1993, paragraph 7.1.1.9, states that
			 * the EOF characters are discarded if there are other
			 * characters to process in the line, i.e. if the EOF
			 * is not the first character in the line.  For this
			 * reason, historic ex discarded the EOF characters,
			 * even if occurring in the middle of the input line.
			 * We match that historic practice.
			 *
			 * !!!
			 * The test for discarding in the middle of the line is
			 * done in the switch, because the CARAT forms are N+1,
			 * not N.
			 *
			 * !!!
			 * There's considerable magic to make the terminal code
			 * return the EOF character at all.  See that code for
			 * details.
			 */
			if (!LF_ISSET(TXT_AUTOINDENT) || tp->len == 0)
				continue;
			switch (carat_st) {
			case C_CARATSET:		/* ^^D */
				if (tp->len > tp->ai + 1)
					continue;

				/* Save the ai string for later. */
				ait.lb = NULL;
				ait.lb_len = 0;
				BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai);
				MEMCPYW(ait.lb, tp->lb, tp->ai);
				ait.ai = ait.len = tp->ai;

				carat_st = C_NOCHANGE;
				goto leftmargin;
			case C_ZEROSET:			/* 0^D */
				if (tp->len > tp->ai + 1)
					continue;

				carat_st = C_NOTSET;
leftmargin:			(void)gp->scr_ex_adjust(sp, EX_TERM_CE);
				tp->ai = tp->len = 0;
				break;
			case C_NOTSET:			/* ^D */
				if (tp->len > tp->ai)
					continue;

				if (txt_dent(sp, tp))
					goto err;
				break;
			default:
				abort();
			}

			/* Clear and redisplay the line. */
			(void)gp->scr_ex_adjust(sp, EX_TERM_CE);
			txt_prompt(sp, tp, prompt, flags);
			break;
		default:
			/*
			 * See the TXT_BEAUTIFY comment in vi/v_txt_ev.c.
			 *
			 * Silently eliminate any iscntrl() character that was
			 * not already handled specially, except for <tab> and
			 * <ff>.
			 */
ins_ch:			if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(ev.e_c) &&
			    ev.e_value != K_FORMFEED && ev.e_value != K_TAB)
				break;

			tp->lb[tp->len++] = ev.e_c;
			break;
		}
	}
	/* NOTREACHED */

done:	return (rval);

err:	
alloc_err:
	return (1);
}
예제 #28
0
파일: ex_z.c 프로젝트: coyizumi/cs111
/*
 * ex_z -- :[line] z [^-.+=] [count] [flags]
 *	Adjust window.
 *
 * PUBLIC: int ex_z __P((SCR *, EXCMD *));
 */
int
ex_z(SCR *sp, EXCMD *cmdp)
{
    MARK abs;
    recno_t cnt, equals, lno;
    int eofcheck;

    NEEDFILE(sp, cmdp);

    /*
     * !!!
     * If no count specified, use either two times the size of the
     * scrolling region, or the size of the window option.  POSIX
     * 1003.2 claims that the latter is correct, but historic ex/vi
     * documentation and practice appear to use the scrolling region.
     * I'm using the window size as it means that the entire screen
     * is used instead of losing a line to roundoff.  Note, we drop
     * a line from the cnt if using the window size to leave room for
     * the next ex prompt.
     */
    if (FL_ISSET(cmdp->iflags, E_C_COUNT))
        cnt = cmdp->count;
    else
#ifdef HISTORICAL_PRACTICE
        cnt = O_VAL(sp, O_SCROLL) * 2;
#else
        cnt = O_VAL(sp, O_WINDOW) - 1;
#endif

    equals = 0;
    eofcheck = 0;
    lno = cmdp->addr1.lno;

    switch (FL_ISSET(cmdp->iflags,
                     E_C_CARAT | E_C_DASH | E_C_DOT | E_C_EQUAL | E_C_PLUS)) {
    case E_C_CARAT:		/* Display cnt * 2 before the line. */
        eofcheck = 1;
        if (lno > cnt * 2)
            cmdp->addr1.lno = (lno - cnt * 2) + 1;
        else
            cmdp->addr1.lno = 1;
        cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1;
        break;
    case E_C_DASH:		/* Line goes at the bottom of the screen. */
        cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1;
        cmdp->addr2.lno = lno;
        break;
    case E_C_DOT:		/* Line goes in the middle of the screen. */
        /*
         * !!!
         * Historically, the "middleness" of the line overrode the
         * count, so that "3z.19" or "3z.20" would display the first
         * 12 lines of the file, i.e. (N - 1) / 2 lines before and
         * after the specified line.
         */
        eofcheck = 1;
        cnt = (cnt - 1) / 2;
        cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
        cmdp->addr2.lno = lno + cnt;

        /*
         * !!!
         * Historically, z. set the absolute cursor mark.
         */
        abs.lno = sp->lno;
        abs.cno = sp->cno;
        (void)mark_set(sp, ABSMARK1, &abs, 1);
        break;
    case E_C_EQUAL:		/* Center with hyphens. */
        /*
         * !!!
         * Strangeness.  The '=' flag is like the '.' flag (see the
         * above comment, it applies here as well) but with a special
         * little hack.  Print out lines of hyphens before and after
         * the specified line.  Additionally, the cursor remains set
         * on that line.
         */
        eofcheck = 1;
        cnt = (cnt - 1) / 2;
        cmdp->addr1.lno = lno > cnt ? lno - cnt : 1;
        cmdp->addr2.lno = lno - 1;
        if (ex_pr(sp, cmdp))
            return (1);
        (void)ex_puts(sp, "----------------------------------------\n");
        cmdp->addr2.lno = cmdp->addr1.lno = equals = lno;
        if (ex_pr(sp, cmdp))
            return (1);
        (void)ex_puts(sp, "----------------------------------------\n");
        cmdp->addr1.lno = lno + 1;
        cmdp->addr2.lno = (lno + cnt) - 1;
        break;
    default:
        /* If no line specified, move to the next one. */
        if (F_ISSET(cmdp, E_ADDR_DEF))
            ++lno;
    /* FALLTHROUGH */
    case E_C_PLUS:		/* Line goes at the top of the screen. */
        eofcheck = 1;
        cmdp->addr1.lno = lno;
        cmdp->addr2.lno = (lno + cnt) - 1;
        break;
    }

    if (eofcheck) {
        if (db_last(sp, &lno))
            return (1);
        if (cmdp->addr2.lno > lno)
            cmdp->addr2.lno = lno;
    }

    if (ex_pr(sp, cmdp))
        return (1);
    if (equals)
        sp->lno = equals;
    return (0);
}
예제 #29
0
파일: ex_args.c 프로젝트: AgamAgarwal/minix
/*
 * ex_next -- :next [+cmd] [files]
 *	Edit the next file, optionally setting the list of files.
 *
 * !!!
 * The :next command behaved differently from the :rewind command in
 * historic vi.  See nvi/docs/autowrite for details, but the basic
 * idea was that it ignored the force flag if the autowrite flag was
 * set.  This implementation handles them all identically.
 *
 * PUBLIC: int ex_next __P((SCR *, EXCMD *));
 */
int
ex_next(SCR *sp, EXCMD *cmdp)
{
	ARGS **argv;
	FREF *frp;
	int noargs;
	char **ap;
	const CHAR_T *wp;
	size_t wlen;
	const char *np;
	size_t nlen;

	/* Check for file to move to. */
	if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) {
		msgq(sp, M_ERR, "111|No more files to edit");
		return (1);
	}

	if (F_ISSET(cmdp, E_NEWSCREEN)) {
		/* By default, edit the next file in the old argument list. */
		if (cmdp->argc == 0) {
			CHAR2INT(sp, sp->cargv[1], strlen(sp->cargv[1]) + 1,
					   wp, wlen);
			if (argv_exp0(sp, cmdp, wp, wlen - 1))
				return (1);
			return (ex_edit(sp, cmdp));
		}
		return (ex_N_next(sp, cmdp));
	}

	/* Check modification. */
	if (file_m1(sp,
	    FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE))
		return (1);

	/* Any arguments are a replacement file list. */
	if (cmdp->argc) {
		/* Free the current list. */
		if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) {
			for (ap = sp->argv; *ap != NULL; ++ap)
				free(*ap);
			free(sp->argv);
		}
		F_CLR(sp, SC_ARGNOFREE | SC_ARGRECOVER);
		sp->cargv = NULL;

		/* Create a new list. */
		CALLOC_RET(sp,
		    sp->argv, char **, cmdp->argc + 1, sizeof(char *));
		for (ap = sp->argv,
		    argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) {
			INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen);
			if ((*ap = v_strdup(sp, np, nlen)) == NULL)
				return (1);
		}
		*ap = NULL;

		/* Switch to the first file. */
		sp->cargv = sp->argv;
		if ((frp = file_add(sp, *sp->cargv)) == NULL)
			return (1);
		noargs = 0;

		/* Display a file count with the welcome message. */
		F_SET(sp, SC_STATUS_CNT);
	} else {
		if ((frp = file_add(sp, sp->cargv[1])) == NULL)
/*
 * ex_aci --
 *	Append, change, insert in ex.
 */
static int
ex_aci(SCR *sp, EXCMD *cmdp, enum which cmd)
{
	CHAR_T *p, *t;
	GS *gp;
	TEXT *tp;
	TEXTH tiq;
	db_recno_t cnt, lno;
	size_t len;
	u_int32_t flags;
	int need_newline;

	gp = sp->gp;
	NEEDFILE(sp, cmdp);

	/*
	 * If doing a change, replace lines for as long as possible.  Then,
	 * append more lines or delete remaining lines.  Changes to an empty
	 * file are appends, inserts are the same as appends to the previous
	 * line.
	 *
	 * !!!
	 * Set the address to which we'll append.  We set sp->lno to this
	 * address as well so that autoindent works correctly when get text
	 * from the user.
	 */
	lno = cmdp->addr1.lno;
	sp->lno = lno;
	if ((cmd == CHANGE || cmd == INSERT) && lno != 0)
		--lno;

	/*
	 * !!!
	 * If the file isn't empty, cut changes into the unnamed buffer.
	 */
	if (cmd == CHANGE && cmdp->addr1.lno != 0 &&
	    (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) ||
	    del(sp, &cmdp->addr1, &cmdp->addr2, 1)))
		return (1);

	/*
	 * !!!
	 * Anything that was left after the command separator becomes part
	 * of the inserted text.  Apparently, it was common usage to enter:
	 *
	 *	:g/pattern/append|stuff1
	 *
	 * and append the line of text "stuff1" to the lines containing the
	 * pattern.  It was also historically legal to enter:
	 *
	 *	:append|stuff1
	 *	stuff2
	 *	.
	 *
	 * and the text on the ex command line would be appended as well as
	 * the text inserted after it.  There was an historic bug however,
	 * that the user had to enter *two* terminating lines (the '.' lines)
	 * to terminate text input mode, in this case.  This whole thing
	 * could be taken too far, however.  Entering:
	 *
	 *	:append|stuff1\
	 *	stuff2
	 *	stuff3
	 *	.
	 *
	 * i.e. mixing and matching the forms confused the historic vi, and,
	 * not only did it take two terminating lines to terminate text input
	 * mode, but the trailing backslashes were retained on the input.  We
	 * match historic practice except that we discard the backslashes.
	 *
	 * Input lines specified on the ex command line lines are separated by
	 * <newline>s.  If there is a trailing delimiter an empty line was
	 * inserted.  There may also be a leading delimiter, which is ignored
	 * unless it's also a trailing delimiter.  It is possible to encounter
	 * a termination line, i.e. a single '.', in a global command, but not
	 * necessary if the text insert command was the last of the global
	 * commands.
	 */
	if (cmdp->save_cmdlen != 0) {
		for (p = cmdp->save_cmd,
		    len = cmdp->save_cmdlen; len > 0; p = t) {
			for (t = p; len > 0 && t[0] != '\n'; ++t, --len);
			if (t != p || len == 0) {
				if (F_ISSET(sp, SC_EX_GLOBAL) &&
				    t - p == 1 && p[0] == '.') {
					++t;
					if (len > 0)
						--len;
					break;
				}
				if (db_append(sp, 1, lno++, p, t - p))
					return (1);
			}
			if (len != 0) {
				++t;
				if (--len == 0 &&
				    db_append(sp, 1, lno++, NULL, 0))
					return (1);
			}
		}
		/*
		 * If there's any remaining text, we're in a global, and
		 * there's more command to parse.
		 *
		 * !!!
		 * We depend on the fact that non-global commands will eat the
		 * rest of the command line as text input, and before getting
		 * any text input from the user.  Otherwise, we'd have to save
		 * off the command text before or during the call to the text
		 * input function below.
		 */
		if (len != 0)
			cmdp->save_cmd = t;
		cmdp->save_cmdlen = len;
	}

	if (F_ISSET(sp, SC_EX_GLOBAL)) {
		if ((sp->lno = lno) == 0 && db_exist(sp, 1))
			sp->lno = 1;
		return (0);
	}

	/*
	 * If not in a global command, read from the terminal.
	 *
	 * If this code is called by vi, we want to reset the terminal and use
	 * ex's line get routine.  It actually works fine if we use vi's get
	 * routine, but it doesn't look as nice.  Maybe if we had a separate
	 * window or something, but getting a line at a time looks awkward.
	 * However, depending on the screen that we're using, that may not
	 * be possible.
	 */
	if (F_ISSET(sp, SC_VI)) {
		if (gp->scr_screen(sp, SC_EX)) {
			ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
			return (1);
		}

		/* If we're still in the vi screen, move out explicitly. */
		need_newline = !F_ISSET(sp, SC_SCR_EXWROTE);
		F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
		if (need_newline)
			(void)ex_puts(sp, "\n");

		/*
		 * !!!
		 * Users of historical versions of vi sometimes get confused
		 * when they enter append mode, and can't seem to get out of
		 * it.  Give them an informational message.
		 */
		(void)ex_puts(sp,
		    msg_cat(sp, "273|Entering ex input mode.", NULL));
		(void)ex_puts(sp, "\n");
		(void)ex_fflush(sp);
	}

	/*
	 * Set input flags; the ! flag turns off autoindent for append,
	 * change and insert.
	 */
	LF_INIT(TXT_DOTTERM | TXT_NUMBER);
	if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT))
		LF_SET(TXT_AUTOINDENT);
	if (O_ISSET(sp, O_BEAUTIFY))
		LF_SET(TXT_BEAUTIFY);

	/*
	 * This code can't use the common screen TEXTH structure (sp->tiq),
	 * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail
	 * as we are only halfway through the text when the append code fires.
	 * Use a local structure instead.  (The ex code would have to use a
	 * local structure except that we're guaranteed to finish remaining
	 * characters in the common TEXTH structure when they were inserted
	 * into the file, above.)
	 */
	memset(&tiq, 0, sizeof(TEXTH));
	TAILQ_INIT(&tiq);

	if (ex_txt(sp, &tiq, 0, flags))
		return (1);

	for (cnt = 0, tp = TAILQ_FIRST(&tiq); tp != NULL;
	    ++cnt, tp = TAILQ_NEXT(tp, q))
		if (db_append(sp, 1, lno++, tp->lb, tp->len))
			return (1);

	/*
	 * Set sp->lno to the final line number value (correcting for a
	 * possible 0 value) as that's historically correct for the final
	 * line value, whether or not the user entered any text.
	 */
	if ((sp->lno = lno) == 0 && db_exist(sp, 1))
		sp->lno = 1;

	return (0);
}