/* Function to iterate and return the next element value. NOTE: this is not a method of Array. Rather, it is a callback function for Iterator */ static EjsObj *nextValue(Ejs *ejs, EjsIterator *ip, int argc, EjsObj **argv) { EjsFile *fp; fp = (EjsFile*) ip->target; if (!ejsIs(ejs, fp, File)) { ejsThrowReferenceError(ejs, "Wrong type"); return 0; } if (ip->index < fp->info.size) { #if !ME_CC_MMU || 1 if (mprSeekFile(fp->file, SEEK_CUR, 0) != ip->index) { if (mprSeekFile(fp->file, SEEK_SET, ip->index) != ip->index) { ejsThrowIOError(ejs, "Cannot seek to %d", ip->index); return 0; } } ip->index++; return (EjsObj*) ejsCreateNumber(ejs, mprGetFileChar(fp->file)); #else return (EjsObj*) ejsCreateNumber(ejs, fp->mapped[ip->index++]); #endif } #if ME_CC_MMU && FUTURE unmapFile(fp); fp->mapped = 0; #endif ejsThrowStopIteration(ejs); return 0; }
/* Quick sort partition */ static int partition(Ejs *ejs, EjsArray *array, EjsFunction *compare, int direction, int p, int r) { EjsString *sx, *so; EjsNumber *result; EjsAny *argv[3], *tmp; EjsObj *x; int i, j, order; x = array->data[r]; sx = 0; if (compare) { if ((argv[1] = ejsCreateNumber(ejs, r)) == 0) { return 0; } } else { if ((sx = ejsToString(ejs, x)) == 0) { return 0; } } j = p - 1; for (i = p; i < r; i++) { if (compare) { argv[0] = array; argv[2] = ejsCreateNumber(ejs, i); result = ejsRunFunction(ejs, compare, NULL, 3, argv); if (!ejsIs(ejs, result, Number)) { return 0; } order = ejsGetInt(ejs, result); } else { if ((so = ejsToString(ejs, array->data[i])) == 0) { return 0; } order = ejsCompareString(ejs, sx, so); } order *= direction; if (order > 0) { j = j + 1; tmp = array->data[j]; array->data[j] = array->data[i]; array->data[i] = tmp; } } array->data[r] = array->data[j + 1]; array->data[j + 1] = x; return j + 1; }
/* function send(...content): Number */ static EjsNumber *ws_send(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ba; EjsAny *arg; ssize nbytes; int i; args = (EjsArray*) argv[0]; if (ws->conn->state < HTTP_STATE_PARSED && !waitForHttpState(ws, HTTP_STATE_PARSED, -1, 1)) { return ESV(null); } nbytes = 0; for (i = 0; i < args->length; i++) { if ((arg = ejsGetProperty(ejs, args, i)) != 0) { if (ejsIs(ejs, arg, ByteArray)) { ba = (EjsByteArray*) arg; nbytes = ejsGetByteArrayAvailableData(ba); nbytes = httpSendBlock(ws->conn, WS_MSG_BINARY, (cchar*) &ba->value[ba->readPosition], nbytes, HTTP_BLOCK); } else { nbytes = httpSend(ws->conn, ejsToMulti(ejs, arg)); } if (nbytes < 0) { return ESV(null); } } } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
/* Break a uri into components function components(): Object */ static EjsObj *uri_components(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { EjsObj *obj; HttpUri *uri; uri = up->uri; obj = ejsCreateEmptyPot(ejs); if (uri->scheme) { ejsSetPropertyByName(ejs, obj, EN("scheme"), ejsCreateStringFromAsc(ejs, uri->scheme)); } if (uri->host) { ejsSetPropertyByName(ejs, obj, EN("host"), ejsCreateStringFromAsc(ejs, uri->host)); } if (uri->port > 0) { ejsSetPropertyByName(ejs, obj, EN("port"), ejsCreateNumber(ejs, uri->port)); } if (uri->path) { ejsSetPropertyByName(ejs, obj, EN("path"), ejsCreateStringFromAsc(ejs, uri->path)); } if (uri->reference) { ejsSetPropertyByName(ejs, obj, EN("reference"), ejsCreateStringFromAsc(ejs, uri->reference)); } if (uri->query) { ejsSetPropertyByName(ejs, obj, EN("query"), ejsCreateStringFromAsc(ejs, uri->query)); } return obj; }
/* * Search for an item using strict equality "===". This call searches from * the end of the array for the specified element. * @return Returns the items index into the array if found, otherwise -1. * * function lastIndexOf(element: Object, fromIndex: Number = -1): Number */ static EjsVar *lastArrayIndexOf(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsVar *element; int i, start; mprAssert(argc == 1 || argc == 2); element = argv[0]; start = ((argc == 2) ? (int) ((EjsNumber*) argv[1])->value : ap->length - 1); if (start < 0) { start += ap->length; } if (start >= ap->length) { start = ap->length - 1; } if (start < 0) { return (EjsVar*) ejs->minusOneValue; } for (i = start; i >= 0; i--) { if (compareArrayElement(ejs, ap->data[i], element)) { return (EjsVar*) ejsCreateNumber(ejs, i); } } return (EjsVar*) ejs->minusOneValue; }
/** * 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; }
/* Search for an item using strict equality "===". This call searches from the start of the array for the specified element. @return Returns the items index into the array if found, otherwise -1. function indexOf(element: Object, startIndex: Number = 0): Number */ static EjsNumber *indexOfArray(Ejs *ejs, EjsArray *ap, int argc, EjsObj **argv) { EjsObj *element; int i, start; assert(argc == 1 || argc == 2); element = argv[0]; start = (argc == 2) ? (int) ((EjsNumber*) argv[1])->value : 0; if (start < 0) { start += ap->length; } if (start >= ap->length) { return ESV(minusOne); } if (start < 0) { start = 0; } for (i = start; i < ap->length; i++) { if (compareArrayElement(ejs, ap->data[i], element)) { return ejsCreateNumber(ejs, i); } } return ESV(minusOne); }
/* Function to iterate and return the next element name. NOTE: this is not a method of Array. Rather, it is a callback function for Iterator */ static EjsNumber *nextArrayKey(Ejs *ejs, EjsIterator *ip, int argc, EjsObj **argv) { EjsArray *ap; EjsObj *vp, **data; ap = (EjsArray*) ip->target; if (!ejsIs(ejs, ap, Array)) { ejsThrowReferenceError(ejs, "Wrong type"); return 0; } data = ap->data; if (ap->length < ip->length) { ip->length = ap->length; } for (; ip->index < ip->length; ip->index++) { vp = data[ip->index]; assert(vp); if (ejsIs(ejs, vp, Void)) { continue; } return ejsCreateNumber(ejs, ip->index++); } ejsThrowStopIteration(ejs); return 0; }
static EjsVar *getResponseVar(void *handle, int field) { Ejs *ejs; MaConn *conn; MaResponse *resp; conn = handle; resp = conn->response; ejs = ((EjsWeb*) maGetHandlerQueueData(conn))->ejs; switch (field) { case ES_ejs_web_Response_code: return (EjsVar*) ejsCreateNumber(ejs, resp->code); case ES_ejs_web_Response_filename: return (EjsVar*) createString(ejs, resp->filename); case ES_ejs_web_Response_headers: return (EjsVar*) createHeaders(ejs, conn->response->headers); case ES_ejs_web_Response_mimeType: return (EjsVar*) createString(ejs, resp->mimeType); default: ejsThrowOutOfBoundsError(ejs, "Bad property slot reference"); return 0; } }
/* * native static function get redline(): Number */ static EjsVar *getRedline(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) { MprAlloc *alloc; alloc = mprGetAllocStats(ejs); return (EjsVar*) ejsCreateNumber(ejs, (int) alloc->redLine); }
/* * native static function get peak(): Number */ static EjsVar *getPeakMemory(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) { MprAlloc *alloc; alloc = mprGetAllocStats(ejs); return (EjsVar*) ejsCreateNumber(ejs, (int) alloc->peakAllocated); }
/* * native static function get system(): Number */ static EjsVar *getSystemRam(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv) { MprAlloc *alloc; alloc = mprGetAllocStats(ejs); return (EjsVar*) ejsCreateNumber(ejs, (double) alloc->ram); }
EjsArray *ejsCaptureStack(Ejs *ejs, int uplevels) { EjsFrame *fp; EjsState *state; EjsArray *stack; wchar *source; EjsObj *frame; char *filename; int index, lineNumber; assert(ejs); stack = ejsCreateArray(ejs, 0); index = 0; for (state = ejs->state; state; state = state->prev) { for (fp = state->fp; fp; fp = fp->caller) { if (uplevels-- <= 0) { frame = ejsCreateEmptyPot(ejs); if (ejsGetDebugInfo(ejs, (EjsFunction*) fp, fp->pc, &filename, &lineNumber, &source) >= 0) { ejsSetPropertyByName(ejs, frame, EN("filename"), ejsCreatePathFromAsc(ejs, filename)); ejsSetPropertyByName(ejs, frame, EN("lineno"), ejsCreateNumber(ejs, lineNumber)); ejsSetPropertyByName(ejs, frame, EN("code"), ejsCreateString(ejs, source, wlen(source))); } else { ejsSetPropertyByName(ejs, frame, EN("filename"), EST(undefined)); } ejsSetPropertyByName(ejs, frame, EN("func"), fp->function.name); ejsSetProperty(ejs, stack, index++, frame); } } } return stack; }
/* static function get uid(): Number */ static EjsNumber *app_uid(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { #if ME_UNIX_LIKE return ejsCreateNumber(ejs, getuid()); #else return ESV(null); #endif }
/* Get the current I/O position in the file. function get position(): Number */ static EjsObj *getFilePosition(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { if (fp->file == 0) { ejsThrowStateError(ejs, "File not opened"); return 0; } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) mprGetFilePosition(fp->file)); }
/* Get the size of the file associated with this File object. override function get size(): Number */ static EjsObj *getFileSize(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { MprPath info; if (mprGetPathInfo(fp->path, &info) < 0) { return (EjsObj*) ESV(minusOne); } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) info.size); }
static EjsObj *getFileOptions(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsObj *options; options = (EjsObj*) ejsCreateEmptyPot(ejs); ejsSetPropertyByName(ejs, options, EN("mode"), ejsCreateStringFromAsc(ejs, fp->modeString)); ejsSetPropertyByName(ejs, options, EN("permissions"), ejsCreateNumber(ejs, fp->perms)); return options; }
/* function get contentLength(): Number */ static EjsNumber *http_contentLength(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { MprOff length; if (!waitForResponseHeaders(hp)) { return 0; } length = httpGetContentLength(hp->conn); return ejsCreateNumber(ejs, (MprNumber) length); }
/* Write data to the file function write(data: Object): Number */ PUBLIC EjsObj *writeFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ap; EjsObj *vp; EjsString *str; cchar *buf; ssize len, written; int i; assert(argc == 1 && ejsIs(ejs, argv[0], Array)); args = (EjsArray*) argv[0]; if (!(fp->mode & EJS_FILE_WRITE)) { ejsThrowStateError(ejs, "File not opened for writing"); return 0; } written = 0; for (i = 0; i < args->length; i++) { vp = ejsGetProperty(ejs, (EjsObj*) args, i); assert(vp); switch (TYPE(vp)->sid) { case S_ByteArray: ap = (EjsByteArray*) vp; // TODO UNICODE ENCODING buf = (cchar*) &ap->value[ap->readPosition]; len = ap->writePosition - ap->readPosition; break; case S_String: // UNICODE #if UNICODE && FUTURE buf = awtom(((EjsString*) vp)->value, &len); #else buf = ((EjsString*) vp)->value; len = ((EjsString*) vp)->length; #endif break; default: str = ejsToString(ejs, vp); buf = awtom(((EjsString*) str)->value, &len); break; } if (mprWriteFile(fp->file, buf, len) != len) { ejsThrowIOError(ejs, "Cannot write to %s", fp->path); return 0; } written += len; /* Use GC to free buf as it may not be allocated */ } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) written); }
/* Get the port portion static function get port(): Number? */ static EjsNumber *uri_port(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { HttpUri *uri; uri = up->uri; if (uri->port <= 0) { return ESV(null); #if UNUSED if (uri->host == 0) { return ESV(null); } if (uri->scheme == 0 || strcmp(uri->scheme, "http") == 0) { return ejsCreateNumber(ejs, 80); } else if (uri->scheme && strcmp(uri->scheme, "https") == 0) { return ejsCreateNumber(ejs, 443); } #endif } return ejsCreateNumber(ejs, up->uri->port); }
/* function round(value: Number): Number */ static EjsNumber *math_round(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprNumber n; n = ejsGetNumber(ejs, argv[0]); if (-0.5 <= n && n < 0) { n = -0.0; } else { n += 0.5; } return ejsCreateNumber(ejs, floor(n)); }
/* function get status(): Number */ static EjsNumber *http_status(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { int code; if (!waitForResponseHeaders(hp)) { return 0; } code = httpGetStatus(hp->conn); if (code <= 0) { return ESV(null); } return ejsCreateNumber(ejs, code); }
/* Get a property from the object @param ejs VM handle. @param sp is set to the object instance. @param slotNum Slot number of the property to retrieve. The VM maps the property names to slots. @return the property value */ static EjsObj *getProperty(Ejs *ejs, Shape *sp, int slotNum) { mprAssert(sp); switch (slotNum) { case ES_nclass_Shape_x: return (EjsObj*) ejsCreateNumber(ejs, sp->x); case ES_nclass_Shape_y: return (EjsObj*) ejsCreateNumber(ejs, sp->x); case ES_nclass_Shape_height: return (EjsObj*) ejsCreateNumber(ejs, sp->height); case ES_nclass_Shape_width: return (EjsObj*) ejsCreateNumber(ejs, sp->width); default: ejsThrowReferenceError(ejs, "Bad slot reference"); } return 0; }
/* function sendBlock(content, options): Number */ static EjsNumber *ws_sendBlock(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsByteArray *ba; EjsAny *content, *vp; ssize nbytes; cchar *str; int last, mode, type, flags; assert(argc == 2); if (ws->conn->state < HTTP_STATE_PARSED && !waitForHttpState(ws, HTTP_STATE_PARSED, -1, 1)) { return ESV(null); } content = argv[0]; last = ejsGetPropertyByName(ejs, argv[1], EN("last")) != ESV(false); if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("mode"))) != 0) { mode = (int) ejsGetNumber(ejs, vp); if (mode != HTTP_BUFFER && mode != HTTP_BLOCK && mode != HTTP_NON_BLOCK) { ejsThrowArgError(ejs, "Bad message mode"); return 0; } } else { mode = HTTP_BUFFER; } if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("type"))) != 0) { type = (int) ejsGetNumber(ejs, vp); if (type != WS_MSG_CONT && type != WS_MSG_TEXT && type != WS_MSG_BINARY) { ejsThrowArgError(ejs, "Bad message type"); return 0; } } else { type = WS_MSG_TEXT; } flags = mode; if (!last) { flags |= HTTP_MORE; } if (ejsIs(ejs, content, ByteArray)) { ba = (EjsByteArray*) content; nbytes = ejsGetByteArrayAvailableData(ba); nbytes = httpSendBlock(ws->conn, type, (cchar*) &ba->value[ba->readPosition], nbytes, flags); } else { str = ejsToMulti(ejs, content); nbytes = httpSendBlock(ws->conn, type, str, slen(str), flags); } if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot send block"); return 0; } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
/* function get available(): Number DEPRECATED 1.0.0B3 (11/09) */ static EjsNumber *http_available(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { MprOff len; if (!waitForResponseHeaders(hp)) { return 0; } len = httpGetContentLength(hp->conn); if (len > 0) { return ejsCreateNumber(ejs, (MprNumber) len); } /* Probably should be returning null here */ return (EjsNumber*) ESV(minusOne); }
/* Parse a string based on formatting instructions and intelligently create a variable. Number formats: [(+|-)][0][OCTAL_DIGITS] [(+|-)][0][(x|X)][HEX_DIGITS] [(+|-)][DIGITS] [+|-][DIGITS][.][DIGITS][(e|E)[+|-]DIGITS] */ EjsVar *ejsParseVar(Ejs *ejs, cchar *buf, int preferredType) { int type; mprAssert(buf); type = preferredType; if (preferredType == ES_Void || preferredType < 0) { if ((*buf == '-' || *buf == '+') && isdigit((int) buf[1])) { type = ejs->numberType->id; } else if (!isdigit((int) *buf) && *buf != '.') { if (strcmp(buf, "true") == 0) { return (EjsVar*) ejs->trueValue; } else if (strcmp(buf, "false") == 0) { return (EjsVar*) ejs->falseValue; } type = ES_String; } else { type = ES_Number; } } switch (type) { case ES_Object: case ES_Void: case ES_Null: default: break; case ES_Number: return (EjsVar*) ejsCreateNumber(ejs, parseNumber(ejs, buf)); case ES_Boolean: return (EjsVar*) ejsCreateBoolean(ejs, parseBoolean(ejs, buf)); case ES_String: if (strcmp(buf, "null") == 0) { return (EjsVar*) ejsCreateNull(ejs); } else if (strcmp(buf, "undefined") == 0) { return (EjsVar*) ejsCreateUndefined(ejs); } return (EjsVar*) ejsCreateString(ejs, buf); } return (EjsVar*) ejsCreateUndefined(ejs); }
/* function emit(level: Number, ...data): Number */ static EjsNumber *lf_emit(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ap; EjsObj *vp; EjsString *str; char *msg, *arg; ssize len, written; int i, level, paused; assure(argc >= 2 && ejsIs(ejs, argv[1], Array)); level = ejsGetInt(ejs, argv[0]); args = (EjsArray*) argv[1]; written = 0; msg = 0; paused = ejsBlockGC(ejs); for (i = 0; i < args->length; i++) { vp = ejsGetProperty(ejs, args, i); assure(vp); switch (TYPE(vp)->sid) { case S_ByteArray: ap = (EjsByteArray*) vp; // TODO ENCODING arg = (char*) &ap->value[ap->readPosition]; len = ap->writePosition - ap->readPosition; break; case S_String: // MOB - use NULL instead of &len arg = awtom(((EjsString*) vp)->value, &len); break; default: str = ejsToString(ejs, vp); // MOB - use NULL instead of &len arg = awtom(((EjsString*) str)->value, &len); break; } msg = srejoin(msg, arg, NULL); } if (msg) { mprRawLog(level, "%s", msg); written += slen(msg); } ejsUnblockGC(ejs, paused); return ejsCreateNumber(ejs, (MprNumber) slen(msg)); }
/* function pow(x: Number, y: Number): Number */ static EjsNumber *math_pow(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprNumber x, y, result; x = ejsGetNumber(ejs, argv[0]); y = ejsGetNumber(ejs, argv[1]); result = pow(x, y); #if CYGWIN /* Cygwin computes (0.0 / -1) == -Infinity */ if (result < 0 && x == 0.0) { result = -result; } #endif return ejsCreateNumber(ejs, (MprNumber) result); }
/* Function to iterate and return the next element index. NOTE: this is not a method of Array. Rather, it is a callback function for Iterator */ static EjsNumber *nextKey(Ejs *ejs, EjsIterator *ip, int argc, EjsObj **argv) { EjsFile *fp; fp = (EjsFile*) ip->target; if (!ejsIs(ejs, fp, File)) { ejsThrowReferenceError(ejs, "Wrong type"); return 0; } if (ip->index < fp->info.size) { return ejsCreateNumber(ejs, ip->index++); } ejsThrowStopIteration(ejs); return 0; }
/* Read data bytes from a file. If offset is < 0, then append to the write position. function read(buffer: ByteArray, offset: Number = 0, count: Number = -1): Number */ static EjsNumber *readFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsByteArray *buffer; MprPath info; ssize offset, count, totalRead; assert(1 <= argc && argc <= 3); buffer = (EjsByteArray*) argv[0]; offset = (argc >= 2) ? ejsGetInt(ejs, argv[1]): 0; count = (argc >= 3) ? ejsGetInt(ejs, argv[2]): -1; 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 (offset >= buffer->size) { ejsThrowOutOfBoundsError(ejs, "Bad read offset value"); return 0; } if (offset < 0) { offset = buffer->writePosition; } else if (offset == 0) { ejsSetByteArrayPositions(ejs, buffer, 0, 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); } totalRead = readData(ejs, fp, buffer, offset, count); if (totalRead < 0) { return 0; } else if (totalRead == 0) { return ESV(zero); } ejsSetByteArrayPositions(ejs, buffer, -1, offset + totalRead); return ejsCreateNumber(ejs, (MprNumber) totalRead); }