diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index d172b9f5a..3fb4c9834 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -46,12 +46,18 @@ fault IoError /** - * @param stream - * @require @is_instream(stream) + * Read from a stream (default is stdin) to the next "\n" + * or to the end of the stream, whatever comes first. + * "\r" will be filtered from the String. + * + * @param stream `The stream to read from.` + * @require @is_instream(stream) `The stream must implement InStream.` + * @param [inout] allocator `the allocator to use.` + * @return `The string containing the data read.` **/ macro String! readline(stream = io::stdin(), Allocator allocator = allocator::heap()) { - bool $is_stream = @typeid(stream) == InStream.typeid; + bool $is_stream = @typeis(stream, InStream); $if $is_stream: $typeof(&stream.read_byte) func = &stream.read_byte; char val = func((void*)stream)!; @@ -84,30 +90,51 @@ macro String! readline(stream = io::stdin(), Allocator allocator = allocator::he }; } -macro String! treadline(stream = io::stdin()) => readline(stream, allocator::temp()) @inline; +/** + * Reads a string, see `readline`, except the it is allocated + * on the temporary allocator and does not need to be freed. + * + * @param stream `The stream to read from.` + * @require @is_instream(stream) `The stream must implement InStream.` + * @return `The temporary string containing the data read.` + **/ +macro String! treadline(stream = io::stdin()) +{ + return readline(stream, allocator::temp()) @inline; +} /** - * @require @is_outstream(out) "The output must implement OutStream" + * Print a value to a stream. + * + * @param out `the stream to print to` + * @param x `the value to print` + * @require @is_outstream(out) `The output must implement OutStream.` + * @return `the number of bytes printed.` */ macro usz! fprint(out, x) { var $Type = $typeof(x); $switch ($Type) - $case String: - return out.write(x); - $case ZString: - return out.write(x.str_view()); - $case DString: - return out.write(x.str_view()); - $default: - $if $assignable(x, String): - return out.write((String)x); - $else - return fprintf(out, "%s", x); - $endif + $case String: return out.write(x); + $case ZString: return out.write(x.str_view()); + $case DString: return out.write(x.str_view()); + $default: + $if $assignable(x, String): + return out.write((String)x); + $else + return fprintf(out, "%s", x); + $endif $endswitch } +/** + * Prints using a 'printf'-style formatting string. + * See `printf` for details on formatting. + * + * @param [inout] out `The OutStream to print to` + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! fprintf(OutStream out, String format, args...) { Formatter formatter; @@ -115,6 +142,14 @@ fn usz! fprintf(OutStream out, String format, args...) return formatter.vprintf(format, args); } +/** + * Prints using a 'printf'-style formatting string, + * appending '\n' at the end. See `printf`. + * + * @param [inout] out `The OutStream to print to` + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! fprintfn(OutStream out, String format, args...) @maydiscard { Formatter formatter; @@ -141,21 +176,37 @@ macro usz! fprintn(out, x = "") return len + 1; } +/** + * Print any value to stdout. + **/ macro void print(x) { (void)fprint(io::stdout(), x); } +/** + * Print any value to stdout, appending an '\n’ after. + * + * @param x "The value to print" + **/ macro void printn(x = "") { (void)fprintn(io::stdout(), x); } +/** + * Print any value to stderr. + **/ macro void eprint(x) { (void)fprint(io::stderr(), x); } +/** + * Print any value to stderr, appending an '\n’ after. + * + * @param x "The value to print" + **/ macro void eprintn(x) { (void)fprintn(io::stderr(), x); @@ -173,6 +224,20 @@ fn void! out_putchar_fn(void* data @unused, char c) @private libc::putchar(c); } +/** + * Prints using a 'printf'-style formatting string. + * To print integer numbers, use "%d" or "%x"/"%X, + * the latter gives the hexadecimal representation. + * + * All types can be printed using "%s" which gives + * the default representation of the value. + * + * To create a custom output for a type, implement + * the Printable interface. + * + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! printf(String format, args...) @maydiscard { Formatter formatter; @@ -180,6 +245,13 @@ fn usz! printf(String format, args...) @maydiscard return formatter.vprintf(format, args); } +/** + * Prints using a 'printf'-style formatting string, + * appending '\n' at the end. See `printf`. + * + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! printfn(String format, args...) @maydiscard { Formatter formatter; @@ -190,6 +262,13 @@ fn usz! printfn(String format, args...) @maydiscard return len + 1; } +/** + * Prints using a 'printf'-style formatting string + * to stderr. + * + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! eprintf(String format, args...) @maydiscard { Formatter formatter; @@ -199,6 +278,13 @@ fn usz! eprintf(String format, args...) @maydiscard } +/** + * Prints using a 'printf'-style formatting string, + * to stderr appending '\n' at the end. See `printf`. + * + * @param [in] format `The printf-style format string` + * @return `the number of characters printed` + **/ fn usz! eprintfn(String format, args...) @maydiscard { Formatter formatter; @@ -210,6 +296,14 @@ fn usz! eprintfn(String format, args...) @maydiscard return len; } +/** + * Prints using a 'printf'-style formatting string, + * to a string buffer. See `printf`. + * + * @param [inout] buffer `The buffer to print to` + * @param [in] format `The printf-style format string` + * @return `a slice formed from the "buffer" with the resulting length.` + **/ fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard { Formatter formatter; @@ -219,6 +313,7 @@ fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard return buffer[:data.written]; } +// Used to print to a buffer. fn void! out_buffer_fn(void *data, char c) @private { BufferData *buffer_data = data; @@ -226,22 +321,30 @@ fn void! out_buffer_fn(void *data, char c) @private buffer_data.buffer[buffer_data.written++] = c; } - +// Used for buffer printing struct BufferData @private { char[] buffer; usz written; } - +// Only available with LIBC module std::io @if (env::LIBC); import libc; +/** + * Libc `putchar`, prints a single character to stdout. + **/ fn void putchar(char c) @inline { libc::putchar(c); } +/** + * Get standard out. + * + * @return `stdout as a File` + **/ fn File* stdout() { static File file; @@ -249,6 +352,11 @@ fn File* stdout() return &file; } +/** + * Get standard err. + * + * @return `stderr as a File` + **/ fn File* stderr() { static File file; @@ -256,6 +364,11 @@ fn File* stderr() return &file; } +/** + * Get standard in. + * + * @return `stdin as a File` + **/ fn File* stdin() { static File file; diff --git a/test/test_suite/debug_symbols/defer_macro.c3t b/test/test_suite/debug_symbols/defer_macro.c3t index f86ff7a3e..193c0251b 100644 --- a/test/test_suite/debug_symbols/defer_macro.c3t +++ b/test/test_suite/debug_symbols/defer_macro.c3t @@ -547,6 +547,8 @@ no_match: ; preds = %compare !1 = !{i32 2, !"Debug Info Version", i32 3} !2 = !{i32 2, !"frame-pointer", i32 2} !3 = !{i32 1, !"uwtable", i32 2} +!4 = distinct !DICompileUnit(language: DW_LANG_C11 +!5 = !DIFile(filename: "defer_macro.c3" !6 = !{!7} !7 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Attach_Arg_Kind", scope: !8, file: !5, line: 116, baseType: !13, size: 32, align: 32, elements: !14) !8 = !DICompositeType(tag: DW_TAG_structure_type, name: "Attach_Arg", scope: !5, file: !5, line: 120, size: 128, align: 64, elements: !9, identifier: "attach.Attach_Arg") @@ -614,6 +616,7 @@ no_match: ; preds = %compare !71 = !DILocation(line: 33, column: 63, scope: !63) !72 = !DILocation(line: !73 = distinct !DISubprogram(name: "new", linkageName: "new", scope: !74, file: !74 +!74 = !DIFile(filename: "mem.c3" !75 = !DILocation(line: 34, column: 15, scope: !63) !76 = distinct !DISubprogram(name: "test", linkageName: "test.test", scope: !5, file: !5, line: 41, type: !77, scopeLine: 41, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition !77 = !DISubroutineType(types: !78) @@ -629,7 +632,7 @@ no_match: ; preds = %compare !87 = distinct !DISubprogram(name: "printn", linkageName: "printn" !88 = !DIFile(filename: "io.c3" !89 = !DILocation(line: 42, column: 7, scope: !76) -!90 = !DILocalVariable(name: "len", scope: !91, file: !5, line: 133, type: !44, align: 8) +!90 = !DILocalVariable(name: "len" !91 = distinct !DISubprogram(name: "fprintn", linkageName: "fprintn" !92 = !DILocation !93 = !DILocation