wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* @file ejsObject.c
|
||||
* @brief Object class
|
||||
*/
|
||||
/********************************* Copyright **********************************/
|
||||
/*
|
||||
* @copy default
|
||||
*
|
||||
* Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
|
||||
* Copyright (c) Michael O'Brien, 1994-1995. 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 "ejs.h"
|
||||
|
||||
#if BLD_FEATURE_EJS
|
||||
|
||||
/****************************** Forward Declarations **************************/
|
||||
/*
|
||||
* Support routines
|
||||
*/
|
||||
|
||||
static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp);
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Routine to create an object of the desired class. Class name may
|
||||
* contain "."
|
||||
*
|
||||
* The created object will be a stand-alone class NOT entered into the
|
||||
* properties of any other object. Callers must do this if required. ClassName
|
||||
* may contain "." and is interpreted relative to "obj" if supplied.
|
||||
*
|
||||
* Note: this does not call the constructors for the various objects and base
|
||||
* classes.
|
||||
*/
|
||||
|
||||
EjsVar *ejsCreateSimpleObjInternal(EJS_LOC_DEC(ep, loc), const char *className)
|
||||
{
|
||||
EjsVar *baseClass;
|
||||
|
||||
if (className && *className) {
|
||||
baseClass = ejsGetClass(ep, 0, className);
|
||||
if (baseClass == 0) {
|
||||
mprError(ep, MPR_LOC, "Can't find base class %s", className);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
baseClass = 0;
|
||||
}
|
||||
|
||||
return ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
|
||||
baseClass);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Create an object based upon the specified base class object. It will be a
|
||||
* stand-alone class not entered into the properties of any other object.
|
||||
* Callers must do this if required.
|
||||
*
|
||||
* Note: this does not call the constructors for the various objects and base
|
||||
* classes.
|
||||
*/
|
||||
|
||||
EjsVar *ejsCreateSimpleObjUsingClassInt(EJS_LOC_DEC(ep, loc),
|
||||
EjsVar *baseClass)
|
||||
{
|
||||
EjsVar *vp;
|
||||
|
||||
mprAssert(baseClass);
|
||||
|
||||
if (baseClass == 0) {
|
||||
mprError(ep, MPR_LOC, "Missing base class\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vp = ejsCreateObjVarInternal(EJS_LOC_PASS(ep, loc));
|
||||
if (vp == 0) {
|
||||
return vp;
|
||||
}
|
||||
|
||||
ejsSetBaseClass(vp, baseClass);
|
||||
|
||||
/*
|
||||
* This makes all internal method accesses faster
|
||||
* NOTE: this code is duplicated in ejsCreateSimpleClass
|
||||
*/
|
||||
mprAssert(vp->objectState);
|
||||
vp->objectState->methods = baseClass->objectState->methods;
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void ejsSetMethods(Ejs *ep, EjsVar *op)
|
||||
{
|
||||
op->objectState->methods = ep->global->objectState->methods;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************** Internal Methods ****************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static EjsVar *createObjProperty(Ejs *ep, EjsVar *obj, const char *property)
|
||||
{
|
||||
return ejsGetVarPtr(ejsCreateSimpleProperty(ep, obj, property));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int deleteObjProperty(Ejs *ep, EjsVar *obj, const char *property)
|
||||
{
|
||||
return ejsDeleteProperty(ep, obj, property);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static EjsVar *getObjProperty(Ejs *ep, EjsVar *obj, const char *property)
|
||||
{
|
||||
return ejsGetVarPtr(ejsGetSimpleProperty(ep, obj, property));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Set the value of a property. Create if it does not exist
|
||||
*/
|
||||
|
||||
static EjsVar *setObjProperty(Ejs *ep, EjsVar *obj, const char *property,
|
||||
const EjsVar *value)
|
||||
{
|
||||
EjsProperty *pp;
|
||||
EjsVar *vp;
|
||||
|
||||
pp = ejsCreateSimpleProperty(ep, obj, property);
|
||||
if (pp == 0) {
|
||||
mprAssert(pp);
|
||||
return 0;
|
||||
}
|
||||
vp = ejsGetVarPtr(pp);
|
||||
if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) < 0) {
|
||||
mprAssert(0);
|
||||
return 0;
|
||||
}
|
||||
return ejsGetVarPtr(pp);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*********************************** Constructors *****************************/
|
||||
/******************************************************************************/
|
||||
#if UNUSED
|
||||
/*
|
||||
* Object constructor. We don't use this for speed. Think very carefully if
|
||||
* you add an object constructor.
|
||||
*/
|
||||
|
||||
int ejsObjectConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
/******************************************************************************/
|
||||
/******************************** Visible Methods *****************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static int cloneMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
int copyDepth;
|
||||
|
||||
copyDepth = EJS_DEEP_COPY;
|
||||
|
||||
if (argc == 1 && ejsVarToBoolean(argv[0])) {
|
||||
copyDepth = EJS_RECURSIVE_DEEP_COPY;
|
||||
}
|
||||
|
||||
ejsWriteVar(ep, ep->result, thisObj, copyDepth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int toStringMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
MprBuf *bp;
|
||||
int saveMaxDepth, saveDepth, saveFlags;
|
||||
|
||||
saveMaxDepth = ep->maxDepth;
|
||||
|
||||
if (argc >= 1) {
|
||||
ep->maxDepth = ejsVarToInteger(argv[0]);
|
||||
} else if (ep->maxDepth == 0) {
|
||||
ep->maxDepth = MAXINT;
|
||||
}
|
||||
|
||||
saveFlags = ep->flags;
|
||||
if (argc >= 2) {
|
||||
if (ejsVarToBoolean(argv[1])) {
|
||||
ep->flags |= EJS_FLAGS_ENUM_HIDDEN;
|
||||
}
|
||||
}
|
||||
if (argc == 3) {
|
||||
if (ejsVarToBoolean(argv[2])) {
|
||||
ep->flags |= EJS_FLAGS_ENUM_BASE;
|
||||
}
|
||||
}
|
||||
|
||||
bp = mprCreateBuf(ep, 0, 0);
|
||||
|
||||
saveDepth = ep->depth;
|
||||
|
||||
formatVar(ep, bp, thisObj);
|
||||
|
||||
ep->depth = saveDepth;
|
||||
ep->maxDepth = saveMaxDepth;
|
||||
|
||||
mprAddNullToBuf(bp);
|
||||
|
||||
ejsWriteVarAsString(ep, ep->result, mprGetBufStart(bp));
|
||||
mprFree(bp);
|
||||
|
||||
ep->flags = saveFlags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int valueOfMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
if (argc != 0) {
|
||||
mprAssert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (thisObj->type) {
|
||||
default:
|
||||
case EJS_TYPE_UNDEFINED:
|
||||
case EJS_TYPE_NULL:
|
||||
case EJS_TYPE_CMETHOD:
|
||||
case EJS_TYPE_OBJECT:
|
||||
case EJS_TYPE_METHOD:
|
||||
case EJS_TYPE_STRING_CMETHOD:
|
||||
ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
|
||||
break;
|
||||
|
||||
case EJS_TYPE_STRING:
|
||||
ejsWriteVarAsInteger(ep, ep->result, atoi(thisObj->string));
|
||||
break;
|
||||
|
||||
case EJS_TYPE_BOOL:
|
||||
case EJS_TYPE_INT:
|
||||
#if BLD_FEATURE_INT64
|
||||
case EJS_TYPE_INT64:
|
||||
#endif
|
||||
#if BLD_FEATURE_FLOATING_POINT
|
||||
case EJS_TYPE_FLOAT:
|
||||
#endif
|
||||
ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int hashGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
ejsSetReturnValueToInteger(ejs, (int) thisObj->objectState);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int classGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
if (thisObj->objectState == 0 || thisObj->objectState->baseClass == 0) {
|
||||
ejsSetReturnValueToString(ejs, "object");
|
||||
} else {
|
||||
ejsSetReturnValueToString(ejs,
|
||||
thisObj->objectState->baseClass->objectState->className);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Format an object. Called recursively to format properties and contained
|
||||
* objects.
|
||||
*/
|
||||
|
||||
static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp)
|
||||
{
|
||||
EjsProperty *pp, *first;
|
||||
EjsVar *propVar, *baseClass;
|
||||
char *buf, *value;
|
||||
int i;
|
||||
|
||||
if (vp->type == EJS_TYPE_OBJECT) {
|
||||
if (!vp->objectState->visited) {
|
||||
|
||||
mprPutStringToBuf(bp, vp->isArray ? "[\n" : "{\n");
|
||||
|
||||
ep->depth++;
|
||||
vp->objectState->visited = 1;
|
||||
|
||||
if (ep->depth <= ep->maxDepth) {
|
||||
first = ejsGetFirstProperty(vp, EJS_ENUM_ALL);
|
||||
|
||||
if (ep->flags & EJS_FLAGS_ENUM_BASE) {
|
||||
baseClass = vp->objectState->baseClass;
|
||||
if (baseClass) {
|
||||
for (i = 0; i < ep->depth; i++) {
|
||||
mprPutStringToBuf(bp, " ");
|
||||
}
|
||||
mprPutStringToBuf(bp, baseClass->objectState->objName);
|
||||
mprPutStringToBuf(bp, ": /* Base Class */ ");
|
||||
if (baseClass->objectState == vp->objectState) {
|
||||
value = "this";
|
||||
} else if (ejsRunMethodCmd(ep, baseClass, "toString",
|
||||
"%d", ep->maxDepth) < 0) {
|
||||
value = "[object Object]";
|
||||
} else {
|
||||
mprAssert(ejsVarIsString(ep->result));
|
||||
value = ep->result->string;
|
||||
}
|
||||
mprPutStringToBuf(bp, value);
|
||||
if (first) {
|
||||
mprPutStringToBuf(bp, ",\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pp = first;
|
||||
while (pp) {
|
||||
if (! pp->dontEnumerate ||
|
||||
ep->flags & EJS_FLAGS_ENUM_HIDDEN) {
|
||||
for (i = 0; i < ep->depth; i++) {
|
||||
mprPutStringToBuf(bp, " ");
|
||||
}
|
||||
|
||||
if (! vp->isArray) {
|
||||
mprPutStringToBuf(bp, pp->name);
|
||||
mprPutStringToBuf(bp, ": ");
|
||||
}
|
||||
|
||||
propVar = ejsGetVarPtr(pp);
|
||||
if (propVar->type == EJS_TYPE_OBJECT) {
|
||||
if (pp->var.objectState == vp->objectState) {
|
||||
value = "this";
|
||||
} else if (ejsRunMethodCmd(ep, propVar,
|
||||
"toString", "%d", ep->maxDepth) < 0) {
|
||||
value = "[object Object]";
|
||||
} else {
|
||||
mprAssert(ejsVarIsString(ep->result));
|
||||
value = ep->result->string;
|
||||
}
|
||||
mprPutStringToBuf(bp, value);
|
||||
|
||||
} else {
|
||||
formatVar(ep, bp, &pp->var);
|
||||
}
|
||||
|
||||
pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
|
||||
if (pp) {
|
||||
mprPutStringToBuf(bp, ",\n");
|
||||
}
|
||||
} else {
|
||||
pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
vp->objectState->visited = 0;
|
||||
|
||||
mprPutCharToBuf(bp, '\n');
|
||||
|
||||
ep->depth--;
|
||||
for (i = 0; i < ep->depth; i++) {
|
||||
mprPutStringToBuf(bp, " ");
|
||||
}
|
||||
mprPutCharToBuf(bp, vp->isArray ? ']' : '}');
|
||||
}
|
||||
|
||||
} else if (vp->type == EJS_TYPE_METHOD) {
|
||||
|
||||
mprPutStringToBuf(bp, "function (");
|
||||
for (i = 0; i < vp->method.args->length; i++) {
|
||||
mprPutStringToBuf(bp, vp->method.args->items[i]);
|
||||
if ((i + 1) < vp->method.args->length) {
|
||||
mprPutStringToBuf(bp, ", ");
|
||||
}
|
||||
}
|
||||
mprPutStringToBuf(bp, ") {");
|
||||
mprPutStringToBuf(bp, vp->method.body);
|
||||
for (i = 0; i < ep->depth; i++) {
|
||||
mprPutStringToBuf(bp, " ");
|
||||
}
|
||||
mprPutStringToBuf(bp, "}");
|
||||
|
||||
} else {
|
||||
|
||||
if (vp->type == EJS_TYPE_STRING) {
|
||||
mprPutCharToBuf(bp, '\"');
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't use ejsVarToString for arrays, objects and strings.
|
||||
* This is because ejsVarToString does not call "obj.toString"
|
||||
* and it is not required for strings.
|
||||
* MOB - rc
|
||||
*/
|
||||
buf = ejsVarToString(ep, vp);
|
||||
mprPutStringToBuf(bp, buf);
|
||||
|
||||
if (vp->type == EJS_TYPE_STRING) {
|
||||
mprPutCharToBuf(bp, '\"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* mixin code. Blends code at the "thisObj" level.
|
||||
*/
|
||||
|
||||
static int mixinMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
|
||||
{
|
||||
EjsProperty *pp;
|
||||
char *buf;
|
||||
int fid, i, rc;
|
||||
|
||||
mprAssert(argv);
|
||||
|
||||
/*
|
||||
* Create a variable scope block set to the current object
|
||||
*/
|
||||
rc = 0;
|
||||
fid = ejsSetBlock(ep, thisObj);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
|
||||
if (ejsVarIsString(argv[i])) {
|
||||
rc = ejsEvalScript(ep, argv[i]->string, 0);
|
||||
|
||||
} else if (ejsVarIsObject(argv[i])) {
|
||||
|
||||
/* MOB -- OPT. When we have proper scope chains, we should just
|
||||
refer to the module and not copy */
|
||||
pp = ejsGetFirstProperty(argv[i], EJS_ENUM_ALL);
|
||||
while (pp) {
|
||||
ejsSetProperty(ep, thisObj, pp->name, ejsGetVarPtr(pp));
|
||||
pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* MOB - rc */
|
||||
buf = ejsVarToString(ep, argv[i]);
|
||||
rc = ejsEvalScript(ep, buf, 0);
|
||||
|
||||
}
|
||||
if (rc < 0) {
|
||||
ejsCloseBlock(ep, fid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ejsCloseBlock(ep, fid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*
|
||||
* Create the object class
|
||||
*/
|
||||
|
||||
int ejsDefineObjectClass(Ejs *ep)
|
||||
{
|
||||
EjsMethods *methods;
|
||||
EjsProperty *objectProp, *protoProp;
|
||||
EjsVar *op, *globalClass;
|
||||
|
||||
/*
|
||||
* Must specially hand-craft the object class as it is the base class
|
||||
* of all objects.
|
||||
*/
|
||||
op = ejsCreateObjVar(ep);
|
||||
if (op == 0) {
|
||||
return MPR_ERR_CANT_CREATE;
|
||||
}
|
||||
ejsSetClassName(ep, op, "Object");
|
||||
|
||||
/*
|
||||
* Don't use a constructor for objects for speed
|
||||
*/
|
||||
ejsMakeClassNoConstructor(op);
|
||||
|
||||
/*
|
||||
* MOB -- should mark properties as public / private and class or instance.
|
||||
*/
|
||||
ejsDefineCMethod(ep, op, "clone", cloneMethod, EJS_NO_LOCAL);
|
||||
ejsDefineCMethod(ep, op, "toString", toStringMethod, EJS_NO_LOCAL);
|
||||
ejsDefineCMethod(ep, op, "valueOf", valueOfMethod, EJS_NO_LOCAL);
|
||||
ejsDefineCMethod(ep, op, "mixin", mixinMethod, EJS_NO_LOCAL);
|
||||
|
||||
ejsDefineCAccessors(ep, op, "hash", hashGetAccessor, 0, EJS_NO_LOCAL);
|
||||
ejsDefineCAccessors(ep, op, "baseClass", classGetAccessor, 0, EJS_NO_LOCAL);
|
||||
|
||||
/*
|
||||
* MOB -- make this an accessor
|
||||
*/
|
||||
protoProp = ejsSetProperty(ep, op, "prototype", op);
|
||||
if (protoProp == 0) {
|
||||
ejsFreeVar(ep, op);
|
||||
return MPR_ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the internal methods. Most classes will never override these.
|
||||
* The XML class will. We rely on talloc to free internal. Use "ep" as
|
||||
* the parent as we need "methods" to live while the interpreter lives.
|
||||
*/
|
||||
methods = mprAllocTypeZeroed(ep, EjsMethods);
|
||||
op->objectState->methods = methods;
|
||||
|
||||
methods->createProperty = createObjProperty;
|
||||
methods->deleteProperty = deleteObjProperty;
|
||||
methods->getProperty = getObjProperty;
|
||||
methods->setProperty = setObjProperty;
|
||||
|
||||
objectProp = ejsSetPropertyAndFree(ep, ep->global, "Object", op);
|
||||
|
||||
/*
|
||||
* Change the global class to use Object's methods
|
||||
*/
|
||||
globalClass = ep->service->globalClass;
|
||||
globalClass->objectState->methods = methods;
|
||||
globalClass->objectState->baseClass = ejsGetVarPtr(protoProp);
|
||||
|
||||
ep->objectClass = ejsGetVarPtr(objectProp);
|
||||
|
||||
if (ejsObjHasErrors(ejsGetVarPtr(objectProp))) {
|
||||
ejsFreeVar(ep, op);
|
||||
return MPR_ERR_CANT_CREATE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#else
|
||||
void ejsObjectDummy() {}
|
||||
|
||||
/******************************************************************************/
|
||||
#endif /* BLD_FEATURE_EJS */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim:tw=78
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
||||
Reference in New Issue
Block a user