/* * JX9_EOL * Expand the correct 'End Of Line' symbol for this platform. */ static void JX9_EOL_Const(jx9_value *pVal, void *pUnused) { SXUNUSED(pUnused); #ifdef __WINNT__ jx9_value_string(pVal, "\r\n", (int)sizeof("\r\n")-1); #else jx9_value_string(pVal, "\n", (int)sizeof(char)); #endif }
/* * DIRECTORY_SEPARATOR. * Expand the directory separator character. */ static void JX9_DIRSEP_Const(jx9_value *pVal, void *pUnused) { SXUNUSED(pUnused); #ifdef __WINNT__ jx9_value_string(pVal, "\\", (int)sizeof(char)); #else jx9_value_string(pVal, "/", (int)sizeof(char)); #endif }
/* * __FILE__ * Path of the processed script. */ static void JX9_FILE_Const(jx9_value *pVal, void *pUserData) { jx9_vm *pVm = (jx9_vm *)pUserData; SyString *pFile; /* Peek the top entry */ pFile = (SyString *)SySetPeek(&pVm->aFiles); if( pFile == 0 ){ /* Expand the magic word: ":MEMORY:" */ jx9_value_string(pVal, ":MEMORY:", (int)sizeof(":MEMORY:")-1); }else{ jx9_value_string(pVal, pFile->zString, pFile->nByte); } }
/* * JX9_OS * __OS__ * Expand the name of the host Operating System. */ static void JX9_OS_Const(jx9_value *pVal, void *pUnused) { #if defined(__WINNT__) jx9_value_string(pVal, "WinNT", (int)sizeof("WinNT")-1); #elif defined(__UNIXES__) struct utsname sInfo; if( uname(&sInfo) != 0 ){ jx9_value_string(pVal, "Unix", (int)sizeof("Unix")-1); }else{ jx9_value_string(pVal, sInfo.sysname, -1); } #else jx9_value_string(pVal,"Host OS", (int)sizeof("Host OS")-1); #endif SXUNUSED(pUnused); }
/* * __DIR__ * Directory holding the processed script. */ static void JX9_DIR_Const(jx9_value *pVal, void *pUserData) { jx9_vm *pVm = (jx9_vm *)pUserData; SyString *pFile; /* Peek the top entry */ pFile = (SyString *)SySetPeek(&pVm->aFiles); if( pFile == 0 ){ /* Expand the magic word: ":MEMORY:" */ jx9_value_string(pVal, ":MEMORY:", (int)sizeof(":MEMORY:")-1); }else{ if( pFile->nByte > 0 ){ const char *zDir; int nLen; zDir = jx9ExtractDirName(pFile->zString, (int)pFile->nByte, &nLen); jx9_value_string(pVal, zDir, nLen); }else{ /* Expand '.' as the current directory*/ jx9_value_string(pVal, ".", (int)sizeof(char)); } } }
/* * Dequote [i.e: Resolve all backslash escapes ] a JSON string and store * the result in the given jx9_value. */ static void VmJsonDequoteString(const SyString *pStr, jx9_value *pWorker) { const char *zIn = pStr->zString; const char *zEnd = &pStr->zString[pStr->nByte]; const char *zCur; int c; /* Mark the value as a string */ jx9_value_string(pWorker, "", 0); /* Empty string */ for(;;){ zCur = zIn; while( zIn < zEnd && zIn[0] != '\\' ){ zIn++; } if( zIn > zCur ){ /* Append chunk verbatim */ jx9_value_string(pWorker, zCur, (int)(zIn-zCur)); } zIn++; if( zIn >= zEnd ){ /* End of the input reached */ break; } c = zIn[0]; /* Unescape the character */ switch(c){ case '"': jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); break; case '\\': jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); break; case 'n': jx9_value_string(pWorker, "\n", (int)sizeof(char)); break; case 'r': jx9_value_string(pWorker, "\r", (int)sizeof(char)); break; case 't': jx9_value_string(pWorker, "\t", (int)sizeof(char)); break; case 'f': jx9_value_string(pWorker, "\f", (int)sizeof(char)); break; default: jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); break; } /* Advance the stream cursor */ zIn++; } }
/* * DATE_W3C * World Wide Web Consortium (example: 2005-08-15T15:52:01+00:00) */ static void JX9_DATE_W3C_Const(jx9_value *pVal, void *pUserData) { SXUNUSED(pUserData); /* cc warning */ jx9_value_string(pVal, "Y-m-d\\TH:i:sP", -1/*Compute length automatically*/); }
/* * DATE_RSS * RSS (Mon, 15 Aug 2005 15:52:01 +0000) */ static void JX9_DATE_RSS_Const(jx9_value *pVal, void *pUserData) { SXUNUSED(pUserData); /* cc warning */ jx9_value_string(pVal, "D, d M Y H:i:s O", -1/*Compute length automatically*/); }
/* * DATE_RFC850 * RFC 850 (example: Monday, 15-Aug-05 15:52:01 UTC) */ static void JX9_DATE_RFC850_Const(jx9_value *pVal, void *pUserData) { SXUNUSED(pUserData); /* cc warning */ jx9_value_string(pVal, "l, d-M-y H:i:s T", -1/*Compute length automatically*/); }
/* * JX9_VERSION * __JX9__ * Expand the current version of the JX9 engine. */ static void JX9_VER_Const(jx9_value *pVal, void *pUnused) { SXUNUSED(pUnused); jx9_value_string(pVal, jx9_lib_signature(), -1/*Compute length automatically*/); }
/* * Returns a jx9_value holding the image of a JSON string. In other word perform a JSON decoding operation. * According to wikipedia * JSON's basic types are: * Number (double precision floating-point format in JavaScript, generally depends on implementation) * String (double-quoted Unicode, with backslash escaping) * Boolean (true or false) * Array (an ordered sequence of values, comma-separated and enclosed in square brackets; the values * do not need to be of the same type) * Object (an unordered collection of key:value pairs with the ':' character separating the key * and the value, comma-separated and enclosed in curly braces; the keys must be strings and should * be distinct from each other) * null (empty) * Non-significant white space may be added freely around the "structural characters" (i.e. the brackets "[{]}", colon ":" and comma ", "). */ static sxi32 VmJsonDecode( json_decoder *pDecoder, /* JSON decoder */ jx9_value *pArrayKey /* Key for the decoded array */ ){ jx9_value *pWorker; /* Worker variable */ sxi32 rc; /* Check if we do not nest to much */ if( pDecoder->rec_count > 31 ){ /* Nesting limit reached, abort decoding immediately */ return SXERR_ABORT; } if( pDecoder->pIn->nType & (JSON_TK_STR|JSON_TK_ID|JSON_TK_TRUE|JSON_TK_FALSE|JSON_TK_NULL|JSON_TK_NUM) ){ /* Scalar value */ pWorker = jx9_context_new_scalar(pDecoder->pCtx); if( pWorker == 0 ){ jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); /* Abort the decoding operation immediately */ return SXERR_ABORT; } /* Reflect the JSON image */ if( pDecoder->pIn->nType & JSON_TK_NULL ){ /* Nullify the value.*/ jx9_value_null(pWorker); }else if( pDecoder->pIn->nType & (JSON_TK_TRUE|JSON_TK_FALSE) ){ /* Boolean value */ jx9_value_bool(pWorker, (pDecoder->pIn->nType & JSON_TK_TRUE) ? 1 : 0 ); }else if( pDecoder->pIn->nType & JSON_TK_NUM ){ SyString *pStr = &pDecoder->pIn->sData; /* * Numeric value. * Get a string representation first then try to get a numeric * value. */ jx9_value_string(pWorker, pStr->zString, (int)pStr->nByte); /* Obtain a numeric representation */ jx9MemObjToNumeric(pWorker); }else if( pDecoder->pIn->nType & JSON_TK_ID ){ SyString *pStr = &pDecoder->pIn->sData; jx9_value_string(pWorker, pStr->zString, (int)pStr->nByte); }else{ /* Dequote the string */ VmJsonDequoteString(&pDecoder->pIn->sData, pWorker); } /* Invoke the consumer callback */ rc = pDecoder->xConsumer(pDecoder->pCtx, pArrayKey, pWorker, pDecoder->pUserData); if( rc == SXERR_ABORT ){ return SXERR_ABORT; } /* All done, advance the stream cursor */ pDecoder->pIn++; }else if( pDecoder->pIn->nType & JSON_TK_OSB /*'[' */) { ProcJSONConsumer xOld; void *pOld; /* Array representation*/ pDecoder->pIn++; /* Create a working array */ pWorker = jx9_context_new_array(pDecoder->pCtx); if( pWorker == 0 ){ jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); /* Abort the decoding operation immediately */ return SXERR_ABORT; } /* Save the old consumer */ xOld = pDecoder->xConsumer; pOld = pDecoder->pUserData; /* Set the new consumer */ pDecoder->xConsumer = VmJsonArrayDecoder; pDecoder->pUserData = pWorker; /* Decode the array */ for(;;){ /* Jump trailing comma. Note that the standard JX9 engine will not let you * do this. */ while( (pDecoder->pIn < pDecoder->pEnd) && (pDecoder->pIn->nType & JSON_TK_COMMA) ){ pDecoder->pIn++; } if( pDecoder->pIn >= pDecoder->pEnd || (pDecoder->pIn->nType & JSON_TK_CSB) /*']'*/ ){ if( pDecoder->pIn < pDecoder->pEnd ){ pDecoder->pIn++; /* Jump the trailing ']' */ } break; } /* Recurse and decode the entry */ pDecoder->rec_count++; rc = VmJsonDecode(pDecoder, 0); pDecoder->rec_count--; if( rc == SXERR_ABORT ){ /* Abort processing immediately */ return SXERR_ABORT; } /*The cursor is automatically advanced by the VmJsonDecode() function */ if( (pDecoder->pIn < pDecoder->pEnd) && ((pDecoder->pIn->nType & (JSON_TK_CSB/*']'*/|JSON_TK_COMMA/*','*/))==0) ){ /* Unexpected token, abort immediatley */ *pDecoder->pErr = SXERR_SYNTAX; return SXERR_ABORT; } } /* Restore the old consumer */ pDecoder->xConsumer = xOld; pDecoder->pUserData = pOld; /* Invoke the old consumer on the decoded array */ xOld(pDecoder->pCtx, pArrayKey, pWorker, pOld); }else if( pDecoder->pIn->nType & JSON_TK_OCB /*'{' */) { ProcJSONConsumer xOld; jx9_value *pKey; void *pOld; /* Object representation*/ pDecoder->pIn++; /* Create a working array */ pWorker = jx9_context_new_array(pDecoder->pCtx); pKey = jx9_context_new_scalar(pDecoder->pCtx); if( pWorker == 0 || pKey == 0){ jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); /* Abort the decoding operation immediately */ return SXERR_ABORT; } /* Save the old consumer */ xOld = pDecoder->xConsumer; pOld = pDecoder->pUserData; /* Set the new consumer */ pDecoder->xConsumer = VmJsonArrayDecoder; pDecoder->pUserData = pWorker; /* Decode the object */ for(;;){ /* Jump trailing comma. Note that the standard JX9 engine will not let you * do this. */ while( (pDecoder->pIn < pDecoder->pEnd) && (pDecoder->pIn->nType & JSON_TK_COMMA) ){ pDecoder->pIn++; } if( pDecoder->pIn >= pDecoder->pEnd || (pDecoder->pIn->nType & JSON_TK_CCB) /*'}'*/ ){ if( pDecoder->pIn < pDecoder->pEnd ){ pDecoder->pIn++; /* Jump the trailing ']' */ } break; } if( (pDecoder->pIn->nType & (JSON_TK_ID|JSON_TK_STR)) == 0 || &pDecoder->pIn[1] >= pDecoder->pEnd || (pDecoder->pIn[1].nType & JSON_TK_COLON) == 0){ /* Syntax error, return immediately */ *pDecoder->pErr = SXERR_SYNTAX; return SXERR_ABORT; } if( pDecoder->pIn->nType & JSON_TK_ID ){ SyString *pStr = &pDecoder->pIn->sData; jx9_value_string(pKey, pStr->zString, (int)pStr->nByte); }else{ /* Dequote the key */ VmJsonDequoteString(&pDecoder->pIn->sData, pKey); } /* Jump the key and the colon */ pDecoder->pIn += 2; /* Recurse and decode the value */ pDecoder->rec_count++; rc = VmJsonDecode(pDecoder, pKey); pDecoder->rec_count--; if( rc == SXERR_ABORT ){ /* Abort processing immediately */ return SXERR_ABORT; } /* Reset the internal buffer of the key */ jx9_value_reset_string_cursor(pKey); /*The cursor is automatically advanced by the VmJsonDecode() function */ } /* Restore the old consumer */ pDecoder->xConsumer = xOld; pDecoder->pUserData = pOld; /* Invoke the old consumer on the decoded object*/ xOld(pDecoder->pCtx, pArrayKey, pWorker, pOld); /* Release the key */ jx9_context_release_value(pDecoder->pCtx, pKey); }else{ /* Unexpected token */ return SXERR_ABORT; /* Abort immediately */ } /* Release the worker variable */ jx9_context_release_value(pDecoder->pCtx, pWorker); return SXRET_OK; }