Exemple #1
0
/*JSON{ "type":"method", "class": "String", "name" : "split",
         "description" : "Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==[1,2,3]```",
         "generate" : "jswrap_string_split",
         "params" : [ [ "separator", "JsVar", "The start character index"] ],
         "return" : ["JsVar", "Part of this string from start for len characters"]
}*/
JsVar *jswrap_string_split(JsVar *parent, JsVar *split) {
  JsVar *array;
  int last, idx, arraylen=0;
  int splitlen =  (int)jsvGetStringLength(split);
  int l = (int)jsvGetStringLength(parent) - splitlen;
  last = 0;

  array = jsvNewWithFlags(JSV_ARRAY);
  if (!array) return 0; // out of memory

  for (idx=0;idx<=l;idx++) {
    if (idx==l || jsvCompareString(parent, split, idx, 0, true)==0) {
      JsVar *part = jsvNewFromEmptyString();
      if (!part) break; // out of memory
      JsVar *idxvar = jsvMakeIntoVariableName(jsvNewFromInteger(arraylen++), part);
      if (idxvar) { // could be out of memory
        if (idx==l) idx=l+splitlen; // if the last element, do to the end of the string
        jsvAppendStringVar(part, parent, last, idx-last);
        jsvAddName(array, idxvar);
        last = idx+splitlen;
        jsvUnLock(idxvar);
      }
      jsvUnLock(part);
    }
  }
  return array;
}
Exemple #2
0
/*JSON{
  "type" : "method",
  "ifndef" : "SAVE_ON_FLASH",
  "class" : "RegExp",
  "name" : "exec",
  "params" : [
    ["str","JsVar","A string to match on"]
  ],
  "generate" : "jswrap_regexp_exec",
  "return" : ["JsVar","A result array, or null"]
}
Test this regex on a string - returns a result array on success, or `null` otherwise.


`/Wo/.exec("Hello World")` will return:

```
[
 "Wo",
 "index": 6,
 "input": "Hello World"
]
```

Or with groups `/W(o)rld/.exec("Hello World")` returns:

```
[
 "World",
 "o", "index": 6,
 "input": "Hello World"
]
```

 */
JsVar *jswrap_regexp_exec(JsVar *parent, JsVar *arg) {
  JsVar *str = jsvAsString(arg);
  JsVarInt lastIndex = jsvGetIntegerAndUnLock(jsvObjectGetChild(parent, "lastIndex", 0));
  JsVar *regex = jsvObjectGetChild(parent, "source", 0);
  if (!jsvIsString(regex)) {
    jsvUnLock2(str,regex);
    return 0;
  }
  size_t regexLen = jsvGetStringLength(regex);
  char *regexPtr = (char *)alloca(regexLen+1);
  if (!regexPtr) {
    jsvUnLock2(str,regex);
    return 0;
  }
  jsvGetString(regex, regexPtr, regexLen+1);
  jsvUnLock(regex);
  JsVar *rmatch = match(regexPtr, str, (size_t)lastIndex, jswrap_regexp_hasFlag(parent,'i'));
  jsvUnLock(str);
  if (!rmatch) {
    rmatch = jsvNewWithFlags(JSV_NULL);
    lastIndex = 0;
  } else {
    // if it's global, set lastIndex
    if (jswrap_regexp_hasFlag(parent,'g')) {
      JsVar *matchStr = jsvGetArrayItem(rmatch,0);
      lastIndex = jsvGetIntegerAndUnLock(jsvObjectGetChild(rmatch, "index", 0)) +
                  (JsVarInt)jsvGetStringLength(matchStr);
      jsvUnLock(matchStr);
    } else
      lastIndex = 0;
  }
  jsvObjectSetChildAndUnLock(parent, "lastIndex", jsvNewFromInteger(lastIndex));
  return rmatch;
}
Exemple #3
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "split",
  "generate" : "jswrap_string_split",
  "params" : [
    ["separator","JsVar","The start character index"]
  ],
  "return" : ["JsVar","Part of this string from start for len characters"]
}
Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==[1,2,3]```
*/
JsVar *jswrap_string_split(JsVar *parent, JsVar *split) {
  JsVar *array = jsvNewWithFlags(JSV_ARRAY);
  if (!array) return 0; // out of memory

  if (jsvIsUndefined(split)) {
    jsvArrayPush(array, parent);
    return array;
  }

  split = jsvAsString(split, false);

  int idx, last = 0;
  int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split);
  int l = (int)jsvGetStringLength(parent) + 1 - splitlen;

  for (idx=0;idx<=l;idx++) {
    if (splitlen==0 && idx==0) continue; // special case for where split string is ""
    if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) {
      if (idx==l) {
        idx=l+splitlen; // if the last element, do to the end of the string
        if (splitlen==0) break;
      }

      JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last));
      if (!part) break; // out of memory
      jsvArrayPush(array, part);
      jsvUnLock(part);
      last = idx+splitlen;
    }
  }
  jsvUnLock(split);
  return array;
}
Exemple #4
0
/** Push data into a stream. To be used by Espruino (not a user).
 * This either calls the on('data') handler if it exists, or it
 * puts the data in a buffer. This MAY CLAIM the string that is
 * passed in.
 *
 * This will return true on success, or false if the buffer is
 * full. Setting force=true will attempt to fill the buffer as
 * full as possible, and will raise an error flag if data is lost.
 */
bool jswrap_stream_pushData(JsVar *parent, JsVar *dataString, bool force) {
  assert(jsvIsObject(parent));
  assert(jsvIsString(dataString));
  bool ok = true;

  JsVar *callback = jsvFindChildFromString(parent, STREAM_CALLBACK_NAME, false);
  if (callback) {
    if (!jsiExecuteEventCallback(parent, callback, dataString, 0)) {
      jsError("Error processing Serial data handler - removing it.");
      jsErrorFlags |= JSERR_CALLBACK;
      jsvRemoveNamedChild(parent, STREAM_CALLBACK_NAME);
    }
    jsvUnLock(callback);
  } else {
    // No callback - try and add buffer
    JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0);
    if (!jsvIsString(buf)) {
      // no buffer, just set this one up
      jsvObjectSetChild(parent, STREAM_BUFFER_NAME, dataString);
    } else {
      // append (if there is room!)
      size_t bufLen = jsvGetStringLength(buf);
      size_t dataLen = jsvGetStringLength(dataString);
      if (bufLen + dataLen > STREAM_MAX_BUFFER_SIZE) {
        if (force) jsErrorFlags |= JSERR_BUFFER_FULL;
        // jsWarn("String buffer overflowed maximum size (%d)", STREAM_MAX_BUFFER_SIZE);
        ok = false;
      }
      if ((ok || force) && (bufLen < STREAM_MAX_BUFFER_SIZE))
        jsvAppendStringVar(buf, dataString, 0, STREAM_MAX_BUFFER_SIZE-bufLen);
      jsvUnLock(buf);
    }
  }
  return ok;
}
Exemple #5
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "startsWith",
  "ifndef" : "SAVE_ON_FLASH",
  "generate" : "jswrap_string_startsWith",
  "params" : [
    ["searchString","JsVar","The string to search for"],
    ["position","int","The start character index (or 0 if not defined)"]
  ],
  "return" : ["bool","`true` if the given characters are found at the beginning of the string, otherwise, `false`."]
}
*/
bool jswrap_string_startsWith(JsVar *parent, JsVar *search, int position) {
  if (!jsvIsString(parent)) return false;
  JsVar *searchStr = jsvAsString(search);
  bool match = false;
  if (position >= 0 &&
      jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent))
   match = jsvCompareString(parent, searchStr, position,0,true)==0;
  jsvUnLock(searchStr);
  return match;
}
Exemple #6
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "endsWith",
  "ifndef" : "SAVE_ON_FLASH",
  "generate" : "jswrap_string_endsWith",
  "params" : [
    ["searchString","JsVar","The string to search for"],
    ["length","JsVar","The 'end' of the string - if left off the actual length of the string is used"]
  ],
  "return" : ["bool","`true` if the given characters are found at the end of the string, otherwise, `false`."]
}
*/
bool jswrap_string_endsWith(JsVar *parent, JsVar *search, JsVar *length) {
  if (!jsvIsString(parent)) return false;
  int position = jsvIsNumeric(length) ? jsvGetInteger(length) : (int)jsvGetStringLength(parent);
  JsVar *searchStr = jsvAsString(search);
  position -= jsvGetStringLength(searchStr);
  bool match = false;
  if (position >= 0 &&
      jsvGetStringLength(searchStr)+position <= jsvGetStringLength(parent))
    match = jsvCompareString(parent, searchStr, position,0,true)==0;
  jsvUnLock(searchStr);
  return match;
}
Exemple #7
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "slice",
  "generate" : "jswrap_string_slice",
  "params" : [
    ["start","int","The start character index, if negative it is from the end of the string"],
    ["end","JsVar","The end character index, if negative it is from the end of the string, and if omitted it is the end of the string"]
  ],
  "return" : ["JsVar","Part of this string from start for len characters"]
}*/
JsVar *jswrap_string_slice(JsVar *parent, JsVarInt pStart, JsVar *vEnd) {
  JsVar *res;
  JsVarInt pEnd = jsvIsUndefined(vEnd) ? JSVAPPENDSTRINGVAR_MAXLENGTH : (int)jsvGetInteger(vEnd);
  if (pStart<0) pStart += (JsVarInt)jsvGetStringLength(parent);
  if (pEnd<0) pEnd += (JsVarInt)jsvGetStringLength(parent);
  if (pStart<0) pStart = 0;
  if (pEnd<0) pEnd = 0;
  res = jsvNewFromEmptyString();
  if (!res) return 0; // out of memory
  if (pEnd>pStart)
    jsvAppendStringVar(res, parent, (size_t)pStart, (size_t)(pEnd-pStart));
  return res;
}
Exemple #8
0
/*JSON{ "type":"method", "class": "String", "name" : "indexOf",
         "description" : "Return the index of substring in this string, or -1 if not found",
         "generate" : "jswrap_string_indexOf",
         "params" : [ [ "substring", "JsVar", "The string to search for"] ],
         "return" : ["int", "The index of the string, or -1 if not found"]
}*/
JsVarInt jswrap_string_indexOf(JsVar *parent, JsVar *v) {
  // slow, but simple!
   v = jsvAsString(v, false);
   if (!v) return 0; // out of memory
   int idx = -1;
   int l = (int)jsvGetStringLength(parent) - (int)jsvGetStringLength(v);
   for (idx=0;idx<l;idx++) {
     if (jsvCompareString(parent, v, idx, 0, true)==0) {
       jsvUnLock(v);
       return idx;
     }
   }
   jsvUnLock(v);
   return -1;
}
Exemple #9
0
bool socketSendData(JsNetwork *net, JsVar *connection, int sckt, JsVar **sendData) {
    char buf[64];

    int a=1;
    if (!jsvIsEmptyString(*sendData)) {
        size_t bufLen = httpStringGet(*sendData, buf, sizeof(buf));
        a = net->send(net, sckt, buf, bufLen);
        // Now cut what we managed to send off the beginning of sendData
        if (a>0) {
            JsVar *newSendData = 0;
            if (a < (int)jsvGetStringLength(*sendData)) {
                // we didn't send all of it... cut out what we did send
                newSendData = jsvNewFromStringVar(*sendData, (size_t)a, JSVAPPENDSTRINGVAR_MAXLENGTH);
            } else {
                // we sent all of it! Issue a drain event
                jsiQueueObjectCallbacks(connection, "#ondrain", &connection, 1);
            }
            jsvUnLock(*sendData);
            *sendData = newSendData;
        }
    }
    if (a<0) { // could just be busy which is ok
        jsError("Socket error %d while sending", a);
        return false;
    }
    return true;
}
Exemple #10
0
// returns 0 on success and a (negative) error number on failure
int socketSendData(JsNetwork *net, JsVar *connection, int sckt, JsVar **sendData) {
    char *buf = alloca(net->chunkSize); // allocate on stack

    assert(!jsvIsEmptyString(*sendData));

    size_t bufLen = httpStringGet(*sendData, buf, net->chunkSize);
    int num = netSend(net, sckt, buf, bufLen);
    if (num < 0) return num; // an error occurred
    // Now cut what we managed to send off the beginning of sendData
    if (num > 0) {
        JsVar *newSendData = 0;
        if (num < (int)jsvGetStringLength(*sendData)) {
            // we didn't send all of it... cut out what we did send
            newSendData = jsvNewFromStringVar(*sendData, (size_t)num, JSVAPPENDSTRINGVAR_MAXLENGTH);
        } else {
            // we sent all of it! Issue a drain event, unless we want to close, then we shouldn't
            // callback for more data
            bool wantClose = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_CLOSE,0));
            if (!wantClose) {
                jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_DRAIN, &connection, 1);
            }
            newSendData = jsvNewFromEmptyString();
        }
        jsvUnLock(*sendData);
        *sendData = newSendData;
    }

    return 0;
}
Exemple #11
0
/*JSON{
  "type" : "method",
  "class" : "OneWire",
  "name" : "select",
  "generate" : "jswrap_onewire_select",
  "params" : [
    ["rom","JsVar","The device to select (get this using `OneWire.search()`)"]
  ]
}
Select a ROM - always performs a reset first
 */
void jswrap_onewire_select(JsVar *parent, JsVar *rom) {
  Pin pin = onewire_getpin(parent);
  if (!jshIsPinValid(pin)) return;
  if (!jsvIsString(rom) || jsvGetStringLength(rom)!=16) {
    jsExceptionHere(JSET_TYPEERROR, "Invalid OneWire device address %q", rom);
    return;
  }

  // perform a reset
  OneWireReset(pin);

  // decode the address
  unsigned long long romdata = 0;
  JsvStringIterator it;
  jsvStringIteratorNew(&it, rom, 0);
  int i;
  for (i=0;i<8;i++) {
    char b[3];
    b[0] = jsvStringIteratorGetChar(&it);
    jsvStringIteratorNext(&it);
    b[1] = jsvStringIteratorGetChar(&it);
    jsvStringIteratorNext(&it);
    b[2] = 0;
    romdata = romdata | (((unsigned long long)stringToIntWithRadix(b,16,NULL,NULL)) << (i*8));

  }
  jsvStringIteratorFree(&it);

  // finally write data out
  OneWireWrite(pin, 8, 0x55);
  OneWireWrite(pin, 64, romdata);
}
Exemple #12
0
JsVar *jslNewStringFromLexer(JslCharPos *charFrom, size_t charTo) {
  // Original method - just copy it verbatim
  size_t maxLength = charTo + 1 - jsvStringIteratorGetIndex(&charFrom->it);
  assert(maxLength>0); // will fail if 0
  // Try and create a flat string first
  JsVar *var = 0;
  if (maxLength > JSV_FLAT_STRING_BREAK_EVEN) {
    var = jsvNewFlatStringOfLength((unsigned int)maxLength);
    if (var) {
      // Flat string
      char *flatPtr = jsvGetFlatStringPointer(var);
      *(flatPtr++) = charFrom->currCh;
      JsvStringIterator it = jsvStringIteratorClone(&charFrom->it);
      while (jsvStringIteratorHasChar(&it) && (--maxLength>0)) {
        *(flatPtr++) = jsvStringIteratorGetChar(&it);
        jsvStringIteratorNext(&it);
      }
      jsvStringIteratorFree(&it);
      return var;
    }
  }
  // Non-flat string...
  var = jsvNewFromEmptyString();
  if (!var) { // out of memory
    return 0;
  }

  //jsvAppendStringVar(var, lex->sourceVar, charFrom->it->index, (int)(charTo-charFrom));
  JsVar *block = jsvLockAgain(var);
  block->varData.str[0] = charFrom->currCh;
  size_t blockChars = 1;

  size_t l = maxLength;
  // now start appending
  JsvStringIterator it = jsvStringIteratorClone(&charFrom->it);
  while (jsvStringIteratorHasChar(&it) && (--maxLength>0)) {
    char ch = jsvStringIteratorGetChar(&it);
    if (blockChars >= jsvGetMaxCharactersInVar(block)) {
      jsvSetCharactersInVar(block, blockChars);
      JsVar *next = jsvNewWithFlags(JSV_STRING_EXT_0);
      if (!next) break; // out of memory
      // we don't ref, because  StringExts are never reffed as they only have one owner (and ALWAYS have an owner)
      jsvSetLastChild(block, jsvGetRef(next));
      jsvUnLock(block);
      block = next;
      blockChars=0; // it's new, so empty
    }
    block->varData.str[blockChars++] = ch;
    jsvStringIteratorNext(&it);
  }
  jsvSetCharactersInVar(block, blockChars);
  jsvUnLock(block);
  // Just make sure we only assert if there's a bug here. If we just ran out of memory or at end of string it's ok
  assert((l == jsvGetStringLength(var)) || (jsErrorFlags&JSERR_MEMORY) || !jsvStringIteratorHasChar(&it));
  jsvStringIteratorFree(&it);


  return var;
}
Exemple #13
0
// Return how many bytes are available to read
JsVarInt jswrap_stream_available(JsVar *parent) {
  if (!jsvIsObject(parent)) return 0;
  JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0);
  JsVarInt chars = 0;
  if (jsvIsString(buf))
    chars = (JsVarInt)jsvGetStringLength(buf);
  jsvUnLock(buf);
  return chars;
}
Exemple #14
0
void socketClientPushReceiveData(JsVar *connection, JsVar *socket, JsVar **receiveData) {
    if (*receiveData && jsvGetStringLength(*receiveData)) {
        jswrap_stream_pushData(socket, *receiveData);
        // clear - because we have issued a callback
        jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
        jsvUnLock(*receiveData);
        *receiveData = 0;
    }
}
/*JSON{ "type":"property", "class": "Object", "name" : "length",
         "description" : "Find the length of the object",
         "generate" : "jswrap_object_length",
         "return" : ["JsVar", "The value of the string"]
}*/
JsVar *jswrap_object_length(JsVar *parent) {
  if (jsvIsArray(parent)) {
    return jsvNewFromInteger(jsvGetArrayLength(parent));
  } else if (jsvIsArrayBuffer(parent)) {
      return jsvNewFromInteger((JsVarInt)jsvGetArrayBufferLength(parent));
  } else if (jsvIsString(parent)) {
    return jsvNewFromInteger((JsVarInt)jsvGetStringLength(parent));
  }
  return 0;
}
Exemple #16
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "lastIndexOf",
  "generate_full" : "jswrap_string_indexOf(parent, substring, fromIndex, true)",
  "params" : [
    ["substring","JsVar","The string to search for"],
    ["fromIndex","JsVar","Index to search from"]
  ],
  "return" : ["int32","The index of the string, or -1 if not found"]
}
Return the last index of substring in this string, or -1 if not found
*/
int jswrap_string_indexOf(JsVar *parent, JsVar *substring, JsVar *fromIndex, bool lastIndexOf) {
  if (!jsvIsString(parent)) return 0;
  // slow, but simple!
  substring = jsvAsString(substring, false);
  if (!substring) return 0; // out of memory
  int parentLength = (int)jsvGetStringLength(parent);
  int subStringLength = (int)jsvGetStringLength(substring);
  if (subStringLength > parentLength) {
    jsvUnLock(substring);
    return -1;
  }
  int lastPossibleSearch = parentLength - subStringLength;
  int idx, dir, end;
  if (!lastIndexOf) { // normal indexOf
    dir = 1;
    end = lastPossibleSearch+1;
    idx = 0;
    if (jsvIsNumeric(fromIndex)) {
      idx = (int)jsvGetInteger(fromIndex);
      if (idx<0) idx=0;
      if (idx>end) idx=end;
    }
  } else {
    dir = -1;
    end = -1;
    idx = lastPossibleSearch;
    if (jsvIsNumeric(fromIndex)) {
      idx = (int)jsvGetInteger(fromIndex);
      if (idx<0) idx=0;
      if (idx>lastPossibleSearch) idx=lastPossibleSearch;
    }
  }

  for (;idx!=end;idx+=dir) {
    if (jsvCompareString(parent, substring, (size_t)idx, 0, true)==0) {
      jsvUnLock(substring);
      return idx;
    }
  }
  jsvUnLock(substring);
  return -1;
}
Exemple #17
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "substr",
  "generate" : "jswrap_string_substr",
  "params" : [
    ["start","int","The start character index"],
    ["len","JsVar","The number of characters"]
  ],
  "return" : ["JsVar","Part of this string from start for len characters"]
}*/
JsVar *jswrap_string_substr(JsVar *parent, JsVarInt pStart, JsVar *vLen) {
  JsVar *res;
  JsVarInt pLen = jsvIsUndefined(vLen) ? JSVAPPENDSTRINGVAR_MAXLENGTH : (int)jsvGetInteger(vLen);
  if (pLen<0) pLen = 0;
  if (pStart<0) pStart += (JsVarInt)jsvGetStringLength(parent);
  if (pStart<0) pStart = 0;
  res = jsvNewFromEmptyString();
  if (!res) return 0; // out of memory
  jsvAppendStringVar(res, parent, (size_t)pStart, (size_t)pLen);
  return res;
}
Exemple #18
0
/*JSON{
  "type"     : "staticmethod",
  "class"    : "ESP8266WiFi",
  "name"     : "beAccessPoint",
  "generate" : "jswrap_ESP8266WiFi_beAccessPoint",
  "params"   : [
    ["jsv_ssid", "JsVar", "The network SSID"],
    ["jsv_password", "JsVar", "The password to allow stations to connect to the access point"]
  ]
}*/
void jswrap_ESP8266WiFi_beAccessPoint(
    JsVar *jsv_ssid,    //!< The network identity that the access point will advertize itself as.
    JsVar *jsv_password //!< The password a station will need to connect to the access point.
  ) {
  os_printf("> jswrap_ESP8266WiFi_beAccessPoint\n");
  // Validate that the SSID and password are somewhat useful.
  if (jsv_ssid == NULL || !jsvIsString(jsv_ssid)) {
      jsExceptionHere(JSET_ERROR, "No SSID.");
    return;
  }

  // Build our SoftAP configuration details
  struct softap_config softApConfig;
  memset(&softApConfig, 0, sizeof(softApConfig));

  // If no password has been supplied, then be open.  Otherwise, use WPA2 and the
  // password supplied.  Also check that the password is at least 8 characters long.
  if (jsv_password == NULL || !jsvIsString(jsv_password)) {
    softApConfig.authmode = AUTH_OPEN;
  } else {
    if (jsvGetStringLength(jsv_password) < 8) {
      jsExceptionHere(JSET_ERROR, "Password must be 8 characters or more in length.");
      return;
    }
    softApConfig.authmode = AUTH_WPA2_PSK;
    int len = jsvGetString(jsv_password, (char *)softApConfig.password, sizeof(softApConfig.password)-1);
    softApConfig.password[len]='\0';
  }

  int len = jsvGetString(jsv_ssid, (char *)softApConfig.ssid, sizeof(softApConfig.ssid)-1);
  softApConfig.ssid[len]='\0';

  // Define that we are in Soft AP mode.
  os_printf("Wifi: switching to soft-AP mode, authmode=%d\n", softApConfig.authmode);
  wifi_set_opmode_current(SOFTAP_MODE);

  softApConfig.ssid_len       = 0; // Null terminated SSID
  softApConfig.ssid_hidden    = 0; // Not hidden.
  softApConfig.max_connection = 4; // Maximum number of connections.

  // Set the WiFi configuration.
  int rc = wifi_softap_set_config_current(&softApConfig);
  // We should really check that becoming an access point works, however as of SDK 1.4, we
  // are finding that if we are currently connected to an access point and we switch to being
  // an access point, it works ... but returns 1 indicating an error.
  /*
  if (rc != 1) {
      os_printf(" - Error returned from wifi_softap_set_config_current=%d\n", rc);
      jsExceptionHere(JSET_ERROR, "Error setting ESP8266 softap config.");
  }
  */
  os_printf("< jswrap_ESP8266WiFi_beAccessPoint\n");
}
Exemple #19
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "match",
  "generate" : "jswrap_string_match",
  "params" : [
    ["subStr","JsVar","Substring or RegExp to match"]
  ],
  "return" : ["JsVar","This match array"]
}
Matches `subStr` occurrence in the string.
 */
JsVar *jswrap_string_match(JsVar *parent, JsVar *subStr) {
  if (!jsvIsString(parent)) return 0;
  if (jsvIsUndefined(subStr)) return 0;

#ifndef SAVE_ON_FLASH
  // Use RegExp if one is passed in
  if (jsvIsInstanceOf(subStr, "RegExp")) {
    jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0));
    JsVar *match;
    match = jswrap_regexp_exec(subStr, parent);
    if (!jswrap_regexp_hasFlag(subStr,'g')) {
      return match;
    }

    // global
    JsVar *array = jsvNewEmptyArray();
    if (!array) return 0; // out of memory
    while (match && !jsvIsNull(match)) {
      // get info about match
      JsVar *matchStr = jsvGetArrayItem(match,0);
      JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0));
      JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr);
      int last = idx+len;
      jsvArrayPushAndUnLock(array, matchStr);
      // search again
      jsvUnLock(match);
      jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(last));
      match = jswrap_regexp_exec(subStr, parent);
    }
    jsvUnLock(match);
    jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0));
    return array;
  }
#endif

  subStr = jsvAsString(subStr);

  int idx = jswrap_string_indexOf(parent, subStr, 0, false);
  if (idx>=0) {
      JsVar *array = jsvNewEmptyArray();
      if (!array) {
        jsvUnLock(subStr);
        return 0; // out of memory
      }

      jsvArrayPush(array, subStr);
      jsvObjectSetChildAndUnLock(array, "index", jsvNewFromInteger(idx));
      jsvObjectSetChildAndUnLock(array, "input", subStr);
      return array;
  }
  jsvUnLock(subStr);
  return NULL;
}
Exemple #20
0
/*JSON{
  "type" : "property",
  "class" : "Object",
  "name" : "length",
  "generate" : "jswrap_object_length",
  "return" : ["JsVar","The length of the object"]
}
Find the length of the object
 */
JsVar *jswrap_object_length(JsVar *parent) {
  JsVarInt l;
  if (jsvIsArray(parent)) {
    l = jsvGetArrayLength(parent);
  } else if (jsvIsArrayBuffer(parent)) {
    l = (JsVarInt)jsvGetArrayBufferLength(parent);
  } else if (jsvIsString(parent)) {
    l = (JsVarInt)jsvGetStringLength(parent);
  } else if (jsvIsFunction(parent)) {
    JsVar *args = jsvGetFunctionArgumentLength(parent);
    l = jsvGetArrayLength(args);
    jsvUnLock(args);
  } else
    return 0;
  return jsvNewFromInteger(l);
}
Exemple #21
0
/*JSON{
  "type" : "method",
  "class" : "String",
  "name" : "replace",
  "generate" : "jswrap_string_replace",
  "params" : [
    ["subStr","JsVar","The string to search for"],
    ["newSubStr","JsVar","The string to replace it with"]
  ],
  "return" : ["JsVar","This string with `subStr` replaced"]
}
Search and replace ONE occurrance of `subStr` with `newSubStr` and return the result. This doesn't alter the original string. Regular expressions not supported.
 */
JsVar *jswrap_string_replace(JsVar *parent, JsVar *subStr, JsVar *newSubStr) {
  JsVar *str = jsvAsString(parent, false);
  subStr = jsvAsString(subStr, false);
  newSubStr = jsvAsString(newSubStr, false);

  int idx = jswrap_string_indexOf(parent, subStr, 0, false);
  if (idx>=0) {
    JsVar *newStr = jsvNewFromStringVar(str, 0, (size_t)idx);
    jsvAppendStringVar(newStr, newSubStr, 0, JSVAPPENDSTRINGVAR_MAXLENGTH);
    jsvAppendStringVar(newStr, str, (size_t)idx+jsvGetStringLength(subStr), JSVAPPENDSTRINGVAR_MAXLENGTH);
    jsvUnLock(str);
    str = newStr;
  }

  jsvUnLock2(subStr, newSubStr);
  return str;
}
Exemple #22
0
static bool jsfGetJSONForObjectItWithCallback(JsvObjectIterator *it, JSONFlags flags, const char *whitespace, JSONFlags nflags, vcbprintf_callback user_callback, void *user_data, bool first) {
  bool needNewLine = false;
  size_t sinceNewLine = 0;
  while (jsvObjectIteratorHasValue(it) && !jspIsInterrupted()) {
    JsVar *index = jsvObjectIteratorGetKey(it);
    JsVar *item = jsvGetValueOfName(index);
    bool hidden = jsvIsInternalObjectKey(index) ||
        ((flags & JSON_IGNORE_FUNCTIONS) && jsvIsFunction(item)) ||
        ((flags&JSON_NO_UNDEFINED) && jsvIsUndefined(item)) ||
        jsvIsGetterOrSetter(item);
    if (!hidden) {
      sinceNewLine++;
      if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
      bool newNeedsNewLine = (flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item);
      if ((flags&JSON_SOME_NEWLINES) && sinceNewLine>JSON_ITEMS_ON_LINE_OBJECT)
        needNewLine = true;
      if (flags&JSON_ALL_NEWLINES) {
        needNewLine = true;
        newNeedsNewLine = true;
      }
      if (needNewLine || newNeedsNewLine) {
        jsonNewLine(nflags, whitespace, user_callback, user_data);
        needNewLine = false;
        sinceNewLine = 0;
      }
      bool addQuotes = true;
      if (flags&JSON_DROP_QUOTES) {
        if (jsvIsIntegerish(index)) addQuotes = false;
        else if (jsvIsString(index) && jsvGetStringLength(index)<15) {
          char buf[16];
          jsvGetString(index,buf,sizeof(buf));
          if (isIDString(buf)) addQuotes=false;
        }
      }
      cbprintf(user_callback, user_data, addQuotes?"%q%s":"%v%s", index, (flags&JSON_PRETTY)?": ":":");
      if (first)
        first = false;
      jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
      needNewLine = newNeedsNewLine;
    }
    jsvUnLock2(index, item);
    jsvObjectIteratorNext(it);
  }
  return needNewLine;
}
Exemple #23
0
bool _http_send(SOCKET sckt, JsVar **sendData) {
  char buf[64];

  int a=1;
  int len = (int)jsvGetStringLength(*sendData);
  if (len>0) {
    size_t bufLen = httpStringGet(*sendData, buf, sizeof(buf));
    a = (int)send(sckt,buf,bufLen, MSG_NOSIGNAL);
    JsVar *newSendData = 0;
    if (a!=len) {
      newSendData = jsvNewFromEmptyString();
      jsvAppendStringVar(newSendData, *sendData, a, JSVAPPENDSTRINGVAR_MAXLENGTH);
    }
    jsvUnLock(*sendData);
    *sendData = newSendData;
  }
  if (a<=0) {
    httpError("Socket error while sending");
    return false;
  } return true;
}
Exemple #24
0
// Return a string containing 'chars' bytes. If chars<=0 the string will be all available data
JsVar *jswrap_stream_read(JsVar *parent, JsVarInt chars) {
  if (!jsvIsObject(parent)) return 0;
  JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0);
  JsVar *data = 0;
  if (jsvIsString(buf)) {
    size_t len = jsvGetStringLength(buf);
    if (chars <= 0 || (size_t)chars>=len) {
      // return the whole buffer and remove it
      data = buf;
      buf = 0;
      jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME);
    } else {
      // return just part of the buffer, and shorten it accordingly
      data = jsvNewFromStringVar(buf, 0, (size_t)chars);
      JsVar *newBuf = jsvNewFromStringVar(buf, (size_t)chars, JSVAPPENDSTRINGVAR_MAXLENGTH);
      jsvUnLock(jsvObjectSetChild(parent, STREAM_BUFFER_NAME, newBuf));
    }
  } else
    data = jsvNewFromEmptyString();
  jsvUnLock(buf);
  return data;
}
Exemple #25
0
bool socketClientConnectionsIdle(JsNetwork *net) {
    char *buf = alloca(net->chunkSize); // allocate on stack

    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 connection is httpCRq and socket is httpCRs
        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 && !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, net->chunkSize);
                    //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) {
                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 && jsvGetStringLength(sendData) > 0 && 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 there is 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;
}
Exemple #26
0
/*JSON{
  "type" : "staticmethod",
  "class" : "url",
  "name" : "parse",
  "generate" : "jswrap_url_parse",
  "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`"]
}
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"}}`
*/
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
  if (addrStart>0)
    jsvObjectSetChildAndUnLock(obj, "protocol", jsvNewFromStringVar(url, 0, (size_t)addrStart-1));
  jsvObjectSetChildAndUnLock(obj, "method", jsvNewFromString("GET"));
  jsvObjectSetChildAndUnLock(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, "/");
  jsvObjectSetChildAndUnLock(obj, "path", v);

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

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

  jsvObjectSetChildAndUnLock(obj, "port", (portNumber<=0 || portNumber>65535) ? jsvNewWithFlags(JSV_NULL) : 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) {
          key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0
          jsvMakeIntoVariableName(key, val);
          jsvAddName(query, key);
          jsvUnLock2(key, val);
          key = jsvNewFromEmptyString();
          val = jsvNewFromEmptyString();
          hadEquals = false;
        }
      } else if (!hadEquals && ch=='=') {
        hadEquals = true;
      } else {
        // decode percent escape chars
        if (ch=='%') {
          jsvStringIteratorNext(&it);
          ch = jsvStringIteratorGetChar(&it);
          jsvStringIteratorNext(&it);
          ch = (char)((chtod(ch)<<4) | chtod(jsvStringIteratorGetChar(&it)));
        }

        if (hadEquals) jsvAppendCharacter(val, ch);
        else jsvAppendCharacter(key, ch);
      }
      jsvStringIteratorNext(&it);
      charIdx++;
    }
    jsvStringIteratorFree(&it);
    jsvUnLock(queryStr);

    if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) {
      key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0
      jsvMakeIntoVariableName(key, val);
      jsvAddName(query, key);
    }
    jsvUnLock2(key, val);
  }
  jsvObjectSetChildAndUnLock(obj, "query", query);

  return obj;
}
Exemple #27
0
void jsfGetJSONWithCallback(JsVar *var, JSONFlags flags, const char *whitespace, 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 (!whitespace) whitespace="  ";

  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)) {
      JsVarInt length = jsvGetArrayLength(var);
      bool limited = (flags&JSON_LIMIT) && (length>(JsVarInt)JSON_LIMIT_AMOUNT);
      bool needNewLine = false;
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
      JsVarInt lastIndex = -1;
      bool numeric = true;
      bool first = true;
      JsvObjectIterator it;
      jsvObjectIteratorNew(&it, var);
      while (lastIndex+1<length && numeric && !jspIsInterrupted()) {
        JsVar *key = jsvObjectIteratorGetKey(&it);
        if (!jsvObjectIteratorHasValue(&it) || jsvIsNumeric(key)) {
          JsVarInt index = jsvObjectIteratorHasValue(&it) ? jsvGetInteger(key) : length-1;
          JsVar *item = jsvObjectIteratorGetValue(&it);
          while (lastIndex < index) {
            lastIndex++;
            if (!limited || lastIndex<(JsVarInt)JSON_LIMITED_AMOUNT || lastIndex>=length-(JsVarInt)JSON_LIMITED_AMOUNT) {
              if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
              first = false;
              if (limited && lastIndex==length-(JsVarInt)JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
              bool newNeedsNewLine = ((flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item));
              if (flags&JSON_ALL_NEWLINES) {
                needNewLine = true;
                newNeedsNewLine = true;
              }
              if (needNewLine || newNeedsNewLine) {
                jsonNewLine(nflags, whitespace, user_callback, user_data);
                needNewLine = false;
              }
              if (lastIndex == index)
                jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
              else
                cbprintf(user_callback, user_data, (flags&JSON_NO_UNDEFINED)?"null":"undefined");
              needNewLine = newNeedsNewLine;
            }
          }
          jsvUnLock(item);
          jsvObjectIteratorNext(&it);
        } else {
          numeric = false;
        }
        jsvUnLock(key);
      }

      // non-numeric  - but NOT for standard JSON
      if ((flags&JSON_PRETTY))
        jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, first);
      jsvObjectIteratorFree(&it);
      if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" ]":"]");
    } else if (jsvIsArrayBuffer(var)) {
      JsvArrayBufferIterator it;
      bool allZero = true;
      jsvArrayBufferIteratorNew(&it, var, 0);
      while (jsvArrayBufferIteratorHasElement(&it)) {
        if (jsvArrayBufferIteratorGetFloatValue(&it)!=0)
          allZero = false;
        jsvArrayBufferIteratorNext(&it);
      }
      jsvArrayBufferIteratorFree(&it);
      bool asArray = flags&JSON_ARRAYBUFFER_AS_ARRAY;

      if (allZero && !asArray) {
        cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
      } else {
        const char *aname = jswGetBasicObjectName(var);
        /* You can't do `new ArrayBuffer([1,2,3])` so we have to output
         * `new Uint8Array([1,2,3]).buffer`! */
        bool isBasicArrayBuffer = strcmp(aname,"ArrayBuffer")==0;
        if (isBasicArrayBuffer) {
          aname="Uint8Array";
        }
        cbprintf(user_callback, user_data, asArray?"[":"new %s([", aname);
        if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
        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

        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 (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
            if (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
            JsVar *item = jsvArrayBufferIteratorGetValue(&it);
            jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
            jsvUnLock(item);
          }
          jsvArrayBufferIteratorNext(&it);
        }
        if (flags&JSON_ALL_NEWLINES) jsonNewLine(flags, whitespace, user_callback, user_data);
        jsvArrayBufferIteratorFree(&it);
        cbprintf(user_callback, user_data, asArray?"]":"])");
        if (isBasicArrayBuffer && !asArray) cbprintf(user_callback, user_data, ".buffer");
      }
    } 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 showContents = true;
        if (flags & JSON_SHOW_OBJECT_NAMES) {
          JsVar *proto = jsvObjectGetChild(var, JSPARSE_INHERITS_VAR, 0);
          if (jsvHasChildren(proto)) {
            JsVar *constr = jsvObjectGetChild(proto, JSPARSE_CONSTRUCTOR_VAR, 0);
            if (constr) {
              JsVar *p = jsvGetIndexOf(execInfo.root, constr, true);
              if (p) cbprintf(user_callback, user_data, "%v: ", p);
              jsvUnLock2(p,constr);
              /* We had the constructor - now if there was a non-default toString function
               * we'll execute it and print the result */
              JsVar *toStringFn = jspGetNamedField(var, "toString", false);
              if (toStringFn && toStringFn->varData.native.ptr != (void (*)(void))jswrap_object_toString) {
                // Function found and it's not the default one - execute it
                JsVar *result = jspExecuteFunction(toStringFn,var,0,0);
                cbprintf(user_callback, user_data, "%v", result);
                jsvUnLock(result);
                showContents = false; // we already printed something
              }
              jsvUnLock(toStringFn);
            }
          }
          jsvUnLock(proto);
        }
        if (showContents) {
          JsvObjectIterator it;
          jsvObjectIteratorNew(&it, var);
          cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
          bool needNewLine = jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, true);
          jsvObjectIteratorFree(&it);
          if (needNewLine) jsonNewLine(flags, whitespace, 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);
        jsvUnLock2(var1, var2);
      } else {
        cbprintf(user_callback, user_data, "%q", var);
      }
    } else {
      cbprintf(user_callback, user_data, "%v", var);
    }

    var->flags &= ~JSV_IS_RECURSING;
  }
}
Exemple #28
0
/*JSON{ "type":"staticmethod",
         "class" : "Integer", "name" : "valueOf",
         "generate" : "jswrap_integer_valueOf",
         "description" : "Given a string containing a single character, return the numeric value of it",
         "params" : [ [ "character" ,"JsVar", "A string containing a single character"] ],
         "return" : ["int", "The integer value of char"]
}*/
JsVarInt jswrap_integer_valueOf(JsVar *v) {
  if (!jsvIsString(v) || jsvGetStringLength(v)!=1)
    return 0;
  return (int)v->varData.str[0];
}
Exemple #29
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)) {
      JsvArrayBufferIterator it;
      bool allZero = true;
      jsvArrayBufferIteratorNew(&it, var, 0);
      while (jsvArrayBufferIteratorHasElement(&it)) {
        if (jsvArrayBufferIteratorGetFloatValue(&it)!=0)
          allZero = false;
        jsvArrayBufferIteratorNext(&it);
      }
      jsvArrayBufferIteratorFree(&it);

      if (allZero) {
        cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
      } else {
        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

        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;
  }
}
Exemple #30
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);
    }
}