diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index fa654aead..6f1a287ef 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -75,7 +75,8 @@ fn void String.chop(String this, usize new_size) fn char[] String.str(String str) { StringData* data = (StringData*)str; - return data.chars[0..data.len - 1]; + if (!data) return char[] {}; + return data.chars[:data.len]; } fn void String.append_utf32(String* str, Char32[] chars) @@ -173,6 +174,11 @@ fn ZString String.copy_zstr(String* str, Allocator allocator = { null, null }) return (ZString)zstr; } +fn char[] String.copy_str(String* str, Allocator allocator = { null, null }) +{ + return str.copy_zstr(allocator)[:str.len()]; +} + fn bool String.equals(String str, String other_string) { StringData *str1 = str.data(); diff --git a/lib/std/io.c3 b/lib/std/io.c3 index 8e7a14111..e2511aa9d 100644 --- a/lib/std/io.c3 +++ b/lib/std/io.c3 @@ -166,6 +166,11 @@ fn usize! File.println(File* file, char[] string) return len + 1; } +fn File stdout() +{ + return { libc::stdout() }; +} + /* diff --git a/lib/std/io_printf.c3 b/lib/std/io_printf.c3 index ac9ce4938..9151c94c0 100644 --- a/lib/std/io_printf.c3 +++ b/lib/std/io_printf.c3 @@ -28,14 +28,14 @@ bitstruct PrintFlags : uint struct PrintParam { OutputFn outfn; - char[] buffer; + void* buffer; PrintFlags flags; uint width; uint prec; usize idx; } -define OutputFn = fn void!(char c, char[] buffer, usize buffer_idx); +define OutputFn = fn void!(char c, void* buffer, usize buffer_idx); fn void! PrintParam.out(PrintParam* param, char c) { @@ -207,15 +207,27 @@ private fn void! out_buffer_fn(char c, char[] buffer, usize buffer_idx) buffer[buffer_idx] = c; } -private fn void! out_null_fn(char c @unused, char[] buffer @unused, usize idx @unused) +private fn void! out_null_fn(char c @unused, void* data @unused, usize idx @unused) { } -private fn void! out_putchar_fn(char c, char[] buffer @unused, usize idx @unused) +private fn void! out_putchar_fn(char c, void* data @unused, usize idx @unused) { libc::putchar(c); } +private fn void! out_fputchar_fn(char c, void* data, usize idx @unused) +{ + File* f = data; + f.putc(c)?; +} + +private fn void! out_string_append_fn(char c, void* data, usize idx @unused) +{ + String* s = data; + s.append_char(c); +} + private fn void! PrintParam.out_reverse(PrintParam* param, char[] buf) { usize buffer_start_idx = param.idx; @@ -702,7 +714,17 @@ private fn NtoaType int_from_variant(variant arg, bool *is_neg) fn usize! printf(char[] format, args...) @maydiscard { - return vsnprintf(&out_putchar_fn, " ", format, args); + return vsnprintf(&out_putchar_fn, null, format, args); +} + +fn usize! String.printf(String* str, char[] format, args...) @maydiscard +{ + return vsnprintf(&out_string_append_fn, str, format, args); +} + +fn usize! fprintf(File file, char[] format, args...) @maydiscard +{ + return vsnprintf(&out_putchar_fn, &file, format, args); } private fn void! PrintParam.left_adjust(PrintParam* param, usize len) @@ -737,14 +759,14 @@ private fn void! out_substr(PrintParam* param, char[] str) return param.left_adjust(l); } -private fn usize! vsnprintf(OutputFn out, char[] buffer, char[] format, variant[] variants) +private fn usize! vsnprintf(OutputFn out, void* data, char[] format, variant[] variants) { - if (!buffer) + if (!out) { // use null output function out = &out_null_fn; } - PrintParam param = { .outfn = out, .buffer = buffer }; + PrintParam param = { .outfn = out, .buffer = data }; usize format_len = format.len; usize variant_index = 0; for (usize i = 0; i < format_len; i++) diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index d6824b38b..3fbf2181c 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -3,20 +3,26 @@ import libc; import std::io; struct Doc { Head *head; } -struct Head { char[]* title; } +struct Head { String* title; } struct Summary { - char[]* title; + String* title; bool ok; } -fn void Summary.print(Summary *s, CFile out) +private struct StringData { - // We don't have a native fprintf in C3 yet, so use libc, - // which is not all that nice for the strings but... - char[] title = s.title ? *s.title : "missing"; - libc::fprintf(out, "Summary({ .title = %.*s, .ok = %s})", (int)title.len, title.ptr, s.ok ? "true" : "false"); + Allocator allocator; + usize len; + usize capacity; + char[*] chars; +} + +fn void Summary.print(Summary *s, File out) +{ + char[] title = s.title ? s.title.str() : "missing"; + io::fprintf(out, "Summary({ .title = %s, .ok = %s})", title, s.ok); } fn bool contains(char[] haystack, char[] needle) @@ -36,7 +42,7 @@ fn bool contains(char[] haystack, char[] needle) return false; } -macro dupe(value) +macro @dupe(value) { $typeof(&value) temp = mem::alloc_checked($sizeof(value))?; *temp = value; @@ -52,13 +58,11 @@ fn Doc! readDoc(char[] url) { if (contains(url, "fail")) return ReadError.BAD_READ!; if (contains(url, "head-missing")) return { .head = null }; - if (contains(url, "title-missing")) return { dupe(Head { .title = null })? }; - if (contains(url, "title-empty")) return { dupe(Head { .title = dupe((char[])"")? })? }; - // Not particularly elegant due to missing string functions. - int len = libc::snprintf(null, 0, "Title of %.*s", (int)url.len, url.ptr); - char* str = mem::alloc_checked(len + 1)?; - libc::snprintf(str, len + 1, "Title of %.*s", (int)url.len, url.ptr); - return { dupe(Head { .title = dupe(str[..len - 1])? })? }; + if (contains(url, "title-missing")) return { @dupe(Head { .title = null }) }; + if (contains(url, "title-empty")) return { @dupe(Head { .title = @dupe((String)null) }) }; + String str; + str.printf("Title of %s", url); + return { @dupe(Head { .title = @dupe(str) }) }; } fn Summary buildSummary(Doc doc) @@ -93,9 +97,9 @@ fault TitleResult fn bool! isTitleNonEmpty(Doc doc) { if (!doc.head) return TitleResult.TITLE_MISSING!; - char[]* head = doc.head.title; + String* head = doc.head.title; if (!head) return TitleResult.TITLE_MISSING!; - return (*head).len > 0; + return head.len() > 0; } @@ -123,13 +127,11 @@ fn void main() io::printf(`Checking "https://%s/":` "\n", url); Summary summary = readAndBuildSummary(url); io::printf(" Summary: "); - summary.print(libc::stdout()); + summary.print(io::stdout()); io::println(""); - char[] title_sure = summary.title ? *summary.title : ""; + char[] title_sure = summary.title ? summary.title.str() : ""; io::printf(" Title: %s\n", title_sure); bool! has_title = readWhetherTitleNonEmpty(url); - // This looks a bit less than elegant, but as you see it's mostly due to having to - // use printf here. io::printf(" Has title: %s vs %s\n", bool_to_string(has_title) ?? catch(has_title).nameof, has_title ?? false); }; allocator.reset();