/// <summary> /// Replace all instances of a pattern in a string with a replacement string (scanning from left to right). /// </summary> /// <param name="str">The string to search through (if NULL, an empty string is returned).</param> /// <param name="pattern">The pattern to search for (if NULL, 'str' is returned).</param> /// <param name="replacement">Replacement text for each instance of the pattern (if NULL, will be treated as empty).</param> /// <returns>A new string where all instances of the pattern have been replaced by the given replacement string.</returns> String String_Replace(const String str, const String pattern, const String replacement) { const struct StringInt *s, *p, *r; StringBuilder stringBuilder; struct StringBuilderInt sb; Byte *text, *patText, *repText; Int lastEnd, index; if (String_IsNullOrEmpty(str)) return String_Empty; if (String_IsNullOrEmpty(pattern)) return str; s = (const struct StringInt *)str; text = s->text; p = (const struct StringInt *)pattern; patText = p->text; r = replacement != NULL ? (const struct StringInt *)replacement : (const struct StringInt *)String_Empty; repText = r->text; stringBuilder = (StringBuilder)&sb; StringBuilder_InitWithSize(stringBuilder, s->length); lastEnd = 0; index = 0; while ((index = String_IndexOf(str, pattern, index)) >= 0) { if (index > lastEnd) { StringBuilder_Append(stringBuilder, text, lastEnd, index - lastEnd); } StringBuilder_Append(stringBuilder, repText, 0, r->length); lastEnd = (index += p->length); } if (lastEnd < s->length) { StringBuilder_Append(stringBuilder, text, lastEnd, s->length - lastEnd); } return StringBuilder_ToString(stringBuilder); }
StringBuilder StringBuilder_AppendInt(StringBuilder dynString, int value) { DynamicString string = (DynamicString) dynString; if (string) { // 32-bits gives a 10-digit number + 1 for the null-terminator char str[11]; memset(str, 0, sizeof(str)); sprintf((char*) str, (const char*) "%d", value); string = StringBuilder_Append(string, str); } return (StringBuilder) string; }
static bool CommandBoardDetails(int argc, char** argv) { bool result = false; if (ConfigStore_Config_Read() && ConfigStore_Config_IsValid() && ConfigStore_Config_IsMagicValid()) { StringBuilder response = StringBuilder_New(256); // DeviceType response = StringBuilder_Append(response, ConfigStore_GetDeviceType()); response = StringBuilder_Append(response, LINE_TERM); // MAC address response = StringBuilder_Append(response, ConfigStore_GetMacAddress()); response = StringBuilder_Append(response, LINE_TERM); // Serial number char snString[17]; memset((void*) snString, 0, 17); if (DeviceSerial_GetCpuSerialNumberHexString(snString, 17)) response = StringBuilder_Append(response, snString); else response = StringBuilder_Append(response, " "); response = StringBuilder_Append(response, LINE_TERM); // WiFi SoftAP SSID response = StringBuilder_Append(response, ConfigStore_GetSoftAPSSID()); response = StringBuilder_Append(response, LINE_TERM); // WiFi SoftAP password response = StringBuilder_Append(response, ConfigStore_GetSoftAPPassword()); response = StringBuilder_Append(response, LINE_TERM); char CB[2] = { 0, 0 }; int32_t byteCount = StringBuilder_GetLength(response); int32_t byteIndex = 0; for (byteIndex = 0; byteIndex < byteCount; byteIndex++) { CB[0] += (StringBuilder_GetCString(response))[byteIndex]; } // Compute checkbyte - 2's compliment of MOD-256 sum CB[0] ^= 0xFF; CB[0]++; response = StringBuilder_Append(response, CB); response = StringBuilder_Append(response, LINE_TERM); CreatorConsole_Puts(response); // Output entire response // TODO - delete? // byteCount = StringBuilder_GetLength(response); // uint8_t* _response = (uint8_t*) StringBuilder_GetCString(response); // for (byteIndex = 0; byteIndex < byteCount; byteIndex++) // { // if (((char *) _response)[byteIndex] == '\n') // CreatorConsole_Puts(LINE_TERM); // else // CreatorConsole_Putc(((char *) _response)[byteIndex]); // } //CreatorConsole_Puts(LINE_TERM); StringBuilder_Free(&response); result = true; } return result; }
String Real_ToFixedString(Byte *buffer, Int32 len, Int32 exp, Int32 kind, Int32 minIntDigits, Int32 minFracDigits, Bool forceSign) { DECLARE_INLINE_STRINGBUILDER(numBuilder, 256); INIT_INLINE_STRINGBUILDER(numBuilder); switch (kind) { case REAL_KIND_POS_INF: return forceSign ? Real_String_PosInf : Real_String_Inf; case REAL_KIND_NEG_INF: return Real_String_NegInf; case REAL_KIND_POS_QNAN: return forceSign ? Real_String_PosNaN : Real_String_NaN; case REAL_KIND_NEG_QNAN: return Real_String_NegNaN; case REAL_KIND_POS_SNAN: return forceSign ? Real_String_PosSNaN : Real_String_SNaN; case REAL_KIND_NEG_SNAN: return Real_String_NegSNaN; case REAL_KIND_POS_ZERO: case REAL_KIND_POS_NUM: if (forceSign) { StringBuilder_AppendByte(numBuilder, '+'); } break; case REAL_KIND_NEG_ZERO: case REAL_KIND_NEG_NUM: StringBuilder_AppendByte(numBuilder, '-'); break; } if (exp >= 0) { // All digits are integer; none are fractional. if (len + exp < minIntDigits) { // Need to prepend initial zeros. StringBuilder_AppendRepeat(numBuilder, '0', minIntDigits - (len + exp)); } // Copy all the integer digits. StringBuilder_Append(numBuilder, buffer, 0, len); if (exp > 0) { // Emit trailing zeros. StringBuilder_AppendRepeat(numBuilder, '0', exp); } if (minFracDigits > 0) { // Need to append trailing fractional zeros. StringBuilder_AppendByte(numBuilder, '.'); StringBuilder_AppendRepeat(numBuilder, '0', minFracDigits); } } else if (-exp >= len) { // All digits are fractional; none are integer. if (minIntDigits > 0) { // Need to prepend initial zeros. StringBuilder_AppendRepeat(numBuilder, '0', minIntDigits); } // Emit the decimal point. StringBuilder_AppendByte(numBuilder, '.'); if (-exp - len > 0) { // Emit leading zeros. StringBuilder_AppendRepeat(numBuilder, '0', -exp - len); } // Copy the fractional digits. StringBuilder_Append(numBuilder, buffer, 0, len); if (minFracDigits > -exp) { // Emit trailing zeros. StringBuilder_AppendRepeat(numBuilder, '0', minFracDigits - -exp); } } else { // Negative exponent, and split across the decimal point: Some integer, some fractional digits. Int32 numIntDigits = len - -exp, numFracDigits = -exp; if (numIntDigits < minIntDigits) { // Need to prepend initial zeros. StringBuilder_AppendRepeat(numBuilder, '0', minIntDigits - numIntDigits); } // Copy all the integer digits. StringBuilder_Append(numBuilder, buffer, 0, numIntDigits); // Emit the decimal point. StringBuilder_AppendByte(numBuilder, '.'); // Copy the fractional digits. StringBuilder_Append(numBuilder, buffer, numIntDigits, numFracDigits); if (numFracDigits < minFracDigits) { // Need to append trailing zeros. StringBuilder_AppendRepeat(numBuilder, '0', minFracDigits - numFracDigits); } } return StringBuilder_ToString(numBuilder); }
String Real_ToExpString(Byte *buffer, Int32 len, Int32 exp, Int32 kind, Int32 minFracDigits, Bool forceSign) { DECLARE_INLINE_STRINGBUILDER(numBuilder, 256); Int32 numFracDigits; INIT_INLINE_STRINGBUILDER(numBuilder); switch (kind) { case REAL_KIND_POS_INF: return forceSign ? Real_String_PosInf : Real_String_Inf; case REAL_KIND_NEG_INF: return Real_String_NegInf; case REAL_KIND_POS_QNAN: return forceSign ? Real_String_PosNaN : Real_String_NaN; case REAL_KIND_NEG_QNAN: return Real_String_NegNaN; case REAL_KIND_POS_SNAN: return forceSign ? Real_String_PosSNaN : Real_String_SNaN; case REAL_KIND_NEG_SNAN: return Real_String_NegSNaN; case REAL_KIND_POS_ZERO: case REAL_KIND_POS_NUM: if (forceSign) { StringBuilder_AppendByte(numBuilder, '+'); } break; case REAL_KIND_NEG_ZERO: case REAL_KIND_NEG_NUM: StringBuilder_AppendByte(numBuilder, '-'); break; } // Output the digits. StringBuilder_AppendByte(numBuilder, buffer[0]); numFracDigits = len - 1; if (numFracDigits > 0 || numFracDigits < minFracDigits) { StringBuilder_AppendByte(numBuilder, '.'); } if (numFracDigits > 0) { StringBuilder_Append(numBuilder, buffer, 1, numFracDigits); } exp += numFracDigits; // Pad any missing trailing zeros. This is unrolled for speed. while (numFracDigits + 16 <= minFracDigits) { StringBuilder_Append(numBuilder, "0000000000000000", 0, 16); numFracDigits += 16; } if (numFracDigits <= minFracDigits) { StringBuilder_Append(numBuilder, "0000000000000000", 0, minFracDigits - numFracDigits); numFracDigits += (minFracDigits - numFracDigits); } // Output the exponent, always including 'e+' or 'e-' before it. The only exception // to this is if we're outputting a zero. if (kind != REAL_KIND_POS_ZERO && kind != REAL_KIND_NEG_ZERO) { StringBuilder_Append(numBuilder, exp < 0 ? "e-" : "e+", 0, 2); StringBuilder_AppendFormat(numBuilder, "%d", exp < 0 ? -exp : exp); } // And we're done! return StringBuilder_ToString(numBuilder); }
SMILE_API_FUNC Bool Real128_TryParse(String str, Real128 *result) { DECLARE_INLINE_STRINGBUILDER(cleanString, 256); const Byte *src, *end, *start; Byte ch; src = String_GetBytes(str); end = src + String_Length(str); INIT_INLINE_STRINGBUILDER(cleanString); // We need to clean the Smile-isms out of the string so that it's just raw digits, // decimal points, and possibly 'E' and signs. Then we can pass it to the native // parsing function. // Skip initial whitespace. while (src < end && (ch = *src) >= '\x00' && ch <= '\x20') src++; // If there's no content, this is a fail. if (src >= end) { *result = Real128_Zero; return False; } // Trim off trailing whitespace. while (end > src && (ch = end[-1]) >= '\x00' && ch <= '\x20') end--; // Check for named numeric values like "inf" and "nan". We only allow quiet NaNs, since // nothing in Smile's numerics supports signaling NaNs. We have to check for these up front, // since the underlying parser can't indicate the difference beween a failed parse and the // user actually requesting "NaN". It also allows "infinity", fully-spelled-out, which we // do not. // // Note: These tests are carefully ordered so that the compiler's optimizer can easily // perform CSE on them; these read cleanly, but they optimize down to the most-efficient way // of testing for this. Don't reorder these without a good reason. if (src + 3 == end && (((ch = src[0]) == 'i' || ch == 'I') && ((ch = src[1]) == 'n' || ch == 'N') && ((ch = src[2]) == 'f' || ch == 'F'))) { *result = Real128_Inf; return True; } else if (src + 3 == end && (((ch = src[0]) == 'n' || ch == 'N') && ((ch = src[1]) == 'a' || ch == 'A') && ((ch = src[2]) == 'n' || ch == 'N'))) { *result = Real128_NaN; return True; } else if (src + 4 == end && (src[0] == '+' && ((ch = src[1]) == 'i' || ch == 'I') && ((ch = src[2]) == 'n' || ch == 'N') && ((ch = src[3]) == 'f' || ch == 'F'))) { *result = Real128_Inf; return True; } else if (src + 4 == end && (src[0] == '+' && ((ch = src[1]) == 'n' || ch == 'N') && ((ch = src[2]) == 'a' || ch == 'A') && ((ch = src[3]) == 'n' || ch == 'N'))) { *result = Real128_NaN; return True; } else if (src + 4 == end && (src[0] == '-' && ((ch = src[1]) == 'i' || ch == 'I') && ((ch = src[2]) == 'n' || ch == 'N') && ((ch = src[3]) == 'f' || ch == 'F'))) { *result = Real128_NegInf; return True; } else if (src + 4 == end && (src[0] == '-' && ((ch = src[1]) == 'n' || ch == 'N') && ((ch = src[2]) == 'a' || ch == 'A') && ((ch = src[3]) == 'n' || ch == 'N'))) { *result = Real128_NegNaN; return True; } start = src; // Copy an optional initial '+' or '-' as a sign. if ((ch = *src) == '+' || ch == '-') { src++; } // Make sure this doesn't start with a ' or " or _ character, since those separators are illegal starting chars. if ((ch = *src) == '\'' || ch == '\"' || ch == '_') { *result = Real128_Zero; return False; } // Copy digit chunks and radix and exponent characters, discarding embedded ' and " and _ characters. // We don't need to validate this part, because the underlying parser will do so. while (src < end) { switch (ch = *src) { case '\'': case '\"': case '_': // Separator character. if (src > start) { StringBuilder_Append(cleanString, start, 0, src - start); } else { // Two separator chars in a row is illegal. *result = Real128_Zero; return False; } start = ++src; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'e': case 'E': case '+': case '-': case '.': // Legal numeric character of some kind. src++; break; default: // Unknown character is an error. *result = Real128_Zero; return False; break; } } if (src > start) { StringBuilder_Append(cleanString, start, 0, src - start); } else { // Ending with a separator character is illegal. *result = Real128_Zero; return False; } // Make sure this results in a C-style string. StringBuilder_AppendByte(cleanString, '\0'); // The StringBuilder now contains the desired string, at it's at least *somewhat* // legitimately structured. The rest of the parsing (and validation) can be done // by the underlying raw parser, which will return a NaN if the string isn't valid. // We read the content right out of the StringBuilder: If the content is short // enough, all of the data will be on the stack, so we can avoid ever allocating // anything at all on the heap, which is great for performance. *result = Real128_FromRawCString((const char *)StringBuilder_GetBytes(cleanString)); return !Real128_IsNaN(*result); }
/********************************************************************* * Function: void SYS_ArduinoMonitorTask(void) * * PreCondition: None * * Input: None * * Output: Receive and monitor communications with the Arduino-shield serial comms channel * * Side Effects: None * * Overview: This function implements the task for monitoring comms from the Arduino shield. * * Note: None ********************************************************************/ void SYS_ArduinoMonitorTask(FlowThread thread, void *taskParameters) { char incomingChar = 0; #define ARDUINO_SERIAL_PORT 6 #define ARDUINO_SERIAL_BAUD 115200 // power the PMODRS232 #if defined(MICROCHIP_PIC32) /* * UART 6 - Shield RS232 port * - u6Txd on pin RPB15 * - u6RXd on pin RPC2 */ // TXd Pin setup. PLIB_PORTS_PinModePerPortSelect (PORTS_ID_0, PORT_CHANNEL_B, PORTS_BIT_POS_15, PORTS_PIN_MODE_DIGITAL); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, PORTS_BIT_POS_15 ); RPB15R = 0x04; // RXd Pin setup. PLIB_PORTS_PinModePerPortSelect (PORTS_ID_0, PORT_CHANNEL_C, PORTS_BIT_POS_2, PORTS_PIN_MODE_DIGITAL); PLIB_PORTS_PinDirectionInputSet( PORTS_ID_0, PORT_CHANNEL_C, PORTS_BIT_POS_2 ); U6RXR = 0x0C; // RPG8 3V3 supply Digilent PMODRS232 PLIB_PORTS_PinModePerPortSelect (PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_8, PORTS_PIN_MODE_DIGITAL); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_8 ); PLIB_PORTS_PinSet( PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_8 ); // RPG7 0V supply to Digilent PMODRS232 PLIB_PORTS_PinModePerPortSelect (PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_7, PORTS_PIN_MODE_DIGITAL); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_7 ); PLIB_PORTS_PinClear( PORTS_ID_0, PORT_CHANNEL_G, PORTS_BIT_POS_7 ); #endif arduinoSerial = FlowSerial_Init(ARDUINO_SERIAL_PORT, ARDUINO_SERIAL_BAUD); #define ARDUINO_CMD_BUFFER_LENGTH 255 char commandBuffer[ARDUINO_CMD_BUFFER_LENGTH+1]; char* cursor = commandBuffer; unsigned int freeBufferSize = ARDUINO_CMD_BUFFER_LENGTH; bool processCommand = false; memset(commandBuffer, '\0', ARDUINO_CMD_BUFFER_LENGTH+1); while(1) { while (FlowSerial_Ready(arduinoSerial)) { incomingChar = FlowSerial_Getc(arduinoSerial); if (freeBufferSize > 0 && incomingChar != '\n' && incomingChar != '\r') { *cursor = incomingChar; freeBufferSize--; cursor++; } else { *cursor = '\0'; processCommand = true; } if (processCommand) { cmdRequestID++; // Create a request to send to device owner StringBuilder request = StringBuilder_New(256); // Response Header request = StringBuilder_Append(request, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); request = StringBuilder_Append(request, "<command>"); char* datetime = CommandHandlers_GetTimeString(); request = StringBuilder_Append(request, "<sent type=\"datetime\">"); request = StringBuilder_Append(request, datetime); request = StringBuilder_Append(request, "</sent>"); Flow_MemFree((void **) &datetime); request = StringBuilder_Append(request, "<to>"); request = StringBuilder_Append(request, g_OwnerAoR); request = StringBuilder_Append(request, "</to>"); request = StringBuilder_Append(request, "<from>"); request = StringBuilder_Append(request, g_DeviceAoR); request = StringBuilder_Append(request, "</from>"); request = StringBuilder_Append(request, "<clientid type=\"integer\">"); request = StringBuilder_Append(request, g_ClientID); request = StringBuilder_Append(request, "</clientid>"); request = StringBuilder_Append(request, "<requestid type=\"integer\">"); request = StringBuilder_AppendInt(request, cmdRequestID); request = StringBuilder_Append(request, "</requestid>"); request = StringBuilder_Append(request, "<details>MIF DISPLAY "); request = StringBuilder_Append(request, commandBuffer); request = StringBuilder_Append(request, "</details>"); request = StringBuilder_Append(request, "</command>"); if (FlowMessaging_SendMessageToUser((FlowID) g_OwnerID, "text/plain", (char *)StringBuilder_GetCString(request), StringBuilder_GetLength(request), 60)) { FlowConsole_Printf("\n\rSuccessfully forwarded command received from Arduino-shield comms interface ('%s').\n\r", commandBuffer); } else { FlowConsole_Puts("\n\rWarning: Could not forward command received from Arduino-shield comms interface."); } // Clean up StringBuilder_Free(&request); processCommand = false; cursor = commandBuffer; freeBufferSize = ARDUINO_CMD_BUFFER_LENGTH; } } vTaskDelay( 100 / portTICK_RATE_MS ); } }
Int Lexer_ParseReal(Lexer lexer, Bool isFirstContentOnLine) { DECLARE_INLINE_STRINGBUILDER(digitBuilder, 256); // 256 is plenty for most numbers, but it can grow if necessary. const Byte *src = lexer->src; const Byte *end = lexer->end; const Byte *start; Byte ch; Token token = lexer->token; Int integerDigitCount = 0; Int fractionalDigitCount = 0; const Byte *digits; String digitString, suffix; const Byte *suffixText; Float64 float64; UNUSED(isFirstContentOnLine); INIT_INLINE_STRINGBUILDER(digitBuilder); START_TOKEN(src); // Collect integer digits. start = src; while (src < end && (ch = *src) >= '0' && ch <= '9') { src++; if (src + 1 < end && ((ch = *src) == '\'' || ch == '\"' || ch == '_') && src[1] >= '0' && src[1] <= '9') { if (src > start) { StringBuilder_Append(digitBuilder, start, 0, src - start); } src++; start = src; } } // Copy into the digitBuilder whatever integers are left. if (src > start) { StringBuilder_Append(digitBuilder, start, 0, src - start); } integerDigitCount = StringBuilder_GetLength(digitBuilder); // Collect the decimal point. if (src < end && *src == '.') { src++; // Collect fractional digits. while (src < end && (ch = *src) >= '0' && ch <= '9') { src++; if (src + 1 < end && ((ch = *src) == '\'' || ch == '\"' || ch == '_') && src[1] >= '0' && src[1] <= '9') { if (src > start) { StringBuilder_Append(digitBuilder, start, 0, src - start); } src++; start = src; } } fractionalDigitCount = StringBuilder_GetLength(digitBuilder) - 1 - integerDigitCount; } // Finally copy into the digitBuilder whatever's left. if (src > start) { StringBuilder_Append(digitBuilder, start, 0, src - start); } lexer->src = src; // Make the result C-friendly. StringBuilder_AppendByte(digitBuilder, '\0'); // Extract out the raw text of the number. digitString = StringBuilder_ToString(digitBuilder); digits = String_GetBytes(digitString); // Get any trailing type identifiers. suffix = CollectAlphanumericSuffix(lexer); // And make sure the result is clean. if (!EnsureEndOfNumber(lexer)) { token->text = IllegalRealValueMessage; return END_TOKEN(TOKEN_ERROR); } suffixText = String_GetBytes(suffix); if (suffixText[0] == '\0') { // Real64. if (!Real64_TryParse(digitString, &token->data.real64)) { token->text = IllegalRealValueMessage; return END_TOKEN(TOKEN_ERROR); } token->text = digitString; return END_TOKEN(TOKEN_REAL64); } else if (suffixText[0] == 'F' || suffixText[0] == 'f') { if (suffixText[1] == '\0') { // Float64. float64 = strtod(digits, NULL); token->data.float64 = float64; token->text = digitString; return END_TOKEN(TOKEN_FLOAT64); } else goto badSuffix; } else if (suffixText[0] == 'L' || suffixText[0] == 'l') { // 128-bit something-or-other. if (suffixText[1] == '\0') { // Real128. if (!Real128_TryParse(digitString, &token->data.real128)) { token->text = IllegalRealValueMessage; return END_TOKEN(TOKEN_ERROR); } token->text = String_Concat(digitString, suffix); return END_TOKEN(TOKEN_REAL128); } else if ((suffixText[1] == 'F' || suffixText[1] == 'f') && suffixText[2] == '\0') { // Float128 (not yet supported). goto badSuffix; } else goto badSuffix; } else if (suffixText[0] == 'H' || suffixText[0] == 'h') { // 32-bit something-or-other. if (suffixText[1] == '\0') { // Real32. if (!Real32_TryParse(digitString, &token->data.real32)) { token->text = IllegalRealValueMessage; return END_TOKEN(TOKEN_ERROR); } token->text = String_Concat(digitString, suffix); return END_TOKEN(TOKEN_REAL32); } else if ((suffixText[1] == 'F' || suffixText[1] == 'f') && suffixText[2] == '\0') { // Float32. float64 = strtod(digits, NULL); token->data.float32 = (Float32)float64; token->text = digitString; return END_TOKEN(TOKEN_FLOAT32); } else goto badSuffix; } else goto badSuffix; badSuffix: token->text = String_FormatString(IllegalNumericSuffixMessage, suffix); return END_TOKEN(TOKEN_ERROR); }