unistd: add a preliminary implementation of getopt()
This commit is contained in:
@@ -9,3 +9,5 @@ cbindgen = { path = "../../cbindgen" }
|
||||
|
||||
[dependencies]
|
||||
platform = { path = "../platform" }
|
||||
stdio = { path = "../stdio" }
|
||||
string = { path = "../string" }
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
//! getopt implementation for Redox, following http://pubs.opengroup.org/onlinepubs/009695399/functions/getopt.html
|
||||
|
||||
use super::platform::types::*;
|
||||
use super::platform;
|
||||
use super::stdio;
|
||||
use super::string;
|
||||
use core::ptr;
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut optarg: *mut c_char = ptr::null_mut();
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut optind: c_int = 1;
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut opterr: c_int = 1;
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut optopt: c_int = -1;
|
||||
|
||||
static mut current_opt: *mut c_char = ptr::null_mut();
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getopt(
|
||||
argc: c_int,
|
||||
argv: *const *mut c_char,
|
||||
optstring: *const c_char,
|
||||
) -> c_int {
|
||||
if current_opt == ptr::null_mut() || *current_opt == 0 {
|
||||
let current_arg = *argv.offset(optind as isize);
|
||||
// XXX: is argc check needed?
|
||||
if optind > argc || current_arg == ptr::null_mut() || *current_arg != b'-' as c_char
|
||||
|| string::strcmp(current_arg, b"-\0".as_ptr() as _) == 0
|
||||
{
|
||||
-1
|
||||
} else if string::strcmp(current_arg, b"--\0".as_ptr() as _) == 0 {
|
||||
optind += 1;
|
||||
-1
|
||||
} else {
|
||||
// remove the '-'
|
||||
let current_arg = current_arg.offset(1);
|
||||
|
||||
parse_arg(argc, argv, current_arg, optstring)
|
||||
}
|
||||
} else {
|
||||
parse_arg(argc, argv, current_opt, optstring)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn parse_arg(
|
||||
argc: c_int,
|
||||
argv: *const *mut c_char,
|
||||
current_arg: *mut c_char,
|
||||
optstring: *const c_char,
|
||||
) -> c_int {
|
||||
let update_current_opt = || {
|
||||
current_opt = current_arg.offset(1);
|
||||
if *current_opt == 0 {
|
||||
optind += 1;
|
||||
}
|
||||
};
|
||||
|
||||
let print_error = |desc: &[u8]| {
|
||||
// NOTE: we don't use fprintf to get around the usage of va_list
|
||||
stdio::fputs(*argv as _, stdio::stderr);
|
||||
stdio::fputs(desc.as_ptr() as _, stdio::stderr);
|
||||
stdio::fputc(*current_arg as _, stdio::stderr);
|
||||
stdio::fputc(b'\n' as _, stdio::stderr);
|
||||
};
|
||||
|
||||
match find_option(*current_arg, optstring) {
|
||||
Some(GetoptOption::Flag) => {
|
||||
update_current_opt();
|
||||
|
||||
*current_arg as c_int
|
||||
}
|
||||
Some(GetoptOption::OptArg) => {
|
||||
current_opt = b"\0".as_ptr() as _;
|
||||
if *current_arg.offset(1) == 0 {
|
||||
optind += 2;
|
||||
if optind > argc {
|
||||
current_opt = ptr::null_mut();
|
||||
|
||||
optopt = *current_arg as c_int;
|
||||
let errch = if *optstring == b':' as c_char {
|
||||
b':'
|
||||
} else {
|
||||
if opterr != 0 {
|
||||
print_error(b": option requries an argument -- \0");
|
||||
}
|
||||
|
||||
b'?'
|
||||
};
|
||||
errch as c_int
|
||||
} else {
|
||||
optarg = *argv.offset(optind as isize - 1);
|
||||
|
||||
*current_arg as c_int
|
||||
}
|
||||
} else {
|
||||
optarg = current_arg.offset(1);
|
||||
optind += 1;
|
||||
|
||||
*current_arg as c_int
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// couldn't find the given option in optstring
|
||||
if opterr != 0 {
|
||||
print_error(b": illegal option -- \0");
|
||||
}
|
||||
|
||||
update_current_opt();
|
||||
|
||||
optopt = *current_arg as _;
|
||||
b'?' as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum GetoptOption {
|
||||
Flag,
|
||||
OptArg,
|
||||
}
|
||||
|
||||
unsafe fn find_option(ch: c_char, optstring: *const c_char) -> Option<GetoptOption> {
|
||||
let mut i = 0;
|
||||
|
||||
while *optstring.offset(i) != 0 {
|
||||
if *optstring.offset(i) == ch {
|
||||
let result = if *optstring.offset(i + 1) == b':' as c_char {
|
||||
GetoptOption::OptArg
|
||||
} else {
|
||||
GetoptOption::Flag
|
||||
};
|
||||
return Some(result);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -3,10 +3,15 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate platform;
|
||||
extern crate stdio;
|
||||
extern crate string;
|
||||
|
||||
pub use platform::types::*;
|
||||
pub use getopt::*;
|
||||
use core::ptr;
|
||||
|
||||
mod getopt;
|
||||
|
||||
pub const R_OK: c_int = 1;
|
||||
pub const W_OK: c_int = 2;
|
||||
pub const X_OK: c_int = 4;
|
||||
@@ -204,11 +209,6 @@ pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getopt(argc: c_int, argv: *const *mut c_char, opstring: *const c_char) -> c_int {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getpagesize() -> c_int {
|
||||
unimplemented!();
|
||||
|
||||
Reference in New Issue
Block a user