Add fmtmsg
This commit is contained in:
committed by
Mathew John Roberts
parent
c1912066a1
commit
03d56f4887
@@ -0,0 +1,9 @@
|
||||
sys_includes = []
|
||||
include_guard = "_RELIBC_FMTMSG_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
no_includes = true
|
||||
cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
@@ -0,0 +1,167 @@
|
||||
//! `fmtmsg.h` implementation.
|
||||
//!
|
||||
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fmtmsg.h.html>.
|
||||
//! Ported from Musl.
|
||||
//!
|
||||
//! See <https://github.com/kraj/musl/blob/kraj/master/src/misc/fmtmsg.c>
|
||||
|
||||
use crate::{
|
||||
header::{
|
||||
fcntl::open,
|
||||
pthread::{PTHREAD_CANCEL_DISABLE, pthread_setcancelstate},
|
||||
stdio::dprintf,
|
||||
stdlib::getenv,
|
||||
string::strchr,
|
||||
unistd::close,
|
||||
},
|
||||
platform::types::{c_char, c_int, c_long},
|
||||
};
|
||||
pub const MM_NULLSEV: c_int = 0;
|
||||
pub const MM_HALT: c_int = 1;
|
||||
pub const MM_ERROR: c_int = 2;
|
||||
pub const MM_WARNING: c_int = 3;
|
||||
pub const MM_INFO: c_int = 4;
|
||||
pub const MM_NOMSG: c_int = 1;
|
||||
pub const MM_NOTOK: c_int = -1;
|
||||
// c_long because classification is a c_long
|
||||
pub const MM_PRINT: c_long = 256;
|
||||
// c_long because classification is a c_long
|
||||
pub const MM_CONSOLE: c_long = 512;
|
||||
pub const MM_NOCON: c_int = 4;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const O_WRONLY: c_int = 0x0001;
|
||||
#[cfg(target_os = "redox")]
|
||||
//Take from `src/header/fcntl/redox.rs`
|
||||
pub const O_WRONLY: c_int = 0x0002_0000;
|
||||
|
||||
/*
|
||||
* If lstr is the first part of bstr, check that the next char in bstr
|
||||
* is either \0 or ':'
|
||||
*/
|
||||
unsafe fn strcolcmp(mut lstr: *const c_char, mut bstr: *const c_char) -> c_int {
|
||||
unsafe {
|
||||
// We already know lstr and bstr are non-null
|
||||
while *lstr != 0 && *bstr != 0 && (*lstr == *bstr) {
|
||||
lstr = lstr.add(1);
|
||||
bstr = bstr.add(1);
|
||||
}
|
||||
if *lstr != 0 || (*bstr != 0 && *bstr != b':' as c_char) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fmtmsg.h.html>
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn fmtmsg(
|
||||
classification: c_long,
|
||||
label: *const c_char,
|
||||
severity: c_int,
|
||||
text: *const c_char,
|
||||
action: *const c_char,
|
||||
tag: *const c_char,
|
||||
) -> c_int {
|
||||
let mut ret: c_int = 0;
|
||||
let mut verb: c_int = 0;
|
||||
let mut i: usize;
|
||||
let consolefd: c_int;
|
||||
let mut cs: c_int = 0;
|
||||
unsafe {
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &mut cs as *mut c_int);
|
||||
}
|
||||
let mut cmsg = unsafe { getenv(c"MSGVERB".as_ptr()) };
|
||||
let errstring: *const c_char = match severity {
|
||||
MM_HALT => c"HALT: ".as_ptr(),
|
||||
MM_ERROR => c"ERROR: ".as_ptr(),
|
||||
MM_WARNING => c"WARNING: ".as_ptr(),
|
||||
MM_INFO => c"INFO: ".as_ptr(),
|
||||
_ => MM_NULLSEV as _, // Default
|
||||
};
|
||||
let msgs: [*const c_char; 6] = [
|
||||
c"label".as_ptr(),
|
||||
c"severity".as_ptr(),
|
||||
c"text".as_ptr(),
|
||||
c"action".as_ptr(),
|
||||
c"tag".as_ptr(),
|
||||
core::ptr::null(),
|
||||
];
|
||||
if (classification & MM_CONSOLE) != 0 {
|
||||
//TODO: rusty
|
||||
unsafe {
|
||||
consolefd = open(c"/dev/console".as_ptr(), O_WRONLY);
|
||||
if consolefd < 0 {
|
||||
ret = MM_NOCON;
|
||||
} else {
|
||||
#[rustfmt::skip]
|
||||
let status = dprintf(
|
||||
consolefd,
|
||||
c"%s%s%s%s%s%s%s%s\n".as_ptr(),
|
||||
if !label.is_null() {label } else { c"".as_ptr()},
|
||||
if !label.is_null() {c": ".as_ptr()} else { c"".as_ptr() },
|
||||
if severity != 0 { errstring } else { c"".as_ptr()},
|
||||
if !text.is_null() { text } else { c"".as_ptr() },
|
||||
if !action.is_null() {c"\nTO FIX: ".as_ptr()} else { c"".as_ptr()},
|
||||
if !action.is_null() {action} else {c"".as_ptr()},
|
||||
if !action.is_null() {c" ".as_ptr()} else { c"".as_ptr()},
|
||||
if !tag.is_null() { tag } else { c"".as_ptr() },
|
||||
);
|
||||
if status < 1 {
|
||||
ret = MM_NOCON;
|
||||
}
|
||||
close(consolefd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (classification & MM_PRINT) != 0 {
|
||||
unsafe {
|
||||
while !cmsg.is_null() && *cmsg != 0 {
|
||||
i = 0;
|
||||
loop {
|
||||
if msgs[i].is_null() {
|
||||
break;
|
||||
}
|
||||
if strcolcmp(msgs[i], cmsg) == 0 {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if msgs[i].is_null() {
|
||||
//ignore MSGVERB-unrecognized component
|
||||
verb = 0xFF;
|
||||
break;
|
||||
} else {
|
||||
verb |= 1 << i;
|
||||
cmsg = strchr(cmsg, b':' as _);
|
||||
if !cmsg.is_null() {
|
||||
cmsg = cmsg.add(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if verb == 0 {
|
||||
verb = 0xFF;
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
let status = dprintf(2,c"%s%s%s%s%s%s%s%s\n".as_ptr(),
|
||||
if (verb & 1 != 0) && !label.is_null() { label } else { c"".as_ptr() },
|
||||
if (verb & 1 != 0) && !label.is_null() { c": ".as_ptr() } else { c"".as_ptr() },
|
||||
if (verb & 2 != 0) && severity != 0 { errstring } else { c"".as_ptr() },
|
||||
if (verb & 4 != 0) && !text.is_null() { text } else { c"".as_ptr() },
|
||||
if (verb & 8 != 0) && !action.is_null() { c"\nTO FIX: ".as_ptr() } else { c"".as_ptr() },
|
||||
if (verb & 8 != 0) && !action.is_null() { action } else { c"".as_ptr() },
|
||||
if (verb & 8 != 0) && !action.is_null() { c" ".as_ptr() } else { c"".as_ptr() },
|
||||
if (verb & 16 != 0) && !tag.is_null() { tag } else { c"".as_ptr() },
|
||||
);
|
||||
if status < 1 {
|
||||
ret |= MM_NOMSG;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ret & (MM_NOCON | MM_NOMSG) == (MM_NOCON | MM_NOMSG) {
|
||||
ret = MM_NOTOK;
|
||||
}
|
||||
unsafe {
|
||||
pthread_setcancelstate(cs, 0 as _);
|
||||
}
|
||||
ret
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ pub mod err;
|
||||
pub mod errno;
|
||||
pub mod fcntl;
|
||||
pub mod float;
|
||||
// TODO: fmtmsg.h
|
||||
pub mod fmtmsg;
|
||||
pub mod fnmatch;
|
||||
// TODO: ftw.h
|
||||
pub mod getopt;
|
||||
|
||||
@@ -208,7 +208,8 @@ EXPECT_NAMES=\
|
||||
wctype/towlower \
|
||||
wctype/towupper \
|
||||
mknod \
|
||||
mknodat
|
||||
mknodat \
|
||||
fmtmsg
|
||||
|
||||
# Binaries that may generate varied output
|
||||
VARIED_NAMES=\
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
XSI:cat: ERROR: illegal option
|
||||
TO FIX: refer to cat in user's reference manual XSI:cat:001
|
||||
XSI:cat: ERROR: illegal option
|
||||
TO FIX: refer to cat in user's reference manual XSI:cat:001
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <fmtmsg.h>
|
||||
#include <unistd.h>
|
||||
int main() {
|
||||
/* Returned Value
|
||||
* MM_OK: 0 - The function succeeded.
|
||||
* MM_NOCON: 4 - The function was unable to generate a console message, but otherwise succeeded.
|
||||
* MM_NOMSG: 1 - The function was unable to generate a message on standard error, but otherwise succeeded.
|
||||
* MM_NOTOK: -1 - The function failed completely.
|
||||
*
|
||||
* Take from: https://www.ibm.com/docs/en/zos/3.1.0?topic=functions-fmtmsg-display-message-in-specified-format
|
||||
*/
|
||||
int mm_ok = fmtmsg(MM_PRINT, "XSI:cat", MM_ERROR, "illegal option",
|
||||
"refer to cat in user's reference manual", "XSI:cat:001");
|
||||
if (mm_ok != 0) {
|
||||
return -1;
|
||||
}
|
||||
// Thats return 0 in glibc but return 4 in musl
|
||||
// So we expect 4 here
|
||||
int mm_nocon = fmtmsg(MM_PRINT | MM_CONSOLE, "XSI:cat", MM_ERROR, "illegal option",
|
||||
"refer to cat in user's reference manual", "XSI:cat:001");
|
||||
if (mm_nocon != MM_NOCON) {
|
||||
return -1;
|
||||
}
|
||||
//We close stderr to test.
|
||||
close(STDERR_FILENO);
|
||||
int mm_nomsg = fmtmsg(MM_PRINT , "XSI:cat", MM_ERROR, "illegal option",
|
||||
"refer to cat in user's reference manual", "XSI:cat:001");
|
||||
if (mm_nomsg != MM_NOMSG) {
|
||||
return -1;
|
||||
}
|
||||
// Thats return 1 in glibc but return -1 in musl
|
||||
// Soo we expect -1 here
|
||||
int mm_notok = fmtmsg(MM_PRINT | MM_CONSOLE, "XSI:cat", MM_ERROR, "illegal option",
|
||||
"refer to cat in user's reference manual", "XSI:cat:001");
|
||||
if (mm_notok != MM_NOTOK) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user