diff --git a/bash-5.1/Cargo.toml b/bash-5.1/Cargo.toml index 87ccd3a0269ba34196c9eb01287cb92d0d552724..c97a043982fb4940ac83d2b873095cb9395ff920 100644 --- a/bash-5.1/Cargo.toml +++ b/bash-5.1/Cargo.toml @@ -1,104 +1,19 @@ [package] name = "rsbash" version = "0.1.0" -edition = "2018" - +edition = "2021" [lib] name = "rsbash" crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace] - -members=[ - "builtins_rust/jobs", - "builtins_rust/fg_bg", - "builtins_rust/fc", - "builtins_rust/getopts", - "builtins_rust/read", - "builtins_rust/cd", - "builtins_rust/pushd", - "builtins_rust/rlet", - "builtins_rust/mapfile", - "builtins_rust/help", - "builtins_rust/exit", - "builtins_rust/history", - "builtins_rust/kill", - "builtins_rust/builtin", - "builtins_rust/colon", - "builtins_rust/echo", - "builtins_rust/complete", - "builtins_rust/shopt", - "builtins_rust/alias", - "builtins_rust/caller", - "builtins_rust/eval", - "builtins_rust/exec", - "builtins_rust/common", - "builtins_rust/cmd", - "builtins_rust/enable", - "builtins_rust/declare", - "builtins_rust/command", - "builtins_rust/hash", - "builtins_rust/break_1", - "builtins_rust/type", - "builtins_rust/ulimit", - "builtins_rust/set", - "builtins_rust/bind", - "builtins_rust/echo", - "builtins_rust/hash", - "builtins_rust/umask", - "builtins_rust/wait", - "builtins_rust/suspend", - "builtins_rust/kill", - "builtins_rust/history", - "builtins_rust/mapfile", - "builtins_rust/printf", - "builtins_rust/rlet", - "builtins_rust/rreturn", - "builtins_rust/shift", - "builtins_rust/test", - "builtins_rust/times", - "builtins_rust/trap", - "builtins_rust/setattr", - "builtins_rust/source", - "builtins_rust/exec_cmd", -] +members = ["builtins_rust/read", "builtins/command1", "builtins/command2", "builtins_rust/history", "builtins_rust/kill"] [dependencies] - libc = "*" - rread = {path = "./builtins_rust/read"} - rhistory = {path = "./builtins_rust/history"} - rkill = {path = "./builtins_rust/kill"} - rlet = {path = "./builtins_rust/rlet"} - rsource = {path = "./builtins_rust/source"} - rmapfile = {path = "./builtins_rust/mapfile"} - rprintf = {path = "./builtins_rust/printf"} - rreturn = {path = "./builtins_rust/rreturn"} - rshift = {path = "./builtins_rust/shift"} - rtimes = {path = "./builtins_rust/times"} - rsuspend = {path = "./builtins_rust/suspend"} - rtest = {path = "./builtins_rust/test"} - rtrap = {path = "./builtins_rust/trap"} - rsetattr = {path = "./builtins_rust/setattr"} - rcolon = {path = "./builtins_rust/colon"} - rbuiltin = {path = "./builtins_rust/builtin"} - ralias= {path = "./builtins_rust/alias"} - rexit = {path = "./builtins_rust/exit"} - rhelp = {path = "./builtins_rust/help"} - rcaller = {path = "./builtins_rust/caller"} - reval = {path = "./builtins_rust/eval"} - rexec = {path = "./builtins_rust/exec"} - rcommon = {path = "./builtins_rust/common"} - rcmd = {path = "builtins_rust/cmd"} - renable = {path = "builtins_rust/enable"} - rbreak = {path = "builtins_rust/break_1"} - rulimit = {path = "builtins_rust/ulimit"} - rtype = {path = "builtins_rust/type"} - rset = {path = "builtins_rust/set"} - rbind = {path = "./builtins_rust/bind"} - recho = {path = "./builtins_rust/echo"} - rhash = {path = "./builtins_rust/hash"} - rumask = {path = "./builtins_rust/umask"} - rwait = {path = "./builtins_rust/wait"} - rdeclare = {path = "./builtins_rust/declare"} - rexec_cmd = {path = "./builtins_rust/exec_cmd"} +libc = "0.2" +command1 = {path = "./builtins/command1"} +command2 = {path = "./builtins/command2"} +read = {path = "./builtins_rust/read"} +history = {path = "./builtins_rust/history"} +kill = {path = "./builtins_rust/kill"} diff --git a/bash-5.1/builtins_rust/build.rs b/bash-5.1/builtins_rust/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..5b5544932086123d93bad082cc9783b5d85fd090 --- /dev/null +++ b/bash-5.1/builtins_rust/build.rs @@ -0,0 +1,183 @@ + + + use std::{env}; + + fn main() { + + let library_dir = "/opt/rsbash/builtins"; + + println!("cargo:rustc-link-search=native={}", env::join_paths(&[library_dir]).unwrap().to_str().unwrap()); + + println!("cargo:rustc-flags=-l dylib=jobs"); + println!("cargo:rustc-flags=-l dylib=trap"); + println!("cargo:rustc-flags=-l dylib=execute_cmd"); + println!("cargo:rustc-flags=-l dylib=unwind_prot"); + println!("cargo:rustc-flags=-l dylib=flags"); + println!("cargo:rustc-flags=-l dylib=variables"); + println!("cargo:rustc-flags=-l dylib=builtins_break"); + println!("cargo:rustc-flags=-l dylib=builtins_common"); + println!("cargo:rustc-flags=-l dylib=sig"); + println!("cargo:rustc-flags=-l dylib=builtins_wait"); + println!("cargo:rustc-flags=-l dylib=shell"); + println!("cargo:rustc-flags=-l dylib=input"); + println!("cargo:rustc-flags=-l dylib=xmalloc"); + println!("cargo:rustc-flags=-l dylib=version"); + println!("cargo:rustc-flags=-l dylib=error"); + println!("cargo:rustc-flags=-l dylib=subst"); + println!("cargo:rustc-flags=-l dylib=lib_sh_winsize"); + println!("cargo:rustc-flags=-l dylib=dispose_cmd"); + println!("cargo:rustc-flags=-l dylib=lib_readline_readline"); + println!("cargo:rustc-flags=-l dylib=general"); + println!("cargo:rustc-flags=-l dylib=lib_sh_oslib"); + println!("cargo:rustc-flags=-l dylib=list"); + println!("cargo:rustc-flags=-l dylib=builtins_evalstring"); + println!("cargo:rustc-flags=-l dylib=y.tab"); + println!("cargo:rustc-flags=-l dylib=builtins_evalfile"); + println!("cargo:rustc-flags=-l dylib=lib_sh_casemod"); + println!("cargo:rustc-flags=-l dylib=lib_sh_fmtulong"); + println!("cargo:rustc-flags=-l dylib=builtins_set"); + println!("cargo:rustc-flags=-l dylib=lib_readline_history"); + println!("cargo:rustc-flags=-l dylib=mailcheck"); + println!("cargo:rustc-flags=-l dylib=bashhist"); + println!("cargo:rustc-flags=-l dylib=bashline"); + println!("cargo:rustc-flags=-l dylib=assoc"); + println!("cargo:rustc-flags=-l dylib=builtins_shopt"); + println!("cargo:rustc-flags=-l dylib=lib_readline_histfile"); + println!("cargo:rustc-flags=-l dylib=hashlib"); + println!("cargo:rustc-flags=-l dylib=print_cmd"); + println!("cargo:rustc-flags=-l dylib=copy_cmd"); + println!("cargo:rustc-flags=-l dylib=hashcmd"); + println!("cargo:rustc-flags=-l dylib=pathexp"); + println!("cargo:rustc-flags=-l dylib=lib_sh_random"); + println!("cargo:rustc-flags=-l dylib=findcmd"); + println!("cargo:rustc-flags=-l dylib=arrayfunc"); + println!("cargo:rustc-flags=-l dylib=lib_readline_terminal"); + println!("cargo:rustc-flags=-l dylib=array"); + println!("cargo:rustc-flags=-l dylib=lib_readline_complete"); + println!("cargo:rustc-flags=-l dylib=alias"); + println!("cargo:rustc-flags=-l dylib=builtins_getopt"); + println!("cargo:rustc-flags=-l dylib=locale"); + println!("cargo:rustc-flags=-l dylib=lib_readline_shell"); + println!("cargo:rustc-flags=-l dylib=lib_sh_stringvec"); + println!("cargo:rustc-flags=-l dylib=lib_sh_itos"); + println!("cargo:rustc-flags=-l dylib=pcomplete"); + println!("cargo:rustc-flags=-l dylib=lib_sh_strtrans"); + println!("cargo:rustc-flags=-l dylib=lib_readline_histexpand"); + println!("cargo:rustc-flags=-l dylib=lib_sh_shquote"); + println!("cargo:rustc-flags=-l dylib=builtins_pushd"); + println!("cargo:rustc-flags=-l dylib=redir"); + println!("cargo:rustc-flags=-l dylib=lib_sh_pathcanon"); + println!("cargo:rustc-flags=-l dylib=builtins_getopts"); + println!("cargo:rustc-flags=-l dylib=lib_readline_colors"); + println!("cargo:rustc-flags=-l dylib=lib_readline_mbutil"); + println!("cargo:rustc-flags=-l dylib=lib_readline_signals"); + println!("cargo:rustc-flags=-l dylib=lib_readline_text"); + println!("cargo:rustc-flags=-l dylib=lib_readline_parse-colors"); + println!("cargo:rustc-flags=-l dylib=lib_readline_display"); + println!("cargo:rustc-flags=-l dylib=lib_readline_util"); + println!("cargo:rustc-flags=-l dylib=lib_glob_xmbsrtowcs"); + println!("cargo:rustc-flags=-l dylib=lib_glob_gmisc"); + println!("cargo:rustc-flags=-l dylib=lib_sh_shmbchar"); + println!("cargo:rustc-flags=-l dylib=make_cmd"); + println!("cargo:rustc-flags=-l dylib=syntax"); + println!("cargo:rustc-flags=-l dylib=lib_glob_strmatch"); + println!("cargo:rustc-flags=-l dylib=lib_glob_glob"); + println!("cargo:rustc-flags=-l dylib=builtins_declare"); + println!("cargo:rustc-flags=-l dylib=stringlib"); + println!("cargo:rustc-flags=-l dylib=builtins_setattr"); + println!("cargo:rustc-flags=-l dylib=braces"); + println!("cargo:rustc-flags=-l dylib=lib_readline_misc"); + println!("cargo:rustc-flags=-l dylib=lib_readline_rltty"); + println!("cargo:rustc-flags=-l dylib=lib_readline_keymaps"); + println!("cargo:rustc-flags=-l dylib=lib_readline_kill"); + println!("cargo:rustc-flags=-l dylib=lib_readline_input"); + println!("cargo:rustc-flags=-l dylib=lib_readline_vi_mode"); + println!("cargo:rustc-flags=-l dylib=lib_readline_macro"); + println!("cargo:rustc-flags=-l dylib=lib_readline_bind"); + println!("cargo:rustc-flags=-l dylib=lib_readline_undo"); + println!("cargo:rustc-flags=-l dylib=lib_readline_funmap"); + println!("cargo:rustc-flags=-l dylib=lib_readline_nls"); + println!("cargo:rustc-flags=-l dylib=builtins_read"); + println!("cargo:rustc-flags=-l dylib=eval"); + println!("cargo:rustc-flags=-l dylib=lib_sh_setlinebuf"); + println!("cargo:rustc-flags=-l dylib=lib_sh_netconn"); + println!("cargo:rustc-flags=-l dylib=lib_sh_input_avail"); + println!("cargo:rustc-flags=-l dylib=lib_sh_shtty"); + println!("cargo:rustc-flags=-l dylib=lib_sh_zread"); + println!("cargo:rustc-flags=-l dylib=lib_sh_ufuncs"); + println!("cargo:rustc-flags=-l dylib=lib_sh_uconvert"); + println!("cargo:rustc-flags=-l dylib=pcomplib"); + println!("cargo:rustc-flags=-l dylib=bracecomp"); + println!("cargo:rustc-flags=-l dylib=lib_sh_spell"); + println!("cargo:rustc-flags=-l dylib=lib_sh_fnxform"); + println!("cargo:rustc-flags=-l dylib=lib_termcap_termcap"); + println!("cargo:rustc-flags=-l dylib=lib_termcap_tparam"); + println!("cargo:rustc-flags=-l dylib=builtins_bashgetopt"); + println!("cargo:rustc-flags=-l dylib=builtins_source"); + println!("cargo:rustc-flags=-l dylib=lib_sh_shmatch"); + println!("cargo:rustc-flags=-l dylib=test"); + println!("cargo:rustc-flags=-l dylib=builtins_return"); + println!("cargo:rustc-flags=-l dylib=builtins_exec"); + println!("cargo:rustc-flags=-l dylib=builtins_command"); + println!("cargo:rustc-flags=-l dylib=lib_sh_mbschr"); + println!("cargo:rustc-flags=-l dylib=expr"); + println!("cargo:rustc-flags=-l dylib=lib_sh_timeval"); + println!("cargo:rustc-flags=-l dylib=lib_sh_fpurge"); + println!("cargo:rustc-flags=-l dylib=builtins_fc"); + println!("cargo:rustc-flags=-l dylib=builtins_mapfile"); + println!("cargo:rustc-flags=-l dylib=builtins_eval"); + println!("cargo:rustc-flags=-l dylib=builtins_jobs"); + println!("cargo:rustc-flags=-l dylib=builtins_cd"); + println!("cargo:rustc-flags=-l dylib=builtins_shopt"); + println!("cargo:rustc-flags=-l dylib=builtins_echo"); + println!("cargo:rustc-flags=-l dylib=lib_glob_smatch"); + println!("cargo:rustc-flags=-l dylib=lib_sh_utf8"); + println!("cargo:rustc-flags=-l dylib=lib_readline_search"); + println!("cargo:rustc-flags=-l dylib=lib_readline_isearch"); + println!("cargo:rustc-flags=-l dylib=lib_sh_stringlist"); + println!("cargo:rustc-flags=-l dylib=builtins_complete"); + println!("cargo:rustc-flags=-l dylib=builtins_exit"); + println!("cargo:rustc-flags=-l dylib=lib_sh_tmpfile"); + println!("cargo:rustc-flags=-l dylib=lib_sh_netopen"); + println!("cargo:rustc-flags=-l dylib=lib_sh_eaccess"); + println!("cargo:rustc-flags=-l dylib=lib_readline_histsearch"); + println!("cargo:rustc-flags=-l dylib=lib_tilde_tilde"); + println!("cargo:rustc-flags=-l dylib=lib_sh_makepath"); + println!("cargo:rustc-flags=-l dylib=builtins_shift"); + println!("cargo:rustc-flags=-l dylib=lib_readline_parens"); + println!("cargo:rustc-flags=-l dylib=builtins_type"); + println!("cargo:rustc-flags=-l dylib=lib_sh_zmapfd"); + println!("cargo:rustc-flags=-l dylib=lib_sh_mailstat"); + println!("cargo:rustc-flags=-l dylib=builtins_builtins"); + println!("cargo:rustc-flags=-l dylib=builtins_kill"); + println!("cargo:rustc-flags=-l dylib=builtins_times"); + println!("cargo:rustc-flags=-l dylib=builtins_printf"); + println!("cargo:rustc-flags=-l dylib=builtins_umask"); + println!("cargo:rustc-flags=-l dylib=builtins_let"); + println!("cargo:rustc-flags=-l dylib=builtins_suspend"); + println!("cargo:rustc-flags=-l dylib=builtins_history"); + println!("cargo:rustc-flags=-l dylib=builtins_bind"); + println!("cargo:rustc-flags=-l dylib=builtins_fg_bg"); + println!("cargo:rustc-flags=-l dylib=builtins_builtin"); + println!("cargo:rustc-flags=-l dylib=builtins_alias"); + println!("cargo:rustc-flags=-l dylib=builtins_hash"); + println!("cargo:rustc-flags=-l dylib=builtins_enable"); + println!("cargo:rustc-flags=-l dylib=builtins_help"); + println!("cargo:rustc-flags=-l dylib=builtins_trap"); + println!("cargo:rustc-flags=-l dylib=builtins_caller"); + println!("cargo:rustc-flags=-l dylib=builtins_colon"); + println!("cargo:rustc-flags=-l dylib=builtins_ulimit"); + println!("cargo:rustc-flags=-l dylib=builtins_test"); + println!("cargo:rustc-flags=-l dylib=lib_sh_wcsnwidth"); + println!("cargo:rustc-flags=-l dylib=lib_readline_callback"); + println!("cargo:rustc-flags=-l dylib=lib_sh_zcatfd"); + println!("cargo:rustc-flags=-l dylib=lib_sh_zwrite"); + println!("cargo:rustc-flags=-l dylib=lib_sh_unicode"); + println!("cargo:rustc-flags=-l dylib=lib_sh_zgetline"); + println!("cargo:rustc-flags=-l dylib=lib_malloc_malloc"); + println!("cargo:rustc-flags=-l dylib=lib_sh_pathphys"); + println!("cargo:rustc-flags=-l dylib=lib_sh_fmtumax"); + + + + } diff --git a/bash-5.1/builtins_rust/cd/Cargo.toml b/bash-5.1/builtins_rust/cd/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6c92c52d39437ba0815f490509217580c267f9d6 100644 --- a/bash-5.1/builtins_rust/cd/Cargo.toml +++ b/bash-5.1/builtins_rust/cd/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rcd" +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 = "rcd" diff --git a/bash-5.1/builtins_rust/cd/src/lib.rs b/bash-5.1/builtins_rust/cd/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb10f8c86fbd5f00ae066e241575ed58af6a9ca5 100644 --- a/bash-5.1/builtins_rust/cd/src/lib.rs +++ b/bash-5.1/builtins_rust/cd/src/lib.rs @@ -0,0 +1,852 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(i8)] +pub enum JOB_STATE { + JNONE = -1, + JRUNNING = 1, + JSTOPPED = 2, + JDEAD = 4, + JMIXED = 8 +} + +#[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)] +pub struct PROCESS { + next: *mut PROCESS, + pid:libc::c_int, + status:libc::c_int, + running:libc::c_int, + command:*mut c_char +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, /* Next element, or NULL. */ + redirector:REDIRECTEE, /* Descriptor or varname to be redirected. */ + rflags:libc::c_int, /* Private flags for this redirection */ + flags:libc::c_int, /* Flag value for `open'. */ + instruction:r_instruction, /* What to do with the information. */ + redirectee:REDIRECTEE, /* File descriptor or filename */ + here_doc_eof:*mut c_char /* The word that appeared in <*mut SHELL_VAR, /* Function called to return a `dynamic' + value for a variable, like $SECONDS + or $RANDOM. */ + assign_func:* mut fn(v:* mut SHELL_VAR,str1:* mut c_char,t:c_long,str2:* mut c_char)->*mut SHELL_VAR, /* Function called when this `special + variable' is assigned a value in + bind_variable. */ + attributes:i32, /* export, readonly, array, invisible... */ + context:i32 /* Which context this variable belongs to. */ +} + +#[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! DUP_JOB { + () => {-2} +} + +#[macro_export] +macro_rules! readonly_p { + ($var:expr) => { + (*$var).attributes & 0x0000002 + } +} + +#[macro_export] +macro_rules! exported_p { + ($var:expr) => { + (*$var).attributes & 0x0000001 + } +} + +#[macro_export] +macro_rules! LCD_DOVARS { + () => { + 0x001 + } +} +#[macro_export] +macro_rules! LCD_DOSPELL { + () => { + 0x002 + } +} +#[macro_export] +macro_rules! LCD_PRINTPATH { + () => { + 0x004 + } +} + +#[macro_export] +macro_rules! LCD_FREEDIRNAME { + () => { + 0x008 + } +} + +#[macro_export] +macro_rules! MP_DOTILDE { + () => { + 0x01 + } +} + +#[macro_export] +macro_rules! PATH_CHECKDOTDOT { + () => { + 0x0001 + } +} + +#[macro_export] +macro_rules! PATH_CHECKEXISTS { + () => { + 0x0002 + } +} + +#[macro_export] +macro_rules! errno { + () => { + *libc::__errno_location() + } +} + +extern "C" { + fn builtin_error(err:*const c_char,...); + + static mut loptend:*mut WORD_LIST; + + static mut array_needs_making:i32; + fn bind_variable ( lhs:*const c_char, rhs:* mut c_char, i:i32)->* mut SHELL_VAR; + fn update_export_env_inplace (env_prefix:* mut c_char, preflen:i32, value:* mut c_char); + static mut the_current_working_directory:* mut c_char; + fn get_working_directory (for_whom:* mut c_char)->* mut c_char; + fn sh_physpath (path:*mut c_char, flags:i32)->* mut c_char; + fn sh_chkwrite (s:i32)->i32; + fn get_string_value (var_name:*const c_char)->* mut c_char; + + static mut restricted:i32; + fn sh_restricted (s:*mut c_char); + static no_symbolic_links:i32; + + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + fn builtin_usage(); + static cdable_vars:i32; + static interactive:i32; + static cdspelling:i32; + fn absolute_pathname (str:*const c_char)->i32; + fn extract_colon_unit (string:*mut c_char, p_index:*mut i32)->* mut c_char; + fn sh_makepath (path:*const c_char, dir:*const c_char, flags:i32)->* mut c_char; + static privileged_mode:i32; + fn dirspell (dirname:* mut c_char)->* mut c_char; + fn printable_filename (fnc:* mut c_char, flags:i32)->* mut c_char; + + static posixly_correct:i32; + fn same_file (path1:*const c_char, path2:*const c_char, stp1:*mut libc::stat, stp2:*mut libc::stat)->i32; + fn make_absolute (str1:*const c_char, dot_path:*const c_char)->* mut c_char; + fn sh_canonpath (path:* mut c_char, flags:i32)->* mut c_char; + fn set_working_directory (path:* mut c_char); +} + +pub static mut xattrfd:i32=-1; +pub static mut xattrflag:i32=0; +pub static mut verbatim_pwd:i32=0; +pub static mut eflag:i32=0; + +/* How to bring a job into the foreground. */ +#[no_mangle] +pub extern "C" fn r_setpwd (dirname:* mut c_char)->i32 +{ + let old_anm:i32; + let tvar:* mut SHELL_VAR; + unsafe { + old_anm = array_needs_making; + + let c_str_pwd = CString::new("PWD").unwrap(); + if dirname ==std::ptr::null_mut() { + tvar=bind_variable (c_str_pwd.as_ptr(), CString::new("").unwrap().as_ptr() as * mut c_char, 0); + } else { + tvar = bind_variable (c_str_pwd.as_ptr(), dirname , 0); + } + + if tvar !=std::ptr::null_mut() && readonly_p! (tvar) !=0 { + return EXECUTION_FAILURE!(); + } + + if tvar !=std::ptr::null_mut() && old_anm == 0 && array_needs_making !=0 && exported_p !(tvar) !=0 { + if dirname ==std::ptr::null_mut() { + update_export_env_inplace (c_str_pwd.as_ptr() as * mut c_char, 4, CString::new("").unwrap().as_ptr() as * mut c_char); + } else { + update_export_env_inplace (c_str_pwd.as_ptr() as * mut c_char, 4, dirname); + } + array_needs_making = 0; + } + return EXECUTION_SUCCESS!(); + } +} + +#[no_mangle] +pub extern "C" fn r_bindpwd (no_symlinks:i32)->i32 { + let mut dirname:*mut c_char; + let pwdvar:*mut c_char; + let old_anm:i32; + let mut r:i32; + let mut canon_failed:i32; + let tvar:* mut SHELL_VAR; + unsafe { + r = sh_chkwrite (EXECUTION_SUCCESS!()); + if the_current_working_directory !=std::ptr::null_mut() { + if no_symlinks !=0{ + dirname=sh_physpath (the_current_working_directory, 0); + }else { + dirname =the_current_working_directory; + } + } else { + let c_str_cd = CString::new("cd").unwrap(); + dirname=get_working_directory(c_str_cd.as_ptr() as * mut c_char); + } + + /* If canonicalization fails, reset dirname to the_current_working_directory */ + canon_failed = 0; + if dirname == std::ptr::null_mut() { + canon_failed = 1; + dirname = the_current_working_directory; + } + + old_anm = array_needs_making; + let c_str_pwd = CString::new("PWD").unwrap(); + pwdvar = get_string_value (c_str_pwd.as_ptr()); + + tvar = bind_variable (CString::new("OLDPWD").unwrap().as_ptr(), pwdvar, 0); + if tvar !=std::ptr::null_mut() && readonly_p! (tvar) !=0{ + r = EXECUTION_FAILURE!(); + } + + if old_anm == 0 && array_needs_making !=0 && exported_p! (tvar) !=0 { + update_export_env_inplace (CString::new("OLDPWD").unwrap().as_ptr() as * mut c_char, 7, pwdvar); + array_needs_making = 0; + } + + if r_setpwd (dirname) == EXECUTION_FAILURE!() { + r = EXECUTION_FAILURE!(); + } + + if canon_failed !=0 && eflag !=0 { + r = EXECUTION_FAILURE!(); + } + + if dirname !=std::ptr::null_mut() && dirname != the_current_working_directory { + libc::free(dirname as * mut libc::c_void); + } + return r; + } +} + +/* Call get_working_directory to reset the value of + the_current_working_directory () */ +#[no_mangle] +pub extern "C" fn r_resetpwd (caller:*mut c_char)->*mut c_char { + let tdir:*mut c_char; + unsafe { + libc::free(the_current_working_directory as * mut libc::c_void); + the_current_working_directory = 0 as * mut c_char; + tdir = get_working_directory (caller); + return tdir; + } +} + +#[no_mangle] +pub extern "C" fn r_cdxattr (dir: *mut c_char, ndirp:*mut c_char)->i32 { + return -1; +} + +#[no_mangle] +pub extern "C" fn r_resetxattr () { + unsafe { + xattrfd = -1; /* not strictly necessary */ + } +} + +#[no_mangle] +pub extern "C" fn r_cd_builtin (list:*mut WORD_LIST)->i32 { + let mut dirname:*mut c_char=std::ptr::null_mut(); + let cdpath:*mut c_char; + let mut path:*mut c_char; + let mut temp:*mut c_char; + let mut path_index:i32; + let mut no_symlinks:i32; + let mut opt:i32; + let mut lflag:i32; + let e:i32; + unsafe { + if restricted !=0 { + sh_restricted (0 as * mut c_char); + return EXECUTION_FAILURE!(); + } + + eflag = 0; + no_symlinks = no_symbolic_links; + xattrflag = 0; + reset_internal_getopt (); + let c_str_elp = CString::new("eLP").unwrap(); // from a &str, creates a new allocation + opt = internal_getopt (list, c_str_elp.as_ptr() as * mut c_char); + while opt != -1 { + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar { + 'P'=>{no_symlinks = 1;} + 'L'=>{no_symlinks = 0;} + 'e'=>{eflag = 1;} + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt =internal_getopt (list, c_str_elp.as_ptr() as * mut c_char); + } + + if cdable_vars != 0 { + lflag=LCD_DOVARS!(); + } else { + lflag=0; + } + + if interactive !=0 && cdspelling !=0 { + lflag=lflag | LCD_DOSPELL!(); + } else { + lflag=lflag | 0; + } + + if eflag !=0 && no_symlinks == 0{ + eflag = 0; + } + + if loptend == std::ptr::null_mut() { + /* `cd' without arguments is equivalent to `cd $HOME' */ + dirname = get_string_value (CString::new("HOME").unwrap().as_ptr()); + + if dirname == std::ptr::null_mut() { + builtin_error (CString::new("HOME not set").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + lflag = 0; + }else if (*loptend).next != std::ptr::null_mut() { + builtin_error (CString::new("too many arguments").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + }else if char::from((*(*(*loptend).word).word) as u8) == '-' && char::from(*((((*(*loptend).word).word) as usize +4) as *mut c_char) as u8) == '\0' { + /* This is `cd -', equivalent to `cd $OLDPWD' */ + dirname = get_string_value (CString::new("OLDPWD").unwrap().as_ptr()); + + if dirname == std::ptr::null_mut() { + builtin_error (CString::new("OLDPWD not set").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + lflag = LCD_PRINTPATH!(); /* According to SUSv3 */ + } else if absolute_pathname ((*(*loptend).word).word) !=0 { + dirname = (*(*loptend).word).word; + } else if privileged_mode == 0 { + cdpath = get_string_value (CString::new("CDPATH").unwrap().as_ptr() ); + if cdpath !=std::ptr::null_mut() { + dirname = (*(*loptend).word).word; + /* Find directory in $CDPATH. */ + path_index = 0; + path = extract_colon_unit (cdpath, & mut path_index); + while path != std::ptr::null_mut() { + /* OPT is 1 if the path element is non-empty */ + opt = (char::from(*path as u8 )!= '\0') as i32 ; + temp = sh_makepath (path, dirname, MP_DOTILDE!()); + libc::free (path as * mut c_void); + + if r_change_to_directory (temp, no_symlinks, xattrflag) !=0 { + /* POSIX.2 says that if a nonempty directory from CDPATH + is used to find the directory to change to, the new + directory name is echoed to stdout, whether or not + the shell is interactive. */ + if opt !=0 { + if no_symlinks !=0 { + path=temp; + } else { + path=the_current_working_directory; + } + + if path !=std::ptr::null_mut() { + libc::printf(CString::new("%s\n").unwrap().as_ptr() as * const c_char,path); + } + } + + libc::free (temp as * mut c_void); + return r_bindpwd (no_symlinks); + + } else { + libc::free (temp as * mut c_void); + } + + path = extract_colon_unit (cdpath, &mut path_index); + } + } + } else{ + dirname = (*(*loptend).word).word; + } + + + /* When we get here, DIRNAME is the directory to change to. If we + chdir successfully, just return. */ + if 0 != r_change_to_directory (dirname, no_symlinks, xattrflag) { + if (lflag & LCD_PRINTPATH!()) !=0 { + libc::printf(CString::new("%s\n").unwrap().as_ptr() as * const c_char,dirname); + } + return r_bindpwd (no_symlinks); + } + + /* If the user requests it, then perhaps this is the name of + a shell variable, whose value contains the directory to + change to. */ + if (lflag & LCD_DOVARS!()) !=0 { + temp = get_string_value (dirname); + if temp != std::ptr::null_mut() && r_change_to_directory (temp, no_symlinks, xattrflag) !=0 { + libc::printf(CString::new("%s\n").unwrap().as_ptr() as * const c_char,temp); + return r_bindpwd (no_symlinks); + } + } + + /* If the user requests it, try to find a directory name similar in + spelling to the one requested, in case the user made a simple + typo. This is similar to the UNIX 8th and 9th Edition shells. */ + if (lflag & LCD_DOSPELL!()) !=0 { + temp = dirspell (dirname); + if temp !=std::ptr::null_mut() && r_change_to_directory (temp, no_symlinks, xattrflag) !=0 { + println!("{:?}", temp); + libc::free (temp as * mut c_void); + return r_bindpwd (no_symlinks); + } else { + libc::free (temp as * mut c_void); + } + } + + e =errno!(); + temp = printable_filename (dirname, 0); + builtin_error (CString::new("%s: %s").unwrap().as_ptr(), temp, libc::strerror (e)); + + if temp != dirname { + libc::free (temp as * mut c_void); + } + return EXECUTION_FAILURE!(); + } +} + +#[no_mangle] +pub extern "C" fn r_pwd_builtin (list:* mut WORD_LIST)->i32 { + let mut directory:* mut c_char; + let mut opt:i32; + let mut pflag:i32; + unsafe { + verbatim_pwd = no_symbolic_links; + pflag = 0; + reset_internal_getopt (); + let c_str_lp = CString::new("LP").unwrap(); // from a &str, creates a new allocation + opt = internal_getopt (list, c_str_lp.as_ptr() as * mut c_char); + while opt != -1 { + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'P'=>{verbatim_pwd =1; + pflag = 1;} + 'L'=>{verbatim_pwd = 0;} + _=>{builtin_usage (); + return EX_USAGE!(); + } + } + opt = internal_getopt (list, c_str_lp.as_ptr() as * mut c_char); + } + if the_current_working_directory != std::ptr::null_mut() { + if verbatim_pwd != 0 { + directory=sh_physpath (the_current_working_directory, 0); + } else { + directory=the_current_working_directory; + } + } else { + directory=get_working_directory(CString::new("pwd").unwrap().as_ptr() as * mut c_char); + } + + /* Try again using getcwd() if canonicalization fails (for instance, if + the file system has changed state underneath bash). */ + if (the_current_working_directory != std::ptr::null_mut() && directory == std::ptr::null_mut()) || + (posixly_correct !=0 && same_file (CString::new(".").unwrap().as_ptr(), the_current_working_directory, std::ptr::null_mut() , std::ptr::null_mut()) == 0) { + if directory !=std::ptr::null_mut() && directory != the_current_working_directory { + libc::free (directory as * mut c_void); + } + directory = r_resetpwd (CString::new("pwd").unwrap().as_ptr() as * mut c_char); + } + + if directory != std::ptr::null_mut() { + opt = EXECUTION_SUCCESS!(); + libc::printf(CString::new("%s\n").unwrap().as_ptr() as * const c_char,directory); + /* This is dumb but posix-mandated. */ + if posixly_correct !=0 && pflag !=0 { + opt = r_setpwd (directory); + } + + if directory != the_current_working_directory { + libc::free (directory as * mut c_void); + } + return sh_chkwrite (opt); + } else { + return EXECUTION_FAILURE!(); + } + } +} + +/* Do the work of changing to the directory NEWDIR. Handle symbolic + link following, etc. This function *must* return with + the_current_working_directory either set to NULL (in which case + getcwd() will eventually be called), or set to a string corresponding + to the working directory. Return 1 on success, 0 on failure. */ +#[no_mangle] +pub extern "C" fn r_change_to_directory (newdir:* mut c_char, nolinks:i32, xattr:i32)->i32 { + unsafe { + let mut t:*mut c_char; + let mut tdir:*mut c_char; + let mut ndir:*mut c_char; + let err:i32; + let mut canon_failed:i32; + let mut r:i32; + let ndlen:i32; + + tdir = std::ptr::null_mut(); + + if the_current_working_directory == std::ptr::null_mut() { + t = get_working_directory (CString::new("chdir").unwrap().as_ptr() as * mut c_char); + libc::free (t as * mut c_void); + } + + t = make_absolute (newdir, the_current_working_directory); + + /* TDIR is either the canonicalized absolute pathname of NEWDIR + (nolinks == 0) or the absolute physical pathname of NEWDIR + (nolinks != 0). */ + if nolinks !=0 { + tdir=sh_physpath (t, 0); + } else { + tdir=sh_canonpath (t, PATH_CHECKDOTDOT!()|PATH_CHECKEXISTS!()); + } + + ndlen = libc::strlen (newdir ) as i32; + + /* Use the canonicalized version of NEWDIR, or, if canonicalization + failed, use the non-canonical form. */ + canon_failed = 0; + if tdir !=std::ptr::null_mut() && *tdir !=0 { + libc::free (t as * mut c_void); + } else { + libc::free (tdir as * mut c_void); + tdir = t; + canon_failed = 1; + } + + /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath + returns NULL (because it checks the path, it will return NULL if the + resolved path doesn't exist), fail immediately. */ + if posixly_correct !=0 && nolinks == 0 && canon_failed !=0 && (errno!() != libc::ENAMETOOLONG || ndlen > libc::PATH_MAX) { + if errno!() != libc::ENOENT && errno!() != libc::ENAMETOOLONG { + errno!() = libc::ENOTDIR; + } + libc::free (tdir as * mut c_void); + return 0; + } + + { + if nolinks !=0 { + r = libc::chdir (newdir); + } else { + r = libc::chdir (tdir); + } + + if r >= 0 { + r_resetxattr (); + } + + } + + /* If the chdir succeeds, update the_current_working_directory. */ + if r == 0 { + /* If canonicalization failed, but the chdir succeeded, reset the + shell's idea of the_current_working_directory. */ + if canon_failed !=0 { + t = r_resetpwd (CString::new("cd").unwrap().as_ptr() as * mut c_char); + if t == std::ptr::null_mut(){ + set_working_directory (tdir); + } else { + libc::free (t as * mut c_void); + } + } else { + set_working_directory (tdir); + } + + libc::free (tdir as * mut c_void); + return 1; + } + + /* We failed to change to the appropriate directory name. If we tried + what the user passed (nolinks != 0), punt now. */ + if nolinks !=0 { + libc::free (tdir as * mut c_void); + return 0; + } + + err = errno!(); + + /* We're not in physical mode (nolinks == 0), but we failed to change to + the canonicalized directory name (TDIR). Try what the user passed + verbatim. If we succeed, reinitialize the_current_working_directory. + POSIX requires that we just fail here, so we do in posix mode. */ + if posixly_correct == 0 && libc::chdir (newdir) == 0 { + t = r_resetpwd (CString::new("cd").unwrap().as_ptr() as * mut c_char); + if t == std::ptr::null_mut() { + set_working_directory (tdir); + } else { + libc::free (t as * mut c_void); + } + r = 1; + } else { + errno!()= err; + r = 0; + } + + libc::free (tdir as * mut c_void); + return r; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"cd" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_cd_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/declare/Cargo.toml b/bash-5.1/builtins_rust/declare/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ade288e7b35bb63b1b564b59c382282a59b513b8 100644 --- a/bash-5.1/builtins_rust/declare/Cargo.toml +++ b/bash-5.1/builtins_rust/declare/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rdeclare" +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 = "rdeclare" diff --git a/bash-5.1/builtins_rust/declare/src/lib.rs b/bash-5.1/builtins_rust/declare/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ca36790378977b0647e9a6b79477bcdfa703830a 100644 --- a/bash-5.1/builtins_rust/declare/src/lib.rs +++ b/bash-5.1/builtins_rust/declare/src/lib.rs @@ -0,0 +1,1552 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::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:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:libc::c_int, + flags:libc::c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:libc::c_int, + line:libc::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:libc::c_int +} + +#[repr(C)] +pub struct case_com { + flags:libc::c_int, + line:libc::c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:libc::c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:libc::c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:libc::c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:libc::c_int +} + +#[repr(C)] +pub struct simple_com { + flags:libc::c_int, + line:libc::c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:libc::c_int, + line:libc::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:libc::c_int, + line:libc::c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:libc::c_int, + line:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:libc::c_int, + line:libc::c_int, + type_c:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:libc::c_int, + line:libc::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 +} + +#[repr(C)] +pub struct SHELL_VAR { + name:*mut c_char, /* Symbol that the user types. */ + value:*mut c_char, /* Value that is returned. */ + exportstr:*mut c_char, /* String for the environment. */ + dynamic_value:*mut fn(v:* mut SHELL_VAR)->*mut SHELL_VAR, /* Function called to return a `dynamic' + value for a variable, like $SECONDS + or $RANDOM. */ + assign_func:* mut fn(v:* mut SHELL_VAR,str1:* mut c_char,t:c_long,str2:* mut c_char)->*mut SHELL_VAR, /* Function called when this `special + variable' is assigned a value in + bind_variable. */ + attributes:i32, /* export, readonly, array, invisible... */ + context:i32 /* Which context this variable belongs to. */ +} + +#[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 c_void, /* What we really want. */ + khash:u32, /* What key hashes to */ + times_found:i32 /* Number of times this item has been found. */ +} + +#[repr(C)] +pub struct HASH_TABLE { + bucket_array:*mut * mut BUCKET_CONTENTS, /* Where the data is kept. */ + nbuckets:i32, /* How many buckets does this table have. */ + nentries:i32 /* How many entries does this table have. */ +} + +#[repr(C)] +pub struct VAR_CONTEXT { + name:* mut c_char,/* empty or NULL means global context */ + scope:i32, /* 0 means global context */ + flags:i32, + up:* mut VAR_CONTEXT, /* previous function calls */ + down:* mut VAR_CONTEXT, /* down towards global context */ + table:* mut HASH_TABLE /* variables at this scope */ +} + +#[macro_export] +macro_rules! EXECUTION_FAILURE { + () => {1} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! ARGS_SETBLTIN { + () => { + 0x04 + } +} + +#[macro_export] +macro_rules! EXITPROG { + () => { + 3 + } +} + +#[macro_export] +macro_rules! att_local { + () => { + 0x0000020 + } +} + +#[macro_export] +macro_rules! att_array { + () => { + 0x0000004 /* value is an array */ + } +} + +#[macro_export] +macro_rules! att_assoc { + () => { + 0x0000040 /* variable is an associative array */ + } +} + +#[macro_export] +macro_rules! att_function { + () => { + 0x0000008 /* value is a function */ + } +} + +#[macro_export] +macro_rules! att_integer { + () => { + 0x0000010 /* internal representation is int */ + } +} + +#[macro_export] +macro_rules! att_nameref { + () => { + 0x0000800 /* word is a name reference */ + } +} + +#[macro_export] +macro_rules! att_readonly { + () => { + 0x0000002 /* cannot change */ + } +} + +#[macro_export] +macro_rules! att_trace { + () => { + 0x0000080 /* function is traced with DEBUG trap */ + } +} + +#[macro_export] +macro_rules! att_exported { + () => { + 0x0000001 /* export to environment */ + } +} + +#[macro_export] +macro_rules! att_capcase { + () => { + 0x0000400 /* word capitalized on assignment */ + } +} + +#[macro_export] +macro_rules! att_uppercase { + () => { + 0x0000100 /* word converted to uppercase on assignment */ + } +} + +#[macro_export] +macro_rules! att_lowercase { + () => { + 0x0000200 /* word converted to lowercase on assignment */ + } +} + +#[macro_export] +macro_rules! MKLOC_INHERIT { + () => { + 0x04 + } +} + +#[macro_export] +macro_rules! EXECUTION_SUCCESS { + () => { + 0 + } +} + +#[macro_export] +macro_rules! ASS_APPEND { + () => { + 0x0001 + } +} + +#[macro_export] +macro_rules! ASS_MKLOCAL { + () => { + 0x0002 + } +} + +#[macro_export] +macro_rules! MKLOC_ARRAYOK { + () => { + 0x02 + } +} + +#[macro_export] +macro_rules! MKLOC_ASSOCOK { + () => { + 0x01 + } +} + +#[macro_export] +macro_rules! FUNC_MULTILINE { + () => { + 0x01 + } +} + +#[macro_export] +macro_rules! FUNC_EXTERNAL { + () => { + 0x02 + } +} + +#[macro_export] +macro_rules! ASS_FORCE { + () => { + 0x0020 /* force assignment even to readonly variable */ + } +} + +#[macro_export] +macro_rules! W_COMPASSIGN { + () => { + 1 << 15 /* Compound assignment */ + } +} + +#[macro_export] +macro_rules! ASS_NOEXPAND { + () => { + 0x0080 /* don't expand associative array subscripts */ + } +} + +#[macro_export] +macro_rules! EX_BADASSIGN { + () => { + 260 /* variable assignment error */ + } +} + +#[macro_export] +macro_rules! att_tempvar { + () => { + 0x0100000 /* variable came from the temp environment */ + } +} + +#[macro_export] +macro_rules! att_propagate { + () => { + 0x0200000 /* propagate to previous scope */ + } +} + +#[macro_export] +macro_rules! ASS_NAMEREF { + () => { + 0x0010 /* assigning to nameref variable */ + } +} + +#[macro_export] +macro_rules! att_invisible { + () => { + 0x0001000 /* cannot see */ + } +} + +#[macro_export] +macro_rules! att_noassign { + () => { + 0x0004000 /* assignment not allowed */ + } +} + +pub union Functions { + f_xfree:unsafe extern "C" fn(str1:* mut c_void), + f_maybe_pop_dollar_vars: unsafe extern "C" fn(), + f_maybe_set_debug_trap:unsafe extern "C" fn(* mut c_char) +} + +extern "C" { + fn builtin_help (); + static variable_context:i32; + fn builtin_error(err:*const c_char,...); + fn builtin_warning(err:*const c_char,...); + fn find_variable (str:*const c_char)->* mut SHELL_VAR; + fn find_global_variable (str:*const c_char)->* mut SHELL_VAR; + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + static mut list_opttype:i32; + static mut array_needs_making:i32; + fn builtin_usage(); + static mut loptend:*mut WORD_LIST; + fn show_local_var_attributes (v:i32, nodefs:i32)->i32; + fn show_all_var_attributes (v:i32, nodefs:i32)->i32; + fn set_builtin (list:*mut WORD_LIST)->i32; + fn set_or_show_attributes (list:*mut WORD_LIST, attribute:i32, nodefs:i32)->i32; + fn sh_chkwrite (ret:i32)->i32; + fn show_func_attributes (name:* mut c_char, nodefs:i32)->i32; + fn show_localname_attributes (name:* mut c_char, nodefs:i32)->i32; + fn show_name_attributes (name:* mut c_char, nodefs:i32)->i32; + fn sh_notfound (name:* mut c_char); + static assoc_expand_once:i32; + fn assignment (str1:* const c_char, flags:i32)->i32; + fn make_local_variable (name:* const c_char, flags:i32)->* mut SHELL_VAR; + fn get_current_options ()->* mut c_char; + fn valid_array_reference (name:* const c_char, flags:i32)->i32; + fn check_selfref (name:* const c_char, value:* mut c_char, flags:i32)->i32; + fn valid_nameref_value (name:* const c_char, flags:i32)->i32; + fn sh_invalidid (value:* mut c_char); + static mut posixly_correct:i32; + fn nameref_transform_name (name:* mut c_char, flags:i32)->* mut c_char; + fn find_variable_last_nameref (name:* const c_char, flags:i32)->* mut SHELL_VAR; + fn make_local_assoc_variable (value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn make_local_array_variable (value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn find_global_variable_last_nameref (value:* const c_char, flags:i32)->* mut SHELL_VAR; + fn find_global_variable_noref (value:* const c_char)->* mut SHELL_VAR; + fn find_variable_noref (value:* const c_char)->* mut SHELL_VAR; + fn sh_readonly (name:* const c_char); + fn sh_invalidopt (value:* mut c_char); + static mut debugging_mode:i32; + fn find_function_def (name:* const c_char)->* mut function_def; + fn named_function_string (name:* mut c_char, cmd:* mut COMMAND, i:i32)->* mut c_char; + fn make_new_assoc_variable (name:* mut c_char)->* mut SHELL_VAR; + fn make_new_array_variable (name:* mut c_char)->* mut SHELL_VAR; + fn bind_global_variable (name:* const c_char,value:* mut c_char,flags:i32)->* mut SHELL_VAR; + fn bind_variable (name:* const c_char,value:* mut c_char,flags:i32)->* mut SHELL_VAR; + static mut shell_compatibility_level:i32; + fn internal_warning (format:* const c_char, ...); + fn assign_array_element (name:* mut c_char, value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn bind_assoc_variable (var:* mut SHELL_VAR, name:* mut c_char, key:* mut c_char, value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn bind_array_variable (name:* mut c_char, s:libc::c_long, value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn bind_variable_value (var:* mut SHELL_VAR, name:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn delete_var (name:* const c_char, varc:* mut VAR_CONTEXT)->i32; + static global_variables:* mut VAR_CONTEXT; + static shell_variables:* mut VAR_CONTEXT; + fn find_tempenv_variable (format:* const c_char)->* mut SHELL_VAR; + fn stupidly_hack_special_variables (name:* mut c_char); + fn assign_array_var_from_string (var:* mut SHELL_VAR, value:* mut c_char, flags:i32)->* mut SHELL_VAR; + fn convert_var_to_array (var:* mut SHELL_VAR)->* mut SHELL_VAR; + fn convert_var_to_assoc (var:* mut SHELL_VAR)->* mut SHELL_VAR; + fn find_function (name:* const c_char)->* mut SHELL_VAR; + fn legal_identifier (name:* const c_char)->i32; +} + +#[no_mangle] +pub extern "C" fn r_declare_builtin (list:* mut WORD_LIST)->i32 +{ + return r_declare_internal (list, 0); +} + +unsafe fn STREQ( a:* const c_char, b:* const c_char)->bool { + return *a ==*b && libc::strcmp(a, b) == 0; +} + +#[no_mangle] +pub extern "C" fn r_local_builtin (list:* mut WORD_LIST)->i32 +{ + unsafe { + /* Catch a straight `local --help' before checking function context */ + if list !=std::ptr::null_mut() && (*list).word != std::ptr::null_mut() && STREQ ((*(*list).word).word, CString::new("--help").unwrap().as_ptr()) { + builtin_help (); + return EX_USAGE!(); + } + + if variable_context !=0 { + return r_declare_internal (list, 1); + } else { + builtin_error (CString::new("can only be used in a function").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + } + +} + +unsafe fn local_p( varr:* mut SHELL_VAR)->i32 { + return (*varr).attributes & att_local!(); +} + +#[no_mangle] +pub extern "C" fn r_declare_find_variable (name:* const c_char, mkglobal:i32, chklocal:i32)->* mut SHELL_VAR +{ + let varr: * mut SHELL_VAR; + unsafe { + if mkglobal == 0 { + return find_variable (name); + } else if chklocal !=0 { + varr = find_variable (name); + if varr != std::ptr::null_mut() && local_p (varr) !=0 && (*varr).context == variable_context { + return varr; + } + + return find_global_variable (name); + } else { + return find_global_variable (name); + } + } +} + +unsafe fn DECLARE_OPTS()->* const c_char +{ + return CString::new("+acfgilnprtuxAFGI").unwrap().as_ptr(); +} + +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 value_cell(var:*mut SHELL_VAR)->* mut c_char +{ + return (*var).value; +} + +unsafe fn var_setvalue(var:*mut SHELL_VAR,str1:* mut c_char) +{ + (*var).value=str1; +} + +unsafe fn VSETATTR(var:*mut SHELL_VAR, attr:i32) { + (*var).attributes=attr; +} + +unsafe fn readonly_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_readonly!(); +} + +unsafe fn nameref_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_nameref!(); +} + +unsafe fn nameref_cell(var:*mut SHELL_VAR) ->* mut c_char { + return (*var).value;/* so it can change later */ +} + +unsafe fn function_cell(var:*mut SHELL_VAR) ->* mut COMMAND { + return (*var).value as * mut COMMAND; +} + +unsafe fn VUNSETATTR(var:*mut SHELL_VAR,attr:i32) ->i32 { + return (*var).attributes & !attr; +} + +unsafe fn array_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_array!(); +} + +unsafe fn assoc_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_assoc!(); +} + +unsafe fn var_isset(var:*mut SHELL_VAR) ->bool { + return (*var).value !=std::ptr::null_mut(); +} + +unsafe fn tempvar_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_tempvar!(); +} + +unsafe fn noassign_p(var:*mut SHELL_VAR) ->i32 { + return (*var).attributes & att_noassign!(); +} + +#[no_mangle] +pub extern "C" fn r_declare_internal (list:* mut WORD_LIST, local_var:i32)->i32 +{ + let mut flags_on:i32=0; + let mut flags_off:i32=0; + let mut flags:* mut i32; + let mut any_failed:i32=0; + let mut assign_error:i32=0; + let mut pflag:i32=0; + let mut nodefs:i32=0; + let opt:i32; + let mut onref:i32; + let mut offref:i32; + let mut mkglobal:i32=0; + let mut chklocal:i32=0; + let mut inherit_flag:i32=0; + + let mut t: *mut c_char; + let mut subscript_start: *mut c_char; + let mut var:*mut SHELL_VAR; + let mut refvar:*mut SHELL_VAR; + let mut v:*mut SHELL_VAR; + + let mut shell_fn:*mut function_def; + + refvar = std::ptr::null_mut(); + + unsafe { + reset_internal_getopt (); + opt = internal_getopt (list, DECLARE_OPTS() as * mut c_char); + while opt != -1 { + if list_opttype == '+' as i32 { + flags= &mut flags_off; + } else { + flags= &mut flags_on; + } + + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + + /* If you add options here, see whether or not they need to be added to + the loop in subst.c:shell_expand_word_list() */ + match optChar { + 'a'=>{ *flags |= att_array!();} + 'A'=>{ *flags |= att_assoc!();} + 'p'=>{ pflag+=1;} + 'F'=>{ nodefs+=1; + *flags |= att_function!(); + } + 'f'=>{ *flags |= att_function!();} + 'G'=>{ + if flags == &mut flags_on { + chklocal = 1; + } + } + 'g'=>{ + if flags == &mut flags_on { + mkglobal = 1; + } + } + 'i'=>{ *flags |= att_integer!();} + 'n'=>{ *flags |= att_nameref!();} + 'r'=>{ *flags |= att_readonly!();} + 't'=>{ *flags |= att_trace!();} + 'x'=>{ *flags |= att_exported!(); + array_needs_making = 1; + } + 'c'=>{ *flags |= att_capcase!(); + if flags == &mut flags_on { + flags_off |= att_uppercase!() | att_lowercase!(); + } + } + 'l'=>{ *flags |= att_lowercase!(); + if flags == &mut flags_on { + flags_off |= att_capcase!()| att_uppercase!(); + } + } + 'u'=>{ *flags |= att_uppercase!(); + if flags == &mut flags_on { + flags_off |= att_capcase!()| att_lowercase!(); + } + } + 'I'=>{ inherit_flag = MKLOC_INHERIT!();} + _=>{ builtin_usage (); + return EX_USAGE!(); + } + } + internal_getopt (list, DECLARE_OPTS() as * mut c_char); + } + + let mut llist:* mut WORD_LIST = loptend.clone(); + + /* If there are no more arguments left, then we just want to show + some variables. */ + if llist == std::ptr::null_mut() { /* declare -[aAfFirtx] */ + /* Show local variables defined at this context level if this is + the `local' builtin. */ + if local_var != 0 { + show_local_var_attributes (0, nodefs); /* XXX - fix up args later */ + } else if pflag != 0 && (flags_on == 0 || flags_on == att_function!()) { + let mut ret=0; + if flags_on == 0 { + ret=1; + } + show_all_var_attributes (ret, nodefs); + } else if flags_on == 0 { + return set_builtin (std::ptr::null_mut()); + } else { + set_or_show_attributes (std::ptr::null_mut(), flags_on, nodefs); + } + return sh_chkwrite (EXECUTION_SUCCESS!()); + } + + if pflag !=0 { /* declare -p [-aAfFirtx] name [name...] */ + any_failed=0; + while llist != std::ptr::null_mut() { + if (flags_on & att_function!()) != 0 { + pflag = show_func_attributes ((*(*llist).word).word, nodefs); + } else if local_var !=0 { + pflag = show_localname_attributes ((*(*llist).word).word, nodefs); + } else { + pflag = show_name_attributes ((*(*llist).word).word, nodefs); + } + + if pflag !=0 { + sh_notfound ((*(*llist).word).word); + any_failed+=1; + } + llist = (*llist).next; + } + + if any_failed !=0 { + return EXECUTION_FAILURE!(); + } else { + return EXECUTION_SUCCESS!(); + } + } + + /* There are arguments left, so we are making variables. */ + while llist !=std::ptr::null_mut() { /* declare [-aAfFirx] name [name ...] */ + + let mut value:* mut c_char; + let mut name:* mut c_char; + let mut oldname:* mut c_char; + let mut offset:i32; + let mut aflags:i32; + let wflags:i32; + let mut created_var:i32; + let mut namelen:i32; + let assoc_noexpand:i32; + + let mut making_array_special:i32; + let mut compound_array_assign:i32; + let mut simple_array_assign:i32; + let mut var_exists:i32; + let mut array_exists:i32; + let mut creating_array:i32; + let mut array_subscript_assignment:i32; + + name = savestring ((*(*llist).word).word); + wflags = (*(*llist).word).flags; + + assoc_noexpand = (assoc_expand_once !=0 && (wflags & (1 << 2)) !=0) as i32; + if assoc_noexpand !=0 { + offset = assignment (name, 2); + } else { + offset = assignment (name, 0); + } + + aflags = 0; + created_var = 0; + + if local_var !=0 && variable_context !=0 && STREQ (name, CString::new("-").unwrap().as_ptr()) { + var = make_local_variable (CString::new("-").unwrap().as_ptr(), 0); + libc::free (value_cell (var) as * mut c_void); /* just in case */ + value = get_current_options (); + var_setvalue (var, value); + VSETATTR (var, att_invisible!()); + libc::free (name as * mut c_void); + llist = (*llist).next; + continue; + } + + if offset !=0 { /* declare [-aAfFirx] name=value */ + *((name as usize + offset as usize) as * mut c_char) = '\0' as c_char; + value = (name as usize + (offset + 1) as usize) as * mut c_char; + if *((name as usize + (offset - 1) as usize) as * mut c_char) == '+' as c_char { + aflags |= ASS_APPEND!(); + *((name as usize + (offset - 1) as usize) as * mut c_char) = '\0' as c_char; + } + } else { + value = CString::new("").unwrap().as_ptr() as * mut c_char; + } + + /* Do some lexical error checking on the LHS and RHS of the assignment + that is specific to nameref variables. */ + if (flags_on & att_nameref!()) !=0 { + if valid_array_reference (name, 0) !=0 { + builtin_error (CString::new("%s: reference variable cannot be an array").unwrap().as_ptr(), name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + continue; + } else if check_selfref (name, value, 0) !=0 {/* disallow self references at global scope, warn at function scope */ + if variable_context == 0 { + builtin_error (CString::new("%s: nameref variable self references not allowed").unwrap().as_ptr(), name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + continue; + } else { + builtin_warning (CString::new("%s: circular name reference").unwrap().as_ptr(), name); + } + } + + if value != std::ptr::null_mut() && (*value) !=0 && (aflags & ASS_APPEND!()) == 0 && valid_nameref_value (value, 1) == 0 { + builtin_error (CString::new("`nvalid %s': ivariable name for name reference").unwrap().as_ptr(), value); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + continue; + } + } + +//restart_new_var_name: + loop { + + var_exists = 0; + array_exists = 0; + creating_array = 0; + compound_array_assign = 0; + simple_array_assign = 0; + array_subscript_assignment = 0; + subscript_start = std::ptr::null_mut(); + t = libc::strchr (name, '[' as libc::c_int); + if t !=std::ptr::null_mut() && (flags_on & att_function!()) == 0 {/* ] */ + /* If offset != 0 we have already validated any array reference + because assignment() calls skipsubscript() */ + if offset == 0 && valid_array_reference (name, 0) == 0 { + sh_invalidid (name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + subscript_start = t; + *t = '\0' as c_char; + making_array_special = 1; /* XXX - should this check offset? */ + array_subscript_assignment = (offset != 0) as i32; + } else { + making_array_special = 0; + } + /* If we're in posix mode or not looking for a shell function (since + shell function names don't have to be valid identifiers when the + shell's not in posix mode), check whether or not the argument is a + valid, well-formed shell identifier. */ + if (posixly_correct !=0 || (flags_on & att_function!()) == 0) && legal_identifier (name) == 0 { + sh_invalidid (name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + /* If VARIABLE_CONTEXT has a non-zero value, then we are executing + inside of a function. This means we should make local variables, + not global ones. */ + + /* XXX - this has consequences when we're making a local copy of a + variable that was in the temporary environment. Watch out + for this. */ + refvar = std::ptr::null_mut(); + if variable_context !=0 && mkglobal == 0 && ((flags_on & att_function!()) == 0) { + let newname: * mut c_char; + + /* check name for validity here? */ + var = find_variable (name); + if var == std::ptr::null_mut() { + newname = nameref_transform_name (name, ASS_MKLOCAL!()); + } else if (flags_on & att_nameref!()) == 0 && (flags_off & att_nameref!()) == 0 { + /* Ok, we're following namerefs here, so let's make sure that if + we followed one, it was at the same context (see below for + more details). */ + refvar = find_variable_last_nameref (name, 1); + if refvar != std::ptr::null_mut() && (*refvar).context != variable_context { + newname = name ; + } else { + newname = (*var).name; + } + refvar = std::ptr::null_mut(); + } else { + newname = name; /* dealing with nameref attribute */ + } + + /* Pass 1 as second argument to make_local_{assoc,array}_variable + return an existing {array,assoc} variable to be flagged as an + error below. */ + if (flags_on & att_assoc!()) !=0 { + var = make_local_assoc_variable (newname, MKLOC_ARRAYOK!()|inherit_flag); + } else if (flags_on & att_array!()) !=0 || making_array_special !=0 { + var = make_local_array_variable (newname, MKLOC_ASSOCOK!()|inherit_flag); + } else if offset == 0 && (flags_on & att_nameref!()) !=0 { + /* First look for refvar at current scope */ + refvar = find_variable_last_nameref (name, 1); + /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify + the attributes for a local variable at the same scope. If we've + used a reference from a previous context to resolve VAR, we + want to throw REFVAR and VAR away and create a new local var. */ + if refvar != std::ptr::null_mut() && (*refvar).context != variable_context { + refvar = std::ptr::null_mut(); + var = make_local_variable (name, inherit_flag); + } else if refvar != std::ptr::null_mut() && (*refvar).context == variable_context { + var = refvar; + } else if var == std::ptr::null_mut() || (*refvar).context != variable_context {/* Maybe we just want to create a new local variable */ + var = make_local_variable (name, inherit_flag); + } + /* otherwise we have a var at the right context */ + } else { + /* XXX - check name for validity here with valid_nameref_value */ + if flags_on & att_nameref!() !=0 { + var = make_local_variable ( name , inherit_flag); + } else { + var = make_local_variable ( newname, inherit_flag); /* sets att_invisible for new vars */ + } + } + + if var == std::ptr::null_mut() { + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + if var != std::ptr::null_mut() && nameref_p (var) !=0 && readonly_p (var) != 0 && nameref_cell (var) != std::ptr::null_mut() && (flags_off & att_nameref!()) !=0 { + sh_readonly (name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + } else { + var = std::ptr::null_mut(); + } + /* If we are declaring a function, then complain about it in some way. + We don't let people make functions by saying `typeset -f foo=bar'. */ + + /* There should be a way, however, to let people look at a particular + function definition by saying `typeset -f foo'. */ + + if (flags_on & att_function!()) !=0 { + if offset !=0 { /* declare -f [-rix] foo=bar */ + builtin_error (CString::new("cannot use `-f' to make functions").unwrap().as_ptr()); + libc::free (name as * mut c_void); + return EXECUTION_FAILURE!(); + } else {/* declare -f [-rx] name [name...] */ + var = find_function (name); + if var != std::ptr::null_mut() { + if readonly_p (var) !=0 && (flags_off & att_readonly!()) !=0 { + builtin_error (CString::new("%s: readonly function").unwrap().as_ptr(), name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } else if (flags_on & (att_array!()|att_assoc!())) !=0 { + if (flags_on & att_array!()) !=0 { + sh_invalidopt (CString::new("-a").unwrap().as_ptr() as * mut c_char); + } else { + sh_invalidopt (CString::new("-A").unwrap().as_ptr() as * mut c_char); + } + + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + /* declare -[Ff] name [name...] */ + if flags_on == att_function!() && flags_off == 0 { + if nodefs !=0 && debugging_mode !=0 { + shell_fn = find_function_def ((*var).name); + if shell_fn !=std::ptr::null_mut() { + libc::printf (CString::new("%s %d %s\n").unwrap().as_ptr(), (*var).name, (*shell_fn).line, (*shell_fn).source_file); + } else { + libc::printf (CString::new("%s\n").unwrap().as_ptr(), (*var).name); + } + } else { + if nodefs !=0 { + t=(*var).name; + } else { + named_function_string (name, function_cell (var), FUNC_MULTILINE!()|FUNC_EXTERNAL!()); + } + libc::printf (CString::new("%s\n").unwrap().as_ptr(), t); + any_failed = sh_chkwrite (any_failed); + } + } else { /* declare -[fF] -[rx] name [name...] */ + VSETATTR (var, flags_on); + flags_off &= ! att_function!(); /* makes no sense */ + VUNSETATTR (var, flags_off); + } + } else { + any_failed+=1; + } + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + } else { /* declare -[aAinrx] name [name...] */ + /* Non-null if we just created or fetched a local variable. */ + + /* Here's what ksh93 seems to do as of the 2012 version: if we are + using declare -n to modify the value of an existing nameref + variable, don't follow the nameref chain at all and just search + for a nameref at the current context. If we have a nameref, + modify its value (changing which variable #define ASS_NAMEREF 0x0010 /* assigning to nameref variable */it references). */ + if var == std::ptr::null_mut() && (flags_on & att_nameref!()) !=0 { + /* See if we are trying to modify an existing nameref variable, + but don't follow the nameref chain. */ + if mkglobal !=0 { + var = find_global_variable_noref (name); + } else { + var = find_variable_noref (name); + } + + if var != std::ptr::null_mut() && nameref_p (var) == 0 { + var = std::ptr::null_mut(); + } + } else if var == std::ptr::null_mut() && (flags_off & att_nameref!()) !=0 { + /* However, if we're turning off the nameref attribute on an existing + nameref variable, we first follow the nameref chain to the end, + modify the value of the variable this nameref variable references + if there is an assignment statement argument, + *CHANGING ITS VALUE AS A SIDE EFFECT*, then turn off the nameref + flag *LEAVING THE NAMEREF VARIABLE'S VALUE UNCHANGED* */ + /* See if we are trying to modify an existing nameref variable */ + if mkglobal !=0 { + refvar=find_global_variable_last_nameref (name, 0); + } else { + refvar=find_variable_last_nameref (name, 0); + } + + if refvar != std::ptr::null_mut() && nameref_p (refvar) == 0 { + refvar = std::ptr::null_mut(); + } + /* If the nameref is readonly but doesn't have a value, ksh93 + allows the nameref attribute to be removed. If it's readonly + and has a value, even if the value doesn't reference an + existing variable, we disallow the modification */ + if refvar != std::ptr::null_mut() && nameref_cell (refvar) != std::ptr::null_mut() && readonly_p (refvar) != 0 { + sh_readonly (name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + /* If all we're doing is turning off the nameref attribute, don't + bother with VAR at all, whether it exists or not. Just turn it + off and go on. */ + if refvar != std::ptr::null_mut() && flags_on == 0 && offset == 0 && (flags_off & !att_nameref!()) == 0 { + VUNSETATTR (refvar, att_nameref!()); + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + if refvar !=std::ptr::null_mut() { + /* XXX - use declare_find_variable here? */ + if mkglobal !=0 { + var = find_global_variable (nameref_cell (refvar)); + } else { + var =find_variable (nameref_cell (refvar)); + } + } + } else if var == std::ptr::null_mut() && offset !=0 && array_subscript_assignment !=0 { + /* If we have an array assignment to a nameref, remove the nameref + attribute and go on. */ + if mkglobal !=0 { + var = find_global_variable_noref (name); + } else { + var = find_variable_noref (name); + } + + if var !=std::ptr::null_mut() && nameref_p (var) !=0 { + internal_warning (CString::new("%s: removing nameref attribute").unwrap().as_ptr(), name); + libc::free (value_cell (var) as * mut c_void); /* XXX - bash-4.3 compat */ + var_setvalue (var, std::ptr::null_mut()); + VUNSETATTR (var, att_nameref!()); + } + } + + /* See if we are trying to set flags or value (or create) for an + existing nameref that points to a non-existent variable: e.g., + declare -n foo=bar + unset foo # unsets bar + declare -i foo + foo=4+4 + declare -p foo */ + if var == std::ptr::null_mut() && (mkglobal !=0 || flags_on !=0 || flags_off !=0 || offset !=0) { + if mkglobal !=0 { + refvar = find_global_variable_last_nameref (name, 0); + } else { + refvar = find_variable_last_nameref (name, 0); + } + + if refvar != std::ptr::null_mut() && nameref_p (refvar) == 0 { + refvar = std::ptr::null_mut(); + } + + if refvar !=std::ptr::null_mut() { + /* XXX - use declare_find_variable here? */ + if mkglobal !=0 { + var = find_global_variable (nameref_cell (refvar)) ; + } else { + var = find_variable (nameref_cell (refvar)); + } + } + + if refvar !=std::ptr::null_mut() && var == std::ptr::null_mut() { + oldname = name; /* need to free this */ + namelen = libc::strlen (nameref_cell (refvar)) as i32; + + if subscript_start != std::ptr::null_mut() { + *subscript_start = '[' as c_char; /*]*/ + namelen += libc::strlen (subscript_start) as i32; + } + + name = libc::malloc (namelen as libc::size_t + 2 + libc::strlen (value) + 1 ) as * mut c_char ; + libc::strcpy (name, nameref_cell (refvar)); + + if subscript_start != std::ptr::null_mut() { + libc::strcpy ((name as usize + (libc::strlen (nameref_cell (refvar))) as usize) as * mut c_char, subscript_start); + } + + /* We are committed to using the new name, so reset */ + if offset !=0 { + /* Rebuild assignment and restore offset and value */ + if (aflags & ASS_APPEND!()) !=0 { + *((name as usize + namelen as usize) as * mut c_char) = '+' as c_char; + namelen+=1; + } + + *((name as usize + namelen as usize) as * mut c_char) = '=' as c_char; + namelen+=1; + + if value != std::ptr::null_mut() && (*value) !=0 { + libc::strcpy ((name as usize + namelen as usize) as * mut c_char, value); + } else { + *((name as usize + namelen as usize) as * mut c_char) = '\0' as c_char; + } + + offset = assignment (name, 0); + /* if offset was valid previously, but the substituting + of the nameref value results in an invalid assignment, + throw an invalid identifier error */ + if offset == 0 { + libc::free (oldname as * mut c_void); + sh_invalidid (name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + *((name as usize + offset as usize) as * mut c_char) = '\0' as c_char; + value = (name as usize + namelen as usize) as * mut c_char; + } + libc::free (oldname as * mut c_void); + + /* OK, let's turn off the nameref attribute. + Now everything else applies to VAR. */ + if (flags_off & att_nameref!()) !=0 { + VUNSETATTR (refvar, att_nameref!()); + } + + //goto restart_new_var_name; + continue; + /* NOTREACHED */ + } + } + if var == std::ptr::null_mut() { + var = r_declare_find_variable (name, mkglobal, chklocal); + } + + var_exists = (var != std::ptr::null_mut()) as i32; + array_exists = (var != std::ptr::null_mut() && (array_p (var) !=0 || assoc_p (var) !=0 )) as i32; + creating_array = flags_on & (att_array!()|att_assoc!()); + + if var == std::ptr::null_mut() { + if (flags_on & att_assoc!()) !=0 { + var = make_new_assoc_variable (name); + if var != std::ptr::null_mut() && offset == 0 { + VSETATTR (var, att_invisible!()); + } + } else if (flags_on & att_array!()) !=0 || making_array_special !=0 { + var = make_new_array_variable (name); + if var != std::ptr::null_mut() && offset == 0 { + VSETATTR (var, att_invisible!()); + } + } else { + if mkglobal !=0 { + var=bind_global_variable (name, std::ptr::null_mut(), ASS_FORCE!()); + } else { + var= bind_variable (name, std::ptr::null_mut(), ASS_FORCE!()); + } + if var != std::ptr::null_mut() && offset == 0 { + VSETATTR (var, att_invisible!()); + } + } + + if var == std::ptr::null_mut() { + /* Has to appear in brackets */ + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + created_var = 1; + } else if (array_p (var) !=0 || assoc_p (var) !=0 ) && (flags_on & att_nameref!()) !=0 { + /* Can't take an existing array variable and make it a nameref */ + builtin_error (CString::new("%s: reference variable cannot be an array").unwrap().as_ptr(), name); + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } else if nameref_p (var) !=0 && (flags_on & att_nameref!()) == 0 && (flags_off & att_nameref!()) == 0 && offset !=0 && valid_nameref_value (value, 1) == 0 { + builtin_error (CString::new("`%s': invalid variable name for name reference").unwrap().as_ptr(), value); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } else if (flags_on & att_nameref!()) !=0 { + /* Check of offset is to allow an assignment to a nameref var as + part of the declare word to override existing value */ + if nameref_p (var) == 0 && var_isset (var) && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0 { + builtin_error (CString::new("`%s': invalid variable name for name reference").unwrap().as_ptr(), value_cell (var)); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + if readonly_p (var) !=0 { + sh_readonly (name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + /* ksh93 compat: turning on nameref attribute turns off -ilu */ + VUNSETATTR (var, att_integer!()|att_uppercase!()|att_lowercase!()|att_capcase!()); + } + + /* Cannot use declare +r to turn off readonly attribute. */ + if readonly_p (var) !=0 && (flags_off & att_readonly!()) !=0 { + sh_readonly ((*var).name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + /* Cannot use declare to assign value to readonly or noassign + variable. */ + if (readonly_p (var) !=0 || noassign_p (var)!=0 ) && offset !=0 { + if readonly_p (var) !=0 { + sh_readonly (name); + } + assign_error+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + /* make declare a[2]=foo as similar to a[2]=foo as possible if + a is already an array or assoc variable. */ + if array_subscript_assignment !=0 && array_exists !=0 && creating_array == 0 { + simple_array_assign = 1; + } else if (making_array_special !=0 || creating_array !=0 || array_exists !=0) && offset!=0 { + let mut vlen:i32; + vlen = libc::strlen (value) as i32; + /*itrace("declare_builtin: name = %s value = %s flags = %d", name, value, wflags);*/ + if shell_compatibility_level > 43 && (wflags & W_COMPASSIGN!()) == 0 && *value == '(' as c_char && *((value as usize + (vlen-1) as usize) as * mut c_char) == ')' as c_char { + /* The warning is only printed when using compound assignment + to an array variable that doesn't already exist. We use + creating_array to allow things like + declare -a foo$bar='(abc)' to work. */ + if array_exists == 0 && creating_array == 0 { + internal_warning (CString::new("%s: quoted compound array assignment deprecated").unwrap().as_ptr(), (*(*llist).word).word); + } + compound_array_assign = (array_exists !=0 || creating_array !=0) as i32; + simple_array_assign = making_array_special; + } else if *value == '(' as c_char && *((value as usize + (vlen-1) as usize) as * mut c_char) == ')' as c_char && (shell_compatibility_level < 44 || (wflags & W_COMPASSIGN!()) !=0 ) { + compound_array_assign = 1; + } else { + simple_array_assign = 1; + } + } + + /* Cannot use declare +a name or declare +A name to remove an + array variable. */ + if ((flags_off & att_array!()) !=0 && array_p (var) !=0) || ((flags_off & att_assoc!()) !=0 && assoc_p (var) !=0) { + builtin_error (CString::new("%s: cannot destroy array variables in this way").unwrap().as_ptr(), name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + if (flags_on & att_array!()) !=0 && assoc_p (var) !=0 { + builtin_error (CString::new("%s: cannot convert associative to indexed array").unwrap().as_ptr(), name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + if (flags_on & att_assoc!()) !=0 && array_p (var) !=0 { + builtin_error (CString::new("%s: cannot convert indexed to associative array").unwrap().as_ptr(), name); + any_failed+=1; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + + /* declare -A name[[n]] makes name an associative array variable. */ + if (flags_on & att_assoc!()) !=0 { + if assoc_p (var) == 0 { + var = convert_var_to_assoc (var); + } + } else if (making_array_special !=0 || (flags_on & att_array!()) !=0 ) && array_p (var) == 0 && assoc_p (var) == 0 { + /* declare -a name[[n]] or declare name[n] makes name an indexed + array variable. */ + var = convert_var_to_array (var); + } + + /* XXX - we note that we are turning on nameref attribute and defer + setting it until the assignment has been made so we don't do an + inadvertent nameref lookup. Might have to do the same thing for + flags_off&att_nameref. */ + /* XXX - ksh93 makes it an error to set a readonly nameref variable + using a single typeset command. */ + onref = flags_on & att_nameref!(); + flags_on &= !att_nameref!(); + + if array_p (var) !=0 || assoc_p (var) !=0 || (offset !=0 && compound_array_assign !=0) || simple_array_assign !=0 { + onref = 0; /* array variables may not be namerefs */ + } + /* ksh93 seems to do this */ + offref = flags_off & att_nameref!(); + flags_off &= !att_nameref!(); + + VSETATTR (var, flags_on); + VUNSETATTR (var, flags_off); + + if offset !=0 && compound_array_assign !=0 { + assign_array_var_from_string (var, value, aflags|ASS_FORCE!()); + } else if simple_array_assign !=0 && subscript_start !=std::ptr::null_mut() { + let mut local_aflags:i32; + /* declare [-aA] name[N]=value */ + *subscript_start = '[' as c_char; /* ] */ + /* XXX - problem here with appending */ + local_aflags = aflags&ASS_APPEND!(); + if assoc_noexpand !=0 { + local_aflags |= ASS_NOEXPAND!(); + } else { + local_aflags |= 0; + } + + var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */ + *subscript_start = '\0' as c_char; + if var == std::ptr::null_mut() {/* some kind of assignment error */ + assign_error+=1; + flags_on |= onref; + flags_off |= offref; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + } else if simple_array_assign !=0 { + /* let bind_{array,assoc}_variable take care of this. */ + if assoc_p (var) !=0 { + bind_assoc_variable (var, name, savestring (CString::new("0").unwrap().as_ptr()), value, aflags|ASS_FORCE!()); + } else { + bind_array_variable (name, 0, value, aflags|ASS_FORCE!()); + } + } else if offset !=0 { + /* XXX - no ASS_FORCE here */ + /* bind_variable_value duplicates the essential internals of bind_variable() */ + if onref !=0 || nameref_p (var) !=0 { + aflags |= ASS_NAMEREF!(); + } + + v = bind_variable_value (var, value, aflags); + if v == std::ptr::null_mut() && (onref !=0 || nameref_p (var) !=0) { + if valid_nameref_value (value, 1) == 0 { + sh_invalidid (value); + } + + assign_error+=1; + /* XXX - unset this variable? or leave it as normal var? */ + if created_var !=0 { + if mkglobal !=0 { + delete_var ( (*var).name, global_variables); + } else { + delete_var ( (*var).name, shell_variables); + } + } + + flags_on |= onref;/* undo change from above */ + flags_off |= offref; + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + } + + /* If we found this variable in the temporary environment, as with + `var=value declare -x var', make sure it is treated identically + to `var=value export var'. Do the same for `declare -r' and + `readonly'. Preserve the attributes, except for att_tempvar. */ + /* XXX -- should this create a variable in the global scope, or + modify the local variable flags? ksh93 has it modify the + global scope. + Need to handle case like in set_var_attribute where a temporary + variable is in the same table as the function local vars. */ + if (flags_on & (att_exported!()|att_readonly!()) !=0 ) && tempvar_p (var) !=0 { + let mut tv:* mut SHELL_VAR; + let tvalue:* mut c_char=std::ptr::null_mut(); + + tv = find_tempenv_variable ((*var).name); + if tv != std::ptr::null_mut() { + if var_isset(var) { + savestring (value_cell (var)); + } else { + savestring (CString::new("").unwrap().as_ptr()); + } + tv = bind_variable ((*var).name, tvalue, 0); + + if tv != std::ptr::null_mut() { + (*tv).attributes |= (*var).attributes & !att_tempvar!(); + if (*tv).context > 0 { + VSETATTR (tv, att_propagate!()); + } + } + libc::free (tvalue as * mut c_void); + } + VSETATTR (var, att_propagate!()); + } + } + + /* Turn on nameref attribute we deferred above. */ + /* XXX - should we turn on the noassign attribute for consistency with + ksh93 when we turn on the nameref attribute? */ + VSETATTR (var, onref); + flags_on |= onref; + VUNSETATTR (var, offref); + flags_off |= offref; + /* Yuck. ksh93 compatibility. XXX - need to investigate more but + definitely happens when turning off nameref attribute on nameref + (see comments above). Under no circumstances allow this to turn + off readonly attribute on readonly nameref variable. */ + if refvar !=std::ptr::null_mut() { + if (flags_off & att_readonly!()) !=0 { + flags_off &= !att_readonly!(); + } + VUNSETATTR (refvar, flags_off); + } + + stupidly_hack_special_variables (name); + libc::free (name as * mut c_void); + llist = (*llist).next; + break; + } + } + if assign_error !=0 { + return EX_BADASSIGN!(); + } else { + if any_failed == 0 { + return EXECUTION_SUCCESS!(); + } else { + return EXECUTION_FAILURE!(); + } + } +} +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"declare" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_declare_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/fc/Cargo.toml b/bash-5.1/builtins_rust/fc/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8101733906766f4c560c672944a7a4f6dce8aa2e 100644 --- a/bash-5.1/builtins_rust/fc/Cargo.toml +++ b/bash-5.1/builtins_rust/fc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rfc" +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 = "rfc" diff --git a/bash-5.1/builtins_rust/fc/src/lib.rs b/bash-5.1/builtins_rust/fc/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3bba2966f5bd7119eb8a2e595d79dcc5d9ee699b 100644 --- a/bash-5.1/builtins_rust/fc/src/lib.rs +++ b/bash-5.1/builtins_rust/fc/src/lib.rs @@ -0,0 +1,1206 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString, i32, io::{Write, stdout}, ops::Add, string, u32}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(i8)] +pub enum JOB_STATE { + JNONE = -1, + JRUNNING = 1, + JSTOPPED = 2, + JDEAD = 4, + JMIXED = 8 +} + +#[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)] +pub struct PROCESS { + next: *mut PROCESS, + pid:libc::c_int, + status:libc::c_int, + running:libc::c_int, + command:*mut c_char +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:libc::c_int, + flags:libc::c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:libc::c_int, + line:libc::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:libc::c_int +} + +#[repr(C)] +pub struct case_com { + flags:libc::c_int, + line:libc::c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:libc::c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:libc::c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:libc::c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:libc::c_int +} + +#[repr(C)] +pub struct simple_com { + flags:libc::c_int, + line:libc::c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:libc::c_int, + line:libc::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:libc::c_int, + line:libc::c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:libc::c_int, + line:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:libc::c_int, + line:libc::c_int, + type_c:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:libc::c_int, + line:libc::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 +} + +#[repr(C)] +pub struct JOB { + wd: *mut c_char, + pipe: *mut PROCESS, + pgrp:i32, + state:JOB_STATE, + flags:i32, + deferred:*mut COMMAND, + j_cleanup:*mut fn(), + cleanarg:* mut fn() +} + +#[repr(C)] +pub struct SHELL_VAR { + name:*mut c_char, + value:*mut c_char, + exportstr:*mut c_char, + dynamic_value:*mut fn(v:* mut SHELL_VAR)->*mut SHELL_VAR, + assign_func:* mut fn(v:* mut SHELL_VAR,str1:* mut c_char,t:c_long,str2:* mut c_char)->*mut SHELL_VAR, + attributes:i32, + context:i32 +} + +#[repr(C)] +pub struct GENERIC_LIST { + next: * mut GENERIC_LIST +} + +#[repr(C)] +pub struct REPL { + next: *mut REPL, + pat:*mut c_char, + rep:*mut c_char +} + +#[repr(C)] +pub struct HIST_ENTRY { + line:*mut c_char, + timestamp:*mut c_char, + data:*mut fn() +} + +#[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! ISHELP { + ($s:expr) => { + libc::strcmp($s as *const c_char,CString::new("--help").unwrap().as_ptr()) + } +} + +#[macro_export] +macro_rules! errno { + () => { + *libc::__errno_location() + } +} + +#[macro_export] +macro_rules! HN_LISTING { + () => { + 0x01 + } +} + +#[macro_export] +macro_rules! SUBSHELL_COMSUB { + () => { + 0x04 + } +} + +#[macro_export] +macro_rules! HN_FIRST { + () => { + 0x02 + } +} + +#[macro_export] +macro_rules! HIST_INVALID { + () => { + std::i32::MIN + } +} + +#[macro_export] +macro_rules! HIST_ERANGE { + () => { + std::i32::MIN +1 + } +} + +#[macro_export] +macro_rules! HIST_NOTFOUND { + () => { + std::i32::MIN +2 + } +} + +#[macro_export] +macro_rules! MT_USETMPDIR { + () => { + 0x0001 + } +} + +#[macro_export] +macro_rules! MT_READWRITE { + () => { + 0x0002 + } +} + +#[macro_export] +macro_rules! MT_USERANDOM { + () => { + 0x0004 + } +} + +#[macro_export] +macro_rules! MT_TEMPLATE { + () => { + 0x0008 + } +} + +#[macro_export] +macro_rules! SEVAL_NOHIST { + () => { + 0x004 + } +} + +pub union Functions { + f_unlink:unsafe extern "C" fn(t: * const c_char)->i32, + f_xfree:unsafe extern "C" fn(str1:* mut c_void), + f_set_verbose: unsafe extern "C" fn(), +} + +extern "C" { + fn reset_internal_getopt(); + static mut loptend:*mut WORD_LIST; + static mut lcurrent:*mut WORD_LIST; + fn legal_number (str1:*const c_char,result:* mut c_long)->i32; + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + static list_optarg:*mut c_char; + fn builtin_usage(); + fn history_list ()->*mut * mut HIST_ENTRY; + static subshell_environment:i32; + fn sh_erange (s:* mut c_char, desc:* mut c_char); + fn builtin_error(err:*const c_char,...); + fn bash_delete_last_history ()->i32; + fn list_reverse (list:* mut GENERIC_LIST)->* mut GENERIC_LIST; + fn strsub (str1:*mut c_char, pat:*mut c_char, rep:*mut c_char, global:i32)->* mut c_char; + fn maybe_add_history (line:* mut c_char); + static mut hist_last_line_added:i32; + static mut remember_on_history:i32; + static mut enable_history_list:i32; + fn sh_mktmpfp (nameroot:* mut c_char, flags:i32, namep:&mut * mut c_char)->* mut libc::FILE; + fn strerror(e:i32)->* mut c_char; + static mut interrupt_state:i32; + static mut terminating_signal:i32; + fn termsig_handler (sig:i32); + fn throw_to_top_level(); + static mut history_base:i32; + static mut posixly_correct:i32; + fn sh_chkwrite (s:i32)->i32; + fn sh_wrerror (); + fn parse_and_execute (str1:* mut c_char, from_file:* const c_char, flags:i32)->i32; + fn unlink (path:* const c_char)->i32; + fn begin_unwind_frame (be:* mut c_char); + fn xfree (str1:* mut c_void); + fn add_unwind_protect(f:Functions,args:* mut c_char); + fn unwind_protect_mem (x:* mut c_char, s:i32); + static mut suppress_debug_trap_verbose:i32; + fn fc_execute_file (filename:*const c_char)->i32; + fn run_unwind_frame (filename:* mut c_char); + static mut echo_input_at_read:i32; + static mut verbose_flag:i32; +} + +#[no_mangle] +pub extern "C" fn r_set_verbose_flag (){ + unsafe { + echo_input_at_read = verbose_flag; + } +} + +#[no_mangle] +pub extern "C" fn r_fc_number (list:* mut WORD_LIST)->i32 +{ + let mut s:*mut c_char; + + if list == std::ptr::null_mut(){ + return 0; + } + + unsafe { + s = (*(*list).word).word; + if char::from(*s as u8 ) == '-' { + s=(s as u8 +1) as *mut c_char; + } + return legal_number (s, std::ptr::null_mut()); + } +} + +unsafe fn savestring(x:* mut c_char)->* mut c_char +{ + let str1:* mut c_char=libc::malloc(1 + libc::strlen (x as * const c_char)) as * mut c_char; + return libc::strcpy(str1,x as * const c_char); +} + +unsafe fn REVERSE_LIST(list:* mut GENERIC_LIST)->* mut REPL +{ + if list != std::ptr::null_mut() && (*list).next != std::ptr::null_mut(){ + list_reverse(list) as * mut REPL + } else { + list as * mut REPL + } +} + +unsafe fn printToStderr(str:* mut c_char) -> std::io::Result<()> { + let stderr = std::io::stderr(); + let mut handle = stderr.lock(); + handle.write_all(std::ffi::CStr::from_ptr(str).to_bytes())?; + Ok(()) +} + +unsafe fn printToStdout(str:* mut c_char) -> std::io::Result<()> { + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(std::ffi::CStr::from_ptr(str).to_bytes())?; + Ok(()) +} + +unsafe fn printToStdoutflush() -> std::io::Result<()> { + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.flush()?; + Ok(()) +} + +unsafe fn QUIT () +{ + if terminating_signal !=0 { + termsig_handler (terminating_signal); + } + + if interrupt_state !=0{ + throw_to_top_level (); + } +} + +unsafe fn DIGIT ( c: c_char)->bool { + char::from(c as u8) >= '0' && char::from(c as u8) <= '9' +} + +unsafe fn STREQN ( a:* const c_char, b:* const c_char, n:i32)->bool { + if n==0 { + return true; + } else { + return *a == *b && libc::strncmp(a, b, n as libc::size_t) == 0 + } +} + +#[no_mangle] +pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 +{ + let mut i:i32; + let mut sep:*mut c_char; + let mut numbering:i32; + let mut reverse:i32; + let mut listing:i32; + let mut execute:i32; + let mut histbeg:i32; + let mut histend:i32; + let mut last_hist:i32; + let mut retval:i32; + let mut opt:i32; + let rh:i32; + let mut real_last:i32; + let stream:* mut libc::FILE; + let mut rlist:*mut REPL; + let mut rl:*mut REPL; + let mut ename:*mut c_char; + let mut command:*mut c_char; + let newcom:*mut c_char; + let fcedit: std::ffi::CString; + let hlist:*mut*mut HIST_ENTRY; + let mut fnc:*mut c_char=std::ptr::null_mut(); + + numbering = 1; + reverse = 0; + listing = 0; + execute = 0; + ename = std::ptr::null_mut(); + unsafe { + reset_internal_getopt (); + lcurrent = list; + + loptend = lcurrent; + let mut ret:bool=r_fc_number (loptend) ==0; + opt = internal_getopt (list, CString::new(":e:lnrs").unwrap().as_ptr() as * mut c_char); + ret= ret && (opt !=-1); + while ret { + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'n'=>{numbering=0;} + 'l'=>{listing = HN_LISTING!();} + 'r'=>{reverse = 1;} + 's'=>{execute = 1;} + 'e'=>{ename = list_optarg;} + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + loptend = lcurrent; + let mut ret:bool=r_fc_number (loptend) ==0; + opt = internal_getopt (list, CString::new(":e:lnrs").unwrap().as_ptr() as * mut c_char); + ret= ret && (opt !=-1); + } + + let mut llist:* mut WORD_LIST = loptend.clone(); + + if ename != std::ptr::null_mut() && char::from(*ename as u8 ) == '-' && char::from(*((ename as usize +4) as * mut c_char) as u8 )== '\0'{ + execute = 1; + } + + if execute != 0 { + rlist = std::ptr::null_mut(); + + let mut ret:bool=loptend !=std::ptr::null_mut(); + sep= libc::strchr((*(*llist).word).word, char::from('=') as libc::c_int); + ret=ret && sep != std::ptr::null_mut(); + while ret { + sep= (sep as usize + 4) as * mut c_char; + *sep = char::from('\0') as c_char ; + rl = libc::malloc ( std::mem::size_of::<& REPL>() ) as * mut REPL; + (*rl).next = std::ptr::null_mut(); + (*rl).pat = savestring ((*(*llist).word).word); + (*rl).rep = savestring (sep); + + if rlist == std::ptr::null_mut(){ + rlist = rl; + } else { + (*rl).next = rlist; + rlist = rl; + } + llist = (*llist).next; + } + + rlist = REVERSE_LIST (rlist as * mut GENERIC_LIST); + hlist = history_list (); + if llist != std::ptr::null_mut() { + command=r_fc_gethist((*(*llist).word).word, hlist, 0); + } else { + command=r_fc_gethist(std::ptr::null_mut(), hlist, 0); + } + + if command == std::ptr::null_mut() { + builtin_error (CString::new("no command found").unwrap().as_ptr()); + if rlist !=std::ptr::null_mut() { + rl = rlist; + while rl != std::ptr::null_mut() { + let r:*mut REPL; + r = (*rl).next; + if (*rl).pat !=std::ptr::null_mut() { + libc::free((*rl).pat as * mut c_void); + } + + if (*rl).rep !=std::ptr::null_mut() { + libc::free((*rl).rep as * mut c_void); + } + + libc::free(rl as * mut c_void); + rl = r; + } + } + return EXECUTION_FAILURE!(); + } + + if rlist !=std::ptr::null_mut() { + newcom = r_fc_dosubs (command, rlist); + libc::free (command as * mut c_void); + rl = rlist; + while rl != std::ptr::null_mut() { + let r:* mut REPL; + r = (*rl).next; + if (*rl).pat !=std::ptr::null_mut() { + libc::free((*rl).pat as * mut c_void); + } + + if (*rl).rep !=std::ptr::null_mut() { + libc::free((*rl).rep as * mut c_void); + } + + libc::free(rl as * mut c_void); + rl = r; + } + command = newcom; + } + printToStderr(command); + r_fc_replhist (command); + return parse_and_execute (command, CString::new("fc").unwrap().as_ptr(), SEVAL_NOHIST!()); + } + + hlist = history_list (); + if hlist == std::ptr::null_mut(){ + return EXECUTION_SUCCESS!(); + } + i=0; + while *((hlist as usize +(8*i) as usize) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { + i+=1; + } + + rh = (remember_on_history !=0 || ((subshell_environment & SUBSHELL_COMSUB!()) !=0 && enable_history_list !=0)) as i32; + last_hist = i - rh - hist_last_line_added; + + real_last = i; + while *((hlist as usize +(8*real_last) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() && real_last > 0 + { + real_last-=1; + } + + if i == last_hist && *((hlist as usize + (8*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + while last_hist >= 0 && *((hlist as usize + (8*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() + { + last_hist-=1; + } + } + + if last_hist < 0{ + last_hist = 0; + } + + if llist != std::ptr::null_mut() { + histbeg = r_fc_gethnum ((*(*llist).word).word, hlist, listing| HN_FIRST!()); + llist = (*llist).next; + + if list != std::ptr::null_mut(){ + histend = r_fc_gethnum ((*(*list).word).word, hlist, listing); + } else if histbeg == real_last { + if listing >0 { + histend=real_last; + }else { + histend=histbeg; + } + } else { + if listing >0 { + histend=last_hist; + }else { + histend=histbeg; + } + } + } else { + if listing > 0 { + histend = last_hist; + histbeg = histend - 16 + 1; + if histbeg < 0{ + histbeg = 0; + } + } else{ + histbeg =last_hist; + histend =last_hist; + } + } + + if histbeg == HIST_INVALID!() || histend == HIST_INVALID!() { + sh_erange (std::ptr::null_mut(), CString::new("history specification").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } else if histbeg == HIST_ERANGE!() || histend == HIST_ERANGE!() { + sh_erange (std::ptr::null_mut(), CString::new("history specification").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } else if histbeg == HIST_NOTFOUND!() || histend == HIST_NOTFOUND!() { + builtin_error (CString::new("no command found").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } + + if histbeg < 0 { + histbeg = 0; + } + + if histend < 0 { + histend = 0; + } + + if listing == 0 && hist_last_line_added !=0 { + bash_delete_last_history (); + + if histbeg == histend && histend == last_hist && *((hlist as usize + (8*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + histend-=1; + last_hist = histend; + histbeg = histend; + } + + if *((hlist as usize + (8*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + last_hist-=1; + } + + if histend >= last_hist { + histend = last_hist; + } else if histbeg >= last_hist { + histbeg = last_hist; + } + } + + if histbeg == HIST_INVALID!() || histend == HIST_INVALID!() { + sh_erange (std::ptr::null_mut(), CString::new ("history specification").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } else if histbeg == HIST_ERANGE!() || histend == HIST_ERANGE!() { + sh_erange (std::ptr::null_mut(), CString::new ("history specification").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } else if histbeg == HIST_NOTFOUND!() || histend == HIST_NOTFOUND!() { + builtin_error (CString::new ("no command found").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + + if histbeg < 0 { + histbeg = 0; + } + + if histend < 0{ + histend = 0; + } + + if histend < histbeg { + i = histend; + histend = histbeg; + histbeg = i; + reverse = 1; + } + + if listing !=0{ + stream = std::ptr::null_mut(); + } else { + numbering = 0; + stream = sh_mktmpfp (CString::new ("bash-fc").unwrap().as_ptr() as * mut c_char, MT_USERANDOM!()|MT_USETMPDIR!(), &mut fnc); + + if stream == std::ptr::null_mut() { + if fnc != std::ptr::null_mut() { + builtin_error (CString::new ("%s: cannot open temp file: %s").unwrap().as_ptr(), fnc , strerror (errno!())); + } else { + builtin_error (CString::new ("%s: cannot open temp file: %s").unwrap().as_ptr(), CString::new ("").unwrap().as_ptr(), strerror (errno!())); + } + + libc::free(fnc as * mut c_void); + return EXECUTION_FAILURE!(); + } + } + + if reverse !=0{ + i=histend; + }else { + i=histbeg; + } + + let mut ret:bool=reverse !=0; + + if ret { + ret =i >= histbeg ; + } else { + ret = i <= histend; + } + + while ret { + QUIT(); + if numbering != 0 { + if stream != std::ptr::null_mut(){ + libc::fprintf (stream, CString::new ("%d").unwrap().as_ptr(), i + history_base); + }else { + let diff =i + history_base; + printToStdout(CString::new (diff.to_string()).unwrap().as_ptr() as * mut c_char ); + } + } + + if listing !=0 { + if posixly_correct !=0 { + if stream != std::ptr::null_mut(){ + libc::fputs (CString::new ("\t").unwrap().as_ptr(), stream); + } else { + printToStdout(CString::new ("\t").unwrap().as_ptr() as * mut c_char ); + } + } else { + let mut ch:char; + if (**((hlist as usize + (8*i) as usize) as *mut*mut HIST_ENTRY)).data != std::ptr::null_mut() { + ch='*'; + } else { + ch=' '; + } + + if stream != std::ptr::null_mut() { + libc::fprintf (stream, CString::new ("\t%c").unwrap().as_ptr(), & mut ch); + }else { + let mut th=vec!['\t' as c_char]; + th.push(ch as c_char); + th.push(0); + printToStdout( th.as_ptr() as * mut c_char); + } + } + } + + if stream != std::ptr::null_mut() { + libc::fprintf (stream, CString::new ("%s\n").unwrap().as_ptr(), (**((hlist as usize + (i*8) as usize) as *mut*mut HIST_ENTRY)).line); + }else { + printToStdout((**((hlist as usize + (i*8) as usize) as *mut*mut HIST_ENTRY)).line); + } + + ret=reverse !=0; + if ret { + i-=1; + } else { + i+=1; + } + + if ret { + ret =i >= histbeg; + } else { + ret =i <= histend; + } + } + + if listing !=0 { + return sh_chkwrite (EXECUTION_SUCCESS!()); + } + + if stream != std::ptr::null_mut() { + libc::fflush (stream); + if libc::ferror (stream) !=0 { + sh_wrerror (); + libc::fclose (stream); + libc::free(fnc as * mut c_void); + return EXECUTION_FAILURE!(); + } + libc::fclose (stream); + } else { + if printToStdoutflush().is_err() { + sh_wrerror (); + libc::free(fnc as * mut c_void); + return EXECUTION_FAILURE!(); + } + } + + /* Now edit the file of commands. */ + if ename != std::ptr::null_mut() { + command=libc::malloc ( libc::strlen (ename) + libc::strlen (fnc) + 2 ) as * mut c_char; + libc::sprintf(command,CString::new("").unwrap().as_ptr()); + libc::strcpy(command,ename); + libc::strcat(command,CString::new(" ").unwrap().as_ptr()); + libc::strcat(command,fnc); + } else { + if posixly_correct !=0 { + fcedit=CString::new("${FCEDIT:-${EDITOR:-ed}}").unwrap(); + } else { + fcedit=CString::new("${FCEDIT:-${EDITOR:-vi}}").unwrap(); + } + + command=libc::malloc ( 3 + libc::strlen(fcedit.as_ptr()) as libc::size_t + libc::strlen (fnc) ) as * mut c_char; + libc::sprintf(command,CString::new("").unwrap().as_ptr()); + libc::strcpy(command,fcedit.as_ptr()); + libc::strcat(command,CString::new(" ").unwrap().as_ptr()); + libc::strcat(command,fnc); + } + + retval = parse_and_execute (command, CString::new("fc").unwrap().as_ptr(), SEVAL_NOHIST!()); + if retval != EXECUTION_SUCCESS!() { + unlink (fnc); + libc::free (fnc as * mut c_void); + return EXECUTION_FAILURE!(); + } + + /* Make sure parse_and_execute doesn't turn this off, even though a + call to parse_and_execute farther up the function call stack (e.g., + if this is called by vi_edit_and_execute_command) may have already + called bash_history_disable. */ + remember_on_history = 1; + + /* Turn on the `v' flag while fc_execute_file runs so the commands + will be echoed as they are read by the parser. */ + //begin_unwind_frame (CString::new ("fc builtin").unwrap().as_ptr() as * mut c_char); + let xf:Functions=Functions{f_xfree :xfree}; + let uk:Functions=Functions{f_unlink :unlink}; + let r_flag:Functions=Functions{f_set_verbose :r_set_verbose_flag}; + add_unwind_protect (xf, fnc); + add_unwind_protect (uk, fnc); + add_unwind_protect (r_flag, std::ptr::null_mut()); + unwind_protect_mem ((& mut (suppress_debug_trap_verbose as c_char) ) as * mut c_char,4); + echo_input_at_read = 1; + suppress_debug_trap_verbose = 1; + + retval = fc_execute_file (fnc); + //run_unwind_frame (CString::new ("fc builtin").unwrap().as_ptr() as * mut c_char); + + return retval; +} +} + +#[no_mangle] +pub extern "C" fn r_fc_gethist (command:* mut c_char, hlist:* mut * mut HIST_ENTRY, mode:i32)->* mut c_char +{ + let mut i:i32; + + if hlist == std::ptr::null_mut() { + return std::ptr::null_mut(); + } + + i = r_fc_gethnum (command, hlist, mode); + unsafe { + if i >= 0 { + return savestring ((*(*((hlist as usize + (8*i) as usize) as * mut * mut HIST_ENTRY))).line ); + } else { + return std::ptr::null_mut(); + } + } +} + +#[no_mangle] +pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENTRY, mode:i32)->i32 +{ + let mut sign:i32; + let mut n:i32; + let mut clen:i32; + let mut rh:i32; + let mut i:i32=0; + let mut j:i32; + let mut last_hist:i32; + let mut real_last:i32; + let mut listing:i32; + + let mut s:* mut c_char; + + unsafe { + listing = mode & HN_LISTING!(); + sign = 1; + /* Count history elements. */ + while *((hlist as usize + (8*i) as usize ) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { + i+=1; + } + + /* With the Bash implementation of history, the current command line + ("fc blah..." and so on) is already part of the history list by + the time we get to this point. This just skips over that command + and makes the last command that this deals with be the last command + the user entered before the fc. We need to check whether the + line was actually added (HISTIGNORE may have caused it to not be), + so we check hist_last_line_added. This needs to agree with the + calculation of last_hist in fc_builtin above. */ + /* Even though command substitution through parse_and_execute turns off + remember_on_history, command substitution in a shell when set -o history + has been enabled (interactive or not) should use it in the last_hist + calculation as if it were on. */ + rh = (remember_on_history !=0 || ((subshell_environment & SUBSHELL_COMSUB!()) !=0 && enable_history_list !=0)) as i32; + last_hist = i - rh - hist_last_line_added; + + if i == last_hist && *((hlist as usize + (8*last_hist) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + while last_hist >= 0 && *((hlist as usize + (8*last_hist) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut(){ + last_hist-=1; + } + } + + if last_hist < 0 { + return -1; + } + + real_last = i; + i = last_hist; + + /* No specification defaults to most recent command. */ + if command == std::ptr::null_mut(){ + return i; + } + + /* back up from the end to the last non-null history entry */ + while *((hlist as usize + (8*real_last) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() && real_last > 0 { + real_last-=1; + } + + /* Otherwise, there is a specification. It can be a number relative to + the current position, or an absolute history number. */ + s = command; + + /* Handle possible leading minus sign. */ + if s != std::ptr::null_mut() && ( char::from(*s as u8) != '-') { + sign = -1; + s = (s as usize +4) as * mut c_char; + } + + if s != std::ptr::null_mut() && DIGIT( *s ) { + n = std::ffi::CStr::from_ptr(s).to_str().unwrap().parse::().unwrap(); + n *= sign; + + /* We want to return something that is an offset to HISTORY_BASE. */ + /* If the value is negative or zero, then it is an offset from + the current history item. */ + /* We don't use HN_FIRST here, so we don't return different values + depending on whether we're looking for the first or last in a + pair of range arguments, but nobody else does, either. */ + if n < 0 { + n += i + 1; + if n < 0 { + return 0; + } else { + return n; + } + } else if n == 0 { + if sign == -1 { + if listing > 0 { + return real_last; + } else { + return HIST_INVALID!(); + } + } else { + return i; + } + } else { + /* If we're out of range (greater than I (last history entry) or + less than HISTORY_BASE, we want to return different values + based on whether or not we are looking for the first or last + value in a desired range of history entries. */ + n -= history_base; + if n < 0 { + if mode & HN_FIRST!() !=0 { + return 0; + } else{ + return i; + } + } else if n >= i { + if mode & HN_FIRST!() !=0 { + return 0; + } else{ + return i; + } + } else { + return n; + } + } + } + + clen = libc::strlen (command as * const c_char) as i32; + j = i; + while j >= 0 { + if STREQN (command, (*(*((hlist as usize + (8*j) as usize ) as * mut * mut HIST_ENTRY))).line, clen) { + return j; + } + j-=1; + } + return HIST_NOTFOUND!(); + } +} + +#[no_mangle] +pub extern "C" fn r_fc_dosubs (command:* mut c_char, subs:* mut REPL)->* mut c_char +{ + let mut new:* mut c_char; + let mut t:* mut c_char; + let mut r:* mut REPL; + unsafe { + new = savestring (command); + while subs !=std::ptr::null_mut() { + r = subs; + t = strsub (new, (*r).pat, (*r).rep, 1); + r = (*r).next; + libc::free(new as * mut c_void); + new = t; + } + return new; + } +} + +#[no_mangle] +pub extern "C" fn r_fc_replhist (command:* mut c_char) +{ + let n:i32; + unsafe { + if command == std::ptr::null_mut() || char::from(*command as u8)== '\0' { + return; + } + + n = libc::strlen (command as * const c_char) as i32; + if char::from(*((command as usize + 4*(n-1) as usize) as *mut c_char) as u8) == '\n' { + *((command as usize + 4*(n-1) as usize ) as *mut c_char)= 0 as c_char; + } + + if command != std::ptr::null_mut() && (*command) != 0 { + bash_delete_last_history (); + maybe_add_history (command); + } + } +} + +#[no_mangle] +pub extern "C" fn fc_addhist (line: * mut c_char) +{ + let n:i32; + unsafe { + if line == std::ptr::null_mut() || *line == 0 { + return; + } + + n = libc::strlen (line) as i32; + + if *((line as usize + (n-1) as usize) as * mut c_char) == '\n' as c_char { + *((line as usize + (n-1) as usize) as * mut c_char) = '\0' as c_char; + } + + if line != std::ptr::null_mut() && *line != 0 { + maybe_add_history (line); + } + } +} + +#[no_mangle] +pub extern "C" fn fc_readline (stream:* mut libc::FILE)->* mut c_char +{ + let mut c:i32; + let mut line_len:i32 = 0; + let mut lindex:i32 = 0; + let mut line:* mut c_char = std::ptr::null_mut(); + unsafe { + c = libc::fgetc (stream); + while c != libc::EOF { + if (lindex + 2) >= line_len { + line_len += 128; + line = libc::malloc ( line_len as libc::size_t) as * mut c_char; + } + + if c == '\n' as i32 { + *((line as usize + (4*lindex) as usize) as * mut c_char)='\n' as c_char; + lindex+=1; + *((line as usize + (4*lindex) as usize) as * mut c_char)='\0' as c_char; + lindex+=1; + return line; + } else { + *((line as usize + (4*lindex) as usize) as * mut c_char)=c as c_char; + lindex+=1; + } + + c = libc::fgetc (stream); + } + + if lindex ==0 { + if line != std::ptr::null_mut() { + libc::free(line as * mut c_void); + } + return std::ptr::null_mut(); + } + + if lindex + 2 >= line_len { + line = libc::malloc((lindex + 3) as libc::size_t) as * mut c_char; + } + + *((line as usize + (4*lindex) as usize) as * mut c_char)='\n' as c_char; + lindex+=1; + *((line as usize + (4*lindex) as usize) as * mut c_char)='\0' as c_char; + lindex+=1; + + return line; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"fc" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_fc_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/fg_bg/Cargo.toml b/bash-5.1/builtins_rust/fg_bg/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..74b94d65e035b5d70545dcb69093062ca56cfb68 100644 --- a/bash-5.1/builtins_rust/fg_bg/Cargo.toml +++ b/bash-5.1/builtins_rust/fg_bg/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rfg_bg" +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 = "rfg_bg" diff --git a/bash-5.1/builtins_rust/fg_bg/src/lib.rs b/bash-5.1/builtins_rust/fg_bg/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..689f42d8aaec91ca5c80b790473a884232dd233c 100644 --- a/bash-5.1/builtins_rust/fg_bg/src/lib.rs +++ b/bash-5.1/builtins_rust/fg_bg/src/lib.rs @@ -0,0 +1,520 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long}; +use std::{ffi::CString, ops::Add}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(i8)] +pub enum JOB_STATE { + JNONE = -1, + JRUNNING = 1, + JSTOPPED = 2, + JDEAD = 4, + JMIXED = 8 +} + +#[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)] +pub struct PROCESS { + next: *mut PROCESS, + pid:libc::c_int, + status:libc::c_int, + running:libc::c_int, + command:*mut c_char +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:libc::c_int, /* Place to redirect REDIRECTOR to, or ... */ + filename:* mut WORD_DESC /* filename to redirect to. */ +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, /* Next element, or NULL. */ + redirector:REDIRECTEE, /* Descriptor or varname to be redirected. */ + rflags:libc::c_int, /* Private flags for this redirection */ + flags:libc::c_int, /* Flag value for `open'. */ + instruction:r_instruction, /* What to do with the information. */ + redirectee:REDIRECTEE, /* File descriptor or filename */ + here_doc_eof:*mut c_char /* The word that appeared in < {1} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! EXECUTION_SUCCESS { + () => {0} +} + +#[macro_export] +macro_rules! BLOCK_SIGNAL { + ($sig:expr, $nvar:expr, $ovar:expr) => { + $nvar.unwrap().clear(); + $nvar.unwrap().add($sig); + $nvar.unwrap().clear(); + nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_BLOCK, $nvar, $ovar); + } +} + +#[macro_export] +macro_rules! UNBLOCK_SIGNAL { + ($ovar:expr) => { + nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_SETMASK, $ovar, None) + } +} + +#[macro_export] +macro_rules! UNBLOCK_CHILD { + ($ovar:expr) => { + UNBLOCK_SIGNAL!($ovar); + } +} + +#[macro_export] +macro_rules! BLOCK_CHILD { + ($nvar:expr,$ovar:expr) => { + BLOCK_SIGNAL!(nix::sys::signal::SIGCHLD, $nvar, $ovar); + } +} + +#[macro_export] +macro_rules! DUP_JOB { + () => {-2} +} + +#[macro_export] +macro_rules! get_job_by_jid { + ($ind:expr) => { + (*(((jobs as usize) + ($ind*8) as usize ) as *mut*mut JOB) as *mut JOB) + } +} + +#[macro_export] +macro_rules! J_JOBCONTROL { + () => {0x04} +} + +#[macro_export] +macro_rules! IS_JOBCONTROL { + ($j:expr) => { + ((*get_job_by_jid!($j)).flags & J_JOBCONTROL!()) != 0 + } +} + +#[macro_export] +macro_rules! INVALID_JOB { + ($j:expr) => { + $j <0 || $j >= js.j_jobslots || get_job_by_jid !($j) == std::ptr::null_mut() + } +} + +#[macro_export] +macro_rules! ISHELP { + ($s:expr) => { + libc::strcmp($s as *const c_char,CString::new("--help").unwrap().as_ptr()) + } +} + +#[macro_export] +macro_rules! CHECK_HELPOPT { + ($l:expr) => { + if $l !=std::ptr::null_mut() && (*$l).word !=std::ptr::null_mut() && ISHELP!((*(*$l).word).word) == 0 { + builtin_help (); + return EX_USAGE!(); + } + } +} + +extern "C" { + fn builtin_error(err:*const c_char,...); + fn get_job_spec (list:*mut WORD_LIST)->i32; + fn sh_badjob (str:*mut c_char); + static jobs:*mut*mut JOB; + static js:jobstats ; + + static mut loptend:*mut WORD_LIST; + fn sh_nojobs (str:*mut c_char); + fn no_options (list:*mut WORD_LIST)->i32; + fn builtin_help (); + static mut job_control:i32; + static mut last_asynchronous_pid:i32; + fn start_job (job:i32, foreground:i32)->i32; +} + +/* How to bring a job into the foreground. */ +#[no_mangle] +pub extern "C" fn r_fg_builtin (list:*mut WORD_LIST)->i32 { + let fg_bit:i32; + unsafe { + CHECK_HELPOPT! (list); + + if job_control == 0 { + sh_nojobs (0 as *mut c_char); + return EXECUTION_FAILURE!(); + } + + if no_options (list) !=0 { + return EX_USAGE!(); + } + + /* If the last arg on the line is '&', then start this job in the + background. Else, fg the job. */ + + if loptend == std::ptr::null_mut() { + return r_fg_bg (loptend, 1); + } else { + let mut t:WORD_LIST=*loptend; + while t.next !=std::ptr::null_mut() { + t=*(t.next); + } + let cstr:&std::ffi::CStr=std::ffi::CStr::from_ptr((*(t.word)).word ); + let mut isfg:bool=char::from( cstr.to_bytes()[0] ) == '&'; + isfg =isfg && char::from( cstr.to_bytes()[1]) == '\0'; + isfg = isfg ==false; + if isfg { + fg_bit=1; + } else { + fg_bit=0; + } + return r_fg_bg (loptend, fg_bit); + } + } +} + +/* How to put a job into the background. */ +#[no_mangle] +pub extern "C" fn r_bg_builtin (list:*mut WORD_LIST)->i32 { + let mut r:i32; + unsafe { + CHECK_HELPOPT !(list); + + if job_control == 0 { + sh_nojobs (0 as *mut c_char); + return EXECUTION_FAILURE!(); + } + + if no_options (list) !=0 { + return EX_USAGE!(); + } + + /* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts + on the first member (if any) of that list. */ + r = EXECUTION_SUCCESS!(); + + if r_fg_bg(loptend,0) == EXECUTION_FAILURE!() { + r = EXECUTION_FAILURE!(); + } + + if loptend !=std::ptr::null_mut() { + let mut t:WORD_LIST=*loptend; + while t.next !=std::ptr::null_mut() { + if r_fg_bg (&mut t, 0) == EXECUTION_FAILURE!() { + r = EXECUTION_FAILURE!(); + } + t = *(t.next); + } + return r; + } else { + return r; + } + } +} + +/* How to put a job into the foreground/background. */ +#[no_mangle] +pub extern "C" fn r_fg_bg (list:*mut WORD_LIST, foreground:i32)->i32{ + + let mut set:nix::sys::signal::SigSet=nix::sys::signal::SigSet::empty(); + let mut oset:nix::sys::signal::SigSet =nix::sys::signal::SigSet::empty(); + let job:i32; + let status:i32; + let mut old_async_pid:i32=0; + let j:*mut JOB; + + unsafe { + BLOCK_CHILD !(Some(&mut set), Some(&mut oset)); + job = get_job_spec (list); + + if INVALID_JOB !(job) { + if job != DUP_JOB!() { + if list != std::ptr::null_mut() { + sh_badjob ( (*(*list).word).word ); + } else { + let mut c_str_current = CString::new("current").unwrap(); // from a &str, creates a new allocation + sh_badjob (c_str_current.as_ptr() as * mut c_char); + } + } + + UNBLOCK_CHILD !(Some(&oset)); + return EXECUTION_FAILURE!(); + } + + j = get_job_by_jid !(job); + /* Or if j->pgrp == shell_pgrp. */ + if ! IS_JOBCONTROL !(job) { + let jobNum:i32=job + 1; + builtin_error ( String::from("job ").add(&jobNum.to_string()).add(&String::from("started without job control").to_string()).as_ptr() as * const c_char); + UNBLOCK_CHILD !(Some(&oset)); + return EXECUTION_FAILURE!(); + } + + if foreground == 0 { + old_async_pid = i32::from(last_asynchronous_pid); + last_asynchronous_pid = i32::from((*j).pgrp); /* As per Posix.2 5.4.2 */ + } + + status = start_job (job, foreground); + + if status >= 0 { + /* win: */ + UNBLOCK_CHILD !(Some(&oset)); + if foreground !=0 { + return status; + } else { + return EXECUTION_SUCCESS!(); + } + } else { + if foreground == 0 { + last_asynchronous_pid = i32::from(old_async_pid); + } + + UNBLOCK_CHILD !(Some(&oset)); + return EXECUTION_FAILURE!(); + } + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"fg" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_fg_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/getopts/Cargo.toml b/bash-5.1/builtins_rust/getopts/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f0190df655efcf8899efefc555dab1a5e41090c3 100644 --- a/bash-5.1/builtins_rust/getopts/Cargo.toml +++ b/bash-5.1/builtins_rust/getopts/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rgetopts" +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 = "rgetopts" diff --git a/bash-5.1/builtins_rust/getopts/src/lib.rs b/bash-5.1/builtins_rust/getopts/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0cb4bee29cf21defa1165bcd8034e26314819f69 100644 --- a/bash-5.1/builtins_rust/getopts/src/lib.rs +++ b/bash-5.1/builtins_rust/getopts/src/lib.rs @@ -0,0 +1,558 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::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:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:libc::c_int, + flags:libc::c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:libc::c_int, + line:libc::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:libc::c_int +} + +#[repr(C)] +pub struct case_com { + flags:libc::c_int, + line:libc::c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:libc::c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:libc::c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:libc::c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:libc::c_int +} + +#[repr(C)] +pub struct simple_com { + flags:libc::c_int, + line:libc::c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:libc::c_int, + line:libc::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:libc::c_int, + line:libc::c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:libc::c_int, + line:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:libc::c_int, + line:libc::c_int, + type_c:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:libc::c_int, + line:libc::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 +} + +#[repr(C)] +pub struct SHELL_VAR { + name:*mut c_char, + value:*mut c_char, + exportstr:*mut c_char, + dynamic_value:*mut fn(v:* mut SHELL_VAR)->*mut SHELL_VAR, + assign_func:* mut fn(v:* mut SHELL_VAR,str1:* mut c_char,t:c_long,str2:* mut c_char)->*mut SHELL_VAR, + attributes:i32, + context:i32 +} + +#[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! EX_MISCERROR { + () => {2} +} + +#[macro_export] +macro_rules! att_readonly { + () => { + 0x0000002 /* cannot change */ + } +} + +#[macro_export] +macro_rules! att_noassign { + () => { + 0x0004000 /* assignment not allowed */ + } +} + +#[macro_export] +macro_rules! G_EOF { + () => { + -1 + } +} + +#[macro_export] +macro_rules! G_INVALID_OPT { + () => { + -2 + } +} + +#[macro_export] +macro_rules! G_ARG_MISSING { + () => { + -3 + } +} + +#[macro_export] +macro_rules! GETOPT_HELP { + () => { + -99 + } +} + +extern "C" { + fn unbind_variable_noref (name: * const c_char)->i32; + static mut sh_optind:i32; + static mut sh_badopt:i32; + fn legal_identifier (name: * const c_char)->i32; + fn bind_variable (name: * const c_char, value: * mut c_char, flags:i32)->* mut SHELL_VAR; + fn sh_invalidid(name:* mut c_char); + fn builtin_usage(); + static mut sh_opterr:i32; + fn sh_getopt_restore_state (argv:*mut*mut c_char); + static dollar_vars:[* mut c_char;10]; + fn sh_getopt (argc:i32, argv: * const*mut c_char, optstring: * const c_char)->i32; + static rest_of_args:* mut WORD_LIST; + fn number_of_args ()->i32; + fn strvec_create (i:i32)->*mut*mut c_char; + static sh_optarg:* mut c_char; + static sh_optopt:i32; + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + fn builtin_help (); + static mut loptend:*mut WORD_LIST; + fn make_builtin_argv (list:* mut WORD_LIST, ac:* mut i32)->*mut*mut c_char; +} + +/* getopts_reset is magic code for when OPTIND is reset. N is the + value that has just been assigned to OPTIND. */ +#[no_mangle] +pub extern "C" fn r_getopts_reset (newind:i32){ + unsafe { + sh_optind = newind; + sh_badopt = 0; + } +} + +#[no_mangle] +pub extern "C" fn r_getopts_unbind_variable (name:* mut c_char)->i32 { + unsafe { + return unbind_variable_noref (name); + } +} + +fn readonly_p(va:* mut SHELL_VAR)->i32 +{ + unsafe { + return (*va).attributes & att_readonly!(); + } +} + +fn noassign_p(va:* mut SHELL_VAR)->i32 +{ + unsafe { + return (*va).attributes & att_noassign!(); + } +} + +#[no_mangle] +pub extern "C" fn r_getopts_bind_variable(name:* mut c_char, value:* mut c_char)->i32 +{ + let v:* mut SHELL_VAR; + unsafe { + if legal_identifier(name) !=0 { + v = bind_variable(name, value, 0); + if v != std::ptr::null_mut() && (readonly_p(v) != 0 || noassign_p(v) != 0) { + return EX_MISCERROR!(); + } + + if v != std::ptr::null_mut() { + return EXECUTION_SUCCESS!(); + } else { + return EXECUTION_FAILURE!(); + } + + } else { + sh_invalidid(name); + return EXECUTION_FAILURE!(); + } + } +} + +#[no_mangle] +pub extern "C" fn r_dogetopts(argc:i32, argv:*mut*mut c_char)->i32 +{ + let mut ret:i32; + let special_error:i32; + let mut old_opterr:i32=0; + let mut i:i32; + let n:i32; + + let mut strval:[c_char;2]=[0;2]; + let mut numval:[c_char;16]=[0;16]; + let mut optstr: * mut c_char; /* list of options */ + let name: * mut c_char; /* variable to get flag val */ + let t:* mut c_char; + unsafe { + let mut argcc:i32=argc; + let mut argvv:*mut*mut c_char=argv; + if argcc < 3 { + builtin_usage(); + return EX_USAGE!(); + } + + /* argv[0] is "getopts". */ + optstr = *((argvv as usize +8) as *mut*mut c_char); + name = *((argvv as usize +16) as *mut*mut c_char); + argcc -= 2; + argvv = (argvv as usize +16) as *mut*mut c_char; + + if *optstr == ':' as c_char { + special_error = 1; + } else { + special_error = 0; + } + + if special_error != 0 { + old_opterr = sh_opterr; + optstr=(optstr as usize + 4) as * mut c_char; + sh_opterr = 0; /* suppress diagnostic messages */ + } + + if argcc > 1 { + sh_getopt_restore_state(&mut(*argvv)); + t = *argvv; + *argvv = dollar_vars[0]; + ret = sh_getopt(argcc, argvv, optstr); + *argvv = t; + } else if rest_of_args == std::ptr::null_mut() { + i=0; + while i < 10 && dollar_vars[i as usize] != std::ptr::null_mut() { + i+=1; + } + + sh_getopt_restore_state(&mut (dollar_vars[0] as * mut c_char)); + ret = sh_getopt(i, &dollar_vars[0], optstr); + } else { + let mut words: * mut WORD_LIST; + let v:*mut*mut c_char; + + i = number_of_args() + 1; /* +1 for $0 */ + v = strvec_create(i + 1); + i=0; + while i < 10 && dollar_vars[i as usize] !=std::ptr::null_mut() { + *((v as usize +8*i as usize) as *mut*mut c_char) = dollar_vars[i as usize]; + i+=1; + } + + words = rest_of_args; + while words != std::ptr::null_mut() { + *((v as usize +8*i as usize) as *mut*mut c_char) = (*(*words).word).word; + words = (*words).next; + i+=1; + } + + *((v as usize +8*i as usize) as *mut*mut c_char) = std::ptr::null_mut(); + sh_getopt_restore_state(&mut(*v)); + ret = sh_getopt(i, v, optstr); + libc::free(v as * mut c_void); + } + + if special_error !=0 { + sh_opterr = old_opterr.clone(); + } + + /* Set the OPTIND variable in any case, to handle "--" skipping. It's + highly unlikely that 14 digits will be too few. */ + if sh_optind < 10 { + numval[14] = sh_optind as c_char+ '0' as c_char; + numval[15] = '\0' as c_char; + i = 14; + } else { + i=15; + numval[15] = '\0' as c_char; + n = sh_optind; + + i-=1; + numval[i as usize] = (n % 10) as c_char + '0' as c_char; + while n / 10 != 0 { + i-=1; + numval[i as usize] = (n % 10) as c_char + '0' as c_char; + } + } + + bind_variable(CString::new ("OPTIND").unwrap().as_ptr(), & mut numval[i as usize], 0); + + /* If an error occurred, decide which one it is and set the return + code appropriately. In all cases, the option character in error + is in OPTOPT. If an invalid option was encountered, OPTARG is + NULL. If a required option argument was missing, OPTARG points + to a NULL string (that is, sh_optarg[0] == 0). */ + if ret == '?' as i32 { + if sh_optarg == std::ptr::null_mut() { + ret = G_INVALID_OPT!(); + } else if *sh_optarg == '\0' as c_char{ + ret = G_ARG_MISSING!(); + } + } + + if ret == G_EOF!() { + r_getopts_unbind_variable(CString::new ("OPTARG").unwrap().as_ptr()as * mut c_char); + r_getopts_bind_variable(name, CString::new ("?").unwrap().as_ptr() as * mut c_char); + return EXECUTION_FAILURE!(); + } + + if ret == G_INVALID_OPT!() { + /* Invalid option encountered. */ + ret = r_getopts_bind_variable(name, CString::new ("?").unwrap().as_ptr() as * mut c_char); + + if special_error !=0 { + strval[0] = sh_optopt as c_char; + strval[1] = '\0' as c_char; + bind_variable(CString::new ("OPTARG").unwrap().as_ptr() as * mut c_char, &mut strval[0], 0); + } else { + r_getopts_unbind_variable(CString::new ("OPTARG").unwrap().as_ptr() as * mut c_char); + } + + return ret; + } + + if ret == G_ARG_MISSING!() { + /* Required argument missing. */ + if special_error !=0 { + ret = r_getopts_bind_variable(name, CString::new (":").unwrap().as_ptr() as * mut c_char); + + strval[0] = sh_optopt as c_char; + strval[1] = '\0' as c_char; + bind_variable(CString::new ("OPTARG").unwrap().as_ptr() as * mut c_char, &mut strval[1], 0); + } else { + ret = r_getopts_bind_variable(name, CString::new ("?").unwrap().as_ptr() as * mut c_char); + r_getopts_unbind_variable(CString::new ("OPTARG").unwrap().as_ptr() as * mut c_char); + } + return ret; + } + + bind_variable(CString::new ("OPTARG").unwrap().as_ptr() as * mut c_char, sh_optarg, 0); + + strval[0] = ret as c_char; + strval[1] = '\0' as c_char; + return r_getopts_bind_variable(name, &mut strval[0]); + } +} + +#[no_mangle] +pub extern "C" fn r_getopts_builtin(list: * mut WORD_LIST)->i32 +{ + unsafe { + let av:*mut*mut c_char; + let mut ac:i32=0; + let mut ret:i32; + + if list == std::ptr::null_mut() { + builtin_usage(); + return EX_USAGE!(); + } + + reset_internal_getopt(); + ret = internal_getopt(list, CString::new ("").unwrap().as_ptr() as * mut c_char); + if ret != -1 { + if ret == GETOPT_HELP!() { + builtin_help(); + } else { + builtin_usage(); + } + + return EX_USAGE!(); + } + let llist: * mut WORD_LIST=loptend.clone(); + av = make_builtin_argv(llist, &mut ac); + ret = r_dogetopts(ac, av); + libc::free(av as * mut c_void); + + return ret; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"getopts" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_getopts_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/history/Cargo.toml b/bash-5.1/builtins_rust/history/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6f1d922dda0c6b06930ffe12d20e39cf08fbd199 100644 --- a/bash-5.1/builtins_rust/history/Cargo.toml +++ b/bash-5.1/builtins_rust/history/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "history" +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 = "rhistory" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/history/src/intercdep.rs b/bash-5.1/builtins_rust/history/src/intercdep.rs new file mode 100644 index 0000000000000000000000000000000000000000..92f11d521b1b375536fe9b9420dd1f749a07f856 --- /dev/null +++ b/bash-5.1/builtins_rust/history/src/intercdep.rs @@ -0,0 +1,92 @@ + +#[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 const EXECUTION_SUCCESS : c_int = 0; +pub const EXECUTION_FAILURE : c_int = 1; +pub const EX_USAGE: c_int = 258; + + +pub type histdata_t = *mut libc::c_void; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _hist_entry { + pub line: *mut c_char, + pub timestamp: *mut c_char, + pub data: histdata_t, +} +pub type HIST_ENTRY = _hist_entry; + +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 bash_clear_history(); + pub fn bash_delete_last_history() -> c_int; + pub fn bash_delete_history_range (first: c_int, last: c_int) -> c_int; + pub fn bash_delete_histent(i: c_int) -> c_int; + + pub fn check_add_history (line: *mut c_char, force: c_int) -> c_int; + pub fn history_expand (hstring: *mut c_char, output: *mut *mut c_char) -> c_int; + pub fn history_get_time(hist: *mut HIST_ENTRY) -> libc::time_t; + pub fn history_list() -> *mut *mut HIST_ENTRY; + pub fn where_history() -> c_int; + pub fn history_set_pos(pos: c_int) -> c_int; + pub fn using_history(); + pub fn maybe_append_history(filename: *mut c_char) -> c_int; + pub fn write_history(filename: *const c_char) -> c_int; + pub fn read_history(filename: *const c_char) -> c_int; + pub fn read_history_range(filename: *const c_char, from: c_int, to: c_int) -> c_int; + pub fn strftime(s: *mut c_char, maxsize:size_t, format: *const c_char, timeptr: *const libc::tm) -> size_t; + pub fn get_numeric_arg(list: *mut WORD_LIST, fatal: c_int, count: *mut c_long) -> c_int; + + pub fn string_list(list: *mut WORD_LIST) -> *mut c_char; + + pub fn sh_chkwrite(s: c_int) -> c_int; + pub fn get_string_value(var_name: *const c_char) -> *mut c_char; + + pub fn termsig_handler(sig: c_int) -> c_int; + pub fn throw_to_top_level() -> c_void; + + pub fn legal_number (str1:*const c_char,result:* mut c_long) -> i32; + + pub fn sh_erange(s: *mut c_char, desc: *mut c_char); + pub fn sh_restricted(s: *mut c_char) -> c_void; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + + pub static mut remember_on_history: c_int; + pub static mut hist_last_line_pushed: c_int; + pub static mut hist_last_line_added: c_int; + pub static mut current_command_line_count: c_int; + pub static mut current_command_first_line_saved: c_int; + pub static mut command_oriented_history: c_int; + + pub static mut terminating_signal: c_int; + pub static mut interrupt_state: c_int; + + pub static mut history_base: c_int; + pub static mut history_length: c_int; + pub static mut history_lines_in_file: c_int; + pub static mut history_lines_read_from_file: c_int; + pub static mut force_append_history: c_int; + pub static mut history_lines_this_session: c_int; + + pub static mut restricted: c_int; +} diff --git a/bash-5.1/builtins_rust/history/src/lib.rs b/bash-5.1/builtins_rust/history/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1529c0dcf7a5d7b66dc63e077d8f9146d0f99aaf 100644 --- a/bash-5.1/builtins_rust/history/src/lib.rs +++ b/bash-5.1/builtins_rust/history/src/lib.rs @@ -0,0 +1,332 @@ +use std::{ffi::{CString, CStr}, io::Write}; + +use libc::{size_t, c_int, c_char, c_long, c_void, PT_NULL}; + +include!(concat!("intercdep.rs")); + +pub const AFLAG: c_int = 0x01; +pub const RFLAG: c_int = 0x02; +pub const WFLAG: c_int = 0x04; +pub const NFLAG: c_int = 0x08; +pub const SFLAG: c_int = 0x10; +pub const PFLAG: c_int = 0x20; +pub const CFLAG: c_int = 0x40; +pub const DFLAG: c_int = 0x80; + +#[no_mangle] +pub extern "C" fn r_history_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_history_builtin call"); + + let mut flags: c_int = 0; + let mut opt: c_int; + let mut result: c_int; + + let mut filename: *mut c_char; + let mut delete_arg: *mut c_char = PT_NULL as *mut c_char; + let mut range: *mut c_char; + + let mut delete_offset: c_long = 0; + +unsafe { + reset_internal_getopt(); + let opt_str = CString::new("acd:npsrw").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 { + 'a' => flags |= AFLAG, + 'c' => flags |= CFLAG, + 'n' => flags |= NFLAG, + 'r' => flags |= RFLAG, + 'w' => flags |= WFLAG, + 's' => flags |= SFLAG, + 'd' => { + flags |= DFLAG; + delete_arg = list_optarg; + } + 'p' => flags |= PFLAG, + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + } + list = loptend; + + let c_tmp = if *delete_arg == b'-' as c_char {(delete_arg as usize + 1) as *mut c_char} else {delete_arg}; + range = libc::strchr(c_tmp, b'-' as c_int); + + opt = flags & (AFLAG | RFLAG | WFLAG | NFLAG); + if opt != 0 && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG { + let c_err = CString::new("cannot use more than one of -anrw").unwrap(); + builtin_error( c_err.as_ptr()); + return EXECUTION_FAILURE; + } + + if (flags & CFLAG) != 0 { + bash_clear_history(); + if list.is_null() { + return EXECUTION_SUCCESS; + } + } + + if (flags & SFLAG) != 0 { + if !list.is_null() { + push_history(list); + } + return EXECUTION_SUCCESS; + } else if (flags & PFLAG) != 0 { + if !list.is_null() { + return expand_and_print_history(list); + } + return sh_chkwrite(EXECUTION_SUCCESS); + } else if (flags & PFLAG) != 0 { + if !list.is_null() { + return expand_and_print_history(list); + } + return sh_chkwrite(EXECUTION_SUCCESS); + } else if (flags & DFLAG) != 0 && !range.is_null() { + let mut delete_start: c_long = 0; + let mut delete_end: c_long = 0; + + *range = b'\0' as c_char; + range = (range as usize + 1) as *mut c_char; + if legal_number(delete_arg, std::mem::transmute(&delete_start)) == 0 || + legal_number(range, std::mem::transmute(&delete_end)) == 0 { + *((range as usize - 1) as *mut c_char) = b'-' as c_char; + sh_erange(delete_arg, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + if *delete_arg == b'-' as c_char && delete_start < 0 { + delete_start += history_length as c_long; + if delete_start < history_base as c_long { + sh_erange(delete_arg, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + } else if delete_start > 0 { + delete_start -= history_base as c_long; + } + if delete_start < 0 || delete_start >= history_length as c_long { + sh_erange(delete_arg, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + if *range == b'-' as c_char && delete_end < 0 { + delete_end += history_length as c_long; + if delete_end < history_base as c_long { + sh_erange(range, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + } else if delete_end > 0 { + delete_end -= history_base as c_long; + } + + if delete_end < 0 || delete_end >= history_length as c_long { + sh_erange(range, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + result = bash_delete_history_range(delete_start as c_int, delete_end as c_int); + if where_history() > history_length { + history_set_pos(history_length); + } + return if result != 0 {EXECUTION_SUCCESS} else {EXECUTION_FAILURE}; + } else if (flags & DFLAG) != 0 { + if legal_number(delete_arg, std::mem::transmute(&delete_offset)) == 0 { + sh_erange(delete_arg, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + + if *delete_arg == b'-' as c_char && delete_offset < 0 { + let ind = history_length + delete_offset as c_int; + if ind < history_base { + sh_erange(range, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + opt = ind + history_base; + } else if delete_offset < history_base as c_long || + (delete_offset >= (history_base + history_length) as c_long) { + sh_erange(range, "history position\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } else { + opt = delete_offset as c_int; + } + + result = bash_delete_histent(opt - history_base); + if where_history() > history_length { + history_set_pos(history_length); + } + return if result != 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; + } else if (flags & (AFLAG | RFLAG | NFLAG | WFLAG | CFLAG)) == 0 { + result = display_history(list); + return sh_chkwrite(result); + } + + filename = if !list.is_null() {(*((*list).word)).word} else {get_string_value("HISTFILE\0".as_ptr() as *mut c_char)}; + result = EXECUTION_SUCCESS; + + if restricted != 0 && !(libc::strchr(filename, b'/' as c_int).is_null()) { + sh_restricted(filename); + return EXECUTION_FAILURE; + } + + if (flags & AFLAG) != 0 { + result = maybe_append_history(filename); + } else if (flags & WFLAG) != 0 { + result = write_history(filename); + } else if (flags & RFLAG) != 0{ + result = read_history(filename); + history_lines_in_file = history_lines_read_from_file; + } else if (flags & NFLAG) != 0{ + let old_history_lines = history_lines_in_file; + let obase = history_base; + + using_history(); + result = read_history_range(filename, history_lines_in_file, -1); + using_history(); + + history_lines_in_file = history_lines_read_from_file; + if force_append_history == 0 { + history_lines_this_session += + history_lines_in_file - old_history_lines + history_base - obase; + } + } +} + + return if result != 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; +} + +fn histtime(hlist: *mut HIST_ENTRY, histtimefmt: *const c_char) -> *mut c_char +{ +unsafe { + static mut timestr: [c_char;128] = [0;128]; + + let mut t = history_get_time(hlist); + let tm = if t != 0 {libc::localtime(&t)} else {PT_NULL as *mut libc::tm}; + if t != 0 && !tm.is_null() { + strftime(std::mem::transmute(×tr), + std::mem::size_of_val(×tr), + histtimefmt, + tm); + } else if !(*hlist).timestamp.is_null() && (*(*hlist).timestamp) != 0 { + let c_str = CString::new("%s: invalid timestamp").unwrap(); + libc::snprintf(std::mem::transmute(×tr), + std::mem::size_of_val(×tr), c_str.as_ptr(), + if *((*hlist).timestamp) == b'#' as c_char {((*hlist).timestamp as usize + 1) as *mut c_char} else {(*hlist).timestamp}); + } else { + libc::strcpy(std::mem::transmute(×tr), b"??\0".as_ptr() as *const c_char); + } + + return timestr.as_mut_ptr(); +} +} + +unsafe fn quit() +{ + if terminating_signal != 0 { + termsig_handler(terminating_signal); + } + if interrupt_state != 0 { + throw_to_top_level(); + } +} + +unsafe fn display_history(list: *mut WORD_LIST) -> c_int +{ + let mut limit:c_long = 0; + let mut histtimefmt: *mut c_char; + let mut timestr: *mut c_char; + + if !list.is_null() { + if get_numeric_arg(list, 0, std::mem::transmute(&limit)) == 0 { + return EXECUTION_FAILURE; + } + if limit < 0 { + limit = -limit; + } + } else { + limit = -1; + } + + let hlist = history_list(); + + if !hlist.is_null() { + let mut i: c_long = 0; + while !((hlist as usize + (i * 8) as usize) as *mut HIST_ENTRY).is_null() { + i += 1; + } + + i = if 0 <= limit && limit < i {i - limit} else {0}; + + histtimefmt = get_string_value("HISTTIMEFORMAT\0".as_ptr() as *const c_char); + + while !((hlist as usize + (i * 8) as usize) as *mut HIST_ENTRY).is_null(){ + quit(); + + if !histtimefmt.is_null() && *histtimefmt != 0 { + timestr = histtime((hlist as usize + (i * 8) as usize) as *mut HIST_ENTRY, histtimefmt); + } else { + timestr = PT_NULL as *mut c_char; + } + + let data = (*((hlist as usize + (i * 8) as usize) as *mut HIST_ENTRY)).data; + let line = (*((hlist as usize + (i * 8) as usize) as *mut HIST_ENTRY)).line; + let s_timestr = CString::from_raw(timestr).into_string().unwrap(); + println!("{:>5}{} {}{}", + i as c_int + history_base, + if !data.is_null() {"*"} else {" "}, + if !timestr.is_null() && *timestr != 0 {s_timestr} else {"".to_owned()}, + CString::from_raw(line).into_string().unwrap() + ); + i += 1; + } + } + + return EXECUTION_SUCCESS; +} + +fn push_history(list: *mut WORD_LIST) { +unsafe { + if remember_on_history != 0 && hist_last_line_pushed == 0 && + (hist_last_line_added != 0 || (current_command_line_count > 0 && current_command_first_line_saved != 0 && command_oriented_history != 0)) && + bash_delete_last_history() == 0 { + return; + } + + let s = string_list(list); + check_add_history(s, 1); + + hist_last_line_pushed = 1; + libc::free(s as *mut c_void); +} +} + +fn expand_and_print_history(mut list: *mut WORD_LIST) -> c_int +{ +unsafe { + + let mut s: *mut c_char = PT_NULL as *mut c_char; + let mut result: c_int; + + if hist_last_line_pushed == 0 && hist_last_line_added != 0 && bash_delete_last_history() == 0 { + return EXECUTION_FAILURE; + } + result = EXECUTION_SUCCESS; + while !list.is_null() { + let r = history_expand((*((*list).word)).word, std::mem::transmute(&s)); + if r < 0 { + let c_err = CString::new("%s: history expansion failed").unwrap(); + builtin_error( c_err.as_ptr(), (*((*list).word)).word); + result = EXECUTION_FAILURE; + } else { + std::io::stdout().lock().write_all(CStr::from_ptr(s).to_bytes()).unwrap(); + libc::putchar(b'\n' as c_int); + } + if !s.is_null() { + libc::free(s as *mut c_void); + } + list = (*list).next; + } + std::io::stdout().lock().flush().unwrap(); + return result; +} +} diff --git a/bash-5.1/builtins_rust/jobs/Cargo.toml b/bash-5.1/builtins_rust/jobs/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa26bda57da3806ceeaf60eaea69d5f32799d1aa 100644 --- a/bash-5.1/builtins_rust/jobs/Cargo.toml +++ b/bash-5.1/builtins_rust/jobs/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rjobs" +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 = "rjobs" diff --git a/bash-5.1/builtins_rust/jobs/README.md b/bash-5.1/builtins_rust/jobs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..96ed60e14fa6e7bbc28c428cd3322874ecc53e0f --- /dev/null +++ b/bash-5.1/builtins_rust/jobs/README.md @@ -0,0 +1,16 @@ + +找到项目bash +先make clean +找到makefile(注意有多个)将CC = gcc 改为 CC = gcc -fPIC +再make +然后生成动态链接库,例如我需要用到jobs +gcc -shared -fPIC -o libjobs.so jobs.o +批量处理脚本create-so.sh + + +添加动态库 +新建 /etc/ld.so.conf.d/jobs.conf +将 依赖的os路径写入 /etc/ld.so.conf.d/jobs.conf +ldconfig -X + + diff --git a/bash-5.1/builtins_rust/jobs/src/lib.rs b/bash-5.1/builtins_rust/jobs/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9456b58f848d8503a96b63ff1294ee7ec04c19e4 100644 --- a/bash-5.1/builtins_rust/jobs/src/lib.rs +++ b/bash-5.1/builtins_rust/jobs/src/lib.rs @@ -0,0 +1,623 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long}; +use std::ffi::CString; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(i8)] +pub enum JOB_STATE { + JNONE = -1, + JRUNNING = 1, + JSTOPPED = 2, + JDEAD = 4, + JMIXED = 8 +} + +#[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)] +pub struct PROCESS { + next: *mut PROCESS, + pid:libc::c_int, + status:libc::c_int, + running:libc::c_int, + command:*mut c_char +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:libc::c_int, /* Place to redirect REDIRECTOR to, or ... */ + filename:* mut WORD_DESC /* filename to redirect to. */ +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, /* Next element, or NULL. */ + redirector:REDIRECTEE, /* Descriptor or varname to be redirected. */ + rflags:libc::c_int, /* Private flags for this redirection */ + flags:libc::c_int, /* Flag value for `open'. */ + instruction:r_instruction, /* What to do with the information. */ + redirectee:REDIRECTEE, /* File descriptor or filename */ + here_doc_eof:*mut c_char /* The word that appeared in < {0} +} + +#[macro_export] +macro_rules! JSTATE_ANY { + () => {0x0} +} + +#[macro_export] +macro_rules! JLIST_LONG { + () => {1} +} + +#[macro_export] +macro_rules! JLIST_PID_ONLY { + () => {2} +} + +#[macro_export] +macro_rules! JLIST_CHANGED_ONLY { + () => {3} +} + +#[macro_export] +macro_rules! EXECUTION_FAILURE { + () => {1} +} + +#[macro_export] +macro_rules! JSTATE_RUNNING { + () => {0x1} +} + +#[macro_export] +macro_rules! JSTATE_STOPPED { + () => {0x2} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! EXECUTION_SUCCESS { + () => {0} +} + +#[macro_export] +macro_rules! BLOCK_SIGNAL { + ($sig:expr, $nvar:expr, $ovar:expr) => { + $nvar.unwrap().clear(); + $nvar.unwrap().add($sig); + $nvar.unwrap().clear(); + nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_BLOCK, $nvar, $ovar); + } +} + +#[macro_export] +macro_rules! UNBLOCK_SIGNAL { + ($ovar:expr) => { + nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_SETMASK, $ovar, None) + } +} + +#[macro_export] +macro_rules! UNBLOCK_CHILD { + ($ovar:expr) => { + UNBLOCK_SIGNAL!($ovar); + } +} + +#[macro_export] +macro_rules! BLOCK_CHILD { + ($nvar:expr,$ovar:expr) => { + BLOCK_SIGNAL!(nix::sys::signal::SIGCHLD, $nvar, $ovar); + } +} + +#[macro_export] +macro_rules! NO_JOB { + () => {-1} +} + +#[macro_export] +macro_rules! DUP_JOB { + () => {-2} +} + +#[macro_export] +macro_rules! CMD_INHIBIT_EXPANSION {/* Do not expand the command words. */ + () => {0x20} +} + +#[macro_export] +macro_rules! get_job_by_jid { + ($ind:expr) => { + (*((jobs as usize + ($ind*8) as usize ) as *mut*mut JOB) as *mut JOB) + } +} + +#[macro_export] +macro_rules! INVALID_JOB { + ($j:expr) => { + $j <0 || $j >= js.j_jobslots || get_job_by_jid !($j) == std::ptr::null_mut() + } +} + +extern "C" { + fn list_running_jobs(format:i32); + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + fn builtin_error(err:*const c_char,...); + fn builtin_usage(); + static mut loptend:*mut WORD_LIST; + fn list_all_jobs(form:i32); + fn list_stopped_jobs(form:i32); + fn list_one_job (jjob:*mut JOB, format:i32, ignore:i32, job_index:i32); + fn get_job_spec (list:*mut WORD_LIST)->i32; + fn sh_badjob (str:*mut c_char); + static jobs:*mut*mut JOB; + fn discard_unwind_frame (str: * mut c_char); + fn begin_unwind_frame (str: * mut c_char); + fn execute_command (command:* mut COMMAND)->i32; + fn dispose_command (command:* mut COMMAND); + fn make_bare_simple_command ()->* mut COMMAND; + fn copy_word_list (list:*mut WORD_LIST)->* mut WORD_LIST; + static js:jobstats ; + fn add_unwind_protect(_:unsafe extern "C" fn(command:* mut COMMAND),...); + fn legal_number(str:* const c_char, result:* mut c_long)->i32; + fn get_job_by_pid (pid:i32, block:i32, ignore:*mut*mut PROCESS)->i32; + fn delete_job (job_index:i32, dflags:i32); + fn nohup_job (job_index:i32); + fn nohup_all_jobs (running_only:i32); + fn delete_all_jobs(running_only:i32); + } + + #[no_mangle] + pub extern "C" fn r_execute_list_with_replacements (list:*mut WORD_LIST)->i32{ + //println!("r_execute_list_with_replacements"); + unsafe{ + let mut l:*mut WORD_LIST=list; + let mut job:i32; + let result:i32; + let command:*mut COMMAND; + + /* First do the replacement of job specifications with pids. */ + while l !=std::ptr::null_mut() { + let lchar:char=char::from((*(*(*l).word).word) as u8); + if lchar== '%' /* we have a winner */ { + job = get_job_spec ( l); + /* A bad job spec is not really a job spec! Pass it through. */ + if INVALID_JOB!(job){ + continue; + } + + libc::free((*(*l).word).word as * mut libc::c_void); + (*(*(*l).word).word) = (*get_job_by_jid! (job)).pgrp as i8; + } + l=(*l).next; + } + + let mut c_str_jobs_builtin = CString::new("jobs_builtin").unwrap(); + /* Next make a new simple command and execute it. */ + begin_unwind_frame (c_str_jobs_builtin.as_ptr() as * mut c_char); + + command = make_bare_simple_command (); + (*((*command).value.Simple)).words= copy_word_list (list); + (*((*command).value.Simple)).redirects = std::ptr::null_mut(); + (*command).flags |= CMD_INHIBIT_EXPANSION!(); + (*((*command).value.Simple)).flags |= CMD_INHIBIT_EXPANSION!(); + + add_unwind_protect(dispose_command, command); + result = execute_command (command); + dispose_command (command); + discard_unwind_frame (c_str_jobs_builtin.as_ptr() as * mut c_char); + return result; + } +} + +#[no_mangle] +pub extern "C" fn r_jobs_builtin(list:*mut WORD_LIST)->i32 { + //println!("r_jobs_builtin"); + let mut form:i32; + let mut execute:i32=0; + let mut state:i32; + let mut opt:i32; + let mut any_failed:i32=0; + let mut job:i32; + + let mut set:nix::sys::signal::SigSet=nix::sys::signal::SigSet::empty(); + let mut oset:nix::sys::signal::SigSet =nix::sys::signal::SigSet::empty(); + + form = JLIST_STANDARD!(); + state = JSTATE_ANY!(); + + unsafe { + reset_internal_getopt(); + + let mut c_str_lpnxrs = CString::new("lpnxrs").unwrap(); // from a &str, creates a new allocation + + opt = internal_getopt (list, c_str_lpnxrs.as_ptr() as * mut c_char); + while opt != -1 { + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'l'=>{form = JLIST_LONG!();} + 'p'=>{form = JLIST_PID_ONLY!();} + 'n'=>{form = JLIST_CHANGED_ONLY!();} + 'x'=>{ + if form != JLIST_STANDARD!() { + let mut c_str_err = CString::new("no other options allowed with `-x'").unwrap(); // from a &str, creates a new allocation + builtin_error (c_str_err.as_ptr()); + return EXECUTION_FAILURE!(); + } + execute+=1; + } + 'r'=>{state = JSTATE_RUNNING!();} + 's'=>{state = JSTATE_STOPPED!();} + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt = internal_getopt (list, c_str_lpnxrs.as_ptr() as * mut c_char); + } + + if execute != 0 { + return r_execute_list_with_replacements (loptend); + } + + if loptend ==std::ptr::null_mut() { + if state == JSTATE_ANY!() { + list_all_jobs (form); + } else if state == JSTATE_RUNNING!() { + list_running_jobs (form); + }else if state == JSTATE_STOPPED!() { + list_stopped_jobs (form); + } + return EXECUTION_SUCCESS!(); + } + + let mut loptendt=*loptend; + while loptendt.next !=std::ptr::null_mut() { + BLOCK_CHILD !(Some(&mut set), Some(&mut oset)); + job = get_job_spec (&mut loptendt); + + if (job == NO_JOB!()) || jobs == std::ptr::null_mut() || get_job_by_jid !(job) == std::ptr::null_mut() { + sh_badjob ((*loptendt.word).word); + any_failed+=1; + } else if (job != DUP_JOB!()) { + list_one_job (0 as * mut JOB, form, 0, job); + } + + UNBLOCK_CHILD !(Some(&oset)); + loptendt = *loptendt.next; + } + if any_failed !=0 { + return EXECUTION_FAILURE!(); + } else { + return EXECUTION_SUCCESS!(); + } + } +} + +#[no_mangle] +pub extern "C" fn r_disown_builtin (list:* mut WORD_LIST)->libc::c_int { + let opt:i32; + let mut job:i32=0; + let mut retval:i32; + let mut nohup_only:i32=0; + let mut running_jobs:i32=0; + let mut all_jobs:i32=0; + + let mut set:nix::sys::signal::SigSet=nix::sys::signal::SigSet::empty(); + let mut oset:nix::sys::signal::SigSet =nix::sys::signal::SigSet::empty(); + let mut pid_value:c_long=0; + //println!("r_disown_builtin"); + unsafe { + reset_internal_getopt (); + let mut c_str_ahr = CString::new("ahr").unwrap(); // from a &str, creates a new allocation + opt = internal_getopt (list, c_str_ahr.as_ptr() as * mut c_char); + while opt != -1 { + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'a'=>{all_jobs = 1;} + 'h'=>{nohup_only = 1;} + 'r'=>{running_jobs = 1;} + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + } + + retval = EXECUTION_SUCCESS!(); + + /* `disown -a' or `disown -r' */ + if loptend == std::ptr::null_mut() && (all_jobs !=0 || running_jobs != 0) { + if nohup_only!=0{ + nohup_all_jobs (running_jobs); + } else { + delete_all_jobs (running_jobs); + } + return EXECUTION_SUCCESS!(); + } + + BLOCK_CHILD !(Some(&mut set), Some(&mut oset)); + if (loptend !=std::ptr::null_mut() && legal_number ((*(*loptend).word).word, &mut pid_value) !=0 && pid_value == pid_value) { + job=get_job_by_pid ( pid_value as i32, 0, 0 as *mut*mut PROCESS); + }else { + get_job_spec (loptend); + } + if job == NO_JOB!() || jobs !=std::ptr::null_mut() || INVALID_JOB!(job) { + if loptend !=std::ptr::null_mut() { + sh_badjob ((*(*loptend).word).word); + } else { + sh_badjob (CString::new("current").unwrap().as_ptr() as * mut c_char); + } + retval = EXECUTION_FAILURE!(); + } else if nohup_only !=0{ + nohup_job (job); + } else { + delete_job (job, 1); + } + + UNBLOCK_CHILD !(Some(&oset)); + + if loptend != std::ptr::null_mut() { + let mut loptendt=*loptend; + while loptendt.next !=std::ptr::null_mut() { + loptendt = *loptendt.next; + BLOCK_CHILD !(Some(&mut set), Some(&mut oset)); + if legal_number ((*loptendt.word).word, &mut pid_value) !=0 && pid_value == pid_value { + job=get_job_by_pid ( pid_value as i32, 0, 0 as *mut*mut PROCESS); + } else { + get_job_spec (&mut loptendt); + } + if job == NO_JOB!() || jobs !=std::ptr::null_mut() || INVALID_JOB!(job) { + sh_badjob ((*loptendt.word).word); + retval = EXECUTION_FAILURE!(); + } else if nohup_only !=0{ + nohup_job (job); + } else { + delete_job (job, 1); + } + UNBLOCK_CHILD !(Some(&oset)); + } + } + return retval; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"jobs" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_jobs_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/kill/Cargo.toml b/bash-5.1/builtins_rust/kill/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e3f22a15a0b392818a12fd7f256aba2f387b5894 100644 --- a/bash-5.1/builtins_rust/kill/Cargo.toml +++ b/bash-5.1/builtins_rust/kill/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "kill" +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 = "rkill" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/kill/src/intercdep.rs b/bash-5.1/builtins_rust/kill/src/intercdep.rs new file mode 100644 index 0000000000000000000000000000000000000000..388884675ed0644797e5fc8f0b08358966a0b3b8 --- /dev/null +++ b/bash-5.1/builtins_rust/kill/src/intercdep.rs @@ -0,0 +1,323 @@ + +#[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 const EXECUTION_SUCCESS : c_int = 0; +pub const EXECUTION_FAILURE : c_int = 1; +pub const EX_USAGE: c_int = 258; + +pub const EINVAL: c_int = 22; +pub const NO_SIG: c_int = -1; + +pub const DSIG_SIGPREFIX: c_int = 0x01; +pub const DSIG_NOCASE: c_int = 0x02; + +pub const DUP_JOB: c_int = -2; + +pub const J_JOBCONTROL: c_int = 0x04; + +pub type pid_t = c_int; +pub type WAIT = c_int; +pub type sh_vptrfunc_t = *mut fn(); +pub type JOB_STATE = c_int; + +pub type command_type = c_uint; +#[repr(C)] +#[derive(Copy, Clone)] +pub union REDIRECTEE { + pub dest: c_int, + pub filename: *mut WORD_DESC, +} + +pub type r_instruction = c_uint; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct redirect { + pub next: *mut redirect, + pub redirector: REDIRECTEE, + pub rflags: c_int, + pub flags: c_int, + pub instruction: r_instruction, + pub redirectee: REDIRECTEE, + pub here_doc_eof: *mut c_char, +} + +pub type REDIRECT = redirect; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct command { + pub type_: command_type, + pub flags: c_int, + pub line: c_int, + pub redirects: *mut REDIRECT, + pub value: command__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union command__bindgen_ty_1 { + pub For: *mut for_com, + pub Case: *mut case_com, + pub While: *mut while_com, + pub If: *mut if_com, + pub Connection: *mut connection, + pub Simple: *mut simple_com, + pub Function_def: *mut function_def, + pub Group: *mut group_com, + pub Select: *mut select_com, + pub Arith: *mut arith_com, + pub Cond: *mut cond_com, + pub ArithFor: *mut arith_for_com, + pub Subshell: *mut subshell_com, + pub Coproc: *mut coproc_com, +} + +pub type COMMAND = command; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct pattern_list { + pub next: *mut pattern_list, + pub patterns: *mut WORD_LIST, + pub action: *mut COMMAND, + pub flags: c_int, +} + +pub type PATTERN_LIST = pattern_list; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct case_com { + pub flags: c_int, + pub line: c_int, + pub word: *mut WORD_DESC, + pub clauses: *mut PATTERN_LIST, +} + +pub type CASE_COM = case_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct for_com { + pub flags: c_int, + pub line: c_int, + pub name: *mut WORD_DESC, + pub map_list: *mut WORD_LIST, + pub action: *mut COMMAND, +} + +pub type FOR_COM = for_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct arith_for_com { + pub flags: c_int, + pub line: c_int, + pub init: *mut WORD_LIST, + pub test: *mut WORD_LIST, + pub step: *mut WORD_LIST, + pub action: *mut COMMAND, +} + +pub type ARITH_FOR_COM = arith_for_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct select_com { + pub flags: c_int, + pub line: c_int, + pub name: *mut WORD_DESC, + pub map_list: *mut WORD_LIST, + pub action: *mut COMMAND, +} + +pub type SELECT_COM = select_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct if_com { + pub flags: c_int, + pub test: *mut COMMAND, + pub true_case: *mut COMMAND, + pub false_case: *mut COMMAND, +} + +pub type IF_COM = if_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct while_com { + pub flags: c_int, + pub test: *mut COMMAND, + pub action: *mut COMMAND, +} + +pub type WHILE_COM = while_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct arith_com { + pub flags: c_int, + pub line: c_int, + pub exp: *mut WORD_LIST, +} + +pub type ARITH_COM = arith_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct cond_com { + pub flags: c_int, + pub line: c_int, + pub type_: c_int, + pub op: *mut WORD_DESC, + pub left: *mut cond_com, + pub right: *mut cond_com, +} + +pub type COND_COM = cond_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct simple_com { + pub flags: c_int, + pub line: c_int, + pub words: *mut WORD_LIST, + pub redirects: *mut REDIRECT, +} + +pub type SIMPLE_COM = simple_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct function_def { + pub flags: c_int, + pub line: c_int, + pub name: *mut WORD_DESC, + pub command: *mut COMMAND, + pub source_file: *mut c_char, +} + +pub type FUNCTION_DEF = function_def; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct group_com { + pub ignore: c_int, + pub command: *mut COMMAND, +} + +pub type GROUP_COM = group_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct subshell_com { + pub flags: c_int, + pub line: c_int, + pub command: *mut COMMAND, +} + +pub type SUBSHELL_COM = subshell_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct coproc { + pub c_name: *mut c_char, + pub c_pid: pid_t, + pub c_rfd: c_int, + pub c_wfd: c_int, + pub c_rsave: c_int, + pub c_wsave: c_int, + pub c_flags: c_int, + pub c_status: c_int, + pub c_lock: c_int, +} + +pub type Coproc = coproc; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct coproc_com { + pub flags: c_int, + pub name: *mut c_char, + pub command: *mut COMMAND, +} + +pub type COPROC_COM = coproc_com; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct process { + pub next: *mut process, + pub pid: pid_t, + pub status: WAIT, + pub running: c_int, + pub command: *mut c_char, +} + +pub type PROCESS = process; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct job { + pub wd: *mut c_char, + pub pipe: *mut PROCESS, + pub pgrp: pid_t, + pub state: JOB_STATE, + pub flags: c_int, + pub deferred: *mut COMMAND, + pub j_cleanup: sh_vptrfunc_t, + pub cleanarg: *mut c_void, +} + +pub type JOB = job; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct connection { + pub _address: u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct jobstats { + pub c_childmax: c_long, + pub c_living: c_int, + pub c_reaped: c_int, + pub c_injobs: c_int, + pub c_totforked: c_int, + pub c_totreaped: c_int, + pub j_jobslots: c_int, + pub j_lastj: c_int, + pub j_firstj: c_int, + pub j_njobs: c_int, + pub j_ndead: c_int, + pub j_current: c_int, + pub j_previous: c_int, + pub j_lastmade: *mut JOB, + pub j_lastasync: *mut JOB, +} + +extern "C" { + pub fn reset_internal_getopt(); + pub fn internal_getopt(list: *mut WORD_LIST, opts: *mut c_char) -> c_int; + + pub fn get_job_spec(list: *mut WORD_LIST) -> c_int; + + pub fn builtin_usage(); + pub fn builtin_help(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn legal_number(string: *mut c_char, result: c_long) -> c_int; + pub fn display_signal_list (list: *mut WORD_LIST, forcecols: c_int) -> c_int; + pub fn decode_signal (string: *mut c_char, flags: c_int) -> c_int; + + pub fn sh_needarg(s: *mut c_char) -> c_void; + pub fn sh_invalidsig(s: *mut c_char) -> c_void; + pub fn sh_badpid(s: *mut c_char) -> c_void; + pub fn sh_badjob(s: *mut c_char) -> c_void; + + pub fn kill_pid(pid: libc::pid_t, sig: c_int, group: c_int) -> c_int; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + + pub static posixly_correct: c_int; + + pub static mut js: jobstats; + pub static mut jobs: *mut *mut JOB; +} diff --git a/bash-5.1/builtins_rust/kill/src/lib.rs b/bash-5.1/builtins_rust/kill/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5f294f17be414ca3eef80d1ffecb4c2e66d96352 100644 --- a/bash-5.1/builtins_rust/kill/src/lib.rs +++ b/bash-5.1/builtins_rust/kill/src/lib.rs @@ -0,0 +1,206 @@ +use std::{ffi::{CString, CStr}}; +use libc::{c_int, c_uint, c_char, c_long, c_void, PT_NULL}; + +include!(concat!("intercdep.rs")); + + +#[no_mangle] +pub extern "C" fn r_kill_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_kill_builtin call"); + +unsafe { + let mut word: *mut c_char; + let mut pid:libc::pid_t; + let mut pid_value: c_long = 0; + + if list.is_null() { + builtin_usage(); + return EX_USAGE; + } + + if !list.is_null() && !(*list).word.is_null() && + libc::strcmp((*((*list).word)).word, "--help\0".as_ptr() as *const c_char) == 0 { + builtin_help (); + return EX_USAGE; + } + + let mut any_succeeded: c_int = 0; + let mut listing: c_int = 0; + let mut saw_signal: c_int = 0; + let mut sig = libc::SIGTERM; + let mut sigspec = "TERM\0".as_ptr() as *mut c_char; + + let dflags = DSIG_NOCASE | if posixly_correct == 0 {DSIG_SIGPREFIX} else {0}; + while !list.is_null() { + word = (*((*list).word)).word; + + if is_option(word, b'l') || is_option(word, b'L') { + listing += 1; + list = (*list).next; + } else if is_option(word, b's') || is_option(word, b'n') { + list = (*list).next; + if !list.is_null() { + sigspec = (*((*list).word)).word; + if *sigspec == b'0' as c_char && + *((sigspec as usize + 1) as *mut c_char) == b'\0' as c_char { + sig = 0; + } else { + sig = decode_signal(sigspec, dflags); + } + list = (*list).next; + saw_signal += 1; + } else { + sh_needarg(word); + return EXECUTION_FAILURE; + } + } else if *word == b'-' as c_char && + *((word as usize + 1) as *mut c_char) == b's' as c_char && + libc::isalpha(*((word as usize + 2) as *mut c_char) as c_int) != 0 { + sigspec = (word as usize + 2) as *mut c_char; + if *sigspec == b'0' as c_char && + *((sigspec as usize + 1) as *mut c_char) == b'\0' as c_char { + sig = 0; + } else { + sig = decode_signal(sigspec, dflags); + } + list = (*list).next; + saw_signal += 1; + } else if *word == b'-' as c_char && + *((word as usize + 1) as *mut c_char) == b'n' as c_char && + libc::isdigit(*((word as usize + 2) as *mut c_char) as c_int) != 0 { + sigspec = (word as usize + 2) as *mut c_char; + if *sigspec == b'0' as c_char && + *((sigspec as usize + 1) as *mut c_char) == b'\0' as c_char { + sig = 0; + } else { + sig = decode_signal(sigspec, dflags); + } + list = (*list).next; + saw_signal += 1; + } else if is_option(word, b'-') { + list = (*list).next; + break; + } else if is_option(word, b'?') { + builtin_usage(); + return EX_USAGE; + } else if *word == b'-' as c_char && saw_signal == 0 { + sigspec = (word as usize + 1) as *mut c_char; + sig = decode_signal(sigspec, dflags); + saw_signal += 1; + list = (*list).next; + } else { + break; + } + } + + if listing != 0 { + return display_signal_list(list, 0); + } + + if sig == NO_SIG { + sh_invalidsig(sigspec); + return EXECUTION_FAILURE; + } + + if list.is_null() { + builtin_usage(); + return EX_USAGE; + } + + while !list.is_null() { + word = (*((*list).word)).word; + + if *word == b'-' as c_char { + word = (word as usize + 1) as *mut c_char; + } + + if *word != 0 && legal_number((*((*list).word)).word, std::mem::transmute(&pid_value)) != 0 + && (pid_value == (pid_value as c_int) as c_long) { + pid = pid_value as libc::pid_t; + + if kill_pid(pid, sig, (pid < -1) as c_int) < 0 { + if *(libc::__errno_location()) == EINVAL { + sh_invalidsig(sigspec); + } else { + kill_error(pid, *(libc::__errno_location())); + } + list = (*list).next; + continue; + } else { + any_succeeded += 1; + } + } + else if *((*((*list).word)).word) != 0 && *((*((*list).word)).word) != b'%' as c_char { + let c_err = CString::new("%s: arguments must be process or job IDs").unwrap(); + builtin_error(c_err.as_ptr(), (*((*list).word)).word); + list = (*list).next; + continue; + } else if *word != 0 { + let set: libc::sigset_t = std::mem::zeroed(); + let oset: libc::sigset_t = std::mem::zeroed(); + let j: *mut JOB; + + libc::sigemptyset(std::mem::transmute(&set)); + libc::sigaddset(std::mem::transmute(&set), libc::SIGCHLD); + libc::sigemptyset(std::mem::transmute(&oset)); + libc::sigprocmask(libc::SIG_BLOCK, std::mem::transmute(&set), std::mem::transmute(&oset)); + + let job = get_job_spec(list); + + if job < 0 || job > js.j_jobslots || ((jobs as usize + job as usize * 8) as *mut JOB).is_null() { + if job != DUP_JOB { + sh_badjob((*((*list).word)).word); + } + libc::sigprocmask(libc::SIG_SETMASK, std::mem::transmute(&oset), PT_NULL as *mut libc::sigset_t); + list = (*list).next; + continue; + } + + j = (jobs as usize + job as usize * 8) as *mut JOB; + if (*j).flags & J_JOBCONTROL != 0 { + pid = (*j).pgrp; + } else { + pid = (*((*j).pipe)).pid; + } + + libc::sigprocmask(libc::SIG_SETMASK, std::mem::transmute(&oset), PT_NULL as *mut libc::sigset_t); + + if kill_pid(pid, sig, 1) < 0 { + if *(libc::__errno_location()) == EINVAL { + sh_invalidsig(sigspec); + } else { + kill_error(pid, *(libc::__errno_location())); + } + list = (*list).next; + continue; + } else { + any_succeeded += 1; + } + } + else { + sh_badpid((*((*list).word)).word); + list = (*list).next; + continue; + } + list = (*list).next; + } + + return if any_succeeded != 0 {EXECUTION_SUCCESS} else {EXECUTION_FAILURE}; +} +} + +unsafe fn is_option(s: *mut c_char, c: u8) -> bool +{ + let str = CStr::from_ptr(s).to_bytes_with_nul(); + return str[0] == b'-' && str[1] == c && str[2] != 0 +} + +unsafe fn kill_error(pid: libc::pid_t, e: c_int) +{ + let mut x = libc::strerror(e); + if x.is_null() { + x = "Unknown error".as_ptr() as *mut c_char; + } + + builtin_error("(%ld) - %s".as_ptr() as *const c_char, pid, x); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/pushd/Cargo.toml b/bash-5.1/builtins_rust/pushd/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..69270a844857840d2961e304bfa0f21fde860fe2 --- /dev/null +++ b/bash-5.1/builtins_rust/pushd/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rpushd" +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 = "rpushd" diff --git a/bash-5.1/builtins_rust/pushd/src/lib.rs b/bash-5.1/builtins_rust/pushd/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..bd0783c7e3aeac783f7bbd15f41694604185f1e3 --- /dev/null +++ b/bash-5.1/builtins_rust/pushd/src/lib.rs @@ -0,0 +1,972 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::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:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:libc::c_int, + flags:libc::c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:libc::c_int, + line:libc::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:libc::c_int +} + +#[repr(C)] +pub struct case_com { + flags:libc::c_int, + line:libc::c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:libc::c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:libc::c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:libc::c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:libc::c_int +} + +#[repr(C)] +pub struct simple_com { + flags:libc::c_int, + line:libc::c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:libc::c_int, + line:libc::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:libc::c_int, + line:libc::c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:libc::c_int, + line:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:libc::c_int, + line:libc::c_int, + type_c:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:libc::c_int, + line:libc::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 +} + +#[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! NOCD { + () => { + 0x01 + } +} + +#[macro_export] +macro_rules! ROTATE { + () => { + 0x02 + } +} + +#[macro_export] +macro_rules! LONGFORM { + () => { + 0x04 + } +} + +#[macro_export] +macro_rules! CLEARSTAK { + () => { + 0x08 + } +} + +extern "C" { + fn builtin_help (); + fn builtin_error(err:*const c_char,...); + fn get_working_directory (path:* mut c_char)-> * mut c_char; + fn sh_invalidopt (value:* mut c_char); + fn builtin_usage(); + fn sh_invalidnum (value:* mut c_char); + fn legal_number (str1:* const c_char, num:* mut libc::c_long)->i32; + fn cd_builtin (list:*mut WORD_LIST)->i32; + fn polite_directory_format (path:* mut c_char)->* mut c_char; + fn sh_erange (str1:* mut c_char, str2:* mut c_char); + fn make_word_list (w: * mut WORD_DESC , l: * mut WORD_LIST)->* mut WORD_LIST; + fn make_word (w:*const c_char)->* mut WORD_DESC; + fn dispose_words (l: * mut WORD_LIST); + fn strvec_resize (c:* mut * mut c_char, s:i32)->* mut * mut c_char; + fn get_string_value (w:*const c_char)-> * mut c_char; + fn sh_chkwrite (i:i32)->i32; +} +pub static mut pushd_directory_list:* mut * mut c_char=std::ptr::null_mut(); +pub static mut directory_list_offset:i32=0; +pub static mut directory_list_size:i32=0; + +unsafe fn STREQ( a:* const c_char, b:* const c_char)->bool +{ + return *a ==*b && libc::strcmp(a, b) == 0; +} + +unsafe fn ISHELP(s:* const c_char)->bool +{ + return STREQ (s, CString::new("--help").unwrap().as_ptr()); +} + +unsafe fn ISOPTION(s:* const c_char, c:c_char)->bool +{ + return *s == '-' as c_char && *((s as usize + 1)as * mut c_char) == c && *((s as usize + 8)as * mut c_char) != 0; +} + +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 ); +} + +#[no_mangle] +pub extern "C" fn r_pushd_builtin (listt:* mut WORD_LIST)->i32 +{ + let orig_list:* mut WORD_LIST; + let mut temp:* mut c_char; + let current_directory:* mut c_char; + let mut top:* mut c_char; + let mut j:i32; + let mut flags:i32; + let skipopt:i32; + let mut num:libc::c_long=0; + let mut direction:c_char; + + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + orig_list = list.clone(); + + if list != std::ptr::null_mut() && (*list).word != std::ptr::null_mut() && ISHELP((*((*list).word)).word) { + builtin_help (); + return EX_USAGE!(); + } + + if list != std::ptr::null_mut() && (*list).word != std::ptr::null_mut() && ISOPTION ((*((*list).word)).word, '-' as c_char) { + list = (*list).next; + skipopt = 1; + } else { + skipopt = 0; + } + + /* If there is no argument list then switch current and + top of list. */ + if list == std::ptr::null_mut() { + if directory_list_offset == 0 { + builtin_error (CString::new("no other directory").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + + current_directory = get_working_directory (CString::new("pushd").unwrap().as_ptr() as * mut c_char); + if current_directory == std::ptr::null_mut() { + return EXECUTION_FAILURE!(); + } + + j = directory_list_offset - 1; + temp = *((pushd_directory_list as usize + (j*8) as usize) as * mut *mut c_char); + *((pushd_directory_list as usize + (j*8) as usize) as * mut *mut c_char) = current_directory; + j = r_change_to_temp (temp); + libc::free (temp as * mut c_void); + return j; + } + + flags = 0; + + while skipopt == 0 && list !=std::ptr::null_mut() { + if ISOPTION ((*((*list).word)).word, 'n' as c_char) { + flags |= NOCD!(); + } else if ISOPTION ((*((*list).word)).word, '-' as c_char) { + list = (*list).next; + break; + } else if *((*((*list).word)).word) == '-' as c_char && *(((*((*list).word)).word as usize +1) as * mut c_char) == '\0' as c_char { + /* Let `pushd -' work like it used to. */ + break; + } else { + direction = *((*((*list).word)).word); + if direction == '+' as c_char || direction == '-' as c_char { + if legal_number (((*((*list).word)).word as usize +1) as * mut c_char, &mut num) == 0 { + sh_invalidnum ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } + + if direction == '-' as c_char { + num = directory_list_offset as libc::c_long - num; + } + + if num > directory_list_offset as libc::c_long || num < 0 { + r_pushd_error (directory_list_offset, (*((*list).word)).word); + return EXECUTION_FAILURE!(); + } + flags |= ROTATE!(); + } else if *((*((*list).word)).word)== '-' as c_char { + sh_invalidopt ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } else { + break; + } + } + list = (*list).next; + } + + if (flags & ROTATE!()) != 0 { + /* Rotate the stack num times. Remember, the current + directory acts like it is part of the stack. */ + temp = get_working_directory (CString::new("pushd").unwrap().as_ptr() as * mut c_char); + + if num == 0 { + if (flags & NOCD!()) == 0 { + j=r_change_to_temp (temp); + } else { + j=EXECUTION_SUCCESS!(); + } + + libc::free (temp as * mut c_void); + return j; + } + + { + top = *((pushd_directory_list as usize + ((directory_list_offset - 1)*8) as usize ) as * mut * mut c_char); + j = directory_list_offset - 2; + + while j > -1 { + *((pushd_directory_list as usize + ((j +1)*8) as usize ) as * mut * mut c_char) =*((pushd_directory_list as usize + (j*8) as usize ) as * mut * mut c_char); + j-=1; + } + + *((pushd_directory_list as usize + ((j +1)*8) as usize ) as * mut * mut c_char)=temp; + + temp = top; + num-=1; + } + + while num != 0 { + top = *((pushd_directory_list as usize + ((directory_list_offset - 1)*8) as usize ) as * mut * mut c_char); + j = directory_list_offset - 2; + + while j > -1 { + *((pushd_directory_list as usize + ((j +1)*8) as usize ) as * mut * mut c_char) =*((pushd_directory_list as usize + (j*8) as usize ) as * mut * mut c_char); + j-=1; + } + + *((pushd_directory_list as usize + ((j +1)*8) as usize ) as * mut * mut c_char)=temp; + + temp = top; + num-=1; + } + + if (flags & NOCD!()) == 0 { + j=r_change_to_temp (temp); + } else { + j=EXECUTION_SUCCESS!(); + } + + libc::free (temp as * mut c_void); + return j; + } + + if list == std::ptr::null_mut() { + return EXECUTION_SUCCESS!(); + } + + /* Change to the directory in list->word->word. Save the current + directory on the top of the stack. */ + current_directory = get_working_directory (CString::new("pushd").unwrap().as_ptr() as * mut c_char); + if current_directory == std::ptr::null_mut() { + return EXECUTION_FAILURE!(); + } + + if (flags & NOCD!()) == 0 { + if skipopt !=0 { + j=cd_builtin(orig_list); + } else { + j=cd_builtin(list); + } + } else { + j=EXECUTION_SUCCESS!(); + } + + if j == EXECUTION_SUCCESS!() { + if (flags & NOCD!()) !=0 { + r_add_dirstack_element(savestring ((*((*list).word)).word)); + } else { + r_add_dirstack_element(current_directory); + } + + r_dirs_builtin (std::ptr::null_mut()); + if (flags & NOCD!()) != 0 { + libc::free (current_directory as * mut c_void); + } + return EXECUTION_SUCCESS!(); + } else { + libc::free (current_directory as * mut c_void); + return EXECUTION_FAILURE!(); + } + } +} + +/* Pop the directory stack, and then change to the new top of the stack. + If LIST is non-null it should consist of a word +N or -N, which says + what element to delete from the stack. The default is the top one. */ +#[no_mangle] +pub extern "C" fn r_popd_builtin (listt:* mut WORD_LIST)->i32 { +let mut i:i32; +let mut which:libc::c_long; +let mut flags:i32; +let mut direction:c_char; +let mut which_word:* mut c_char; + +unsafe { +let mut list:* mut WORD_LIST=listt.clone(); +if list != std::ptr::null_mut() && (*list).word != std::ptr::null_mut() && ISHELP((*((*list).word)).word) { + builtin_help (); + return EX_USAGE!(); +} + +which_word = std::ptr::null_mut(); +flags = 0; +which = 0; +direction = '+' as c_char; +while list != std::ptr::null_mut() { + if ISOPTION ((*((*list).word)).word, 'n' as c_char){ + flags |= NOCD!(); + } else if ISOPTION ((*((*list).word)).word, '-' as c_char) { + list = (*list).next; + break; + } else { + direction = *((*((*list).word)).word); + if direction == '+' as c_char || direction == '-' as c_char { + + if legal_number ((((*((*list).word)).word as usize + 1) as * mut c_char), & mut which) == 0 { + sh_invalidnum ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } + which_word = (*((*list).word)).word; + } else if *((*((*list).word)).word) == '-' as c_char { + sh_invalidopt ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } else if (*((*list).word)).word != std::ptr::null_mut() { + builtin_error (CString::new("%s: invalid argument").unwrap().as_ptr() as * mut c_char, (*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } else { + break; + } + } + list = (*list).next; +} + +if which > directory_list_offset as libc::c_long || (which < -directory_list_offset as libc::c_long) || (directory_list_offset == 0 && which == 0) { + if which_word !=std::ptr::null_mut() { + r_pushd_error (directory_list_offset, which_word); + } else { + r_pushd_error (directory_list_offset, CString::new("").unwrap().as_ptr() as * mut c_char); + } + return EXECUTION_FAILURE!(); +} + +/* Handle case of no specification, or top of stack specification. */ +if (direction == '+' as c_char && which == 0) || + (direction == '-' as c_char && which == directory_list_offset as libc::c_long) { + if (flags & NOCD!()) == 0 { + i=r_cd_to_string (*((pushd_directory_list as usize + ((directory_list_offset - 1)*8) as usize) as *mut *mut c_char)); + } else { + i=EXECUTION_SUCCESS!(); + } + + if i != EXECUTION_SUCCESS!() { + return i; + } + + directory_list_offset-=1; + + libc::free ((*((pushd_directory_list as usize + (directory_list_offset *8) as usize) as *mut *mut c_char)) as * mut c_void); + } else { + /* Since an offset other than the top directory was specified, + remove that directory from the list and shift the remainder + of the list into place. */ + if direction == '+' as c_char{ + i= directory_list_offset - which as i32; + } else { + i=which as i32; + } + + if i < 0 || i > directory_list_offset { + if which_word !=std::ptr::null_mut() { + r_pushd_error (directory_list_offset, which_word); + } else { + r_pushd_error (directory_list_offset, CString::new("").unwrap().as_ptr() as * mut c_char); + } + + return EXECUTION_FAILURE!(); + } + libc::free ((*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char)) as * mut c_void); + directory_list_offset-=1; + + /* Shift the remainder of the list into place. */ + while i < directory_list_offset { + *((pushd_directory_list as usize +(i*8) as usize) as * mut * mut c_char)=*((pushd_directory_list as usize +((i+1)*8) as usize) as * mut * mut c_char); + i+=1; + } + } + + r_dirs_builtin (std::ptr::null_mut()); + return EXECUTION_SUCCESS!(); +} +} + +/* Print the current list of directories on the directory stack. */ +#[no_mangle] +pub extern "C" fn r_dirs_builtin (listt:* mut WORD_LIST)->i32 +{ + let mut flags:i32=0; + let mut desired_index:i32=-1; + let mut index_flag:i32=0; + let mut vflag:i32=0; + let mut i:libc::c_long=0; + let mut temp:*mut c_char; + let mut w:* mut c_char=CString::new("").unwrap().as_ptr() as * mut c_char; + + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + if list != std::ptr::null_mut() && (*list).word != std::ptr::null_mut() && ISHELP((*((*list).word)).word) { + builtin_help (); + return EX_USAGE!(); + } + + while list != std::ptr::null_mut() { + if ISOPTION ((*((*list).word)).word, 'l' as c_char) { + flags |= LONGFORM!(); + } else if ISOPTION ((*((*list).word)).word, 'c' as c_char) { + flags |= CLEARSTAK!(); + } else if ISOPTION ((*((*list).word)).word, 'v' as c_char) { + vflag |= 2; + } else if ISOPTION ((*((*list).word)).word, 'p' as c_char) { + vflag |= 1; + } else if ISOPTION ((*((*list).word)).word, '-' as c_char) { + list = (*list).next; + break; + } else if *((*((*list).word)).word) == '+' as c_char || *((*((*list).word)).word) == '-' as c_char { + let sign:i32; + w = ((*((*list).word)).word as usize +1) as * mut c_char; + if legal_number (w, &mut i) == 0 { + sh_invalidnum ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } + + if *((*((*list).word)).word) == '+' as c_char { + sign = -1; + } else { + sign = -1; + } + + desired_index = r_get_dirstack_index (i, sign, &mut index_flag); + } else { + sh_invalidopt ((*((*list).word)).word); + builtin_usage (); + return EX_USAGE!(); + } + list=(*list).next + } + + if (flags & CLEARSTAK!()) !=0 { + r_clear_directory_stack (); + return EXECUTION_SUCCESS!(); + } + + if index_flag !=0 && (desired_index < 0 || desired_index > directory_list_offset) { + r_pushd_error (directory_list_offset, w); + return EXECUTION_FAILURE!(); + } + + /* The first directory printed is always the current working directory. */ + if index_flag == 0 || (index_flag == 1 && desired_index == 0) { + temp = get_working_directory (CString::new("dirs").unwrap().as_ptr() as * mut c_char); + if temp == std::ptr::null_mut() { + temp = savestring (CString::new("").unwrap().as_ptr() as * mut c_char); + } + + if (vflag & 2) !=0 { + if (flags & LONGFORM!()) !=0 { + libc::printf (CString::new("%2d %s").unwrap().as_ptr(), 0, temp); + } else { + libc::printf (CString::new("%2d %s").unwrap().as_ptr(), 0, polite_directory_format (temp)); + } + } else { + if (flags & LONGFORM!()) !=0 { + libc::printf (CString::new("%s").unwrap().as_ptr(), temp); + } else { + libc::printf (CString::new("%s").unwrap().as_ptr(), polite_directory_format (temp)); + } + } + + libc::free (temp as * mut c_void); + if index_flag !=0 { + libc::putchar ('\n' as libc::c_int); + return sh_chkwrite (EXECUTION_SUCCESS!()); + } + } + + /* Now print the requested directory stack entries. */ + if index_flag !=0 { + if (vflag & 2) !=0 { + if (flags & LONGFORM!()) !=0 { + libc::printf (CString::new("%2d %s").unwrap().as_ptr(), directory_list_offset - desired_index, + *((pushd_directory_list as usize + (desired_index*8) as usize) as * mut * mut c_char) ); + } else { + libc::printf (CString::new("%2d %s").unwrap().as_ptr(), directory_list_offset - desired_index, + polite_directory_format (*((pushd_directory_list as usize + (desired_index*8) as usize) as * mut * mut c_char))); + } + } else { + if (flags & LONGFORM!()) !=0 { + libc::printf (CString::new("%s").unwrap().as_ptr(), *((pushd_directory_list as usize + (desired_index*8) as usize) as * mut * mut c_char) ); + } else { + libc::printf (CString::new("%s").unwrap().as_ptr(), polite_directory_format (*((pushd_directory_list as usize + (desired_index*8) as usize) as * mut * mut c_char))); + } + } + } else { + i = (directory_list_offset - 1) as libc::c_long; + while i >= 0 { + if vflag >= 2 { + if (flags & LONGFORM!()) !=0 { + libc::printf (CString::new("\n%2d %s").unwrap().as_ptr(), directory_list_offset - i as i32 ,*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) ); + } else { + libc::printf (CString::new("\n%2d %s").unwrap().as_ptr(),directory_list_offset - i as i32 ,polite_directory_format (*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char))); + } + } else { + if (flags & LONGFORM!()) !=0 { + if (vflag & 1) !=0 { + libc::printf (CString::new("%s%s").unwrap().as_ptr(),CString::new("\n").unwrap().as_ptr() as * mut c_char,*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) ); + } else { + libc::printf (CString::new("%s%s").unwrap().as_ptr() , CString::new(" ").unwrap().as_ptr() as * mut c_char,*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) ); + } + + } else { + if (vflag & 1) !=0 { + libc::printf (CString::new("%s%s").unwrap().as_ptr(), CString::new("\n").unwrap().as_ptr() as * mut c_char,polite_directory_format (*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char))); + } else { + libc::printf (CString::new("%s%s").unwrap().as_ptr() , CString::new(" ").unwrap().as_ptr() as * mut c_char,polite_directory_format (*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char))); + } + } + + } + i-=1; + } + } + + libc::putchar ('\n' as libc::c_int); + return sh_chkwrite (EXECUTION_SUCCESS!()); + } +} + +#[no_mangle] +pub extern "C" fn r_pushd_error (offset:i32, arg:* mut c_char) +{ + unsafe { + if offset == 0 { + builtin_error (CString::new("directory stack empty").unwrap().as_ptr()); + } else{ + sh_erange (arg, CString::new("directory stack index").unwrap().as_ptr() as * mut c_char); + } + } +} + +#[no_mangle] +pub extern "C" fn r_clear_directory_stack () +{ + let mut i:i32=0; + unsafe { + while i < directory_list_offset { + libc::free (*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) as * mut c_void); + i+=1; + } + + directory_list_offset = 0; + } +} + +/* Switch to the directory in NAME. This uses the cd_builtin to do the work, + so if the result is EXECUTION_FAILURE then an error message has already + been printed. */ +#[no_mangle] +pub extern "C" fn r_cd_to_string (name:* mut c_char)->i32 +{ + unsafe { + let tlist:* mut WORD_LIST; + let dir:* mut WORD_LIST; + let result:i32; + + dir = make_word_list (make_word (name), std::ptr::null_mut()); + tlist = make_word_list (make_word (CString::new("--").unwrap().as_ptr()), dir); + result = cd_builtin (tlist); + dispose_words (tlist); + return result; + } +} + +#[no_mangle] +pub extern "C" fn r_change_to_temp (temp: * mut c_char)->i32 +{ + let tt:i32; + + if temp !=std::ptr::null_mut() { + tt = r_cd_to_string (temp); + } else { + tt= EXECUTION_FAILURE!(); + } + + if tt == EXECUTION_SUCCESS!() { + r_dirs_builtin (std::ptr::null_mut()); + } + + return tt; +} + +#[no_mangle] +pub extern "C" fn r_add_dirstack_element (dir:* mut c_char) +{ + unsafe { + if directory_list_offset == directory_list_size { + directory_list_size += 10; + pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size); + } + + *((pushd_directory_list as usize + (directory_list_offset*8) as usize ) as * mut * mut c_char) = dir; + directory_list_offset+=1; + } +} + +#[no_mangle] +pub extern "C" fn r_get_dirstack_index (ind:libc::c_long, sign:i32, indexp:* mut i32)->i32 +{ + unsafe { + if indexp !=std::ptr::null_mut(){ + if sign > 0 { + *indexp=1; + } else { + *indexp=0; + } + } + /* dirs +0 prints the current working directory. */ + /* dirs -0 prints last element in directory stack */ + if ind == 0 && sign > 0 { + return 0; + } else if ind == directory_list_offset as libc::c_long { + if indexp !=std::ptr::null_mut() { + if sign > 0 { + *indexp = 2; + } else { + *indexp = 1; + } + } + return 0; + } else if ind >= 0 && ind <= directory_list_offset as libc::c_long { + if sign > 0 { + return directory_list_offset - ind as i32; + } else { + return ind as i32; + } + } else { + return -1; + } + } +} + +/* Used by the tilde expansion code. */ +#[no_mangle] +pub extern "C" fn r_get_dirstack_from_string (strt:* mut c_char)-> * mut c_char +{ + let ind:i32; + let mut sign:i32; + let mut index_flag:i32; + let mut i:libc::c_long=0; + + sign = 1; + let mut str1=strt.clone(); + unsafe { + + if *str1 == '-' as c_char || *str1 == '+' as c_char { + if *str1 == '-' as c_char { + sign=-1; + } else { + sign=1; + } + str1=(str1 as usize + 1 ) as * mut c_char; + } + + if legal_number (str1, &mut i) == 0 { + return std::ptr::null_mut(); + } + + index_flag = 0; + ind = r_get_dirstack_index (i, sign, &mut index_flag); + if index_flag !=0 && (ind < 0 || ind > directory_list_offset) { + return std::ptr::null_mut(); + } + + if index_flag == 0 || (index_flag == 1 && ind == 0) { + return get_string_value (CString::new("PWD").unwrap().as_ptr()); + } else { + return *((pushd_directory_list as usize + (ind*8) as usize) as * mut * mut c_char); + } + } +} + +#[no_mangle] +pub extern "C" fn r_get_dirstack_element (ind:libc::c_long, sign:i32)-> * mut c_char +{ + let mut i:i32; + unsafe { + i = r_get_dirstack_index (ind, sign, std::ptr::null_mut()); + if i < 0 || i > directory_list_offset { + return std::ptr::null_mut(); + } else { + return *((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char); + } + } +} + +#[no_mangle] +pub extern "C" fn r_set_dirstack_element (ind:libc::c_long, sign:i32, value:* mut c_char) +{ + let i:i32; + unsafe { + i = r_get_dirstack_index (ind, sign, std::ptr::null_mut()); + if ind == 0 || i < 0 || i > directory_list_offset { + return; + } + libc::free ((*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char)) as * mut c_void); + *((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) = savestring (value); + } +} + +#[no_mangle] +pub extern "C" fn r_get_directory_stack (flags:i32)->* mut WORD_LIST +{ + let mut i:i32; + let mut ret:* mut WORD_LIST; + let mut d:* mut c_char; + let t:* mut c_char; + unsafe { + ret = std::ptr::null_mut(); + i = 0; + while i < directory_list_offset { + if (flags&1) !=0 { + d=polite_directory_format (*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char)); + } else { + d=*((pushd_directory_list as usize + (i*8) as usize) as * mut * mut c_char) + } + ret = make_word_list (make_word (d), ret); + i+=1; + } + /* Now the current directory. */ + d = get_working_directory (CString::new("dirstack").unwrap().as_ptr() as * mut c_char); + i = 0; /* sentinel to decide whether or not to free d */ + if d == std::ptr::null_mut() { + d = CString::new(".").unwrap().as_ptr() as * mut c_char; + } else { + if (flags&1) !=0 { + t=polite_directory_format(d); + } else { + t=d; + } + /* polite_directory_format sometimes returns its argument unchanged. + If it does not, we can free d right away. If it does, we need to + mark d to be deleted later. */ + if t != d { + libc::free (d as * mut c_void); + d = t; + } else { /* t == d, so d is what we want */ + i = 1; + } + } + ret = make_word_list (make_word (d), ret); + if i !=0 { + libc::free (d as * mut c_void); + } + return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */ + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"pushd" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_pushd_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/read/Cargo.toml b/bash-5.1/builtins_rust/read/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..79188cea38680aae347fe57d76492ca2d78524ef 100644 --- a/bash-5.1/builtins_rust/read/Cargo.toml +++ b/bash-5.1/builtins_rust/read/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "read" +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 = "rread" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/read/src/intercdep.rs b/bash-5.1/builtins_rust/read/src/intercdep.rs new file mode 100644 index 0000000000000000000000000000000000000000..61985e931645181fcd38c714e40f2ab80e12901d --- /dev/null +++ b/bash-5.1/builtins_rust/read/src/intercdep.rs @@ -0,0 +1,320 @@ + +#[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 SHELL_VAR = variable; + +pub type __intmax_t = c_long; +pub type intmax_t = __intmax_t; +pub type arrayind_t = intmax_t; +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 __jmp_buf = [c_long; 8usize]; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __sigset_t { + pub __val: [c_ulong; 16usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __jmp_buf_tag { + pub __jmpbuf: __jmp_buf, + pub __mask_was_saved: c_int, + pub __saved_mask: __sigset_t, +} + +pub type sigjmp_buf = [__jmp_buf_tag; 1usize]; + +pub type rl_hook_func_t = fn() -> c_int; +pub type rl_completion_func_t = fn(args1 : *const c_char, args2 : c_int) -> *mut *mut c_char; + +#[repr(C)] +#[derive(Copy, Clone)] +pub union __mbstate_t__bindgen_ty_1 { + pub __wch: c_uint, + pub __wchb: [c_char; 4], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __mbstate_t { + pub __count: c_int, + pub __value: __mbstate_t__bindgen_ty_1, +} +pub type mbstate_t = __mbstate_t; + +pub const EXECUTION_SUCCESS : c_int = 0; +pub const EXECUTION_FAILURE : c_int = 1; +pub const EINTR : c_int = 4; +pub const EX_USAGE : c_int = 258; + +pub const VA_NOEXPAND : c_int = 0x001; +pub const VA_ONEWORD : c_int = 0x002; + +pub const ISFUNC: c_int = 0; + +pub const MB_LEN_MAX: c_int = 16; + +pub const CTLESC: c_char = b'\x01' as c_char; +pub const CTLNUL: c_char = b'\x4f' as c_char; + +pub const __S_IFMT: u32 = 0o0170000; +pub const __S_IFREG: u32 = 0o0100000; + +extern "C" { + pub fn reset_internal_getopt(); + + pub fn internal_getopt( + arg1: *mut WORD_LIST, + arg2: *mut c_char, + ) -> c_int; + + pub fn list_string(s: *mut c_char, t: *mut c_char, i: c_int) -> *mut WORD_LIST; + pub fn dequote_string(s: *mut c_char) -> *mut c_char; + pub fn dequote_list(s: *mut WORD_LIST) -> *mut WORD_LIST; + pub fn word_list_remove_quoted_nulls(s: *mut WORD_LIST); + pub fn dispose_words(s: *mut WORD_LIST); + pub fn assign_array_var_from_word_list(var: *mut SHELL_VAR, list: *mut WORD_LIST, flags: c_int) -> *mut SHELL_VAR; + + pub fn builtin_usage(); + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + pub static mut assoc_expand_once : c_int; + pub static mut interactive_shell : c_int; + + pub static mut rl_num_chars_to_read: c_int; + pub static mut rl_attempted_completion_function : rl_completion_func_t; + + pub static mut bash_readline_initialized : c_int; + pub static mut rl_startup_hook: *mut rl_hook_func_t; + + pub static interrupt_state : c_int; + pub static terminating_signal : c_int; + pub static trapped_signal_received : c_int; + + pub static mut alrmbuf: sigjmp_buf; + + pub static mut rl_instream: *mut libc::FILE; + + pub static posixly_correct: c_int; + + pub static locale_utf8locale: c_int; + + pub static mut ifs_cmap: [u8; 256]; + + pub fn uconvert( + s: *mut c_char, + ip: *mut c_long, + up: *mut c_long, + ep: *mut *mut c_char, + ) -> c_int; + + pub fn builtin_error(arg1: *const c_char, ...); + + pub fn legal_number( + arg1: *const c_char, + arg2: *mut std::os::raw::c_long, + ) -> c_int; + + pub fn sh_invalidnum(arg1: *mut c_char); + + pub fn sh_validfd(arg1: c_int) -> c_int; + + pub fn input_avail(arg1: c_int) -> c_int; + + pub fn legal_identifier(arg1: *const c_char) -> c_int; + + pub fn valid_array_reference( + arg1: *const c_char, + arg2: c_int, + ) -> c_int; + + pub fn sh_invalidid(arg1: *mut c_char); + + pub fn getifs() -> *mut c_char; + + pub fn xmalloc(arg1: libc::size_t) -> *mut c_void; + + pub fn xfree(arg1: *mut c_void); + + pub fn xrealloc(arg1: *mut c_void, arg2: libc::size_t) + -> *mut c_void; + + pub fn get_string_value(arg1: *const c_char) -> *mut c_char; + + pub fn begin_unwind_frame(arg1: *mut c_char); + pub fn run_unwind_frame(arg1: *mut c_char); + pub fn discard_unwind_frame(arg1: *mut c_char); + + pub fn fd_is_bash_input(arg1: c_int) -> c_int; + + pub fn sync_buffered_stream(arg1: c_int) -> c_int; + + pub fn initialize_readline() -> c_void; + pub fn readline(p : *const c_char) -> *mut c_char; + pub fn rl_insert_text(p : *const c_char) -> c_int; + + pub fn bashline_set_event_hook() -> c_void; + pub fn bashline_reset_event_hook() -> c_void; + + pub fn zreadintr(arg1: c_int, arg2: *mut c_char, arg3: size_t) -> libc::ssize_t; + pub fn zreadcintr(arg1: c_int, arg2: *mut c_char) -> libc::ssize_t; + + pub fn zread(arg1: c_int, arg2: *mut c_char, arg3: size_t) -> libc::ssize_t; + pub fn zreadn(arg1: c_int, arg2: *mut c_char, arg3: size_t) -> libc::ssize_t; + pub fn zreadc(arg1: c_int, arg2: *mut c_char) -> libc::ssize_t; + + pub fn zsyncfd(fd: c_int) -> c_void; + + pub fn check_signals(); + pub fn termsig_handler(arg1: c_int) -> c_void; + pub fn throw_to_top_level() -> c_void; + + pub fn builtin_bind_variable(name: *mut c_char, value: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + pub fn bind_variable(name: *const c_char, value: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + pub fn find_or_make_array_variable(name: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + + pub fn array_flush(a: *mut ARRAY); + + pub fn get_word_from_string(stringp: *mut *mut c_char, separators: *mut c_char, endptr: *mut *mut c_char) -> *mut c_char; + + pub fn stupidly_hack_special_variables(name: *mut c_char); + pub fn strip_trailing_ifs_whitespace(s: *mut c_char, sep: *mut c_char, es: c_int) -> *mut c_char; +} + +extern "C" { + pub fn initialize_terminating_signals(); +} + +pub type SigHandler = unsafe extern "C" fn(arg1: c_int); +extern "C" { + pub fn set_signal_handler(arg1: c_int, arg2: *mut SigHandler) -> *mut SigHandler; +} + +extern "C" { + // todo: more f type + pub fn add_unwind_protect(f : *mut c_void,...); + pub fn unwind_protect_mem(var : *mut c_int, size : c_int); + pub fn remove_unwind_protect() -> c_void; +} + +extern "C" { + pub fn falarm( + arg1: c_uint, + arg2: c_uint, + ) -> c_uint; +} + +extern "C" { + pub fn __sigsetjmp( + __env: *mut __jmp_buf_tag, + __savemask: c_int, + ) -> c_int; + + pub fn siglongjmp(__env: *mut __jmp_buf_tag, __val: c_int); + +} + +extern "C" { + pub fn ttgetattr(arg1: c_int, arg2: *mut libc::termios) -> c_int; + pub fn ttsetattr(arg1: c_int, arg2: *mut libc::termios) -> c_int; + + pub fn ttfd_noecho( + arg1: c_int, + arg2: *mut libc::termios, + ) -> c_int; + +} + +extern "C" { + pub fn sh_ttyerror(arg1: c_int); + pub fn ttfd_cbreak(fd: c_int, ttp: *mut libc::termios) -> c_int; + pub fn ttfd_onechar(fd: c_int, ttp: *mut libc::termios) -> c_int; +} + + +pub type rl_command_func_t = unsafe extern "C" fn(c_int, c_int) -> c_int; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _keymap_entry { + pub tp: c_char, + pub function: rl_command_func_t, +} +pub type KEYMAP_ENTRY = _keymap_entry; +pub type Keymap = *mut KEYMAP_ENTRY; + +extern "C" { + pub fn rl_get_keymap() -> Keymap; + pub fn rl_insert(count: c_int, key: c_int) -> c_int; + pub fn rl_newline(count: c_int, key: c_int) -> c_int; + +} + +extern "C" { + pub fn mbrtowc(pwc: *mut libc::wchar_t, s: *mut c_char, n: libc::size_t, ps: *mut mbstate_t) -> libc::size_t; + pub fn mbrlen(mbstr: *const c_char, count: size_t, mbstate: *mut mbstate_t) -> c_int; +} + +pub const atype_array_indexed: atype = 0; +pub const atype_array_assoc: atype = 1; +pub type atype = c_uint; + +#[repr(C)] +#[derive(Debug, 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(Debug, 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; diff --git a/bash-5.1/builtins_rust/read/src/lib.rs b/bash-5.1/builtins_rust/read/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8015ec1bdb1e8a163b80b63470ef4306b9fbb214 100644 --- a/bash-5.1/builtins_rust/read/src/lib.rs +++ b/bash-5.1/builtins_rust/read/src/lib.rs @@ -0,0 +1,1008 @@ +use libc::{c_int, c_char, c_long, c_ulong, c_uint, size_t, c_void, PT_NULL, ssize_t}; +use nix::errno::errno; +use std::{ffi::{CString, CStr}, ptr::null_mut}; + +include!(concat!("intercdep.rs")); + +static mut old_alrm : *mut SigHandler = PT_NULL as *mut SigHandler; + +static mut sigalrm_seen : c_int = 0; +static mut reading : c_int = 0; +static mut tty_modified : c_int = 0; + +static mut delim : c_char= b'\n' as c_char; +#[derive(Clone, Copy)] +pub struct tty_save { + fd: i32, + attrs: libc::termios, +} + +static mut termsave : Option = None; +static mut ptermsave: *mut c_void = PT_NULL as *mut c_void; + +static mut interactive : c_int = 0; +static mut default_buffered_input : c_int = -1; + +#[no_mangle] +pub extern "C" fn r_read_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_read_builtin call"); + + let mut varname :*mut c_char = libc::PT_NULL as *mut c_char; + let mut size : c_int = 0; + let mut nr : c_int = 0; + let mut pass_next : c_int = 0; + let mut saw_escape : c_int = 0; + let mut eof : c_int; + let mut opt : c_int; + let mut retval : c_int; + let mut code : c_int; + let mut print_ps2 : c_int; + let mut nflag : c_int = 0; + + let mut i : c_int = 0; + + let mut input_is_tty : c_int = 0; + let mut input_is_pipe : c_int = 0; + let mut unbuffered_read : c_int = 0; + let mut skip_ctlesc : c_int; + let mut skip_ctlnul : c_int; + + let mut raw : c_int = 0; + let mut edit : c_int = 0; + let mut nchars : c_int = 0; + let mut silent : c_int = 0; + let mut have_timeout : c_int = 0; + let mut ignore_delim : c_int = 0; + let mut fd : c_int = 0; + + let mut lastsig : c_int = 0; + let mut t_errno : c_int; + + let mut mb_cur_max : c_int; + + let mut tmsec : c_uint = 0; + let mut tmusec : c_uint = 0; + + let mut ival : c_long = 0; + let mut uval : c_long = 0; + let mut intval : c_long = 0; + + let mut c : c_char = 0; + + let mut input_string : *mut c_char; + let mut orig_input_string : *mut c_char; + let ifs_chars_null = CString::new("").unwrap(); + let mut ifs_chars : *mut c_char; + let mut prompt : *mut c_char = PT_NULL as *mut c_char; + let mut arrayname : *mut c_char = PT_NULL as *mut c_char; + + let mut e : *mut c_char; + let t : *mut c_char; + let t1 : *mut c_char; + let mut ps2 : *mut c_char; + let mut tofree : *mut c_char; + + let mut tsb : libc::stat; + + let mut var : *mut SHELL_VAR = PT_NULL as *mut SHELL_VAR; + + let mut ttattrs : libc::termios; + let mut ttset : libc::termios; + unsafe { + ttattrs = std::mem::zeroed(); + ttset = std::mem::zeroed(); + } + + let mut alist : *mut WORD_LIST; + + let mut vflags : c_int; + let mut rlbuf : *mut c_char = null_mut(); + let mut itext : *mut c_char = null_mut(); + + let mut rlind : c_int = 0; + + + let mut save_instream : *mut libc::FILE; + + let mut mb_cur_max : c_int = 1; + +unsafe { + + if termsave.is_none() { + let tmp: tty_save = std::mem::zeroed(); + termsave = Some(tmp); + } + ptermsave = std::mem::transmute(&termsave.unwrap()); + + reset_internal_getopt(); + let opt_str = CString::new("ersa:d:i:n:p:t:u:N:").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 { + 'r' => raw = 1, + 'p' => prompt = list_optarg, + 's' => silent = 1, + 'e' => edit = 1, + 'i' => itext = list_optarg, + 'a' => arrayname = list_optarg, + 't' => { + code = uconvert(list_optarg, &mut ival, &mut uval, PT_NULL as *mut *mut c_char); + if code == 0 || ival < 0 || uval < 0 { + let c_err = CString::new("%s: invalid timeout specification").unwrap(); + builtin_error( c_err.as_ptr(), list_optarg); + return EXECUTION_FAILURE; + } else { + have_timeout = 1; + tmsec = ival as c_uint; + tmusec = uval as c_uint; + } + } + 'N' => { + ignore_delim = 1; + delim = -1; + } + 'n' => { + nflag = 1; + code = legal_number(list_optarg, &mut intval); + if code == 0 || intval < 0 || intval != (intval as c_int) as c_long { + sh_invalidnum(list_optarg); + return EXECUTION_FAILURE; + } else { + nchars = intval as c_int; + } + } + 'u' => { + code = legal_number(list_optarg, &mut intval); + if code == 0 || intval < 0 || intval != (intval as c_int) as c_long { + let c_err = CString::new("%s: invalid file descriptor specification").unwrap(); + builtin_error(c_err.as_ptr(), list_optarg); + return EXECUTION_FAILURE; + } else { + fd = intval as c_int; + } + if sh_validfd(fd) == 0 { + let c_err = CString::new("%d: invalid file descriptor: %s").unwrap(); + builtin_error(c_err.as_ptr(), fd, libc::strerror(nix::errno::errno())); + return EXECUTION_FAILURE; + } + } + 'd' => delim = *list_optarg, + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + } + + list = loptend; + + if have_timeout == 1 && tmsec == 0 && tmusec == 0 { + return if input_avail(fd) != 0 {EXECUTION_SUCCESS} else {EXECUTION_FAILURE}; + } + + vflags = if assoc_expand_once != 0 {(VA_NOEXPAND | VA_ONEWORD) as c_int} else {0}; + + if !list.is_null() && + legal_identifier((*(*list).word).word) == 0 && + valid_array_reference((*(*list).word).word, vflags) == 0 { + sh_invalidid((*(*list).word).word); + return EXECUTION_FAILURE; + } + + ifs_chars = getifs(); + if ifs_chars.is_null() { + ifs_chars = ifs_chars_null.as_ptr() as *mut c_char; + } + + if ignore_delim != 0 { + delim = -1; + ifs_chars = ifs_chars_null.as_ptr() as *mut c_char; + } + + skip_ctlesc = 0; + skip_ctlnul = 0; + e = ifs_chars; + loop { + if *e == 0 { + break; + } + skip_ctlesc |= (*e == 1) as c_int; + skip_ctlnul |= (*e == 117) as c_int; + e = ((e as usize) + 1) as *mut c_char; + } + + input_string = xmalloc(112) as *mut c_char; + *input_string = b'\0' as c_char; + +'out_assig_vars: loop { + if nflag == 1 && nchars == 0 { + let mut gc : c_int = 0; + retval = libc::read(fd, &mut gc as *mut i32 as *mut c_void, 0) as c_int; + retval = if retval >= 0 {EXECUTION_SUCCESS} else {EXECUTION_FAILURE}; + + break 'out_assig_vars; + } + + let str_val = CString::new("TMOUT").unwrap(); + e = get_string_value(str_val.as_ptr()); + if have_timeout == 0 && !e.is_null() { + code = uconvert(e, &mut ival, &mut uval, 0 as *mut *mut c_char); + if code == 0 || ival < 0 || uval < 0 { + tmsec = 0; + tmusec = 0; + } else { + tmsec = ival as c_uint; + tmusec = uval as c_uint; + } + } + + let frame_name = CString::new("read_builtin").unwrap(); + begin_unwind_frame(frame_name.as_ptr() as *mut c_char); + + if interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input(fd) != 0 { + sync_buffered_stream(default_buffered_input); + } + + input_is_tty = libc::isatty(fd); + if input_is_tty == 0 { + input_is_pipe = (libc::lseek(fd, 0, libc::SEEK_CUR) < 0 && (errno() == libc::ESPIPE)) as c_int; + } + + if (!prompt.is_null() || edit != 0 || silent != 0) && input_is_tty == 0 { + itext = PT_NULL as *mut c_char; + edit = 0; + silent = 0; + } + + if edit != 0 { + add_unwind_protect(xfree as *mut c_void, rlbuf); + } + + tsb = std::mem::zeroed(); + if tmsec > 0 || tmusec > 0 { + if (libc::fstat(fd, &mut tsb as *mut libc::stat) < 0) || + ((tsb.st_mode & __S_IFMT) == __S_IFREG) { + tmsec = 0; + tmusec = 0; + } + } + + if tmsec > 0 || tmusec > 0 { + code = __sigsetjmp(&mut alrmbuf as *mut __jmp_buf_tag, 0); + if code != 0 { + sigalrm_seen = 0; + orig_input_string = PT_NULL as *mut c_char; + if i == 0 { + t = libc::malloc(1) as *mut c_char; + *t = b'\0' as c_char; + } else { + t = libc::strcpy( xmalloc( + (libc::strlen(input_string) + 1) as size_t) as *mut c_char, input_string); + } + + run_unwind_frame(frame_name.as_ptr() as *mut c_char); + input_string = t; + retval = 128 + libc::SIGALRM; + break 'out_assig_vars; + } + + if interactive_shell == 0 { + initialize_terminating_signals(); + } + + old_alrm = set_signal_handler(libc::SIGALRM, sigalrm as *mut SigHandler); + add_unwind_protect(reset_alarm as *mut c_void, PT_NULL as *mut c_char); + + if edit != 0 { + add_unwind_protect(reset_attempted_completion_function as *mut c_void, + PT_NULL as *mut c_char); + add_unwind_protect(bashline_reset_event_hook as *mut c_void, + PT_NULL as *mut c_char); + } + + falarm(tmsec, tmusec); + } + + if nchars > 0 || delim != b'\n' as c_char { + if edit != 0 { + if nchars > 0 { + unwind_protect_mem(&mut rl_num_chars_to_read as *mut c_int, std::mem::size_of_val(&rl_num_chars_to_read) as c_int); + rl_num_chars_to_read = nchars; + } + + if delim != b'\n' as c_char { + set_eol_delim(delim as c_int); + add_unwind_protect(reset_eol_delim as *mut c_void, PT_NULL as *mut c_char); + } + } else if input_is_tty != 0 { + termsave.unwrap().fd = fd; + ttgetattr(fd, &mut ttattrs as *mut libc::termios); + termsave.unwrap().attrs = ttattrs; + ttset = ttattrs; + if silent != 0 { + i = ttfd_cbreak(fd, std::mem::transmute(&ttset)); + } else { + i = ttfd_onechar(fd, std::mem::transmute(&ttset)); + } + + if i < 0 { + sh_ttyerror(1); + } + tty_modified = 1; + add_unwind_protect(ttyrestore as *mut c_void, ptermsave); + if interactive_shell == 0 { + initialize_terminating_signals(); + } + + } + } else if silent != 0 { + termsave.unwrap().fd = fd; + ttgetattr(fd, &mut ttattrs as *mut libc::termios); + termsave.unwrap().attrs = ttattrs; + + ttset = ttattrs; + i = ttfd_noecho(fd, std::mem::transmute(&ttset)); + if i < 0 { + sh_ttyerror(1); + } + + tty_modified = 1; + add_unwind_protect(ttyrestore as *mut c_void, ptermsave); + if interactive_shell == 0 { + initialize_terminating_signals(); + } + } + + save_instream = std::mem::zeroed(); + if edit != 0 && fd != 0 { + if bash_readline_initialized == 0 { + initialize_readline(); + } + + unwind_protect_mem(std::mem::transmute(rl_instream), std::mem::size_of_val(&rl_instream) as c_int); + save_instream = rl_instream; + rl_instream = libc::fdopen(fd, "r".as_ptr() as *const c_char); + + } + + add_unwind_protect(xfree as *mut c_void, input_string); + check_alrm(); + if nchars > 0 && input_is_tty == 0 && ignore_delim != 0 { + unbuffered_read = 2; + } else if nchars > 0 || delim != b'\n' as c_char || input_is_pipe != 0 { + unbuffered_read = 1; + } + + if !prompt.is_null() && edit == 0 { + eprintln!("{}", CStr::from_ptr(prompt).to_str().unwrap()); + + } + + ps2 = PT_NULL as *mut c_char; + print_ps2 = 0; + eof = 0; + retval = 0; + 'get_input_string: loop { + if sigalrm_seen != 0 { + siglongjmp (std::mem::transmute(&alrmbuf), 1); + } + + if edit != 0 { + if !rlbuf.is_null() && + *((rlbuf as usize + rlind as usize) as *mut c_char) == 0 && + delim != 0 { + libc::free(rlbuf as *mut c_void); + rlbuf = PT_NULL as *mut c_char; + } + if rlbuf.is_null() { + reading = 1; + rlbuf = if prompt.is_null() {edit_line("".as_ptr() as *mut c_char, itext)} + else {edit_line(prompt, itext)}; + reading = 0; + rlind = 0; + } + if rlbuf.is_null() { + eof = 1; + break 'get_input_string; + } + c = *((rlbuf as usize + rlind as usize) as *mut c_char); + rlind += 1; + } else { + if print_ps2 != 0 { + if ps2.is_null() { + ps2 = get_string_value("PS2".as_ptr() as *const c_char); + } + eprintln!("{}", CStr::from_ptr(prompt).to_str().unwrap()); + print_ps2 = 0; + } + + reading = 1; + check_alrm(); + *(libc::__errno_location()) = 0; + if unbuffered_read == 2 { + retval = if posixly_correct != 0 {zreadintr(fd, &mut c as *mut c_char, 1) as c_int} + else {zreadn(fd, &mut c as *mut c_char, (nchars - nr) as usize) as c_int}; + } else if unbuffered_read != 0 { + retval = if posixly_correct != 0 {zreadintr(fd, &mut c as *mut c_char, 1) as c_int} + else {zreadn(fd, &mut c as *mut c_char, 1) as c_int}; + } else { + retval = if posixly_correct != 0 {zreadcintr(fd, &mut c as *mut c_char) as c_int} + else {zreadc(fd, &mut c as *mut c_char) as c_int}; + } + + reading = 0; + + if retval <= 0 { + let t = *libc::__errno_location(); + if retval < 0 && *libc::__errno_location() == libc::EINTR { + check_signals(); + //lastsig = LASTSIG(); + if terminating_signal != 0 { + lastsig = terminating_signal; + } else { + lastsig = if interrupt_state != 0 {libc::SIGINT} else { 0 }; + } + + if lastsig == 0 { + lastsig = trapped_signal_received; + } + } else { + lastsig = 0; + } + + if terminating_signal != 0 && tty_modified != 0 { + ttyrestore(); + } + check_alrm(); + eof = 1; + *libc::__errno_location() = t; + break 'get_input_string; + } + + quit(); + } + + if retval <= 0 { + check_alrm(); + } + + if mb_cur_max <= 4 { + mb_cur_max = 4; + } + if i + mb_cur_max >= size { + size += 128; + let t: *mut c_char= xrealloc(input_string as *mut c_void, size as usize) as *mut c_char; + if t != input_string { + input_string = t; + remove_unwind_protect(); + add_unwind_protect(xfree as *mut c_void, input_string); + } + } +'out_add_char: loop { + if pass_next != 0 { + pass_next = 0; + if c == b'\n' as c_char { + if skip_ctlesc == 0 && i > 0 {i -= 1;} + if interactive != 0 && input_is_tty != 0 && raw == 0 {print_ps2 = 1;} + } else { + break 'out_add_char; + } + continue 'get_input_string; + } + + if c == b'\\' as c_char && raw == 0 { + pass_next += 1; + if skip_ctlesc == 0 { + saw_escape += 1; + *((input_string as usize + i as usize) as *mut c_char) = CTLESC; + i += 1; + } + continue 'get_input_string; + } + + if ignore_delim == 0 && c == delim { + break 'get_input_string; + } + + if c == b'\0' as c_char && delim != b'\0' as c_char { + continue 'get_input_string; + } + + if (skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL) { + saw_escape += 1; + *((input_string as usize + i as usize) as *mut c_char) = CTLESC; + i += 1; + } + break 'out_add_char; + } + *((input_string as usize + i as usize) as *mut c_char) = c; + i += 1; + check_alrm(); + + if mb_cur_max > 1 && is_basic(c) == 0 { + *((input_string as usize + i as usize) as *mut c_char) = b'\0' as c_char; + + if edit != 0 { + let clen = mbrlen((rlbuf as usize + rlind as usize - 1) as *const c_char, + mb_cur_max as usize, + std::mem::transmute(&PT_NULL)); + if clen > 1 { + libc::memcpy( (input_string as usize + i as usize) as *mut c_void, + (rlbuf as usize + rlind as usize) as *mut c_void, (clen - 1) as size_t); + i += clen - 1; + rlind += clen - 1; + } + } else if locale_utf8locale == 0 || ((c as u8 & 0x80) != 0) { + i += read_mbchar(fd, input_string, i, c as c_int, unbuffered_read); + } + + nr += 1; + if nchars > 0 && nr >= nchars { + break 'get_input_string; + } + } + } + + *((input_string as usize + i as usize) as *mut c_char) = b'\0' as c_char; + check_alrm(); + + if edit != 0 { + libc::free(rlbuf as *mut c_void); + } + + if retval < 0 { + t_errno = *libc::__errno_location(); + if *libc::__errno_location() != EINTR { + let c_err = CString::new("read error: %d: %s").unwrap(); + builtin_error( c_err.as_ptr(), fd, libc::strerror(*libc::__errno_location())); + } + + run_unwind_frame(frame_name.as_ptr() as *mut c_char); + return if t_errno != EINTR {EXECUTION_FAILURE} else { 128 + lastsig}; + } + + if tmsec > 0 || tmusec > 0 { + reset_alarm(); + } + + if nchars > 0 || delim != b'\n' as c_char { + if edit != 0 { + + } else if input_is_tty != 0 { + ttyrestore(); + } + } else if silent != 0 { + ttyrestore(); + } + + if unbuffered_read != 0 { + zsyncfd(fd); + } + + if !save_instream.is_null() { + rl_instream = save_instream; + } + + discard_unwind_frame(frame_name.as_ptr() as *mut c_char); + + retval = if eof != 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; + + break 'out_assig_vars; +} + + if !arrayname.is_null() { + if legal_identifier(arrayname) == 0 { + sh_invalidid(arrayname); + libc::free(input_string as *mut c_void); + return EXECUTION_FAILURE; + } + + var = find_or_make_array_variable(arrayname, 1); + if var.is_null() { + libc::free(input_string as *mut c_void); + return EXECUTION_FAILURE; /* readonly or noassign */ + } + if ((*var).attributes & 0x0000040) != 0 { + let c_err = CString::new("%s: cannot convert associative to indexed array").unwrap(); + builtin_error(c_err.as_ptr(), arrayname); + libc::free(input_string as *mut c_void); + return EXECUTION_FAILURE; /* existing associative array */ + } else if ((*var).attributes & 0x0001000) != 0 { + (*var).attributes &= ((*var).attributes as u32 ^ 0xffffffff as u32) as i32; + } + + array_flush(std::mem::transmute((*var).value)); + + alist = list_string(input_string, ifs_chars, 0); + if !alist.is_null() { + if saw_escape != 0 { + dequote_list(alist); + } else { + word_list_remove_quoted_nulls(alist); + } + assign_array_var_from_word_list(var, alist, 0); + dispose_words(alist); + } + + libc::free(input_string as *mut c_void); + return retval; + } + + if list.is_null() { + if saw_escape != 0 { + let t = dequote_string(input_string); + var = bind_variable("REPLY".as_ptr() as *const c_char, t, 0); + libc::free(t as *mut c_void); + } else { + var = bind_variable("REPLY".as_ptr() as *const c_char, input_string, 0); + } + let cond = var.is_null() || ((*var).attributes & 0x0000002) != 0 || ((*var).attributes & 0x0004000) != 0; + if cond { + retval = EXECUTION_FAILURE; + } else { + (*var).attributes &= ((*var).attributes as u32 ^ 0xffffffff as u32) as i32; + } + + libc::free(input_string as *mut c_void); + return retval; + } + + orig_input_string = input_string; + + let mut t = input_string; + while !ifs_chars.is_null() && *ifs_chars != 0 && + (*t == b' ' as c_char|| *t == b'\t' as c_char || *t == b'\n' as c_char) && + (ifs_cmap[*t as usize] != 0) { + t = (t as usize + 1) as *mut c_char; + } + input_string = t; + + while !(*list).next.is_null() { + varname = (*((*list).word)).word; + + if legal_identifier(varname) == 0 && + valid_array_reference(varname, vflags) == 0 { + sh_invalidid(varname); + libc::free(orig_input_string as *mut c_void); + return EXECUTION_FAILURE; + } + + if *input_string != 0 { + t = get_word_from_string(std::mem::transmute(&input_string), ifs_chars, std::mem::transmute(&e)); + if !t.is_null() { *e = b'\0' as c_char;} + + if !t.is_null() && saw_escape != 0 { + let t1 = dequote_string(t); + var = bind_read_variable(varname, t1); + libc::free(t1 as *mut c_void); + } else { + var = bind_read_variable(varname, if !t.is_null() {t} else {"".as_ptr() as *mut c_char}); + } + } else { + t = PT_NULL as *mut c_char; + var = bind_read_variable(varname, "".as_ptr() as *mut c_char); + } + + if !t.is_null() { + libc::free(t as *mut c_void); + } + + if var.is_null() { + libc::free(orig_input_string as *mut c_void); + return EXECUTION_FAILURE; + } + + stupidly_hack_special_variables(varname); + (*var).attributes &= ((*var).attributes as u32 ^ 0xffffffff as u32) as i32; + + list = (*list).next; + } + + if legal_identifier((*((*list).word)).word) == 0 && + valid_array_reference((*((*list).word)).word, vflags) == 0 { + sh_invalidid((*((*list).word)).word); + libc::free(orig_input_string as *mut c_void); + return EXECUTION_FAILURE; + } + + tofree = PT_NULL as *mut c_char; + if *input_string != 0 { + t1 = input_string; + t = get_word_from_string(std::mem::transmute(&input_string), ifs_chars, std::mem::transmute(&e)); + if *input_string == 0 { + input_string = t; + tofree = input_string; + } else { + input_string = strip_trailing_ifs_whitespace(t1, ifs_chars, saw_escape); + tofree = t; + } + } + + if saw_escape != 0 && !input_string.is_null() && *input_string != 0 { + t = dequote_string(input_string); + var = bind_read_variable((*((*list).word)).word, t); + libc::free(t as *mut c_void); + } else { + var = bind_read_variable((*((*list).word)).word, if !input_string.is_null() {input_string} else {"".as_ptr() as *mut c_char}); + } + + if !var.is_null() { + stupidly_hack_special_variables((*((*list).word)).word); + (*var).attributes &= ((*var).attributes as u32 ^ 0xffffffff as u32) as i32; + } else { + retval = EXECUTION_FAILURE; + } + + if !tofree.is_null() { + libc::free(tofree as *mut c_void); + } + libc::free(orig_input_string as *mut c_void); + return retval; +} +} + +/* ---------------------------------------------------------------------------------- */ + +pub fn is_basic(c: i8) -> u32 { + let is_basic_table :[c_uint; 8] = [ 0x00001a00, 0xffffffef, 0xfffffffe, 0x7ffffffe, 0,0,0,0]; + + let index = (c >> 5) as usize; + return (is_basic_table[index] >> (c & 31) ) & 1; +} + +pub fn bind_read_variable(name: *mut c_char, value: *mut c_char) -> * mut SHELL_VAR { + let v: *mut SHELL_VAR; +unsafe { + v = builtin_bind_variable(name, value, 0); + + if v.is_null() { + return v; + } else { + if ((*v).attributes & 0x0000002) != 0 || ((*v).attributes & 0x0004000) != 0 { + return PT_NULL as *mut SHELL_VAR; + } else { + return v; + } + } +} +} + +fn read_mbchar(fd: c_int, string: *mut c_char, ind: c_int, ch: c_int, unbuffered: c_int) -> c_int { + let mut i: size_t = 1; + let mut r: ssize_t; + let mut c: c_char = 0; + let mut ret: ssize_t; + +unsafe { + let mut mbchar: [c_char; MB_LEN_MAX as usize + 1] = std::mem::zeroed(); + let mut ps: mbstate_t = std::mem::zeroed(); + let mut ps_back: mbstate_t = std::mem::zeroed(); + let mut wc: libc::wchar_t = std::mem::zeroed(); + +'out: loop { + mbchar[0] = ch as c_char; + for n in 0..= MB_LEN_MAX { + ps_back = ps; + ret = mbrtowc(std::mem::transmute(&wc), std::mem::transmute(&mbchar), i, std::mem::transmute(&ps)) as ssize_t; + if ret == -2 { + ps = ps_back; + + /* We don't want to be interrupted during a multibyte char read */ + if unbuffered == 2 { + r = zreadn(fd, std::mem::transmute(&c), 1); + } else if unbuffered != 0 { + r = zread(fd, std::mem::transmute(&c), 1); + } else { + r = zreadc(fd, std::mem::transmute(&c)); + } + if r <= 0 { + break 'out; + } + mbchar[i] = c; + i += 1; + continue; + } else if ret == -1 || ret == 0 || ret > 0 { + break; + } + } + break 'out; +} + if i > 1 { + r = 1; + while r < i as isize { + *((string as usize + ind as usize + r as usize -1) as *mut c_char) = mbchar[r as size_t]; + + r += 1; + } + } + return (i - 1) as c_int; +} +} + +fn quit() { +unsafe { + if terminating_signal != 0 { + termsig_handler(terminating_signal); + } + + if interrupt_state != 0 { + throw_to_top_level(); + } +} +} + +fn check_alrm() { + unsafe { + if sigalrm_seen != 0 { + siglongjmp (std::mem::transmute(&alrmbuf), 1); + } + } +} + +static mut old_attempted_completion_function: usize = 0; + +pub fn reset_attempted_completion_function(cp: *mut c_char) +{ +unsafe { + if rl_attempted_completion_function as usize == 0 && + old_attempted_completion_function as usize != 0 { + rl_attempted_completion_function = std::mem::transmute(old_attempted_completion_function); + } +} +} + +static mut old_startup_hook: usize = 0; +static mut deftext: *mut c_char = PT_NULL as *mut c_char; + +fn set_itext() -> c_int +{ + let mut r1 = 0; + let mut r2 = 0; + +unsafe { + if old_startup_hook != 0 { + let fp: rl_hook_func_t = std::mem::transmute(old_startup_hook); + r1 = fp(); + } + if !deftext.is_null() { + r2 = rl_insert_text(deftext as *const c_char); + deftext = PT_NULL as *mut c_char; + rl_startup_hook = std::mem::transmute(old_startup_hook); + old_startup_hook = std::mem::transmute(0 as usize); + } +} + return (r1 != 0 || r2 != 0) as c_int; +} + +fn edit_line(p : *mut c_char, itext : *mut c_char) -> *mut c_char { +unsafe { + if bash_readline_initialized == 0 { + initialize_readline(); + } + + old_attempted_completion_function = std::mem::transmute(rl_attempted_completion_function); + rl_attempted_completion_function = std::mem::transmute(0 as usize); + bashline_set_event_hook(); + if !itext.is_null() { + old_startup_hook = std::mem::transmute(rl_startup_hook); + rl_startup_hook = std::mem::transmute(set_itext as usize); + deftext = itext; + } + + let mut ret = readline(p); + + rl_attempted_completion_function = std::mem::transmute(old_attempted_completion_function); + old_attempted_completion_function = std::mem::transmute(0 as usize); + bashline_reset_event_hook(); + + if ret.is_null() { + return ret; + } + + let len = libc::strlen(ret); + ret = xrealloc(ret as *mut c_void, len + 2) as *mut c_char; + *ret = delim; + *((ret as usize + 1) as *mut c_char) = b'\0' as c_char; + return ret; +} +} + +fn sigalrm(s : c_int) { +unsafe { + sigalrm_seen = 1; +} +} + +fn reset_alarm() +{ +unsafe { + falarm(0, 0); + set_signal_handler(libc::SIGALRM, old_alrm); +} +} + +fn ttyrestore() +{ +unsafe { + if termsave.is_none() { + let tmp: tty_save = std::mem::zeroed(); + termsave = Some(tmp); + } + + let ter = termsave.unwrap(); + ttsetattr(ter.fd, std::mem::transmute(&(ter.attrs))); + tty_modified = 0; +} +} + +#[no_mangle] +pub extern "C" fn read_tty_cleanup() +{ +unsafe { + if tty_modified != 0 { + ttyrestore(); + } +} +} + +#[no_mangle] +pub extern "C" fn read_tty_modified() -> c_int +{ +unsafe { + return tty_modified; + } +} + +static mut old_delim_ctype: c_int = 0; +static mut old_delim_func: usize = 0; +static mut old_newline_ctype: c_int = 0; +static mut old_newline_func: usize = 0; + +static mut delim_char: u8 = 0; +fn set_eol_delim(c: c_int) +{ +unsafe { + if bash_readline_initialized == 0 { + initialize_readline(); + } + + let cmap = rl_get_keymap(); + let n = std::mem::size_of_val(&*cmap); + let ret_pos = (b'M' & 0x1f) as usize * n; + let c_pos = (c & 0x1f) as usize * n; + + /* Save the old delimiter char binding */ + old_newline_ctype = (*((cmap as usize + ret_pos) as Keymap)).tp as c_int; + old_newline_func = (*((cmap as usize + ret_pos) as Keymap)).function as usize; + old_delim_ctype = (*((cmap as usize + c_pos) as Keymap)).tp as c_int; + old_delim_func = (*((cmap as usize + c_pos) as Keymap)).function as usize; + + /* Change newline to self-insert */ + (*((cmap as usize + ret_pos) as Keymap)).tp = ISFUNC as c_char; + (*((cmap as usize + ret_pos) as Keymap)).function = rl_insert; + + /* Bind the delimiter character to accept-line. */ + (*((cmap as usize + c_pos) as Keymap)).tp = ISFUNC as c_char; + (*((cmap as usize + c_pos) as Keymap)).function = rl_newline; + + delim_char = c as u8; +} +} + +fn reset_eol_delim(cp: *mut c_char) +{ +unsafe { + let cmap = rl_get_keymap(); + let n = std::mem::size_of_val(&*cmap); + let ret_pos = (b'M' & 0x1f) as usize * n; + let delim_pos = (delim_char & 0x1f) as usize * n; + + (*((cmap as usize + ret_pos) as Keymap)).tp = old_newline_ctype as c_char; + (*((cmap as usize + ret_pos) as Keymap)).function = std::mem::transmute(old_newline_func); + + (*((cmap as usize + delim_pos) as Keymap)).tp = old_delim_ctype as c_char; + (*((cmap as usize + delim_pos) as Keymap)).function = std::mem::transmute(old_delim_func); +} +} diff --git a/bash-5.1/builtins_rust/source/Cargo.toml b/bash-5.1/builtins_rust/source/Cargo.toml index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..124fdbef9e63753521fef64f013b1b1ec05e9662 100644 --- a/bash-5.1/builtins_rust/source/Cargo.toml +++ b/bash-5.1/builtins_rust/source/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rsource" +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 = "rsource" diff --git a/bash-5.1/builtins_rust/source/src/lib.rs b/bash-5.1/builtins_rust/source/src/lib.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f3e3d5e03a0207b9fab991c51bcd3e14502c3e24 100644 --- a/bash-5.1/builtins_rust/source/src/lib.rs +++ b/bash-5.1/builtins_rust/source/src/lib.rs @@ -0,0 +1,416 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_long, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut libc::c_char, + pub flags:libc::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:libc::c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:libc::c_int, + flags:libc::c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:libc::c_int, + line:libc::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:libc::c_int +} + +#[repr(C)] +pub struct case_com { + flags:libc::c_int, + line:libc::c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:libc::c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:libc::c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:libc::c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:libc::c_int +} + +#[repr(C)] +pub struct simple_com { + flags:libc::c_int, + line:libc::c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:libc::c_int, + line:libc::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:libc::c_int, + line:libc::c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:libc::c_int, + line:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:libc::c_int, + line:libc::c_int, + type_c:libc::c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:libc::c_int, + line:libc::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 +} + +#[macro_export] +macro_rules! EXECUTION_FAILURE { + () => {1} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! ARGS_SETBLTIN { + () => { + 0x04 + } +} + +#[macro_export] +macro_rules! EXITPROG { + () => { + 3 + } +} +pub union Functions { + f_xfree:unsafe extern "C" fn(str1:* mut c_void), + f_maybe_pop_dollar_vars: unsafe extern "C" fn(), + f_maybe_set_debug_trap:unsafe extern "C" fn(* mut c_char) +} + +extern "C" { + static variable_context:i32; + fn dollar_vars_changed ()->i32; + fn dispose_saved_dollar_vars (); + fn pop_dollar_vars (); + static mut debugging_mode:i32; + fn pop_args (); + fn set_dollar_vars_unchanged (); + fn invalidate_cached_quoted_dollar_at (); + fn no_options (list:* mut WORD_LIST)->i32; + static mut loptend:*mut WORD_LIST; + fn builtin_usage(); + fn builtin_error(err:*const c_char,...); + static mut restricted:i32; + fn sh_restricted (word:* mut c_char); + static mut posixly_correct:i32; + static mut source_searches_cwd:i32; + fn printable_filename (path:* mut c_char, tab:i32)->* mut c_char; + fn absolute_pathname (path:* const c_char)->i32; + static source_uses_path:i32; + fn find_path_file (path:* const c_char)->* mut c_char; + static mut interactive_shell:i32; + static mut executing_command_builtin:i32; + static mut last_command_exit_value:i32; + fn jump_to_top_level(level:i32); + fn begin_unwind_frame (str: * mut c_char); + fn add_unwind_protect(f:Functions,args:* mut c_char); + fn maybe_set_debug_trap (str: * mut c_char); + fn xfree(str1:* mut c_void); + fn push_dollar_vars (); + static shell_compatibility_level:i32; + fn init_bash_argv(); + fn remember_args (list:* mut WORD_LIST, argc:i32); + fn push_args (list:* mut WORD_LIST); + static mut function_trace_mode:i32; + fn signal_is_trapped (sig:i32)->i32; + fn signal_is_ignored (sig:i32)->i32; + static trap_list:[* mut c_char;68]; + fn restore_default_signal (sig:i32); + fn source_file (name:* const c_char, sflags:i32)->i32; + fn run_unwind_frame (filename:* mut c_char); +} + +#[no_mangle] +pub extern "C" fn r_maybe_pop_dollar_vars () +{ + unsafe { + if variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN!()) !=0 { + dispose_saved_dollar_vars (); + } else { + pop_dollar_vars (); + } + if debugging_mode !=0 { + pop_args (); /* restore BASH_ARGC and BASH_ARGV */ + } + + set_dollar_vars_unchanged (); + invalidate_cached_quoted_dollar_at (); /* just invalidate to be safe */ + } +} + +unsafe fn savestring(x:* mut c_char)->* mut c_char +{ + let str1:* mut c_char=libc::malloc(1 + libc::strlen (x as * const c_char)) as * mut c_char; + return libc::strcpy(str1,x as * const c_char); +} + +unsafe fn TRAP_STRING(s:i32)->* mut c_char { + if signal_is_trapped (s) !=0 && signal_is_ignored (s) == 0 { + return trap_list[s as usize]; + } else { + return std::ptr::null_mut(); + } +} + +unsafe fn DEBUG_TRAP()->i32 +{ + return libc::SIGRTMAX() +1; +} + +#[no_mangle] +pub extern "C" fn r_source_builtin (list:* mut WORD_LIST)->i32 +{ + let mut result:i32; + let mut filename:*mut c_char; + let mut debug_trap:* mut c_char; + let x:* mut c_char; + unsafe { + if no_options (list) !=0{ + return EX_USAGE!(); + } + + let mut llist:* mut WORD_LIST = loptend.clone(); + + if list == std::ptr::null_mut() { + builtin_error (CString::new("filename argument required").unwrap().as_ptr()); + builtin_usage (); + return EX_USAGE!(); + } + + if restricted !=0 && libc::strchr ((*(*llist).word).word, '/' as libc::c_int) != std::ptr::null_mut() { + sh_restricted ((*(*llist).word).word); + return EXECUTION_FAILURE!(); + } + + filename = std::ptr::null_mut(); + /* XXX -- should this be absolute_pathname? */ + if posixly_correct !=0 && libc::strchr ((*(*llist).word).word, '/' as libc::c_int) != std::ptr::null_mut() { + filename = savestring ((*(*llist).word).word); + } else if absolute_pathname ((*(*llist).word).word) !=0 { + filename = savestring ((*(*llist).word).word); + } else if source_uses_path !=0 { + filename = find_path_file ((*(*llist).word).word); + } + + if filename == std::ptr::null_mut() { + if source_searches_cwd == 0 { + x = printable_filename ((*(*llist).word).word, 0); + builtin_error (CString::new("%s: file not found").unwrap().as_ptr(), x); + if x != (*(*llist).word).word { + libc::free (x as * mut c_void); + } + + if posixly_correct !=0 && interactive_shell == 0 && executing_command_builtin == 0 { + last_command_exit_value = EXECUTION_FAILURE!(); + jump_to_top_level (EXITPROG!()); + } + return EXECUTION_FAILURE!(); + } else { + filename = savestring ((*(*llist).word).word); + } + } + + begin_unwind_frame (CString::new("source").unwrap().as_ptr() as * mut c_char); + let xf:Functions=Functions{f_xfree :xfree}; + add_unwind_protect (xf, filename); + + if (*list).next != std::ptr::null_mut() { + push_dollar_vars (); + let xvars:Functions=Functions{f_maybe_pop_dollar_vars:r_maybe_pop_dollar_vars}; + add_unwind_protect (xvars, std::ptr::null_mut()); + if debugging_mode !=0 || shell_compatibility_level <= 44 { + init_bash_argv (); /* Initialize BASH_ARGV and BASH_ARGC */ + } + + remember_args ((*list).next, 1); + if debugging_mode !=0 { + push_args ((*list).next); /* Update BASH_ARGV and BASH_ARGC */ + } + + } + set_dollar_vars_unchanged (); + + /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded) + is set. XXX - should sourced files inherit the RETURN trap? Functions + don't. */ + debug_trap = TRAP_STRING (DEBUG_TRAP()); + if debug_trap != std::ptr::null_mut() && function_trace_mode == 0 { + debug_trap = savestring (debug_trap); + let xf1:Functions=Functions{f_xfree :xfree}; + add_unwind_protect (xf1, debug_trap); + + let xfmaybe_set_debug_trap:Functions=Functions{f_maybe_set_debug_trap :maybe_set_debug_trap}; + add_unwind_protect (xfmaybe_set_debug_trap, debug_trap); + restore_default_signal (DEBUG_TRAP()); + } + + result = source_file (filename, (list !=std::ptr::null_mut() && (*list).next !=std::ptr::null_mut()) as i32); + + run_unwind_frame (CString::new("source").unwrap().as_ptr() as * mut c_char); + + return result; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"source" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_source_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/execute_cmd.c b/bash-5.1/execute_cmd.c index ecd509c32581a4e37a2b5e4ab5eb4bb138891e59..9d66af0b4ee4f01b484fbcebdc4ddfdc75e156e7 100644 --- a/bash-5.1/execute_cmd.c +++ b/bash-5.1/execute_cmd.c @@ -4737,7 +4737,7 @@ execute_builtin (builtin, words, flags, subshell) error_trap = 0; should_keep = 0; - r_execute_cmd(); + //r_execute_cmd(); /* The eval builtin calls parse_and_execute, which does not know about the setting of flags, and always calls the execution functions with flags that will exit the shell on an error if -e is set. If the @@ -4841,6 +4841,7 @@ execute_builtin (builtin, words, flags, subshell) executing_builtin++; executing_command_builtin |= builtin == command_builtin; result = ((*builtin) (words->next)); + // r_execute_cmd2(words->next); /* This shouldn't happen, but in case `return' comes back instead of longjmp'ing, we need to unwind. */ diff --git a/bash-5.1/rsbuiltins.h b/bash-5.1/rsbuiltins.h index f3b7f9be9d9ad1014d1aab6e2550fd762765ebc1..f6f3be36af13058d9fcb82d8cc048c5a0921f165 100644 --- a/bash-5.1/rsbuiltins.h +++ b/bash-5.1/rsbuiltins.h @@ -1,2 +1,4 @@ #include +#include "command.h" int r_execute_cmd(); +int r_execute_cmd2(WORD_LIST *l); diff --git a/bash-5.1/src/lib.rs b/bash-5.1/src/lib.rs index 874f7e601d0de1901eee964f3b7613a623bc330a..39f431c556dcf9dc6f02557a42876c3844fdda25 100644 --- a/bash-5.1/src/lib.rs +++ b/bash-5.1/src/lib.rs @@ -1,5 +1,42 @@ +use libc::{c_char, c_int, c_long}; +use std::ffi::CStr; +use std::str; + +#[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 +} + + +//#[link(name = "")] +//extern { + // pub fn printf( #[no_mangle] pub extern "C" fn r_execute_cmd() { - println!("hello"); + //println!("hello"); + //common::builtin_error("test error") } +#[no_mangle] +pub extern "C" fn r_execute_cmd2(l : *mut WORD_LIST) -> i32 { + unsafe { + let mut it : *mut WORD_LIST = l; + while std::ptr::null() != it { + //let mut a = (&((* ((*l).word)).word) ); + let mut a :*mut c_char =( *(*it).word).word; + let c_str: &CStr = CStr::from_ptr(a); + let str_slice: &str = c_str.to_str().unwrap(); + println! ("word is {:?}", str_slice); + it = (*it).next; + } + } + 0 +} diff --git a/record.txt b/record.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb8812a9b9c3f8f581af9afe958354b83673a34d --- /dev/null +++ b/record.txt @@ -0,0 +1,3 @@ +20 +21 +22