diff options
author | P. J. McDermott <pj@pehjota.net> | 2016-02-14 21:46:40 (EST) |
---|---|---|
committer | P. J. McDermott <pj@pehjota.net> | 2016-02-14 21:46:40 (EST) |
commit | 5da1775daf87fe38d46dcdeef6ed64c6fac0bd29 (patch) | |
tree | 0389b995add0684e7c8f0099d810dc3a7fb7ce0c /libsh/stdio.sh | |
download | eggshell-5da1775daf87fe38d46dcdeef6ed64c6fac0bd29.zip eggshell-5da1775daf87fe38d46dcdeef6ed64c6fac0bd29.tar.gz eggshell-5da1775daf87fe38d46dcdeef6ed64c6fac0bd29.tar.bz2 |
Initial commit
Diffstat (limited to 'libsh/stdio.sh')
-rw-r--r-- | libsh/stdio.sh | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libsh/stdio.sh b/libsh/stdio.sh new file mode 100644 index 0000000..7d44d12 --- /dev/null +++ b/libsh/stdio.sh @@ -0,0 +1,123 @@ +# Copyright (C) 2013, 2016 Patrick "P. J." McDermott +# +# This file is part of libsh. +# +# libsh is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# libsh is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with libsh. If not, see +# <http://www.gnu.org/licenses/>. + +# Shells and the file descriptors they reserve for the user: +# * Debian Almquist Shell +# - The shell doesn't understand any file descriptor greater than 9. +# - File descriptors starting at 10 are used for I/O redirection. +# * BusyBox ash +# - File descriptors starting at 10 are used for job control and I/O +# redirection. +# * GNU Bash: +# - GNU Readline uses file descriptor 255 in interactive shells. +# - File descriptors starting at 10 are used for I/O redirection. +# * MirOS Korn Shell +# - File descriptors starting at either 10 or 24 are used for the shell's +# tty_fd and shl_dbg_fd. +# * Solaris ksh +# - The shell doesn't understand any file descriptor greater than 9. +static fd_min=3 +static fd_max=9 + +static fd_3_set=false +static fd_4_set=false +static fd_5_set=false +static fd_6_set=false +static fd_7_set=false +static fd_8_set=false +static fd_9_set=false + +fd=0 + +static fopen() +{ + local path="${1}" + local mode="${2}" + local mode_r= + local mode_w= + local i= + local f= + + case "${mode}" in + 'r') mode_r=true mode_w=false mode='<' ;; + 'r+') mode_r=true mode_w=true mode='<>';; + 'w') mode_r=false mode_w=true mode='>' ;; + 'a') mode_r=false mode_w=true mode='>>';; + *) return ${EINVAL};; + esac + + # Find first available file descriptor. + i=${fd_min} + while [ ${i} -le ${fd_max} ]; do + if ! $(eval "printf '%s' \${fd_${i}_set}"); then + f=${i} + break + fi + i=$(($i + 1)) + done + if [ "x${f}" = 'x' ]; then + return ${EMFILE} + fi + + # Check file mode and existence. + if ${mode_r} && ! [ -r "${path}" ]; then + return ${EACCES} + fi + if ${mode_w} && ! [ -w "${path}" ]; then + return ${EACCES} + fi + if ! [ -e "${path}" ]; then + return ${ENOENT} + fi + if [ -d "${path}" ]; then + return ${EISDIR} + fi + + if ! eval "exec ${f}${mode}'${path}'" 2>/dev/null; then + return ${EUNK} + fi + + eval "fd_${f}_set=true" + fd="${f}" + return 0 +} + +static fclose() +{ + local f=${1} + + # Make sure the file descriptor is valid and open. + if [ ${f} -lt ${fd_min} ] || [ ${f} -gt ${fd_max} ]; then + return ${EINVAL} + fi + if $(eval "printf '%s' \${fd_${i}_set}"); then + return ${EBADF} + fi + + eval "exec ${f}>&-" + unset "fd_${f}" + + return 0 +} + +static stdio_alias() +{ + __alias ${fopen} fopen string string + __alias ${fclose} fclose int +} +__init ${stdio_alias} |