static ParserElem* S_consume_text(StringIterator *iter) { StringIterator *temp = StrIter_Clone(iter); while (1) { int32_t code_point = StrIter_Next(temp); if (code_point == '\\') { code_point = StrIter_Next(temp); if (code_point == STR_OOB) { break; } } else if (code_point == STR_OOB) { break; } else if (StrHelp_is_whitespace(code_point) || code_point == '"' || code_point == '(' || code_point == ')' ) { StrIter_Recede(temp, 1); break; } } String *text = StrIter_crop(iter, temp); StrIter_Assign(iter, temp); DECREF(temp); return ParserElem_new(TOKEN_STRING, (Obj*)text); }
String* IxFileNames_local_part(String *path) { StringIterator *top = Str_Tail(path); int32_t code_point = StrIter_Prev(top); // Trim trailing slash. while (code_point == '/') { code_point = StrIter_Prev(top); } StringIterator *tail = StrIter_Clone(top); StrIter_Advance(tail, 1); // Substring should start after last slash. while (code_point != STR_OOB) { if (code_point == '/') { StrIter_Advance(top, 1); break; } code_point = StrIter_Prev(top); } String *retval = StrIter_crop(top, tail); DECREF(tail); DECREF(top); return retval; }
static ParserElem* S_consume_field(StringIterator *iter) { StringIterator *temp = StrIter_Clone(iter); // Field names constructs must start with a letter or underscore. int32_t code_point = StrIter_Next(temp); if (code_point == STR_OOB) { DECREF(temp); return NULL; } if (!(isalpha(code_point) || code_point == '_')) { DECREF(temp); return NULL; } // Only alphanumerics and underscores are allowed in field names. while (':' != (code_point = StrIter_Next(temp))) { if (code_point == STR_OOB) { DECREF(temp); return NULL; } if (!(isalnum(code_point) || code_point == '_')) { DECREF(temp); return NULL; } } // Field name constructs must be followed by something sensible. int32_t lookahead = StrIter_Next(temp); if (lookahead == STR_OOB) { DECREF(temp); return NULL; } if (!(isalnum(lookahead) || lookahead == '_' || lookahead > 127 || lookahead == '"' || lookahead == '(' ) ) { DECREF(temp); return NULL; } // Consume string data. StrIter_Recede(temp, 2); // Back up over lookahead and colon. String *field = StrIter_crop(iter, temp); StrIter_Advance(temp, 1); // Skip colon. StrIter_Assign(iter, temp); DECREF(temp); return ParserElem_new(TOKEN_FIELD, (Obj*)field); }
String* Str_Trim_IMP(String *self) { StringIterator *top = STACK_ITER(self, 0); StrIter_Skip_Whitespace(top); StringIterator *tail = NULL; if (top->byte_offset < self->size) { tail = STACK_ITER(self, self->size); StrIter_Skip_Whitespace_Back(tail); } return StrIter_crop((StringIterator*)top, (StringIterator*)tail); }
uint64_t IxFileNames_extract_gen(String *name) { StringIterator *iter = Str_Top(name); // Advance past first underscore. Bail if we run out of string or if we // encounter a NULL. while (1) { int32_t code_point = StrIter_Next(iter); if (code_point == STR_OOB) { return 0; } else if (code_point == '_') { break; } } String *num_string = StrIter_crop(iter, NULL); uint64_t retval = (uint64_t)Str_BaseX_To_I64(num_string, 36); DECREF(num_string); DECREF(iter); return retval; }
static ParserElem* S_consume_quoted_string(StringIterator *iter) { StringIterator *temp = StrIter_Clone(iter); if (StrIter_Next(temp) != '"') { THROW(ERR, "Internal error: expected a quote"); } while (1) { int32_t code_point = StrIter_Next(temp); if (code_point == STR_OOB || code_point == '"') { break; } else if (code_point == '\\') { StrIter_Next(temp); } } String *text = StrIter_crop(iter, temp); StrIter_Assign(iter, temp); DECREF(temp); return ParserElem_new(TOKEN_STRING, (Obj*)text); }
String* Str_Trim_Tail_IMP(String *self) { StringIterator *tail = STACK_ITER(self, self->size); StrIter_Skip_Whitespace_Back(tail); return StrIter_crop(NULL, (StringIterator*)tail); }
String* Str_Trim_Top_IMP(String *self) { StringIterator *top = STACK_ITER(self, 0); StrIter_Skip_Whitespace(top); return StrIter_crop((StringIterator*)top, NULL); }
static void test_iterator_substring(TestBatchRunner *runner) { String *string = Str_newf("a%sb%sc%sd", smiley, smiley, smiley); StringIterator *start = Str_Top(string); StringIterator *end = Str_Tail(string); { String *substring = StrIter_crop(start, end); TEST_TRUE(runner, Str_Equals(substring, (Obj*)string), "StrIter_crop whole string"); DECREF(substring); } StrIter_Advance(start, 2); StrIter_Recede(end, 2); { String *substring = StrIter_crop(start, end); String *wanted = Str_newf("b%sc", smiley); TEST_TRUE(runner, Str_Equals(substring, (Obj*)wanted), "StrIter_crop"); TEST_TRUE(runner, StrIter_Starts_With(start, wanted), "Starts_With returns true"); TEST_TRUE(runner, StrIter_Ends_With(end, wanted), "Ends_With returns true"); DECREF(wanted); DECREF(substring); } { String *short_str = Str_newf("b%sx", smiley); TEST_FALSE(runner, StrIter_Starts_With(start, short_str), "Starts_With returns false"); TEST_FALSE(runner, StrIter_Ends_With(start, short_str), "Ends_With returns false"); String *long_str = Str_newf("b%sxxxxxxxxxxxx%sc", smiley, smiley); TEST_FALSE(runner, StrIter_Starts_With(start, long_str), "Starts_With long string returns false"); TEST_FALSE(runner, StrIter_Ends_With(end, long_str), "Ends_With long string returns false"); DECREF(short_str); DECREF(long_str); } { String *substring = StrIter_crop(end, NULL); String *wanted = Str_newf("%sd", smiley); TEST_TRUE(runner, Str_Equals(substring, (Obj*)wanted), "StrIter_crop with NULL tail"); DECREF(wanted); DECREF(substring); } { String *substring = StrIter_crop(NULL, start); String *wanted = Str_newf("a%s", smiley); TEST_TRUE(runner, Str_Equals(substring, (Obj*)wanted), "StrIter_crop with NULL top"); DECREF(wanted); DECREF(substring); } DECREF(start); DECREF(end); DECREF(string); }