From ddc4138f41e892d7e665a04217d6c0c4108c132e Mon Sep 17 00:00:00 2001
From: P. J. McDermott <pjm@nac.net>
Date: Sat, 26 Oct 2013 18:04:22 -0400
Subject: lib/fd.sh: New file.

---
(limited to 'lib')

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
--
cgit v0.9.1