PUBLIC EjsArray *ejsCloneArray(Ejs *ejs, EjsArray *ap, bool deep) { EjsArray *newArray; EjsObj **dest, **src; int i; if ((newArray = ejsClonePot(ejs, ap, deep)) == 0) { ejsThrowMemoryError(ejs); return 0; } if (ap->length > 0) { if (growArray(ejs, newArray, ap->length) < 0) { ejsThrowMemoryError(ejs); return 0; } src = ap->data; dest = newArray->data; if (deep) { for (i = 0; i < ap->length; i++) { dest[i] = ejsClone(ejs, src[i], deep); } } else { memcpy(dest, src, ap->length * sizeof(EjsObj*)); } } return newArray; }
/* * Convert the array to a single string each member of the array has toString called on it and the resulting strings * are concatenated. * * override function toString(): String */ static EjsVar *arrayToString(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsString *result; EjsVar *vp; int i, rc; result = ejsCreateString(ejs, ""); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } for (i = 0; i < ap->length; i++) { vp = ap->data[i]; rc = 0; if (i > 0) { rc = ejsStrcat(ejs, result, (EjsVar*) ejsCreateString(ejs, ",")); } if (vp != 0 && vp != ejs->undefinedValue && vp != ejs->nullValue) { rc = ejsStrcat(ejs, result, vp); } if (rc < 0) { ejsThrowMemoryError(ejs); return 0; } } return (EjsVar*) result; }
static EjsArray *cloneArray(Ejs *ejs, EjsArray *ap, bool deep) { EjsArray *newArray; EjsVar **dest, **src; int i; newArray = (EjsArray*) ejsCopyObject(ejs, (EjsObject*) ap, deep); if (newArray == 0) { ejsThrowMemoryError(ejs); return 0; } if (ap->length > 0) { if (growArray(ejs, newArray, ap->length) < 0) { ejsThrowMemoryError(ejs); return 0; } src = ap->data; dest = newArray->data; if (deep) { for (i = 0; i < ap->length; i++) { dest[i] = ejsCloneVar(ejs, src[i], 1); } } else { memcpy(dest, src, ap->length * sizeof(EjsVar*)); } } return newArray; }
/* Convert the array to a single string each member of the array has toString called on it and the resulting strings are concatenated. override function toString(): String */ static EjsString *arrayToString(Ejs *ejs, EjsArray *ap, int argc, EjsObj **argv) { EjsString *result, *comma; EjsObj *vp; int i, rc; result = ESV(empty); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } comma = ejsCreateStringFromAsc(ejs, ","); for (i = 0; i < ap->length; i++) { vp = ap->data[i]; rc = 0; if (i > 0) { result = ejsJoinString(ejs, result, comma); } if (ejsIsDefined(ejs, vp)) { result = ejsJoinString(ejs, result, ejsToString(ejs, vp)); } if (rc < 0) { ejsThrowMemoryError(ejs); return 0; } } return result; }
static EjsVar *arrayConstructor(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *args; EjsVar *arg0, **src, **dest; int size, i; mprAssert(argc == 1 && ejsIsArray(argv[0])); args = (EjsArray*) argv[0]; if (args->length == 0) { return 0; } size = 0; arg0 = getArrayProperty(ejs, args, 0); if (args->length == 1 && ejsIsNumber(arg0)) { /* * x = new Array(size); */ size = ejsGetInt(arg0); if (size > 0 && growArray(ejs, ap, size) < 0) { ejsThrowMemoryError(ejs); return 0; } } else { /* * x = new Array(element0, element1, ..., elementN): */ size = args->length; if (size > 0 && growArray(ejs, ap, size) < 0) { ejsThrowMemoryError(ejs); return 0; } src = args->data; dest = ap->data; for (i = 0; i < size; i++) { dest[i] = src[i]; } } ap->length = size; return (EjsVar*) ap; }
/** * Iterate over all elements in the object and find all elements for which the matching function is true. * The match is called with the following signature: * * function match(arrayElement: Object, elementIndex: Number, arr: Array): Boolean * * @param match Matching function * @return Returns a new array containing all matching elements. */ static EjsVar *findAll(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsVar *funArgs[3]; EjsBoolean *result; EjsArray *elements; int i; mprAssert(argc == 1 && ejsIsFunction(argv[0])); elements = ejsCreateArray(ejs, 0); if (elements == 0) { ejsThrowMemoryError(ejs); return 0; } for (i = 0; i < ap->length; i++) { funArgs[0] = ap->obj.properties.slots[i]; /* Array element */ funArgs[1] = (EjsVar*) ejsCreateNumber(ejs, i); /* element index */ funArgs[2] = (EjsVar*) ap; /* Array */ result = (EjsBoolean*) ejsRunFunction(ejs, (EjsFunction*) argv[0], 0, 3, funArgs); if (result == 0 || !ejsIsBoolean(result) || !result->value) { setArrayProperty(ejs, elements, elements->length, ap->obj.properties.slots[i]); } } return (EjsVar*) elements; }
/* * Post a message to this worker. Note: the worker is the destination worker which may be the parent. * * function postMessage(data: Object, ports: Array = null): Void */ static EjsVar *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { EjsVar *data; EjsWorker *target; MprDispatcher *dispatcher; Message *msg; if (worker->state >= EJS_WORKER_CLOSED) { ejsThrowStateError(ejs, "Worker has completed"); return 0; } /* * Create the event with serialized data in the originating interpreter. It owns the data. */ if ((data = ejsSerialize(ejs, argv[0], -1, 0, 0)) == 0) { ejsThrowArgError(ejs, "Can't serialize message data"); return 0; } if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = mprStrdup(target->ejs, ejsGetString(data)); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_ejs_sys_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); return 0; }
EjsVar *ejsCreateInstance(Ejs *ejs, EjsType *type, int argc, EjsVar **argv) { EjsFunction *fun; EjsVar *vp; int slotNum; mprAssert(type); vp = ejsCreateVar(ejs, type, 0); if (vp == 0) { ejsThrowMemoryError(ejs); return 0; } if (type->hasConstructor) { slotNum = type->block.numInherited; fun = (EjsFunction*) ejsGetProperty(ejs, (EjsVar*) type, slotNum); if (fun == 0) { return 0; } if (!ejsIsFunction(fun)) { return 0; } vp->permanent = 1; ejsRunFunction(ejs, fun, vp, argc, argv); vp->permanent = 0; } return vp; }
/* Post a message to this worker. Note: the worker is the destination worker which may be the parent. function postMessage(data: Object, ports: Array = null): Void */ static EjsObj *workerPostMessage(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { EjsString *data; EjsWorker *target; MprDispatcher *dispatcher; Message *msg; if (worker->state >= EJS_WORKER_CLOSED) { ejsThrowStateError(ejs, "Worker has completed"); return 0; } /* Create the event with serialized data in the originating interpreter. It owns the data. */ ejsBlockGC(ejs); if ((data = ejsToJSON(ejs, argv[0], NULL)) == 0) { ejsThrowArgError(ejs, "Cannot serialize message data"); return 0; } if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return 0; } target = worker->pair; msg->data = ejsToMulti(ejs, data); msg->worker = target; msg->callback = "onmessage"; msg->callbackSlot = ES_Worker_onmessage; dispatcher = target->ejs->dispatcher; mprCreateEvent(dispatcher, "postMessage", 0, doMessage, msg, 0); return 0; }
static EjsObj *loadXml(Ejs *ejs, EjsXML *xml, int argc, EjsObj **argv) { MprFile *file; MprXml *xp; cchar *filename; assert(argc == 1 && ejsIs(ejs, argv[0], String)); filename = ejsToMulti(ejs, argv[0]); file = mprOpenFile(filename, O_RDONLY, 0664); if (file == 0) { ejsThrowIOError(ejs, "Cannot open: %s", filename); return 0; } // TODO - convert to open/close xp = ejsCreateXmlParser(ejs, xml, filename); if (xp == 0) { ejsThrowMemoryError(ejs); mprCloseFile(file); return 0; } mprXmlSetInputStream(xp, readFileData, (void*) file); if (mprXmlParse(xp) < 0 && !ejsHasException(ejs)) { ejsThrowIOError(ejs, "Cannot parse XML file: %s\nDetails %s", filename, mprXmlGetErrorMsg(xp)); } mprCloseFile(file); return 0; }
/* * Concatenate the supplied elements with the array to create a new array. If any arguments specify an array, * their elements are catenated. This is a one level deep copy. * * function concat(...args): Array */ static EjsVar *concatArray(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *args, *newArray, *vpa; EjsVar *vp, **src, **dest; int i, k, next; mprAssert(argc == 1 && ejsIsArray(argv[0])); args = ((EjsArray*) argv[0]); newArray = ejsCreateArray(ejs, ap->length); src = ap->data; dest = newArray->data; /* * Copy the original array */ for (next = 0; next < ap->length; next++) { dest[next] = src[next]; } /* * Copy the args. If any element is itself an array, then flatten it and copy its elements. */ for (i = 0; i < args->length; i++) { vp = args->data[i]; if (ejsIsArray(vp)) { vpa = (EjsArray*) vp; if (growArray(ejs, newArray, next + vpa->length) < 0) { ejsThrowMemoryError(ejs); return 0; } dest = newArray->data; dest = newArray->data; for (k = 0; k < vpa->length; k++) { dest[next++] = vpa->data[k]; } } else { if (growArray(ejs, newArray, next + 1) < 0) { ejsThrowMemoryError(ejs); return 0; } dest[next++] = vp; } } return (EjsVar*) newArray; }
/* function WebSocket(uri: Uri, protocols = null, options) options = { certificate: Path, verify: Boolean, } */ static EjsWebSocket *wsConstructor(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsAny *certificate; bool verify; assert(ejsIsPot(ejs, ws)); ejsLoadHttpService(ejs); ws->ejs = ejs; verify = 0; ws->uri = httpUriToString(((EjsUri*) argv[0])->uri, 0); if (argc >= 2) { if (ejsIs(ejs, argv[1], Array)) { ws->protocols = sclone((ejsToString(ejs, argv[1]))->value); } else if (ejsIs(ejs, argv[1], String)) { ws->protocols = sclone(((EjsString*) argv[1])->value); } else { ws->protocols = sclone("chat"); } } else { ws->protocols = sclone("chat"); } if (*ws->protocols == '\0') { ejsThrowArgError(ejs, "Bad protocol"); return 0; } if (argc >= 3) { ws->frames = ejsGetPropertyByName(ejs, argv[2], EN("frames")) == ESV(true); verify = ejsGetPropertyByName(ejs, argv[2], EN("verify")) == ESV(true); if ((certificate = ejsGetPropertyByName(ejs, argv[2], EN("certificate"))) != 0) { ws->certFile = ejsToMulti(ejs, argv[0]); } } if ((ws->conn = httpCreateConn(MPR->httpService, NULL, ejs->dispatcher)) == 0) { ejsThrowMemoryError(ejs); return 0; } httpSetAsync(ws->conn, 1); httpPrepClientConn(ws->conn, 0); httpSetConnNotifier(ws->conn, webSocketNotify); httpSetWebSocketProtocols(ws->conn, ws->protocols); httpSetConnContext(ws->conn, ws); if (sstarts(ws->uri, "wss")) { ws->ssl = mprCreateSsl(0); mprVerifySslIssuer(ws->ssl, verify); mprVerifySslPeer(ws->ssl, verify); #if FUTURE if (!hp->caFile) { //MOB - Some define for this. hp->caFile = mprJoinPath(mprGetAppDir(), "http-ca.crt"); } mprSetSslCaFile(hp->ssl, hp->caFile); mprSetSslCaFile(hp->ssl, mprJoinPath(mprGetAppDir(), "http-ca.crt")); #endif } startWebSocketRequest(ejs, ws); return ws; }
/* * DB Constructor and also used for constructor for sub classes. * * function DB(connectionString: String) */ static EjsVar *dbConstructor(Ejs *ejs, EjsDb *db, int argc, EjsVar **argv) { sqlite3 *sdb; EjsDb **dbp; char *path; path = ejsGetString(argv[0]); /* * Create a memory context for use by sqlite. This is a virtual paged memory region. * TODO - this is not ideal for long running applications. */ db->arena = mprAllocArena(ejs, "sqlite", EJS_MAX_DB_MEM, 0, 0); if (db->arena == 0) { return 0; } /* * Create a destructor object so we can cleanup and close the database. Must create after the arena so it will be * invoked before the arena is freed. */ if ((dbp = mprAllocObject(ejs, 1, (MprDestructor) dbDestructor)) == 0) { ejsThrowMemoryError(ejs); return 0; } *dbp = db; db->tls = mprCreateThreadLocal(db->arena); if (db->tls == 0) { return 0; } ejsSetDbMemoryContext(db->tls, db->arena); sdb = 0; if (sqlite3_open(path, &sdb /* TODO remove , SQLITE_OPEN_READWRITE, 0 */) != SQLITE_OK) { ejsThrowIOError(ejs, "Can't open database %s", path); return 0; } db->sdb = sdb; sqlite3_busy_timeout(sdb, 15000); /* * Query or change the count-changes flag. Normally, when the count-changes flag is not set, INSERT, UPDATE and * DELETE statements return no data. When count-changes is set, each of these commands returns a single row of * data consisting of one integer value - the number of rows inserted, modified or deleted by the command. The * returned change count does not include any insertions, modifications or deletions performed by triggers. */ // sqlite3_exec(sdb, "PRAGMA count_changes = OFF", NULL, NULL, NULL); ejsSetProperty(ejs, (EjsVar*) db, ES_ejs_db_Database__connection, (EjsVar*) ejsCreateString(ejs, path)); ejsSetProperty(ejs, (EjsVar*) db, ES_ejs_db_Database__name, (EjsVar*) ejsCreateString(ejs, mprGetBaseName(path))); return 0; }
/* * Worker thread main procedure */ static void workerMain(EjsWorker *worker, MprWorker *mprWorker) { Ejs *ejs, *inside; EjsWorker *insideWorker; MprDispatcher *dispatcher; Message *msg; mprAssert(!worker->inside); insideWorker = worker->pair; mprAssert(insideWorker->state == EJS_WORKER_BEGIN); ejs = worker->ejs; inside = insideWorker->ejs; insideWorker->state = EJS_WORKER_STARTED; /* * Run the script or file */ if (worker->scriptFile) { loadFile(insideWorker, worker->scriptFile); } else if (worker->scriptLiteral) { if (ejs->service->loadScriptLiteral == 0) { ejsThrowIOError(ejs, "worker: Compiling is not enabled"); return; } (ejs->service->loadScriptLiteral)(inside, worker->scriptLiteral); } /* * Check for exceptions */ if (inside->exception) { handleError(ejs, worker, inside->exception); } if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return; } /* * Post "onclose" finalization message */ msg->worker = worker; msg->callback = "onclose"; msg->callbackSlot = ES_ejs_sys_Worker_onclose; insideWorker->state = EJS_WORKER_CLOSED; worker->state = EJS_WORKER_CLOSED; insideWorker->obj.var.permanent = 0; dispatcher = worker->ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); }
/* Worker thread main procedure. Worker is the inside worker. */ static int workerMain(EjsWorker *insideWorker, MprEvent *event) { Ejs *outside, *inside; EjsWorker *outsideWorker; MprDispatcher *dispatcher; Message *msg; assert(insideWorker->inside); outsideWorker = insideWorker->pair; assert(!outsideWorker->inside); assert(insideWorker->state == EJS_WORKER_BEGIN); outside = outsideWorker->ejs; inside = insideWorker->ejs; insideWorker->state = EJS_WORKER_STARTED; /* Run the script or file */ if (outsideWorker->scriptFile) { loadFile(insideWorker, outsideWorker->scriptFile); } else if (outsideWorker->scriptLiteral) { if (outside->service->loadScriptLiteral == 0) { ejsThrowIOError(outside, "worker: Compiling is not enabled"); return 0; } (outside->service->loadScriptLiteral)(inside, outsideWorker->scriptLiteral, NULL); } /* Check for exceptions */ if (inside->exception) { handleError(outside, outsideWorker, inside->exception, 0); inside->exception = 0; } ejsBlockGC(inside); if ((msg = createMessage()) == 0) { ejsThrowMemoryError(outside); return 0; } /* Post "onclose" finalization message */ msg->worker = outsideWorker; msg->callback = "onclose"; msg->callbackSlot = ES_Worker_onclose; insideWorker->state = EJS_WORKER_CLOSED; outsideWorker->state = EJS_WORKER_CLOSED; dispatcher = outside->dispatcher; mprCreateEvent(dispatcher, "doMessage", 0, (MprEventProc) doMessage, msg, 0); return 0; }
static int checkSlot(Ejs *ejs, EjsArray *ap, int slotNum) { if (slotNum < 0) { if (!ap->obj.var.dynamic) { ejsThrowTypeError(ejs, "Object is not dynamic"); return EJS_ERR; } slotNum = ap->length; if (growArray(ejs, ap, ap->length + 1) < 0) { ejsThrowMemoryError(ejs); return EJS_ERR; } } else if (slotNum >= ap->length) { if (growArray(ejs, ap, slotNum + 1) < 0) { ejsThrowMemoryError(ejs); return EJS_ERR; } } return slotNum; }
static EjsObj *cloneXmlList(Ejs *ejs, EjsXML *list, bool deep) { EjsXML *newList; // TODO - implement deep copy newList = ejsCreateObj(ejs, TYPE(list), 0); if (newList == 0) { ejsThrowMemoryError(ejs); return 0; } // TODO incomplete return (EjsObj*) newList; }
/* DB Constructor and also used for constructor for sub classes. function Debugger(connectionString: String) */ static EjsVar *debuggerConstructor(Ejs *ejs, EjsDebugger *db, int argc, EjsVar **argv) { debugger3 *sdb; cchar *path; path = ejsGetString(ejs, argv[0]); db->ejs = ejs; /* * Create a memory context for use by debugger. This is a virtual paged memory region. * TODO OPT - Could do better for running applications. */ #if MAP_ALLOC db->arena = mprAllocArena(ejs, "debugger", EJS_MAX_SQLITE_MEM, !USE_TLS, 0); if (db->arena == 0) { return 0; } SET_CTX(db->arena); #else db->arena = mprAllocHeap(ejs, "debugger", EJS_MAX_SQLITE_MEM, 1, 0); if (db->arena == 0) { return 0; } SET_CTX(db->arena); #endif #if UNUSED EjsDebugger **dbp; /* * Create a destructor object so we can cleanup and close the database. Must create after the arena so it will be * invoked before the arena is freed. */ if ((dbp = mprAllocWithDestructor(ejs, sizeof(void*), (MprDestructor) sqldbDestructor)) == 0) { ejsThrowMemoryError(ejs); return 0; } *dbp = db; #endif sdb = 0; if (debugger3_open(path, &sdb) != SQLITE_OK) { ejsThrowIOError(ejs, "Cannot open database %s", path); return 0; } db->sdb = sdb; debugger3_busy_timeout(sdb, ME_MAX_SQLITE_DURATION); debugger3_soft_heap_limit(ME_MAX_SQLITE_MEM); return 0; }
/* Read data bytes from a file function readBytes(count: Number = -1): ByteArray */ static EjsObj *readFileBytes(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *result; MprPath info; ssize count, totalRead; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } result = ejsCreateByteArray(ejs, count); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } totalRead = readData(ejs, fp, result, 0, count); if (totalRead < 0) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } else if (totalRead == 0) { return ESV(null); } ejsSetByteArrayPositions(ejs, result, 0, totalRead); return (EjsObj*) result; }
PUBLIC EjsArray *ejsCreateArray(Ejs *ejs, int size) { EjsArray *ap; /* No need to invoke constructor */ if ((ap = ejsCreatePot(ejs, ESV(Array), 0)) != 0) { ap->length = 0; if (size > 0 && growArray(ejs, ap, size) < 0) { ejsThrowMemoryError(ejs); return 0; } } return ap; }
/* Copy all properties of the instance including all references. If deep is true and if some properties are reference types, then recursively copy all their properties and so on. @param ejs VM handle. @param sp is set to the object instance to clone. @return The newly copied object */ static EjsObj *cloneShape(Ejs *ejs, Shape *sp, bool deep) { Shape *newShape; newShape = ejsCreateObj(ejs, TYPE(sp), 0); if (newShape == 0) { ejsThrowMemoryError(ejs); return 0; } newShape->x = sp->x; newShape->y = sp->y; newShape->height = sp->height; newShape->width = sp->width; return (EjsObj*) newShape; }
/* WARNING: the inside interpreter owns the exception object. Must fully extract all fields */ static void handleError(Ejs *ejs, EjsWorker *worker, EjsObj *exception, int throwOutside) { Ejs *inside; EjsObj *e; MprDispatcher *dispatcher; Message *msg; assert(!worker->inside); assert(exception); assert(ejs == worker->ejs); ejsBlockGC(ejs); if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return; } msg->worker = worker; msg->callback = "onerror"; msg->callbackSlot = ES_Worker_onerror; inside = worker->pair->ejs; inside->exception = 0; e = ejsDeserialize(ejs, ejsSerialize(inside, exception, 0)); inside->exception = exception; /* Inside interpreter owns the exception object, so must fully extract all exception. Allocate into the outside worker's interpreter. */ if (ejsIsError(inside, exception)) { msg->message = ejsGetPropertyByName(ejs, e, EN("message")); msg->stack = ejsGetPropertyByName(ejs, e, EN("stack")); } else { msg->message = e; msg->stack = 0; } if (throwOutside) { if (msg->stack) { ejsThrowStateError(ejs, "%@\n%@", ejsToString(ejs, msg->message), ejsToString(ejs, msg->stack)); } else { ejsThrowStateError(ejs, "%@", ejsToString(ejs, msg->message)); } } dispatcher = ejs->dispatcher; mprCreateEvent(dispatcher, "doMessage-error", 0, (MprEventProc) doMessage, msg, 0); }
/* function read(buffer: ByteArray, offset: Number = 0, count: Number = -1): Number Returns a count of bytes read. Non-blocking if a callback is defined. Otherwise, blocks. Offset: -1 then read to the buffer write position, >= 0 then read to that offset count: -1 then read as much as the buffer will hold. If buffer is growable, read all content. If not growable, read the buffer size. If count >= 0, then read that number of bytes. */ static EjsNumber *http_read(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { EjsByteArray *buffer; HttpConn *conn; MprOff contentLength; ssize offset, count; conn = hp->conn; buffer = (EjsByteArray*) argv[0]; offset = (argc >= 2) ? ejsGetInt(ejs, argv[1]) : 0; count = (argc >= 3) ? ejsGetInt(ejs, argv[2]): -1; if (!waitForResponseHeaders(hp)) { return 0; } contentLength = httpGetContentLength(conn); if (conn->state >= HTTP_STATE_PARSED && contentLength == hp->readCount) { /* End of input */ return ESV(null); } if (offset < 0) { offset = buffer->writePosition; } else if (offset < buffer->size) { ejsSetByteArrayPositions(ejs, buffer, offset, offset); } else { ejsThrowOutOfBoundsError(ejs, "Bad read offset value"); return 0; } if (count < 0 && !buffer->resizable) { count = buffer->size - offset; } if ((count = readHttpData(ejs, hp, count)) < 0) { assert(ejs->exception); return 0; } else if (count == 0 && conn->state > HTTP_STATE_CONTENT) { return ESV(null); } hp->readCount += count; if (ejsCopyToByteArray(ejs, buffer, offset, (char*) mprGetBufStart(hp->responseContent), count) != count) { ejsThrowMemoryError(ejs); } ejsSetByteArrayPositions(ejs, buffer, -1, buffer->writePosition + count); mprAdjustBufStart(hp->responseContent, count); mprResetBufIfEmpty(hp->responseContent); return ejsCreateNumber(ejs, (MprNumber) count); }
/* Read data as a string function readString(count: Number = -1): String */ static EjsString *readFileString(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsString *result; MprPath info; ssize totalRead; int count; if (argc == 0) { count = -1; } else if (argc != 1) { count = 0; ejsThrowArgError(ejs, "Bad args"); return 0; } else { assert(argc == 1 && ejsIs(ejs, argv[0], Number)); count = ejsGetInt(ejs, argv[0]); } if (fp->file == 0) { ejsThrowStateError(ejs, "File not open"); return 0; } if (!(fp->mode & EJS_FILE_READ)) { ejsThrowStateError(ejs, "File not opened for reading"); return 0; } if (count < 0) { // TODO OPT could this be cached in fp->info if (mprGetPathInfo(fp->path, &info) == 0) { count = (int) info.size; count -= (int) mprGetFilePosition(fp->file); } else { count = ME_MAX_BUFFER; } assert(count >= 0); } if ((result = ejsCreateBareString(ejs, count)) == NULL) { ejsThrowMemoryError(ejs); return 0; } totalRead = mprReadFile(fp->file, result->value, count); if (totalRead != count) { ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path); return 0; } return ejsInternString(result); }
EjsArray *ejsCreateArray(Ejs *ejs, int size) { EjsArray *ap; /* * No need to invoke constructor */ ap = (EjsArray*) ejsCreateObject(ejs, ejs->arrayType, 0); if (ap != 0) { ap->length = 0; if (size > 0 && growArray(ejs, ap, size) < 0) { ejsThrowMemoryError(ejs); return 0; } } ejsSetDebugName(ap, "array instance"); return ap; }
/* * Allocate a new variable. Size is set to the extra bytes for properties in addition to the type's instance size. */ EjsVar *ejsAllocVar(Ejs *ejs, EjsType *type, int extra) { EjsVar *vp; mprAssert(type); if ((vp = (EjsVar*) mprAllocZeroed(ejsGetAllocCtx(ejs), type->instanceSize + extra)) == 0) { ejsThrowMemoryError(ejs); return 0; } vp->type = type; vp->master = (ejs->master == 0); ejsAddToGcStats(ejs, vp, type->id); if (++ejs->workDone >= ejs->workQuota) { ejs->gcRequired = 1; ejs->attention = 1; } return (EjsVar*) vp; }
/* function Http(uri: Uri = null) */ static EjsHttp *httpConstructor(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { ejsLoadHttpService(ejs); hp->ejs = ejs; if ((hp->conn = httpCreateConn(ejs->http, NULL, ejs->dispatcher)) == 0) { ejsThrowMemoryError(ejs); return 0; } httpPrepClientConn(hp->conn, 0); httpSetConnNotifier(hp->conn, httpEventChange); httpSetConnContext(hp->conn, hp); if (argc == 1 && ejsIs(ejs, argv[0], Null)) { hp->uri = httpUriToString(((EjsUri*) argv[0])->uri, HTTP_COMPLETE_URI); } hp->method = sclone("GET"); hp->requestContent = mprCreateBuf(BIT_MAX_BUFFER, -1); hp->responseContent = mprCreateBuf(BIT_MAX_BUFFER, -1); return hp; }
/* * WARNING: the inside interpreter owns the exception object. Must fully extract all fields */ static void handleError(Ejs *ejs, EjsWorker *worker, EjsVar *exception) { EjsError *error; MprDispatcher *dispatcher; Message *msg; mprAssert(!worker->inside); mprAssert(exception); mprAssert(ejs == worker->ejs); if ((msg = mprAllocObjZeroed(ejs, Message)) == 0) { ejsThrowMemoryError(ejs); return; } msg->worker = worker; msg->callback = "onerror"; msg->callbackSlot = ES_ejs_sys_Worker_onerror; /* * Inside interpreter owns the exception object, so must fully extract all exception. * Allocate into the outside worker's interpreter. */ if (ejsIsError(exception)) { error = (EjsError*) exception; msg->message = mprStrdup(ejs, error->message); msg->filename = mprStrdup(ejs, error->filename ? error->filename : "script"); msg->lineNumber = error->lineNumber; msg->stack = mprStrdup(ejs, error->stack); } else if (ejsIsString(exception)) { msg->message = mprStrdup(ejs, ejsGetString(exception)); } else { msg->message = mprStrdup(ejs, ejsGetString(ejsToString(ejs, exception))); } dispatcher = ejs->dispatcher; mprCreateEvent(dispatcher, (MprEventProc) doMessage, 0, MPR_NORMAL_PRIORITY, msg, 0); mprSignalCond(dispatcher->cond); }
static inline void pruneTypePools(Ejs *ejs) { EjsPool *pool; EjsGC *gc; EjsVar *vp; MprAlloc *alloc; MprBlk *bp, *next; int64 memory; int i; gc = &ejs->gc; /* * Still insufficient memory, must reclaim all objects from the type pools. */ for (i = 0; i < gc->numPools; i++) { pool = gc->pools[i]; if (pool->count) { for (bp = mprGetFirstChild(pool); bp; bp = next) { next = bp->next; vp = MPR_GET_PTR(bp); mprFree(vp); } pool->count = 0; } } gc->totalRedlines++; memory = mprGetUsedMemory(ejs); alloc = mprGetAllocStats(ejs); if (memory >= alloc->maxMemory) { /* * Could not provide sufficient memory. Go into graceful degrade mode */ ejsThrowMemoryError(ejs); ejsGracefulDegrade(ejs); } }
static EjsVar *castError(Ejs *ejs, EjsError *vp, EjsType *type) { EjsVar *sp; char *buf; switch (type->id) { case ES_Boolean: return (EjsVar*) ejsCreateBoolean(ejs, 1); case ES_String: if ((buf = mprAsprintf(ejs, -1, "%s Exception: %s\nStack:\n%s\n", vp->obj.var.type->qname.name, vp->message, vp->stack)) == NULL) { ejsThrowMemoryError(ejs); } sp = (EjsVar*) ejsCreateString(ejs, buf); mprFree(buf); return sp; default: ejsThrowTypeError(ejs, "Unknown type"); return 0; } }