From 590bf48b8c6e00ce3568285f4a098cd31d07fa88 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 14 Jun 2023 18:28:42 +0800 Subject: [PATCH] builtins_rust: add shift plugin builtins_rust: add times plugin builtins_rust: add suspend plugin builtins_rust: add test plugin --- bash-5.1/Cargo.toml | 15 +- bash-5.1/builtins_rust/complete/Cargo.toml | 16 + bash-5.1/builtins_rust/complete/src/lib.rs | 1414 +++++++++++++++ bash-5.1/builtins_rust/declare/Cargo.toml | 16 + bash-5.1/builtins_rust/declare/src/lib.rs | 1552 +++++++++++++++++ bash-5.1/builtins_rust/fc/src/lib.rs | 36 +- bash-5.1/builtins_rust/fg_bg/src/lib.rs | 2 +- bash-5.1/builtins_rust/getopts/Cargo.toml | 16 + bash-5.1/builtins_rust/getopts/src/lib.rs | 558 ++++++ bash-5.1/builtins_rust/history/Cargo.toml | 16 + .../builtins_rust/history/src/intercdep.rs | 92 + bash-5.1/builtins_rust/history/src/lib.rs | 332 ++++ bash-5.1/builtins_rust/jobs/src/lib.rs | 268 +-- bash-5.1/builtins_rust/kill/Cargo.toml | 16 + bash-5.1/builtins_rust/kill/src/intercdep.rs | 323 ++++ bash-5.1/builtins_rust/kill/src/lib.rs | 206 +++ bash-5.1/builtins_rust/mapfile/Cargo.toml | 16 + .../builtins_rust/mapfile/src/intercdep.rs | 114 ++ bash-5.1/builtins_rust/mapfile/src/lib.rs | 220 +++ bash-5.1/builtins_rust/printf/Cargo.toml | 16 + .../builtins_rust/printf/src/intercdep.rs | 117 ++ bash-5.1/builtins_rust/printf/src/lib.rs | 1214 +++++++++++++ bash-5.1/builtins_rust/pushd/Cargo.toml | 16 + bash-5.1/builtins_rust/pushd/src/lib.rs | 972 +++++++++++ bash-5.1/builtins_rust/read/src/intercdep.rs | 320 ++++ bash-5.1/builtins_rust/read/src/lib.rs | 1023 ++++++++++- bash-5.1/builtins_rust/rlet/Cargo.toml | 16 + bash-5.1/builtins_rust/rlet/src/intercdep.rs | 46 + bash-5.1/builtins_rust/rlet/src/lib.rs | 63 + bash-5.1/builtins_rust/rreturn/Cargo.toml | 16 + .../builtins_rust/rreturn/src/intercdep.rs | 54 + bash-5.1/builtins_rust/rreturn/src/lib.rs | 25 + bash-5.1/builtins_rust/shift/Cargo.toml | 16 + bash-5.1/builtins_rust/shift/src/intercdep.rs | 36 + bash-5.1/builtins_rust/shift/src/lib.rs | 47 + bash-5.1/builtins_rust/source/Cargo.toml | 16 + bash-5.1/builtins_rust/source/src/lib.rs | 416 +++++ bash-5.1/builtins_rust/suspend/Cargo.toml | 16 + .../builtins_rust/suspend/src/intercdep.rs | 42 + bash-5.1/builtins_rust/suspend/src/lib.rs | 54 + bash-5.1/builtins_rust/test/Cargo.toml | 16 + bash-5.1/builtins_rust/test/src/intercdep.rs | 32 + bash-5.1/builtins_rust/test/src/lib.rs | 25 + bash-5.1/builtins_rust/times/Cargo.toml | 16 + bash-5.1/builtins_rust/times/src/intercdep.rs | 28 + bash-5.1/builtins_rust/times/src/lib.rs | 34 + bash-5.1/execute_cmd.c | 3 +- bash-5.1/rsbuiltins.h | 2 + bash-5.1/src/lib.rs | 39 +- record.txt | 1 + 50 files changed, 9785 insertions(+), 180 deletions(-) create mode 100644 bash-5.1/builtins_rust/complete/Cargo.toml create mode 100644 bash-5.1/builtins_rust/complete/src/lib.rs create mode 100644 bash-5.1/builtins_rust/declare/Cargo.toml create mode 100644 bash-5.1/builtins_rust/declare/src/lib.rs create mode 100644 bash-5.1/builtins_rust/getopts/Cargo.toml create mode 100644 bash-5.1/builtins_rust/getopts/src/lib.rs create mode 100644 bash-5.1/builtins_rust/history/Cargo.toml create mode 100644 bash-5.1/builtins_rust/history/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/history/src/lib.rs create mode 100644 bash-5.1/builtins_rust/kill/Cargo.toml create mode 100644 bash-5.1/builtins_rust/kill/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/kill/src/lib.rs create mode 100644 bash-5.1/builtins_rust/mapfile/Cargo.toml create mode 100644 bash-5.1/builtins_rust/mapfile/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/mapfile/src/lib.rs create mode 100644 bash-5.1/builtins_rust/printf/Cargo.toml create mode 100644 bash-5.1/builtins_rust/printf/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/printf/src/lib.rs create mode 100644 bash-5.1/builtins_rust/pushd/Cargo.toml create mode 100644 bash-5.1/builtins_rust/pushd/src/lib.rs create mode 100644 bash-5.1/builtins_rust/read/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/rlet/Cargo.toml create mode 100644 bash-5.1/builtins_rust/rlet/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/rlet/src/lib.rs create mode 100644 bash-5.1/builtins_rust/rreturn/Cargo.toml create mode 100644 bash-5.1/builtins_rust/rreturn/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/rreturn/src/lib.rs create mode 100644 bash-5.1/builtins_rust/shift/Cargo.toml create mode 100644 bash-5.1/builtins_rust/shift/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/shift/src/lib.rs create mode 100644 bash-5.1/builtins_rust/source/Cargo.toml create mode 100644 bash-5.1/builtins_rust/source/src/lib.rs create mode 100644 bash-5.1/builtins_rust/suspend/Cargo.toml create mode 100644 bash-5.1/builtins_rust/suspend/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/suspend/src/lib.rs create mode 100644 bash-5.1/builtins_rust/test/Cargo.toml create mode 100644 bash-5.1/builtins_rust/test/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/test/src/lib.rs create mode 100644 bash-5.1/builtins_rust/times/Cargo.toml create mode 100644 bash-5.1/builtins_rust/times/src/intercdep.rs create mode 100644 bash-5.1/builtins_rust/times/src/lib.rs diff --git a/bash-5.1/Cargo.toml b/bash-5.1/Cargo.toml index 48dca7e2..9b30d0dd 100644 --- a/bash-5.1/Cargo.toml +++ b/bash-5.1/Cargo.toml @@ -8,9 +8,22 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace] -members = ["builtins/command1", "builtins/command2"] +members = ["builtins_rust/read", "builtins/command1", "builtins/command2", "builtins_rust/history", "builtins_rust/kill", +"builtins_rust/rlet", "builtins_rust/mapfile", "builtins_rust/printf", "builtins_rust/rreturn", "builtins_rust/shift", +"builtins_rust/times","builtins_rust/suspend", "builtins_rust/test"] [dependencies] +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"} +rlet = {path = "./builtins_rust/rlet"} +mapfile = {path = "./builtins_rust/mapfile"} +printf = {path = "./builtins_rust/printf"} +rreturn = {path = "./builtins_rust/rreturn"} +shift = {path = "./builtins_rust/shift"} +times = {path = "./builtins_rust/times"} +suspend = {path = "./builtins_rust/suspend"} +test = {path = "./builtins_rust/test"} diff --git a/bash-5.1/builtins_rust/complete/Cargo.toml b/bash-5.1/builtins_rust/complete/Cargo.toml new file mode 100644 index 00000000..eb141388 --- /dev/null +++ b/bash-5.1/builtins_rust/complete/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["huzhengming"] +name = "rcomplete" +version = "0.0.1" +build = "../build.rs" +edition = "2021" + + +[dependencies] +lazy_static = "1.4.0" +libc = "0.2" +nix = "0.23.0" + +[lib] +crate-type = ["cdylib"] +name = "rcomplete" diff --git a/bash-5.1/builtins_rust/complete/src/lib.rs b/bash-5.1/builtins_rust/complete/src/lib.rs new file mode 100644 index 00000000..d00afdf7 --- /dev/null +++ b/bash-5.1/builtins_rust/complete/src/lib.rs @@ -0,0 +1,1414 @@ +extern crate libc; +extern crate nix; + +use libc::{c_char, c_int, c_ulong, c_void}; +use std::{ffi::CString}; + +#[repr(C)] +pub struct WORD_DESC { + pub word: *mut c_char, + pub flags:c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct WORD_LIST { + next: *mut WORD_LIST, + word: *mut WORD_DESC +} + +#[repr(u8)] +enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select, + cm_connection, cm_function_def, cm_until, cm_group, + cm_arith, cm_cond, cm_arith_for, cm_subshell, cm_coproc +} + +#[repr(u8)] +#[derive(Copy,Clone)] +enum r_instruction { + r_output_direction, r_input_direction, r_inputa_direction, + r_appending_to, r_reading_until, r_reading_string, + r_duplicating_input, r_duplicating_output, r_deblank_reading_until, + r_close_this, r_err_and_out, r_input_output, r_output_force, + r_duplicating_input_word, r_duplicating_output_word, + r_move_input, r_move_output, r_move_input_word, r_move_output_word, + r_append_err_and_out +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub union REDIRECTEE { + dest:c_int, + filename:* mut WORD_DESC +} + +#[repr(C)] +pub union REDIRECT { + next:*mut REDIRECT, + redirector:REDIRECTEE, + rflags:c_int, + flags:c_int, + instruction:r_instruction, + redirectee:REDIRECTEE, + here_doc_eof:*mut c_char +} + +/* FOR command. */ +#[repr(C)] +pub struct for_com { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct PATTERN_LIST { + next:* mut PATTERN_LIST, + patterns:* mut WORD_LIST, + action:*mut COMMAND, + flags:c_int +} + +#[repr(C)] +pub struct case_com { + flags:c_int, + line:c_int, + word:*mut WORD_DESC, + clauses:*mut PATTERN_LIST +} + +#[repr(C)] +pub struct while_com { + flags:c_int, + test:*mut COMMAND, + action:*mut COMMAND +} + +#[repr(C)] +pub struct if_com { + flags:c_int, + test:*mut COMMAND, + true_case:*mut COMMAND, + false_case:*mut COMMAND +} + +#[repr(C)] +pub struct connection { + ignore:c_int, + first:*mut COMMAND, + second:*mut COMMAND, + connector:c_int +} + +#[repr(C)] +pub struct simple_com { + flags:c_int, + line:c_int, + words:*mut WORD_LIST, + redirects:*mut REDIRECT +} + +#[repr(C)] +pub struct function_def { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + command:*mut COMMAND, + source_file:*mut c_char +} + +#[repr(C)] +pub struct group_com { + ignore:libc::c_int, + command:*mut COMMAND, + source_file:*mut c_char +} + +#[repr(C)] +pub struct select_com { + flags:c_int, + line:c_int, + name:*mut WORD_DESC, + map_list:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct arith_com { + flags:c_int, + line:c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct cond_com { + flags:c_int, + line:c_int, + type_c:c_int, + exp:*mut WORD_LIST +} + +#[repr(C)] +pub struct arith_for_com { + flags:c_int, + line:c_int, + init:*mut WORD_LIST, + test:*mut WORD_LIST, + step:*mut WORD_LIST, + action:*mut COMMAND +} + +#[repr(C)] +pub struct subshell_com { + flags:i32, + line:i32, + command:*mut COMMAND +} + +#[repr(C)] +pub struct coproc_com { + flags:i32, + name:*mut c_char, + command:*mut COMMAND +} + +#[repr(C)] +pub union VALUE_COMMAND { + For:*mut for_com, + Case:*mut case_com, + While:*mut while_com, + If:*mut if_com, + Connection:*mut connection, + Simple:*mut simple_com, + Function_def:*mut function_def, + Group:*mut group_com, + Select:*mut select_com, + Arith:*mut arith_com, + Cond:*mut cond_com, + ArithFor:*mut arith_for_com, + Subshell:*mut subshell_com, + Coproc:*mut coproc_com +} + +#[repr(C)] +pub struct COMMAND { + type_c:command_type, + flags:i32, + line:i32, + redirects:*mut REDIRECT, + value:VALUE_COMMAND +} + +/* Structure containing all the non-action (binary) options; filled in by + build_actions(). */ +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _optflags { + pflag:c_int, + rflag:c_int, + Dflag:c_int, + Eflag:c_int, + Iflag:c_int +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _compacts { + actname:* const c_char, + actflag:libc::c_ulong, + actopt:c_int, +} + +pub struct CompactsArray { + compactsArr:[_compacts;25usize] +} + +impl CompactsArray { + pub fn new()->CompactsArray { + CompactsArray{ + compactsArr:[ + _compacts{ actname:"alias\0".as_ptr() as *const c_char, actflag: CA_ALIAS!(),actopt: 'a' as c_int }, + _compacts{ actname:"arrayvar\0".as_ptr() as *const c_char, actflag: CA_ARRAYVAR!(),actopt: 0 as c_int }, + _compacts{ actname:"binding\0".as_ptr() as *const c_char, actflag: CA_BINDING!(),actopt: 0 as c_int }, + _compacts{ actname:"builtin\0".as_ptr() as *const c_char, actflag: CA_BUILTIN!(),actopt: 'b' as c_int }, + _compacts{ actname:"command\0".as_ptr() as *const c_char, actflag: CA_COMMAND!(),actopt: 'c' as c_int }, + _compacts{ actname:"directory\0".as_ptr() as *const c_char, actflag: CA_DIRECTORY!(),actopt: 'd' as c_int }, + _compacts{ actname:"disabled\0".as_ptr() as *const c_char, actflag: CA_DISABLED!(),actopt: 0 as c_int }, + _compacts{ actname:"enabled\0".as_ptr() as *const c_char, actflag: CA_ENABLED!(),actopt: 0 as c_int }, + _compacts{ actname:"export\0".as_ptr() as *const c_char, actflag: CA_EXPORT!(),actopt: 'e' as c_int }, + _compacts{ actname:"file\0".as_ptr() as *const c_char, actflag: CA_FILE!(),actopt: 'f' as c_int }, + _compacts{ actname:"function\0".as_ptr() as *const c_char, actflag: CA_FUNCTION!(),actopt: 0 as c_int }, + _compacts{ actname:"helptopic\0".as_ptr() as *const c_char, actflag: CA_HELPTOPIC!(),actopt: 0 as c_int }, + _compacts{ actname:"hostname\0".as_ptr() as *const c_char, actflag: CA_HOSTNAME!(),actopt: 0 as c_int }, + _compacts{ actname:"group\0".as_ptr() as *const c_char, actflag: CA_GROUP!(),actopt: 'g' as c_int }, + _compacts{ actname:"job\0".as_ptr() as *const c_char, actflag: CA_JOB!(),actopt: 'j' as c_int }, + _compacts{ actname:"keyword\0".as_ptr() as *const c_char, actflag: CA_KEYWORD!(),actopt: 'k' as c_int }, + _compacts{ actname:"running\0".as_ptr() as *const c_char, actflag: CA_RUNNING!(),actopt: 0 as c_int }, + _compacts{ actname:"service\0".as_ptr() as *const c_char, actflag: CA_SERVICE!(),actopt: 's' as c_int }, + _compacts{ actname:"setopt\0".as_ptr() as *const c_char, actflag: CA_SETOPT!(),actopt: 0 as c_int }, + _compacts{ actname:"shopt\0".as_ptr() as *const c_char, actflag: CA_SHOPT!(),actopt: 0 as c_int }, + _compacts{ actname:"signal\0".as_ptr() as *const c_char, actflag: CA_SIGNAL!(),actopt: 0 as c_int }, + _compacts{ actname:"stopped\0".as_ptr() as *const c_char, actflag: CA_STOPPED!(),actopt: 0 as c_int }, + _compacts{ actname:"user\0".as_ptr() as *const c_char, actflag: CA_USER!(),actopt: 'u' as c_int }, + _compacts{ actname:"variable\0".as_ptr() as *const c_char, actflag: CA_VARIABLE!(),actopt: 'v' as c_int }, + _compacts{ actname:std::ptr::null_mut(), actflag: 0,actopt: 0 as c_int }, + ] + } + } +} + +#[repr(C)] +#[derive(Copy,Clone)] +pub struct _compopt { + optname:* const c_char, + optflag:libc::c_ulong, +} + +pub struct CompoptArray { + compoptArr:[_compopt;9usize] +} + +impl CompoptArray { + pub fn new()->CompoptArray{ + CompoptArray{ + compoptArr:[ + _compopt{ optname:"bashdefault\0".as_ptr() as *const c_char, optflag:COPT_BASHDEFAULT!() }, + _compopt{ optname:"default\0".as_ptr() as *const c_char, optflag:COPT_DEFAULT!() }, + _compopt{ optname:"dirnames\0".as_ptr() as *const c_char, optflag:COPT_DIRNAMES!() }, + _compopt{ optname:"filenames\0".as_ptr() as *const c_char,optflag:COPT_FILENAMES!()}, + _compopt{ optname:"noquote\0".as_ptr() as *const c_char, optflag:COPT_NOQUOTE!() }, + _compopt{ optname:"nosort\0".as_ptr() as *const c_char, optflag:COPT_NOSORT!() }, + _compopt{ optname:"nospace\0".as_ptr() as *const c_char, optflag:COPT_NOSPACE!() }, + _compopt{ optname:"plusdirs\0".as_ptr() as *const c_char, optflag:COPT_PLUSDIRS!() }, + _compopt{ optname:std::ptr::null_mut(), optflag:0 }, + ] + } + } +} + + +#[repr(C)] +pub struct COMPSPEC { + refcount:c_int, + actions:c_ulong, + options:c_ulong, + globpat:* mut c_char, + words:* mut c_char, + prefix: * mut c_char, + suffix: * mut c_char, + funcname: * mut c_char, + command:* mut c_char, + lcommand:* mut c_char, + filterpat:* mut c_char, +} +#[repr(C)] +pub struct BUCKET_CONTENTS { + next:* mut BUCKET_CONTENTS, /* Link to next hashed key in this bucket. */ + key:* mut c_char, /* What we look up. */ + data:* mut libc::c_void, /* What we really want. */ + khash:libc::c_uint, /* What key hashes to */ + times_found:i32, /* Number of times this item has been found. */ +} + +#[repr(C)] +pub struct STRINGLIST { + list:* mut * mut c_char, + list_size:c_int, + list_len:c_int, +} + +#[macro_export] +macro_rules! EXECUTION_FAILURE { + () => {1} +} + +#[macro_export] +macro_rules! EX_USAGE { + () => {258} +} + +#[macro_export] +macro_rules! EXECUTION_SUCCESS { + () => { + 0 + } +} + +#[macro_export] +macro_rules! CA_ALIAS { + () => { + 1<<0 + } +} + +#[macro_export] +macro_rules! CA_ARRAYVAR { + () => { + 1<<1 + } +} + +#[macro_export] +macro_rules! CA_BINDING { + () => { + 1<<2 + } +} + +#[macro_export] +macro_rules! CA_BUILTIN { + () => { + 1<<3 + } +} + +#[macro_export] +macro_rules! CA_COMMAND { + () => { + 1<<4 + } +} + +#[macro_export] +macro_rules! CA_DIRECTORY { + () => { + 1<<5 + } +} + +#[macro_export] +macro_rules! CA_DISABLED { + () => { + 1<<6 + } +} + +#[macro_export] +macro_rules! CA_ENABLED { + () => { + 1<<7 + } +} + +#[macro_export] +macro_rules! CA_EXPORT { + () => { + 1<<8 + } +} + +#[macro_export] +macro_rules! CA_FILE { + () => { + 1<<9 + } +} + +#[macro_export] +macro_rules! CA_FUNCTION { + () => { + 1<<10 + } +} + +#[macro_export] +macro_rules! CA_GROUP { + () => { + 1<<11 + } +} + +#[macro_export] +macro_rules! CA_HELPTOPIC { + () => { + 1<<12 + } +} + +#[macro_export] +macro_rules! CA_HOSTNAME { + () => { + 1<<13 + } +} + +#[macro_export] +macro_rules! CA_JOB { + () => { + 1<<14 + } +} + +#[macro_export] +macro_rules! CA_KEYWORD { + () => { + 1<<15 + } +} + +#[macro_export] +macro_rules! CA_RUNNING { + () => { + 1<<16 + } +} + +#[macro_export] +macro_rules! CA_SERVICE { + () => { + 1<<17 + } +} + +#[macro_export] +macro_rules! CA_SETOPT { + () => { + 1<<18 + } +} + +#[macro_export] +macro_rules! CA_SHOPT { + () => { + 1<<19 + } +} + +#[macro_export] +macro_rules! CA_SIGNAL { + () => { + 1<<20 + } +} + +#[macro_export] +macro_rules! CA_STOPPED { + () => { + 1<<21 + } +} + +#[macro_export] +macro_rules! CA_USER { + () => { + 1<<22 + } +} + +#[macro_export] +macro_rules! CA_VARIABLE { + () => { + 1<<23 + } +} + +#[macro_export] +macro_rules! COPT_RESERVED { + () => { + 1<<0 + } +} + +#[macro_export] +macro_rules! COPT_DEFAULT { + () => { + 1<<1 + } +} + +#[macro_export] +macro_rules! COPT_FILENAMES { + () => { + 1<<2 + } +} + +#[macro_export] +macro_rules! COPT_DIRNAMES { + () => { + 1<<3 + } +} + +#[macro_export] +macro_rules! COPT_NOQUOTE { + () => { + 1<<4 + } +} + +#[macro_export] +macro_rules! COPT_NOSPACE { + () => { + 1<<5 + } +} + +#[macro_export] +macro_rules! COPT_BASHDEFAULT { + () => { + 1<<6 + } +} + +#[macro_export] +macro_rules! COPT_PLUSDIRS { + () => { + 1<<7 + } +} + +#[macro_export] +macro_rules! COPT_NOSORT { + () => { + 1<<8 + } +} + +#[macro_export] +macro_rules! RL_STATE_COMPLETING { + () => { + 0x0004000 /* doing completion */ + } +} + +extern "C" { + fn reset_internal_getopt(); + fn internal_getopt (list:*mut WORD_LIST , opts:*mut c_char)->i32; + fn sh_invalidopt (value:* mut c_char); + fn sh_invalidid (value:* mut c_char); + fn sh_invalidoptname (value:* mut c_char); + fn builtin_usage(); + static list_optarg:* mut c_char; + fn builtin_error(err:*const c_char,...); + fn check_identifier (w:* mut WORD_DESC, f:i32)->i32; + static mut posixly_correct:i32; + static mut loptend:*mut WORD_LIST; + fn make_word_list (w:* mut WORD_DESC, list:*mut WORD_LIST)->*mut WORD_LIST; + fn make_bare_word (w:*const c_char)->* mut WORD_DESC; + fn dispose_words (list:*mut WORD_LIST); + fn progcomp_flush (); + fn compspec_create ()->* mut COMPSPEC; + fn progcomp_insert (str:* mut c_char, c:* mut COMPSPEC)->i32; + fn progcomp_remove (str:* mut c_char)->i32; + fn sh_single_quote (str:* mut c_char)->* mut c_char; + fn progcomp_walk (func: unsafe extern "C" fn (item:* mut BUCKET_CONTENTS)->i32); + fn sh_chkwrite (i:i32)->i32; + fn progcomp_search (w:*const c_char)->* mut COMPSPEC; + static mut pcomp_line:* mut c_char; + static mut pcomp_ind:c_int; + fn gen_compspec_completions (cs:* mut COMPSPEC, cmd:*const c_char, word:*const c_char, start:i32, end:i32, foundp:* mut i32)->* mut STRINGLIST; + fn bash_default_completion (text:* const c_char, start:i32, end:i32, qc:i32, compflags:i32)->* mut * mut c_char; + fn rl_filename_completion_function (text:* const c_char, state:i32)-> * mut c_char; + fn rl_completion_matches (text:* const c_char, entry_function:unsafe extern "C" fn (text:* const c_char, state:i32)-> * mut c_char)->* mut * mut c_char; + fn completions_to_stringlist (matches:* mut * mut c_char)->* mut STRINGLIST; + fn strvec_dispose (matches:* mut * mut c_char); + fn strlist_dispose (strlist:* mut STRINGLIST); + fn strlist_print (strlist:* mut STRINGLIST, text:* mut c_char); + fn compspec_dispose (com:* mut COMPSPEC); + static mut list_opttype:i32; + static mut rl_readline_state:c_ulong; + static mut pcomp_curcs:* mut COMPSPEC; + static pcomp_curcmd:* mut c_char; + fn pcomp_set_compspec_options (cs:* mut COMPSPEC, flags:i32, set_or_unset:i32); + fn pcomp_set_readline_variables (flags:i32, nval:i32); +} + +pub static mut Garg:* mut c_char=std::ptr::null_mut(); +pub static mut Warg:* mut c_char=std::ptr::null_mut(); +pub static mut Parg:* mut c_char=std::ptr::null_mut(); +pub static mut Sarg:* mut c_char=std::ptr::null_mut(); +pub static mut Xarg:* mut c_char=std::ptr::null_mut(); +pub static mut Farg:* mut c_char=std::ptr::null_mut(); +pub static mut Carg:* mut c_char=std::ptr::null_mut(); + +unsafe fn savestring(x:* const c_char)->* mut c_char +{ + let str1:* mut c_char=libc::malloc(1 + libc::strlen (x )) as * mut c_char; + return libc::strcpy(str1,x ); +} + +unsafe fn STRDUP(x:* const c_char)->* mut c_char +{ + if x !=std::ptr::null_mut() { + return savestring (x); + } else { + return std::ptr::null_mut(); + } +} + +unsafe fn STREQ( a:* const c_char, b:* const c_char)->bool +{ + return *a ==*b && libc::strcmp(a, b) == 0; +} + +unsafe fn shell_break_chars()->* const c_char +{ + return "()<>;&| \t\n\0".as_ptr() as *const c_char; +} + +unsafe fn EMPTYCMD()->* const c_char +{ + return "_EmptycmD_\0".as_ptr() as *const c_char; +} + +unsafe fn DEFAULTCMD()->* const c_char +{ + return "_DefaultCmD_\0".as_ptr() as *const c_char; +} + +unsafe fn INITIALWORD()->* const c_char +{ + return "_InitialWorD_\0".as_ptr() as *const c_char; +} + +unsafe fn RL_ISSTATE(x:c_ulong)->c_ulong +{ + return rl_readline_state & x; +} + +#[no_mangle] +pub extern "C" fn r_find_compact (name:* mut c_char)->i32 +{ + let mut i:i32=0; + unsafe { + let compacts:CompactsArray=CompactsArray::new(); + while compacts.compactsArr[i as usize].actname != std::ptr::null_mut() { + if STREQ (name, compacts.compactsArr[i as usize].actname) { + return i; + } + i+=1; + } + return -1; + } +} + +#[no_mangle] +pub extern "C" fn r_find_compopt (name:* mut c_char)->i32 +{ + let mut i:i32=0; + let compopts:CompoptArray=CompoptArray::new(); + unsafe { + while compopts.compoptArr[i as usize].optname != std::ptr::null_mut() { + if STREQ (name, compopts.compoptArr[i as usize].optname) { + return i; + } + i+=1; + } + return -1; + } +} + +#[no_mangle] +pub extern "C" fn r_build_actions (list : *mut WORD_LIST, flagp:* mut _optflags, actp:* mut c_ulong, optp:* mut c_ulong)->i32 +{ + let mut opt:i32; + let mut ind:i32; + let mut opt_given:i32=0; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut w:WORD_DESC=WORD_DESC{word:std::ptr::null_mut(),flags:0}; + + unsafe { + reset_internal_getopt (); + opt = internal_getopt(list, CString::new("abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI").unwrap().as_ptr() as * mut c_char); + while opt != -1 { + opt_given = 1; + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + match optChar{ + 'r'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).rflag = 1; + } else { + sh_invalidopt (CString::new("-r").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'p'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).pflag = 1; + } else { + sh_invalidopt (CString::new("-p").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'a'=>{ + acts |= CA_ALIAS!(); + } + 'b'=>{ + acts |= CA_BUILTIN!(); + } + 'c'=>{ + acts |= CA_COMMAND!(); + } + 'd'=>{ + acts |= CA_DIRECTORY!(); + } + 'e'=>{ + acts |= CA_EXPORT!(); + } + 'f'=>{ + acts |= CA_FILE!(); + } + 'g'=>{ + acts |= CA_GROUP!(); + } + 'j'=>{ + acts |= CA_GROUP!(); + } + 'k'=>{ + acts |= CA_KEYWORD!(); + } + 's'=>{ + acts |= CA_SERVICE!(); + } + 'u'=>{ + acts |= CA_USER!(); + } + 'v'=>{ + acts |= CA_VARIABLE!(); + } + 'o'=>{ + ind = r_find_compopt (list_optarg); + if ind < 0 { + sh_invalidoptname (list_optarg); + return EX_USAGE!(); + } + let compopts:CompoptArray=CompoptArray::new(); + copts |= compopts.compoptArr[ind as usize].optflag; + } + 'A'=>{ + ind = r_find_compact (list_optarg); + if ind < 0 { + builtin_error (CString::new("%s: invalid action name").unwrap().as_ptr(), list_optarg); + return EX_USAGE!(); + } + let compacts:CompactsArray=CompactsArray::new(); + acts |= compacts.compactsArr[ind as usize].actflag; + } + 'C'=>{ + Carg = list_optarg; + } + 'D'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Dflag = 1; + } else { + sh_invalidopt (CString::new("-D").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'E'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Eflag = 1; + } else { + sh_invalidopt (CString::new("-E").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'I'=>{ + if flagp !=std::ptr::null_mut() { + (*flagp).Iflag = 1; + } else { + sh_invalidopt (CString::new("-I").unwrap().as_ptr() as * mut c_char); + builtin_usage (); + return EX_USAGE!(); + } + } + 'F'=>{ + w.word = list_optarg; + Farg = list_optarg; + w.flags = 0; + if check_identifier (&mut w, posixly_correct) == 0 || libc::strpbrk (Farg, shell_break_chars()) != std::ptr::null_mut() { + sh_invalidid (Farg); + return EX_USAGE!(); + } + } + 'G'=>{ + Garg = list_optarg; + } + 'P'=>{ + Parg = list_optarg; + } + 'S'=>{ + Sarg = list_optarg; + } + 'W'=>{ + Warg = list_optarg; + } + 'X'=>{ + Xarg = list_optarg; + } + 'X'=>{ + Xarg = list_optarg; + } + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt=internal_getopt(list, CString::new("abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI").unwrap().as_ptr() as * mut c_char); + } + *actp = acts; + *optp = copts; + if opt_given !=0 { + return EXECUTION_SUCCESS!(); + } else { + return EXECUTION_FAILURE!(); + } + } +} + +/* Add, remove, and display completion specifiers. */ +#[no_mangle] +pub extern "C" fn r_complete_builtin (listt: *mut WORD_LIST)->i32 +{ + let mut opt_given:i32=0; + let mut rval:i32; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut cs:* mut COMPSPEC; + let mut oflags:_optflags=_optflags{pflag:0,rflag:0,Dflag:0,Eflag:0,Iflag:0}; + let mut l: *mut WORD_LIST; + let mut wl: *mut WORD_LIST; + + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + if list == std::ptr::null_mut() { + r_print_all_completions (); + return EXECUTION_SUCCESS!(); + } + + oflags.pflag=0; + oflags.rflag=0; + oflags.Dflag=0; + oflags.Eflag=0; + oflags.Iflag=0; + + Garg=std::ptr::null_mut(); + Warg=std::ptr::null_mut(); + Parg=std::ptr::null_mut(); + Sarg=std::ptr::null_mut(); + Xarg=std::ptr::null_mut(); + Farg=std::ptr::null_mut(); + Carg=std::ptr::null_mut(); + + cs=std::ptr::null_mut(); + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = r_build_actions (list, &mut oflags, &mut acts, &mut copts); + if rval == EX_USAGE!() { + return rval; + } + + opt_given = (rval != EXECUTION_FAILURE!()) as i32; + + list = loptend.clone(); + + if oflags.Dflag !=0 { + wl = make_word_list (make_bare_word (DEFAULTCMD()), std::ptr::null_mut()); + } else if oflags.Eflag !=0 { + wl = make_word_list (make_bare_word (EMPTYCMD()), std::ptr::null_mut()); + } else if oflags.Iflag !=0 { + wl = make_word_list (make_bare_word (INITIALWORD()), std::ptr::null_mut()); + } else { + wl = std::ptr::null_mut(); + } + + /* -p overrides everything else */ + if oflags.pflag !=0 || (list == std::ptr::null_mut() && opt_given == 0) { + if wl != std::ptr::null_mut() { + rval = r_print_cmd_completions (wl); + dispose_words (wl); + return rval; + } else if list == std::ptr::null_mut() { + r_print_all_completions (); + return EXECUTION_SUCCESS!(); + } + return r_print_cmd_completions (list); + } + + /* next, -r overrides everything else. */ + if oflags.rflag !=0 { + if wl != std::ptr::null_mut() { + rval = r_remove_cmd_completions (wl); + dispose_words (wl); + return rval; + } else if list == std::ptr::null_mut() { + progcomp_flush (); + return EXECUTION_SUCCESS!(); + } + return r_remove_cmd_completions (list); + } + + if wl == std::ptr::null_mut() && list == std::ptr::null_mut() && opt_given !=0 { + builtin_usage (); + return EX_USAGE!(); + } + + /* If we get here, we need to build a compspec and add it for each + remaining argument. */ + cs = compspec_create (); + (*cs).actions = acts; + (*cs).options = copts; + + (*cs).globpat = STRDUP (Garg); + (*cs).words = STRDUP (Warg); + (*cs).prefix = STRDUP (Parg); + (*cs).suffix = STRDUP (Sarg); + (*cs).funcname = STRDUP (Farg); + (*cs).command = STRDUP (Carg); + (*cs).filterpat = STRDUP (Xarg); + + rval = EXECUTION_SUCCESS!(); + + if wl != std::ptr::null_mut() { + l= wl.clone(); + } else { + l= list.clone(); + } + + while l != std::ptr::null_mut() { + /* Add CS as the compspec for the specified commands. */ + if progcomp_insert ((*(*l).word).word, cs) == 0 { + rval = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + + dispose_words (wl); + return rval; + } +} + +#[no_mangle] +pub extern "C" fn r_remove_cmd_completions (list: * mut WORD_LIST)->i32 +{ + let mut l:* mut WORD_LIST; + let mut ret:i32; + unsafe { + ret = EXECUTION_SUCCESS!(); + l = list.clone(); + while l!=std::ptr::null_mut() { + if progcomp_remove ((*(*l).word).word) == 0 { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(), (*(*l).word).word); + ret = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + return ret; + } +} + +#[no_mangle] +pub extern "C" fn r_print_compoptions (copts:c_ulong, full:i32) +{ + unsafe { + let compopts:CompoptArray=CompoptArray::new(); + for i in 0..compopts.compoptArr.len() { + if (copts & compopts.compoptArr[i].optflag) !=0 { + libc::printf (CString::new("-o %s ").unwrap().as_ptr(), compopts.compoptArr[i].optname); + } else if full !=0 { + libc::printf (CString::new("+o %s ").unwrap().as_ptr(), compopts.compoptArr[i].optname); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_compactions (acts:c_ulong) +{ + unsafe { + let compacts:CompactsArray=CompactsArray::new(); + for i in 0..compacts.compactsArr.len() { + if compacts.compactsArr[i].actopt !=0 && (acts & compacts.compactsArr[i].actflag) !=0 { + libc::printf (CString::new("-%c ").unwrap().as_ptr(), compacts.compactsArr[i].actopt); + } + } + + for i in 0..compacts.compactsArr.len() { + if compacts.compactsArr[i].actopt ==0 && (acts & compacts.compactsArr[i].actflag) !=0 { + libc::printf (CString::new("-A %s ").unwrap().as_ptr(), compacts.compactsArr[i].actname); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_arg (arg:* const c_char, flag:* const c_char, quote:i32) +{ + let x:* mut c_char; + unsafe { + if arg != std::ptr::null_mut() { + if quote !=0 { + x = sh_single_quote (arg as * mut c_char); + } else { + x= arg as * mut c_char; + } + libc::printf (CString::new("%s %s ").unwrap().as_ptr(), flag, x); + if x != arg as * mut c_char { + libc::free (x as * mut c_void); + } + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_cmd_name (cmd:* const c_char) +{ + unsafe { + if STREQ (cmd, DEFAULTCMD()) { + libc::printf (CString::new("-D").unwrap().as_ptr()); + } else if STREQ (cmd, EMPTYCMD()) { + libc::printf (CString::new("-E").unwrap().as_ptr()); + } else if STREQ (cmd, INITIALWORD()) { + libc::printf (CString::new("-I").unwrap().as_ptr()); + } else if *cmd == 0 { /* XXX - can this happen? */ + libc::printf (CString::new("''").unwrap().as_ptr()); + } else { + libc::printf (CString::new("%s").unwrap().as_ptr(),cmd); + } + } +} + +#[no_mangle] +pub extern "C" fn r_print_one_completion (cmd: * mut c_char, cs:* mut COMPSPEC)->i32 +{ + unsafe { + libc::printf (CString::new("complete ").unwrap().as_ptr()); + + r_print_compoptions ((*cs).options, 0); + r_print_compactions ((*cs).actions); + + /* now the rest of the arguments */ + + /* arguments that require quoting */ + r_print_arg ((*cs).globpat, CString::new("-G").unwrap().as_ptr(), 1); + r_print_arg ((*cs).words, CString::new("-W").unwrap().as_ptr(), 1); + r_print_arg ((*cs).prefix, CString::new("-P").unwrap().as_ptr(), 1); + r_print_arg ((*cs).suffix, CString::new("-S").unwrap().as_ptr(), 1); + r_print_arg ((*cs).filterpat, CString::new("-X").unwrap().as_ptr(), 1); + + r_print_arg ((*cs).command, CString::new("-C").unwrap().as_ptr(), 1); + + /* simple arguments that don't require quoting */ + r_print_arg ((*cs).funcname, CString::new("-F").unwrap().as_ptr(), 0); + + r_print_cmd_name (cmd); + libc::printf (CString::new("\n").unwrap().as_ptr()); + + return 0; + } +} + +#[no_mangle] +pub extern "C" fn r_print_compopts (cmd:* mut c_char, cs:* mut COMPSPEC, full:i32) +{ + unsafe { + libc::printf (CString::new("compopt ").unwrap().as_ptr()); + + r_print_compoptions ((*cs).options, full); + r_print_cmd_name (cmd); + + libc::printf (CString::new("\n").unwrap().as_ptr()); + } +} + +#[no_mangle] +pub extern "C" fn r_print_compitem (item:* mut BUCKET_CONTENTS)->i32 +{ + let cs:* mut COMPSPEC; + let cmd:* mut c_char; + unsafe { + cmd = (*item).key; + cs = (*item).data as * mut COMPSPEC; + } + + return r_print_one_completion (cmd, cs); +} + +#[no_mangle] +pub extern "C" fn r_print_all_completions () +{ + unsafe { + progcomp_walk (r_print_compitem); + } +} + +#[no_mangle] +pub extern "C" fn r_print_cmd_completions (list:* mut WORD_LIST)->i32 +{ + let mut l:* mut WORD_LIST; + let mut cs:* mut COMPSPEC; + let mut ret:i32; + + unsafe { + ret = EXECUTION_SUCCESS!(); + l = list.clone(); + while l != std::ptr::null_mut() { + cs = progcomp_search ((*(*l).word).word); + if cs != std::ptr::null_mut() { + r_print_one_completion ((*(*l).word).word, cs); + } else { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(),(*(*l).word).word); + ret = EXECUTION_FAILURE!(); + } + l = (*l).next; + } + return sh_chkwrite (ret); + } +} + +#[no_mangle] +pub extern "C" fn r_compgen_builtin (listt:* mut WORD_LIST)->i32 +{ + let mut rval:i32; + let mut acts:c_ulong=0; + let mut copts:c_ulong=0; + let mut cs: * mut COMPSPEC; + let mut sl:* mut STRINGLIST; + let word:* mut c_char; + let mut matches:* mut * mut c_char; + let old_line:* mut c_char; + let old_ind:i32; + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + if list == std::ptr::null_mut() { + return EXECUTION_SUCCESS!(); + } + + Garg=std::ptr::null_mut(); + Warg=std::ptr::null_mut(); + Parg=std::ptr::null_mut(); + Sarg=std::ptr::null_mut(); + Xarg=std::ptr::null_mut(); + Farg=std::ptr::null_mut(); + Carg=std::ptr::null_mut(); + + cs = std::ptr::null_mut(); + + /* Build the actions from the arguments. Also sets the [A-Z]arg variables + as a side effect if they are supplied as options. */ + rval = r_build_actions (list, std::ptr::null_mut(), &mut acts, &mut copts); + if rval == EX_USAGE!() { + return rval; + } + + if rval == EXECUTION_FAILURE!() { + return EXECUTION_SUCCESS!(); + } + + list = loptend.clone(); + + if list !=std::ptr::null_mut() && (*list).word != std::ptr::null_mut() { + word = (*((*list).word)).word; + } else { + word=CString::new("").unwrap().as_ptr() as * mut c_char; + } + + if Farg != std::ptr::null_mut() { + builtin_error (CString::new("warning: -F option may not work as you expect").unwrap().as_ptr()); + } + + if Carg != std::ptr::null_mut() { + builtin_error (CString::new("warning: -C option may not work as you expect").unwrap().as_ptr()); + } + + /* If we get here, we need to build a compspec and evaluate it. */ + cs = compspec_create (); + (*cs).actions = acts; + (*cs).options = copts; + (*cs).refcount = 1; + + (*cs).globpat = STRDUP (Garg); + (*cs).words = STRDUP (Warg); + (*cs).prefix = STRDUP (Parg); + (*cs).suffix = STRDUP (Sarg); + (*cs).funcname = STRDUP (Farg); + (*cs).command = STRDUP (Carg); + (*cs).filterpat = STRDUP (Xarg); + + rval = EXECUTION_FAILURE!(); + + /* probably don't have to save these, just being safe */ + old_line = pcomp_line; + old_ind = pcomp_ind; + pcomp_line = std::ptr::null_mut(); + pcomp_ind = 0; + sl = gen_compspec_completions (cs, CString::new("compgen").unwrap().as_ptr(), word, 0, 0, std::ptr::null_mut()); + pcomp_line = old_line; + pcomp_ind = old_ind; + + /* If the compspec wants the bash default completions, temporarily + turn off programmable completion and call the bash completion code. */ + if (sl == std::ptr::null_mut() || (*sl).list_len == 0) && (copts & COPT_BASHDEFAULT!()) !=0 { + matches = bash_default_completion (word, 0, 0, 0, 0); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + /* This isn't perfect, but it's the best we can do, given what readline + exports from its set of completion utility functions. */ + if (sl == std::ptr::null_mut() || (*sl).list_len == 0) && (copts & COPT_DEFAULT!()) !=0 { + matches = rl_completion_matches (word, rl_filename_completion_function); + strlist_dispose (sl); + sl = completions_to_stringlist (matches); + strvec_dispose (matches); + } + + if sl != std::ptr::null_mut() { + if (*sl).list != std::ptr::null_mut() && (*sl).list_len !=0 { + rval = EXECUTION_SUCCESS!(); + strlist_print (sl, std::ptr::null_mut()); + } + strlist_dispose (sl); + } + + compspec_dispose (cs); + return rval; + } +} + +#[no_mangle] +pub extern "C" fn r_compopt_builtin (listt:* mut WORD_LIST)->i32 +{ + let mut opts_on:i32=0; + let mut opts_off:i32=0; + let mut opts:* mut i32; + let mut opt:i32; + let mut oind:i32; + let mut ret:i32; + let mut Dflag:i32=0; + let mut Eflag:i32=0; + let mut Iflag:i32=0; + let mut l:* mut WORD_LIST; + let mut wl:* mut WORD_LIST; + let mut cs:* mut COMPSPEC; + + ret = EXECUTION_SUCCESS!(); + unsafe { + let mut list:* mut WORD_LIST=listt.clone(); + reset_internal_getopt (); + + opt = internal_getopt (list, CString::new("+o:DEI").unwrap().as_ptr() as * mut c_char); + + while opt != -1 { + if list_opttype == '-' as i32 { + opts = &mut opts_on; + } else { + opts = &mut opts_off; + } + + let optu8:u8= opt as u8; + let optChar:char=char::from(optu8); + + match optChar { + 'o'=>{ + oind = r_find_compopt (list_optarg); + if oind < 0 { + sh_invalidoptname (list_optarg); + return EX_USAGE!(); + } + let compopts:CompoptArray=CompoptArray::new(); + *opts |= compopts.compoptArr[oind as usize].optflag as i32; + } + 'D'=>{ + Dflag = 1; + } + 'E'=>{ + Eflag = 1; + } + 'I'=>{ + Iflag = 1; + } + _=>{ + builtin_usage (); + return EX_USAGE!(); + } + } + opt = internal_getopt (list, CString::new("+o:DEI").unwrap().as_ptr() as * mut c_char); + } + + list = loptend.clone(); + + if Dflag != 0 { + wl = make_word_list (make_bare_word (DEFAULTCMD()), std::ptr::null_mut()); + } else if Eflag !=0 { + wl = make_word_list (make_bare_word (EMPTYCMD()), std::ptr::null_mut()); + } else if Iflag !=0 { + wl = make_word_list (make_bare_word (INITIALWORD()), std::ptr::null_mut()); + } else { + wl = std::ptr::null_mut(); + } + + if list == std::ptr::null_mut() && wl == std::ptr::null_mut() { + if RL_ISSTATE (RL_STATE_COMPLETING!()) == 0 || pcomp_curcs == std::ptr::null_mut() { + builtin_error (CString::new("not currently executing completion function").unwrap().as_ptr()); + return EXECUTION_FAILURE!(); + } + cs = pcomp_curcs.clone(); + + if opts_on == 0 && opts_off == 0 { + r_print_compopts (pcomp_curcmd, cs, 1); + return sh_chkwrite (ret); + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + + /* And change the readline variables the options control */ + pcomp_set_readline_variables (opts_on, 1); + pcomp_set_readline_variables (opts_off, 0); + + return ret; + } + + if wl != std::ptr::null_mut() { + l = wl.clone(); + } else { + l=list.clone(); + } + + while l != std::ptr::null_mut() { + cs = progcomp_search ((*((*list).word)).word); + if cs == std::ptr::null_mut() { + builtin_error (CString::new("%s: no completion specification").unwrap().as_ptr(), (*((*list).word)).word); + ret = EXECUTION_FAILURE!(); + continue; + } + if opts_on == 0 && opts_off == 0 { + r_print_compopts ((*((*list).word)).word, cs, 1); + continue; /* XXX -- fill in later */ + } + + /* Set the compspec options */ + pcomp_set_compspec_options (cs, opts_on, 1); + pcomp_set_compspec_options (cs, opts_off, 0); + l = (*l).next; + } + + if wl != std::ptr::null_mut() { + dispose_words (wl); + } + + return ret; + } +} + +#[no_mangle] +pub extern "C" fn cmd_name() ->*const u8 { + return b"complete" as *const u8; +} + +#[no_mangle] +pub extern "C" fn run(list : *mut WORD_LIST)->i32 { + return r_complete_builtin(list); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/declare/Cargo.toml b/bash-5.1/builtins_rust/declare/Cargo.toml new file mode 100644 index 00000000..ade288e7 --- /dev/null +++ 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 new file mode 100644 index 00000000..ca367903 --- /dev/null +++ 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/src/lib.rs b/bash-5.1/builtins_rust/fc/src/lib.rs index b3593752..3bba2966 100644 --- a/bash-5.1/builtins_rust/fc/src/lib.rs +++ b/bash-5.1/builtins_rust/fc/src/lib.rs @@ -488,14 +488,14 @@ unsafe fn QUIT () } unsafe fn DIGIT ( c: c_char)->bool { - char::from(c as u8) >= '0' && char::from(c as u8) <= '9' + 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 as usize +4) as * const c_char) ==*((b as usize +4) as * const c_char) && libc::strncmp(a, b, n as libc::size_t) == 0 + return *a == *b && libc::strncmp(a, b, n as libc::size_t) == 0 } } @@ -647,7 +647,7 @@ pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 return EXECUTION_SUCCESS!(); } i=0; - while *((hlist as usize +(4*i) as usize) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { + while *((hlist as usize +(8*i) as usize) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { i+=1; } @@ -655,13 +655,13 @@ pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 last_hist = i - rh - hist_last_line_added; real_last = i; - while *((hlist as usize +(4*real_last) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() && real_last > 0 + 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 + (4*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { - while last_hist >= 0 && *((hlist as usize + (4*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() + 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; } @@ -725,13 +725,13 @@ pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 if listing == 0 && hist_last_line_added !=0 { bash_delete_last_history (); - if histbeg == histend && histend == last_hist && *((hlist as usize + (4*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + 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 + (4*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { + if *((hlist as usize + (8*last_hist) as usize) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { last_hist-=1; } @@ -820,7 +820,7 @@ pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 } } else { let mut ch:char; - if (**((hlist as usize + i as usize) as *mut*mut HIST_ENTRY)).data != std::ptr::null_mut() { + if (**((hlist as usize + (8*i) as usize) as *mut*mut HIST_ENTRY)).data != std::ptr::null_mut() { ch='*'; } else { ch=' '; @@ -838,9 +838,9 @@ pub extern "C" fn r_fc_builtin (list:* mut WORD_LIST)->i32 } if stream != std::ptr::null_mut() { - libc::fprintf (stream, CString::new ("%s\n").unwrap().as_ptr(), (**((hlist as usize + (i*4) as usize) as *mut*mut HIST_ENTRY)).line); + 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*4) as usize) as *mut*mut HIST_ENTRY)).line); + printToStdout((**((hlist as usize + (i*8) as usize) as *mut*mut HIST_ENTRY)).line); } ret=reverse !=0; @@ -944,7 +944,7 @@ pub extern "C" fn r_fc_gethist (command:* mut c_char, hlist:* mut * mut HIST_ENT i = r_fc_gethnum (command, hlist, mode); unsafe { if i >= 0 { - return savestring ((*(*((hlist as usize + (4*i) as usize) as * mut * mut HIST_ENTRY))).line ); + return savestring ((*(*((hlist as usize + (8*i) as usize) as * mut * mut HIST_ENTRY))).line ); } else { return std::ptr::null_mut(); } @@ -970,7 +970,7 @@ pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENT listing = mode & HN_LISTING!(); sign = 1; /* Count history elements. */ - while *((hlist as usize + (4*i) as usize ) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { + while *((hlist as usize + (8*i) as usize ) as * mut * mut HIST_ENTRY) != std::ptr::null_mut() { i+=1; } @@ -989,8 +989,8 @@ pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENT 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 + (4*last_hist) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() { - while last_hist >= 0 && *((hlist as usize + (4*last_hist) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut(){ + 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; } } @@ -1008,7 +1008,7 @@ pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENT } /* back up from the end to the last non-null history entry */ - while *((hlist as usize + (4*real_last) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() && real_last > 0 { + while *((hlist as usize + (8*real_last) as usize ) as * mut * mut HIST_ENTRY) == std::ptr::null_mut() && real_last > 0 { real_last-=1; } @@ -1019,7 +1019,7 @@ pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENT /* Handle possible leading minus sign. */ if s != std::ptr::null_mut() && ( char::from(*s as u8) != '-') { sign = -1; - s = (s as usize +1) as * mut c_char; + s = (s as usize +4) as * mut c_char; } if s != std::ptr::null_mut() && DIGIT( *s ) { @@ -1076,7 +1076,7 @@ pub extern "C" fn r_fc_gethnum (command:* mut c_char, hlist:* mut * mut HIST_ENT clen = libc::strlen (command as * const c_char) as i32; j = i; while j >= 0 { - if STREQN (command, (*(*((hlist as usize + (4*j) as usize ) as * mut * mut HIST_ENTRY))).line, clen) { + if STREQN (command, (*(*((hlist as usize + (8*j) as usize ) as * mut * mut HIST_ENTRY))).line, clen) { return j; } j-=1; 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 b1d9d35a..689f42d8 100644 --- a/bash-5.1/builtins_rust/fg_bg/src/lib.rs +++ b/bash-5.1/builtins_rust/fg_bg/src/lib.rs @@ -310,7 +310,7 @@ macro_rules! DUP_JOB { #[macro_export] macro_rules! get_job_by_jid { ($ind:expr) => { - (*(((jobs as usize) + ($ind*32) as usize ) as *mut*mut JOB) as *mut JOB) + (*(((jobs as usize) + ($ind*8) as usize ) as *mut*mut JOB) as *mut JOB) } } diff --git a/bash-5.1/builtins_rust/getopts/Cargo.toml b/bash-5.1/builtins_rust/getopts/Cargo.toml new file mode 100644 index 00000000..f0190df6 --- /dev/null +++ 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 new file mode 100644 index 00000000..0cb4bee2 --- /dev/null +++ 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 new file mode 100644 index 00000000..6f1d922d --- /dev/null +++ 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 00000000..92f11d52 --- /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 new file mode 100644 index 00000000..1529c0dc --- /dev/null +++ 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/src/lib.rs b/bash-5.1/builtins_rust/jobs/src/lib.rs index 5c016271..9456b58f 100644 --- a/bash-5.1/builtins_rust/jobs/src/lib.rs +++ b/bash-5.1/builtins_rust/jobs/src/lib.rs @@ -31,6 +31,7 @@ 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 { @@ -41,7 +42,8 @@ enum r_instruction { 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, @@ -69,7 +71,6 @@ pub union REDIRECT { here_doc_eof:*mut c_char /* The word that appeared in < {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) => { + ($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); + nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_BLOCK, $nvar, $ovar); } } @@ -317,17 +322,18 @@ macro_rules! UNBLOCK_SIGNAL { nix::sys::signal::sigprocmask(nix::sys::signal::SigmaskHow::SIG_SETMASK, $ovar, None) } } + #[macro_export] macro_rules! UNBLOCK_CHILD { ($ovar:expr) => { - UNBLOCK_SIGNAL!($ovar); + UNBLOCK_SIGNAL!($ovar); } } #[macro_export] macro_rules! BLOCK_CHILD { ($nvar:expr,$ovar:expr) => { - BLOCK_SIGNAL!(nix::sys::signal::SIGCHLD, $nvar, $ovar); + BLOCK_SIGNAL!(nix::sys::signal::SIGCHLD, $nvar, $ovar); } } @@ -340,6 +346,7 @@ macro_rules! NO_JOB { macro_rules! DUP_JOB { () => {-2} } + #[macro_export] macro_rules! CMD_INHIBIT_EXPANSION {/* Do not expand the command words. */ () => {0x20} @@ -348,14 +355,14 @@ macro_rules! CMD_INHIBIT_EXPANSION {/* Do not expand the command words. */ #[macro_export] macro_rules! get_job_by_jid { ($ind:expr) => { - (*(((jobs as i32) + $ind*8 ) as *mut*mut JOB) as *mut JOB) + (*((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) as u8 == 0 + $j <0 || $j >= js.j_jobslots || get_job_by_jid !($j) == std::ptr::null_mut() } } @@ -365,15 +372,14 @@ extern "C" { 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; + 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 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 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); @@ -388,34 +394,32 @@ extern "C" { 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"); + //println!("r_execute_list_with_replacements"); unsafe{ - let mut l:WORD_LIST=*list; + 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.next as u8 !=0 { - let lchar:char=char::from((*(*l.word).word) as u8); + /* 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 (&mut l); - + 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); - } - - + 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); @@ -429,15 +433,14 @@ extern "C" { 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"); +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; @@ -452,44 +455,41 @@ pub extern "C" fn r_jobs_builtin(list:*mut WORD_LIST)->i32{ 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; + 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!(); } - 'r'=>{state = JSTATE_RUNNING!();} - 's'=>{state = JSTATE_STOPPED!();} - - _=>{ - builtin_usage (); - return EX_USAGE!(); + execute+=1; } - - } - opt = internal_getopt (list, c_str_lpnxrs.as_ptr() as * mut c_char); + '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 { + if execute != 0 { return r_execute_list_with_replacements (loptend); - } - - if loptend as u8 ==0 { + } + + if loptend ==std::ptr::null_mut() { if state == JSTATE_ANY!() { list_all_jobs (form); } else if state == JSTATE_RUNNING!() { @@ -499,16 +499,16 @@ pub extern "C" fn r_jobs_builtin(list:*mut WORD_LIST)->i32{ } return EXECUTION_SUCCESS!(); } - + let mut loptendt=*loptend; - while loptendt.next as u8 !=0 { + 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 as u8 == 0 || get_job_by_jid !(job) as u8 == 0 { - sh_badjob ((*loptendt.word).word); + 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!()){ + } else if (job != DUP_JOB!()) { list_one_job (0 as * mut JOB, form, 0, job); } @@ -517,13 +517,14 @@ pub extern "C" fn r_jobs_builtin(list:*mut WORD_LIST)->i32{ } if any_failed !=0 { return EXECUTION_FAILURE!(); - }else { + } else { return EXECUTION_SUCCESS!(); } } } + #[no_mangle] -pub extern "C" fn r_disown_builtin (list:* mut WORD_LIST)->libc::c_int{ +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; @@ -534,88 +535,89 @@ pub extern "C" fn r_disown_builtin (list:* mut WORD_LIST)->libc::c_int{ 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"); + //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{ + 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!(); - } - + '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 as u8 == 0 && (all_jobs !=0 || running_jobs != 0) { + if loptend == std::ptr::null_mut() && (all_jobs !=0 || running_jobs != 0) { if nohup_only!=0{ nohup_all_jobs (running_jobs); - } else{ + } else { delete_all_jobs (running_jobs); } - - return EXECUTION_SUCCESS!(); - } + return EXECUTION_SUCCESS!(); + } - BLOCK_CHILD !(Some(&mut set), Some(&mut oset)); - if (loptend as u8 !=0 && 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 as u8 !=0 || INVALID_JOB!(job){ - if loptend as u8 !=0 { + 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 { + } else { sh_badjob (CString::new("current").unwrap().as_ptr() as * mut c_char); - } - retval = EXECUTION_FAILURE!(); - } else if nohup_only !=0{ + } + retval = EXECUTION_FAILURE!(); + } else if nohup_only !=0{ nohup_job (job); } else { delete_job (job, 1); } - - UNBLOCK_CHILD !(Some(&oset)); - - - if loptend as u8 !=0 { + + UNBLOCK_CHILD !(Some(&oset)); + + if loptend != std::ptr::null_mut() { let mut loptendt=*loptend; - while loptendt.next as u8 !=0 { + 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 { + } else { get_job_spec (&mut loptendt); - } - if job == NO_JOB!() || jobs as u8 !=0 || INVALID_JOB!(job){ - - sh_badjob ((*loptendt.word).word); - + 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 new file mode 100644 index 00000000..e3f22a15 --- /dev/null +++ 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 00000000..38888467 --- /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 new file mode 100644 index 00000000..5f294f17 --- /dev/null +++ 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/mapfile/Cargo.toml b/bash-5.1/builtins_rust/mapfile/Cargo.toml new file mode 100644 index 00000000..133475e8 --- /dev/null +++ b/bash-5.1/builtins_rust/mapfile/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mapfile" +version = "0.1.0" +edition = "2021" +authors = ["lvgenggeng"] +build = "../build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "rmapfile" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/mapfile/src/intercdep.rs b/bash-5.1/builtins_rust/mapfile/src/intercdep.rs new file mode 100644 index 00000000..f4de2e9c --- /dev/null +++ b/bash-5.1/builtins_rust/mapfile/src/intercdep.rs @@ -0,0 +1,114 @@ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct word_desc { + pub word: *mut c_char, + pub flags: c_int, +} +pub type WORD_DESC = word_desc; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct word_list { + pub next: *mut word_list, + pub word: *mut WORD_DESC, +} +pub type WORD_LIST = word_list; + +pub type arrayind_t = c_long; + +pub type sh_var_value_func_t = + ::std::option::Option *mut variable>; + + pub type sh_var_assign_func_t = ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut variable, + arg2: *mut c_char, + arg3: arrayind_t, + arg4: *mut c_char, + ) -> *mut variable, +>; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct variable { + pub name: *mut c_char, + pub value: *mut c_char, + pub exportstr: *mut c_char, + pub dynamic_value: sh_var_value_func_t, + pub assign_func: sh_var_assign_func_t, + pub attributes: c_int, + pub context: c_int, +} +pub type SHELL_VAR = variable; + +pub const atype_array_indexed: atype = 0; +pub const atype_array_assoc: atype = 1; +pub type atype = c_uint; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct array { + pub type_: atype, + pub max_index: arrayind_t, + pub num_elements: c_int, + pub head: *mut array_element, + pub lastref: *mut array_element, +} +pub type ARRAY = array; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct array_element { + pub ind: arrayind_t, + pub value: *mut c_char, + pub next: *mut array_element, + pub prev: *mut array_element, +} +pub type ARRAY_ELEMENT = array_element; + +pub const ESPIPE: c_int = 29; +pub const SEEK_CUR: c_int = 1; + +pub const EXECUTION_SUCCESS : c_int = 0; +pub const EXECUTION_FAILURE : c_int = 1; +pub const EX_USAGE: c_int = 258; + +pub const SEVAL_NOHIST: c_int = 0x004; + +pub const att_readonly: c_int = 0x0000002; +pub const att_array: c_int = 0x0000004; +pub const att_invisible: c_int = 0x0001000; +pub const att_noassign: c_int = 0x0004000; + +extern "C" { + pub fn reset_internal_getopt(); + pub fn internal_getopt(list: *mut WORD_LIST, opts: *mut c_char) -> c_int; + pub fn builtin_usage(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn legal_identifier(arg1: *const c_char) -> c_int; + pub fn legal_number (str1:*const c_char,result:* mut c_long) -> i32; + pub fn sh_invalidid(arg1: *mut c_char); + pub fn sh_validfd(arg1: c_int) -> c_int; + + pub fn sh_single_quote(s: *mut c_char) -> *mut c_char; + + pub fn evalstring(string: *mut c_char, from_file: *const c_char, flags: c_int) -> c_int; + + pub fn find_or_make_array_variable(name: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + + pub fn bind_array_element(entry: *mut SHELL_VAR, ind: c_long, value: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + + pub fn array_flush(a: *mut ARRAY); + + pub fn err_readonly(s: *const c_char) -> c_void; + + pub fn zreset() -> c_void; + pub fn zsyncfd(fd: c_int) -> c_void; + pub fn zgetline (fd: c_int, lineptr: *mut *mut c_char, n: *mut size_t, delim: c_int, unbuffered_read: c_int) -> ssize_t; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + +} diff --git a/bash-5.1/builtins_rust/mapfile/src/lib.rs b/bash-5.1/builtins_rust/mapfile/src/lib.rs new file mode 100644 index 00000000..b5f8ba84 --- /dev/null +++ b/bash-5.1/builtins_rust/mapfile/src/lib.rs @@ -0,0 +1,220 @@ +use std::{ffi::CString}; + +use libc::{size_t, ssize_t, c_int, c_uint, c_char, c_uchar, c_long, c_void, PT_NULL}; + +include!(concat!("intercdep.rs")); + +pub const DEFAULT_QUANTUM: c_long = 5000; +pub const MAPF_CLEARARRAY: c_int = 0x01; +pub const MAPF_CHOP: c_int = 0x02; + +static mut delim: c_int = 0; + +#[no_mangle] +pub extern "C" fn r_mapfile_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_mapfile_builtin call"); + + let mut opt: c_int; + let mut code: c_int; + let mut fd: c_int = 0; + let mut flags: c_int = MAPF_CLEARARRAY; + let intval: c_long = 0; + let mut lines: c_long = 0; + let mut origin: c_long = 0; + let mut nskip: c_long = 0; + let mut callback_quantum: c_long = DEFAULT_QUANTUM; + + let array_name: *mut c_char; + let mut callback: *mut c_char = PT_NULL as *mut c_char; + +unsafe { + + delim = b'\n' as c_int; + + reset_internal_getopt(); + let opt_str = CString::new("d:u:n:O:tC:c:s:").unwrap(); + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + while opt != -1 { + let opt_char:char=char::from(opt as u8); + match opt_char { + 'd' => delim = *list_optarg as c_int, + 'u' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_int) as c_long{ + builtin_error("%s: invalid file descriptor specification\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + fd = intval as c_int; + } + if sh_validfd(fd) == 0 { + builtin_error("%d: invalid file descriptor: %s\0".as_ptr() as *const c_char, + fd, libc::strerror(*libc::__errno_location())); + return EXECUTION_FAILURE; + } + } + 'n' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid line count\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + lines = intval; + } + } + 'O' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid array origin\0".as_ptr() as *const c_char, + list_optarg); + return EXECUTION_FAILURE; + } else { + origin = intval; + } + flags &= (MAPF_CLEARARRAY as c_uint ^ 0xffffffff) as c_int; + } + 't' => flags |= MAPF_CHOP, + 'C' => callback = list_optarg, + 'c' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid callback quantum\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + callback_quantum = intval; + } + } + 's' => { + code = legal_number(list_optarg, std::mem::transmute(&intval)); + if code == 0 || intval < 0 || intval != (intval as c_uint) as c_long { + builtin_error("%s: invalid line count\0".as_ptr() as *const c_char, list_optarg); + return EXECUTION_FAILURE; + } else { + nskip = intval; + } + } + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + } + list = loptend; + + if list.is_null() { + array_name = "MAPFILE".as_ptr() as *mut c_char; + } else if (*list).word.is_null() || (*(*list).word).word.is_null() { + builtin_error("internal error: getting variable name\0".as_ptr() as *const c_char); + return EXECUTION_FAILURE; + } else if *(*(*list).word).word == b'\0' as c_char { + builtin_error("empty array variable name\0".as_ptr() as *const c_char); + return EX_USAGE; + } else { + array_name = (*(*list).word).word; + } + if legal_identifier(array_name) == 0 { + sh_invalidid(array_name); + return EXECUTION_FAILURE; + } + + return mapfile(fd, lines, origin, nskip, callback_quantum, callback, + array_name, delim, flags); +} +} + +unsafe fn run_callback(callback: *const c_char, curindex: c_uint, curline: *mut c_char) -> c_int +{ + let qline = sh_single_quote(curline); + let execlen = libc::strlen(callback) + libc::strlen(qline) + 10 + 3; + let execstr = libc::malloc(execlen); + + let flags = SEVAL_NOHIST; + + libc::snprintf(execstr as *mut c_char, execlen, "%s %d %s\0".as_ptr() as *const c_char, + callback, curindex, qline); + libc::free(qline as *mut c_void); + return evalstring(execstr as *mut c_char, PT_NULL as *const c_char, flags); +} + +unsafe fn do_chop(line: *mut c_char, d: c_uchar) +{ + let length = libc::strlen(line); + if length != 0 && *((line as usize + length - 1) as *mut c_char) == d as c_char { + *((line as usize + length - 1) as *mut c_char) = b'\0' as c_char; + } +} + +unsafe fn mapfile(fd: c_int, line_count_goal: c_long, origin: c_long, nskip: c_long, callback_quantum: c_long, + callback: *mut c_char, array_name: *mut c_char, dlm: c_int, flags: c_int) -> c_int +{ + let mut line: *mut c_char = PT_NULL as *mut c_char; + let mut line_length: size_t = 0; + let mut unbuffered_read: c_int; + + let entry = find_or_make_array_variable(array_name, 1); + if entry.is_null() || ((*entry).attributes & att_readonly) != 0 || ((*entry).attributes & att_noassign) != 0 { + if !entry.is_null() && ((*entry).attributes & att_readonly) != 0 { + err_readonly(array_name); + } + + return EXECUTION_FAILURE; + } else if ((*entry).attributes & att_array) == 0 { + builtin_error("%s: not an indexed array\0".as_ptr() as *const c_char, array_name); + return EXECUTION_FAILURE; + } else if ((*entry).attributes & att_array) != 0 { + (*entry).attributes &= (att_invisible as c_uint ^ 0xffffffff) as c_int; + } + + if (flags & MAPF_CLEARARRAY) != 0 { + array_flush(std::mem::transmute((*entry).value)); + } + unbuffered_read = ((libc::lseek(fd, 0, SEEK_CUR) < 0) && (*libc::__errno_location() == ESPIPE)) as c_int; + + if dlm != b'\n' as c_int { + unbuffered_read = 1; + } + zreset(); + + let mut line_count: c_uint = 0; + while (line_count as c_long) < nskip { + if zgetline(fd, std::mem::transmute(&line), std::mem::transmute(&line_length), dlm, unbuffered_read) < 0 { + break; + } + line_count += 1; + } + + line = PT_NULL as *mut c_char; + line_length = 0; + let mut array_index: c_uint = origin as c_uint; + line_count = 1; + while zgetline(fd, std::mem::transmute(&line), std::mem::transmute(&line_length), dlm, unbuffered_read) != -1 { + if (flags & MAPF_CHOP) != 0 { + do_chop(line, dlm as c_uchar); + } + + if !callback.is_null() && line_count != 0 && (line_count as c_long % callback_quantum) == 0 { + run_callback(callback, array_index, line); + + if unbuffered_read == 0 { + zsyncfd(fd); + } + } + + bind_array_element(entry, array_index as c_long, line, 0); + + line_count += 1; + if line_count_goal != 0 && (line_count as c_long) > line_count_goal { + break; + } + + array_index += 1; + } + + libc::free(line as *mut c_void); + + if unbuffered_read == 0 { + zsyncfd(fd); + } + + return EXECUTION_SUCCESS; +} diff --git a/bash-5.1/builtins_rust/printf/Cargo.toml b/bash-5.1/builtins_rust/printf/Cargo.toml new file mode 100644 index 00000000..9d8dc7f3 --- /dev/null +++ b/bash-5.1/builtins_rust/printf/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "printf" +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 = "rprintf" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/printf/src/intercdep.rs b/bash-5.1/builtins_rust/printf/src/intercdep.rs new file mode 100644 index 00000000..f782774a --- /dev/null +++ b/bash-5.1/builtins_rust/printf/src/intercdep.rs @@ -0,0 +1,117 @@ +#[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, +} + +#[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 EX_USAGE: c_int = 258; + +pub const VA_NOEXPAND: c_int = 0x001; +pub const VA_ONEWORD: c_int = 0x002; + +pub const att_readonly: c_int = 0x0000002; +pub const att_noassign: c_int = 0x0004000; + +extern "C" { + pub fn reset_internal_getopt(); + pub fn internal_getopt(list: *mut WORD_LIST, opts: *mut c_char) -> c_int; + pub fn builtin_usage(); + pub fn builtin_error(format: *const c_char, ...); + pub fn builtin_warning(format: *const c_char, ...); + pub fn builtin_bind_variable(name: *mut c_char, value: *mut c_char, flags: c_int) -> *mut SHELL_VAR; + pub fn stupidly_hack_special_variables(name: *const c_char) -> c_void; + pub fn legal_identifier(arg1: *const c_char) -> c_int; + pub fn legal_number (str1:*const c_char,result:* mut c_long) -> i32; + pub fn sh_invalidid(arg1: *mut c_char); + + pub fn valid_array_reference (name: *const c_char, flags: c_int) -> c_int; + pub fn bind_var_to_int(var: *mut c_char, val: c_long) -> *mut SHELL_VAR; + + pub fn mbtowc(pwc: *mut libc::wchar_t, s: *const c_char, n: size_t) -> size_t; + + pub fn sh_invalidnum(s: *mut c_char) -> c_void; + + pub fn xmalloc(bytes: size_t) -> *mut c_void; + pub fn xrealloc(p: *mut c_void, bytes: size_t) -> *mut c_void; + pub fn savestring(s: *const c_char) -> *mut c_char; + pub fn ansic_shouldquote(s: *const c_char) -> c_int; + pub fn ansic_quote(str: *mut c_char, flags: c_int, rlen: *mut c_int) -> *mut c_char; + pub fn sh_backslash_quote(string: *mut c_char, table: *mut c_char, flags: c_int) -> *mut c_char; + + pub fn u32cconv(c: c_ulong, s: *mut c_char) -> c_int; + + pub fn termsig_handler(arg1: c_int) -> c_void; + pub fn throw_to_top_level() -> c_void; + + pub fn sv_tz(name: *mut c_char) -> c_void; + pub fn strftime(s: *mut c_char, maxsize: size_t, format: *const c_char, timeptr: *const libc::tm) -> size_t; + + pub fn sh_wrerror() -> c_void; + + 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 terminating_signal : c_int; + pub static interrupt_state : c_int; + + pub static stdout: *mut libc::FILE; + + pub static shell_start_time: libc::time_t; +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/printf/src/lib.rs b/bash-5.1/builtins_rust/printf/src/lib.rs new file mode 100644 index 00000000..eae57791 --- /dev/null +++ b/bash-5.1/builtins_rust/printf/src/lib.rs @@ -0,0 +1,1214 @@ +use std::{ffi::CString}; +use libc::{size_t, c_int, c_uint, c_char, c_long, c_void, PT_NULL, c_ulong, strchr}; + +include!(concat!("intercdep.rs")); + +macro_rules! IS_DIGITAL { + ($x: expr) => { + $x >= b'0' as c_char && $x <= b'9' as c_char + }; +} + +unsafe fn QUIT() +{ + if terminating_signal != 0 { + termsig_handler(terminating_signal); + } + + if interrupt_state != 0 { + throw_to_top_level(); + } +} + +unsafe fn PC(c: u8) +{ + let mut b: [c_char; 2] = [0; 2]; + tw += 1; + b[0] = c as c_char; + if vflag != 0 { + vbadd(b.as_ptr() as *mut c_char, 1); + } else { + libc::putchar(c as c_int ); + } + QUIT(); +} + +static mut conversion_error: c_int = 0; +static mut conv_buf: *mut c_char = PT_NULL as *mut c_char; +static mut conv_bufsize: size_t = 0; + +static mut vbuf: *mut c_char = PT_NULL as *mut c_char; +static mut vname: *mut c_char = PT_NULL as *mut c_char; +static mut vflag: c_int = 0; +static mut vbsize: size_t = 0; +static mut vblen: c_int = 0; + +static mut retval: c_int = 0; +static mut tw: c_long = 0; + +static mut garglist: *mut WORD_LIST = PT_NULL as *mut WORD_LIST; +static mut orig_arglist: *mut WORD_LIST = PT_NULL as *mut WORD_LIST; + +#[no_mangle] +pub extern "C" fn r_printf_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_printf_builtin call"); + + let mut ch: c_int; + let mut fieldwidth: c_int; + let mut have_fieldwidth: c_int; + let mut precision: c_int; + let mut have_precision: c_int; + let mut arrayflags: c_int; + + let mut fmt; + let mut start; + let mut modstart; + let mut convch; + let mut thisch; + let mut nextch; +unsafe { + + let PRETURN = |out_val: c_int| { + QUIT(); + if vflag != 0 { + let v = builtin_bind_variable(vname, vbuf, 0); + stupidly_hack_special_variables(vname); + if v.is_null() || ((*v).attributes & att_readonly) != 0 || ((*v).attributes & att_noassign) != 0 { + return EXECUTION_FAILURE; + } + } + if conv_bufsize > 4096 { + libc::free(conv_buf as *mut c_void); + conv_bufsize = 0; + conv_buf = PT_NULL as *mut c_char; + } + + if vbsize > 4096 { + libc::free(vbuf as *mut c_void); + vbsize = 0; + vbuf = PT_NULL as *mut c_char; + } else if !vbuf.is_null() { + *vbuf = 0; + } + + if libc::ferror(stdout) == 0 { + libc::fflush(stdout); + } + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + + return out_val; + }; + + vflag = 0; + reset_internal_getopt(); + let opt_str = CString::new("v:").unwrap(); + let mut 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 { + 'v' => { + vname = list_optarg; + arrayflags = if assoc_expand_once != 0 {VA_NOEXPAND | VA_ONEWORD} else {0}; + if legal_identifier(vname) != 0 || valid_array_reference(vname, arrayflags) != 0 { + vflag = 1; + if vbsize == 0 { + vbsize = 16; + vbuf = xmalloc(16) as *mut c_char; + } + vblen = 0; + if !vbuf.is_null() { + *vbuf = 0; + } + } else { + sh_invalidid(vname); + return EX_USAGE; + } + } + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str.as_ptr() as * mut c_char); + } + list = loptend; + + if list.is_null() { + builtin_usage(); + return EX_USAGE; + } + + if vflag != 0 && !((*(*list).word).word.is_null()) && *(*(*list).word).word == b'\0' as c_char { + let v = builtin_bind_variable(vname, "\0".as_ptr() as *mut c_char, 0); + stupidly_hack_special_variables(vname); + return if v.is_null() || ((*v).attributes & att_readonly) != 0 || ((*v).attributes & att_noassign) != 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; + } + + if (*(*list).word).word.is_null() || *(*(*list).word).word == b'\0' as c_char { + return EXECUTION_SUCCESS; + } + + let format = (*(*list).word).word; + tw = 0; + + garglist = (*list).next; + orig_arglist = (*list).next; + + if format.is_null() || *format == 0 { + return EXECUTION_SUCCESS; + } + + 'outer: loop { + tw = 0; + fmt = format; + while *fmt != 0 { + precision = 0; + fieldwidth = 0; + have_fieldwidth = 0; + have_precision = 0; + + if *fmt == b'\\' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + let mut mbch: [i8;25] = [0; 25]; + let mut mblen: c_int = 0; + fmt = (fmt as usize + tescape(fmt, mbch.as_ptr() as *mut c_char, std::mem::transmute(&mblen), PT_NULL as *mut c_int) as usize) as *mut c_char; + let mut mbind = 0; + while mbind < mblen { + PC(mbch[mbind as usize] as u8); + } + fmt = (fmt as usize - 1) as *mut c_char; + continue; + } + + if *fmt != b'%' as c_char { + PC(*fmt as u8); + continue; + } + + start = fmt; + fmt = (fmt as usize + 1) as *mut c_char; + if *fmt == b'%' as c_char { + PC(b'%'); + continue; + } + + while *fmt != 0 && !(strchr("#'-+ 0\0".as_ptr() as *const c_char, *fmt as c_int).is_null()) { + fmt = (fmt as usize + 1) as *mut c_char; + } + + if *fmt == b'*' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + have_fieldwidth = 1; + fieldwidth = getint(); + } else { + while IS_DIGITAL!(*fmt) { + fmt = (fmt as usize + 1) as *mut c_char; + } + } + + if *fmt == b'.' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + if *fmt == b'*' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + have_precision = 1; + precision = getint(); + } else { + if *fmt == b'-' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + } + while IS_DIGITAL!(*fmt) { + fmt = (fmt as usize + 1) as *mut c_char; + } + } + } + + modstart = fmt; + while *fmt != 0 && !(strchr("hjlLtz\0".as_ptr() as *const c_char, *fmt as c_int).is_null()) { + fmt = (fmt as usize + 1) as *mut c_char; + } + + if *fmt == 0 { + builtin_error("`%s': missing format character\0".as_ptr() as *const c_char, start); + return PRETURN(EXECUTION_FAILURE); + } + + convch = *fmt; + thisch = *modstart; + nextch = *((modstart as usize + 1) as *mut c_char); + *modstart = convch; + *((modstart as usize + 1) as *mut c_char) = b'\0' as c_char; + + QUIT(); + let format_type = convch as u8; + match format_type { + b'c' => { + let p = getchr(); + let f = start; + libc::clearerr(stdout); + let PF = || { + let nw: c_int; + if vflag == 0 { + if have_fieldwidth != 0 && have_precision != 0 { + nw = libc::printf(f, fieldwidth, precision, p); + } else if have_fieldwidth != 0 { + nw = libc::printf(f, fieldwidth, p); + } else if have_precision != 0 { + nw = libc::printf(f, precision, p); + } else { + nw = libc::printf(f, p); + } + } else { + let vbsnprintf2 = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf1 = |x: c_int| { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + if have_fieldwidth != 0 && have_precision != 0 { + nw = vbsnprintf2(); + } else if have_fieldwidth != 0 { + nw = vbsnprintf1(fieldwidth); + } else if have_precision != 0 { + nw = vbsnprintf1(precision); + } else { + nw = vbsnprintf(); + } + } + tw += nw as c_long; + }; + PF(); + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + } + b's' => { + let p = getstr(); + let f = start; + libc::clearerr(stdout); + let PF = || { + let nw: c_int; + if vflag == 0 { + if have_fieldwidth != 0 && have_precision != 0 { + nw = libc::printf(f, fieldwidth, precision, p); + } else if have_fieldwidth != 0 { + nw = libc::printf(f, fieldwidth, p); + } else if have_precision != 0 { + nw = libc::printf(f, precision, p); + } else { + nw = libc::printf(f, p); + } + } else { + let vbsnprintf2 = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf1 = |x: c_int| { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + if have_fieldwidth != 0 && have_precision != 0 { + nw = vbsnprintf2(); + } else if have_fieldwidth != 0 { + nw = vbsnprintf1(fieldwidth); + } else if have_precision != 0 { + nw = vbsnprintf1(precision); + } else { + nw = vbsnprintf(); + } + } + tw += nw as c_long; + }; + PF(); + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + } + b'(' => { + *((modstart as usize + 1) as *mut c_char) = nextch; + let timefmt = xmalloc(libc::strlen(fmt) + 3) as *mut c_char; + fmt = (fmt as usize + 1) as *mut c_char; + let mut t = timefmt; + let mut n = 1; + while *fmt != 0 { + if *fmt == b'(' as c_char { + n += 1; + } else if *fmt == b')' as c_char { + n -= 1; + } + if n == 0 { + break; + } + *t = *fmt; + t = (t as usize + 1) as *mut c_char; + fmt = (fmt as usize + 1) as *mut c_char; + } + *t = b'\0' as c_char; + fmt = (fmt as usize + 1) as *mut c_char; + if *fmt != b'T' as c_char { + builtin_warning("`%c': invalid time format specification\0".as_ptr() as *const c_char, *fmt as c_int); + fmt = start; + libc::free(timefmt as *mut c_void); + PC(*fmt as u8); + continue; + } + if *timefmt == b'\0' as c_char { + *timefmt = b'%' as c_char; + *((timefmt as usize + 1) as *mut c_char) = b'X' as c_char; + *((timefmt as usize + 2) as *mut c_char) = b'\0' as c_char; + } + + let arg = if !garglist.is_null() {getintmax()} else {-1}; + let mut secs: libc::time_t; + if arg == -1 { + secs = libc::time(0 as *mut libc::time_t); + } else if arg == -2 { + secs = shell_start_time; + } else { + secs = arg; + } + + sv_tz("TZ\0".as_ptr() as *mut c_char); + let mut tm = libc::localtime(std::mem::transmute(&secs)); + if tm.is_null() { + secs = 0; + tm = libc::localtime(std::mem::transmute(&secs)); + } + let mut timebuf:[c_char; 128] = [0; 128]; + let mut n: c_int = if !tm.is_null() {strftime(timebuf.as_ptr() as *mut c_char, 128, timefmt, tm) as c_int} else {0}; + libc::free(timefmt as *mut c_void); + if n == 0 { + timebuf[0] = b'\0' as c_char; + } else { + timebuf[127] = b'\0' as c_char; + } + + *modstart = b's' as c_char; + *((modstart as usize + 1) as *mut c_char) = b'\0' as c_char; + n = printstr(start, timebuf.as_ptr() as *mut c_char, libc::strlen(timebuf.as_ptr()) as c_int, fieldwidth, precision); + if n < 0 { + if libc::ferror(stdout) == 0 { + sh_wrerror(); + libc::clearerr(stdout); + } + return PRETURN(EXECUTION_FAILURE); + } + } + b'n' => { + let var = getstr(); + if !var.is_null() && *var != 0 { + if legal_identifier(var) != 0 { + bind_var_to_int(var, tw); + } else { + sh_invalidid(var); + return PRETURN(EXECUTION_FAILURE); + } + } + } + b'b' => { + let mut rlen: c_int = 0; + let mut r: c_int = 0; + ch = 0; + let p = getstr(); + let xp = bexpand(p, libc::strlen(p) as c_int, std::mem::transmute(&ch), std::mem::transmute(&rlen)); + if !xp.is_null() { + r = printstr(start, xp, rlen, fieldwidth, precision); + if r < 0 { + if libc::ferror(stdout) == 0 { + sh_wrerror(); + libc::clearerr(stdout); + } + retval = EXECUTION_FAILURE; + } + libc::free(xp as *mut c_void); + } + if ch != 0 || r < 0 { + return PRETURN(retval); + } + } + b'q' => { + let mut r: c_int = 0; + let xp: *mut c_char; + let p = getstr(); + if !p.is_null() && *p == 0 { + xp = savestring(b"''\0".as_ptr() as *const c_char); + } else if ansic_shouldquote(p) != 0 { + xp = ansic_quote(p, 0, PT_NULL as *mut c_int); + } else { + xp = sh_backslash_quote(p, PT_NULL as *mut c_char, 3); + } + if !xp.is_null() { + r = printstr(start, xp, libc::strlen(xp) as c_int, fieldwidth, precision); + if r < 0 { + if libc::ferror(stdout) == 0 { + sh_wrerror(); + libc::clearerr(stdout); + } + libc::free(xp as *mut c_void); + } + } + if r < 0 { + return PRETURN(EXECUTION_FAILURE); + } + } + b'd' | b'i' => { + let f = mklong(start, "l\0".as_ptr() as *mut c_char, 1); + let p = getintmax(); + libc::clearerr(stdout); + let PF = || { + let nw: c_int; + if vflag == 0 { + if have_fieldwidth != 0 && have_precision != 0 { + nw = libc::printf(f, fieldwidth, precision, p); + } else if have_fieldwidth != 0 { + nw = libc::printf(f, fieldwidth, p); + } else if have_precision != 0 { + nw = libc::printf(f, precision, p); + } else { + nw = libc::printf(f, p); + } + } else { + let vbsnprintf2 = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf1 = |x: c_int| { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + if have_fieldwidth != 0 && have_precision != 0 { + nw = vbsnprintf2(); + } else if have_fieldwidth != 0 { + nw = vbsnprintf1(fieldwidth); + } else if have_precision != 0 { + nw = vbsnprintf1(precision); + } else { + nw = vbsnprintf(); + } + } + tw += nw as c_long; + }; + PF(); + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + } + b'o' | b'u' | b'x' | b'X' => { + let f = mklong(start, "l\0".as_ptr() as *mut c_char, 1); + let p = getuintmax(); + libc::clearerr(stdout); + let PF = || { + let nw: c_int; + if vflag == 0 { + if have_fieldwidth != 0 && have_precision != 0 { + nw = libc::printf(f, fieldwidth, precision, p); + } else if have_fieldwidth != 0 { + nw = libc::printf(f, fieldwidth, p); + } else if have_precision != 0 { + nw = libc::printf(f, precision, p); + } else { + nw = libc::printf(f, p); + } + } else { + let vbsnprintf2 = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf1 = |x: c_int| { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + if have_fieldwidth != 0 && have_precision != 0 { + nw = vbsnprintf2(); + } else if have_fieldwidth != 0 { + nw = vbsnprintf1(fieldwidth); + } else if have_precision != 0 { + nw = vbsnprintf1(precision); + } else { + nw = vbsnprintf(); + } + } + tw += nw as c_long; + }; + PF(); + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + } + b'e' | b'E' | b'f' | b'F' | b'g' | b'G' | b'a' | b'A' => { + let p = getfloatmax(); + let f = mklong(start, "L\0".as_ptr() as *mut c_char, 1); + libc::clearerr(stdout); + let PF = || { + let nw: c_int; + if vflag == 0 { + if have_fieldwidth != 0 && have_precision != 0 { + nw = libc::printf(f, fieldwidth, precision, p); + } else if have_fieldwidth != 0 { + nw = libc::printf(f, fieldwidth, p); + } else if have_precision != 0 { + nw = libc::printf(f, precision, p); + } else { + nw = libc::printf(f, p); + } + } else { + let vbsnprintf2 = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, have_fieldwidth, have_precision, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf1 = |x: c_int| { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, x, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + let vbsnprintf = || { + let mut blen: c_int; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen > vbsize { + vbsize = ((nlen as size_t + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + blen = libc::snprintf((vbuf as usize + vblen as usize) as *mut c_char, vbsize - vblen as usize, f, p); + } + vblen += blen; + *((vbuf as usize + vblen as usize) as *mut c_char) = b'0' as c_char; + blen + }; + if have_fieldwidth != 0 && have_precision != 0 { + nw = vbsnprintf2(); + } else if have_fieldwidth != 0 { + nw = vbsnprintf1(fieldwidth); + } else if have_precision != 0 { + nw = vbsnprintf1(precision); + } else { + nw = vbsnprintf(); + } + } + tw += nw as c_long; + }; + PF(); + QUIT(); + if libc::ferror(stdout) != 0 { + sh_wrerror(); + libc::clearerr(stdout); + return EXECUTION_FAILURE; + } + } + _ => { + builtin_error("`%c': invalid format character\0".as_ptr() as *const c_char, convch as c_int); + return PRETURN(EXECUTION_FAILURE); + } + } + + *modstart = thisch; + *((modstart as usize + 1) as *mut c_char) = nextch; + + fmt = (fmt as usize + 1) as *mut c_char; + } + + if libc::ferror(stdout) != 0 { + return PRETURN(EXECUTION_FAILURE); + } + + if !garglist.is_null() && garglist != (*list).next { + continue 'outer; + } else { + break 'outer; + } + } + + if conversion_error != 0 { + retval = EXECUTION_FAILURE; + } + + return PRETURN(retval); +} +} + +fn hexvalue(c: u8) -> c_int +{ + return ( + if (c) >= b'a' && (c) <= b'f' { + (c) - b'a' + 10 + } else if (c) >= b'A' && (c) <= b'F' { + (c) - b'A' + 10 + } else { + (c) - b'0' + }) as i32 +} + +unsafe fn printstr(mut fmt: *mut c_char, mut string: *mut c_char, len: c_int, fieldwidth: c_int, precision: c_int) -> c_int +{ + if string.is_null() { + string = "\0".as_ptr() as *mut c_char; + } + + if *fmt == b'%' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + } + + let mut ljust: c_int = 0; + let mut fw: c_int = 0; + let mut mfw: c_long = 0; + let mut pr: c_int = -1; + let mut mpr: c_long = -1; + + while !(strchr("#'-+ 0\0".as_ptr() as *const c_char, *fmt as c_int).is_null()) { + if *fmt == b'-' as c_char { + ljust = 1; + } + fmt = (fmt as usize + 1) as *mut c_char; + } + + if *fmt == b'*' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + fw = fieldwidth; + if fw < 0 { + fw = -fw; + ljust = 1; + } + } else if IS_DIGITAL!(*fmt) { + mfw = (*fmt - b'0' as c_char) as c_long; + fmt = (fmt as usize + 1) as *mut c_char; + while IS_DIGITAL!(*fmt) { + mfw = mfw * 10 + (*fmt - b'0' as c_char) as c_long; + fmt = (fmt as usize + 1) as *mut c_char; + } + fw = if mfw < 0 || mfw > (libc::INT_MAX as c_long) {libc::INT_MAX} else {mfw as c_int}; + } + + if *fmt == b'.' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + if *fmt == b'*' as c_char { + fmt = (fmt as usize + 1) as *mut c_char; + pr = precision; + } else if IS_DIGITAL!(*fmt) { + mpr = (*fmt - b'0' as c_char) as c_long; + fmt = (fmt as usize + 1) as *mut c_char; + while IS_DIGITAL!(*fmt) { + mpr = mpr * 10 + (*fmt - b'0' as c_char) as c_long; + fmt = (fmt as usize + 1) as *mut c_char; + } + pr = if mpr < 0 || mpr > (libc::INT_MAX as c_long) {libc::INT_MAX} else {mpr as c_int}; + } else { + pr = 0; + } + } + + let nc = if pr >= 0 && pr <= len {pr} else {len}; + let mut padlen = fw - nc; + if padlen < 0 { + padlen = 0; + } + if ljust != 0 { + padlen = -padlen; + } + + while padlen > 0 { + PC(b' '); + padlen -= 1; + } + + for i in 0..nc { + PC(*((string as usize + i as usize) as *mut c_char) as u8); + } + + return 0; +} + +unsafe fn tescape(estart: *mut c_char, cp:*mut c_char, lenp: *mut c_int, sawc: *mut c_int) -> c_int +{ + + let mut p: *mut c_char = estart; + let mut evalue: c_int; + let mut temp: c_int; + let mut uvalue: c_ulong; + if !lenp.is_null() { + *lenp = 1; + } + + let c = *p as u8; + p = (p as usize + 1) as *mut c_char; + match c { + b'a' => *cp = 7, + b'b' => *cp = 8, + b'e' | b'E' => *cp = 27, + b'f' => *cp = 12, + b'n' => *cp = 10, + b'r' => *cp = 13, + b't' => *cp = 9, + b'v' => *cp = 11, + b'0'..=b'7' => { + evalue = (c - b'0') as c_int; + temp = 2 + (evalue == 0 && !sawc.is_null()) as c_int; + while *p >= b'0' as c_char && *p <= b'7' as c_char && temp != 0 { + temp -= 1; + evalue = (evalue * 8) + (*p - b'0' as c_char) as c_int; + p = (p as usize + 1) as *mut c_char; + } + + *cp = (evalue & 0xff) as c_char; + } + b'x' => { + temp = 2; + evalue = 0; + while libc::isdigit(*p as c_int) != 0 && temp != 0 { + temp -= 1; + evalue = (evalue * 16) + hexvalue(*p as u8); + p = (p as usize + 1) as *mut c_char; + } + + if p as usize == (estart as usize + 1) { + builtin_error("missing hex digit for \\x\0".as_ptr() as *const c_char); + *cp = b'\\' as c_char; + return 0; + } + *cp = (evalue & 0xff) as c_char; + } + b'u' | b'U' => { + temp = if c == b'u' {4} else {8}; + uvalue = 0; + while libc::isdigit(*p as c_int) != 0 && temp != 0 { + temp -= 1; + uvalue = (uvalue * 16) + hexvalue(*p as u8) as c_ulong; + p = (p as usize + 1) as *mut c_char; + } + + if p as usize == (estart as usize + 1) { + builtin_error("missing unicode digit for \\%c\0".as_ptr() as *const c_char, c as c_int); + *cp = b'\\' as c_char; + return 0; + } + if uvalue <= 0x7f { + *cp = uvalue as c_char; + } else { + temp = u32cconv(uvalue, cp); + *((cp as usize + temp as usize) as *mut c_char) = b'\0' as c_char; + if !lenp.is_null() { + *lenp = temp; + } + } + } + b'\\' => *cp = c as c_char, + b'\'' | b'"' | b'?' => { + if sawc.is_null() { + *cp = c as c_char; + } else { + *cp = b'\\' as c_char; + return 0; + } + } + b'c' => { + if sawc.is_null() { + *sawc = 1; + } else { + *cp = b'\\' as c_char; + return 0; + } + } + _ => { + *cp = b'\\' as c_char; + return 0; + } + } + return (p as usize - estart as usize) as c_int; +} + +unsafe fn bexpand(string: *mut c_char, len: c_int, sawc: *mut c_int, lenp: *mut c_int) -> *mut c_char +{ + let mut mbch:[c_char; 25]; + let mut mblen: c_int = 0; + + let mut ret: *mut c_char; + let mut r: *mut c_char; + let mut s: *mut c_char; + let mut c: c_char; + + if string.is_null() || len == 0 { + if !sawc.is_null() { + *sawc = 0; + } + if !lenp.is_null() { + *lenp = 0; + } + ret = xmalloc(1) as *mut c_char; + *ret = b'\0' as c_char; + return ret; + } + + ret = xmalloc(len as size_t + 1) as *mut c_char; + r = ret; + s = string; + while !s.is_null() && *s != 0 { + c = *s as c_char; + s = (s as usize + 1) as *mut c_char; + if c != b'\\' as c_char || *s == b'\0' as c_char { + *r = c; + r = (r as usize + 1) as *mut c_char; + continue; + } + + let mut temp: c_int = 0; + mbch = [0; 25]; + let n = tescape(s, mbch.as_mut_ptr() as *mut c_char, + std::mem::transmute(&mblen), std::mem::transmute(&temp)); + s = (s as usize + n as size_t) as *mut c_char; + + if temp != 0 { + if !sawc.is_null() { + *sawc = 1; + } + break; + } + + for mbind in 0..mblen { + *r = mbch[mbind as usize]; + r = (r as usize + 1) as *mut c_char; + } + } + + *r = b'\0' as c_char; + if !lenp.is_null() { + *lenp = (r as usize - ret as usize) as c_int; + } + + return ret; +} + +unsafe fn vbadd(buf: *mut c_char, blen: c_int) -> *mut c_char +{ + let nlen: size_t = vblen as size_t + blen as size_t + 1; + if nlen >= vbsize { + vbsize = ((nlen + 63) >> 6) << 6; + vbuf = xrealloc(vbuf as *mut c_void, vbsize) as *mut c_char; + } + + if blen == 1 { + *((vbuf as usize + vblen as usize) as *mut c_char) = *buf; + vblen += 1; + } else if blen > 1 { + libc::memcpy((vbuf as usize + vblen as usize) as *mut c_void, + buf as *mut c_void, blen as size_t); + vblen += blen; + } + *((vbuf as usize + vblen as usize) as *mut c_char) = b'\0' as c_char; + + return vbuf; +} + +unsafe fn printf_erange(s: *mut c_char) +{ + builtin_error("warning: %s: %s\0".as_ptr() as *const c_char, s, libc::strerror(libc::ERANGE)); +} + +unsafe fn mklong(str: *mut c_char, modifiers: *mut c_char, mlen: size_t) -> *mut c_char +{ + let slen = libc::strlen(str); + let len = slen + mlen + 1; + + if len > conv_bufsize { + conv_bufsize = ((len + 1023) >> 10) << 10; + conv_buf = libc::realloc(conv_buf as *mut c_void, conv_bufsize) as *mut c_char; + } + + libc::memcpy(conv_buf as *mut c_void, str as *mut c_void, slen - 1); + libc::memcpy((conv_buf as usize + slen - 1) as *mut c_void, modifiers as *mut c_void, mlen); + + *((conv_buf as usize + len - 2) as *mut c_char) = *((str as usize + slen - 1) as *mut c_char); + *((conv_buf as usize + len - 1) as *mut c_char) = b'\0' as c_char; + + return conv_buf; +} + +unsafe fn getchr() -> c_int +{ + if garglist.is_null() { + return b'\0' as c_int; + } + + let ret = *(*(*garglist).word).word as c_int; + garglist = (*garglist).next; + return ret; +} + +unsafe fn getstr() -> *mut c_char +{ + if garglist.is_null() { + return "\0".as_ptr() as *mut c_char; + } + + let ret = (*(*garglist).word).word; + garglist = (*garglist).next; + return ret; +} + +unsafe fn getint() -> c_int +{ + let mut ret = getintmax(); + + if garglist.is_null() { + return ret as c_int; + } + + if ret > libc::INT_MAX as c_long{ + printf_erange((*(*garglist).word).word); + ret = libc::INT_MAX as c_long; + } else if ret < libc::INT_MIN as c_long{ + printf_erange((*(*garglist).word).word); + ret = libc::INT_MIN as c_long; + } + + return ret as c_int; +} + +unsafe fn getintmax() -> c_long +{ + if garglist.is_null() { + return 0; + } + + if *(*(*garglist).word).word == b'\'' as c_char || + *(*(*garglist).word).word == b'"' as c_char { + return asciicode(); + } + + let mut ep: *mut c_char = PT_NULL as *mut c_char; + *libc::__errno_location() = 0; + let ret = libc::strtol((*(*garglist).word).word, std::mem::transmute(&ep), 0); + if *ep != 0 { + sh_invalidnum((*(*garglist).word).word); + conversion_error = 1; + } else if *libc::__errno_location() == libc::ERANGE { + printf_erange((*(*garglist).word).word); + } + garglist = (*garglist).next; + return ret; +} + +unsafe fn getuintmax() -> c_ulong +{ + if garglist.is_null() { + return 0; + } + + if *(*(*garglist).word).word == b'\'' as c_char || + *(*(*garglist).word).word == b'"' as c_char { + return asciicode() as c_ulong; + } + + *libc::__errno_location() = 0; + let mut ep: *mut c_char = PT_NULL as *mut c_char; + let ret = libc::strtoul((*(*garglist).word).word, std::mem::transmute(&ep), 0); + if *ep != 0 { + sh_invalidnum((*(*garglist).word).word); + conversion_error = 1; + } else if *libc::__errno_location() == libc::ERANGE { + printf_erange((*(*garglist).word).word); + } + garglist = (*garglist).next; + return ret; +} + +unsafe fn getfloatmax() -> f64 +{ + let ep: *mut c_char = PT_NULL as *mut c_char; + + if garglist.is_null() { + return 0.0; + } + + if *(*(*garglist).word).word == b'\'' as c_char || + *(*(*garglist).word).word == b'\"' as c_char { + return asciicode() as f64; + } + + *libc::__errno_location() = 0; + let ret = libc::strtod((*(*garglist).word).word, std::mem::transmute(&ep)); + if *ep != 0 { + sh_invalidnum((*(*garglist).word).word); + conversion_error = 1; + } else if *libc::__errno_location() == libc::ERANGE { + printf_erange((*(*garglist).word).word); + } + + garglist = (*garglist).next; + + return ret; +} + +unsafe fn asciicode() -> c_long +{ + let ch: c_long; + //let state: mbstate_t = std::mem::zeroed(); + let slen = libc::strlen((*(*garglist).word).word); + let wc: libc::wchar_t = 0; + let mblength = mbtowc(std::mem::transmute(&wc), ((*(*garglist).word).word as usize + 1) as *mut c_char, slen); + if mblength > 0 { + ch = wc as c_long; + } else { + ch = *(((*(*garglist).word).word as usize + 1) as *mut c_char) as c_long; + } + + garglist = (*garglist).next; + + return ch; +} 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 00000000..69270a84 --- /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 00000000..bd0783c7 --- /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/src/intercdep.rs b/bash-5.1/builtins_rust/read/src/intercdep.rs new file mode 100644 index 00000000..61985e93 --- /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 3c47a31b..8015ec1b 100644 --- a/bash-5.1/builtins_rust/read/src/lib.rs +++ b/bash-5.1/builtins_rust/read/src/lib.rs @@ -1,35 +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}; -use libc::{F_UNLCK, c_char, c_long}; -use std::ffi::CString; +include!(concat!("intercdep.rs")); -#[repr(C)] -pub struct WORD_DESC { - pub word: *mut libc::c_char, - pub flags:libc::c_int +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, } -#[repr(C)] -#[derive(Copy,Clone)] -pub struct WORD_LIST { - next: *mut WORD_LIST, - word: *mut WORD_DESC +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; } -/* -Read a line from the standard input and split it into fields. +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); -Reads a single line from the standard input, or from file descriptor FD -if the -u option is supplied. The line is split into fields as with word -splitting, and the first word is assigned to the first NAME, the second -word to the second NAME, and so on, with any leftover words assigned to -the last NAME. Only the characters found in $IFS are recognized as word -delimiters. + 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; -If no NAMEs are supplied, the line read is stored in the REPLY variable. -*/ +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 r_read_builtin(list: *mut WORD_LIST) -> i32 { - println!("r_read_builtin call"); - 0 -} \ No newline at end of file +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/rlet/Cargo.toml b/bash-5.1/builtins_rust/rlet/Cargo.toml new file mode 100644 index 00000000..dbc2ca83 --- /dev/null +++ b/bash-5.1/builtins_rust/rlet/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rlet" +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 = "rlet" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/rlet/src/intercdep.rs b/bash-5.1/builtins_rust/rlet/src/intercdep.rs new file mode 100644 index 00000000..d2246f94 --- /dev/null +++ b/bash-5.1/builtins_rust/rlet/src/intercdep.rs @@ -0,0 +1,46 @@ + +#[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 EXP_EXPANDED: c_int = 0x01; + +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 string_list(list: *mut WORD_LIST) -> *mut c_char; + + pub fn builtin_usage(); + pub fn builtin_help(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn evalexp (expr: *mut c_char, flags: c_int, validp: *mut c_int) -> c_long; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + +} diff --git a/bash-5.1/builtins_rust/rlet/src/lib.rs b/bash-5.1/builtins_rust/rlet/src/lib.rs new file mode 100644 index 00000000..7fe5af59 --- /dev/null +++ b/bash-5.1/builtins_rust/rlet/src/lib.rs @@ -0,0 +1,63 @@ +use std::ffi::CStr; +use libc::{c_int, c_char, c_long, c_void}; + +include!(concat!("intercdep.rs")); + +#[no_mangle] +pub extern "C" fn r_let_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_let_builtin call"); +unsafe { + let mut ret: c_long = 0; + let mut expok: c_int = 0; + + 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; + } + + if !list.is_null() && !(*list).word.is_null() && is_option((*((*list).word)).word, b'-') { + list = (*list).next; + } + + if list.is_null() { + builtin_error("expression expected\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + + while !list.is_null() { + ret = evalexp((*((*list).word)).word, EXP_EXPANDED, std::mem::transmute(&expok)); + if expok == 0 { + return EXECUTION_FAILURE; + } + list = (*list).next; + } + + return if ret == 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; +} +} + +#[no_mangle] +pub extern "C" fn r_exp_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_exp_builtin call"); + +unsafe { + let mut expok: c_int = 0; + + if list.is_null() { + builtin_error("expression expected\0".as_ptr() as *const c_char); + return EXECUTION_FAILURE; + } + + let exp = string_list(list); + let ret = evalexp(exp, EXP_EXPANDED, std::mem::transmute(&expok)); + libc::free(exp as *mut c_void); + return if ret == 0 || expok == 0 {EXECUTION_FAILURE} else {EXECUTION_SUCCESS}; +} +} + +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 +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/rreturn/Cargo.toml b/bash-5.1/builtins_rust/rreturn/Cargo.toml new file mode 100644 index 00000000..959acd1b --- /dev/null +++ b/bash-5.1/builtins_rust/rreturn/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rreturn" +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 = "rreturn" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/rreturn/src/intercdep.rs b/bash-5.1/builtins_rust/rreturn/src/intercdep.rs new file mode 100644 index 00000000..7e976417 --- /dev/null +++ b/bash-5.1/builtins_rust/rreturn/src/intercdep.rs @@ -0,0 +1,54 @@ + +#[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 __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]; + +extern "C" { + pub fn builtin_usage(); + pub fn builtin_help(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn get_exitstat(list: *mut WORD_LIST) -> c_int; + + pub fn siglongjmp(__env: *mut __jmp_buf_tag, __val: c_int); + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + + pub static mut return_catch_value: c_int; + pub static return_catch_flag: c_int; + pub static return_catch: sigjmp_buf; +} diff --git a/bash-5.1/builtins_rust/rreturn/src/lib.rs b/bash-5.1/builtins_rust/rreturn/src/lib.rs new file mode 100644 index 00000000..277faa26 --- /dev/null +++ b/bash-5.1/builtins_rust/rreturn/src/lib.rs @@ -0,0 +1,25 @@ +use libc::{c_int, c_char, c_long, c_ulong}; + +include!(concat!("intercdep.rs")); + +#[no_mangle] +pub extern "C" fn r_return_builtin(list: *mut WORD_LIST) -> i32 { + println!("r_return_builtin call"); + +unsafe { + 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; + } + + return_catch_value = get_exitstat(list); + if return_catch_flag != 0 { + siglongjmp(std::mem::transmute(&return_catch), 1); + } else { + builtin_error("can only `return' from a function or sourced script\0".as_ptr() as *const c_char); + return EX_USAGE; + } +} + return EXECUTION_SUCCESS; +} diff --git a/bash-5.1/builtins_rust/shift/Cargo.toml b/bash-5.1/builtins_rust/shift/Cargo.toml new file mode 100644 index 00000000..e53a57fd --- /dev/null +++ b/bash-5.1/builtins_rust/shift/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "shift" +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 = "rshift" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/shift/src/intercdep.rs b/bash-5.1/builtins_rust/shift/src/intercdep.rs new file mode 100644 index 00000000..24ce4a1b --- /dev/null +++ b/bash-5.1/builtins_rust/shift/src/intercdep.rs @@ -0,0 +1,36 @@ + +#[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; + +extern "C" { + pub fn builtin_usage(); + pub fn builtin_help(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn get_numeric_arg(list: *mut WORD_LIST, fatal: c_int, count: c_long) -> c_int; + pub fn number_of_args() -> c_int; + pub fn sh_erange(s: *mut c_char, desc: *mut c_char); + pub fn clear_dollar_vars(); + pub fn shift_args(times: c_int); + pub fn invalidate_cached_quoted_dollar_at(); + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; +} diff --git a/bash-5.1/builtins_rust/shift/src/lib.rs b/bash-5.1/builtins_rust/shift/src/lib.rs new file mode 100644 index 00000000..00fb8f87 --- /dev/null +++ b/bash-5.1/builtins_rust/shift/src/lib.rs @@ -0,0 +1,47 @@ +use libc::{c_int, c_char, c_long, PT_NULL}; + +include!(concat!("intercdep.rs")); + +pub static print_shift_error: c_int = 0; + +#[no_mangle] +pub extern "C" fn r_shift_builtin(list: *mut WORD_LIST) -> i32 { + println!("r_shift_builtin call"); + +unsafe { + 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 times: c_int = 0; + if get_numeric_arg(list, 0, std::mem::transmute(×)) == 0 { + return EXECUTION_FAILURE; + } + + if times == 0 { + return EXECUTION_SUCCESS; + } else if times < 0 { + let s = if list.is_null() {PT_NULL as *mut c_char} else {(*(*list).word).word}; + sh_erange(s,"shift count\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + + let nargs = number_of_args(); + if times > nargs { + if print_shift_error != 0 { + let s = if list.is_null() {PT_NULL as *mut c_char} else {(*(*list).word).word}; + sh_erange(s,"shift count\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + } else if times == nargs { + clear_dollar_vars(); + } else { + shift_args(times); + } + + invalidate_cached_quoted_dollar_at(); +} + return EXECUTION_SUCCESS; +} diff --git a/bash-5.1/builtins_rust/source/Cargo.toml b/bash-5.1/builtins_rust/source/Cargo.toml new file mode 100644 index 00000000..124fdbef --- /dev/null +++ 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 new file mode 100644 index 00000000..f3e3d5e0 --- /dev/null +++ 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/builtins_rust/suspend/Cargo.toml b/bash-5.1/builtins_rust/suspend/Cargo.toml new file mode 100644 index 00000000..c758cc9f --- /dev/null +++ b/bash-5.1/builtins_rust/suspend/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "suspend" +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 = "rsuspend" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/suspend/src/intercdep.rs b/bash-5.1/builtins_rust/suspend/src/intercdep.rs new file mode 100644 index 00000000..5cf962bf --- /dev/null +++ b/bash-5.1/builtins_rust/suspend/src/intercdep.rs @@ -0,0 +1,42 @@ + +#[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 SigHandler = unsafe extern "C" fn(arg1: c_int); + +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_help(); + pub fn builtin_error(format: *const c_char, ...); + + pub fn sh_nojobs(s: *mut c_char); + pub fn no_args(list: *mut WORD_LIST); + pub fn killpg(pgrp: libc::pid_t, sig: c_int) -> c_int; + + pub fn set_signal_handler(arg1: c_int, arg2: *mut SigHandler) -> *mut SigHandler; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + pub static mut job_control: c_int; + pub static mut login_shell: c_int; + pub static mut shell_pgrp: libc::pid_t; +} diff --git a/bash-5.1/builtins_rust/suspend/src/lib.rs b/bash-5.1/builtins_rust/suspend/src/lib.rs new file mode 100644 index 00000000..b92a6ff3 --- /dev/null +++ b/bash-5.1/builtins_rust/suspend/src/lib.rs @@ -0,0 +1,54 @@ +use libc::{c_int, c_char, c_long, PT_NULL}; + +include!(concat!("intercdep.rs")); + +pub static mut old_cont: *mut SigHandler = PT_NULL as *mut SigHandler; + +#[no_mangle] +pub extern "C" fn r_suspend_builtin(mut list: *mut WORD_LIST) -> i32 { + println!("r_suspend_builtin call"); + + let mut opt: c_int; + let mut force: c_int = 0; + +unsafe { + reset_internal_getopt(); + let opt_str = "f:\0".as_ptr() as *mut c_char; + opt = internal_getopt (list, opt_str); + while opt != -1 { + let opt_char:char=char::from(opt as u8); + match opt_char { + 'f' => force += 1, + _ => { + builtin_usage (); + return EX_USAGE; + } + } + opt = internal_getopt (list, opt_str); + } + list = loptend; + + if job_control == 0 { + sh_nojobs("cannot suspend\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + + if force == 0 { + no_args(list); + if login_shell != 0 { + builtin_error("cannot suspend a login shell\0".as_ptr() as *mut c_char); + return EXECUTION_FAILURE; + } + } + + old_cont = set_signal_handler(libc::SIGCONT, std::mem::transmute(suspend_continue as usize)); + + killpg(shell_pgrp, libc::SIGSTOP); +} + return EXECUTION_SUCCESS; +} + +unsafe fn suspend_continue(sig: c_int) +{ + set_signal_handler(libc::SIGCONT, old_cont); +} \ No newline at end of file diff --git a/bash-5.1/builtins_rust/test/Cargo.toml b/bash-5.1/builtins_rust/test/Cargo.toml new file mode 100644 index 00000000..2e66e538 --- /dev/null +++ b/bash-5.1/builtins_rust/test/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "test" +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 = "rtest" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/test/src/intercdep.rs b/bash-5.1/builtins_rust/test/src/intercdep.rs new file mode 100644 index 00000000..060c9f46 --- /dev/null +++ b/bash-5.1/builtins_rust/test/src/intercdep.rs @@ -0,0 +1,32 @@ + +#[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_BADUSAGE : c_int = 2; +pub const EX_USAGE: c_int = 258; + +extern "C" { + pub fn builtin_error(format: *const c_char, ...); + + pub fn make_builtin_argv(list: *mut WORD_LIST, ip: *mut c_int) -> *mut *mut c_char; + pub fn test_command (margc: c_int, margv: *mut *mut c_char) -> c_int; + + pub static mut list_optarg : *mut libc::c_char; + pub static mut loptend : *mut WORD_LIST; + pub static mut this_command_name: *mut c_char; +} diff --git a/bash-5.1/builtins_rust/test/src/lib.rs b/bash-5.1/builtins_rust/test/src/lib.rs new file mode 100644 index 00000000..e45d4aad --- /dev/null +++ b/bash-5.1/builtins_rust/test/src/lib.rs @@ -0,0 +1,25 @@ +use libc::{c_int, c_char, c_void}; + +include!(concat!("intercdep.rs")); + +#[no_mangle] +pub extern "C" fn r_test_builtin(list: *mut WORD_LIST) -> i32 { + println!("r_test_builtin call"); + + let result: c_int; + let mut argc: c_int = 0; +unsafe { + if list.is_null() { + if *this_command_name == b'[' as c_char && + *((this_command_name as usize + 1) as *mut c_char) == 0 { + builtin_error("missing `]'\0".as_ptr() as *mut c_char); + return EX_BADUSAGE; + } + return EXECUTION_FAILURE; + } + let argv = make_builtin_argv(list, std::mem::transmute(&argc)); + result = test_command(argc, argv); + libc::free(argv as *mut c_void); +} + return result; +} diff --git a/bash-5.1/builtins_rust/times/Cargo.toml b/bash-5.1/builtins_rust/times/Cargo.toml new file mode 100644 index 00000000..4067fac2 --- /dev/null +++ b/bash-5.1/builtins_rust/times/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "times" +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 = "rtimes" +crate-type = ["cdylib"] + +[dependencies] +libc = "0.2" +nix = "0.23" diff --git a/bash-5.1/builtins_rust/times/src/intercdep.rs b/bash-5.1/builtins_rust/times/src/intercdep.rs new file mode 100644 index 00000000..beca3327 --- /dev/null +++ b/bash-5.1/builtins_rust/times/src/intercdep.rs @@ -0,0 +1,28 @@ + +#[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; + +extern "C" { + pub fn no_options(list: *mut WORD_LIST) -> c_int; + pub fn print_timeval(fp: *mut libc::FILE, tvp: *mut libc::timeval); + pub fn sh_chkwrite(s: c_int) -> c_int; + + pub static stdout: *mut libc::FILE; +} diff --git a/bash-5.1/builtins_rust/times/src/lib.rs b/bash-5.1/builtins_rust/times/src/lib.rs new file mode 100644 index 00000000..1632fee5 --- /dev/null +++ b/bash-5.1/builtins_rust/times/src/lib.rs @@ -0,0 +1,34 @@ +use libc::{c_int, c_char}; + +include!(concat!("intercdep.rs")); + +#[no_mangle] +pub extern "C" fn r_times_builtin(list: *mut WORD_LIST) -> i32 { + println!("r_times_builtin call"); + +unsafe { + + if no_options(list) != 0 { + return EX_USAGE; + } + + let mut curr: libc::rusage = std::mem::zeroed(); + let mut kids: libc::rusage = std::mem::zeroed(); + libc::putchar(b'\n' as c_int); + + libc::getrusage(libc::RUSAGE_SELF, std::mem::transmute(&curr)); + libc::getrusage(libc::RUSAGE_CHILDREN, std::mem::transmute(&kids)); + + print_timeval(stdout, std::mem::transmute(&curr.ru_utime)); + libc::putchar(b' ' as c_int); + print_timeval(stdout, std::mem::transmute(&curr.ru_stime)); + libc::putchar(b'\n' as c_int); + + print_timeval(stdout, std::mem::transmute(&kids.ru_utime)); + libc::putchar(b' ' as c_int); + print_timeval(stdout, std::mem::transmute(&kids.ru_stime)); + libc::putchar(b'\n' as c_int); + + return sh_chkwrite(EXECUTION_SUCCESS); +} +} diff --git a/bash-5.1/execute_cmd.c b/bash-5.1/execute_cmd.c index ecd509c3..9d66af0b 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 f3b7f9be..f6f3be36 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 874f7e60..39f431c5 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 index d4de868f..127299a0 100644 --- a/record.txt +++ b/record.txt @@ -19,3 +19,4 @@ 19 20 21 +25 -- Gitee