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

📄 input.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * input - nested input source file reader * * Copyright (C) 1999-2006  David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL.  You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. * * @(#) $Revision: 29.12 $ * @(#) $Id: input.c,v 29.12 2006/12/15 17:02:49 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/input.c,v $ * * Under source code control:	1990/02/15 01:48:16 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ *//* * Nested input source file reader. * For terminal input, this also provides a simple command stack. */#include <stdio.h>#include <ctype.h>#if !defined(_WIN32)# include <pwd.h>#endif#include <sys/types.h>#include <sys/stat.h>#include "have_unistd.h"#if defined(HAVE_UNISTD_H)#include <unistd.h>#endif#if defined(__MSDOS__)#include <limits.h>#define _fullpath(f,n,s) (_fixpath(n,f),f)#define _MAX_PATH PATH_MAX#endif#include "calc.h"#include "conf.h"#include "hist.h"extern int stdin_tty;		/* TRUE if stdin is a tty */extern FILE *f_open(char *name, char *mode);extern FILE *curstream(void);#define TTYSIZE		100	/* reallocation size for terminal buffers */#define MAXDEPTH		10	/* maximum depth of input */#define IS_READ		1	/* reading normally */#define IS_REREAD	2	/* reread current character */#define chartoint(ch)	((ch) & 0xff)	/* make sure char is not negative */#define READSET_ALLOC	8	/* readset to allocate chunk size */typedef struct {	int i_state;		/* state (read, reread) */	int i_char;		/* currently read char */	long i_line;		/* line number */	char *i_cp;		/* pointer to string character to be read */	char *i_str;		/* start of string copy to be read, or NULL */	long i_num;		/* number of string characters remaining */	char *i_ttystr;		/* current character of tty line (or NULL) */	FILE *i_fp;		/* current file for input (if not NULL) */	char *i_name;		/* file name if known */} INPUT;/* files that calc has read or included */typedef struct {	int active;		/* != 0 => active entry, 0 => unused entry */	char *name;		/* name used to read file */	char *path;		/* real path used to open file */	struct stat inode;	/* inode information for file */} READSET;static READSET *readset = NULL;		/* array of files read */static int maxreadset = 0;		/* length of readset */static int linesize;		/* current max size of input line */static char *linebuf;		/* current input line buffer */static char *prompt;		/* current prompt for terminal */static BOOL noprompt;		/* TRUE if should not print prompt */static int depth;		/* current input depth */static INPUT *cip;		/* current input source */static INPUT inputs[MAXDEPTH];	/* input sources */static int openfile(char *name);static int ttychar(void);static int isinoderead(struct stat *sbuf);static int findfreeread(void);static int addreadset(char *name, char *path, struct stat *sbuf);static char *homeexpand(char *name);/* * Open an input file by possibly searching through a path list * and also possibly applying the specified extension.	For example: * *	opensearchfile("barf", ".:/tmp", ".c", rd_once) * * searches in order for the files: * *	"./barf", "./barf.c", "/tmp/barf", and "/tmp/barf.c". * * Returns -1 if we could not open a file or error. * Returns 1 if file was opened and added to/updated in the readset * Returns 0 if file was already in the readset and reopen was 0. * * given: *	name		file name to be read *	pathlist	list of colon separated paths (or NULL) *	extension	extra extension to try (or NULL) *	rd_once		TRUE => do not reread a file */intopensearchfile(char *name, char *pathlist, char *extension, int rd_once){	int i;	char *cp;	char *path;		/* name being searched for */	struct stat statbuf;	/* stat of the path */	size_t namelen;	/* length of name */	size_t extlen;	/* length of the extension if non-NULL or 0 */	size_t pathlen;	/* length of the pathlist if non-NULL or 0 */	/* firewall */	if (name == NULL) {		math_error("NULL name given to opensearchfile");		/*NOTREACHED*/	}	/*	 * We ignore the pathlist of the file is absolute, dot-relative	 * or tilde-relative or if there is no search path.	 */	if (name[0] == PATHCHAR ||	    name[0] == HOMECHAR ||	    (name[0] == DOTCHAR && name[1] == '\0') ||	    (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == '\0') ||	    (name[0] == DOTCHAR && name[1] == PATHCHAR) ||	    (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == PATHCHAR) ||	    pathlist == NULL) {		pathlist = "";	}	/*	 * allocate storage for the longest name being searched for	 *	 * We will allocate more than we could ever want/need.	 * The longest we could ever need would be:	 *	 *	pathlist (as a single long string)	 *	/	 *	name	 *	.	 *	extension	 *	\0	 *	guard byte	 */	namelen = strlen(name);	if (extension != NULL) {	    extlen = strlen(extension);	} else {	    extlen = 0;	}	pathlen = strlen(pathlist);	path = malloc(pathlen+1 + 1 + namelen+1 + extlen+1 + 1 + 1);	if (path == NULL) {		math_error("Cannot allocate filename path buffer");		/*NOTREACHED*/	}	/*	 * Don't try the extension if the filename already contains it.	 */	if (extension != NULL && namelen >= extlen &&	    strcmp(&name[namelen-extlen], extension) == 0) {		extension = NULL;	}	/*	 * Search through the path list for the file	 */	pathlist--;	do {		pathlist++;		cp = path;		while (*pathlist && (*pathlist != LISTCHAR))			*cp++ = *pathlist++;		if (cp != path)			*cp++ = PATHCHAR;		strncpy(cp, name, namelen+1);		i = openfile(path);		if ((i < 0) &&		    (extension != NULL && extension[0] != '\0')) {			strcat(path, extension);			i = openfile(path);		}	} while ((i < 0) && *pathlist);	/* examine what our search produced */	if (i < 0) {		free(path);		return i;	}	if (cip->i_fp == NULL) {		/* cannot find a file to open */		free(path);		return -3;	}	if (fstat(fileno(cip->i_fp), &statbuf) < 0) {		/* unable to fstat the open file */		free(path);		return -4;	}	/* note if we will reopen a file and if that is allowed */	if (rd_once == TRUE && isinoderead(&statbuf) >= 0) {		/* file is in readset and reopen is false */		closeinput();		free(path);		return 1;	}	/* add this name to the readset if allowed */	if (addreadset(name, path, &statbuf) < 0) {		/* cannot add to readset */		closeinput();		free(path);		return -1;	}	/* file was added to/updated in readset */	free(path);	return 0;}/* * f_pathopen - open an absolute filename, or a relative filename along a search path * * Open a file by possibly searching through a path list.  For example: * *	f_pathopen("curds", ".:/tmp:~/pub", "r", NULL) * * searches in order for a file that it can open for reading: * *	"./curds", "/tmp/curds", "~/pub/curds" * * 	NOTE: ~ is expanded accordingly (see homeexpand() below). * * However is the file is /absolue/path/name or a ./dot/relative/name, or * a ~/home/dir/name, or a ~user/home/name, then the pathlist is ignored * we just attempt to open name. * * and opens the first one that exists and allows the mode. * *	name		file name to be read *	mode		fopen() mode argument (one of "r", "w", "a", "r+", "w+", "a+") *	pathlist	list of colon separated paths (or NULL) *	openpath	if non-NULL, and file was opened, set to malloced path used to open * * returns: *	open file stream, NULL ==> file was not found or error *	If file was open and openpath was non-NULL, changed to point to path used to open */FILE *f_pathopen(char *name, char *mode, char *pathlist, char **openpath){	char *cp;	char *path;		/* name being searched for */	size_t namelen;		/* length of name */	size_t pathlen;		/* length of the pathlist if non-NULL or 0 */	FILE *ret;		/* return open stream or NULL */	/* firewall */	if (name == NULL) {		math_error("NULL name given to f_pathopen");		/*NOTREACHED*/	}	if (mode == NULL) {		math_error("NULL mode given to f_pathopen");		/*NOTREACHED*/	}	/*	 * We ignore the pathlist of the file is absolute, dot-relative	 * or tilde-relative or if there is no search path.	 */	if (name[0] == PATHCHAR ||	    name[0] == HOMECHAR ||	    (name[0] == DOTCHAR && name[1] == '\0') ||	    (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == '\0') ||	    (name[0] == DOTCHAR && name[1] == PATHCHAR) ||	    (name[0] == DOTCHAR && name[1] == DOTCHAR && name[2] == PATHCHAR) ||	    pathlist == NULL) {		pathlist = "";	}	/*	 * allocate storage for the longest name being searched for	 *	 * We will allocate more than we could ever want/need.	 * The longest we could ever need would be:	 *	 *	pathlist (as a single long string)	 *	/	 *	name	 *	\0	 *	guard byte	 */	namelen = strlen(name);	pathlen = strlen(pathlist);	path = malloc(pathlen+1 + 1 + namelen+1 + 1 + 1);	if (path == NULL) {		math_error("Cannot allocate f_pathopen buffer");		/*NOTREACHED*/	}	/*	 * Search through the path list for the file	 */	pathlist--;	do {		pathlist++;		cp = path;		while (*pathlist && (*pathlist != LISTCHAR))			*cp++ = *pathlist++;		if (cp != path)			*cp++ = PATHCHAR;		strncpy(cp, name, namelen+1);		ret = f_open(path, mode);	} while ((ret == NULL) && *pathlist);	/* if caller wants to know the path, malloc it and return it */	if (openpath != NULL && ret != NULL) {		if (path[0] == HOMECHAR) {			*openpath = homeexpand(path);		} else {			*openpath = strdup(path);		}		if (*openpath == NULL) {			free(path);			fclose(ret);			math_error("cannot malloc return openpath buffer");			/*NOTREACHED*/		}	}	free(path);	/* return open file or NULL */	return ret;}/* * Given a filename with a leading ~, expand it into a home directory for * that user.  This function will malloc the space for the expanded path. * * If the path is just ~, or begins with ~/, expand it to the home * directory of the current user.  If the environment variable $HOME * is known, it will be used, otherwise the password file will be * consulted. * * If the path is just ~username, or ~username/, expand it to the home * directory of that user by looking it up in the password file. * * If the password file must be consulted and the username is not found * a NULL pointer is returned. * * given: *	name		a filename with a leading ~ */static char *homeexpand(char *name){#if defined(_WIN32)	return NULL;#else /* Windoz free systems */	struct passwd *ent;	/* password entry */	char *home2;		/* fullpath of the home directory */	char *fullpath;		/* the malloced expanded path */	char *after;		/* after the ~user or ~ */	char *username;		/* extracted username */	size_t fullpath_len;	/* length of fullpath */	/* firewall */	if (name[0] != HOMECHAR)		return NULL;	/*	 * obtain the home directory component	 */	switch (name[1]) {	case PATHCHAR:		/* ~/... */	case '\0':		/* ~ */		home2 = home;		after = name+1;		break;	default:		/* ~username or ~username/... */		/* extract the username after the ~ */		after = (char *)strchr(name+2, PATHCHAR);		if (after == NULL) {			/* path is just ~username */			ent = (struct passwd *)getpwnam(name+1);			if (ent == NULL) {				/* unknown user */				return NULL;			}			/* just malloc the home directory and return it */			fullpath_len = strlen(ent->pw_dir);			fullpath = (char *)malloc(fullpath_len+1);			if (fullpath == NULL) {				return NULL;			}			strncpy(fullpath, ent->pw_dir, fullpath_len+1);			return fullpath;		}		username = (char *) malloc(after-name + 1 + 1);		if (username == NULL) {			/* failed to malloc username */			return NULL;		}		strncpy(username, name+1, after-name-1);		username[after-name-1] = '\0';		/* get that user's home directory */		ent = (struct passwd *)getpwnam(username);		free(username);		if (ent == NULL) {			/* unknown user */			return NULL;		}		home2 = ent->pw_dir;		break;	}	/*	 * build the fullpath given the home directory	 */	fullpath = (char *)malloc(strlen(home2)+strlen(after)+1);	if (fullpath == NULL) {		return NULL;	}	sprintf(fullpath, "%s%s", home2, after);	return fullpath;#endif /* Windoz free systems */}/* * f_open - ~-expand a filename and fopen() it * * given: *	name		the filename to open *	mode		fopen() mode argument (one of "r", "w", "a", "r+", "w+", "a+") */FILE *f_open(char *name, char *mode){	FILE *fp;		/* open file descriptor */	char *fullname;		/* file name with HOMECHAR expansion */	/*	 * be sore we are allowed to open a file in this mode	 */	if (!allow_read && !allow_write) {		/* no reads and no writes means no opens! */		if (run_state > RUN_BEGIN) {			fprintf(stderr,				"open of %s mode %s - %s\n", name, mode,				"open for read or write disallowed by -m\n");		}		return NULL;	} else if (!allow_read && strchr(mode, 'r') != NULL) {		/* reading new files disallowed */		if (run_state > RUN_BEGIN) {			fprintf(stderr,				"open of %s mode %s - %s\n", name, mode,				"open for read disallowed by -m\n");		}		return NULL;	} else if (!allow_write &&		   (strchr(mode, 'w') != NULL ||		    strchr(mode, 'a') != NULL ||		    strchr(mode, '+') != NULL)) {		/* writing new files disallowed */		if (run_state > RUN_BEGIN) {			fprintf(stderr,				"open of %s mode %s - %s\n", name, mode,				"open for write disallowed by -m\n");		}		return NULL;	}	/*	 * expand ~ if needed	 */	if (name[0] == HOMECHAR) {		fullname = homeexpand(name);		if (fullname == NULL)			return NULL;		fp = fopen(fullname, mode);		free(fullname);	} else {		fp = fopen(name, mode);	}	return fp;}/* * Setup for reading from a input file. * Returns -1 if file could not be opened. * * given: *	name		file name to be read */static intopenfile(char *name){	FILE *fp;		/* open file descriptor */	size_t namelen;	if (depth >= MAXDEPTH)		 return -2;	fp = f_open(name, "r");	if (fp == NULL)		 return -1;	cip = inputs + depth++;	cip->i_state = IS_READ;	cip->i_char = '\0';	cip->i_str = NULL;	cip->i_ttystr = NULL;	cip->i_fp = fp;	cip->i_line = 1;	namelen = strlen(name);	cip->i_name = (char *)malloc(namelen+1);	if (cip->i_name == NULL) {		 return -1;	}	strncpy(cip->i_name, name, namelen+1);

⌨️ 快捷键说明

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