unistd: add a preliminary implementation of getopt()
This commit is contained in:
Generated
+2
@@ -534,6 +534,8 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen 0.5.2",
|
||||
"platform 0.1.0",
|
||||
"stdio 0.1.0",
|
||||
"string 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -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!();
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
/string/strchr
|
||||
/string/strrchr
|
||||
/string/strspn
|
||||
/unistd/getopt
|
||||
/unlink
|
||||
/waitpid
|
||||
/write
|
||||
|
||||
@@ -32,6 +32,7 @@ EXPECT_BINS=\
|
||||
string/strpbrk \
|
||||
string/strtok \
|
||||
string/strtok_r \
|
||||
unistd/getopt \
|
||||
unlink \
|
||||
waitpid \
|
||||
write
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
bflg: 0
|
||||
aflg: 1
|
||||
errflg: 0
|
||||
ifile:
|
||||
ofile: arg
|
||||
result: 0
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RUN(...) \
|
||||
{ \
|
||||
optind = 1; \
|
||||
optarg = NULL; \
|
||||
opterr = 1; \
|
||||
optopt = -1; \
|
||||
char *args_arr[] = { __VA_ARGS__ }; \
|
||||
printf("result: %d\n", runner(sizeof(args_arr) / sizeof(args_arr[0]), args_arr)); \
|
||||
}
|
||||
|
||||
int runner(int argc, const char *argv[]) {
|
||||
int c;
|
||||
int bflg = 0, aflg = 0, errflg = 0;
|
||||
char *ifile = "";
|
||||
char *ofile = "";
|
||||
|
||||
while((c = getopt(argc, argv, ":abf:o:")) != -1) {
|
||||
switch(c) {
|
||||
case 'a':
|
||||
if(bflg)
|
||||
errflg++;
|
||||
else
|
||||
aflg++;
|
||||
break;
|
||||
case 'b':
|
||||
if(aflg)
|
||||
errflg++;
|
||||
else
|
||||
bflg++;
|
||||
break;
|
||||
case 'f':
|
||||
ifile = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
ofile = optarg;
|
||||
break;
|
||||
case ':':
|
||||
printf("Option -%c requires an operand\n", optopt);
|
||||
errflg++;
|
||||
break;
|
||||
case '?':
|
||||
printf("Unrecognized option: -%c\n", optopt);
|
||||
errflg++;
|
||||
}
|
||||
}
|
||||
printf("bflg: %d\n", bflg);
|
||||
printf("aflg: %d\n", aflg);
|
||||
printf("errflg: %d\n", errflg);
|
||||
printf("ifile: %s\n", ifile);
|
||||
printf("ofile: %s\n", ofile);
|
||||
if(errflg) {
|
||||
printf("Usage: info goes here\n");
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
RUN("test", "-ao", "arg", "path", "path");
|
||||
RUN("test", "-a", "-o", "arg", "path", "path");
|
||||
RUN("test", "-o", "arg", "-a", "path", "path");
|
||||
RUN("test", "-a", "-o", "arg", "--", "path", "path");
|
||||
RUN("test", "-a", "-oarg", "path", "path");
|
||||
RUN("test", "-aoarg", "path", "path");
|
||||
}
|
||||
Reference in New Issue
Block a user