Browse Source

Implement printf (very simple version)

Jeremy Soller 7 years ago
parent
commit
5520526bef
11 changed files with 176 additions and 19 deletions
  1. 7 0
      Cargo.lock
  2. 1 1
      crt0/src/lib.rs
  3. 11 2
      include/bits/stdio.h
  4. 1 0
      include/stdarg.h
  5. 19 0
      platform/src/lib.rs
  6. 7 16
      src/lib.rs
  7. 1 0
      stdio/Cargo.toml
  8. 112 0
      stdio/src/lib.rs
  9. 1 0
      tests/.gitignore
  10. 1 0
      tests/Makefile
  11. 15 0
      tests/printf.c

+ 7 - 0
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"

+ 1 - 1
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 {}
 }

+ 11 - 2
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;
 }

+ 1 - 0
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)

+ 19 - 0
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(())
+    }
+}

+ 7 - 16
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);
 }

+ 1 - 0
stdio/Cargo.toml

@@ -9,3 +9,4 @@ cbindgen = { path = "../cbindgen" }
 
 [dependencies]
 platform = { path = "../platform" }
+va_list = { version = "0.1", features = ["no_std"] }

+ 112 - 0
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::<u32>();
+
+                    w.write_char(a as u8 as char);
+
+                    found_percent = false;
+                },
+                'd' | 'i' => {
+                    let a = ap.get::<c_int>();
+
+                    w.write_fmt(format_args!("{}", a));
+
+                    found_percent = false;
+                },
+                'n' => {
+                    let _a = ap.get::<c_int>();
+
+                    found_percent = false;
+                },
+                'p' => {
+                    let a = ap.get::<usize>();
+
+                    w.write_fmt(format_args!("0x{:x}", a));
+
+                    found_percent = false;
+                },
+                's' => {
+                    let a = ap.get::<usize>();
+
+                    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::<c_uint>();
+
+                    w.write_fmt(format_args!("{}", a));
+
+                    found_percent = false;
+                },
+                'x' => {
+                    let a = ap.get::<c_uint>();
+
+                    w.write_fmt(format_args!("{:x}", a));
+
+                    found_percent = false;
+                },
+                'X' => {
+                    let a = ap.get::<c_uint>();
+
+                    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 {

+ 1 - 0
tests/.gitignore

@@ -3,4 +3,5 @@
 /create
 /create.out
 /math
+/printf
 /write

+ 1 - 0
tests/Makefile

@@ -3,6 +3,7 @@ BINS=\
 	args \
 	create \
 	math \
+	printf \
 	write
 
 all: $(BINS)

+ 15 - 0
tests/printf.c

@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+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;
+}