Merge pull request #97 from Arcterus/master

unistd: add a preliminary implementation of getopt()
This commit is contained in:
Jeremy Soller
2018-03-21 20:55:43 -06:00
committed by GitHub
9 changed files with 271 additions and 5 deletions
Generated
+2
View File
@@ -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]]
+2
View File
@@ -9,3 +9,5 @@ cbindgen = { path = "../../cbindgen" }
[dependencies]
platform = { path = "../platform" }
stdio = { path = "../stdio" }
string = { path = "../string" }
+149
View File
@@ -0,0 +1,149 @@
//! 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;
#[allow(non_upper_case_globals)]
#[no_mangle]
pub static mut optarg: *mut c_char = ptr::null_mut();
#[allow(non_upper_case_globals)]
#[no_mangle]
pub static mut optind: c_int = 1;
#[allow(non_upper_case_globals)]
#[no_mangle]
pub static mut opterr: c_int = 1;
#[allow(non_upper_case_globals)]
#[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.is_null() || *CURRENT_OPT == 0 {
if optind >= argc {
-1
} else {
let current_arg = *argv.offset(optind as isize);
if current_arg.is_null() || *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
}
+5 -5
View File
@@ -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!();
+1
View File
@@ -33,6 +33,7 @@
/string/strchr
/string/strrchr
/string/strspn
/unistd/getopt
/unlink
/waitpid
/write
+1
View File
@@ -32,6 +32,7 @@ EXPECT_BINS=\
string/strpbrk \
string/strtok \
string/strtok_r \
unistd/getopt \
unlink \
waitpid \
write
View File
+42
View File
@@ -0,0 +1,42 @@
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
bflg: 0
aflg: 0
errflg: 0
ifile:
ofile:
result: 0
+69
View File
@@ -0,0 +1,69 @@
#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, 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");
RUN("test");
}