about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Hahn <flo@fhahn.com>2013-08-30 16:42:49 +0200
committerFlorian Hahn <flo@fhahn.com>2013-09-04 14:18:56 +0200
commite38739bb442263f1ef67b6c2415f932aa49e6646 (patch)
tree832cc6ef84a7f48f8cd776c1b058a1f34ffe89a3
parented422b88727807aee40495a6193a69e4c3842be1 (diff)
downloadrust-e38739bb442263f1ef67b6c2415f932aa49e6646.tar.gz
rust-e38739bb442263f1ef67b6c2415f932aa49e6646.zip
Convert rust_log.cpp to Rust, closes #8703
-rw-r--r--mk/rt.mk1
-rw-r--r--src/libstd/rt/logging.rs263
-rw-r--r--src/rt/rust_crate_map.cpp38
-rw-r--r--src/rt/rust_crate_map.h14
-rw-r--r--src/rt/rust_log.cpp155
-rw-r--r--src/rt/rustrt.def.in4
6 files changed, 285 insertions, 190 deletions
diff --git a/mk/rt.mk b/mk/rt.mk
index c260945cbc9..352165d6002 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -76,7 +76,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/rust_upcall.cpp \
               rt/rust_uv.cpp \
               rt/rust_crate_map.cpp \
-              rt/rust_log.cpp \
               rt/isaac/randport.cpp \
               rt/miniz.cpp \
               rt/memory_region.cpp \
diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs
index e716549d1e6..bcd8ef98d28 100644
--- a/src/libstd/rt/logging.rs
+++ b/src/libstd/rt/logging.rs
@@ -7,10 +7,159 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-
+use cast::transmute;
 use either::*;
-use libc;
+use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
+use option::{Some, None};
+use rt::util::dumb_println;
 use str::StrSlice;
+use str::raw::from_c_str;
+use u32;
+use unstable::raw::Closure;
+use vec::ImmutableVector;
+
+
+struct LogDirective {
+    name: ~str,
+    level: u32
+}
+
+// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
+struct ModEntry{
+    name: *c_char,
+    log_level: *mut u32
+}
+
+static MAX_LOG_DIRECTIVES: u32 = 255;
+static MAX_LOG_LEVEL: u32 = 255;
+static DEFAULT_LOG_LEVEL: u32 = 1;
+
+fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
+    unsafe {
+        let closure : Closure = transmute(f);
+        let code = transmute(closure.code);
+        let env = transmute(closure.env);
+        rust_iter_crate_map(transmute(map), iter_cb, code, env);
+    }
+
+    extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
+         unsafe {
+            let closure: Closure = Closure {
+                code: transmute(code),
+                env: transmute(env),
+            };
+            let closure: &fn(*ModEntry) = transmute(closure);
+            return closure(entry);
+        }
+    }
+    extern {
+        #[cfg(not(stage0))]
+        #[rust_stack]
+        fn rust_iter_crate_map(map: *c_void,
+                    f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
+                    code: *c_void,
+                    data: *c_void);
+
+        #[cfg(stage0)]
+        #[rust_stack]
+        fn rust_iter_crate_map(map: *c_void,
+                    f: *u8,
+                    code: *c_void,
+                    data: *c_void);
+    }
+}
+
+/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
+/// and return a vector with log directives.
+/// Valid log levels are 0-255, with the most likely ones being 0-3 (defined in std::).
+fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
+    let mut dirs = ~[];
+    for s in spec.split_iter(',') {
+        let parts: ~[&str] = s.split_iter('=').collect();
+        let mut loglevel;
+        match parts.len() {
+            1 => loglevel = MAX_LOG_LEVEL,
+            2 => {
+                let num = u32::from_str(parts[1]);
+                match (num) {
+                    Some(num) => {
+                        if num < MAX_LOG_LEVEL {
+                            loglevel = num;
+                        } else {
+                            loglevel = MAX_LOG_LEVEL;
+                        }
+                    }
+                    _ => {
+                         dumb_println(fmt!("warning: invalid logging spec \
+                                           '%s', ignoring it", s));
+                         loop;
+                    }
+                }
+                if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL}
+            },
+            _ => {
+                dumb_println(fmt!("warning: invalid logging spec '%s',\
+                                  ignoring it", s));
+                loop;
+            }
+        }
+        let dir = LogDirective {name: parts[0].to_owned(), level: loglevel};
+        dirs.push(dir);
+    }
+    return dirs;
+}
+
+/// Set the log level of an entry in the crate map depending on the vector
+/// of log directives
+fn update_entry(dirs: &[LogDirective], entry: *mut ModEntry) -> u32 {
+    let mut new_lvl: u32 = DEFAULT_LOG_LEVEL;
+    let mut longest_match = 0;
+    unsafe {
+        for dir in dirs.iter() {
+            let name = from_c_str((*entry).name);
+            if name.starts_with(dir.name) && dir.name.len() > longest_match {
+                longest_match = dir.name.len();
+                new_lvl = dir.level;
+            }
+        }
+        *(*entry).log_level = new_lvl;
+    }
+    if longest_match > 0 { return 1; } else { return 0; }
+}
+
+#[fixed_stack_segment] #[inline(never)]
+/// Set log level for every entry in crate_map according to the sepecification
+/// in settings
+fn update_log_settings(crate_map: *u8, settings: ~str) {
+    let mut dirs = ~[];
+    if settings.len() > 0 {
+        if settings == ~"::help" || settings == ~"?" {
+            dumb_println("\nCrate log map:\n");
+            do iter_crate_map(crate_map) |entry: *mut ModEntry| {
+                unsafe {
+                    dumb_println(" "+from_c_str((*entry).name));
+                }
+            }
+            unsafe {
+                exit(1);
+            }
+        }
+        dirs = parse_logging_spec(settings);
+    }
+
+    let mut n_matches: u32 = 0;
+    do iter_crate_map(crate_map) |entry: *mut ModEntry| {
+        let m = update_entry(dirs, entry);
+        n_matches += m;
+    }
+
+    if n_matches < (dirs.len() as u32) {
+        dumb_println(fmt!("warning: got %u RUST_LOG specs but only matched %u of them.\n\
+                          You may have mistyped a RUST_LOG spec.\n\
+                          Use RUST_LOG=::help to see the list of crates and modules.\n",
+                          dirs.len() as uint, n_matches as uint));
+    }
+}
 
 pub trait Logger {
     fn log(&mut self, msg: Either<~str, &'static str>);
@@ -47,34 +196,26 @@ impl Logger for StdErrLogger {
         };
 
         fn print(s: &str) {
-            let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
+            let dbg = STDERR_FILENO as ::io::fd_t;
             dbg.write_str(s);
             dbg.write_str("\n");
             dbg.flush();
         }
     }
 }
-
 /// Configure logging by traversing the crate map and setting the
 /// per-module global logging flags based on the logging spec
 #[fixed_stack_segment] #[inline(never)]
 pub fn init(crate_map: *u8) {
-    use c_str::ToCStr;
     use os;
-    use ptr;
-    use option::{Some, None};
 
     let log_spec = os::getenv("RUST_LOG");
     match log_spec {
         Some(spec) => {
-            do spec.with_c_str |buf| {
-                unsafe { rust_update_log_settings(crate_map, buf) }
-            }
+            update_log_settings(crate_map, spec);
         }
         None => {
-            unsafe {
-                rust_update_log_settings(crate_map, ptr::null());
-            }
+            update_log_settings(crate_map, ~"");
         }
     }
 }
@@ -89,9 +230,101 @@ pub fn console_off() { unsafe { rust_log_console_off() } }
 fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
 
 extern {
-    fn rust_update_log_settings(crate_map: *u8, settings: *libc::c_char);
     fn rust_log_console_on();
     fn rust_log_console_off();
-    fn rust_should_log_console() -> libc::uintptr_t;
+    fn rust_should_log_console() -> uintptr_t;
+}
+
+// Tests for parse_logging_spec()
+#[test]
+fn parse_logging_spec_valid() {
+    let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4");
+    assert_eq!(dirs.len(), 3);
+    assert!(dirs[0].name == ~"crate1::mod1");
+    assert_eq!(dirs[0].level, 1);
+
+    assert!(dirs[1].name == ~"crate1::mod2");
+    assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
+
+    assert!(dirs[2].name == ~"crate2");
+    assert_eq!(dirs[2].level, 4);
+}
+
+#[test]
+fn parse_logging_spec_invalid_crate() {
+    // test parse_logging_spec with multiple = in specification
+    let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1=2,crate2=4");
+    assert_eq!(dirs.len(), 1);
+    assert!(dirs[0].name == ~"crate2");
+    assert_eq!(dirs[0].level, 4);
+}
+
+#[test]
+fn parse_logging_spec_invalid_log_level() {
+    // test parse_logging_spec with 'noNumber' as log level
+    let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4");
+    assert_eq!(dirs.len(), 1);
+    assert!(dirs[0].name == ~"crate2");
+    assert_eq!(dirs[0].level, 4);
+}
+
+// Tests for update_entry
+#[test]
+fn update_entry_match_full_path() {
+    use c_str::ToCStr;
+    let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
+    LogDirective {name: ~"crate2", level: 3}];
+    unsafe {
+        do "crate1::mod1".to_c_str().with_ref |ptr| {
+            let entry= &ModEntry {name: ptr, log_level: &mut 0};
+            let m = update_entry(dirs, transmute(entry));
+            assert!(*entry.log_level == 2);
+            assert!(m == 1);
+        }
+    }
 }
 
+#[test]
+fn update_entry_no_match() {
+    use c_str::ToCStr;
+    let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
+        LogDirective {name: ~"crate2", level: 3}];
+    unsafe {
+        do "crate3::mod1".to_c_str().with_ref |ptr| {
+            let entry= &ModEntry {name: ptr, log_level: &mut 0};
+            let m = update_entry(dirs, transmute(entry));
+            assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
+            assert!(m == 0);
+        }
+    }
+}
+
+#[test]
+fn update_entry_match_beginning() {
+    use c_str::ToCStr;
+    let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
+        LogDirective {name: ~"crate2", level: 3}];
+    unsafe {
+        do "crate2::mod1".to_c_str().with_ref |ptr| {
+            let entry= &ModEntry {name: ptr, log_level: &mut 0};
+            let m = update_entry(dirs, transmute(entry));
+            assert!(*entry.log_level == 3);
+            assert!(m == 1);
+        }
+    }
+}
+
+#[test]
+fn update_entry_match_beginning_longest_match() {
+    use c_str::ToCStr;
+    let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 },
+        LogDirective {name: ~"crate2", level: 3}, LogDirective {name: ~"crate2::mod", level: 4}];
+    unsafe {
+        do "crate2::mod1".to_c_str().with_ref |ptr| {
+            let entry = &ModEntry {name: ptr, log_level: &mut 0};
+            let m = update_entry(dirs, transmute(entry));
+            assert!(*entry.log_level == 4);
+            assert!(m == 1);
+        }
+    }
+}
diff --git a/src/rt/rust_crate_map.cpp b/src/rt/rust_crate_map.cpp
index 7faae196000..e6206fd7bcb 100644
--- a/src/rt/rust_crate_map.cpp
+++ b/src/rt/rust_crate_map.cpp
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -12,36 +12,52 @@
 #include <set>
 
 void iter_module_map(const mod_entry* map,
-                     void (*fn)(const mod_entry* entry, void *cookie),
-                     void *cookie) {
+                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                    void* fptr,
+                    void* env
+                    ) {
     for (const mod_entry* cur = map; cur->name; cur++) {
-        fn(cur, cookie);
+        fn(fptr, env, cur);
     }
 }
 
 void iter_crate_map(const cratemap* map,
-                    void (*fn)(const mod_entry* map, void *cookie),
-                    void *cookie,
+                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                    void *fptr,
+                    void *env,
                     std::set<const cratemap*>& visited) {
     if (visited.find(map) == visited.end()) {
         // Mark this crate visited
         visited.insert(map);
         // First iterate this crate
-        iter_module_map(map->entries(), fn, cookie);
+        iter_module_map(map->entries(), fn, fptr, env);
         // Then recurse on linked crates
         for (cratemap::iterator i = map->begin(),
                 e = map->end(); i != e; ++i) {
-            iter_crate_map(*i, fn, cookie, visited);
+            iter_crate_map(*i, fn, fptr, env, visited);
         }
     }
 }
 
 void iter_crate_map(const cratemap* map,
-                    void (*fn)(const mod_entry* map, void *cookie),
-                    void *cookie) {
+                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                    void *fptr,
+                    void *env
+                    ) {
     std::set<const cratemap*> visited;
-    iter_crate_map(map, fn, cookie, visited);
+    iter_crate_map(map, fn, fptr, env, visited);
 }
+
+extern "C" CDECL void
+rust_iter_crate_map(const cratemap* map,
+                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                    void *fptr,
+                    void *env
+                    ) {
+    return iter_crate_map(map, fn, fptr, env);
+}
+
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rust_crate_map.h b/src/rt/rust_crate_map.h
index 80b969d6f6d..1bcb2aa8f7e 100644
--- a/src/rt/rust_crate_map.h
+++ b/src/rt/rust_crate_map.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -16,7 +16,7 @@
 
 struct mod_entry {
     const char* name;
-    uint32_t* state;
+    uint32_t* log_level;
 };
 
 class cratemap;
@@ -83,12 +83,14 @@ public:
 };
 
 void iter_module_map(const mod_entry* map,
-                     void (*fn)(const mod_entry* entry, void *cookie),
-                     void *cookie);
+                     void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                     void *fptr,
+                     void *env);
 
 void iter_crate_map(const cratemap* map,
-                    void (*fn)(const mod_entry* entry, void *cookie),
-                    void *cookie);
+                    void (*fn)(void* fptr, void* env, const mod_entry *entry),
+                    void *fptr,
+                    void *env);
 
 //
 // Local Variables:
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
deleted file mode 100644
index 97c1135fe01..00000000000
--- a/src/rt/rust_log.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*
- * Logging infrastructure that aims to support multi-threading
- */
-
-
-#include "rust_crate_map.h"
-#include "util/array_list.h"
-#include "rust_util.h"
-
-// Reading log directives and setting log level vars
-
-struct log_directive {
-    char* name;
-    size_t level;
-};
-
-
-const uint32_t log_err = 1;
-const uint32_t log_warn = 2;
-const uint32_t log_info = 3;
-const uint32_t log_debug = 4;
-
-const size_t max_log_directives = 255;
-const size_t max_log_level = 255;
-const size_t default_log_level = log_err;
-
-// This is a rather ugly parser for strings in the form
-// "crate1,crate2.mod3,crate3.x=1". Log levels are 0-255,
-// with the most likely ones being 0-3 (defined in std::).
-size_t parse_logging_spec(char* spec, log_directive* dirs) {
-    size_t dir = 0;
-    while (dir < max_log_directives && *spec) {
-        char* start = spec;
-        char cur;
-        while (true) {
-            cur = *spec;
-            if (cur == ',' || cur == '=' || cur == '\0') {
-                if (start == spec) {spec++; break;}
-                if (*spec != '\0') {
-                    *spec = '\0';
-                    spec++;
-                }
-                size_t level = max_log_level;
-                if (cur == '=' && *spec != '\0') {
-                    level = *spec - '0';
-                    if (level > max_log_level) level = max_log_level;
-                    if (*spec) ++spec;
-                }
-                dirs[dir].name = start;
-                dirs[dir++].level = level;
-                break;
-            } else {
-                spec++;
-            }
-        }
-    }
-    return dir;
-}
-
-struct update_entry_args {
-    log_directive* dirs;
-    size_t n_dirs;
-    size_t *n_matches;
-};
-
-static void update_entry(const mod_entry* entry, void *cookie) {
-    update_entry_args *args = (update_entry_args *)cookie;
-    size_t level = default_log_level, longest_match = 0;
-    for (size_t d = 0; d < args->n_dirs; d++) {
-        if (strstr(entry->name, args->dirs[d].name) == entry->name &&
-            strlen(args->dirs[d].name) > longest_match) {
-            longest_match = strlen(args->dirs[d].name);
-            level = args->dirs[d].level;
-        }
-    }
-    *entry->state = level;
-    if (longest_match > 0) {
-        (*args->n_matches)++;
-    }
-}
-
-void update_crate_map(const cratemap* map, log_directive* dirs,
-                      size_t n_dirs, size_t *n_matches) {
-    update_entry_args args = { dirs, n_dirs, n_matches };
-    iter_crate_map(map, update_entry, &args);
-}
-
-void print_mod_name(const mod_entry* mod, void *cooke) {
-    printf(" %s\n", mod->name);
-}
-
-void print_crate_log_map(const cratemap* map) {
-    iter_crate_map(map, print_mod_name, NULL);
-}
-
-void update_log_settings(void* crate_map, char* settings) {
-    char* buffer = NULL;
-    log_directive dirs[256];
-    size_t n_dirs = 0;
-
-    if (settings) {
-
-        if (strcmp(settings, "::help") == 0 ||
-            strcmp(settings, "?") == 0) {
-            printf("\nCrate log map:\n\n");
-            print_crate_log_map((const cratemap*)crate_map);
-            printf("\n");
-            exit(1);
-        }
-
-        size_t buflen = strlen(settings) + 1;
-        buffer = (char*)malloc(buflen);
-        strncpy(buffer, settings, buflen);
-        n_dirs = parse_logging_spec(buffer, &dirs[0]);
-    }
-
-    size_t n_matches = 0;
-    update_crate_map((const cratemap*)crate_map, &dirs[0],
-                     n_dirs, &n_matches);
-
-    if (n_matches < n_dirs) {
-        fprintf(stderr, "warning: got %lu RUST_LOG specs but only matched %lu of them.\n"
-                "You may have mistyped a RUST_LOG spec.\n"
-                "Use RUST_LOG=::help to see the list of crates and modules.\n",
-                (unsigned long)n_dirs, (unsigned long)n_matches);
-    }
-
-    free(buffer);
-}
-
-extern "C" CDECL void
-rust_update_log_settings(void* crate_map, char* settings) {
-    update_log_settings(crate_map, settings);
-}
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
-// End:
-//
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index b668d394406..c1ba0524be9 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -182,7 +182,7 @@ rust_valgrind_stack_register
 rust_valgrind_stack_deregister
 rust_take_env_lock
 rust_drop_env_lock
-rust_update_log_settings
+rust_iter_crate_map
 rust_running_on_valgrind
 rust_get_num_cpus
 rust_get_global_args_ptr
@@ -191,4 +191,4 @@ rust_drop_global_args_lock
 rust_take_change_dir_lock
 rust_drop_change_dir_lock
 rust_get_test_int
-rust_get_task
\ No newline at end of file
+rust_get_task