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

📄 exf.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992, 1993 *	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 lintstatic char sccsid[] = "@(#)exf.c	8.72 (Berkeley) 3/25/94";#endif /* not lint */#include <sys/param.h>#include <sys/queue.h>#include <sys/stat.h>#include <sys/time.h>/* * We include <sys/file.h>, because the flock(2) #defines were * found there on historical systems.  We also include <fcntl.h> * because the open(2) #defines are found there on newer systems. */#include <sys/file.h>#include <bitstring.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <db.h>#include <regex.h>#include <pathnames.h>#include "vi.h"#include "excmd.h"/* * file_add -- *	Insert a file name into the FREF list, if it doesn't already *	appear in it. * * !!! * The "if it doesn't already appear" changes vi's semantics slightly.  If * you do a "vi foo bar", and then execute "next bar baz", the edit of bar * will reflect the line/column of the previous edit session.  Historic nvi * did not do this.  The change is a logical extension of the change where * vi now remembers the last location in any file that it has ever edited, * not just the previously edited file. */FREF *file_add(sp, frp_append, name, ignore)	SCR *sp;	FREF *frp_append;	CHAR_T *name;	int ignore;{	FREF *frp;	char *p;	/*	 * Return it if it already exists.  Note that we test against the	 * user's current name, whatever that happens to be, including if	 * it's a temporary file.  If the user is trying to set an argument	 * list, the ignore argument will be on -- if we're ignoring the	 * file turn off the ignore bit, so it's back in the argument list.	 */	if (name != NULL)		for (frp = sp->frefq.cqh_first;		    frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)			if ((p = FILENAME(frp)) != NULL && !strcmp(p, name)) {				if (!ignore)					F_CLR(frp, FR_IGNORE);				return (frp);			}	/* Allocate and initialize the FREF structure. */	CALLOC(sp, frp, FREF *, 1, sizeof(FREF));	if (frp == NULL)		return (NULL);	/*	 * If no file name specified, or if the file name is a request	 * for something temporary, file_init() will allocate the file	 * name.  Temporary files are always ignored.	 */#define	TEMPORARY_FILE_STRING	"/tmp"	if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) &&	    (frp->name = strdup(name)) == NULL) {		FREE(frp, sizeof(FREF));		msgq(sp, M_SYSERR, NULL);		return (NULL);	}	/* Only the initial argument list is "remembered". */	if (ignore)		F_SET(frp, FR_IGNORE);	/* Append into the chain of file names. */	if (frp_append != NULL) {		CIRCLEQ_INSERT_AFTER(&sp->frefq, frp_append, frp, q);	} else		CIRCLEQ_INSERT_TAIL(&sp->frefq, frp, q);	return (frp);}/* * file_first -- *	Return the first file name for editing, if any. */FREF *file_first(sp)	SCR *sp;{	FREF *frp;	/* Return the first file name. */	for (frp = sp->frefq.cqh_first;	    frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)		if (!F_ISSET(frp, FR_IGNORE))			return (frp);	return (NULL);}/* * file_next -- *	Return the next file name, if any. */FREF *file_next(sp, frp)	SCR *sp;	FREF *frp;{	while ((frp = frp->q.cqe_next) != (FREF *)&sp->frefq)		if (!F_ISSET(frp, FR_IGNORE))			return (frp);	return (NULL);}/* * file_prev -- *	Return the previous file name, if any. */FREF *file_prev(sp, frp)	SCR *sp;	FREF *frp;{	while ((frp = frp->q.cqe_prev) != (FREF *)&sp->frefq)		if (!F_ISSET(frp, FR_IGNORE))			return (frp);	return (NULL);}/* * file_unedited -- *	Return if there are files that aren't ignored and are unedited. */FREF *file_unedited(sp)	SCR *sp;{	FREF *frp;	/* Return the next file name. */	for (frp = sp->frefq.cqh_first;	    frp != (FREF *)&sp->frefq; frp = frp->q.cqe_next)		if (!F_ISSET(frp, FR_EDITED | FR_IGNORE))			return (frp);	return (NULL);}/* * file_init -- *	Start editing a file, based on the FREF structure.  If successsful, *	let go of any previous file.  Don't release the previous file until *	absolutely sure we have the new one. */intfile_init(sp, frp, rcv_name, force)	SCR *sp;	FREF *frp;	char *rcv_name;	int force;{	EXF *ep;	RECNOINFO oinfo;	struct stat sb;	size_t psize;	int fd;	char *p, *oname, tname[MAXPATHLEN];	/*	 * Required ep initialization:	 *	Flush the line caches.	 *	Default recover mail file fd to -1.	 *	Set initial EXF flag bits.	 */	CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));	ep->c_lno = ep->c_nlines = OOBLNO;	ep->rcv_fd = -1;	LIST_INIT(&ep->marks);	F_SET(ep, F_FIRSTMODIFY);	/*	 * If no name or backing file, create a backing temporary file, saving	 * the temp file name so can later unlink it.  Repoint the name to the	 * temporary name (we display it to the user until they rename it).	 * There are some games we play with the FR_FREE_TNAME and FR_NONAME	 * flags (see ex/ex_file.c) to make sure that the temporary memory gets	 * free'd up.	 */	if ((oname = FILENAME(frp)) == NULL || stat(oname, &sb)) {		(void)snprintf(tname, sizeof(tname),		    "%s/vi.XXXXXX", O_STR(sp, O_DIRECTORY));		if ((fd = mkstemp(tname)) == -1) {			msgq(sp, M_SYSERR, "Temporary file");			goto err;		}		(void)close(fd);		if ((frp->tname = strdup(tname)) == NULL) {			msgq(sp, M_SYSERR, NULL);			(void)unlink(tname);			goto err;		}		oname = frp->tname;		psize = 4 * 1024;		F_SET(frp, FR_NEWFILE);	} else {		/* Try to keep it at 10 pages or less per file. */		if (sb.st_size < 40 * 1024)			psize = 4 * 1024;		else if (sb.st_size < 320 * 1024)			psize = 32 * 1024;		else			psize = 64 * 1024;		frp->mtime = sb.st_mtime;		if (!S_ISREG(sb.st_mode))			msgq(sp, M_ERR,			    "Warning: %s is not a regular file.", oname);	}	/* Set up recovery. */	memset(&oinfo, 0, sizeof(RECNOINFO));	oinfo.bval = '\n';			/* Always set. */	oinfo.psize = psize;	oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0;	if (rcv_name == NULL) {		if (!rcv_tmp(sp, ep, FILENAME(frp)))			oinfo.bfname = ep->rcv_path;	} else {		if ((ep->rcv_path = strdup(rcv_name)) == NULL) {			msgq(sp, M_SYSERR, NULL);			goto err;		}		oinfo.bfname = ep->rcv_path;		F_SET(ep, F_MODIFIED);	}	/* Open a db structure. */	if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL,	    O_NONBLOCK | O_RDONLY, DEFFILEMODE, DB_RECNO, &oinfo)) == NULL) {		msgq(sp, M_SYSERR, rcv_name == NULL ? oname : rcv_name);		goto err;	}	/* Init file marks. */	if (mark_init(sp, ep))		goto err;	/* Start logging. */	if (log_init(sp, ep))		goto err;	/*	 * The -R flag, or doing a "set readonly" during a session causes	 * all files edited during the session (using an edit command, or	 * even using tags) to be marked read-only.  Changing the file name	 * (see ex/ex_file.c), clears this flag.	 *	 * Otherwise, try and figure out if a file is readonly.  This is a	 * dangerous thing to do.  The kernel is the only arbiter of whether	 * or not a file is writeable, and the best that a user program can	 * do is guess.  Obvious loopholes are files that are on a file system	 * mounted readonly (access catches this one on a few systems), or	 * alternate protection mechanisms, ACL's for example, that we can't	 * portably check.  Lots of fun, and only here because users whined.	 *	 * !!!	 * Historic vi displayed the readonly message if none of the file	 * write bits were set, or if an an access(2) call on the path	 * failed.  This seems reasonable.  If the file is mode 444, root	 * users may want to know that the owner of the file did not expect	 * it to be written.	 *	 * Historic vi set the readonly bit if no write bits were set for	 * a file, even if the access call would have succeeded.  This makes	 * the superuser force the write even when vi expects that it will	 * succeed.  I'm less supportive of this semantic, but it's historic	 * practice and the conservative approach to vi'ing files as root.	 *	 * It would be nice if there was some way to update this when the user	 * does a "^Z; chmod ...".  The problem is that we'd first have to	 * distinguish between readonly bits set because of file permissions	 * and those set for other reasons.  That's not too hard, but deciding	 * when to reevaluate the permissions is trickier.  An alternative	 * might be to turn off the readonly bit if the user forces a write	 * and it succeeds.	 *	 * XXX	 * Access(2) doesn't consider the effective uid/gid values.  This	 * probably isn't a problem for vi when it's running standalone.	 */	if (O_ISSET(sp, O_READONLY) || !F_ISSET(frp, FR_NEWFILE) &&	    (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||	    access(FILENAME(frp), W_OK)))		F_SET(frp, FR_RDONLY);	else		F_CLR(frp, FR_RDONLY);

⌨️ 快捷键说明

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