static value_t read_string(void) { char *buf, *temp; char eseq[10]; size_t i=0, j, sz = 64, ndig; int c; value_t s; u_int32_t wc=0; buf = malloc(sz); while (1) { if (i >= sz-4) { // -4: leaves room for longest utf8 sequence sz *= 2; temp = realloc(buf, sz); if (temp == NULL) { free(buf); lerror(ParseError, "read: out of memory reading string"); } buf = temp; } c = ios_getc(F); if (c == IOS_EOF) { free(buf); lerror(ParseError, "read: unexpected end of input in string"); } if (c == '"') break; else if (c == '\\') { c = ios_getc(F); if (c == IOS_EOF) { free(buf); lerror(ParseError, "read: end of input in escape sequence"); } j=0; if (octal_digit(c)) { do { eseq[j++] = c; c = ios_getc(F); } while (octal_digit(c) && j<3 && (c!=IOS_EOF)); if (c!=IOS_EOF) ios_ungetc(c, F); eseq[j] = '\0'; wc = strtol(eseq, NULL, 8); // \DDD and \xXX read bytes, not characters buf[i++] = ((char)wc); } else if ((c=='x' && (ndig=2)) || (c=='u' && (ndig=4)) || (c=='U' && (ndig=8))) { c = ios_getc(F); while (hex_digit(c) && j<ndig && (c!=IOS_EOF)) { eseq[j++] = c; c = ios_getc(F); } if (c!=IOS_EOF) ios_ungetc(c, F); eseq[j] = '\0'; if (j) wc = strtol(eseq, NULL, 16); if (!j || wc > 0x10ffff) { free(buf); lerror(ParseError, "read: invalid escape sequence"); } if (ndig == 2) buf[i++] = ((char)wc); else i += u8_wc_toutf8(&buf[i], wc); } else { buf[i++] = read_escape_control_char((char)c); } } else { buf[i++] = c; } } s = cvalue_string(i); memcpy(cvalue_data(s), buf, i); free(buf); return s; }
std::shared_ptr<Object> read_string(std::istream &in) { std::stringstream buf; // lambda to get the next char, or throw EOF exception std::function<int ()> getc = [&in] () -> int { int c = in.get(); if (in.eof()) { throw "EOF while reading string"; } return c; }; while (1) { int c = getc(); if (c == '"') { return std::make_shared<String>(buf.str()); } if (c == '\\') { c = getc(); if (octal_digit(c)) { int j = 0; char eseq[4] = { 0, 0, 0, 0 } ; do { eseq[j++] = c; c = getc(); } while (octal_digit(c) && j < 3); in.unget(); if (!octal_digit(c) && j < 3) { if (c == '\\') { } else { buf.str("Invalid digit: "); buf.put(c); throw buf.str(); } } u8_wc_toutf8(buf, std::strtol(eseq, 0, 8)); } else if (c == 'u') { int j = 0; char eseq[5] = { 0, 0, 0, 0, 0 }; c = getc(); while (hex_digit(c) && j < 4) { eseq[j++] = c; c = getc(); } if (j != 4) { buf.str("Invalid character length: "); buf << j << ", should be: 4"; throw buf.str(); } in.unget(); long uni = std::strtol(eseq, 0, 16); u8_wc_toutf8(buf, uni); } else { if (c == 'b') { buf.put('\b'); } else if (c == 'n') { buf.put('\n'); } else if (c == 't') { buf.put('\t'); } else if (c == 'f') { buf.put('\f'); } else if (c == 'r') { buf.put('\r'); } else if (c == '"') { buf.put('\''); } else if (c == '\\') { buf.put('\\'); } else { buf.str("Unsupported escape character: \\"); buf.put(c); throw buf.str(); } } } else { buf.put(c); } } return Object::nil; }