static EjsVar *getHostVar(void *handle, int field) { switch (field) { case ES_ejs_web_Host_documentRoot: return createString(ejs, getHeader(handle, "DOCUMENT_ROOT")); case ES_ejs_web_Host_name: return createString(ejs, getHeader(handle, "SERVER_NAME")); case ES_ejs_web_Host_protocol: return createString(ejs, getHeader(handle, "REQUEST_TRANSPORT")); #if TODO case ES_ejs_web_Host_isVirtualHost: return (EjsVar*) ejsCreateBoolean(ejs, host->flags & MA_HOST_VHOST); case ES_ejs_web_Host_isNamedVirtualHost: return (EjsVar*) ejsCreateBoolean(ejs, host->flags & MA_HOST_NAMED_VHOST); #endif case ES_ejs_web_Host_software: return createString(ejs, EJS_SERVER_NAME); case ES_ejs_web_Host_logErrors: return (EjsVar*) ((web->flags & EJS_WEB_FLAG_BROWSER_ERRORS) ? ejs->falseValue : ejs->trueValue); } ejsThrowOutOfBoundsError(ejs, "Bad property slot reference"); return 0; }
/* function get finalized(): Boolean */ static EjsBoolean *http_finalized(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { if (hp->conn) { return ejsCreateBoolean(ejs, hp->conn->tx->finalizedOutput); } return ESV(false); }
/* Handle all core operators. We currenly handle only === and !== TODO. Must implement: +, -, <, >, <=, >=, ==, ===, !=, !==, &, | */ static EjsObj *invokeOperator(Ejs *ejs, EjsXML *lhs, int opCode, EjsXML *rhs) { EjsObj *l, *r; bool boolResult; assure(ejsIsXML(ejs, lhs)); assure(ejsIsXML(ejs, rhs)); // TODO - Complete switch (opCode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: boolResult = (lhs == rhs); break; case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: boolResult = !(lhs == rhs); break; default: /* Cast to strings and re-invoke */ l = ejsCast(ejs, lhs, String); r = ejsCast(ejs, rhs, String); return ejsInvokeOperator(ejs, l, opCode, r); } return (EjsObj*) ejsCreateBoolean(ejs, boolResult); }
static EjsAny *invokeNamespaceOperator(Ejs *ejs, EjsNamespace *lhs, int opCode, EjsNamespace *rhs) { bool boolResult; switch (opCode) { case EJS_OP_COMPARE_EQ: if (!ejsIsDefined(ejs, rhs)) { return ((opCode == EJS_OP_COMPARE_EQ) ? ESV(false): ESV(true)); } boolResult = ejsCompareString(ejs, lhs->value, rhs->value) == 0; break; case EJS_OP_COMPARE_STRICTLY_EQ: boolResult = lhs == rhs; break; case EJS_OP_COMPARE_NE: if (!ejsIsDefined(ejs, rhs)) { return ((opCode == EJS_OP_COMPARE_EQ) ? ESV(false): ESV(true)); } boolResult = !(ejsCompareString(ejs, lhs->value, rhs->value) == 0); break; case EJS_OP_COMPARE_STRICTLY_NE: boolResult = !(lhs == rhs); break; default: ejsThrowTypeError(ejs, "Operation is not valid on this type"); return 0; } return ejsCreateBoolean(ejs, boolResult); }
/* Determine if the file name is a directory. This function get isDir(): Boolean */ static EjsBoolean *uri_isDir(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { HttpUri *uri; uri = up->uri; return ejsCreateBoolean(ejs, uri->path[strlen(uri->path) - 1] == '/'); }
/* Compare two Uris function same(other: String, exact: Boolean = false): Boolean */ static EjsObj *uri_same(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { EjsUri *other; int exact; other = (EjsUri*) argv[0]; exact = (argc == 2 && argv[1] == ESV(true)); return ejsCreateBoolean(ejs, same(ejs, up->uri, other->uri, exact)); }
static EjsObj *invokeXmlOperator(Ejs *ejs, EjsXML *lhs, int opcode, EjsXML *rhs) { EjsObj *result; if ((result = ejsCoerceOperands(ejs, (EjsObj*) lhs, opcode, (EjsObj*) rhs)) != 0) { return result; } switch (opcode) { case EJS_OP_COMPARE_EQ: return (EjsObj*) ejsCreateBoolean(ejs, deepCompare(lhs, rhs)); case EJS_OP_COMPARE_NE: return (EjsObj*) ejsCreateBoolean(ejs, !deepCompare(lhs, rhs)); default: return ejsInvokeOperatorDefault(ejs, (EjsObj*) lhs, opcode, (EjsObj*) rhs); } }
static EjsVar *invokeOperator(Ejs *ejs, EjsVar *lhs, int opCode, EjsVar *rhs) { switch (opCode) { case EJS_OP_BRANCH_EQ: case EJS_OP_BRANCH_STRICTLY_EQ: return (EjsVar*) ejsCreateBoolean(ejs, lhs == rhs); case EJS_OP_BRANCH_NE: case EJS_OP_BRANCH_STRICTLY_NE: return (EjsVar*) ejsCreateBoolean(ejs, !(lhs == rhs)); default: /* * Pass to the standard Object helpers to implement Object methods. */ return (ejs->objectHelpers->invokeOperator)(ejs, lhs, opCode, rhs); } return 0; }
/* Implement byte code operators. @param ejs VM handle. @param lhs Left hand side object. @param opCode Bytecode opcode to invoke. @param rhs Right hand side object. */ static EjsObj *invokeOperator(Ejs *ejs, Shape *lhs, int opCode, Shape *rhs) { switch (opCode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_GE: return (EjsObj*) ejsCreateBoolean(ejs, lhs == rhs); case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GT: return (EjsObj*) ejsCreateBoolean(ejs, !(lhs == rhs)); default: /* Pass to the standard Object helpers to implement other op codes */ return (ejs->defaultHelpers->invokeOperator)(ejs, (EjsObj*) lhs, opCode, (EjsObj*) rhs); } return 0; }
/* Cast the object operand to a primitive type */ static EjsObj *xlCast(Ejs *ejs, EjsXML *vp, EjsType *type) { MprBuf *buf; EjsObj *result; EjsXML *elt, *item; int next; if (type == ESV(XML)) { return (EjsObj*) vp; } switch (type->sid) { case S_Object: case S_Boolean: return (EjsObj*) ejsCreateBoolean(ejs, 1); case S_Number: result = xlCast(ejs, vp, ESV(String)); result = (EjsObj*) ejsToNumber(ejs, result); return result; case S_String: buf = mprCreateBuf(MPR_BUFSIZE, -1); if (mprGetListLength(vp->elements) == 1) { elt = mprGetFirstItem(vp->elements); if (elt->kind == EJS_XML_ELEMENT) { if (elt->elements == 0) { return (EjsObj*) ESV(empty); } if (elt->elements && mprGetListLength(elt->elements) == 1) { // TODO - what about PI and comments? item = mprGetFirstItem(elt->elements); if (item->kind == EJS_XML_TEXT) { return (EjsObj*) item->value; } } } } for (next = 0; (elt = mprGetNextItem(vp->elements, &next)) != 0; ) { if (ejsXMLToBuf(ejs, buf, elt, -1) < 0) { return 0; } if (next < vp->elements->length) { mprPutStringToBuf(buf, " "); } } return (EjsObj*) ejsCreateStringFromAsc(ejs, (char*) buf->start); default: ejsThrowTypeError(ejs, "Cannot cast to this type"); return 0; } }
static EjsVar *getHostVar(void *handle, int field) { Ejs *ejs; MaConn *conn; MaHost *host; EjsWeb *web; conn = handle; host = conn->host; ejs = ((EjsWeb*) maGetHandlerQueueData(conn))->ejs; switch (field) { case ES_ejs_web_Host_documentRoot: return createString(ejs, host->documentRoot); case ES_ejs_web_Host_name: return createString(ejs, host->name); case ES_ejs_web_Host_protocol: return createString(ejs, host->secure ? "https" : "http"); case ES_ejs_web_Host_isVirtualHost: return (EjsVar*) ejsCreateBoolean(ejs, host->flags & MA_HOST_VHOST); case ES_ejs_web_Host_isNamedVirtualHost: return (EjsVar*) ejsCreateBoolean(ejs, host->flags & MA_HOST_NAMED_VHOST); case ES_ejs_web_Host_software: return createString(ejs, MA_SERVER_NAME); case ES_ejs_web_Host_logErrors: web = ejs->handle; return (EjsVar*) ((web->flags & EJS_WEB_FLAG_BROWSER_ERRORS) ? ejs->falseValue : ejs->trueValue); } ejsThrowOutOfBoundsError(ejs, "Bad property slot reference"); return 0; }
static EjsAny *castNamespace(Ejs *ejs, EjsNamespace *vp, EjsType *type) { switch (type->sid) { case S_Boolean: return ejsCreateBoolean(ejs, 1); case S_String: return vp->value; default: ejsThrowTypeError(ejs, "Cannot cast to this type"); return 0; } }
/* 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); }
/* Cast the object operand to a primitive type */ static EjsAny *castXml(Ejs *ejs, EjsXML *xml, EjsType *type) { EjsXML *item; EjsObj *result; MprBuf *buf; assert(ejsIsXML(ejs, xml)); if (type == ESV(XMLList)) { return xml; } switch (type->sid) { case S_Object: case S_Boolean: return ejsCreateBoolean(ejs, 1); case S_Number: result = castXml(ejs, xml, ESV(String)); return ejsToNumber(ejs, result); case S_String: if (xml->kind == EJS_XML_ELEMENT) { if (xml->elements == 0) { return ESV(empty); } if (xml->elements && mprGetListLength(xml->elements) == 1) { // TODO - what about PI and comments? item = mprGetFirstItem(xml->elements); if (item->kind == EJS_XML_TEXT) { return item->value; } } } buf = mprCreateBuf(BIT_MAX_BUFFER, -1); if (ejsXMLToBuf(ejs, buf, xml, -1) < 0) { return 0; } return ejsCreateStringFromAsc(ejs, (char*) buf->start); default: ejsThrowTypeError(ejs, "Cannot cast to this type"); return 0; } return 0; }
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; } }
/* Cast the operand to the specified type function cast(type: Type) : Object */ static EjsAny *castError(Ejs *ejs, EjsError *error, EjsType *type) { EjsString *stack, *msg; EjsString *us; char *buf; switch (type->sid) { case S_Boolean: return ejsCreateBoolean(ejs, 1); case S_String: stack = (EjsString*) ejsRunFunctionBySlot(ejs, error, ES_Error_formatStack, 0, NULL); us = ejsIs(ejs, stack, String) ? stack : ESV(empty); msg = ejsGetProperty(ejs, error, ES_Error_message); if ((buf = sfmt("%@ Exception: %@\nStack:\n%@\n", TYPE(error)->qname.name, msg, us)) == NULL) { ejsThrowMemoryError(ejs); } return ejsCreateStringFromAsc(ejs, buf); default: ejsThrowTypeError(ejs, "Unknown type"); } return 0; }
/* * Run an operator on the operands */ static EjsVar *invokeBooleanOperator(Ejs *ejs, EjsBoolean *lhs, int opcode, EjsBoolean *rhs) { EjsVar *result; if (rhs == 0 || lhs->var.type != rhs->var.type) { if ((result = coerceBooleanOperands(ejs, (EjsVar*) lhs, opcode, (EjsVar*) rhs)) != 0) { return result; } } /* * Types now match */ switch (opcode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: return (EjsVar*) ((lhs->value == rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: return (EjsVar*) ((lhs->value != rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_LT: return (EjsVar*) ((lhs->value < rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_LE: return (EjsVar*) ((lhs->value <= rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_GT: return (EjsVar*) ((lhs->value > rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_GE: return (EjsVar*) ((lhs->value >= rhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_NOT_ZERO: return (EjsVar*) ((lhs->value) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_ZERO: return (EjsVar*) ((lhs->value == 0) ? ejs->trueValue: ejs->falseValue); case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NULL: return (EjsVar*) ejs->falseValue; case EJS_OP_COMPARE_FALSE: return (EjsVar*) ((lhs->value) ? ejs->falseValue: ejs->trueValue); case EJS_OP_COMPARE_TRUE: return (EjsVar*) ((lhs->value) ? ejs->trueValue: ejs->falseValue); /* * Unary operators */ case EJS_OP_NEG: return (EjsVar*) ejsCreateNumber(ejs, - lhs->value); case EJS_OP_LOGICAL_NOT: return (EjsVar*) ejsCreateBoolean(ejs, !lhs->value); case EJS_OP_NOT: return (EjsVar*) ejsCreateBoolean(ejs, ~lhs->value); /* * Binary operations */ case EJS_OP_ADD: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value + rhs->value); case EJS_OP_AND: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value & rhs->value); case EJS_OP_DIV: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value / rhs->value); case EJS_OP_MUL: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value * rhs->value); case EJS_OP_OR: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value | rhs->value); case EJS_OP_REM: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value % rhs->value); case EJS_OP_SUB: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value - rhs->value); case EJS_OP_USHR: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value >> rhs->value); case EJS_OP_XOR: return (EjsVar*) ejsCreateBoolean(ejs, lhs->value ^ rhs->value); default: ejsThrowTypeError(ejs, "Opcode %d not implemented for type %s", opcode, lhs->var.type->qname.name); return 0; } }
/* * Parse a string based on formatting instructions and intelligently create a variable. * * Float and decimal format: [+|-]DIGITS][DIGITS][(e|E)[+|-]DIGITS] * * TODO - refactor all this number parsing. */ EjsVar *ejsParseVar(Ejs *ejs, cchar *buf, int preferredType) { cchar *cp; int isHex, type; mprAssert(buf); type = preferredType; isHex = 0; if (preferredType == ES_Void || preferredType < 0) { if (*buf == '-' || *buf == '+') { type = ejs->numberType->id; } else if (!isdigit((int) *buf)) { if (strcmp(buf, "true") == 0 || strcmp(buf, "false") == 0) { type = ES_Boolean; } else { type = ES_String; } } else { if (buf[0] == '0' && tolower((int) buf[1]) == 'x') { isHex = 1; for (cp = &buf[2]; *cp; cp++) { if (! isxdigit((int) *cp)) { break; } } } else { for (cp = buf; *cp; cp++) { if (! isdigit((int) *cp)) { #if BLD_FEATURE_FLOATING_POINT int c = tolower((int) *cp); if (c != '.' && c != 'e' && c != 'f') #endif break; } } } if (*cp == '\0') { type = ES_Number; } else { type = ES_String; } } } switch (type) { case ES_Object: case ES_Void: case ES_Null: default: break; case ES_Number: return (EjsVar*) ejsCreateNumber(ejs, parseNumber(ejs, buf, isHex)); 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); }
/* Determine if the uri has a scheme static function get hasScheme(): Boolean */ static EjsBoolean *uri_hasScheme(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, up->uri->scheme); }
/* function get isAbsolute(): Boolean */ static EjsBoolean *uri_isAbsolute(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, up->uri->path[0] == '/'); }
/* function get isSecure(): Boolean */ static EjsBoolean *http_isSecure(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, hp->conn->secure); }
/* function get followRedirects(): Boolean */ static EjsBoolean *http_followRedirects(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, hp->conn->followRedirects); }
static EjsBoolean *regex_getGlobalFlag(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, rp->global); }
static EjsBoolean *regex_getMultiline(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, rp->multiline); }
static void onWebSocketEvent(EjsWebSocket *ws, int event, EjsAny *data, HttpPacket *packet) { Ejs *ejs; EjsAny *eobj; EjsFunction *fn; HttpRx *rx; cchar *eventName, *reason; int slot, status; ejs = ws->ejs; rx = ws->conn->rx; eobj = ejsCreateObj(ejs, ESV(Object), 0); slot = -1; eventName = 0; switch(event) { case HTTP_EVENT_READABLE: slot = ES_WebSocket_onmessage; eventName = "readable"; assert(data); ejsSetPropertyByName(ejs, eobj, EN("data"), data); ejsSetPropertyByName(ejs, eobj, EN("last"), ejsCreateBoolean(ejs, packet->last)); ejsSetPropertyByName(ejs, eobj, EN("type"), ejsCreateNumber(ejs, packet->type)); break; case HTTP_EVENT_ERROR: eventName = "error"; slot = ES_WebSocket_onerror; break; case HTTP_EVENT_APP_OPEN: slot = ES_WebSocket_onopen; eventName = "headers"; if (rx->webSocket) { httpSetWebSocketPreserveFrames(ws->conn, ws->frames); } break; case HTTP_EVENT_DESTROY: if (ws->closed) { break; } ws->closed = 1; /* Fall through to close */ case HTTP_EVENT_APP_CLOSE: eventName = "complete"; slot = ES_WebSocket_onclose; status = rx ? rx->webSocket->closeStatus: WS_STATUS_COMMS_ERROR; reason = rx ? rx->webSocket->closeReason: 0; ejsSetPropertyByName(ejs, eobj, EN("code"), ejsCreateNumber(ejs, status)); ejsSetPropertyByName(ejs, eobj, EN("reason"), ejsCreateStringFromAsc(ejs, reason)); ejsSetPropertyByName(ejs, eobj, EN("wasClean"), ejsCreateBoolean(ejs, status != WS_STATUS_COMMS_ERROR)); break; } if (slot >= 0) { if (ws->emitter) { ejsSendEvent(ejs, ws->emitter, eventName, ws, data); } fn = ejsGetProperty(ejs, ws, slot); if (ejsIsFunction(ejs, fn) && !ejs->exception) { ejsRunFunction(ejs, fn, ws, 1, &eobj); } } }
/* function get canRead(): Boolean */ static EjsBoolean *canReadFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, fp->mode & EJS_FILE_OPEN && (fp->mode & EJS_FILE_READ)); }
static EjsBoolean *regex_getIgnoreCase(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, rp->ignoreCase); }
/* function get canRead(): Boolean */ static EjsBoolean *canWriteFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, fp->mode & EJS_FILE_OPEN && (fp->mode & EJS_FILE_WRITE)); }
static EjsBoolean *regex_sticky(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { return ejsCreateBoolean(ejs, rp->sticky); }
/* function get isOpen(): Boolean */ static EjsObj *isFileOpen(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { return (EjsObj*) ejsCreateBoolean(ejs, fp->mode & EJS_FILE_OPEN); }