forked from bonsai/harakit
110 lines
3.3 KiB
Rust
110 lines
3.3 KiB
Rust
/*
|
|
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
|
|
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
* the terms of the GNU Lesser General Public License as published by the Free
|
|
* Software Foundation, either version 3 of the License, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
*/
|
|
|
|
use std::ffi::{ c_int, c_char, CString, CStr };
|
|
|
|
pub struct Opt {
|
|
pub arg: Option<String>,
|
|
pub ind: i32,
|
|
pub opt: i32,
|
|
}
|
|
|
|
pub enum OptError {
|
|
MissingArg,
|
|
UnknownOpt,
|
|
}
|
|
|
|
// Function signature
|
|
pub trait GetOpt {
|
|
fn getopt(&self, optstring: &str) -> Option<Result<Opt, OptError>>;
|
|
}
|
|
|
|
impl GetOpt for Vec<String> {
|
|
fn getopt(&self, optstring: &str) -> Option<Result<Opt, OptError>> {
|
|
let c_strings: Vec<_> = self
|
|
.iter()
|
|
.cloned()
|
|
.map(CString::new)
|
|
.map(Result::unwrap)
|
|
.collect();
|
|
|
|
let argv: Vec<_> = c_strings.iter().map(|x| x.as_ptr()).collect();
|
|
let argv_ptr = argv.as_ptr() as *const *mut c_char;
|
|
let optstring_c = CString::new(optstring).unwrap();
|
|
let opts = optstring_c.into_raw();
|
|
let len = self.len() as c_int;
|
|
|
|
unsafe {
|
|
let a = match getopt(len, argv_ptr, opts) {
|
|
/* From getopt(3p):
|
|
*
|
|
* The getopt() function shall return the next option character
|
|
* specified on the command line.
|
|
*
|
|
* A <colon> (':') shall be returned if getopt() detects a
|
|
* missing argument and the first character of optstring was a
|
|
* <colon> (':').
|
|
*
|
|
* A <question-mark> ('?') shall be returned if getopt()
|
|
* encounters an option character not in optstring or detects a
|
|
* missing argument and the first character of optstring was not
|
|
* a <colon> (':').
|
|
*
|
|
* Otherwise, getopt() shall return -1 when all command line
|
|
* options are parsed. */
|
|
58 => { /* ASCII value for ':' */
|
|
return Some(Err(OptError::MissingArg));
|
|
},
|
|
63 => { /* ASCII value for '?' */
|
|
return Some(Err(OptError::UnknownOpt))
|
|
},
|
|
/* From getopt(3p):
|
|
*
|
|
* If, when getopt() is called:
|
|
*
|
|
* argv[optind] is a null pointer
|
|
* *argv[optind] is not the character -
|
|
* argv[optind] points to the string "-"
|
|
*
|
|
* getopt() shall return -1 without changing optind. If:
|
|
*
|
|
* argv[optind] points to the string "--"
|
|
*
|
|
* getopt() shall return -1 after incrementing optind. */
|
|
-1 => return None,
|
|
_ => CStr::from_ptr(optarg).to_string_lossy().into_owned(),
|
|
};
|
|
|
|
Some(Ok(Opt { arg: Some(a), ind: optind, opt: optopt }))
|
|
}
|
|
}
|
|
}
|
|
/* binding to getopt(3p) */
|
|
extern "C" {
|
|
static mut optarg: *mut c_char;
|
|
static mut _opterr: c_int;
|
|
static mut optind: c_int;
|
|
static mut optopt: c_int;
|
|
|
|
fn getopt(
|
|
___argc: c_int,
|
|
___argv: *const *mut c_char,
|
|
__shortopts: *const c_char,
|
|
) -> c_int;
|
|
}
|