Mercurial > repo
diff interps/cfunge/cfunge-src/tools/fprint_funcs.sh @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/interps/cfunge/cfunge-src/tools/fprint_funcs.sh Sun Dec 09 19:30:08 2012 +0000 @@ -0,0 +1,245 @@ +#!/usr/bin/env bash +# -*- coding: utf-8 -*- +########################################################################### +# # +# cfunge - A standard-conforming Befunge93/98/109 interpreter in C. # +# Copyright (C) 2008-2009 Arvid Norlander # +# # +# 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 the proxy's option) any later version. Arvid Norlander is a # +# proxy who can decide which future versions of the GNU General Public # +# License can be used. # +# # +# 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/>. # +# # +########################################################################### + +# This script contains utility functions for the fingerprint scripts. It is +# not meant for stand alone use. + +# Clean up locale settings to prevent strange bugs: +unset LANG LC_ALL LC_COLLATE LC_CTYPE LC_NUMERIC +export LANG=C +export LC_ALL=C + +# Print error message to stderr and exit. Each parameter is printed on it's own +# line prefixed by "ERROR: ". +die() { + local emsg + for emsg in "$@"; do + echo "ERROR: $emsg" >&2 + echo -ne '\a' >&2 + done + exit 1 +} + +warn() { + local emsg + for emsg in "$@"; do + echo "WARNING: $emsg" >&2 + echo -ne '\a' >&2 + done + echo -ne '\a' >&2 + sleep 5 +} + +progress() { + echo " * ${1}..." +} +progresslvl2() { + echo " * ${1}..." +} + +status() { + echo " ${1}" +} +statuslvl2() { + echo " ${1}" +} + +# Char to decimal (ASCII value) +# $1 Name of output variable +# $2 Char to convert. +ord() { + printf -v "$1" '%d' "'$2" +} + +# $1 is fingerprint name +# Returns if ok, otherwise it dies. +checkfprint() { + local FPRINT="$1" + if [[ $FPRINT =~ ^[A-Z0-9]{4}$ ]]; then + status "Fingerprint name $FPRINT ok style." + elif [[ $FPRINT =~ ^[^\ /\\]{4}$ ]]; then + status "Fingerprint name $FPRINT probably ok (but not common style)." + status "Make sure each char is in the ASCII range 0-254." + status "Note that alphanumeric (upper case only) fingerprint names are strongly preferred." + else + die "Not valid format for fingerprint name." + fi +} + +# Parse a spec file. Will make use of FD 4. +# $1 Fingerprint name. +# There must be a file named ${1}.spec in the current directory +# The caller should make sure it exists. The caller should also have +# called checkfprint to validate it. +# This will set/change these globals: +# Strings: +# fp_URL Fingerprint URL +# fp_F109_URI URI for Funge-109 +# fp_CONDITION #if condition for compilation. +# fp_SAFE Safe for sandbox mode (true/false) +# fp_OPCODES Defined opcodes. +# fp_DESCRIPTION Description +# Arrays: +# fp_ALIASES An array with aliases for the fingerprint. +# (text format, not hex) +# fp_OPCODE_NAMES Opcode names (index: opcode's ASCII value). +# fp_OPCODE_DESC Opcode descriptions (index: opcode's ASCII value). +# +# On return IFS is unset. +# This function calls die in case of errors. +parse_spec() { + local FPRINT="$1" + # Variables + fp_URL="" + fp_F109_URI="NULL" + fp_CONDITION="" + fp_SAFE="" + fp_OPCODES="" + fp_DESCRIPTION="" + fp_ALIASES=() + fp_OPCODE_NAMES=() + fp_OPCODE_DESC=() + + if [[ ! -f "${FPRINT}.spec" ]]; then + die "${FPRINT}.spec not found (or not a normal file)." + fi + + progresslvl2 "Opening spec file" + IFS=$'\n' + local line type data instr name desc number + # First line is %fingerprint-spec 1.[234] + # (1.2 is still supported). + exec 4<"${FPRINT}.spec" || die "Couldn't open spec file for reading on FD 4." + statuslvl2 "Success." + progresslvl2 "Parsing spec file" + read -ru 4 line + if ! [[ "$line" =~ ^%fingerprint-spec\ 1\.[234]$ ]]; then + die "Either the spec file is not a fingerprint spec, or it is not a supported version (1.2, 1.3 and 1.4 are currently supported)." + fi + + # 0: pre-"begin instrs" + # 1: "begin-instrs" + local parsestate=0 + + while read -ru 4 line; do + if [[ "$line" =~ ^# ]]; then + continue + fi + if [[ $parsestate == 0 ]]; then + IFS=':' read -rd $'\n' type data <<< "$line" || true + case $type in + "%fprint") + if [[ "$FPRINT" != "$data" ]]; then + die "%fprint and spec file name doesn't match." + fi + ;; + "%url") + fp_URL="$data" + ;; + "%f108-uri") + warn "%f108-uri is deprecated. Replace with %f109-uri and update spec format to 1.4." + fp_F109_URI="\"$data\"" + ;; + "%f109-uri") + fp_F109_URI="\"$data\"" + ;; + "%condition") + fp_CONDITION="$data" + ;; + "%alias") + fp_ALIASES+=( "$data" ) + ;; + "%desc") + fp_DESCRIPTION="$data" + ;; + "%safe") + fp_SAFE="$data" + ;; + "%begin-instrs") + parsestate=1 + ;; + "#"*) + # A comment, ignore + ;; + *) + die "Unknown entry $type found in ${FPRINT}." + ;; + esac + else + if [[ "$line" == "%end" ]]; then + break + fi + # Parse instruction lines. + IFS=$' \t' read -rd $'\n' instr name desc <<< "$line" + + fp_OPCODES+="$instr" + ord number "${instr:0:1}" + fp_OPCODE_NAMES[$number]="$name" + fp_OPCODE_DESC[$number]="$desc" + fi + done + + unset IFS + + statuslvl2 "Done parsing." + + exec 4<&- + + progresslvl2 "Validating the parsed data" + + if [[ "$fp_URL" ]]; then + statuslvl2 "%url: Good, not empty" + else + die "%url is not given or is empty." + fi + + if [[ "$fp_DESCRIPTION" ]]; then + statuslvl2 "%desc: Good, not empty" + else + die "%desc is not given or is empty." + fi + + if [[ ( "$fp_SAFE" == "true" ) || ( "$fp_SAFE" == "false" ) ]]; then + statuslvl2 "%safe: OK" + else + die "%safe must be either true or false." + fi + + if [[ "$fp_OPCODES" =~ ^[A-Z]+$ ]]; then + # Check that they are sorted. + local previousnr=0 + for (( i = 0; i < ${#fp_OPCODES}; i++ )); do + ord number "${fp_OPCODES:$i:1}" + if [[ $previousnr -ge $number ]]; then + die "Instructions not sorted or there are duplicates" + else + previousnr=$number + fi + done + statuslvl2 "Instructions: OK" + else + die "The opcodes are not valid. The must be in the range A-Z" + fi + return 0 +}