END_TEST START_TEST(Null_token_with_trailing_garbage_is_rejected) { Streader* sr = init_with_cstr("nullz"); fail_if(Streader_read_null(sr), "Reading null token did not check for trailing garbage"); }
END_TEST START_TEST(Reading_null_consumes_data) { Streader* sr = init_with_cstr("null x"); fail_if(!Streader_read_null(sr), "Could not read a null value"); fail_if(!Streader_match_char(sr, 'x'), "Streader did not consume the null value"); }
bool Streader_readf(Streader* sr, const char* format, ...) { rassert(sr != NULL); rassert(format != NULL); va_list args; va_start(args, format); while (!Streader_is_error_set(sr) && *format != '\0') { if (*format == '%') { // Conversion characters ++format; switch (*format) { case 'n': { Streader_read_null(sr); } break; case 'b': { bool* dest = va_arg(args, bool*); Streader_read_bool(sr, dest); } break; case 'i': { int64_t* dest = va_arg(args, int64_t*); Streader_read_int(sr, dest); } break; case 'f': { double* dest = va_arg(args, double*); Streader_read_float(sr, dest); } break; case 's': { Streader_readf_str_info info = va_arg(args, Streader_readf_str_info); rassert(info.guard == Streader_readf_str_guard); const int64_t max_bytes = info.max_bytes; char* dest = info.dest; Streader_read_string(sr, max_bytes, dest); } break; case 't': { Tstamp* dest = va_arg(args, Tstamp*); Streader_read_tstamp(sr, dest); } break; case 'p': { Pat_inst_ref* dest = va_arg(args, Pat_inst_ref*); Streader_read_piref(sr, dest); } break; case 'l': { List_item_reader* ir = va_arg(args, List_item_reader*); void* userdata = va_arg(args, void*); Streader_read_list(sr, ir, userdata); } break; case 'd': { Dict_item_reader* ir = va_arg(args, Dict_item_reader*); void* userdata = va_arg(args, void*); Streader_read_dict(sr, ir, userdata); } break; case '%': { Streader_match_char(sr, '%'); } break; default: rassert(false); } } else { // Characters to be matched if (!isspace(*format))