diff --git a/Cargo.lock b/Cargo.lock index 7a33582447..a485ed6ca6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,6 +393,7 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.0", "platform 0.1.0", + "va_list 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -512,6 +513,11 @@ dependencies = [ "platform 0.1.0", ] +[[package]] +name = "va_list" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" version = "0.8.0" @@ -600,6 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum va_list 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7365862faee55ed0dbc112491aa5f0451ca01bf98afcc6463183b5aaa5bd3128" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" diff --git a/crt0/src/lib.rs b/crt0/src/lib.rs index c16d2d7449..4103eb39a3 100644 --- a/crt0/src/lib.rs +++ b/crt0/src/lib.rs @@ -51,6 +51,6 @@ pub unsafe extern "C" fn _start_rust(sp: &'static Stack) -> ! { } #[lang = "panic_fmt"] -pub extern "C" fn rust_begin_unwind(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { +pub extern "C" fn rust_begin_unwind(_fmt: ::core::fmt::Arguments, _file: &str, _line: u32) -> ! { loop {} } diff --git a/include/bits/stdio.h b/include/bits/stdio.h index 1d9815ce28..351dc1e774 100644 --- a/include/bits/stdio.h +++ b/include/bits/stdio.h @@ -1,11 +1,20 @@ #ifndef _BITS_STDIO_H #define _BITS_STDIO_H -int printf(const char *restrict fmt, ...) { +int fprintf(FILE * stream, const char * fmt, ...) { int ret; va_list ap; va_start(ap, fmt); - ret = vfprintf(stdout, fmt, ap); + ret = vfprintf(stream, fmt, ap); + va_end(ap); + return ret; +} + +int printf(const char * fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vprintf(fmt, ap); va_end(ap); return ret; } diff --git a/include/stdarg.h b/include/stdarg.h index 809114e57f..28ff0905ba 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -1,6 +1,7 @@ #ifndef _STDARG_H #define _STDARG_H +typedef __builtin_va_list va_list; #define va_start(v,l) __builtin_va_start(v,l) #define va_end(v) __builtin_va_end(v) #define va_arg(v,l) __builtin_va_arg(v,l) diff --git a/platform/src/lib.rs b/platform/src/lib.rs index e094fbaa89..bdddb79a68 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -17,3 +17,22 @@ mod sys; mod sys; pub mod types; + +use core::fmt; + +use types::c_int; + +pub struct FileWriter(pub c_int); + +impl FileWriter { + pub fn write(&mut self, buf: &[u8]) { + write(self.0, buf); + } +} + +impl fmt::Write for FileWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write(s.as_bytes()); + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index a72ecd8e8b..0e04380255 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,27 +10,17 @@ extern crate stdlib; extern crate string; extern crate unistd; -use core::fmt; - -struct PanicWriter; - -impl fmt::Write for PanicWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - platform::write(2, s.as_bytes()); - Ok(()) - } -} - #[lang = "eh_personality"] #[no_mangle] pub extern "C" fn rust_eh_personality() {} #[lang = "panic_fmt"] #[no_mangle] -pub extern "C" fn rust_begin_unwind(fmt: fmt::Arguments, file: &str, line: u32) -> ! { - use fmt::Write; +pub extern "C" fn rust_begin_unwind(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! { + use core::fmt::Write; - let _ = PanicWriter.write_fmt(format_args!("{}:{}: {}\n", file, line, fmt)); + let mut w = platform::FileWriter(2); + let _ = w.write_fmt(format_args!("{}:{}: {}\n", file, line, fmt)); platform::exit(1); } @@ -38,9 +28,10 @@ pub extern "C" fn rust_begin_unwind(fmt: fmt::Arguments, file: &str, line: u32) #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn _Unwind_Resume() -> ! { - use fmt::Write; + use core::fmt::Write; - let _ = PanicWriter.write_str("_Unwind_Resume\n"); + let mut w = platform::FileWriter(2); + let _ = w.write_str("_Unwind_Resume\n"); platform::exit(1); } diff --git a/stdio/Cargo.toml b/stdio/Cargo.toml index aa996191f9..7914741731 100644 --- a/stdio/Cargo.toml +++ b/stdio/Cargo.toml @@ -9,3 +9,4 @@ cbindgen = { path = "../cbindgen" } [dependencies] platform = { path = "../platform" } +va_list = { version = "0.1", features = ["no_std"] } diff --git a/stdio/src/lib.rs b/stdio/src/lib.rs index b2e0ea5bc0..a84c5a3193 100644 --- a/stdio/src/lib.rs +++ b/stdio/src/lib.rs @@ -3,13 +3,125 @@ #![no_std] extern crate platform; +extern crate va_list as vl; use platform::types::*; +use vl::VaList as va_list; pub const BUFSIZ: c_int = 4096; pub const FILENAME_MAX: c_int = 4096; +pub struct FILE; + +pub static mut stdout: *mut FILE = 1 as *mut FILE; +pub static mut stderr: *mut FILE = 2 as *mut FILE; + +#[no_mangle] +pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, mut ap: va_list) -> c_int { + use core::fmt::Write; + use core::slice; + use core::str; + + extern "C" { + fn strlen(s: *const c_char) -> size_t; + } + + let mut w = platform::FileWriter(file as c_int); + + let format = slice::from_raw_parts(format as *const u8, strlen(format)); + + let mut i = 0; + let mut found_percent = false; + while i < format.len() { + let b = format[i]; + + if found_percent { + match b as char { + '%' => { + w.write_char('%'); + found_percent = false; + }, + 'c' => { + let a = ap.get::(); + + w.write_char(a as u8 as char); + + found_percent = false; + }, + 'd' | 'i' => { + let a = ap.get::(); + + w.write_fmt(format_args!("{}", a)); + + found_percent = false; + }, + 'n' => { + let _a = ap.get::(); + + found_percent = false; + }, + 'p' => { + let a = ap.get::(); + + w.write_fmt(format_args!("0x{:x}", a)); + + found_percent = false; + }, + 's' => { + let a = ap.get::(); + + w.write_str(str::from_utf8_unchecked( + slice::from_raw_parts(a as *const u8, strlen(a as *const c_char)) + )); + + found_percent = false; + }, + 'u' => { + let a = ap.get::(); + + w.write_fmt(format_args!("{}", a)); + + found_percent = false; + }, + 'x' => { + let a = ap.get::(); + + w.write_fmt(format_args!("{:x}", a)); + + found_percent = false; + }, + 'X' => { + let a = ap.get::(); + + w.write_fmt(format_args!("{:X}", a)); + + found_percent = false; + }, + '-' => {}, + '+' => {}, + ' ' => {}, + '#' => {}, + '0' ... '9' => {}, + _ => {} + } + } else if b == b'%' { + found_percent = true; + } else { + w.write_char(b as char); + } + + i += 1; + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int { + vfprintf(stdout, format, ap) +} + /* #[no_mangle] pub extern "C" fn func(args) -> c_int { diff --git a/tests/.gitignore b/tests/.gitignore index f9aa667a81..45f2b7aa2e 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -3,4 +3,5 @@ /create /create.out /math +/printf /write diff --git a/tests/Makefile b/tests/Makefile index ba2b659025..8d98779817 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,6 +3,7 @@ BINS=\ args \ create \ math \ + printf \ write all: $(BINS) diff --git a/tests/printf.c b/tests/printf.c new file mode 100644 index 0000000000..f02250675f --- /dev/null +++ b/tests/printf.c @@ -0,0 +1,15 @@ +#include + +int main(int argc, char ** argv) { + printf( + "percent: %%\nstring: %s\nchar: %c\nint: %d\nuint: %u\nhex: %x\nHEX: %X\nstring: %s\n", + "String", + 'c', + -16, + 32, + 0xbeef, + 0xC0FFEE, + "end" + ); + return 0; +}