⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exf.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	/*	 * Close the previous file; if that fails, close the new one	 * and run for the border.	 */	if (sp->ep != NULL && file_end(sp, sp->ep, force)) {		(void)file_end(sp, ep, 1);		goto err;	}	/*	 * 4.4BSD supports locking in the open call, other systems don't.	 * Since the user can't interrupt us between the open and here,	 * it's a don't care.	 *	 * !!!	 * We need to distinguish a lock not being available for the file	 * from the file system not supporting locking.  Assume that EAGAIN	 * or EWOULDBLOCK is the former.  There isn't a portable way to do	 * this.	 *	 * XXX	 * The locking is flock(2) style, not fcntl(2).  The latter is known	 * to fail badly on some systems, and its only advantage is that it	 * occasionally works over NFS.	 */	if (flock(ep->db->fd(ep->db), LOCK_EX | LOCK_NB))		if (errno == EAGAIN || errno == EWOULDBLOCK) {			msgq(sp, M_INFO,			    "%s already locked, session is read-only", oname);			F_SET(frp, FR_RDONLY);		} else			msgq(sp, M_VINFO, "%s cannot be locked", oname);	/*	 * Set the previous file pointer and the alternate file name to be	 * the file we're about to discard.	 *	 * !!!	 * If the current file was a temporary file, the call to file_end()	 * unlinked it and free'd the name.  So, there is no previous file,	 * and there is no alternate file name.  This matches historical	 * practice, although in historical vi it could only happen as the	 * result of the initial command, i.e. if vi was execute without a	 * file name.	 */	if (sp->frp != NULL) {		p = FILENAME(sp->frp);		if (p == NULL)			sp->p_frp = NULL;		else			sp->p_frp = sp->frp;		set_alt_name(sp, p);	}	/* The new file has now been officially edited. */	F_SET(frp, FR_EDITED);	/* Switch... */	++ep->refcnt;	sp->ep = ep;	sp->frp = frp;	return (0);err:	if (frp->tname != NULL) {		(void)unlink(frp->tname);		free(frp->tname);		frp->tname = NULL;	}	if (ep->rcv_path != NULL) {		free(ep->rcv_path);		ep->rcv_path = NULL;	}	FREE(ep, sizeof(EXF));	return (1);}/* * file_end -- *	Stop editing a file. */intfile_end(sp, ep, force)	SCR *sp;	EXF *ep;	int force;{	FREF *frp;	/*	 *	 * sp->ep MAY NOT BE THE SAME AS THE ARGUMENT ep, SO DON'T USE IT!	 *	 * Save the cursor location.	 *	 * XXX	 * It would be cleaner to do this somewhere else, but by the time	 * ex or vi knows that we're changing files it's already happened.	 */	frp = sp->frp;	frp->lno = sp->lno;	frp->cno = sp->cno;	F_SET(frp, FR_CURSORSET);	/* If multiply referenced, just decrement the count and return. */	if (--ep->refcnt != 0)		return (0);	/* Close the db structure. */	if (ep->db->close != NULL && ep->db->close(ep->db) && !force) {		msgq(sp, M_ERR,		    "%s: close: %s", FILENAME(frp), strerror(errno));		++ep->refcnt;		return (1);	}	/* COMMITTED TO THE CLOSE.  THERE'S NO GOING BACK... */	/* Stop logging. */	(void)log_end(sp, ep);	/* Free up any marks. */	mark_end(sp, ep);	/*	 * Delete the recovery files, close the open descriptor,	 * free recovery memory.	 */	if (!F_ISSET(ep, F_RCV_NORM)) {		if (ep->rcv_path != NULL && unlink(ep->rcv_path))			msgq(sp, M_ERR,			    "%s: remove: %s", ep->rcv_path, strerror(errno));		if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))			msgq(sp, M_ERR,			    "%s: remove: %s", ep->rcv_mpath, strerror(errno));	}	if (ep->rcv_fd != -1)		(void)close(ep->rcv_fd);	if (ep->rcv_path != NULL)		free(ep->rcv_path);	if (ep->rcv_mpath != NULL)		free(ep->rcv_mpath);	/*	 * Unlink any temporary file, file name.  We also turn on the	 * ignore bit at this point, because it was a "created" file,	 * not an argument file.	 */	if (frp->tname != NULL) {		if (unlink(frp->tname))			msgq(sp, M_ERR,			    "%s: remove: %s", frp->tname, strerror(errno));		free(frp->tname);		frp->tname = NULL;		if (frp->name == NULL && frp->cname == NULL)			F_SET(frp, FR_IGNORE);	}	/* Free the EXF structure. */	FREE(ep, sizeof(EXF));	return (0);}/* * file_write -- *	Write the file to disk.  Historic vi had fairly convoluted *	semantics for whether or not writes would happen.  That's *	why all the flags. */intfile_write(sp, ep, fm, tm, name, flags)	SCR *sp;	EXF *ep;	MARK *fm, *tm;	char *name;	int flags;{	struct stat sb;	FILE *fp;	FREF *frp;	MARK from, to;	u_long nlno, nch;	int btear, fd, itear, oflags, rval;	char *msg;	/*	 * Don't permit writing to temporary files.  The problem is that	 * if it's a temp file, and the user does ":wq", we write and quit,	 * unlinking the temporary file.  Not what the user had in mind	 * at all.  This test cannot be forced.	 */	frp = sp->frp;	if (name == NULL && frp->cname == NULL && frp->name == NULL) {		msgq(sp, M_ERR, "No filename to which to write.");		return (1);	}	/* Can't write files marked read-only, unless forced. */	if (!LF_ISSET(FS_FORCE) &&	    name == NULL && F_ISSET(frp, FR_RDONLY)) {		if (LF_ISSET(FS_POSSIBLE))			msgq(sp, M_ERR,			    "Read-only file, not written; use ! to override.");		else			msgq(sp, M_ERR,			    "Read-only file, not written.");		return (1);	}	/* If not forced, not appending, and "writeany" not set ... */	if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) {		/* Don't overwrite anything but the original file. */		if (name != NULL) {			if (!stat(name, &sb))				goto exists;		} else if (frp->cname != NULL &&		    !F_ISSET(frp, FR_CHANGEWRITE) && !stat(frp->cname, &sb)) {			name = frp->cname;exists:			if (LF_ISSET(FS_POSSIBLE))				msgq(sp, M_ERR,		"%s exists, not written; use ! to override.", name);			else				msgq(sp, M_ERR,				    "%s exists, not written.", name);			return (1);		}		/*		 * Don't write part of any existing file.  Only test for the		 * original file, the previous test catches anything else.		 */		if (!LF_ISSET(FS_ALL) && name == NULL &&		    frp->cname == NULL && !stat(frp->name, &sb)) {			if (LF_ISSET(FS_POSSIBLE))				msgq(sp, M_ERR,				    "Use ! to write a partial file.");			else				msgq(sp, M_ERR, "Partial file, not written.");			return (1);		}	}	/*	 * Figure out if the file already exists -- if it doesn't, we display	 * the "new file" message.  The stat might not be necessary, but we	 * just repeat it because it's easier than hacking the previous tests.	 * The information is only used for the user message and modification	 * time test, so we can ignore the obvious race condition.	 *	 * If the user is overwriting a file other than the original file, and	 * O_WRITEANY was what got us here (neither force nor append was set),	 * display the "existing file" messsage.  Since the FR_CHANGEWRITE flag	 * is set on a successful write, the message only appears once when the	 * user changes a file name.  This is historic practice.	 *	 * One final test.  If we're not forcing or appending, and we have a	 * saved modification time, stop the user if it's been written since	 * we last edited or wrote it, and make them force it.	 */	if (stat(name == NULL ? FILENAME(frp) : name, &sb))		msg = ": new file";	else {		msg = "";		if (!LF_ISSET(FS_FORCE | FS_APPEND)) {			if (frp->mtime && sb.st_mtime > frp->mtime) {				msgq(sp, M_ERR,			"%s: file modified more recently than this copy%s.",				    name == NULL ? frp->name : name,				    LF_ISSET(FS_POSSIBLE) ?				    "; use ! to override" : "");				return (1);			}			if (name != NULL ||			    !F_ISSET(frp, FR_CHANGEWRITE) && frp->cname != NULL)				msg = ": existing file";		}	}	/* We no longer care where the name came from. */	if (name == NULL)		name = FILENAME(frp);	/* Set flags to either append or truncate. */	oflags = O_CREAT | O_WRONLY;	if (LF_ISSET(FS_APPEND))		oflags |= O_APPEND;	else		oflags |= O_TRUNC;	/* Open the file. */	if ((fd = open(name, oflags, DEFFILEMODE)) < 0) {		msgq(sp, M_SYSERR, name);		return (1);	}	/* Use stdio for buffering. */	if ((fp = fdopen(fd, "w")) == NULL) {		(void)close(fd);		msgq(sp, M_SYSERR, name);		return (1);	}	/* Build fake addresses, if necessary. */	if (fm == NULL) {		from.lno = 1;		from.cno = 0;		fm = &from;		if (file_lline(sp, ep, &to.lno))			return (1);		to.cno = 0;		tm = &to;	}	/* Write the file, allowing interrupts. */	btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Writing...");	itear = !intr_init(sp);	rval = ex_writefp(sp, ep, name, fp, fm, tm, &nlno, &nch);	if (btear)		busy_off(sp);	if (itear)		intr_end(sp);	/*	 * Save the new last modification time -- even if the write fails	 * we re-init the time.  That way the user can clean up the disk	 * and rewrite without having to force it.	 */	frp->mtime = stat(name, &sb) ? 0 : sb.st_mtime;	/* If the write failed, complain loudly. */	if (rval) {		if (!LF_ISSET(FS_APPEND))			msgq(sp, M_ERR, "%s: WARNING: file truncated!", name);		return (1);	}	/*	 * Once we've actually written the file, it doesn't matter that the	 * file name was changed -- if it was, we've already whacked it.	 */	F_SET(frp, FR_CHANGEWRITE);	/* If wrote the entire file, clear the modified bit. */	if (LF_ISSET(FS_ALL))		F_CLR(ep, F_MODIFIED);	msgq(sp, M_INFO, "%s%s: %lu line%s, %lu characters.",	    name, msg, nlno, nlno == 1 ? "" : "s", nch);	return (0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -