diff options
author | Patrick McDermott <patrick.mcdermott@libiquity.com> | 2018-12-20 17:01:00 (EST) |
---|---|---|
committer | Patrick McDermott <patrick.mcdermott@libiquity.com> | 2018-12-20 17:01:00 (EST) |
commit | 032e6186fe8dd3c54b9e027cb63fff3127e2d559 (patch) | |
tree | 8e4fe2f91661ee1f70c896c5a74b07fbb368b33b /tools/shld.sh | |
parent | f6f4e858207d7df649d9848fa91458925b7b1794 (diff) |
tools/shld.sh, tools/shpp.sh: Add
Diffstat (limited to 'tools/shld.sh')
-rwxr-xr-x | tools/shld.sh | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/tools/shld.sh b/tools/shld.sh new file mode 100755 index 0000000..41751d3 --- /dev/null +++ b/tools/shld.sh @@ -0,0 +1,166 @@ +#!/bin/sh +# +# Shell command language linker +# +# Copyright (C) 2015 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/>. + +set -u + +VERSION='0.2.0' + +die() +{ + local fmt="${1}" + shift 1 + + printf "shld: ${fmt}\n" "${@}" >&2 + exit 2 +} + +link() +{ + local make_executable="${1}" + local interpreter="${2}" + local entry_point="${3}" + local output="${4}" + shift 4 + local input= + + # Open output file. + if ! exec 3>"${output}~"; then + die 'Cannot open file "%s"' "${output}~" + fi + + # Write magic number and interpreter path. + if ${make_executable}; then + printf '#!%s\n' "${interpreter}" >&3 + fi + + # Write __init() function. + cat >&3 <<-'EOF' + __init_funcs='' + __init() + { + __init_funcs="${__init_funcs} ${1}" + } + EOF + + # Read input files. + for input in "${@}"; do + if ! cat "${input}" >&3; then + die 'Cannot read file "%s"' "${input}" + fi + done + + # Add call to init functions. + cat >&3 <<-'EOF' + for __func in ${__init_funcs}; do + ${__func} + done + EOF + + # Add call to entry point. + if ${make_executable}; then + printf '%s "${@}"\n' "${entry_point}" >&3 + fi + + # Close output file, make it executable, and set its name. + exec 3>&- + if ${make_executable}; then + if ! chmod a+x "${output}~"; then + die 'Cannot set mode of file "%s"' "${output}~" + fi + fi + if ! mv "${output}~" "${output}"; then + die 'Cannot rename file to "%s"' "${output}" + fi +} + +usage() +{ + printf 'Usage: %s [option ...] <file>...\n' "${0}" +} + +help() +{ + usage + cat <<EOF +Options: + -h Display this information + -V Display linker version information + -I <interp> Make an executable and use <interp> as the interpreter for your + program, instead of the default of "/bin/sh" + -e <entry> Make an executable and use <entry> as the function for beginning + execution of your program, instead of the default of "main" + -o <output> Use <output> as the name of the program produced by shld, instead + of the default of "out.sh" +EOF +} + +version() +{ + cat <<EOF +shld ${VERSION} +Copyright (C) 2015 Patrick "P. J." McDermott +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +EOF +} + +main() +{ + local opt= + local make_executable=false + local interpreter='/bin/sh' + local entry_point='main' + local output='out.sh' + + while getopts 'hVI:e:o:' opt; do + case "${opt}" in + 'h') + help + exit + ;; + 'V') + version + exit + ;; + 'I') + interpreter="${OPTARG}" + make_executable=true + ;; + 'e') + entry_point="${OPTARG}" + make_executable=true + ;; + 'o') + output="${OPTARG}" + ;; + esac + done + shift $(($OPTIND - 1)) + + if [ ${#} -lt 1 ]; then + usage >&2 + exit 1 + fi + + link "${make_executable}" "${interpreter}" "${entry_point}" \ + "${output}" "${@}" +} + +main "${@}" |