summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/fd.sh95
-rw-r--r--lib/local.mk1
-rw-r--r--locale/en_US.sh4
3 files changed, 100 insertions, 0 deletions
diff --git a/lib/fd.sh b/lib/fd.sh
new file mode 100644
index 0000000..0f78a40
--- /dev/null
+++ b/lib/fd.sh
@@ -0,0 +1,95 @@
+# ProteanOS Development Kit
+# lib/fd.sh
+# Functions for opening and closing file descriptors
+#
+# Copyright (C) 2013 Patrick "P. J." McDermott
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+[ "x${_FD_SM+set}" = 'xset' ] && return 0
+_FD_SM=1
+
+_FD_MIN=3
+# 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.
+_FD_MAX=9
+
+FD=
+
+fopen()
+{
+ local path="${1}"
+ local mode="${2}"
+ local i=
+ local fd=
+
+ case "${mode}" in
+ 'r') mode='<' ;;
+ 'w') mode='>' ;;
+ 'a') mode='>>';;
+ 'rw') mode='<>';;
+ *) return 125;;
+ esac
+
+ # Find first available file descriptor.
+ i=${_FD_MIN}
+ while [ ${i} -le ${_FD_MAX} ]; do
+ if [ "x$(eval echo "\${_fd_${i}+set}")" != 'xset' ]; then
+ fd=${i}
+ break
+ fi
+ i=$(($i + 1))
+ done
+ if [ "x${fd:+set}" != 'xset' ]; then
+ error 2 "$(get_msg 'emfile')"
+ return
+ fi
+
+ if eval "exec ${fd}${mode}'${path}'"; then
+ eval "_fd_${fd}='${mode}${path}'"
+ FD="${fd}"
+ return 0
+ else
+ FD=''
+ return 1
+ fi
+}
+
+fclose()
+{
+ local fd="${1}"
+
+ # Make sure the file descriptor is open.
+ if [ "x$(eval echo "\${_fd_${fd}+set}")" != 'xset' ]; then
+ error 2 "$(get_msg 'ebadf')"
+ fi
+
+ eval "exec ${fd}>&-"
+ unset "_fd_${fd}"
+
+ return 0
+}
diff --git a/lib/local.mk b/lib/local.mk
index f0ccd5c..2525d10 100644
--- a/lib/local.mk
+++ b/lib/local.mk
@@ -2,4 +2,5 @@ pkgdata_sources = \
lib/output.sh \
lib/locale.sh \
lib/getopt.sh \
+ lib/fd.sh \
lib/cmd.sh
diff --git a/locale/en_US.sh b/locale/en_US.sh
index 103f6e2..02f82a9 100644
--- a/locale/en_US.sh
+++ b/locale/en_US.sh
@@ -21,6 +21,10 @@
msg_prokit_opt_h_summary='print this help message'
msg_prokit_opt_V_summary='print version information'
+# lib/fd.sh
+msg_prokit_emfile='Too many open files'
+msg_prokit_ebadf='Bad file descriptor'
+
# lib/cmd.sh
msg_prokit_cmd_not_found='Command "%s" not found'
msg_prokit_cmd_usage='Usage: %s [<option> ...] %s %s'