Example #1
0
/*JSON{
  "type" : "method",
  "class" : "Function",
  "name" : "bind",
  "generate" : "jswrap_function_bind",
  "params" : [
    ["this","JsVar","The value to use as the 'this' argument when executing the function"],
    ["params","JsVarArray","Optional Default parameters that are prepended to the call"]
  ],
  "return" : ["JsVar","The 'bound' function"]
}
This executes the function with the supplied 'this' argument and parameters
 */
JsVar *jswrap_function_bind(JsVar *parent, JsVar *thisArg, JsVar *argsArray) {
  if (!jsvIsFunction(parent)) {
    jsExceptionHere(JSET_TYPEERROR, "Function.bind expects to be called on function, got %t", parent);
    return 0;
  }
  JsVar *fn;
  if (jsvIsNativeFunction(parent))
    fn = jsvNewNativeFunction(parent->varData.native.ptr, parent->varData.native.argTypes);
  else
    fn = jsvNewWithFlags(JSV_FUNCTION);
  if (!fn) return 0;

  // Old function info
  JsvObjectIterator fnIt;
  jsvObjectIteratorNew(&fnIt, parent);
  // add previously bound arguments
  while (jsvObjectIteratorHasValue(&fnIt)) {
    JsVar *param = jsvObjectIteratorGetKey(&fnIt);
    JsVar *defaultValue = jsvObjectIteratorGetValue(&fnIt);
    bool wasBound = jsvIsFunctionParameter(param) && defaultValue;
    if (wasBound) {
      JsVar *newParam = jsvCopy(param);
      if (newParam) { // could be out of memory
        jsvAddName(fn, newParam);
        jsvUnLock(newParam);
      }
    }
    jsvUnLock2(param, defaultValue);
    if (!wasBound) break;
    jsvObjectIteratorNext(&fnIt);
  }

  // add bound arguments
  JsvObjectIterator argIt;
  jsvObjectIteratorNew(&argIt, argsArray);
  while (jsvObjectIteratorHasValue(&argIt)) {
    JsVar *defaultValue = jsvObjectIteratorGetValue(&argIt);
    bool addedParam = false;
    while (!addedParam && jsvObjectIteratorHasValue(&fnIt)) {
      JsVar *param = jsvObjectIteratorGetKey(&fnIt);
      if (!jsvIsFunctionParameter(param)) {
        jsvUnLock(param);
        break;
      }
      JsVar *newParam = jsvCopyNameOnly(param, false,  true);
      jsvSetValueOfName(newParam, defaultValue);
      jsvAddName(fn, newParam);
      addedParam = true;
      jsvUnLock2(param, newParam);
      jsvObjectIteratorNext(&fnIt);
    }

    if (!addedParam) {
      JsVar *paramName = jsvNewFromEmptyString();
      if (paramName) {
        jsvMakeFunctionParameter(paramName); // force this to be called a function parameter
        jsvSetValueOfName(paramName, defaultValue);
        jsvAddName(fn, paramName);
        jsvUnLock(paramName);
      }
    }
    jsvUnLock(defaultValue);
    jsvObjectIteratorNext(&argIt);
  }
  jsvObjectIteratorFree(&argIt);

  // Copy the rest of the old function's info
  while (jsvObjectIteratorHasValue(&fnIt)) {
    JsVar *param = jsvObjectIteratorGetKey(&fnIt);
    JsVar *newParam = jsvCopyNameOnly(param, true, true);
    if (newParam) { // could be out of memory
      jsvAddName(fn, newParam);
      jsvUnLock(newParam);
    }
    jsvUnLock(param);
    jsvObjectIteratorNext(&fnIt);
  }
  jsvObjectIteratorFree(&fnIt);
  // Add 'this'
  jsvObjectSetChild(fn, JSPARSE_FUNCTION_THIS_NAME, thisArg); // no unlock needed

  return fn;
}
Example #2
0
/*JSON{
  "type" : "init",
  "generate" : "jswrap_wice_init"
}*/
void jswrap_wice_init() {
  jspCallNamedFunction(execInfo.root, "USB.setConsole", 0, 0);
  jspEvaluate("USB.setConsole();");
#ifdef WICE_DEBUG
  WDEBUGLN("USB is console");
#endif
  /*JsVar *mode = jsvNewFromString("output");
  jswrap_io_pinMode(jshGetPinFromString(PIN_DASH7_XTAL_EN), mode);
  jswrap_io_pinMode(jshGetPinFromString(PIN_DASH7_RST), mode);
  jsvUnLock(mode);*/

  enableDASH();

  // Set up the DASH7 USART how we want it
  JshUSARTInfo inf;
  jshUSARTInitInfo(&inf);
  inf.baudRate = 115200;
  inf.pinRX = jshGetPinFromString(PIN_DASH7_RX);
  inf.pinTX = jshGetPinFromString(PIN_DASH7_TX);
  jshUSARTSetup(EV_SERIAL1, &inf);

  JsVar *serial = jspGetNamedField(execInfo.root, SERIAL1_DASH7, false);
  jswrap_object_addEventListener(serial, "data", dash7Callback, JSWAT_VOID | (JSWAT_JSVAR<<(JSWAT_BITS)));
  jsvUnLock(serial);

  startTime = jshGetSystemTime();

  wice_msg_init(&wifiMessage, wifiMessageBuffer, 2048);
  wice_msg_init(&dash7Message, dash7MessageBuffer, 256);


  options = jspEvaluate("x = {\"repeat\": \"true\", \"edge\": \"rising\", \"debounce\":\"50\"}");
  Pin btn = jshGetPinFromString("B10");
  JsVar *btnmode = jsvNewFromString("input");
  jswrap_io_pinMode(btn, btnmode);
  jsvUnLock(btnmode);

#ifdef GATEWAY
  WDEBUGLN("GATEWAY");
  blink(PIN_GRN, 50);
  /// opendrain and digitalwrite 1 will 'opencircuit it'
  /// http://www.espruino.com/Reference#l__global_pinMode
  JsVar *opendrain = jsvNewFromString("opendrain");
  WDEBUGSTRVAR(opendrain);
  jswrap_io_pinMode(jshGetPinFromString(PIN_ESP_GPIO_0), opendrain);
  jswrap_io_pinMode(jshGetPinFromString(PIN_ESP_GPIO_2), opendrain);
  jshPinOutput(jshGetPinFromString(PIN_ESP_GPIO_0), 1);
  jshPinOutput(jshGetPinFromString(PIN_ESP_GPIO_2), 1);
  jsvUnLock(opendrain);
  /// must opendrain gpio0/2 because of boot modes
  /// https://github.com/esp8266/esp8266-wiki/wiki/Boot-Process
  enableWifi();

  // Set up the Wifi USART how we want it
  JshUSARTInfo inf4;
  jshUSARTInitInfo(&inf4);
  inf4.baudRate = 115200;
  inf4.pinRX = jshGetPinFromString(PIN_ESP_RX);
  inf4.pinTX = jshGetPinFromString(PIN_ESP_TX);
  jshUSARTSetup(EV_SERIAL4, &inf4);

  /// make button restart wifi for gateway
  JsVar *restartWifi_fn = jsvNewNativeFunction(restartWifi, JSWAT_VOID);
  btnEvent = jswrap_interface_setWatch(restartWifi_fn,
                            btn, 
                            options);
  jsvUnLock(restartWifi_fn);
  /// configure wifi usart callback
  JsVar *wifiSerial = jspGetNamedField(execInfo.root, SERIAL4_WIFI, false);
  jswrap_object_addEventListener(wifiSerial, "data", wifiCallback, JSWAT_VOID | (JSWAT_JSVAR<<(JSWAT_BITS)));
  jsvUnLock(wifiSerial);
  doSendSerial();
#else 
  WDEBUGLN("NODE");
  blink(PIN_BLUE, 50);
  /// make button a forced measurement for nodes
  JsVar *doMeasurementAndWaitForResponse_fn = jsvNewNativeFunction(doMeasurementAndWaitForResponse, JSWAT_VOID);
  btnEvent = jswrap_interface_setWatch(doMeasurementAndWaitForResponse_fn,
                            btn, 
                            options);
  jsvUnLock(doMeasurementAndWaitForResponse_fn);

  /// set up main interval callback for nodes
  JsVar *doMeasurement_fn = jsvNewNativeFunction(doMeasurement, JSWAT_VOID);
  currentInterval = jswrap_interface_setInterval(doMeasurement_fn, INTERVAL, 0);
  jsvUnLock(doMeasurement_fn);

  /// prepare the I2C bus for talking with the Si7050 temp sensor
  JsVar *s = jspEvaluate("I2C1.setup({scl:B8, sda:B9, bitrate:50000});"); jsvUnLock(s);
  disableDASH();
  jswrap_interface_setDeepSleep(true); //do deep sleep [TODO can we wake on press?]
#endif
}
Example #3
0
int main(int argc, char **argv) {
  int i;
  for (i=1;i<argc;i++) {
    if (argv[i][0]=='-') {
      // option
      char *a = argv[i];
      if (!strcmp(a,"-h") || !strcmp(a,"--help")) {
        show_help();
        exit(1);
      } else if (!strcmp(a,"-e") || !strcmp(a,"--eval")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        jshInit();
        jsvInit();
        jsiInit(true);
        addNativeFunction("quit", nativeQuit);
        jsvUnLock(jspEvaluate(argv[i+1], false));
        int errCode = handleErrors();
        isRunning = !errCode;
        bool isBusy = true;
        while (isRunning && (jsiHasTimers() || isBusy))
          isBusy = jsiLoop();
        jsiKill();
        jsvKill();
        jshKill();
        exit(errCode);
      } else if (!strcmp(a,"--test")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        bool ok = run_test(argv[i+1]);
        exit(ok ? 0 : 1);
      } else if (!strcmp(a,"--test-all")) {
        bool ok = run_all_tests();
        exit(ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem-all")) {
        bool ok = run_memory_tests(0);
        exit(ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        bool ok = run_memory_test(argv[i+1], 0);
        exit(ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem-n")) {
        if (i+2>=argc) die("Expecting an extra 2 arguments\n");
        bool ok = run_memory_test(argv[i+1], atoi(argv[i+2]));
        exit(ok ? 0 : 1);
      } else {
        printf("Unknown Argument %s\n", a);
        show_help();
        exit(1);
      }
    }
  }

  if (argc==1) {
    printf("Interactive mode.\n");
  } else if (argc==2) {
    // single file - just run it
    char *buffer = read_file(argv[1]);
    if (!buffer) exit(1);
    // check for '#' as the first char, and if so, skip the first line
    char *cmd = buffer;
    if (cmd[0]=='#') {
      while (cmd[0] && cmd[0]!='\n') cmd++;
      if (cmd[0]=='\n') cmd++;
    }
    jshInit();
    jsvInit();
    jsiInit(false /* do not autoload!!! */);
    addNativeFunction("quit", nativeQuit);
    jsvUnLock(jspEvaluate(cmd, true));
    int errCode = handleErrors();
    free(buffer);
    isRunning = !errCode;
    bool isBusy = true;
    while (isRunning && (jsiHasTimers() || isBusy))
      isBusy = jsiLoop();
    jsiKill();
    jsvKill();
    jshKill();
    exit(errCode);
  } else {
    printf("Unknown arguments!\n");
    show_help();
    exit(1);
  }

  printf("Size of JsVar is now %d bytes\n", (int)sizeof(JsVar));
  printf("Size of JsVarRef is now %d bytes\n", (int)sizeof(JsVarRef));

#ifndef __MINGW32__
  struct sigaction sa;
  sa.sa_handler = sig_handler;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  if (sigaction(SIGINT, &sa, NULL) == -1)
    printf("Adding SIGINT hook failed\n");
  else
    printf("Added SIGINT hook\n");
  if (sigaction(SIGHUP, &sa, NULL) == -1)
    printf("Adding SIGHUP hook failed\n");
  else
    printf("Added SIGHUP hook\n");
  if (sigaction(SIGTERM, &sa, NULL) == -1)
    printf("Adding SIGTERM hook failed\n");
  else
    printf("Added SIGTERM hook\n");
#endif//!__MINGW32__

  jshInit();
  jsvInit();
  jsiInit(true);

  addNativeFunction("quit", nativeQuit);
  addNativeFunction("interrupt", nativeInterrupt);

  while (isRunning) {
    jsiLoop();
  }
  jsiConsolePrint("\n");
  jsiKill();
  jsvGarbageCollect();
  jsvShowAllocated();
  jsvKill();
  jshKill();

  return 0;
}
Example #4
0
/*JSON{ "type":"staticmethod",
         "class" : "Modules", "name" : "removeAllCached",
         "description" : "Remove all cached modules",
         "generate" : "jswrap_modules_removeAllCached"
}*/
void jswrap_modules_removeAllCached() {
  JsVar *moduleList = jswrap_modules_getModuleList();
  if (!moduleList) return; // out of memory
  jsvRemoveAllChildren(moduleList);
  jsvUnLock(moduleList);
}
Example #5
0
void getSerial(char *serialBuffer, int size){
  JsVar *serialNumberString = jspEvaluate("getSerial().toString();");
  jsvGetString(serialNumberString, serialBuffer, size);
  jsvUnLock(serialNumberString);
}
Example #6
0
bool socketClientConnectionsIdle(JsNetwork *net) {
    char buf[CHUNK];

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP we split it into a request and a response
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);
        bool socketClosed = false;
        JsVar *receiveData = 0;

        bool hadHeaders = false;
        int error = 0; // error code received from netXxxx functions
        bool isHttp = (socketType&ST_TYPE_MASK) == ST_HTTP;
        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));
        bool alreadyConnected = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CONNECTED, false));
        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        if (sckt>=0) {
            if (isHttp)
                hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
            else
                hadHeaders = true;
            receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);

            /* We do this up here because we want to wait until we have been once
             * around the idle loop (=callbacks have been executed) before we run this */
            if (hadHeaders)
                socketClientPushReceiveData(connection, socket, &receiveData);

            JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0);
            if (!closeConnectionNow) {
                // send data if possible
                if (sendData && !jsvIsEmptyString(sendData)) {
                    // don't try to send if we're already in error state
                    int num = 0;
                    if (error == 0) num = socketSendData(net, connection, sckt, &sendData);
                    //if (num != 0) printf("send returned %d\r\n", num);
                    if (num > 0 && !alreadyConnected && !isHttp) { // whoa, we sent something, must be connected!
                        jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1);
                        jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true));
                        alreadyConnected = true;
                    }
                    if (num < 0) {
                        closeConnectionNow = true;
                        error = num;
                    }
                    jsvObjectSetChild(connection, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData
                } else {
                    // no data to send, do we want to close? do so.
                    if (jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSE, false)))
                        closeConnectionNow = true;
                }
                // Now read data if possible (and we have space for it)
                if (!receiveData || !hadHeaders) {
                    int num = netRecv(net, sckt, buf, sizeof(buf));
                    //if (num != 0) printf("recv returned %d\r\n", num);
                    if (!alreadyConnected && num == SOCKET_ERR_NO_CONN) {
                        ; // ignore... it's just telling us we're not connected yet
                    } else if (num < 0) {
                        closeConnectionNow = true;
                        error = num;
                        // disconnected without headers? error.
                        if (!hadHeaders && error == SOCKET_ERR_CLOSED) error = SOCKET_ERR_NO_RESP;
                    } else {
                        // did we just get connected?
                        if (!alreadyConnected && !isHttp) {
                            jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1);
                            jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true));
                            alreadyConnected = true;
                            // if we do not have any data to send, issue a drain event
                            if (!sendData || (int)jsvGetStringLength(sendData) == 0)
                                jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_DRAIN, &connection, 1);
                        }
                        // got data add it to our receive buffer
                        if (num > 0) {
                            if (!receiveData) {
                                receiveData = jsvNewFromEmptyString();
                                jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData);
                            }
                            if (receiveData) { // could be out of memory
                                jsvAppendStringBuf(receiveData, buf, (size_t)num);
                                if ((socketType&ST_TYPE_MASK)==ST_HTTP && !hadHeaders) {
                                    // for HTTP see whether we now have full response headers
                                    JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0);
                                    if (httpParseHeaders(&receiveData, resVar, false)) {
                                        hadHeaders = true;
                                        jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders));
                                        jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &resVar, 1);
                                    }
                                    jsvUnLock(resVar);
                                    jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData);
                                }
                            }
                        }
                    }
                }
                jsvUnLock(sendData);
            }
        }

        if (closeConnectionNow) {
            socketClientPushReceiveData(connection, socket, &receiveData);
            if (!receiveData) {
                //printf("closing now error=%d\r\n", error);
                if ((socketType&ST_TYPE_MASK) != ST_HTTP)
                    jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_END, &socket, 1);

                // If we had data to send but the socket closed, this is an error
                JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0);
                if (sendData && error == SOCKET_ERR_CLOSED) error = SOCKET_ERR_UNSENT_DATA;
                jsvUnLock(sendData);

                _socketConnectionKill(net, connection);
                JsVar *connectionName = jsvObjectIteratorGetKey(&it);
                jsvObjectIteratorNext(&it);
                jsvRemoveChild(arr, connectionName);
                jsvUnLock(connectionName);
                socketClosed = true;

                // fire error event, if ther eis an error
                bool hadError = fireErrorEvent(error, connection, NULL);

                // close callback must happen after error callback
                JsVar *params[1] = { jsvNewFromBool(hadError) };
                jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1);
                jsvUnLock(params[0]);
            }
        }


        if (!socketClosed) {
            jsvObjectIteratorNext(&it);
        }

        jsvUnLock3(receiveData, connection, socket);
    }
    jsvUnLock(arr);

    return hadSockets;
}
Example #7
0
/*JSON{ "type":"method",
         "class" : "WLAN", "name" : "disconnect",
         "generate" : "jswrap_wlan_disconnect",
         "description" : "Completely uninitialise and power down the CC3000. After this you'll have to use ```require(\"CC3000\").connect()``` again."
}*/
void jswrap_wlan_disconnect(JsVar *wlanObj) {
  jsvUnLock(jsvObjectSetChild(wlanObj,JS_HIDDEN_CHAR_STR"DISC", jsvNewFromBool(true)));
  networkState = NETWORKSTATE_OFFLINE; // force offline
  //wlan_disconnect();
  wlan_stop();
}
Example #8
0
void jslGetNextToken() {
  jslGetNextToken_start:
  // Skip whitespace
  while (isWhitespace(lex->currCh))
    jslGetNextCh();
  // Search for comments
  if (lex->currCh=='/') {
    // newline comments
    if (jslNextCh()=='/') {
      while (lex->currCh && lex->currCh!='\n') jslGetNextCh();
      jslGetNextCh();
      goto jslGetNextToken_start;
    }
    // block comments
    if (jslNextCh()=='*') {
      jslGetNextCh();
      jslGetNextCh();
      while (lex->currCh && !(lex->currCh=='*' && jslNextCh()=='/'))
        jslGetNextCh();
      if (!lex->currCh) {
        lex->tk = LEX_UNFINISHED_COMMENT;
        return; /* an unfinished multi-line comment. When in interactive console,
                   detect this and make sure we accept new lines */
      }
      jslGetNextCh();
      jslGetNextCh();
      goto jslGetNextToken_start;
    }
  }
  int lastToken = lex->tk;
  lex->tk = LEX_EOF;
  lex->tokenl = 0; // clear token string
  if (lex->tokenValue) {
    jsvUnLock(lex->tokenValue);
    lex->tokenValue = 0;
  }
  // record beginning of this token
  lex->tokenLastStart = jsvStringIteratorGetIndex(&lex->tokenStart.it) - 1;
  /* we don't lock here, because we know that the string itself will be locked
   * because of lex->sourceVar */
  lex->tokenStart.it = lex->it;
  lex->tokenStart.currCh = lex->currCh;
  // tokens
  if (((unsigned char)lex->currCh) < jslJumpTableStart ||
      ((unsigned char)lex->currCh) > jslJumpTableEnd) {
    // if unhandled by the jump table, just pass it through as a single character
    jslSingleChar();
  } else {
    switch(jslJumpTable[((unsigned char)lex->currCh) - jslJumpTableStart]) {
    case JSLJT_ID: {
      while (isAlpha(lex->currCh) || isNumeric(lex->currCh) || lex->currCh=='$') {
        jslTokenAppendChar(lex->currCh);
        jslGetNextCh();
      }
      lex->tk = LEX_ID;
      // We do fancy stuff here to reduce number of compares (hopefully GCC creates a jump table)
      switch (lex->token[0]) {
      case 'b': if (jslIsToken("break", 1)) lex->tk = LEX_R_BREAK;
      break;
      case 'c': if (jslIsToken("case", 1)) lex->tk = LEX_R_CASE;
      else if (jslIsToken("catch", 1)) lex->tk = LEX_R_CATCH;
      else if (jslIsToken("class", 1)) lex->tk = LEX_R_CLASS;
      else if (jslIsToken("const", 1)) lex->tk = LEX_R_CONST;
      else if (jslIsToken("continue", 1)) lex->tk = LEX_R_CONTINUE;
      break;
      case 'd': if (jslIsToken("default", 1)) lex->tk = LEX_R_DEFAULT;
      else if (jslIsToken("delete", 1)) lex->tk = LEX_R_DELETE;
      else if (jslIsToken("do", 1)) lex->tk = LEX_R_DO;
      else if (jslIsToken("debugger", 1)) lex->tk = LEX_R_DEBUGGER;
      break;
      case 'e': if (jslIsToken("else", 1)) lex->tk = LEX_R_ELSE;
      else if (jslIsToken("extends", 1)) lex->tk = LEX_R_EXTENDS;
      break;
      case 'f': if (jslIsToken("false", 1)) lex->tk = LEX_R_FALSE;
      else if (jslIsToken("finally", 1)) lex->tk = LEX_R_FINALLY;
      else if (jslIsToken("for", 1)) lex->tk = LEX_R_FOR;
      else if (jslIsToken("function", 1)) lex->tk = LEX_R_FUNCTION;
      break;
      case 'i': if (jslIsToken("if", 1)) lex->tk = LEX_R_IF;
      else if (jslIsToken("in", 1)) lex->tk = LEX_R_IN;
      else if (jslIsToken("instanceof", 1)) lex->tk = LEX_R_INSTANCEOF;
      break;
      case 'l': if (jslIsToken("let", 1)) lex->tk = LEX_R_LET;
      break;
      case 'n': if (jslIsToken("new", 1)) lex->tk = LEX_R_NEW;
      else if (jslIsToken("null", 1)) lex->tk = LEX_R_NULL;
      break;
      case 'o': if (jslIsToken("of", 1)) lex->tk = LEX_R_OF;
      break;
      case 'r': if (jslIsToken("return", 1)) lex->tk = LEX_R_RETURN;
      break;
      case 's': if (jslIsToken("static", 1)) lex->tk = LEX_R_STATIC;
      else if (jslIsToken("super", 1)) lex->tk = LEX_R_SUPER;
      else if (jslIsToken("switch", 1)) lex->tk = LEX_R_SWITCH;
      break;
      case 't': if (jslIsToken("this", 1)) lex->tk = LEX_R_THIS;
      else if (jslIsToken("throw", 1)) lex->tk = LEX_R_THROW;
      else if (jslIsToken("true", 1)) lex->tk = LEX_R_TRUE;
      else if (jslIsToken("try", 1)) lex->tk = LEX_R_TRY;
      else if (jslIsToken("typeof", 1)) lex->tk = LEX_R_TYPEOF;
      break;
      case 'u': if (jslIsToken("undefined", 1)) lex->tk = LEX_R_UNDEFINED;
      break;
      case 'w': if (jslIsToken("while", 1)) lex->tk = LEX_R_WHILE;
      break;
      case 'v': if (jslIsToken("var", 1)) lex->tk = LEX_R_VAR;
      else if (jslIsToken("void", 1)) lex->tk = LEX_R_VOID;
      break;
      default: break;
      } break;
      case JSLJT_NUMBER: {
        // TODO: check numbers aren't the wrong format
        bool canBeFloating = true;
        if (lex->currCh=='.') {
          jslGetNextCh();
          if (isNumeric(lex->currCh)) {
            // it is a float
            lex->tk = LEX_FLOAT;
            jslTokenAppendChar('.');
          } else {
            // it wasn't a number after all
            lex->tk = '.';
            break;
          }
        } else {
          if (lex->currCh=='0') {
            jslTokenAppendChar(lex->currCh);
            jslGetNextCh();
            if ((lex->currCh=='x' || lex->currCh=='X') ||
                (lex->currCh=='b' || lex->currCh=='B') ||
                (lex->currCh=='o' || lex->currCh=='O')) {
              canBeFloating = false;
              jslTokenAppendChar(lex->currCh); jslGetNextCh();
            }
          }
          lex->tk = LEX_INT;
          while (isNumeric(lex->currCh) || (!canBeFloating && isHexadecimal(lex->currCh))) {
            jslTokenAppendChar(lex->currCh);
            jslGetNextCh();
          }
          if (canBeFloating && lex->currCh=='.') {
            lex->tk = LEX_FLOAT;
            jslTokenAppendChar('.');
            jslGetNextCh();
          }
        }
        // parse fractional part
        if (lex->tk == LEX_FLOAT) {
          while (isNumeric(lex->currCh)) {
            jslTokenAppendChar(lex->currCh);
            jslGetNextCh();
          }
        }
        // do fancy e-style floating point
        if (canBeFloating && (lex->currCh=='e'||lex->currCh=='E')) {
          lex->tk = LEX_FLOAT;
          jslTokenAppendChar(lex->currCh); jslGetNextCh();
          if (lex->currCh=='-' || lex->currCh=='+') { jslTokenAppendChar(lex->currCh); jslGetNextCh(); }
          while (isNumeric(lex->currCh)) {
            jslTokenAppendChar(lex->currCh); jslGetNextCh();
          }
        }
      } break;
      case JSLJT_STRING: jslLexString(); break;
      case JSLJT_EXCLAMATION: jslSingleChar();
      if (lex->currCh=='=') { // !=
        lex->tk = LEX_NEQUAL;
        jslGetNextCh();
        if (lex->currCh=='=') { // !==
          lex->tk = LEX_NTYPEEQUAL;
          jslGetNextCh();
        }
      } break;
      case JSLJT_PLUS: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_PLUSEQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='+') {
        lex->tk = LEX_PLUSPLUS;
        jslGetNextCh();
      } break;
      case JSLJT_MINUS: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_MINUSEQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='-') {
        lex->tk = LEX_MINUSMINUS;
        jslGetNextCh();
      } break;
      case JSLJT_AND: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_ANDEQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='&') {
        lex->tk = LEX_ANDAND;
        jslGetNextCh();
      } break;
      case JSLJT_OR: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_OREQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='|') {
        lex->tk = LEX_OROR;
        jslGetNextCh();
      } break;
      case JSLJT_TOPHAT: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_XOREQUAL;
        jslGetNextCh();
      } break;
      case JSLJT_STAR: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_MULEQUAL;
        jslGetNextCh();
      } break;
      case JSLJT_FORWARDSLASH:
      // yay! JS is so awesome.
      if (lastToken==LEX_EOF ||
          lastToken=='!' ||
          lastToken=='%' ||
          lastToken=='&' ||
          lastToken=='*' ||
          lastToken=='+' ||
          lastToken=='-' ||
          lastToken=='/' ||
          lastToken=='<' ||
          lastToken=='=' ||
          lastToken=='>' ||
          lastToken=='?' ||
          (lastToken>=_LEX_OPERATOR_START && lastToken<=_LEX_OPERATOR_END) ||
          (lastToken>=_LEX_R_LIST_START && lastToken<=_LEX_R_LIST_END) || // keywords
          lastToken==LEX_R_CASE ||
          lastToken==LEX_R_NEW ||
          lastToken=='[' ||
          lastToken=='{' ||
          lastToken=='}' ||
          lastToken=='(' ||
          lastToken==',' ||
          lastToken==';' ||
          lastToken==':' ||
          lastToken==LEX_ARROW_FUNCTION) {
        // EOF operator keyword case new [ { } ( , ; : =>
        // phew. We're a regex
        jslLexRegex();
      } else {
        jslSingleChar();
        if (lex->currCh=='=') {
          lex->tk = LEX_DIVEQUAL;
          jslGetNextCh();
        }
      } break;
      case JSLJT_PERCENT: jslSingleChar();
      if (lex->currCh=='=') {
        lex->tk = LEX_MODEQUAL;
        jslGetNextCh();
      } break;
      case JSLJT_EQUAL: jslSingleChar();
      if (lex->currCh=='=') { // ==
        lex->tk = LEX_EQUAL;
        jslGetNextCh();
        if (lex->currCh=='=') { // ===
          lex->tk = LEX_TYPEEQUAL;
          jslGetNextCh();
        }
      } else if (lex->currCh=='>') { // =>
        lex->tk = LEX_ARROW_FUNCTION;
        jslGetNextCh();
      } break;
      case JSLJT_LESSTHAN: jslSingleChar();
      if (lex->currCh=='=') { // <=
        lex->tk = LEX_LEQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='<') { // <<
        lex->tk = LEX_LSHIFT;
        jslGetNextCh();
        if (lex->currCh=='=') { // <<=
          lex->tk = LEX_LSHIFTEQUAL;
          jslGetNextCh();
        }
      } break;
      case JSLJT_GREATERTHAN: jslSingleChar();
      if (lex->currCh=='=') { // >=
        lex->tk = LEX_GEQUAL;
        jslGetNextCh();
      } else if (lex->currCh=='>') { // >>
        lex->tk = LEX_RSHIFT;
        jslGetNextCh();
        if (lex->currCh=='=') { // >>=
          lex->tk = LEX_RSHIFTEQUAL;
          jslGetNextCh();
        } else if (lex->currCh=='>') { // >>>
          jslGetNextCh();
          if (lex->currCh=='=') { // >>>=
            lex->tk = LEX_RSHIFTUNSIGNEDEQUAL;
            jslGetNextCh();
          } else {
            lex->tk = LEX_RSHIFTUNSIGNED;
          }
        }
      } break;

      case JSLJT_SINGLECHAR: jslSingleChar(); break;
      default: assert(0);break;
    }
    }
  }
}
Example #9
0
void   jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt value) {
  // FIXME: Do this without the allocation!
  JsVar *val = jsvNewFromInteger(value);
  jsvArrayBufferIteratorSetValue(it, val);
  jsvUnLock(val);
}
Example #10
0
void jsfGetJSONWithCallback(JsVar *var, JSONFlags flags, vcbprintf_callback user_callback, void *user_data) {
  JSONFlags nflags = flags + JSON_INDENT; // if we add a newline, make sure we indent any subsequent JSON more

  if (jsvIsUndefined(var)) {
    cbprintf(user_callback, user_data, "undefined");
  } else {
    // Use IS_RECURSING  flag to stop recursion
    if (var->flags & JSV_IS_RECURSING) {
      cbprintf(user_callback, user_data, " ... ");
      return;
    }
    var->flags |= JSV_IS_RECURSING;

    if (jsvIsArray(var)) {
      size_t length = (size_t)jsvGetArrayLength(var);
      bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
      bool needNewLine = false;
      size_t i;
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
      for (i=0;i<length && !jspIsInterrupted();i++) {
        if (!limited || i<JSON_LIMITED_AMOUNT || i>=length-JSON_LIMITED_AMOUNT) {
          if (i>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
          if (limited && i==length-JSON_LIMITED_AMOUNT) {
            if (needNewLine) jsonNewLine(nflags, user_callback, user_data);
            cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
          }
          JsVar *item = jsvGetArrayItem(var, (JsVarInt)i);
          if (jsvIsUndefined(item) && (flags&JSON_NO_UNDEFINED))
              item = jsvNewWithFlags(JSV_NULL);
          bool newNeedsNewLine = (flags&JSON_NEWLINES) && jsonNeedsNewLine(item);
          if (needNewLine || newNeedsNewLine) {
            jsonNewLine(nflags, user_callback, user_data);
            needNewLine = false;
          }
          jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
          needNewLine = newNeedsNewLine;
          jsvUnLock(item);
        }
      }
      if (needNewLine) jsonNewLine(flags, user_callback, user_data);
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" ]":"]");
    } else if (jsvIsArrayBuffer(var)) {
      cbprintf(user_callback, user_data, "new %s([", jswGetBasicObjectName(var));
      size_t length = jsvGetArrayBufferLength(var);
      bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
      // no newlines needed for array buffers as they only contain simple stuff
      JsvArrayBufferIterator it;
      jsvArrayBufferIteratorNew(&it, var, 0);
      while (jsvArrayBufferIteratorHasElement(&it) && !jspIsInterrupted()) {
        if (!limited || it.index<JSON_LIMITED_AMOUNT || it.index>=length-JSON_LIMITED_AMOUNT) {
          if (it.index>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
          if (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
          JsVar *item = jsvArrayBufferIteratorGetValue(&it);
          jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
          jsvUnLock(item);
        }
        jsvArrayBufferIteratorNext(&it);
      }
      jsvArrayBufferIteratorFree(&it);
      cbprintf(user_callback, user_data, "])");
    } else if (jsvIsObject(var)) {
      IOEventFlags device = (flags & JSON_SHOW_DEVICES) ? jsiGetDeviceFromClass(var) : EV_NONE;
      if (device!=EV_NONE) {
        cbprintf(user_callback, user_data, "%s", jshGetDeviceString(device));
      } else {
        bool first = true;
        bool needNewLine = false;
        size_t sinceNewLine = 0;
        JsvObjectIterator it;
        jsvObjectIteratorNew(&it, var);
        cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
        while (jsvObjectIteratorHasValue(&it) && !jspIsInterrupted()) {
          JsVar *index = jsvObjectIteratorGetKey(&it);
          JsVar *item = jsvObjectIteratorGetValue(&it);
          bool hidden = jsvIsInternalObjectKey(index) ||
                        ((flags & JSON_IGNORE_FUNCTIONS) && jsvIsFunction(item)) ||
                        ((flags&JSON_NO_UNDEFINED) && jsvIsUndefined(item));
          if (!hidden) {
            sinceNewLine++;
            if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
            bool newNeedsNewLine = (flags&JSON_NEWLINES) && jsonNeedsNewLine(item);
            if ((flags&JSON_NEWLINES) && sinceNewLine>JSON_ITEMS_ON_LINE_OBJECT)
              needNewLine = true;
            if (needNewLine || newNeedsNewLine) {
              jsonNewLine(nflags, user_callback, user_data);
              needNewLine = false;
              sinceNewLine = 0;
            }
            cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"%q: ":"%q:", index);
            if (first)
              first = false;
            jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
            needNewLine = newNeedsNewLine;
          }
          jsvUnLock(index);
          jsvUnLock(item);
          jsvObjectIteratorNext(&it);
        }
        jsvObjectIteratorFree(&it);
        if (needNewLine) jsonNewLine(flags, user_callback, user_data);
        cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" }":"}");
      }
    } else if (jsvIsFunction(var)) {
      if (flags & JSON_IGNORE_FUNCTIONS) {
        cbprintf(user_callback, user_data, "undefined");
      } else {
        cbprintf(user_callback, user_data, "function ");
        jsfGetJSONForFunctionWithCallback(var, nflags, user_callback, user_data);
      }
    } else if (jsvIsString(var) && !jsvIsName(var)) {
      if ((flags&JSON_LIMIT) && jsvGetStringLength(var)>JSON_LIMIT_STRING_AMOUNT) {
        // if the string is too big, split it and put dots in the middle
        JsVar *var1 = jsvNewFromStringVar(var, 0, JSON_LIMITED_STRING_AMOUNT);
        JsVar *var2 = jsvNewFromStringVar(var, jsvGetStringLength(var)-JSON_LIMITED_STRING_AMOUNT, JSON_LIMITED_STRING_AMOUNT);
        cbprintf(user_callback, user_data, "%q%s%q", var1, JSON_LIMIT_TEXT, var2);
        jsvUnLock(var1);
        jsvUnLock(var2);
      } else {
        cbprintf(user_callback, user_data, "%q", var);
      }
    } else {
      cbprintf(user_callback, user_data, "%v", var);
    }

    var->flags &= ~JSV_IS_RECURSING;
  }
}
Example #11
0
JsVar *jswrap_json_parse_internal(JsLex *lex) {
  switch (lex->tk) {
    case LEX_R_TRUE:  jslGetNextToken(lex); return jsvNewFromBool(true);
    case LEX_R_FALSE: jslGetNextToken(lex); return jsvNewFromBool(false);
    case LEX_R_NULL:  jslGetNextToken(lex); return jsvNewWithFlags(JSV_NULL);
    case LEX_INT: {
      long long v = stringToInt(jslGetTokenValueAsString(lex));
      jslGetNextToken(lex);
      return jsvNewFromLongInteger(v);
    }
    case LEX_FLOAT: {
      JsVarFloat v = stringToFloat(jslGetTokenValueAsString(lex));
      jslGetNextToken(lex);
      return jsvNewFromFloat(v);
    }
    case LEX_STR: {
      JsVar *a = jslGetTokenValueAsVar(lex);
      jslGetNextToken(lex);
      return a;
    }
    case '[': {
      JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0;
      jslGetNextToken(lex); // [
      while (lex->tk != ']') {
        JsVar *value = jswrap_json_parse_internal(lex);
        if (!value ||
            (lex->tk!=']' && !jslMatch(lex, ','))) {
          jsvUnLock(value);
          jsvUnLock(arr);
          return 0;
        }
        jsvArrayPush(arr, value);
        jsvUnLock(value);
      }
      if (!jslMatch(lex, ']')) {
        jsvUnLock(arr);
        return 0;
      }
      return arr;
    }
    case '{': {
      JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0;
      jslGetNextToken(lex); // {
      while (lex->tk == LEX_STR) {
        JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex));
        jslGetNextToken(lex);
        JsVar *value = 0;
        if (!jslMatch(lex, ':') ||
            !(value=jswrap_json_parse_internal(lex)) ||
            (lex->tk!='}' && !jslMatch(lex, ','))) {
          jsvUnLock(key);
          jsvUnLock(value);
          jsvUnLock(obj);
          return 0;
        }
        jsvAddName(obj, jsvMakeIntoVariableName(key, value));
        jsvUnLock(value);
        jsvUnLock(key);
      }
      if (!jslMatch(lex, '}')) {
        jsvUnLock(obj);
        return 0;
      }
      return obj;
    }
    default: return 0; // undefined = error
  }
}
Example #12
0
// httpParseHeaders(&receiveData, reqVar, true) // server
// httpParseHeaders(&receiveData, resVar, false) // client
bool httpParseHeaders(JsVar **receiveData, JsVar *objectForData, bool isServer) {
    // find /r/n/r/n
    int newlineIdx = 0;
    int strIdx = 0;
    int headerEnd = -1;
    JsvStringIterator it;
    jsvStringIteratorNew(&it, *receiveData, 0);
    while (jsvStringIteratorHasChar(&it)) {
        char ch = jsvStringIteratorGetChar(&it);
        if (ch == '\r') {
            if (newlineIdx==0) newlineIdx=1;
            else if (newlineIdx==2) newlineIdx=3;
        } else if (ch == '\n') {
            if (newlineIdx==1) newlineIdx=2;
            else if (newlineIdx==3) {
                headerEnd = strIdx+1;
            }
        } else newlineIdx=0;
        jsvStringIteratorNext(&it);
        strIdx++;
    }
    jsvStringIteratorFree(&it);
    // skip if we have no header
    if (headerEnd<0) return false;
    // Now parse the header
    JsVar *vHeaders = jsvNewWithFlags(JSV_OBJECT);
    if (!vHeaders) return true;
    jsvUnLock(jsvAddNamedChild(objectForData, vHeaders, "headers"));
    strIdx = 0;
    int firstSpace = -1;
    int secondSpace = -1;
    int firstEOL = -1;
    int lineNumber = 0;
    int lastLineStart = 0;
    int colonPos = 0;
    //jsiConsolePrintStringVar(receiveData);
    jsvStringIteratorNew(&it, *receiveData, 0);
    while (jsvStringIteratorHasChar(&it)) {
        char ch = jsvStringIteratorGetChar(&it);
        if (ch==' ' || ch=='\r') {
            if (firstSpace<0) firstSpace = strIdx;
            else if (secondSpace<0) secondSpace = strIdx;
        }
        if (ch == ':' && colonPos<0) colonPos = strIdx;
        if (ch == '\r') {
            if (firstEOL<0) firstEOL=strIdx;
            if (lineNumber>0 && colonPos>lastLineStart && lastLineStart<strIdx) {
                JsVar *hVal = jsvNewFromEmptyString();
                if (hVal)
                    jsvAppendStringVar(hVal, *receiveData, (size_t)colonPos+2, (size_t)(strIdx-(colonPos+2)));
                JsVar *hKey = jsvNewFromEmptyString();
                if (hKey) {
                    jsvMakeIntoVariableName(hKey, hVal);
                    jsvAppendStringVar(hKey, *receiveData, (size_t)lastLineStart, (size_t)(colonPos-lastLineStart));
                    jsvAddName(vHeaders, hKey);
                    jsvUnLock(hKey);
                }
                jsvUnLock(hVal);
            }
            lineNumber++;
            colonPos=-1;
        }
        if (ch == '\r' || ch == '\n') {
            lastLineStart = strIdx+1;
        }

        jsvStringIteratorNext(&it);
        strIdx++;
    }
    jsvStringIteratorFree(&it);
    jsvUnLock(vHeaders);
    // try and pull out methods/etc
    if (isServer) {
        jsvObjectSetChildAndUnLock(objectForData, "method", jsvNewFromStringVar(*receiveData, 0, (size_t)firstSpace));
        jsvObjectSetChildAndUnLock(objectForData, "url", jsvNewFromStringVar(*receiveData, (size_t)(firstSpace+1), (size_t)(secondSpace-(firstSpace+1))));
    } else {
        jsvObjectSetChildAndUnLock(objectForData, "httpVersion", jsvNewFromStringVar(*receiveData, 5, (size_t)firstSpace-5));
        jsvObjectSetChildAndUnLock(objectForData, "statusCode", jsvNewFromStringVar(*receiveData, (size_t)(firstSpace+1), (size_t)(secondSpace-(firstSpace+1))));
        jsvObjectSetChildAndUnLock(objectForData, "statusMessage", jsvNewFromStringVar(*receiveData, (size_t)(secondSpace+1), (size_t)(firstEOL-(secondSpace+1))));
    }
    // strip out the header
    JsVar *afterHeaders = jsvNewFromStringVar(*receiveData, (size_t)headerEnd, JSVAPPENDSTRINGVAR_MAXLENGTH);
    jsvUnLock(*receiveData);
    *receiveData = afterHeaders;
    return true;
}
Example #13
0
void clientRequestWrite(JsNetwork *net, JsVar *httpClientReqVar, JsVar *data) {
    SocketType socketType = socketGetType(httpClientReqVar);
    // Append data to sendData
    JsVar *sendData = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, 0);
    if (!sendData) {
        JsVar *options = 0;
        // Only append a header if we're doing HTTP AND we haven't already connected
        if ((socketType&ST_TYPE_MASK) == ST_HTTP)
            if (jsvGetIntegerAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SOCKET, 0))==0)
                options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, 0);
        if (options) {
            // We're an HTTP client - make a header
            JsVar *method = jsvObjectGetChild(options, "method", 0);
            JsVar *path = jsvObjectGetChild(options, "path", 0);
            sendData = jsvVarPrintf("%v %v HTTP/1.0\r\nUser-Agent: Espruino "JS_VERSION"\r\nConnection: close\r\n", method, path);
            jsvUnLock2(method, path);
            JsVar *headers = jsvObjectGetChild(options, "headers", 0);
            bool hasHostHeader = false;
            if (jsvIsObject(headers)) {
                JsVar *hostHeader = jsvObjectGetChild(headers, "Host", 0);
                hasHostHeader = hostHeader!=0;
                jsvUnLock(hostHeader);
                httpAppendHeaders(sendData, headers);
                // if Transfer-Encoding:chunked was set, subsequent writes need to 'chunk' the data that is sent
                if (jsvIsStringEqualAndUnLock(jsvObjectGetChild(headers, "Transfer-Encoding", 0), "chunked")) {
                    jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CHUNKED, jsvNewFromBool(true));
                }
            }
            jsvUnLock(headers);
            if (!hasHostHeader) {
                JsVar *host = jsvObjectGetChild(options, "host", 0);
                int port = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0));
                if (port>0 && port!=80)
                    jsvAppendPrintf(sendData, "Host: %v:%d\r\n", host, port);
                else
                    jsvAppendPrintf(sendData, "Host: %v\r\n", host);
                jsvUnLock(host);
            }
            // finally add ending newline
            jsvAppendString(sendData, "\r\n");
        } else { // !options
            // We're not HTTP (or were already connected), so don't send any header
            sendData = jsvNewFromString("");
        }
        jsvObjectSetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, sendData);
        jsvUnLock(options);
    }
    // We have data and aren't out of memory...
    if (data && sendData) {
        // append the data to what we want to send
        JsVar *s = jsvAsString(data, false);
        if (s) {
            if ((socketType&ST_TYPE_MASK) == ST_HTTP &&
                    jsvGetBoolAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_CHUNKED, 0))) {
                // If we asked to send 'chunked' data, we need to wrap it up,
                // prefixed with the length
                jsvAppendPrintf(sendData, "%x\r\n%v\r\n", jsvGetStringLength(s), s);
            } else {
                jsvAppendStringVarComplete(sendData,s);
            }
            jsvUnLock(s);
        }
    }
    jsvUnLock(sendData);
    if ((socketType&ST_TYPE_MASK) == ST_HTTP) {
        // on HTTP we connect after the first write
        clientRequestConnect(net, httpClientReqVar);
    }
}
Example #14
0
bool socketIdle(JsNetwork *net) {
    if (networkState != NETWORKSTATE_ONLINE) {
        // clear all clients and servers
        _socketCloseAllConnections(net);
        return false;
    }
    bool hadSockets = false;
    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVERS,false);
    if (arr) {
        JsvObjectIterator it;
        jsvObjectIteratorNew(&it, arr);
        while (jsvObjectIteratorHasValue(&it)) {
            hadSockets = true;

            JsVar *server = jsvObjectIteratorGetValue(&it);
            int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(server,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined

            int theClient = netAccept(net, sckt);
            if (theClient >= 0) {
                SocketType socketType = socketGetType(server);
                if ((socketType&ST_TYPE_MASK) == ST_HTTP) {
                    JsVar *req = jspNewObject(0, "httpSRq");
                    JsVar *res = jspNewObject(0, "httpSRs");
                    if (res && req) { // out of memory?
                        socketSetType(req, ST_HTTP);
                        JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS, true);
                        if (arr) {
                            jsvArrayPush(arr, req);
                            jsvUnLock(arr);
                        }
                        jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res);
                        jsvObjectSetChild(req, HTTP_NAME_SERVER_VAR, server);
                        jsvObjectSetChildAndUnLock(req, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1));
                    }
                    jsvUnLock2(req, res);
                } else {
                    // Normal sockets
                    JsVar *sock = jspNewObject(0, "Socket");
                    if (sock) { // out of memory?
                        socketSetType(sock, ST_NORMAL);
                        JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS, true);
                        if (arr) {
                            jsvArrayPush(arr, sock);
                            jsvUnLock(arr);
                        }
                        jsvObjectSetChildAndUnLock(sock, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1));
                        jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, &sock, 1);
                        jsvUnLock(sock);
                    }
                }
            }

            jsvUnLock(server);
            jsvObjectIteratorNext(&it);
        }
        jsvObjectIteratorFree(&it);
        jsvUnLock(arr);
    }

    if (socketServerConnectionsIdle(net)) hadSockets = true;
    if (socketClientConnectionsIdle(net)) hadSockets = true;
    netCheckError(net);
    return hadSockets;
}
Example #15
0
int espruino(int argc, char **argv) {
  int i;
  for (i=1;i<argc;i++) {
    if (argv[i][0]=='-') {
      // option
      char *a = argv[i];
      if (!strcmp(a,"-h") || !strcmp(a,"--help")) {
        show_help();
        return (1);
      } else if (!strcmp(a,"-e") || !strcmp(a,"--eval")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        jshInit();
        jsiInit(true);
        jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
        jsvUnLock(jspEvaluate(jsiGetParser(), argv[i+1]));
        isRunning = true;
        //while (isRunning && jsiHasTimers()) jsiLoop();
        jsiKill();
        jshKill();
        return (0);
      } else if (!strcmp(a,"--test")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        bool ok = run_test(argv[i+1]);
        return (ok ? 0 : 1);
      } else if (!strcmp(a,"--test-all")) {
        bool ok = run_all_tests();
        return (ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem-all")) {
        bool ok = run_memory_tests(0);
        return (ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem")) {
        if (i+1>=argc) die("Expecting an extra argument\n");
        bool ok = run_memory_test(argv[i+1], 0);
        return (ok ? 0 : 1);
      } else if (!strcmp(a,"--test-mem-n")) {
        if (i+2>=argc) die("Expecting an extra 2 arguments\n");
        bool ok = run_memory_test(argv[i+1], atoi(argv[i+2]));
        return (ok ? 0 : 1);
      } else {
        printf("Unknown Argument %s\n", a);
        show_help();
        return -1;
      }
    }
  }

  if (argc==1) {
    printf("Interactive mode.\n");
  } else if (argc==2) {
    // single file - just run it
    char *buffer = (char *)read_file(argv[1]);
    if (!buffer) return (1);
    // check for '#' as the first char, and if so, skip the first line
    char *cmd = buffer;
    if (cmd[0]=='#') {
      while (cmd[0] && cmd[0]!='\n') cmd++;
      if (cmd[0]=='\n') cmd++;
    }
    jshInit();
    jsiInit(false /* do not autoload!!! */);
    jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
    jsvUnLock(jspEvaluate(jsiGetParser(), cmd ));
    free(buffer);
    //isRunning = true;
    //while (isRunning && jsiHasTimers()) jsiLoop();
    jsiKill();
    jshKill();
    return -1;
  } else {
    printf("Unknown arguments!\n");
    show_help();
    return -1;
  }

  printf("Size of JsVar is now %d bytes\n", (int)sizeof(JsVar));
  printf("Size of JsVarRef is now %d bytes\n", (int)sizeof(JsVarRef));

  jshInit();
  jsiInit(true);

  jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit);
  jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt);

  while (isRunning) {
    jsiLoop();
  }
  jsiConsolePrint("\n");
  jsiKill();

  jsvShowAllocated();
  jshKill();

  return 0;
}
Example #16
0
/*JSON{ "type":"staticmethod",
         "class" : "url", "name" : "parse",
         "generate" : "jswrap_url_parse",
         "description" : ["A utility function to split a URL into parts", 
                          "This is useful in web servers for instance when handling a request.",
                          "For instance `url.parse(\"/a?b=c&d=e\",true)` returns `{\"method\":\"GET\",\"host\":\"\",\"path\":\"/a?b=c&d=e\",\"pathname\":\"/a\",\"search\":\"?b=c&d=e\",\"port\":80,\"query\":{\"b\":\"c\",\"d\":\"e\"}}`"],
         "params" : [ [ "urlStr", "JsVar", "A URL to be parsed"],
                      [ "parseQuery", "bool", "Whether to parse the query string into an object not (default = false)"] ],
         "return" : ["JsVar", "An object containing options for ```http.request``` or ```http.get```. Contains `method`, `host`, `path`, `pathname`, `search`, `port` and `query`" ]
}*/
JsVar *jswrap_url_parse(JsVar *url, bool parseQuery) {
  if (!jsvIsString(url)) return 0;
  JsVar *obj = jsvNewWithFlags(JSV_OBJECT);
  if (!obj) return 0; // out of memory

  // scan string to try and pick stuff out
  JsvStringIterator it;
  jsvStringIteratorNew(&it, url, 0);
  int slashes = 0;
  int colons = 0;
  int addrStart = -1;
  int portStart = -1;
  int pathStart = -1;
  int searchStart = -1;
  int charIdx = 0;
  int portNumber = 0;
  while (jsvStringIteratorHasChar(&it)) {
    char ch = jsvStringIteratorGetChar(&it);
    if (ch == '/') {
      slashes++;
      if (pathStart<0) pathStart = charIdx;
      if (colons==1 && slashes==2 && addrStart<0) {
        addrStart = charIdx;
        pathStart = -1;
        searchStart = -1;
      }
    }
    if (ch == ':') {
      colons++;
      if (addrStart>=0 && pathStart<0)
        portStart = charIdx;
    }

    if (portStart>=0 && charIdx>portStart && pathStart<0 && ch >= '0' && ch <= '9') {
      portNumber = portNumber*10 + (ch-'0');
    }

    if (ch == '?' && pathStart>=0) {
      searchStart = charIdx;
    }

    jsvStringIteratorNext(&it);
    charIdx++;
  }
  jsvStringIteratorFree(&it);
  // try and sort stuff out
  if (pathStart<0) pathStart = charIdx;
  if (pathStart<0) pathStart = charIdx;
  int addrEnd = (portStart>=0) ? portStart : pathStart;
  // pull out details
  jsvUnLock(jsvObjectSetChild(obj, "method", jsvNewFromString("GET")));
  jsvUnLock(jsvObjectSetChild(obj, "host", jsvNewFromStringVar(url, (size_t)(addrStart+1), (size_t)(addrEnd-(addrStart+1)))));

  JsVar *v;

  v = jsvNewFromStringVar(url, (size_t)pathStart, JSVAPPENDSTRINGVAR_MAXLENGTH);
  if (jsvGetStringLength(v)==0) jsvAppendString(v, "/");
  jsvUnLock(jsvObjectSetChild(obj, "path", v));

  v = jsvNewFromStringVar(url, (size_t)pathStart, (size_t)((searchStart>=0)?(searchStart-pathStart):JSVAPPENDSTRINGVAR_MAXLENGTH));
  if (jsvGetStringLength(v)==0) jsvAppendString(v, "/");
  jsvUnLock(jsvObjectSetChild(obj, "pathname", v));

  jsvUnLock(jsvObjectSetChild(obj, "search", (searchStart>=0)?jsvNewFromStringVar(url, (size_t)searchStart, JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull()));

  if (portNumber<=0 || portNumber>65535) portNumber=80;
  jsvUnLock(jsvObjectSetChild(obj, "port", jsvNewFromInteger(portNumber)));

  JsVar *query = (searchStart>=0)?jsvNewFromStringVar(url, (size_t)(searchStart+1), JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull();
  if (parseQuery && !jsvIsNull(query)) {
    JsVar *queryStr = query;
    jsvStringIteratorNew(&it, query, 0);
    query = jsvNewWithFlags(JSV_OBJECT);

    JsVar *key = jsvNewFromEmptyString();
    JsVar *val = jsvNewFromEmptyString();
    bool hadEquals = false;

    while (jsvStringIteratorHasChar(&it)) {
      char ch = jsvStringIteratorGetChar(&it);
      if (ch=='&') {
        if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) {
          jsvMakeIntoVariableName(key, val);
          jsvAddName(query, key);
          jsvUnLock(key);
          jsvUnLock(val);
          key = jsvNewFromEmptyString();
          val = jsvNewFromEmptyString();
          hadEquals = false;
        }
      } else if (!hadEquals && ch=='=') {
        hadEquals = true;
      } else {
        if (hadEquals) jsvAppendCharacter(val, ch);
        else jsvAppendCharacter(key, ch);
      }
      jsvStringIteratorNext(&it);
      charIdx++;
    }
    jsvStringIteratorFree(&it);
    jsvUnLock(queryStr);

    if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) {
      jsvMakeIntoVariableName(key, val);
      jsvAddName(query, key);
    }
    jsvUnLock(key);
    jsvUnLock(val);
  }
  jsvUnLock(jsvObjectSetChild(obj, "query", query));

  return obj;
}
Example #17
0
/** This is for Object.keys and Object. */
JsVar *jswrap_object_keys_or_property_names(
    JsVar *obj,
    bool includeNonEnumerable,  ///< include 'hidden' items
    bool includePrototype) { ///< include items for the prototype too (for autocomplete)

  JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
  if (!arr) return 0;

  // strings are iterable, but we shouldn't try and show keys for them
  if (jsvIsIterable(obj)) {
    JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj);

    JsvIterator it;
    jsvIteratorNew(&it, obj);
    while (jsvIteratorHasElement(&it)) {
      JsVar *key = jsvIteratorGetKey(&it);
      if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) {
        /* Not sure why constructor is included in getOwnPropertyNames, but
         * not in for (i in ...) but it is, so we must explicitly override the
         * check in jsvIsInternalObjectKey! */
        JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false));
        if (name) {
          jsvArrayPushAndUnLock(arr, name);
        }
      }
      jsvUnLock(key);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }

  /* Search our built-in symbol table
     Assume that ALL builtins are non-enumerable. This isn't great but
     seems to work quite well right now! */
  if (includeNonEnumerable) {
    const JswSymList *symbols = 0;

    JsVar *protoOwner = jspGetPrototypeOwner(obj);
    if (protoOwner) {
      // If protoOwner then this is the prototype (protoOwner is the object)
      symbols = jswGetSymbolListForObjectProto(protoOwner);
      jsvUnLock(protoOwner);
    } else if (!jsvIsObject(obj) || jsvIsRoot(obj)) {
      // get symbols, but only if we're not doing it on a basic object
      symbols = jswGetSymbolListForObject(obj);
    }

    if (symbols) {
      unsigned int i;
      for (i=0;i<symbols->symbolCount;i++)
        jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]);
    }

    if (includePrototype) {
      symbols = jswGetSymbolListForObjectProto(obj);
      if (symbols) {
        unsigned int i;
        for (i=0;i<symbols->symbolCount;i++)
          jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]);
      }
    }

    if (jsvIsArray(obj) || jsvIsString(obj)) {
      jsvArrayAddString(arr, "length");
    }
  }

  return arr;
}
Example #18
0
bool socketServerConnectionsIdle(JsNetwork *net) {
    char buf[CHUNK];

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP we split it into a request and a response
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);

        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));
        int error = 0;

        if (!closeConnectionNow) {
            int num = netRecv(net, sckt, buf,sizeof(buf));
            if (num<0) {
                // we probably disconnected so just get rid of this
                closeConnectionNow = true;
                error = num;
            } else {
                // add it to our request string
                if (num>0) {
                    JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
                    JsVar *oldReceiveData = receiveData;
                    if (!receiveData) receiveData = jsvNewFromEmptyString();
                    if (receiveData) {
                        jsvAppendStringBuf(receiveData, buf, (size_t)num);
                        bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
                        if (!hadHeaders && httpParseHeaders(&receiveData, connection, true)) {
                            hadHeaders = true;
                            jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders));
                            JsVar *server = jsvObjectGetChild(connection,HTTP_NAME_SERVER_VAR,0);
                            JsVar *args[2] = { connection, socket };
                            jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, args, ((socketType&ST_TYPE_MASK)==ST_HTTP) ? 2 : 1);
                            jsvUnLock(server);
                        }
                        if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                            // execute 'data' callback or save data
                            if (jswrap_stream_pushData(connection, receiveData, false)) {
                                // clear received data
                                jsvUnLock(receiveData);
                                receiveData = 0;
                            }
                        }
                        // if received data changed, update it
                        if (receiveData != oldReceiveData)
                            jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,receiveData);
                        jsvUnLock(receiveData);
                    }
                }
            }

            // send data if possible
            JsVar *sendData = jsvObjectGetChild(socket,HTTP_NAME_SEND_DATA,0);
            if (sendData && !jsvIsEmptyString(sendData)) {
                int sent = socketSendData(net, socket, sckt, &sendData);
                // FIXME? checking for errors is a bit iffy. With the esp8266 network that returns
                // varied error codes we'd want to skip SOCKET_ERR_CLOSED and let the recv side deal
                // with normal closing so we don't miss the tail of what's received, but other drivers
                // return -1 (which is the same value) for all errors. So we rely on the check ~12 lines
                // down if(num>0)closeConnectionNow=false instead.
                if (sent < 0) {
                    closeConnectionNow = true;
                    error = sent;
                }
                jsvObjectSetChild(socket, HTTP_NAME_SEND_DATA, sendData); // socketSendData prob updated sendData
            }
            // only close if we want to close, have no data to send, and aren't receiving data
            bool wantClose = jsvGetBoolAndUnLock(jsvObjectGetChild(socket,HTTP_NAME_CLOSE,0));
            if (wantClose && (!sendData || jsvIsEmptyString(sendData)) && num<=0)
                closeConnectionNow = true;
            else if (num > 0)
                closeConnectionNow = false; // guarantee that anything received is processed
            jsvUnLock(sendData);
        }
        if (closeConnectionNow) {
            // send out any data that we were POSTed
            JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
            bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
            if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                // execute 'data' callback or save data
                jswrap_stream_pushData(connection, receiveData, true);
            }
            jsvUnLock(receiveData);

            // fire error events
            bool hadError = fireErrorEvent(error, connection, socket);

            // fire the close listeners
            JsVar *params[1] = { jsvNewFromBool(hadError) };
            jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CLOSE, params, 1);
            jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1);
            jsvUnLock(params[0]);

            _socketConnectionKill(net, connection);
            JsVar *connectionName = jsvObjectIteratorGetKey(&it);
            jsvObjectIteratorNext(&it);
            jsvRemoveChild(arr, connectionName);
            jsvUnLock(connectionName);
        } else
            jsvObjectIteratorNext(&it);
        jsvUnLock2(connection, socket);
    }
    jsvObjectIteratorFree(&it);
    jsvUnLock(arr);

    return hadSockets;
}