diff --git a/bash-5.1/Cargo.toml b/bash-5.1/Cargo.toml index aca5602b61b44cfb680059a592d04899c71e340b..8e32b89b05855f3b8b9eeae138b947958011f59b 100644 --- a/bash-5.1/Cargo.toml +++ b/bash-5.1/Cargo.toml @@ -9,7 +9,8 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace] members = ["builtins_rust/read", "builtins/command1", "builtins/command2", "builtins_rust/history", "builtins_rust/kill", -"builtins_rust/rlet"] +"builtins_rust/rlet", "builtins_rust/mapfile"] + [dependencies] libc = "0.2" @@ -19,3 +20,5 @@ read = {path = "./builtins_rust/read"} history = {path = "./builtins_rust/history"} kill = {path = "./builtins_rust/kill"} rlet = {path = "./builtins_rust/rlet"} +mapfile = {path = "./builtins_rust/mapfile"} + diff --git a/bash-5.1/builtins_rust/complete/Cargo.toml b/bash-5.1/builtins_rust/complete/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..eb1413884f10dec06d0e8bda6b1db9cf141cf1fc 100644 --- a/bash-5.1/builtins_rust/complete/Cargo.toml +++ b/bash-5.1/builtins_rust/complete/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rcomplete" +version = "0.0.1" +build = "../build.rs" +edition = "2021" + + +[dependencies] +lazy_static = "1.4.0" +libc = "0.2" +nix = "0.23.0" + +[lib] +crate-type = ["cdylib"] +name = "rcomplete" diff --git a/bash-5.1/builtins_rust/complete/src/lib.rs b/bash-5.1/builtins_rust/complete/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d00afdf7de2705ac7a918839b467f67c998f7bc9 100644 --- a/bash-5.1/builtins_rust/complete/src/lib.rs +++ b/bash-5.1/builtins_rust/complete/src/lib.rs @@ -0,0 +1,1414 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_int, c_ulong, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut c_char, + pub flags:c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(u8)] +enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, + cm_connection, cm_function_def, cm_until, cm_group, + cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc +} + +#[repr(u8)] +#[derive(Copy,Clone)] +enum r_instruction { + r_output_direction, r_input_direction, r_inputa_direction, + r_appending_to, r_reading_until, r_reading_string, + r_duplicating_input, r_duplicating_output, r_deblank_reading_until, + r_close_this, r_err_and_out, r_input_output, r_output_force, + r_duplicating_input_word, r_duplicating_output_word, + r_move_input, r_move_output, r_move_input_word, r_move_output_word, + r_append_err_and_out +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:c_int, + flags:c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct PATTERN_LIST { + next:* mut PATTERN_LIST, + patterns:* mut WORD_LIST, + action:*mut COMMAND, + flags:c_int +} + +#[repr(C)] +pub struct case_com { + flags:c_int, + line:c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:c_int +} + +#[repr(C)] +pub struct simple_com { + flags:c_int, + line:c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + command:*mut COMMAND, + source_file:*mut c_char +} + +#[repr(C)] +pub struct group_com { + ignore:libc::c_int, + command:*mut COMMAND, + source_file:*mut c_char +} + +#[repr(C)] +pub struct select_com { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:c_int, + line:c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:c_int, + line:c_int, + type_c:c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:c_int, + line:c_int, + init:*mut WORD_LIST, + test:*mut WORD_LIST, + step:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct subshell_com { + flags:i32, + line:i32, + command:*mut COMMAND +} + +#[repr(C)] +pub struct coproc_com { + flags:i32, + name:*mut c_char, + command:*mut COMMAND +} + +#[repr(C)] +pub union VALUE_COMMAND { + For:*mut for_com, + Case:*mut case_com, + While:*mut while_com, + If:*mut if_com, + Connection:*mut connection, + Simple:*mut simple_com, + Function_def:*mut function_def, + Group:*mut group_com, + Select:*mut select_com, + Arith:*mut arith_com, + Cond:*mut cond_com, + ArithFor:*mut arith_for_com, + Subshell:*mut subshell_com, + Coproc:*mut coproc_com +} + +#[repr(C)] +pub struct COMMAND { + type_c:command_type, + flags:i32, + line:i32, + redirects:*mut REDIRECT, + value:VALUE_COMMAND +} + +/* Structure containing all the non-action (binary) options; filled in by + build_actions(). */ +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _optflags { + pflag:c_int, + rflag:c_int, + Dflag:c_int, + Eflag:c_int, + Iflag:c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _compacts { + actname:* const c_char, + actflag:libc::c_ulong, + actopt:c_int, +} + +pub struct CompactsArray { + compactsArr:[_compacts;25usize] +} + +impl CompactsArray { + pub fn new()->CompactsArray { + CompactsArray{ + compactsArr:[ + _compacts{ actname:"alias\0".as_ptr() as *const c_char, actflag: CA_ALIAS!(),actopt: 'a' as c_int }, + _compacts{ actname:"arrayvar\0".as_ptr() as *const c_char, actflag: CA_ARRAYVAR!(),actopt: 0 as c_int }, + _compacts{ actname:"binding\0".as_ptr() as *const c_char, actflag: CA_BINDING!(),actopt: 0 as c_int }, + _compacts{ actname:"builtin\0".as_ptr() as *const c_char, actflag: CA_BUILTIN!(),actopt: 'b' as c_int }, + _compacts{ actname:"command\0".as_ptr() as *const c_char, actflag: CA_COMMAND!(),actopt: 'c' as c_int }, + _compacts{ actname:"directory\0".as_ptr() as *const c_char, actflag: CA_DIRECTORY!(),actopt: 'd' as c_int }, + _compacts{ actname:"disabled\0".as_ptr() as *const c_char, actflag: CA_DISABLED!(),actopt: 0 as c_int }, + _compacts{ actname:"enabled\0".as_ptr() as *const c_char, actflag: CA_ENABLED!(),actopt: 0 as c_int }, + _compacts{ actname:"export\0".as_ptr() as *const c_char, actflag: CA_EXPORT!(),actopt: 'e' as c_int }, + _compacts{ actname:"file\0".as_ptr() as *const c_char, actflag: CA_FILE!(),actopt: 'f' as c_int }, + _compacts{ actname:"function\0".as_ptr() as *const c_char, actflag: CA_FUNCTION!(),actopt: 0 as c_int }, + _compacts{ actname:"helptopic\0".as_ptr() as *const c_char, actflag: CA_HELPTOPIC!(),actopt: 0 as c_int }, + _compacts{ actname:"hostname\0".as_ptr() as *const c_char, actflag: CA_HOSTNAME!(),actopt: 0 as c_int }, + _compacts{ actname:"group\0".as_ptr() as *const c_char, actflag: CA_GROUP!(),actopt: 'g' as c_int }, + _compacts{ actname:"job\0".as_ptr() as *const c_char, actflag: CA_JOB!(),actopt: 'j' as c_int }, + _compacts{ actname:"keyword\0".as_ptr() as *const c_char, actflag: CA_KEYWORD!(),actopt: 'k' as c_int }, + _compacts{ actname:"running\0".as_ptr() as *const c_char, actflag: CA_RUNNING!(),actopt: 0 as c_int }, + _compacts{ actname:"service\0".as_ptr() as *const c_char, actflag: CA_SERVICE!(),actopt: 's' as c_int }, + _compacts{ actname:"setopt\0".as_ptr() as *const c_char, actflag: CA_SETOPT!(),actopt: 0 as c_int }, + _compacts{ actname:"shopt\0".as_ptr() as *const c_char, actflag: CA_SHOPT!(),actopt: 0 as c_int }, + _compacts{ actname:"signal\0".as_ptr() as *const c_char, actflag: CA_SIGNAL!(),actopt: 0 as c_int }, + _compacts{ actname:"stopped\0".as_ptr() as *const c_char, actflag: CA_STOPPED!(),actopt: 0 as c_int }, + _compacts{ actname:"user\0".as_ptr() as *const c_char, actflag: CA_USER!(),actopt: 'u' as c_int }, + _compacts{ actname:"variable\0".as_ptr() as *const c_char, actflag: CA_VARIABLE!(),actopt: 'v' as c_int }, + _compacts{ actname:std::ptr::null_mut(), actflag: 0,actopt: 0 as c_int }, + ] + } + } +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _compopt { + optname:* const c_char, + optflag:libc::c_ulong, +} + +pub struct CompoptArray { + compoptArr:[_compopt;9usize] +} + +impl CompoptArray { + pub fn new()->CompoptArray{ + CompoptArray{ + compoptArr:[ + _compopt{ optname:"bashdefault\0".as_ptr() as *const c_char, optflag:COPT_BASHDEFAULT!() }, + _compopt{ optname:"default\0".as_ptr() as *const c_char, optflag:COPT_DEFAULT!() }, + _compopt{ optname:"dirnames\0".as_ptr() as *const c_char, optflag:COPT_DIRNAMES!() }, + _compopt{ optname:"filenames\0".as_ptr() as *const c_char,optflag:COPT_FILENAMES!()}, + _compopt{ optname:"noquote\0".as_ptr() as *const c_char, optflag:COPT_NOQUOTE!() }, + _compopt{ optname:"nosort\0".as_ptr() as *const c_char, optflag:COPT_NOSORT!() }, + _compopt{ optname:"nospace\0".as_ptr() as *const c_char, optflag:COPT_NOSPACE!() }, + _compopt{ optname:"plusdirs\0".as_ptr() as *const c_char, optflag:COPT_PLUSDIRS!() }, + _compopt{ optname:std::ptr::null_mut(), optflag:0 }, + ] + } + } +} + + +#[repr(C)] +pub struct COMPSPEC { + refcount:c_int, + actions:c_ulong, + options:c_ulong, + globpat:* mut c_char, + words:* mut c_char, + prefix: * mut c_char, + suffix: * mut c_char, + funcname: * mut c_char, + command:* mut c_char, + lcommand:* mut c_char, + filterpat:* mut c_char, +} +#[repr(C)] +pub struct BUCKET_CONTENTS { + next:* mut BUCKET_CONTENTS, /* Link to next hashed key in this bucket. */ + key:* mut c_char, /* What we look up. */ + data:* mut libc::c_void, /* What we really want. */ + khash:libc::c_uint, /* What key hashes to */ + times_found:i32, /* Number of times this item has been found. */ +} + +#[repr(C)] +pub struct STRINGLIST { + list:* mut * mut c_char, + list_size:c_int, + list_len:c_int, +} + +#[macro_export] +macro_rules! EXECUTION_FAILURE { + () => {1} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! EXECUTION_SUCCESS { + () => { + 0 + } +} + +#[macro_export] +macro_rules! CA_ALIAS { + () => { + 1<<0 + } +} + +#[macro_export] +macro_rules! CA_ARRAYVAR { + () => { + 1<<1 + } +} + +#[macro_export] +macro_rules! CA_BINDING { + () => { + 1<<2 + } +} + +#[macro_export] +macro_rules! CA_BUILTIN { + () => { + 1<<3 + } +} + +#[macro_export] +macro_rules! CA_COMMAND { + () => { + 1<<4 + } +} + +#[macro_export] +macro_rules! CA_DIRECTORY { + () => { + 1<<5 + } +} + +#[macro_export] +macro_rules! CA_DISABLED { + () => { + 1<<6 + } +} + +#[macro_export] +macro_rules! CA_ENABLED { + () => { + 1<<7 + } +} + +#[macro_export] +macro_rules! CA_EXPORT { + () => { + 1<<8 + } +} + +#[macro_export] +macro_rules! CA_FILE { + () => { + 1<<9 + } +} + +#[macro_export] +macro_rules! CA_FUNCTION { + () => { + 1<<10 + } +} + +#[macro_export] +macro_rules! CA_GROUP { + () => { + 1<<11 + } +} + +#[macro_export] +macro_rules! CA_HELPTOPIC { + () => { + 1<<12 + } +} + +#[macro_export] +macro_rules! CA_HOSTNAME { + () => { + 1<<13 + } +} + +#[macro_export] +macro_rules! CA_JOB { + () => { + 1<<14 + } +} + +#[macro_export] +macro_rules! CA_KEYWORD { + () => { + 1<<15 + } +} + +#[macro_export] +macro_rules! CA_RUNNING { + () => { + 1<<16 + } +} + +#[macro_export] +macro_rules! CA_SERVICE { + () => { + 1<<17 + } +} + +#[macro_export] +macro_rules! CA_SETOPT { + () => { + 1<<18 + } +} + +#[macro_export] +macro_rules! CA_SHOPT { + () => { + 1<<19 + } +} + +#[macro_export] +macro_rules! CA_SIGNAL { + () => { + 1<<20 + } +} + +#[macro_export] +macro_rules! CA_STOPPED { + () => { + 1<<21 + } +} + +#[macro_export] +macro_rules! CA_USER { + () => { + 1<<22 + } +} + +#[macro_export] +macro_rules! CA_VARIABLE { + () => { + 1<<23 + } +} + +#[macro_export] +macro_rules! COPT_RESERVED { + () => { + 1<<0 + } +} + +#[macro_export] +macro_rules! COPT_DEFAULT { + () => { + 1<<1 + } +} + +#[macro_export] +macro_rules! COPT_FILENAMES { + () => { + 1<<2 + } +} + +#[macro_export] +macro_rules! COPT_DIRNAMES { + () => { + 1<<3 + } +} + +#[macro_export] +macro_rules! COPT_NOQUOTE { + () => { + 1<<4 + } +} + +#[macro_export] +macro_rules! COPT_NOSPACE { + () => { + 1<<5 + } +} + +#[macro_export] +macro_rules! COPT_BASHDEFAULT { + () => { + 1<<6 + } +} + +#[macro_export] +macro_rules! COPT_PLUSDIRS { + () => { + 1<<7 + } +} + +#[macro_export] +macro_rules! COPT_NOSORT { + () => { + 1<<8 + } +} + +#[macro_export] +macro_rules! RL_STATE_COMPLETING { + () => { + 0x0004000 /* doing completion */ + } +} + +extern "C" { + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + fn sh_invalidopt (value:* mut c_char); + fn sh_invalidid (value:* mut c_char); + fn sh_invalidoptname (value:* mut c_char); + fn builtin_usage(); + static list_optarg:* mut c_char; + fn builtin_error(err:*const c_char,...); + fn check_identifier (w:* mut WORD_DESC, f:i32)->i32; + static mut posixly_correct:i32; + static mut loptend:*mut WORD_LIST; + fn make_word_list (w:* mut WORD_DESC, list:*mut WORD_LIST)->*mut WORD_LIST; + fn make_bare_word (w:*const c_char)->* mut WORD_DESC; + fn dispose_words (list:*mut WORD_LIST); + fn progcomp_flush (); + fn compspec_create ()->* mut COMPSPEC; + fn progcomp_insert (str:* mut c_char, c:* mut COMPSPEC)->i32; + fn progcomp_remove (str:* mut c_char)->i32; + fn sh_single_quote (str:* mut c_char)->* mut c_char; + fn progcomp_walk (func: unsafe extern "C" fn (item:* mut BUCKET_CONTENTS)->i32); + fn sh_chkwrite (i:i32)->i32; + fn progcomp_search (w:*const c_char)->* mut COMPSPEC; + static mut pcomp_line:* mut c_char; + static mut pcomp_ind:c_int; + fn gen_compspec_completions (cs:* mut COMPSPEC, cmd:*const c_char, word:*const c_char, start:i32, end:i32, foundp:* mut i32)->* mut STRINGLIST; + fn bash_default_completion (text:* const c_char, start:i32, end:i32, qc:i32, compflags:i32)->* mut * mut c_char; + fn rl_filename_completion_function (text:* const c_char, state:i32)-> * mut c_char; + fn rl_completion_matches (text:* const c_char, entry_function:unsafe extern "C" fn (text:* const c_char, state:i32)-> * mut c_char)->* mut * mut c_char; + fn completions_to_stringlist (matches:* mut * mut c_char)->* mut STRINGLIST; + fn strvec_dispose (matches:* mut * mut c_char); + fn strlist_dispose (strlist:* mut STRINGLIST); + fn strlist_print (strlist:* mut STRINGLIST, text:* mut c_char); + fn compspec_dispose (com:* mut COMPSPEC); + static mut list_opttype:i32; + static mut rl_readline_state:c_ulong; + static mut pcomp_curcs:* mut COMPSPEC; + static pcomp_curcmd:* mut c_char; + fn pcomp_set_compspec_options (cs:* mut COMPSPEC, flags:i32, set_or_unset:i32); + fn pcomp_set_readline_variables (flags:i32, nval:i32); +} + +pub static mut Garg:* mut c_char=std::ptr::null_mut(); +pub static mut Warg:* mut c_char=std::ptr::null_mut(); +pub static mut Parg:* mut c_char=std::ptr::null_mut(); +pub static mut Sarg:* mut c_char=std::ptr::null_mut(); +pub static mut Xarg:* mut c_char=std::ptr::null_mut(); +pub static mut Farg:* mut c_char=std::ptr::null_mut(); +pub static mut Carg:* mut c_char=std::ptr::null_mut(); + +unsafe fn savestring(x:* const c_char)->* mut c_char +{ + let str1:* mut c_char=libc::malloc(1 + libc::strlen (x )) as * mut c_char; + return libc::strcpy(str1,x ); +} + +unsafe fn STRDUP(x:* const c_char)->* mut c_char +{ + if x !=std::ptr::null_mut() { + return savestring (x); + } else { + return std::ptr::null_mut(); + } +} + +unsafe fn STREQ( a:* const c_char, b:* const c_char)->bool +{ + return *a ==*b && libc::strcmp(a, b) == 0; +} + +unsafe fn shell_break_chars()->* const c_char +{ + return "()<>;&| \t\n\0".as_ptr() as *const c_char; +} + +unsafe fn EMPTYCMD()->* const c_char +{ + return "_EmptycmD_\0".as_ptr() as *const c_char; +} + +unsafe fn DEFAULTCMD()->* const c_char +{ + return "_DefaultCmD_\0".as_ptr() as *const c_char; +} + +unsafe fn INITIALWORD()->* const c_char +{ + return "_InitialWorD_\0".as_ptr() as *const c_char; +} + +unsafe fn RL_ISSTATE(x:c_ulong)->c_ulong +{ + return rl_readline_state & x; +} + +#[no_mangle] +pub extern "C" fn r_find_compact (name:* mut c_char)->i32 +{ + let mut i:i32=0; + unsafe { + let compacts:CompactsArray=CompactsArray::new(); + while compacts.compactsArr[i as usize].actname != std::ptr::null_mut() { + if STREQ (name, compacts.compactsArr[i as usize].actname) { + return i; + } + i+=1; + } + return -1; + } +} + +#[no_mangle] +pub extern "C" fn r_find_compopt (name:* mut c_char)->i32 +{ + let mut i:i32=0; + let compopts:CompoptArray=CompoptArray::new(); + unsafe { + while compopts.compoptArr[i as usize].optname != std::ptr::null_mut() { + if STREQ (name, compopts.compoptArr[i as usize].optname) { + return i; + } + i+=1; + } + return -1; + } +} + +#[no_mangle] +pub extern "C" fn r_build_actions (list : *mut WORD_LIST, flagp:* mut _optflags, actp:* mut c_ulong, optp:* mut c_ulong)->i32 +{ + let mut opt:i32; + let mut ind:i32; + let mut opt_given:i32=0; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut w:WORD_DESC=WORD_DESC{word:std::ptr::null_mut(),flags:0}; + + unsafe { + reset_internal_getopt (); + opt = internal_getopt(list, CString::new("abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI").unwrap().as_ptr() as * mut c_char); + while opt != -1 { + opt_given = 1; + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'r'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).rflag = 1; + } else { + sh_invalidopt (CString::new("-r").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'p'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).pflag = 1; + } else { + sh_invalidopt (CString::new("-p").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'a'=>{ + acts |= CA_ALIAS!(); + } + 'b'=>{ + acts |= CA_BUILTIN!(); + } + 'c'=>{ + acts |= CA_COMMAND!(); + } + 'd'=>{ + acts |= CA_DIRECTORY!(); + } + 'e'=>{ + acts |= CA_EXPORT!(); + } + 'f'=>{ + acts |= CA_FILE!(); + } + 'g'=>{ + acts |= CA_GROUP!(); + } + 'j'=>{ + acts |= CA_GROUP!(); + } + 'k'=>{ + acts |= CA_KEYWORD!(); + } + 's'=>{ + acts |= CA_SERVICE!(); + } + 'u'=>{ + acts |= CA_USER!(); + } + 'v'=>{ + acts |= CA_VARIABLE!(); + } + 'o'=>{ + ind = r_find_compopt (list_optarg); + if ind < 0 { + sh_invalidoptname (list_optarg); + return EX_USAGE!(); + } + let compopts:CompoptArray=CompoptArray::new(); + copts |= compopts.compoptArr[ind as usize].optflag; + } + 'A'=>{ + ind = r_find_compact (list_optarg); + if ind < 0 { + builtin_error (CString::new("%s: invalid action name").unwrap().as_ptr(), list_optarg); + return EX_USAGE!(); + } + let compacts:CompactsArray=CompactsArray::new(); + acts |= compacts.compactsArr[ind as usize].actflag; + } + 'C'=>{ + Carg = list_optarg; + } + 'D'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Dflag = 1; + } else { + sh_invalidopt (CString::new("-D").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'E'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Eflag = 1; + } else { + sh_invalidopt (CString::new("-E").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'I'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Iflag = 1; + } else { + sh_invalidopt (CString::new("-I").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'F'=>{ + w.word = list_optarg; + Farg = list_optarg; + w.flags = 0; + if check_identifier (&mut w, posixly_correct) == 0 || libc::strpbrk (Farg, shell_break_chars()) != std::ptr::null_mut() { + sh_invalidid (Farg); + return EX_USAGE!(); + } + } + 'G'=>{ + Garg = list_optarg; + } + 'P'=>{ + Parg = list_optarg; + } + 'S'=>{ + Sarg = list_optarg; + } + 'W'=>{ + Warg = list_optarg; + } + 'X'=>{ + Xarg = list_optarg; + } + 'X'=>{ + Xarg = list_optarg; + } + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt=internal_getopt(list, CString::new("abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI").unwrap().as_ptr() as * mut c_char); + } + *actp = acts; + *optp = copts; + if opt_given !=0 { + return EXECUTION_SUCCESS!(); + } else { + return EXECUTION_FAILURE!(); + } + } +} + +/* Add, remove, and display completion specifiers. */ +#[no_mangle] +pub extern "C" fn r_complete_builtin (listt: *mut WORD_LIST)->i32 +{ + let mut opt_given:i32=0; + let mut rval:i32; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut cs:* mut COMPSPEC; + let mut oflags:_optflags=_optflags{pflag:0,rflag:0,Dflag:0,Eflag:0,Iflag:0}; + let mut l: *mut WORD_LIST; + let mut wl: *mut WORD_LIST; + + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + if list == std::ptr::null_mut() { + r_print_all_completions (); + return EXECUTION_SUCCESS!(); + } + + oflags.pflag=0; + oflags.rflag=0; + oflags.Dflag=0; + oflags.Eflag=0; + oflags.Iflag=0; + + Garg=std::ptr::null_mut(); + Warg=std::ptr::null_mut(); + Parg=std::ptr::null_mut(); + Sarg=std::ptr::null_mut(); + Xarg=std::ptr::null_mut(); + Farg=std::ptr::null_mut(); + Carg=std::ptr::null_mut(); + + cs=std::ptr::null_mut(); + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = r_build_actions (list, &mut oflags, &mut acts, &mut copts); + if rval == EX_USAGE!() { + return rval; + } + + opt_given = (rval != EXECUTION_FAILURE!()) as i32; + + list = loptend.clone(); + + if oflags.Dflag !=0 { + wl = make_word_list (make_bare_word (DEFAULTCMD()), std::ptr::null_mut()); + } else if oflags.Eflag !=0 { + wl = make_word_list (make_bare_word (EMPTYCMD()), std::ptr::null_mut()); + } else if oflags.Iflag !=0 { + wl = make_word_list (make_bare_word (INITIALWORD()), std::ptr::null_mut()); + } else { + wl = std::ptr::null_mut(); + } + + /* -p overrides everything else */ + if oflags.pflag !=0 || (list == std::ptr::null_mut() && opt_given == 0) { + if wl != std::ptr::null_mut() { + rval = r_print_cmd_completions (wl); + dispose_words (wl); + return rval; + } else if list == std::ptr::null_mut() { + r_print_all_completions (); + return EXECUTION_SUCCESS!(); + } + return r_print_cmd_completions (list); + } + + /* next, -r overrides everything else. */ + if oflags.rflag !=0 { + if wl != std::ptr::null_mut() { + rval = r_remove_cmd_completions (wl); + dispose_words (wl); + return rval; + } else if list == std::ptr::null_mut() { + progcomp_flush (); + return EXECUTION_SUCCESS!(); + } + return r_remove_cmd_completions (list); + } + + if wl == std::ptr::null_mut() && list == std::ptr::null_mut() && opt_given !=0 { + builtin_usage (); + return EX_USAGE!(); + } + + /* If we get here, we need to build a compspec and add it for each + remaining argument. */ + cs = compspec_create (); + (*cs).actions = acts; + (*cs).options = copts; + + (*cs).globpat = STRDUP (Garg); + (*cs).words = STRDUP (Warg); + (*cs).prefix = STRDUP (Parg); + (*cs).suffix = STRDUP (Sarg); + (*cs).funcname = STRDUP (Farg); + (*cs).command = STRDUP (Carg); + (*cs).filterpat = STRDUP (Xarg); + + rval = EXECUTION_SUCCESS!(); + + if wl != std::ptr::null_mut() { + l= wl.clone(); + } else { + l= list.clone(); + } + + while l != std::ptr::null_mut() { + /* Add CS as the compspec for the specified commands. */ + if progcomp_insert ((*(*l).word).word, cs) == 0 { + rval = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + + dispose_words (wl); + return rval; + } +} + +#[no_mangle] +pub extern "C" fn r_remove_cmd_completions (list: * mut WORD_LIST)->i32 +{ + let mut l:* mut WORD_LIST; + let mut ret:i32; + unsafe { + ret = EXECUTION_SUCCESS!(); + l = list.clone(); + while l!=std::ptr::null_mut() { + if progcomp_remove ((*(*l).word).word) == 0 { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(), (*(*l).word).word); + ret = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + return ret; + } +} + +#[no_mangle] +pub extern "C" fn r_print_compoptions (copts:c_ulong, full:i32) +{ + unsafe { + let compopts:CompoptArray=CompoptArray::new(); + for i in 0..compopts.compoptArr.len() { + if (copts & compopts.compoptArr[i].optflag) !=0 { + libc::printf (CString::new("-o %s ").unwrap().as_ptr(), compopts.compoptArr[i].optname); + } else if full !=0 { + libc::printf (CString::new("+o %s ").unwrap().as_ptr(), compopts.compoptArr[i].optname); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_compactions (acts:c_ulong) +{ + unsafe { + let compacts:CompactsArray=CompactsArray::new(); + for i in 0..compacts.compactsArr.len() { + if compacts.compactsArr[i].actopt !=0 && (acts & compacts.compactsArr[i].actflag) !=0 { + libc::printf (CString::new("-%c ").unwrap().as_ptr(), compacts.compactsArr[i].actopt); + } + } + + for i in 0..compacts.compactsArr.len() { + if compacts.compactsArr[i].actopt ==0 && (acts & compacts.compactsArr[i].actflag) !=0 { + libc::printf (CString::new("-A %s ").unwrap().as_ptr(), compacts.compactsArr[i].actname); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_arg (arg:* const c_char, flag:* const c_char, quote:i32) +{ + let x:* mut c_char; + unsafe { + if arg != std::ptr::null_mut() { + if quote !=0 { + x = sh_single_quote (arg as * mut c_char); + } else { + x= arg as * mut c_char; + } + libc::printf (CString::new("%s %s ").unwrap().as_ptr(), flag, x); + if x != arg as * mut c_char { + libc::free (x as * mut c_void); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_cmd_name (cmd:* const c_char) +{ + unsafe { + if STREQ (cmd, DEFAULTCMD()) { + libc::printf (CString::new("-D").unwrap().as_ptr()); + } else if STREQ (cmd, EMPTYCMD()) { + libc::printf (CString::new("-E").unwrap().as_ptr()); + } else if STREQ (cmd, INITIALWORD()) { + libc::printf (CString::new("-I").unwrap().as_ptr()); + } else if *cmd == 0 { /* XXX - can this happen? */ + libc::printf (CString::new("''").unwrap().as_ptr()); + } else { + libc::printf (CString::new("%s").unwrap().as_ptr(),cmd); + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_one_completion (cmd: * mut c_char, cs:* mut COMPSPEC)->i32 +{ + unsafe { + libc::printf (CString::new("complete ").unwrap().as_ptr()); + + r_print_compoptions ((*cs).options, 0); + r_print_compactions ((*cs).actions); + + /* now the rest of the arguments */ + + /* arguments that require quoting */ + r_print_arg ((*cs).globpat, CString::new("-G").unwrap().as_ptr(), 1); + r_print_arg ((*cs).words, CString::new("-W").unwrap().as_ptr(), 1); + r_print_arg ((*cs).prefix, CString::new("-P").unwrap().as_ptr(), 1); + r_print_arg ((*cs).suffix, CString::new("-S").unwrap().as_ptr(), 1); + r_print_arg ((*cs).filterpat, CString::new("-X").unwrap().as_ptr(), 1); + + r_print_arg ((*cs).command, CString::new("-C").unwrap().as_ptr(), 1); + + /* simple arguments that don't require quoting */ + r_print_arg ((*cs).funcname, CString::new("-F").unwrap().as_ptr(), 0); + + r_print_cmd_name (cmd); + libc::printf (CString::new("\n").unwrap().as_ptr()); + + return 0; + } +} + +#[no_mangle] +pub extern "C" fn r_print_compopts (cmd:* mut c_char, cs:* mut COMPSPEC, full:i32) +{ + unsafe { + libc::printf (CString::new("compopt ").unwrap().as_ptr()); + + r_print_compoptions ((*cs).options, full); + r_print_cmd_name (cmd); + + libc::printf (CString::new("\n").unwrap().as_ptr()); + } +} + +#[no_mangle] +pub extern "C" fn r_print_compitem (item:* mut BUCKET_CONTENTS)->i32 +{ + let cs:* mut COMPSPEC; + let cmd:* mut c_char; + unsafe { + cmd = (*item).key; + cs = (*item).data as * mut COMPSPEC; + } + + return r_print_one_completion (cmd, cs); +} + +#[no_mangle] +pub extern "C" fn r_print_all_completions () +{ + unsafe { + progcomp_walk (r_print_compitem); + } +} + +#[no_mangle] +pub extern "C" fn r_print_cmd_completions (list:* mut WORD_LIST)->i32 +{ + let mut l:* mut WORD_LIST; + let mut cs:* mut COMPSPEC; + let mut ret:i32; + + unsafe { + ret = EXECUTION_SUCCESS!(); + l = list.clone(); + while l != std::ptr::null_mut() { + cs = progcomp_search ((*(*l).word).word); + if cs != std::ptr::null_mut() { + r_print_one_completion ((*(*l).word).word, cs); + } else { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(),(*(*l).word).word); + ret = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + return sh_chkwrite (ret); + } +} + +#[no_mangle] +pub extern "C" fn r_compgen_builtin (listt:* mut WORD_LIST)->i32 +{ + let mut rval:i32; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut cs: * mut COMPSPEC; + let mut sl:* mut STRINGLIST; + let word:* mut c_char; + let mut matches:* mut * mut c_char; + let old_line:* mut c_char; + let old_ind:i32; + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + if list == std::ptr::null_mut() { + return EXECUTION_SUCCESS!(); + } + + Garg=std::ptr::null_mut(); + Warg=std::ptr::null_mut(); + Parg=std::ptr::null_mut(); + Sarg=std::ptr::null_mut(); + Xarg=std::ptr::null_mut(); + Farg=std::ptr::null_mut(); + Carg=std::ptr::null_mut(); + + cs = std::ptr::null_mut(); + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = r_build_actions (list, std::ptr::null_mut(), &mut acts, &mut copts); + if rval == EX_USAGE!() { + return rval; + } + + if rval == EXECUTION_FAILURE!() { + return EXECUTION_SUCCESS!(); + } + + list = loptend.clone(); + + if list !=std::ptr::null_mut() && (*list).word != std::ptr::null_mut() { + word = (*((*list).word)).word; + } else { + word=CString::new("").unwrap().as_ptr() as * mut c_char; + } + + if Farg != std::ptr::null_mut() { + builtin_error (CString::new("warning: -F option may not work as you expect").unwrap().as_ptr()); + } + + if Carg != std::ptr::null_mut() { + builtin_error (CString::new("warning: -C option may not work as you expect").unwrap().as_ptr()); + } + + /* If we get here, we need to build a compspec and evaluate it. */ + cs = compspec_create (); + (*cs).actions = acts; + (*cs).options = copts; + (*cs).refcount = 1; + + (*cs).globpat = STRDUP (Garg); + (*cs).words = STRDUP (Warg); + (*cs).prefix = STRDUP (Parg); + (*cs).suffix = STRDUP (Sarg); + (*cs).funcname = STRDUP (Farg); + (*cs).command = STRDUP (Carg); + (*cs).filterpat = STRDUP (Xarg); + + rval = EXECUTION_FAILURE!(); + + /* probably don't have to save these, just being safe */ + old_line = pcomp_line; + old_ind = pcomp_ind; + pcomp_line = std::ptr::null_mut(); + pcomp_ind = 0; + sl = gen_compspec_completions (cs, CString::new("compgen").unwrap().as_ptr(), word, 0, 0, std::ptr::null_mut()); + pcomp_line = old_line; + pcomp_ind = old_ind; + + /* If the compspec wants the bash default completions, temporarily + turn off programmable completion and call the bash completion code. */ + if (sl == std::ptr::null_mut() || (*sl).list_len == 0) && (copts & COPT_BASHDEFAULT!()) !=0 { + matches = bash_default_completion (word, 0, 0, 0, 0); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + /* This isn't perfect, but it's the best we can do, given what readline + exports from its set of completion utility functions. */ + if (sl == std::ptr::null_mut() || (*sl).list_len == 0) && (copts & COPT_DEFAULT!()) !=0 { + matches = rl_completion_matches (word, rl_filename_completion_function); + strlist_dispose (sl); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + if sl != std::ptr::null_mut() { + if (*sl).list != std::ptr::null_mut() && (*sl).list_len !=0 { + rval = EXECUTION_SUCCESS!(); + strlist_print (sl, std::ptr::null_mut()); + } + strlist_dispose (sl); + } + + compspec_dispose (cs); + return rval; + } +} + +#[no_mangle] +pub extern "C" fn r_compopt_builtin (listt:* mut WORD_LIST)->i32 +{ + let mut opts_on:i32=0; + let mut opts_off:i32=0; + let mut opts:* mut i32; + let mut opt:i32; + let mut oind:i32; + let mut ret:i32; + let mut Dflag:i32=0; + let mut Eflag:i32=0; + let mut Iflag:i32=0; + let mut l:* mut WORD_LIST; + let mut wl:* mut WORD_LIST; + let mut cs:* mut COMPSPEC; + + ret = EXECUTION_SUCCESS!(); + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + reset_internal_getopt (); + + opt = internal_getopt (list, CString::new("+o:DEI").unwrap().as_ptr() as * mut c_char); + + while opt != -1 { + if list_opttype == '-' as i32 { + opts = &mut opts_on; + } else { + opts = &mut opts_off; + } + + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + + match optChar { + 'o'=>{ + oind = r_find_compopt (list_optarg); + if oind < 0 { + sh_invalidoptname (list_optarg); + return EX_USAGE!(); + } + let compopts:CompoptArray=CompoptArray::new(); + *opts |= compopts.compoptArr[oind as usize].optflag as i32; + } + 'D'=>{ + Dflag = 1; + } + 'E'=>{ + Eflag = 1; + } + 'I'=>{ + Iflag = 1; + } + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt = internal_getopt (list, CString::new("+o:DEI").unwrap().as_ptr() as * mut c_char); + } + + list = loptend.clone(); + + if Dflag != 0 { + wl = make_word_list (make_bare_word (DEFAULTCMD()), std::ptr::null_mut()); + } else if Eflag !=0 { + wl = make_word_list (make_bare_word (EMPTYCMD()), std::ptr::null_mut()); + } else if Iflag !=0 { + wl = make_word_list (make_bare_word (INITIALWORD()), std::ptr::null_mut()); + } else { + wl = std::ptr::null_mut(); + } + + if list == std::ptr::null_mut() && wl == std::ptr::null_mut() { + if RL_ISSTATE (RL_STATE_COMPLETING!()) == 0 || pcomp_curcs == std::ptr::null_mut() { + builtin_error (CString::new("not currently executing completion function").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + cs = pcomp_curcs.clone(); + + if opts_on == 0 && opts_off == 0 { + r_print_compopts (pcomp_curcmd, cs, 1); + return sh_chkwrite (ret); + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + + /* And change the readline variables the options control */ + pcomp_set_readline_variables (opts_on, 1); + pcomp_set_readline_variables (opts_off, 0); + + return ret; + } + + if wl != std::ptr::null_mut() { + l = wl.clone(); + } else { + l=list.clone(); + } + + while l != std::ptr::null_mut() { + cs = progcomp_search ((*((*list).word)).word); + if cs == std::ptr::null_mut() { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(), (*((*list).word)).word); + ret = EXECUTION_FAILURE!(); + continue; + } + if opts_on == 0 && opts_off == 0 { + r_print_compopts ((*((*list).word)).word, cs, 1); + continue; /* XXX -- fill in later */ + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + l = (*l).next; + } + + if wl != std::ptr::null_mut() { + dispose_words (wl); + } + + return ret; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"complete" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_complete_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/mapfile/Cargo.toml b/bash-5.1/builtins_rust/mapfile/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..133475e88a5bc5d5ca28b844a3c1fb875c11b46d 100644 --- a/bash-5.1/builtins_rust/mapfile/Cargo.toml +++ b/bash-5.1/builtins_rust/mapfile/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mapfile" +version = "0.1.0" +edition = "2021" +authors = ["lvgenggeng"] +build = "../build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "rmapfile" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/mapfile/src/intercdep.rs b/bash-5.1/builtins_rust/mapfile/src/intercdep.rs new file mode 100644 index 0000000000000000000000000000000000000000..f4de2e9c91124fd305a5547ddcaa3c7adbd0e02e --- /dev/null +++ b/bash-5.1/builtins_rust/mapfile/src/intercdep.rs @@ -0,0 +1,114 @@ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct word_desc { + pub word: *mut c_char, + pub flags: c_int, +} +pub type WORD_DESC = word_desc; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct word_list { + pub next: *mut word_list, + pub word: *mut WORD_DESC, +} +pub type WORD_LIST = word_list; + +pub type arrayind_t = c_long; + +pub type sh_var_value_func_t = + ::std::option::Option *mut variable>; + + pub type sh_var_assign_func_t = ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut variable, + arg2: *mut c_char, + arg3: arrayind_t, + arg4: *mut c_char, + ) -> *mut variable, +>; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct variable { + pub name: *mut c_char, + pub value: *mut c_char, + pub exportstr: *mut c_char, + pub dynamic_value: sh_var_value_func_t, + pub assign_func: sh_var_assign_func_t, + pub attributes: c_int, + pub context: c_int, +} +pub type SHELL_VAR = variable; + +pub const atype_array_indexed: atype = 0; +pub const atype_array_assoc: atype = 1; +pub type atype = c_uint; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct array { + pub type_: atype, + pub max_index: arrayind_t, + pub num_elements: c_int, + pub head: *mut array_element, + pub lastref: *mut array_element, +} +pub type ARRAY = array; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct array_element { + pub ind: arrayind_t, + pub value: *mut c_char, + pub next: *mut array_element, + pub prev: *mut array_element, +} +pub type ARRAY_ELEMENT = array_element; + +pub const ESPIPE: c_int = 29; +pub const SEEK_CUR: c_int = 1; + +pub const EXECUTION_SUCCESS : c_int = 0; +pub const EXECUTION_FAILURE : c_int = 1; +pub const EX_USAGE: c_int = 258; + +pub const SEVAL_NOHIST: c_int = 0x004; + +pub const att_readonly: c_int = 0x0000002; +pub const att_array: c_int = 0x0000004; +pub const att_invisible: c_int = 0x0001000; +pub const att_noassign: c_int = 0x0004000; + +extern "C" { + pub fn reset_internal_getopt(); + pub fn internal_getopt(list: *mut WORD_LIST, opts: *mut c_char) -> c_int; + pub fn builtin_usage(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn legal_identifier(arg1: *const c_char) -> c_int; + pub fn legal_number (str1:*const c_char,result:* mut c_long) -> i32; + pub fn sh_invalidid(arg1: *mut c_char); + pub fn sh_validfd(arg1: c_int) -> c_int; + + pub fn sh_single_quote(s: *mut c_char) -> *mut c_char; + + pub fn evalstring(string: *mut c_char, from_file: *const c_char, flags: c_int) -> c_int; + + pub fn find_or_make_array_variable(name: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + + pub fn bind_array_element(entry: *mut SHELL_VAR, ind: c_long, value: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + + pub fn array_flush(a: *mut ARRAY); + + pub fn err_readonly(s: *const c_char) -> c_void; + + pub fn zreset() -> c_void; + pub fn zsyncfd(fd: c_int) -> c_void; + pub fn zgetline (fd: c_int, lineptr: *mut *mut c_char, n: *mut size_t, delim: c_int, unbuffered_read: c_int) -> ssize_t; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + +} diff --git a/bash-5.1/builtins_rust/mapfile/src/lib.rs b/bash-5.1/builtins_rust/mapfile/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b5f8ba8471085ecc0a0982c81c3aa51de2c6396f 100644 --- a/bash-5.1/builtins_rust/mapfile/src/lib.rs +++ b/bash-5.1/builtins_rust/mapfile/src/lib.rs @@ -0,0 +1,220 @@ +use std::{ffi::CString}; + +use libc::{size_t, ssize_t, c_int, c_uint, c_char, c_uchar, c_long, c_void, PT_NULL}; + +include!(concat!("intercdep.rs")); + +pub const DEFAULT_QUANTUM: c_long = 5000; +pub const MAPF_CLEARARRAY: c_int = 0x01; +pub const MAPF_CHOP: c_int = 0x02; + +static mut delim: c_int = 0; + +#[no_mangle] +pub extern "C" fn r_mapfile_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_mapfile_builtin call"); + + let mut opt: c_int; + let mut code: c_int; + let mut fd: c_int = 0; + let mut flags: c_int = MAPF_CLEARARRAY; + let intval: c_long = 0; + let mut lines: c_long = 0; + let mut origin: c_long = 0; + let mut nskip: c_long = 0; + let mut callback_quantum: c_long = DEFAULT_QUANTUM; + + let array_name: *mut c_char; + let mut callback: *mut c_char = PT_NULL as *mut c_char; + +unsafe { + + delim = b'\n' as c_int; + + reset_internal_getopt(); + let opt_str = CString::new("d:u:n:O:tC:c:s:").unwrap(); + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + while opt != -1 { + let opt_char:char=char::from(opt as u8); + match opt_char { + 'd' => delim = *list_optarg as c_int, + 'u' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_int) as c_long{ + builtin_error("%s: invalid file descriptor specification\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + fd = intval as c_int; + } + if sh_validfd(fd) == 0 { + builtin_error("%d: invalid file descriptor: %s\0".as_ptr() as *const c_char, + fd, libc::strerror(*libc::__errno_location())); + return EXECUTION_FAILURE; + } + } + 'n' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid line count\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + lines = intval; + } + } + 'O' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid array origin\0".as_ptr() as *const c_char, + list_optarg); + return EXECUTION_FAILURE; + } else { + origin = intval; + } + flags &= (MAPF_CLEARARRAY as c_uint ^ 0xffffffff) as c_int; + } + 't' => flags |= MAPF_CHOP, + 'C' => callback = list_optarg, + 'c' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid callback quantum\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + callback_quantum = intval; + } + } + 's' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid line count\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + nskip = intval; + } + } + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + } + list = loptend; + + if list.is_null() { + array_name = "MAPFILE".as_ptr() as *mut c_char; + } else if (*list).word.is_null() || (*(*list).word).word.is_null() { + builtin_error("internal error: getting variable name\0".as_ptr() as *const c_char); + return EXECUTION_FAILURE; + } else if *(*(*list).word).word == b'\0' as c_char { + builtin_error("empty array variable name\0".as_ptr() as *const c_char); + return EX_USAGE; + } else { + array_name = (*(*list).word).word; + } + if legal_identifier(array_name) == 0 { + sh_invalidid(array_name); + return EXECUTION_FAILURE; + } + + return mapfile(fd, lines, origin, nskip, callback_quantum, callback, + array_name, delim, flags); +} +} + +unsafe fn run_callback(callback: *const c_char, curindex: c_uint, curline: *mut c_char) -> c_int +{ + let qline = sh_single_quote(curline); + let execlen = libc::strlen(callback) + libc::strlen(qline) + 10 + 3; + let execstr = libc::malloc(execlen); + + let flags = SEVAL_NOHIST; + + libc::snprintf(execstr as *mut c_char, execlen, "%s %d %s\0".as_ptr() as *const c_char, + callback, curindex, qline); + libc::free(qline as *mut c_void); + return evalstring(execstr as *mut c_char, PT_NULL as *const c_char, flags); +} + +unsafe fn do_chop(line: *mut c_char, d: c_uchar) +{ + let length = libc::strlen(line); + if length != 0 && *((line as usize + length - 1) as *mut c_char) == d as c_char { + *((line as usize + length - 1) as *mut c_char) = b'\0' as c_char; + } +} + +unsafe fn mapfile(fd: c_int, line_count_goal: c_long, origin: c_long, nskip: c_long, callback_quantum: c_long, + callback: *mut c_char, array_name: *mut c_char, dlm: c_int, flags: c_int) -> c_int +{ + let mut line: *mut c_char = PT_NULL as *mut c_char; + let mut line_length: size_t = 0; + let mut unbuffered_read: c_int; + + let entry = find_or_make_array_variable(array_name, 1); + if entry.is_null() || ((*entry).attributes & att_readonly) != 0 || ((*entry).attributes & att_noassign) != 0 { + if !entry.is_null() && ((*entry).attributes & att_readonly) != 0 { + err_readonly(array_name); + } + + return EXECUTION_FAILURE; + } else if ((*entry).attributes & att_array) == 0 { + builtin_error("%s: not an indexed array\0".as_ptr() as *const c_char, array_name); + return EXECUTION_FAILURE; + } else if ((*entry).attributes & att_array) != 0 { + (*entry).attributes &= (att_invisible as c_uint ^ 0xffffffff) as c_int; + } + + if (flags & MAPF_CLEARARRAY) != 0 { + array_flush(std::mem::transmute((*entry).value)); + } + unbuffered_read = ((libc::lseek(fd, 0, SEEK_CUR) < 0) && (*libc::__errno_location() == ESPIPE)) as c_int; + + if dlm != b'\n' as c_int { + unbuffered_read = 1; + } + zreset(); + + let mut line_count: c_uint = 0; + while (line_count as c_long) < nskip { + if zgetline(fd, std::mem::transmute(&line), std::mem::transmute(&line_length), dlm, unbuffered_read) < 0 { + break; + } + line_count += 1; + } + + line = PT_NULL as *mut c_char; + line_length = 0; + let mut array_index: c_uint = origin as c_uint; + line_count = 1; + while zgetline(fd, std::mem::transmute(&line), std::mem::transmute(&line_length), dlm, unbuffered_read) != -1 { + if (flags & MAPF_CHOP) != 0 { + do_chop(line, dlm as c_uchar); + } + + if !callback.is_null() && line_count != 0 && (line_count as c_long % callback_quantum) == 0 { + run_callback(callback, array_index, line); + + if unbuffered_read == 0 { + zsyncfd(fd); + } + } + + bind_array_element(entry, array_index as c_long, line, 0); + + line_count += 1; + if line_count_goal != 0 && (line_count as c_long) > line_count_goal { + break; + } + + array_index += 1; + } + + libc::free(line as *mut c_void); + + if unbuffered_read == 0 { + zsyncfd(fd); + } + + return EXECUTION_SUCCESS; +} diff --git a/record.txt b/record.txt index 622d73b55363069f0b9cf6028ca6f73447e003da..59f0abdbc5604f69d64bb26a3fc07f45889344ad 100644 --- a/record.txt +++ b/record.txt @@ -1,4 +1,4 @@ 20 21 22 -23 +24