# Eggshell runtime library # # Copyright (C) 2016 Patrick "P. J." McDermott # # This file is part of the Eggshell Linker. # # The Eggshell Linker 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. # # The Eggshell Linker 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 the Eggshell Linker If not, see # . eshrtbegin() { cat <<-'EOF' __ESC="$(printf '\033.')"; __ESC="${__ESC%.}" __RS="$(printf '\036.')"; __RS="${__RS%.}" __US="$(printf '\037.')"; __US="${__US%.}" __fn_stack='' __fn_frame='' __fn_name='' __fn_tu='' __fn_vars='' __fn_var_vals='' __fn='' __prev_tu='' __prev_vars='' __var='' __val='' __init_funcs='' __fn_stack_push() { __fn_stack="${__fn_stack}${__RS}${__fn_frame}" } __fn_stack_peek() { __fn_frame="${__fn_stack##*${__RS}}" } __fn_stack_pop() { __fn_stack_peek __fn_stack="${__fn_stack%${__RS}*}" } __fn_frame_encode() { # RS and US in frame variable values must be encoded. __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed " s|${__ESC}|${__ESC}0|g; s|${__RS}|${__ESC}1|g; s|${__US}|${__ESC}2|g; ")" __fn_frame="${__fn_name}${__US}${__fn_tu}" __fn_frame="${__fn_frame}${__US}${__fn_vars}${__US}${__fn_var_vals}" } __fn_frame_decode() { __fn_name="${__fn_frame%%${__US}*}" __fn_frame="${__fn_frame#*${__US}}" __fn_tu="${__fn_frame%%${__US}*}" __fn_frame="${__fn_frame#*${__US}}" __fn_vars="${__fn_frame%%${__US}*}" __fn_var_vals="${__fn_frame#*${__US}}" __fn_var_vals="$(printf '%s' "${__fn_var_vals}" | sed " s|${__ESC}0|${__ESC}|g; s|${__ESC}1|${__RS}|g; s|${__ESC}2|${__US}|g; ")" } __fn_ctxsw() { unset IFS case "${__prev_tu}" in ${__fn_tu});; ?*) # Unset static variables and functions from previous TU. case "$(eval "printf '%s' \ \"\${__${__prev_tu}_static_vars}\"")" \ in ?*) eval "unset \${__${__prev_tu}_static_vars}" ;; esac for __fn in $(eval printf '%s' \ "\"\${__${__prev_tu}_static_fns}\""); do unset -f "${__fn%:*}" done ;; esac case "${__fn_tu}" in ${__prev_tu});; ?*) # Set static variables and function for the current TU. eval "$(eval printf '%s' "\"$(eval printf '%s' \ "'\${__${__fn_tu}_static_var_vals}'")\"")" for __fn in $(eval printf '%s' \ "\"\${__${__fn_tu}_static_fns}\""); do eval "${__fn%:*}() { ${__fn#*:}; }" done ;; esac case "${__prev_vars}" in ?*) unset ${__prev_vars} ;; esac eval "${__fn_var_vals}" } __fn_update_vars() { for __var in ${__fn_vars}; do __val="$(eval "printf '%s' \"\${${__var}}\"" | \ sed "s|'|'\\\\''|g;")" __fn_var_vals="${__fn_var_vals} ${__var}='${__val}'" done } __fn_start() { # Old state. __prev_tu="${__fn_tu}" __prev_vars="${__fn_vars}" # Update local vars in stack. __fn_stack_pop __fn_vars="${__prev_vars}" __fn_update_vars __fn_frame_encode __fn_stack_push # New state. __fn_name="${2}" __fn_tu="${1}" __fn_vars= __fn_var_vals= __fn_frame_encode __fn_stack_push # Switch. __fn_ctxsw } __fn_end() { # Old state. __fn_stack_pop __fn_frame_decode __prev_tu="${__fn_tu}" __prev_vars="${__fn_vars}" # New state. __fn_stack_peek __fn_frame_decode # Switch. __fn_ctxsw } __tu_end() { # Save TU static vars. for __var in $(eval "printf '%s' \"\${__${__tu}_static_vars}\""); do __val="$(eval "printf '%s' \"\${${__var}}\"" | \ sed "s|'|'\\\\''|g")" eval "__${__tu}_static_var_vals=\"\${__${__tu}_static_var_vals}\ ${__var}='\${__val}'\"" unset ${__var} done __tu='' } __stack_trace() { IFS="${__RS}" for __fn_frame in ${__fn_stack#${__RS}}; do printf '%s\n' "${__fn_frame%%${__US}*}" done } __local() { for __var in "${@}"; do case "${__var}" in *=*) __val="${__var#*=}" __var="${__var%%=*}" ;; *) __val='' ;; esac case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*) printf 'Syntax error: %s %s\n' \ 'illegal static variable name:' "${__var}" >&2 exit 1 ;; esac eval "${__var}=\${__val}" __fn_vars="${__fn_vars} ${__var}" done } static() { case "${__tu}" in '') printf 'Error: Cannot declare static variables in functions' >&2 exit 1 ;; esac for __var in "${@}"; do case "${__var}" in *=*) __val="${__var#*=}" __var="${__var%%=*}" ;; *) __val='' ;; esac case "${__var}" in [!A-Za-z_]* | *[!0-9A-Za-z_]*) printf 'Syntax error: %s %s\n' \ 'illegal static variable name:' "${__var}" >&2 exit 1 ;; esac eval "${__var}=\${__val}" eval "__${__tu}_static_vars=\"\${__${__tu}_static_vars} \ ${__var}\"" done } __init() { __init_funcs="${__init_funcs} ${1}" } EOF } eshrtend() { local entry="${1}" shift 1 cat <<-'EOF' for __func in ${__init_funcs}; do ${__func} done EOF printf '%s "${@}"\n' "${entry_point}" }