ejslib.c

来自「samba最新软件」· C语言 代码 · 共 1,091 行 · 第 1/2 页

C
1,091
字号
/* *	@file 	ejs.c *	@brief 	Embedded JavaScript (EJS)  *	@overview Main module interface logic. *//********************************* Copyright **********************************//* *	@copy	default.g *	 *	Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. *	Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved. *	 *	This software is distributed under commercial and open source licenses. *	You may use the GPL open source license described below or you may acquire  *	a commercial license from Mbedthis Software. You agree to be fully bound  *	by the terms of either license. Consult the LICENSE.TXT distributed with  *	this software for full details. *	 *	This software is open source; you can redistribute it and/or modify it  *	under the terms of the GNU General Public License as published by the  *	Free Software Foundation; either version 2 of the License, or (at your  *	option) any later version. See the GNU General Public License for more  *	details at: http://www.mbedthis.com/downloads/gplLicense.html *	 *	This program is distributed WITHOUT ANY WARRANTY; without even the  *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  *	 *	This GPL license does NOT permit incorporating this software into  *	proprietary programs. If you are unable to comply with the GPL, you must *	acquire a commercial license to use this software. Commercial licenses  *	for this software and support services are available from Mbedthis  *	Software at http://www.mbedthis.com  *	 *	@end *//********************************** Includes **********************************/#include	"ejsInternal.h"#if BLD_FEATURE_EJS/********************************** Local Data ********************************//* *	These fields must be locked before any access when multithreaded */static MprVar	master;					/* Master object */static MprArray	*ejsList;				/* List of ej handles */#if BLD_FEATURE_MULTITHREADstatic EjsLock		lock;static EjsUnlock	unlock;static void			*lockData;#define ejsLock()	if (lock) { (lock)(lockData); } else#define ejsUnlock()	if (unlock) { (unlock)(lockData); } else#else#define ejsLock()		#define ejsUnlock()	#endif/*  save/restore global ejs state - used to cope with simultaneous ejs requests  this is a workaround for the use of global variables in ejs*/struct ejs_state_ctx {	MprVar master;	MprArray *ejsList;};void *ejs_save_state(void){	struct ejs_state_ctx *ctx = talloc(talloc_autofree_context(), struct ejs_state_ctx);	ctx->master = master;	ctx->ejsList = ejsList;	return ctx;}void ejs_restore_state(void *ptr){	struct ejs_state_ctx *ctx = talloc_get_type(ptr, struct ejs_state_ctx);	master = ctx->master;	ejsList = ctx->ejsList;	talloc_free(ctx);}/****************************** Forward Declarations **************************/static char	*getNextVarToken(char **next, char *tokBuf, int tokBufLen);/************************************* Code ***********************************//* *	Initialize the EJ subsystem */int ejsOpen(EjsLock lockFn, EjsUnlock unlockFn, void *data){	MprVar	*np;#if BLD_FEATURE_MULTITHREAD	if (lockFn) {		lock = lockFn;		unlock = unlockFn;		lockData = data;	}#endif	ejsLock();	/*	 *	Master is the top level object (above global). It is used to clone its	 *	contents into the global scope for each. This is never visible to the	 *	user, so don't use ejsCreateObj().	 */	master = mprCreateObjVar("master", EJS_SMALL_OBJ_HASH_SIZE);	if (master.type == MPR_TYPE_UNDEFINED) {		ejsUnlock();		return MPR_ERR_CANT_ALLOCATE;	}	ejsList = mprCreateArray();	ejsDefineStandardProperties(&master);	/*	 *	Make these objects immutable	 */	np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);	while (np) {		mprSetVarReadonly(np, 1);		np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS | 			MPR_ENUM_DATA);	}	ejsUnlock();	return 0;}/******************************************************************************/void ejsClose(){	ejsLock();	mprDestroyArray(ejsList);	mprDestroyVar(&master);	ejsUnlock();}/******************************************************************************//* *	Create and initialize an EJS engine */EjsId ejsOpenEngine(EjsHandle primaryHandle, EjsHandle altHandle){	MprVar	*np;	Ejs		*ep;	ep = (Ejs *)mprMalloc(sizeof(Ejs));	if (ep == 0) {		return (EjsId) -1;	}	memset(ep, 0, sizeof(Ejs));	ejsLock();	ep->eid = (EjsId) mprAddToArray(ejsList, ep);	ejsUnlock();	/*	 *	Create array of local variable frames	 */	ep->frames = mprCreateArray();	if (ep->frames == 0) {		ejsCloseEngine(ep->eid);		return (EjsId) -1;	}	ep->primaryHandle = primaryHandle;	ep->altHandle = altHandle;	/*	 *	Create first frame: global variables	 */	ep->global = (MprVar*) mprMalloc(sizeof(MprVar));	*ep->global = ejsCreateObj("global", EJS_OBJ_HASH_SIZE);	if (ep->global->type == MPR_TYPE_UNDEFINED) {		ejsCloseEngine(ep->eid);		return (EjsId) -1;	}	mprAddToArray(ep->frames, ep->global);	/*	 *	Create first local variable frame	 */	ep->local = (MprVar*) mprMalloc(sizeof(MprVar));	*ep->local = ejsCreateObj("local", EJS_OBJ_HASH_SIZE);	if (ep->local->type == MPR_TYPE_UNDEFINED) {		ejsCloseEngine(ep->eid);		return (EjsId) -1;	}	mprAddToArray(ep->frames, ep->local);	/*	 *	Clone all master variables into the global frame. This does a	 *	reference copy.	 *	 *		ejsDefineStandardProperties(ep->global);	 */	np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);	while (np) {		mprCreateProperty(ep->global, np->name, np);		np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS | 			MPR_ENUM_DATA);	}	mprCreateProperty(ep->global, "global", ep->global);	mprCreateProperty(ep->global, "this", ep->global);	mprCreateProperty(ep->local, "local", ep->local);	return ep->eid;}/******************************************************************************//* *	Close an EJS instance */void ejsCloseEngine(EjsId eid){	Ejs		*ep;	MprVar	*vp;	void	**handles;	int		i;	if ((ep = ejsPtr(eid)) == NULL) {		mprAssert(ep);		return;	}	mprFree(ep->error);	mprDestroyVar(&ep->result);	mprDestroyVar(&ep->tokenNumber);	if (ep->local) {		mprDeleteProperty(ep->local, "local");	}	mprDeleteProperty(ep->global, "this");	mprDeleteProperty(ep->global, "global");	handles = ep->frames->handles;	for (i = 0; i < ep->frames->max; i++) {		vp = handles[i];		if (vp) {#if BLD_DEBUG			if (vp->type == MPR_TYPE_OBJECT && vp->properties->refCount > 1) {				mprLog(7, "ejsCloseEngine: %s has ref count %d\n",					vp->name, vp->properties->refCount);			}#endif			mprDestroyVar(vp);			mprFree(vp);			mprRemoveFromArray(ep->frames, i);		}	}	mprDestroyArray(ep->frames);	ejsLock();	mprRemoveFromArray(ejsList, (int) ep->eid);	ejsUnlock();	mprFree(ep);}/******************************************************************************//* *	Evaluate an EJS script file */int ejsEvalFile(EjsId eid, char *path, MprVar *result, char **emsg){	struct stat	 sbuf;	Ejs			*ep;	char		*script;	int			rc, fd;	mprAssert(path && *path);	if (emsg) {		*emsg = NULL;	}	if ((ep = ejsPtr(eid)) == NULL) {		mprAssert(ep);		goto error;	}	if ((fd = open(path, O_RDONLY | O_BINARY, 0666)) < 0) {		ejsError(ep, "Can't open %s\n", path);		goto error;	}		if (stat(path, &sbuf) < 0) {		close(fd);		ejsError(ep, "Cant stat %s", path);		goto error;	}		if ((script = (char*) mprMalloc(sbuf.st_size + 1)) == NULL) {		close(fd);		ejsError(ep, "Cant malloc %d", (int) sbuf.st_size);		goto error;	}		if (read(fd, script, sbuf.st_size) != (int) sbuf.st_size) {		close(fd);		mprFree(script);		ejsError(ep, "Error reading %s", path);		goto error;	}		script[sbuf.st_size] = '\0';	close(fd);	rc = ejsEvalBlock(eid, script, result, emsg);	mprFree(script);	return rc;/* *	Error return */error:	if(emsg)		*emsg = mprStrdup(ep->error);	return -1;}/******************************************************************************//* *	Create a new variable scope block. This pushes the old local frame down *	the stack and creates a new local variables frame. */int ejsOpenBlock(EjsId eid){	Ejs		*ep;	if((ep = ejsPtr(eid)) == NULL) {		return -1;	}	ep->local = (MprVar*) mprMalloc(sizeof(MprVar));	*ep->local = ejsCreateObj("localBlock", EJS_OBJ_HASH_SIZE);	mprCreateProperty(ep->local, "local", ep->local);	return mprAddToArray(ep->frames, ep->local);}/******************************************************************************//* *	Close a variable scope block opened via ejsOpenBlock. Pop back the old *	local variables frame. */int ejsCloseBlock(EjsId eid, int fid){	Ejs		*ep;	if((ep = ejsPtr(eid)) == NULL) {		mprAssert(ep);		return -1;	}	/* 	 *	Must remove self-references before destroying "local"	 */	mprDeleteProperty(ep->local, "local");	mprDestroyVar(ep->local);	mprFree(ep->local);	mprRemoveFromArray(ep->frames, fid);	ep->local = (MprVar*) ep->frames->handles[ep->frames->used - 1];	return 0;}/******************************************************************************//* *	Create a new variable scope block and evaluate a script. All frames *	created during this context will be automatically deleted when complete. *	vp and emsg are optional. i.e. created local variables will be discarded *	when this routine returns. */int ejsEvalBlock(EjsId eid, char *script, MprVar *vp, char **emsg){	int		rc, fid;	mprAssert(script);	fid = ejsOpenBlock(eid);	rc = ejsEvalScript(eid, script, vp, emsg);	ejsCloseBlock(eid, fid);	return rc;}/******************************************************************************//* *	Parse and evaluate a EJS. Return the result in *vp. The result is "owned" *	by EJ and the caller must not free it. Returns -1 on errors and zero  *	for success. On errors, emsg will be set to the reason. The caller must  *	free emsg. */int ejsEvalScript(EjsId eid, char *script, MprVar *vp, char **emsg){	Ejs			*ep;	int			state;	void		*endlessLoopTest;	int			loopCounter;		if (emsg) {		*emsg = NULL;	} 	if ((ep = ejsPtr(eid)) == NULL) {		mprAssert(ep);		return -1;	}	mprDestroyVar(&ep->result);	if (script == 0) {		return 0;	}	/*	 *	Allocate a new evaluation block, and save the old one	 */	ejsLexOpenScript(ep, script);	/*	 *	Do the actual parsing and evaluation	 */	loopCounter = 0;	endlessLoopTest = NULL;	ep->exitStatus = 0;	do {		state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE);		if (state == EJS_STATE_RET) {			state = EJS_STATE_EOF;		}		/*		 *	Stuck parser and endless recursion protection.		 */		if (endlessLoopTest == ep->input->scriptServp) {			if (loopCounter++ > 10) {				state = EJS_STATE_ERR;				ejsError(ep, "Syntax error");			}		} else {			endlessLoopTest = ep->input->scriptServp;			loopCounter = 0;		}	} while (state != EJS_STATE_EOF && state != EJS_STATE_ERR);	ejsLexCloseScript(ep);	/*	 *	Return any error string to the user	 */	if (state == EJS_STATE_ERR && emsg) {		*emsg = mprStrdup(ep->error);	}	if (state == EJS_STATE_ERR) {		return -1;	}	if (vp) {		*vp = ep->result;	}	return ep->exitStatus;}/******************************************************************************//* *	Core error handling */static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args) 	PRINTF_ATTRIBUTE(2, 0);static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args){	EjsInput	*ip;	char		*errbuf, *msgbuf;	int frame = 0;	mprAssert(ep);	msgbuf = NULL;	mprAllocVsprintf(&msgbuf, MPR_MAX_STRING, fmt, args);	ip = ep->input;	mprAllocSprintf(&errbuf, MPR_MAX_STRING, "%s\nBacktrace:\n", msgbuf);	/* form a backtrace */	while (ip) {		char *msg2, *ebuf2;		mprAllocSprintf(&msg2, MPR_MAX_STRING,						"\t[%2d] %20s:%-4d -> %s\n",						frame++, ip->procName?ip->procName:"", ip->lineNumber, ip->line);		ebuf2 = mprRealloc(errbuf, strlen(errbuf) + strlen(msg2) + 1);		if (ebuf2 == NULL) break;		errbuf = ebuf2;		memcpy(errbuf+strlen(errbuf), msg2, strlen(msg2)+1);		mprFree(msg2);		ip = ip->next;	}	mprFree(ep->error);	ep->error = errbuf;	mprFree(msgbuf);}/******************************************************************************//* *	Internal use function to set the error message */void ejsError(Ejs* ep, const char* fmt, ...){	va_list		args;	va_start(args, fmt);	ejsErrorCore(ep, fmt, args);	va_end(args);}/******************************************************************************//* *	Public routine to set the error message */

⌨️ 快捷键说明

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