Skip to content

Commit 5e027a6

Browse files
Improved Formatted Reading (#23)
1 parent 50089ea commit 5e027a6

3 files changed

Lines changed: 159 additions & 45 deletions

File tree

Include/Misra/Std/Io.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ typedef struct {
8484
u32 width; /// Alignment width or raw read/write size
8585
u32 precision;
8686
FormatFlags flags;
87+
u32 max_read_len;
8788
} FmtInfo;
8889

8990
///

Source/Misra/Std/Io.c

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -403,40 +403,41 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
403403

404404
const char* p = fmtstr;
405405
const char* in = input;
406-
size remaining = ZstrLen(fmtstr);
407-
size arg_index = 0; // Current argument index
406+
u64 rem_p = ZstrLen(fmtstr);
407+
u64 rem_in = ZstrLen(in);
408+
u64 arg_index = 0; // Current argument index
408409

409-
while (remaining > 0) {
410-
if (remaining >= 2 && p[0] == '{' && p[1] == '{') {
410+
while (rem_p > 0) {
411+
if (rem_p >= 2 && p[0] == '{' && p[1] == '{') {
411412
if (!in || *in != '{') {
412413
LOG_ERROR("Expected '{' in input");
413414
return NULL;
414415
}
415416
in++;
416-
p += 2;
417-
remaining -= 2;
418-
} else if (remaining >= 2 && p[0] == '}' && p[1] == '}') {
417+
p += 2;
418+
rem_p -= 2;
419+
} else if (rem_p >= 2 && p[0] == '}' && p[1] == '}') {
419420
if (!in || *in != '}') {
420421
LOG_ERROR("Expected '}' in input");
421422
return NULL;
422423
}
423424
in++;
424-
p += 2;
425-
remaining -= 2;
425+
p += 2;
426+
rem_p -= 2;
426427
} else if (p[0] == '{') {
427428
p++;
428-
remaining--;
429+
rem_p--;
429430

430431
// Find closing brace
431432
const char* start = p;
432433
size spec_len = 0;
433-
while (remaining > 0 && *p != '}') {
434+
while (rem_p > 0 && *p != '}') {
434435
p++;
435-
remaining--;
436+
rem_p--;
436437
spec_len++;
437438
}
438439

439-
if (remaining == 0 || *p != '}') {
440+
if (rem_p == 0 || *p != '}') {
440441
LOG_ERROR("Unmatched '{' in format string");
441442
return NULL;
442443
}
@@ -457,11 +458,16 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
457458
spec_buf[spec_len] = '\0';
458459

459460
// Validate format specifier
460-
FmtInfo fmt_info;
461+
FmtInfo fmt_info = {0};
461462
if (!ParseFormatSpec(spec_buf, spec_len, &fmt_info)) {
462463
LOG_ERROR("Failed to parse format specifier");
463464
return NULL; // Error already logged by ParseFormatSpec
464465
}
466+
fmt_info.max_read_len = rem_in;
467+
468+
// Skip closing '}'
469+
p++;
470+
rem_p--;
465471

466472
// Use the type-specific reader
467473
TypeSpecificIO* io = &argv[arg_index++];
@@ -501,6 +507,10 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
501507
u64 x = 0;
502508
next = raw_reader(in, &fmt_info, &x);
503509

510+
if (next) {
511+
rem_in -= (next - in);
512+
}
513+
504514
// deduce the actual field size
505515
u32 var_width = 0;
506516
void* read_fn = (void*)io->reader;
@@ -548,8 +558,37 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
548558
}
549559
}
550560
} else {
561+
// find length between two format specifiers
562+
u64 space_len = 0;
563+
char c = p[space_len];
564+
while (c) {
565+
// if this is possible start of a new format specifier and not '{{' (escaped brace)
566+
if (c == '{' && p[space_len + 1] != '{') {
567+
break;
568+
} else {
569+
space_len++;
570+
}
571+
c = p[space_len];
572+
}
573+
574+
// if there's something between two format specifiers then we can read only upto that
575+
// otherwise end of input is the limit
576+
if (space_len) {
577+
// Find first occurence of content between current and next format specifier or null character
578+
const char* e = NULL;
579+
if ((e = ZstrFindSubstringN(in, p, space_len))) {
580+
fmt_info.max_read_len = e - in;
581+
}
582+
} else {
583+
fmt_info.max_read_len = rem_in;
584+
}
585+
551586
// do formatted read
552587
next = io->reader(in, &fmt_info, io->data);
588+
589+
if (next) {
590+
rem_in -= (next - in);
591+
}
553592
}
554593

555594
// Check if reading failed
@@ -560,10 +599,6 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
560599

561600
// Update input pointer
562601
in = next;
563-
564-
// Skip closing '}'
565-
p++;
566-
remaining--;
567602
} else {
568603
// Match exact character from format string
569604
if (!in || *in != *p) {
@@ -576,7 +611,8 @@ const char* StrReadFmtInternal(const char* input, const char* fmtstr, TypeSpecif
576611
}
577612
in++;
578613
p++;
579-
remaining--;
614+
rem_p--;
615+
rem_in--;
580616
}
581617
}
582618

@@ -1259,10 +1295,7 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
12591295
bool force_case = fmt_info && (fmt_info->flags & FMT_FLAG_FORCE_CASE) != 0;
12601296
bool is_caps = fmt_info && (fmt_info->flags & FMT_FLAG_CAPS) != 0;
12611297
bool is_string = fmt_info && (fmt_info->flags & FMT_FLAG_STRING) != 0;
1262-
1263-
// Skip leading whitespace
1264-
while (IS_SPACE(*i))
1265-
i++;
1298+
u32 r = fmt_info->max_read_len;
12661299

12671300
// Check for empty input
12681301
if (!*i) {
@@ -1274,9 +1307,10 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
12741307
char quote = 0;
12751308
if (is_string && (*i == '"' || *i == '\'')) {
12761309
quote = *i++;
1310+
r--;
12771311
}
12781312

1279-
while (*i) {
1313+
while (r && *i) {
12801314
if (quote) {
12811315
// Quoted string mode
12821316
if (*i == '\\') {
@@ -1286,7 +1320,8 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
12861320
StrDeinit(s);
12871321
return NULL;
12881322
}
1289-
i = curr + 1; // Move past the escape sequence
1323+
i = curr + 1; // Move past the escape sequence
1324+
r -= 2;
12901325

12911326
// Apply case conversion if needed
12921327
if (force_case) {
@@ -1296,9 +1331,11 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
12961331
StrPushBack(s, c);
12971332
} else if (*i == quote) {
12981333
i++; // Skip closing quote
1334+
r--;
12991335
return i; // Successfully read quoted string
13001336
} else {
13011337
char c = *i++;
1338+
r--;
13021339

13031340
// Apply case conversion if needed
13041341
if (force_case) {
@@ -1309,7 +1346,7 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
13091346
}
13101347
} else {
13111348
// Unquoted string mode - read until whitespace
1312-
if (IS_SPACE(*i)) {
1349+
if (is_string && IS_SPACE(*i)) {
13131350
return i; // Successfully read unquoted string
13141351
}
13151352

@@ -1320,7 +1357,8 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
13201357
StrDeinit(s);
13211358
return NULL;
13221359
}
1323-
i = curr + 1; // Move past the escape sequence
1360+
i = curr + 1; // Move past the escape sequence
1361+
r -= 2;
13241362

13251363
// Apply case conversion if needed
13261364
if (force_case) {
@@ -1330,6 +1368,7 @@ const char* _read_Str(const char* i, FmtInfo* fmt_info, Str* s) {
13301368
StrPushBack(s, c);
13311369
} else {
13321370
char c = *i++;
1371+
r--;
13331372

13341373
// Apply case conversion if needed
13351374
if (force_case) {

0 commit comments

Comments
 (0)