commit 2dda2e227d1a947775f9f647e31cc75ece48da0c Author: Darren 'Tadgy' Austin Date: Tue Jul 16 12:41:49 2019 +0100 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d042548 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.save +.*.swp diff --git a/SPEC b/SPEC new file mode 100644 index 0000000..5c02a28 --- /dev/null +++ b/SPEC @@ -0,0 +1,12 @@ +Blank lines are ignored. +Lines starting with # and ; (configurable; after leading whitespace removal) are treated as comments. + - Comments must appear on their own line. +Values can optionally be bookmarked with single or double quotes. + - If quotes are to be used, they must be the first and last characters of the value + - Occurances of the bookending quotes to be used within the value must be \ escaped. ??? + - Whitespace within the quotes is retained verbatim. + - Backslash line continuation is supported within quotes (but leading whitespace on subsequent lines is removed). +Values can be continued by use of \ in the last column. + - Subsequent lines are subject to leading whitespace removal as normal. + - Comments are not recognised on subsequent lines - they are treated as part of the value. +Escaping of shell special characters is not required. ??? diff --git a/TODO b/TODO new file mode 100644 index 0000000..2a2623f --- /dev/null +++ b/TODO @@ -0,0 +1,13 @@ + -s , --section=Only parse the specified section(s). List multiple + sections seperated by commas. For the global section + use '.'. For every section except global, use '*'. + For every section including the global section, don't + use this option (or use '.,*'). + + --ignore-errors Ignore parse errors in the ini file and continue + processing. This will cause options to be ignored + and whole sections to be skipped if errors are found. + This option should not be used except for debugging. + + +Have the parser accept a filename of '-' to indicate it should read from stdin. diff --git a/bits/comments.ini b/bits/comments.ini new file mode 100644 index 0000000..4d5148a --- /dev/null +++ b/bits/comments.ini @@ -0,0 +1,42 @@ +# comment 1 +; comment 2 + # comment 3 + ; comment 4 + # comment 5 + ; comment 6 + # comment 7 + ; comment 8 + # comment 9 + ; comment 10 + # comment 11 + ; comment 12 + # comment 13 + ; comment 14 + #comment 15 + ;comment 16 +##### comment 17 +;;;;;;;; comment 18 + ########## comment 19 + ;;;; comment 20 + # comment 21 + ;comment 22 + + + + + + +# + # comment 23 # + # # comment 24 + # # comment 25 +Valid 1 +[header1] + Valid 2 + Valid 3 + Valid 4 + [ header 2 ] + Valid 5 +[ header 3 ] +[header_____4____] + [ $%"%^ ] diff --git a/bits/duplicate-sections.ini b/bits/duplicate-sections.ini new file mode 100644 index 0000000..42fae32 --- /dev/null +++ b/bits/duplicate-sections.ini @@ -0,0 +1,10 @@ +global key 1 = value 1 + +[ section 1 ] +key 1 = value 1 + +[ section 2 ] +key 1 = value 1 + +[ section 1 ] +key 2 = value 2 diff --git a/bits/key-blanks.ini b/bits/key-blanks.ini new file mode 100644 index 0000000..6a7820c --- /dev/null +++ b/bits/key-blanks.ini @@ -0,0 +1,314 @@ +####################################################### +# Key format tests: = as deliminator # +# Blanks at the start of, in, and after each key name # +####################################################### + +# Blanks in keys. +[blanks] +keyformattest1a= No blanks in key name, no blanks before or after key name +key formattest1b= Single space in key name, no blanks before or after key name +key format test 1c= Multiple spaces in key name, no blanks before or after key name +key format test 1d= Multiple consecutive spaces in key name, no blanks before or after key name +key formattest1e= Single tab in key name, no blanks before or after key name +key format test 1f= Multiple tabs in key name, no blanks before or after key name +key format test 1g= Multiple consecutive tabs in key name, no blanks before or after key name + +# Blanks before keys. +[single space before key name] + keyformattest2a= No blanks in key name + key formattest2b= Single space in key name + key format test 2c= Multiple spaces in key name + key format test 2d= Multiple consecutive spaces in key name + key formattest2e= Single tab in key name + key format test 2f= Multiple tabs in key name + key format test 2g= Multiple consecutive tabs in key name + +[multiple spaces before key name] + keyformattest3a= No blanks in key name + key formattest3b= Single space in key name + key format test 3c= Multiple spaces in key name + key format test 3d= Multiple consecutive spaces in key name + key formattest3e= Single tab in key name + key format test 3f= Multiple tabs in key name + key format test 3g= Multiple consecutive tabs in key name + +[single tab before key name] + keyformattest4a= No blanks in key name + key formattest4b= Single space in key name + key format test 4c= Multiple spaces in key name + key format test 4d= Multiple consecutive spaces in key name + key formattest4e= Single tab in key name + key format test 4f= Multiple tabs in key name + key format test 4g= Multiple consecutive tabs in key name + +[multiple tabs before key name] + keyformattest5a= No blanks in key name + key formattest5b= Single space in key name + key format test 5c= Multiple spaces in key name + key format test 5d= Multiple consecutive spaces in key name + key formattest5e= Single tab in key name + key format test 5f= Multiple tabs in key name + key format test 5g= Multiple consecutive tabs in key name + +[single space after key name] +keyformattest6a = No blanks in key name +key formattest6b = Single space in key name +key format test 6c = Multiple spaces in key name +key format test 6d = Multiple consecutive spaces in key name +key formattest6e = Single tab in key name +key format test 6f = Multiple tabs in key name +key format test 6g = Multiple consecutive tabs in key name + +[multiple spaces after key name] +keyformattest7a = No blanks in key name +key formattest7b = Single space in key name +key format test 7c = Multiple spaces in key name +key format test 7d = Multiple consecutive spaces in key name +key formattest7e = Single tab in key name +key format test 7f = Multiple tabs in key name +key format test 7g = Multiple consecutive tabs in key name + +[single tab after key name] +keyformattest8a = No blanks in key name +key formattest8b = Single space in key name +key format test 8c = Multiple spaces in key name +key format test 8d = Multiple consecutive spaces in key name +key formattest8e = Single tab in key name +key format test 8f = Multiple tabs in key name +key format test 8g = Multiple consecutive tabs in key name + +[multiple tabs after key name] +keyformattest9a = No blanks in key name +key formattest9b = Single space in key name +key format test 9c= Multiple spaces in key name +key format test 9d = Multiple consecutive spaces in key name +key formattest9e = Single tab in key name +key format test 9f = Multiple tabs in key name +key format test 9g = Multiple consecutive tabs in key name + +[single space before and single space after key name] + keyformattest10a = No blanks in key name + key formattest10b = Single space in key name + key format test 10c = Multiple spaces in key name + key format test 10d = Multiple consecutive spaces in key name + key formattest10e = Single tab in key name + key format test 10f = Multiple tabs in key name + key format test 10g = Multiple consecutive tabs in key name + +[multiple spaces before and single space after key name] + keyformattest11a = No blanks in key name + key formattest11b = Single space in key name + key format test 11c = Multiple spaces in key name + key format test 11d = Multiple consecutive spaces in key name + key formattest11e = Single tab in key name + key format test 11f = Multiple tabs in key name + key format test 11g = Multiple consecutive tabs in key name + +[single tab before and single space after key name] + keyformattest12a = No blanks in key name + key formattest12b = Single space in key name + key format test 12c = Multiple spaces in key name + key format test 12d = Multiple consecutive spaces in key name + key formattest12e = Single tab in key name + key format test 12f = Multiple tabs in key name + key format test 12g = Multiple consecutive tabs in key name + +[multiple tabs before and single space after key name] + keyformattest13a = No blanks in key name + key formattest13b = Single space in key name + key format test 13c = Multiple spaces in key name + key format test 13d = Multiple consecutive spaces in key name + key formattest13e = Single tab in key name + key format test 13f = Multiple tabs in key name + key format test 13g = Multiple consecutive tabs in key name + +[single space before and multiple spaces after key name] + keyformattest14a = No blanks in key name + key formattest14b = Single space in key name + key format test 14c = Multiple spaces in key name + key format test 14d = Multiple consecutive spaces in key name + key formattest14e = Single tab in key name + key format test 14f = Multiple tabs in key name + key format test 14g = Multiple consecutive tabs in key name + +[multiple spaces before and multiple spaces after key name] + keyformattest15a = No blanks in key name + key formattest15b = Single space in key name + key format test 15c = Multiple spaces in key name + key format test 15d = Multiple consecutive spaces in key name + key formattest15e = Single tab in key name + key format test 15f = Multiple tabs in key name + key format test 15g = Multiple consecutive tabs in key name + +[single tab before and multiple spaces after key name] + keyformattest16a = No blanks in key name + key formattest16b = Single space in key name + key format test 16c = Multiple spaces in key name + key format test 16d = Multiple consecutive spaces in key name + key formattest16e = Single tab in key name + key format test 16f = Multiple tabs in key name + key format test 16g = Multiple consecutive tabs in key name + +[multiple tabs before and multiple spaces after key name] + keyformattest17a = No blanks in key name + key formattest17b = Single space in key name + key format test 17c = Multiple spaces in key name + key format test 17d = Multiple consecutive spaces in key name + key formattest17e = Single tab in key name + key format test 17f = Multiple tabs in key name + key format test 17g = Multiple consecutive tabs in key name + +[single space before and single tab after key name] + keyformattest18a = No blanks in key name + key formattest18b = Single space in key name + key format test 18c = Multiple spaces in key name + key format test 18d = Multiple consecutive spaces in key name + key formattest18e = Single tab in key name + key format test 18f = Multiple tabs in key name + key format test 18g = Multiple consecutive tabs in key name + +[multiple spaces before and single tab after key name] + keyformattest19a = No blanks in key name + key formattest19b = Single space in key name + key format test 19c = Multiple spaces in key name + key format test 19d = Multiple consecutive spaces in key name + key formattest19e = Single tab in key name + key format test 19f = Multiple tabs in key name + key format test 19g = Multiple consecutive tabs in key name + +[single tab before and single tab after key name] + keyformattest20a = No blanks in key name + key formattest20b = Single space in key name + key format test 20c = Multiple spaces in key name + key format test 20d = Multiple consecutive spaces in key name + key formattest20e = Single tab in key name + key format test 20f = Multiple tabs in key name + key format test 20g = Multiple consecutive tabs in key name + +[multiple tabs before and single tab after key name] + keyformattest21a = No blanks in key name + key formattest21b = Single space in key name + key format test 21c = Multiple spaces in key name + key format test 21d = Multiple consecutive spaces in key name + key formattest21e = Single tab in key name + key format test 21f = Multiple tabs in key name + key format test 21g = Multiple consecutive tabs in key name + +[single space before and multiple tabs after key name] + keyformattest22a = No blanks in key name + key formattest22b = Single space in key name + key format test 22c = Multiple spaces in key name + key format test 22d = Multiple consecutive spaces in key name + key formattest22e = Single tab in key name + key format test 22f = Multiple tabs in key name + key format test 22g = Multiple consecutive tabs in key name + +[multiple spaces before and multiple tabs after key name] + keyformattest23a = No blanks in key name + key formattest23b = Single space in key name + key format test 23c = Multiple spaces in key name + key format test 23d = Multiple consecutive spaces in key name + key formattest23e = Single tab in key name + key format test 23f = Multiple tabs in key name + key format test 23g = Multiple consecutive tabs in key name + +[single tab before and miltiple tabs after key name] + keyformattest24a = No blanks in key name + key formattest24b = Single space in key name + key format test 24c = Multiple spaces in key name + key format test 24d = Multiple consecutive spaces in key name + key formattest24e = Single tab in key name + key format test 24f = Multiple tabs in key name + key format test 24g = Multiple consecutive tabs in key name + +[multiple tabs before and multiple tabs after key name] + keyformattest25a = No blanks in key name + key formattest25b = Single space in key name + key format test 25c = Multiple spaces in key name + key format test 25d = Multiple consecutive spaces in key name + key formattest25e = Single tab in key name + key format test 25f = Multiple tabs in key name + key format test 25g = Multiple consecutive tabs in key name + + +[random mixture blanks before and single space after key name] + keyformattest26a = No blanks in key name + key formattest26b = Single space in key name + key format test 26c = Multiple spaces in key name + key format test 26d = Multiple consecutive spaces in key name + key formattest26e = Single tab in key name + key format test 26f = Multiple tabs in key name + key format test 26g = Multiple consecutive tabs in key name + +[random mixture blanks before and multiple spaces after key name] + keyformattest27a = No blanks in key name + key formattest27b = Single space in key name + key format test 27c = Multiple spaces in key name + key format test 27d = Multiple consecutive spaces in key name + key formattest27e = Single tab in key name + key format test 27f = Multiple tabs in key name + key format test 27g = Multiple consecutive tabs in key name + +[random mixture blanks before and single tab after key name] + keyformattest28a = No blanks in key name + key formattest28b = Single space in key name + key format test 28c = Multiple spaces in key name + key format test 28d = Multiple consecutive spaces in key name + key formattest28e = Single tab in key name + key format test 28f = Multiple tabs in key name + key format test 28g = Multiple consecutive tabs in key name + +[random mixture blanks before and multiple tabs after key name] + keyformattest29a = No blanks in key name + key formattest29b = Single space in key name + key format test 29c = Multiple spaces in key name + key format test 29d = Multiple consecutive spaces in key name + key formattest29e = Single tab in key name + key format test 29f = Multiple tabs in key name + key format test 29g = Multiple consecutive tabs in key name + + +[single space before and random mixture blanks after key name] + keyformattest30a = No blanks in key name + key formattest30b = Single space in key name + key format test 30c = Multiple spaces in key name + key format test 30d = Multiple consecutive spaces in key name + key formattest30e = Single tab in key name + key format test 30f = Multiple tabs in key name + key format test 30g = Multiple consecutive tabs in key name + +[multiple spaces before and random mixture blanks after key name] + keyformattest31a = No blanks in key name + key formattest31b = Single space in key name + key format test 31c = Multiple spaces in key name + key format test 31d = Multiple consecutive spaces in key name + key formattest31e = Single tab in key name + key format test 31f = Multiple tabs in key name + key format test 31g = Multiple consecutive tabs in key name + +[single tab before and random mixture blanks after key name] + keyformattest32a = No blanks in key name + key formattest32b = Single space in key name + key format test 32c = Multiple spaces in key name + key format test 32d = Multiple consecutive spaces in key name + key formattest32e = Single tab in key name + key format test 32f = Multiple tabs in key name + key format test 32g = Multiple consecutive tabs in key name + +[multiple tabs before and random mixture blanks after key name] + keyformattest33a = No blanks in key name + key formattest33b = Single space in key name + key format test 33c = Multiple spaces in key name + key format test 33d = Multiple consecutive spaces in key name + key formattest33e = Single tab in key name + key format test 33f = Multiple tabs in key name + key format test 33g = Multiple consecutive tabs in key name + +[random mixture blanks before and after key name] + keyformattest34a = No blanks in key name + key formattest34b = Single space in key name + key format test 34c = Multiple spaces in key name + key format test 34d = Multiple consecutive spaces in key name + key formattest34e = Single tab in key name + key format test 34f = Multiple tabs in key name + key format test 34g = Multiple consecutive tabs in key name diff --git a/bits/other-peoples/inifile.bash b/bits/other-peoples/inifile.bash new file mode 100644 index 0000000..28afec2 --- /dev/null +++ b/bits/other-peoples/inifile.bash @@ -0,0 +1,234 @@ +#!@BASH_PATH@ +# Author: Jack L. Frost +# Licensed under the Internet Software Consortium (ISC) license. +# See LICENSE for its text. + +_self="${0##*/}" + +err() { printf '%s\n' "$*" >&2; } + +debug() { + (( $flag_debug )) && { printf '%s\n' "DEBUG: $*"; } +} + +usage() { + while read; do printf '%s\n' "$REPLY"; done <<- EOF + Usage: $_self [flags] + Flags: + -h|--help Show this message. + -c|--config Use a config specified by . + -d|--debug Enable debug messages. + EOF +} + +cfg_load() { + declare section line key value + declare -g -A cfg + + mapfile -t config < "$1" + + for line in "${config[@]}"; do + if [[ "$line" =~ ^\[.+\] ]]; then + section="${line//[\[\]]/}" + + case "$section" in + main) :;; + *) ifaces+=( "${line//[\[\]]/}" );; + esac + elif [[ "$line" =~ ^('#'|\s+?$) ]]; then + : + else + IFS='=' read -r key value <<< "$line" + + if ! [[ "$section" ]]; then + err "Key $key does not belong to a section!" + return 1 + fi + + if [[ "$key" ]]; then + if ! [[ "$value" ]]; then + value=1 + fi + + if [[ ${cfg[${section}_$key]} ]]; then + declare -g cfg["${section}_$key"]="${cfg[${section}_$key]}#${value}" + else + declare -g cfg["${section}_$key"]="$value" + fi + fi + fi + done +} + +net_up() { + for iface in "${ifaces[@]}"; do + # Prepare the interface + if [[ "${cfg[${iface}_preup]}" ]]; then + ${cfg[${iface}_preup]} + fi + + # Bring the interface up + if [[ "${cfg[${iface}_up]}" ]]; then + ${cfg[${iface}_up]} + else + if [[ "${cfg[${iface}_vlan_dev]}" ]]; then + ip link add link "${cfg[${iface}_vlan_dev]}" name "$iface" type vlan id "${cfg[${iface}_vlan_id]}" + fi + + ip link set "$iface" up + fi + + # Add IPs + if [[ "${cfg[${iface}_ip]}" ]]; then + IFS='#' read -r -a ips <<< "${cfg[${iface}_ip]}" + + for a in "${ips[@]}"; do + ip addr add "$a" dev "$iface" + done + fi + + # Configure the interface with dhcp if needed + if [[ "${cfg[${iface}_dhcp]}" ]]; then + ${cfg[main_dhcp_up]} "$iface" + fi + + # Add routes + if [[ "${cfg[${iface}_route]}" ]]; then + IFS='#' read -r -a routes <<< "${cfg[${iface}_route]}" + + for r in "${routes[@]}"; do + read -r net gw <<< "$r" + + ip route add "$net" via "$gw" + done + fi + + if [[ "${cfg[${iface}_postup]}" ]]; then + ${cfg[${iface}_up]} + fi + done +} + +net_down() { + for iface in "${ifaces[@]}"; do + # Prepare the interface + if [[ "${cfg[${iface}_predown]}" ]]; then + ${cfg[${iface}_predown]} + fi + + # Remove routes + if [[ "${cfg[${iface}_route]}" ]]; then + IFS='#' read -r -a routes <<< "${cfg[${iface}_route]}" + + for r in "${routes[@]}"; do + read -r net gw <<< "$r" + + ip route del "$net" via "$gw" + done + fi + + # Stop dhcpcd + if [[ "${cfg[${iface}_dhcp]}" ]]; then + ${cfg[main_dhcp_down]} "$iface" + fi + + # Remove IPs + if [[ "${cfg[${iface}_ip]}" ]]; then + IFS='#' read -r -a ips <<< "${cfg[${iface}_ip]}" + + for a in "${ips[@]}"; do + ip addr del "$a" dev "$iface" + done + fi + + # Bring the interface down + if [[ "${cfg[${iface}_down]}" ]]; then + ${cfg[${iface}_down]} + else + ip link set "$iface" down + + if [[ "${cfg[${iface}_vlan_dev]}" ]]; then + ip link del "$iface" + fi + fi + + if [[ "${cfg[${iface}_postdown]}" ]]; then + ${cfg[${iface}_postdown]} + fi + done +} + +set_argv() { + declare arg opt c + declare -g argv + + while (( $# )); do + unset -v arg opt c + + case "$1" in + (--) argv+=( "$1" ); break;; + + (--*) + IFS='=' read arg opt <<< "$1" + argv+=( "$arg" ) + + [[ "$opt" ]] && { + argv+=( "$opt" ) + } + ;; + + (-*) + while read -n1 c + do + case "$c" in + -|'') :;; + *) argv+=( "-$c" );; + esac + done <<< "$1" + ;; + + (*) argv+=( "$1" );; + esac + shift + done +} + +main() { + while (( $# )); do + case "$1" in + -h|--help) usage; return 0;; + -d|--debug) + flag_debug=1 + debug "Debug flag set." + ;; + -c|--config) cfg_file="$2"; shift;; + + --) shift; break;; + -*) + err "Unknown key: $1" + usage + return 1 + ;; + *) break;; + esac + shift + done + + if ! [[ "$cfg_file" ]]; then + cfg_file='@CONFDIR@/networking' + fi + + cfg_load "$cfg_file" || { + return "$?" + } + + action=${1:-"up"} + + case "$action" in + up) net_up;; + down) net_down;; + esac +} + +set_argv "$@" +main "${argv[@]}" diff --git a/bits/other-peoples/sites b/bits/other-peoples/sites new file mode 100644 index 0000000..c8e08c8 --- /dev/null +++ b/bits/other-peoples/sites @@ -0,0 +1,3 @@ +https://ajdiaz.wordpress.com/2008/02/09/bash-ini-parser/ +https://github.com/rudimeier/bash_ini_parser + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/README b/bits/other-peoples/someone_elses_bash_ini_parser/README new file mode 100644 index 0000000..afe71ab --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/README @@ -0,0 +1,118 @@ + +bash_ini_parser -- Simple INI file parser +========================================= + +This is a comfortable and simple INI file parser to be used in +bash scripts. + + + + +COPYRIGHT +--------- + +Copyright (c) 2009 Kevin Porter / Advanced Web Construction Ltd +(http://coding.tinternet.info / http://webutils.co.uk) +Copyright (c) 2010, 2011 Ruediger Meier +(https://github.com/rudimeier/) + + + + +USAGE +----- + +You must source the bash file into your script: + +> . read_ini.sh + +and then use the read_ini function, defined as: + +> read_ini INI_FILE [SECTION] [[--prefix|-p] PREFIX] [[--booleans|b] [0|1]] + +If SECTION is supplied, then only the specified section of the file will +be processed. + +After running the read_ini function, variables corresponding to the ini +file entries will be available to you. Naming convention for variable +names is: + +PREFIX__SECTION__VARNAME + +PREFIX is 'INI' by default (but can be changed with the --prefix option), +SECTION and VARNAME are the section name and variable name respectively. +For example, to read and output the variables of this ini file: + +-- START test1.ini file + +var1="VAR 1" +var2 = VAR 2 + +[section1] +var1="section1 VAR 1" +var2= section1 VAR 2 + + +-- END test1.ini file + +you could do this: + +-- START bash script + +. read_ini.sh + +read_ini test1.ini + +echo "var1 = ${INI__var1}" +echo "var2 = ${INI__var2}" +echo "section1 var1 = ${INI__section1__var1}" +echo "section1 var2 = ${INI__section1__var2}" + +-- END bash script + + + + +OPTIONS +------- + +[--prefix | -p] PREFIX +String to prepend to generated variable names (automatically followed by '__'). +Default: INI + +[--booleans | -b] [0|1] +Whether to interpret special unquoted string values 'yes', 'no', 'true', +'false', 'on', 'off' as booleans. +Default: 1 + + + + +INI FILE FORMAT +--------------- + +- Variables are stored as name/value pairs, eg: +var=value + +- Leading and trailing whitespace of the name and the value is discarded. + +- Use double or single quotes to get whitespace in the values + +- Section names in square brackets, eg: +[section1] +var1 = value + +- Variable names can be re-used between sections (or out of section), eg: +var1=value +[section1] +var1=value +[section3] +var1=value + +- Dots are converted to underscores in all variable names. + +- Special boolean values: unquoted strings 'yes', 'true' and 'on' are interpreted + as 1; 'no', 'false' and 'off' are interpreted as 0 + + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/TODO b/bits/other-peoples/someone_elses_bash_ini_parser/TODO new file mode 100644 index 0000000..9c47317 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/TODO @@ -0,0 +1,7 @@ + + +- Tabs/newlines to be preserved + +- [] notation for arrays (like PHP's parse_ini_file()) + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/read_ini.sh b/bits/other-peoples/someone_elses_bash_ini_parser/read_ini.sh new file mode 100755 index 0000000..44eccb7 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/read_ini.sh @@ -0,0 +1,272 @@ +# +# Copyright (c) 2009 Kevin Porter / Advanced Web Construction Ltd +# (http://coding.tinternet.info, http://webutils.co.uk) +# Copyright (c) 2010, 2011 Ruediger Meier +# (https://github.com/rudimeier/) +# +# Simple INI file parser. +# +# See README for usage. +# +# + + + + +function read_ini() +{ + # Be strict with the prefix, since it's going to be run through eval + function check_prefix() + { + if ! [[ "${VARNAME_PREFIX}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] ;then + echo "read_ini: invalid prefix '${VARNAME_PREFIX}'" >&2 + return 1 + fi + } + + function check_ini_file() + { + if [ ! -r "$INI_FILE" ] ;then + echo "read_ini: '${INI_FILE}' doesn't exist or not" \ + "readable" >&2 + return 1 + fi + } + + # enable some optional shell behavior (shopt) + function pollute_bash() + { + if ! shopt -q extglob ;then + SWITCH_SHOPT="${SWITCH_SHOPT} extglob" + fi + if ! shopt -q nocasematch ;then + SWITCH_SHOPT="${SWITCH_SHOPT} nocasematch" + fi + shopt -q -s ${SWITCH_SHOPT} + } + + # unset all local functions and restore shopt settings before returning + # from read_ini() + function cleanup_bash() + { + shopt -q -u ${SWITCH_SHOPT} + unset -f check_prefix check_ini_file pollute_bash cleanup_bash + } + + local INI_FILE="" + local INI_SECTION="" + + # {{{ START Deal with command line args + + # Set defaults + local BOOLEANS=1 + local VARNAME_PREFIX=INI + local CLEAN_ENV=0 + + # {{{ START Options + + # Available options: + # --boolean Whether to recognise special boolean values: ie for 'yes', 'true' + # and 'on' return 1; for 'no', 'false' and 'off' return 0. Quoted + # values will be left as strings + # Default: on + # + # --prefix=STRING String to begin all returned variables with (followed by '__'). + # Default: INI + # + # First non-option arg is filename, second is section name + + while [ $# -gt 0 ] + do + + case $1 in + + --clean | -c ) + CLEAN_ENV=1 + ;; + + --booleans | -b ) + shift + BOOLEANS=$1 + ;; + + --prefix | -p ) + shift + VARNAME_PREFIX=$1 + ;; + + * ) + if [ -z "$INI_FILE" ] + then + INI_FILE=$1 + else + if [ -z "$INI_SECTION" ] + then + INI_SECTION=$1 + fi + fi + ;; + + esac + + shift + done + + if [ -z "$INI_FILE" ] && [ "${CLEAN_ENV}" = 0 ] ;then + echo -e "Usage: read_ini [-c] [-b 0| -b 1]] [-p PREFIX] FILE"\ + "[SECTION]\n or read_ini -c [-p PREFIX]" >&2 + cleanup_bash + return 1 + fi + + if ! check_prefix ;then + cleanup_bash + return 1 + fi + + local INI_ALL_VARNAME="${VARNAME_PREFIX}__ALL_VARS" + if [ "${CLEAN_ENV}" = 1 ] ;then + eval unset "\$${INI_ALL_VARNAME}" + fi + unset ${INI_ALL_VARNAME} + + if [ -z "$INI_FILE" ] ;then + cleanup_bash + return 0 + fi + + if ! check_ini_file ;then + cleanup_bash + return 1 + fi + + # Sanitise BOOLEANS - interpret "0" as 0, anything else as 1 + if [ "$BOOLEANS" != "0" ] + then + BOOLEANS=1 + fi + + + # }}} END Options + + # }}} END Deal with command line args + + local LINE_NUM=0 + local SECTION="" + + # IFS is used in "read" and we want to switch it within the loop + local IFS=$' \t\n' + local IFS_OLD="${IFS}" + + # we need some optional shell behavior (shopt) but want to restore + # current settings before returning + local SWITCH_SHOPT="" + pollute_bash + + while read -r line + do +#echo line = "$line" + + ((LINE_NUM++)) + + # Skip blank lines and comments + if [ -z "$line" -o "${line:0:1}" = ";" -o "${line:0:1}" = "#" ] + then + continue + fi + + # Section marker? + if [[ "${line}" =~ ^\[[a-zA-Z0-9_]{1,}\]$ ]] + then + + # Set SECTION var to name of section (strip [ and ] from section marker) + SECTION="${line#[}" + SECTION="${SECTION%]}" + + continue + fi + + # Are we getting only a specific section? And are we currently in it? + if [ ! -z "$INI_SECTION" ] + then + if [ "$SECTION" != "$INI_SECTION" ] + then + continue + fi + fi + + # Valid var/value line? (check for variable name and then '=') + if ! [[ "${line}" =~ ^[a-zA-Z0-9._]{1,}[[:space:]]*= ]] + then + echo "Error: Invalid line:" >&2 + echo " ${LINE_NUM}: $line" >&2 + cleanup_bash + return 1 + fi + + + # split line at "=" sign + IFS="=" + read -r VAR VAL <<< "${line}" + IFS="${IFS_OLD}" + + # delete spaces around the equal sign (using extglob) + VAR="${VAR%%+([[:space:]])}" + VAL="${VAL##+([[:space:]])}" + VAR=$(echo $VAR) + + + # Construct variable name: + # ${VARNAME_PREFIX}__$SECTION__$VAR + # Or if not in a section: + # ${VARNAME_PREFIX}__$VAR + # In both cases, full stops ('.') are replaced with underscores ('_') + if [ -z "$SECTION" ] + then + VARNAME=${VARNAME_PREFIX}__${VAR//./_} + else + VARNAME=${VARNAME_PREFIX}__${SECTION}__${VAR//./_} + fi + eval "${INI_ALL_VARNAME}=\"\$${INI_ALL_VARNAME} ${VARNAME}\"" + + if [[ "${VAL}" =~ ^\".*\"$ ]] + then + # remove existing double quotes + VAL="${VAL##\"}" + VAL="${VAL%%\"}" + elif [[ "${VAL}" =~ ^\'.*\'$ ]] + then + # remove existing single quotes + VAL="${VAL##\'}" + VAL="${VAL%%\'}" + elif [ "$BOOLEANS" = 1 ] + then + # Value is not enclosed in quotes + # Booleans processing is switched on, check for special boolean + # values and convert + + # here we compare case insensitive because + # "shopt nocasematch" + case "$VAL" in + yes | true | on ) + VAL=1 + ;; + no | false | off ) + VAL=0 + ;; + esac + fi + + + # enclose the value in single quotes and escape any + # single quotes and backslashes that may be in the value + VAL="${VAL//\\/\\\\}" + VAL="\$'${VAL//\'/\'}'" + + eval "$VARNAME=$VAL" + done <"${INI_FILE}" + + cleanup_bash +} + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test.sh new file mode 100755 index 0000000..99541b7 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test.sh @@ -0,0 +1,28 @@ + +DIR=$(dirname $0) +cd $DIR + +TESTS=$(ls test*.sh | grep -v test.sh | sed 's/\.sh$//') + +for test in $TESTS +do + + bash $test.sh &> $test.out +# bash $test.sh >$test.out 2>$test.err + + # Fail and bail out if test didn't pass + PASSED=$(diff $test.out $test.out.correct 2>&1) + if [ ! -z "$PASSED" ] + then + echo "Test $test failed. Output is in $DIR/$test.out" + exit 1 + else + rm -rf $test.out + fi + +done + + +echo "All tests passed" + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.ini new file mode 100644 index 0000000..ebb5536 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.ini @@ -0,0 +1,40 @@ + +; Comment beginning with ';' +# Comment beginning with '#' + +; var1 - simple var +var1=VAR 1 + +; var2 - space before '='; leading space that should be stripped +var2 = VAR 2 + +; var3 - with leading and trailing space that should be stripped +var3 = VAR 3 + +; var4 - value in double quotes +var4="VAR 4" + +; var5 - value in double quotes; value's leading and trailing whitespace should +; be preserved; leading and trailing whitespace before/after double quotes should +; not become part of the value +var5 = " VAR 5 " + +; var6 - value in double quotes; value's leading and trailing whitespace should +; be preserved; leading and trailing whitespace before/after double quotes should +; not become part of the value +var6 = ' VAR 6 ' + +; var7 - value contains a single double quote +var7 = VAR " 7 + +; var8 - value contains a single single quote +var8 = VAR ' 8 + +; var9 - leading whitespace before variable name + var9=VAR 9 + +; var10 - leading whitespace before variable name + var10 = VAR 10 + + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.out.correct new file mode 100644 index 0000000..fbd3d90 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.out.correct @@ -0,0 +1,10 @@ +var1:VAR 1 +var2:VAR 2 +var3:VAR 3 +var4:VAR 4 +var5: VAR 5 +var6: VAR 6 +var7:VAR " 7 +var8:VAR ' 8 +var9:VAR 9 +var10:VAR 10 diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.sh new file mode 100755 index 0000000..0503f70 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test1.sh @@ -0,0 +1,21 @@ + + +# Test 1 +# +# Basic variable values; leading/trailing whitespace; comments + +. ../read_ini.sh +read_ini test1.ini + +#echo "a:LOCALVAR=$LOCALVAR" +echo "var1:$INI__var1" +echo "var2:$INI__var2" +echo "var3:$INI__var3" +echo "var4:$INI__var4" +echo "var5:$INI__var5" +echo "var6:$INI__var6" +echo "var7:$INI__var7" +echo "var8:$INI__var8" +echo "var9:$INI__var9" +echo "var10:$INI__var10" + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.ini new file mode 100644 index 0000000..bd4e24d --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.ini @@ -0,0 +1,8 @@ + + +var1=VAR1 + +; Invalid line - should throw an error and stop processing +INVALID LINE +var2=VAR2 + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.out.correct new file mode 100644 index 0000000..426532a --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.out.correct @@ -0,0 +1,2 @@ +Error: Invalid line: + 6: INVALID LINE diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.sh new file mode 100755 index 0000000..2fe34cb --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test2.sh @@ -0,0 +1,8 @@ + +# Test 2 +# +# Invalid line + +. ../read_ini.sh +read_ini test2.ini + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.ini new file mode 100644 index 0000000..406947d --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.ini @@ -0,0 +1,23 @@ + +; Testing sections + +var1=VAR 1 +var2= "VAR 2 " + +[section1] +var1="section 1 VAR 1" +var2= "section 1 VAR 2" +var3 = "section 1 VAR 3 " + +[section2] +var1 = section 2 VAR 1 +var2=" section 2 VAR 2" +var3=section 2 VAR 3 +var4=section 2 VAR 4 +var5=section 2 VAR 5 + +[section3] +var1="section 3 VAR 1" +var2= "section 3 VAR 2" + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.out.correct new file mode 100644 index 0000000..08f0d67 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.out.correct @@ -0,0 +1,12 @@ +var1:VAR 1 +var2:VAR 2 +setion1_var1:section 1 VAR 1 +setion1_var2:section 1 VAR 2 +setion1_var3:section 1 VAR 3 +setion2_var1:section 2 VAR 1 +setion2_var2: section 2 VAR 2 +setion2_var3:section 2 VAR 3 +setion2_var4:section 2 VAR 4 +setion2_var5:section 2 VAR 5 +setion3_var1:section 3 VAR 1 +setion3_var2:section 3 VAR 2 diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.sh new file mode 100755 index 0000000..afc2e70 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test3.sh @@ -0,0 +1,25 @@ + +# Test 3 +# +# Sections + +. ../read_ini.sh +read_ini test3.ini + +echo "var1:$INI__var1" +echo "var2:$INI__var2" + +echo "setion1_var1:$INI__section1__var1" +echo "setion1_var2:$INI__section1__var2" +echo "setion1_var3:$INI__section1__var3" + +echo "setion2_var1:$INI__section2__var1" +echo "setion2_var2:$INI__section2__var2" +echo "setion2_var3:$INI__section2__var3" +echo "setion2_var4:$INI__section2__var4" +echo "setion2_var5:$INI__section2__var5" + +echo "setion3_var1:$INI__section3__var1" +echo "setion3_var2:$INI__section3__var2" + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.ini new file mode 100644 index 0000000..99b4e85 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.ini @@ -0,0 +1,14 @@ + +; Testing dots in variable names (these get converted to underscores in +; output variable names) + +var.1 = "VAR 1" +var.two="VAR 2" +var.3.two_dots="VAR 3" + + +[section1] +var.1="section 1 VAR 1" +var.two="section 1 VAR 2" + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.out.correct new file mode 100644 index 0000000..2c2264d --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.out.correct @@ -0,0 +1,5 @@ +var_1:VAR 1 +var_two:VAR 2 +var_3_two_dots:VAR 3 +section 1 var_1:section 1 VAR 1 +section 1 var_two:section 1 VAR 2 diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.sh new file mode 100755 index 0000000..5c12e6d --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test4.sh @@ -0,0 +1,15 @@ + +# Test 4 +# +# Dots in variable names (converted to underscores in output var names) + +. ../read_ini.sh +read_ini test4.ini + +echo "var_1:$INI__var_1" +echo "var_two:$INI__var_two" +echo "var_3_two_dots:$INI__var_3_two_dots" + +echo "section 1 var_1:$INI__section1__var_1" +echo "section 1 var_two:$INI__section1__var_two" + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.ini new file mode 100644 index 0000000..d780a0a --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.ini @@ -0,0 +1,13 @@ + +; Testing prevention of in-value code execution via eval +var1 = blah blah `ls` blah +var2 = blah blah $(ls) blah + +; these code injections worked on 0.3 +var3 = blah blah \\`ls\\` blah +var4 = blah blah \\$(ls) blah + +; these code injections could work with read -r +var5 = blah blah \`ls\` blah +var6 = blah blah \$(ls) blah + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.out.correct new file mode 100644 index 0000000..8fba6af --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.out.correct @@ -0,0 +1,6 @@ +var1:blah blah `ls` blah +var2:blah blah $(ls) blah +var3:blah blah \\`ls\\` blah +var4:blah blah \\$(ls) blah +var5:blah blah \`ls\` blah +var6:blah blah \$(ls) blah diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.sh new file mode 100755 index 0000000..9f3eb76 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test5.sh @@ -0,0 +1,16 @@ + + +# Test 5 +# +# Prevention of in-value code execution via backticks or $() notation. +# This must be done because the value is run through an eval statement. + +. ../read_ini.sh +read_ini test5.ini + +echo "var1:$INI__var1" +echo "var2:$INI__var2" +echo "var3:$INI__var3" +echo "var4:$INI__var4" +echo "var5:$INI__var5" +echo "var6:$INI__var6" diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.ini new file mode 100644 index 0000000..f8adc21 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.ini @@ -0,0 +1,27 @@ + + +; Testing processing of special boolean constants: unquoted +; strings 'yes', 'true' and 'on' are interpreted as 1; +; unquoted strings 'no', 'false' and 'off' as 0. + +yes1 = yes +yes2 = "yes" +yes3 = Yes +true1=true +true2= true +true3 = "tRuE" +on1 = on +on2 = oN +on3 = "ON" + +no1 = no +no2 = "no" +no3=No +false1 = false +false2 = faLSe +false3 = "FALSE" +off1 = off +off2 = Off +off3 = "off" + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.out.correct new file mode 100644 index 0000000..07d4e7d --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.out.correct @@ -0,0 +1,30 @@ +yes1:1 +yes2:yes +yes3:1 +true1:1 +true2:1 +true3:tRuE +on1:1 +on2:1 +on3:ON +no1:0 +no2:no +no3:0 +false1:0 +false2:0 +false3:FALSE +off1:0 +off2:0 +off3:off +yes1:1 +true2:1 +on3:ON +no3:0 +false2:0 +off1:0 +yes1:yes +true2:true +on3:ON +no3:No +false2:faLSe +off1:off diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.sh new file mode 100755 index 0000000..29cfc4c --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test6.sh @@ -0,0 +1,56 @@ + +# Testing booleans processing + +# First: with default booleans processing (on) +. ../read_ini.sh +read_ini test6.ini + +echo "yes1:$INI__yes1" +echo "yes2:$INI__yes2" +echo "yes3:$INI__yes3" +echo "true1:$INI__true1" +echo "true2:$INI__true2" +echo "true3:$INI__true3" +echo "on1:$INI__on1" +echo "on2:$INI__on2" +echo "on3:$INI__on3" + +echo "no1:$INI__no1" +echo "no2:$INI__no2" +echo "no3:$INI__no3" +echo "false1:$INI__false1" +echo "false2:$INI__false2" +echo "false3:$INI__false3" +echo "off1:$INI__off1" +echo "off2:$INI__off2" +echo "off3:$INI__off3" + + +# Second: with booleans processing explicitly turned on via "--booleans 1" +. ../read_ini.sh +read_ini --booleans 1 test6.ini + +echo "yes1:$INI__yes1" +echo "true2:$INI__true2" +echo "on3:$INI__on3" + +echo "no3:$INI__no3" +echo "false2:$INI__false2" +echo "off1:$INI__off1" + + +# Third: with booleans processing explicity switched off via "--booleans 0" +. ../read_ini.sh +read_ini test6.ini --booleans 0 + +echo "yes1:$INI__yes1" +echo "true2:$INI__true2" +echo "on3:$INI__on3" + +echo "no3:$INI__no3" +echo "false2:$INI__false2" +echo "off1:$INI__off1" + + + + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.ini new file mode 100644 index 0000000..2532342 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.ini @@ -0,0 +1,8 @@ + +; Simple definitions for testing --prefix option + +var1=VAR 1 + +[section1] +var1 = "section 1 VAR 1" + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.out.correct new file mode 100644 index 0000000..6c1bc65 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.out.correct @@ -0,0 +1,7 @@ +# 1 +var1:VAR 1 +section1 var1:section 1 VAR 1 +# 2 +read_ini: invalid prefix 'PR:EFIX,' +# 3 +read_ini: invalid prefix '1PREFIX' diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.sh new file mode 100755 index 0000000..878adac --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test7.sh @@ -0,0 +1,30 @@ + +# Test 7 +# +# Option: [--prefix | -p] PREFIX + +# First: valid value for prefix +echo "# 1" +. ../read_ini.sh +read_ini test7.ini --prefix PREFIX1 + +echo "var1:$PREFIX1__var1" +echo "section1 var1:$PREFIX1__section1__var1" + +# Second: invalid value for prefix (contains illegal chars) +echo "# 2" +. ../read_ini.sh +read_ini -p PR:EFIX, test7.ini && +{ + echo "var1:$PREFIX1__var1" + echo "section1 var1:$PREFIX1__section1__var1" +} + +# Third: invalid value for prefix (begins with a number) +echo "# 3" +. ../read_ini.sh +read_ini --prefix 1PREFIX test7.ini && +{ + echo "var1:$PREFIX1__var1" + echo "section1 var1:$PREFIX1__section1__var1" +} diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.ini new file mode 100644 index 0000000..32f9b3a --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.ini @@ -0,0 +1,4 @@ + +; this code injection via section worked on 0.3 +[x=blah; ls ;] +var1 = blah diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.out.correct new file mode 100644 index 0000000..c79ef3a --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.out.correct @@ -0,0 +1,2 @@ +Error: Invalid line: + 3: [x=blah; ls ;] diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.sh new file mode 100755 index 0000000..782f6b0 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test8.sh @@ -0,0 +1,9 @@ + + +# Test 8 +# +# Prevention of in-value code execution via invalid section + +. ../read_ini.sh +read_ini test8.ini + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.ini b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.ini new file mode 100644 index 0000000..9a8c271 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.ini @@ -0,0 +1,12 @@ + +; Testing quoted quotes (didnt't worked in 0.3) + +; code injection +var1="" ls "." +var2='' ls '.' + +; or just an error: unexpected EOF while looking for matching `"' +var3=""" +var4=''' +var5=" +var6=' diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.out.correct b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.out.correct new file mode 100644 index 0000000..1690de2 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.out.correct @@ -0,0 +1,6 @@ +var1:" ls ". +var2:' ls '. +var3:" +var4:' +var5:" +var6:' diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.sh b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.sh new file mode 100755 index 0000000..91e79e2 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/test/test9.sh @@ -0,0 +1,16 @@ + +# Test 9 +# +# further stuff which didn't worked in 0.3 + +. ../read_ini.sh +if ! read_ini test9.ini ;then exit 1; fi + + +echo "var1:$INI__var1" +echo "var2:$INI__var2" +echo "var3:$INI__var3" +echo "var4:$INI__var4" +echo "var5:$INI__var5" +echo "var6:$INI__var6" + diff --git a/bits/other-peoples/someone_elses_bash_ini_parser/url b/bits/other-peoples/someone_elses_bash_ini_parser/url new file mode 100644 index 0000000..4d39e04 --- /dev/null +++ b/bits/other-peoples/someone_elses_bash_ini_parser/url @@ -0,0 +1 @@ +https://github.com/rudimeier/bash_ini_parser diff --git a/bits/quotes-sed.sh b/bits/quotes-sed.sh new file mode 100644 index 0000000..15a92d4 --- /dev/null +++ b/bits/quotes-sed.sh @@ -0,0 +1,34 @@ +{ echo "keyname1 = line without quotes" + echo "keyname2 = line with 1 \" double quote" + echo "keyname3 = line with \" 2 double \" quotes" + echo "keyname4 = line \\" + echo "with continuation \\" + echo "at end" + echo "keyname5 = \"double quoted text, single line\"" + echo "keyname6 = 'single quoted text, single line'" + echo "keyname7 = \"double quoted text" + echo "over 1" + echo "2" + echo "3" + echo "4 \""; } | + sed -re "{ + # Insert [ at beginning of key + s/^[[:blank:]]*/['/ + # Insert ] at end of key + s/[[:blank:]]*=/']=/ + # Branch if there's a = ... + /^.*[^\\]=[[:blank:]]*['\"]/ { +p + :x + # Branch if there is no at end of line ... + /.*['\"][[:blank:]]*\$/ ! { + # Read new line + N + # Insert a \n + s/\\\n// + # Continue loop if s/ above was successful + tx + } + } + s/(^|$)/#/g +}" diff --git a/bits/readline/readline b/bits/readline/readline new file mode 100755 index 0000000..26524c7 --- /dev/null +++ b/bits/readline/readline @@ -0,0 +1,76 @@ +#!/bin/bash + +shopt -s extglob + +exec {FD} = <%s>\n" "$KEY" "$VALUE" + + unset FOO + declare -A FOO + FOO["$KEY"]=$VALUE +printf "%s\n" "$(key2value "$KEY")" + +# printf "%q\n" "$VALUE" +# declare -p FOO + echo +done + + + + +# FOO="test1 = test2 = test3" +# KEY="${FOO%%=*}" +# VALUE="${FOO#*=}" diff --git a/bits/readline/readline.ini b/bits/readline/readline.ini new file mode 100644 index 0000000..5321ffa --- /dev/null +++ b/bits/readline/readline.ini @@ -0,0 +1,18 @@ +# test +; test + # test + ; test + foo = This is a line with \ +a backslash \ +# foo +\ + +#bar = This is a line without a backslash + +#baz = " This is a = \ +# line in \ +#quotes " + +foo = 'Test \' $BASH_SOURCE' +bar = "Test 2 ' \"" +#foof = This is $BASH_SOURCE line without quotes diff --git a/bits/sanatise_section/sanatise_section b/bits/sanatise_section/sanatise_section new file mode 100755 index 0000000..b4dc322 --- /dev/null +++ b/bits/sanatise_section/sanatise_section @@ -0,0 +1,23 @@ +#!/bin/bash + +INIFILE=sanatise_section.ini + + + if ! exec 10<"$INIFILE"; then + echo "${0##*/}: $INIFILE: failed to open" + return 1 + fi + + shopt -s extglob + + # Parse the ini file + IFS=$'\n' + BUFFER="" + while :; do + # Read a line of input from the file descriptor + read -u 10 LINE || break +# printf -- "->%s<-\n" "$LINE" + LINE="${LINE/#*([[:blank:]])\[*([[:blank:]])/}" + LINE="${LINE/%*([[:blank:]])\]*([[:blank:]])/}" + printf -- "->%s<-\n" "$LINE" + done diff --git a/bits/sanatise_section/sanatise_section.ini b/bits/sanatise_section/sanatise_section.ini new file mode 100644 index 0000000..5f11f0f --- /dev/null +++ b/bits/sanatise_section/sanatise_section.ini @@ -0,0 +1,8 @@ + [test 1] + [ test 2] + [ test 3 ] + [ test 4 ] + [ test 5 ] +[ test 6 ] +[ test 7 ] +[test 8] diff --git a/bits/sed-parser/sed-parser-simplified.sh b/bits/sed-parser/sed-parser-simplified.sh new file mode 100644 index 0000000..f21329b --- /dev/null +++ b/bits/sed-parser/sed-parser-simplified.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +# Notes: +# Cannot use any of the deliminators in the key name +# Todo: +# Lines beginning with #; within " .. " blocks on new lines will be stripped. +# Allow merging of multiple sections with the same name +# Change case of variables: \L \U \E +# export SECLIST="SECTIONS" +# Allow delims to be specified in a var - don't assume =: + +export VARPREFIX="INI_" +export SECPREFIX="SECTION_" +export SECCNAMEKEY="%cannonical name%" +export TOPSEC="global" +initest() { + echo "declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}=(" + echo "[${SECCNAMEKEY}]=\"${TOPSEC}\"" + cat $1 | sed -r "{ + # Ignore blank lines and comments + /^[[:blank:]]*(#|;|$)/ d + # Handle [section] lines + /^[[:blank:]]*\[.*\][[:blank:]]*$/ { + i ) + s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g + h + s/([[:blank:]]+|[^[:alnum:]])/_/g + s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1=(/p + g + s/(.*)/ \[${SECCNAMEKEY}\]=\"\1\"/ + b + } +# FIXME: This needs to pick up escaped =:s + /^([[:blank:]]*[^[:blank:]]+[[:blank:]]*)+[=:].*$/ { + # Escape any ] characters within key name - bash <4.3 can't handle them + s/^(([^\]]*)\[+)*([=:].*)$/\2\\\\\]\3/ + # Escape any ' characters within the key name + s/^[[:blank:]]*/ \[\'/ + s/[[:blank:]]*[=:][[:blank:]]*(.*)$/\']=\1/ +########s/([\"]+)/\\\\\1/g +#s/^(\[')([']+)('\].*)/\1X\3/g +# s/[[:blank:]]*[=:][[:blank:]]*[\"\'\`]?(.*)$/\]=\'\1/ +# s/^[[:blank:]]*([[:print:]]+)[[:blank:]]*[=:][[:blank:]]*/\[\1\]=/ + b + } + q + }" + echo ")" +} + +; initest + +# Join lines ending in \ : +sed ':x; /\\$/ { N; s/\\\n//; tx }' textfile + +echo 'ao ao ao | ao' | sed 'h; s/.*|/|/; x; s/|.*//; s/o/x/g; G; s/\n//' + + + # if a line ends with a backslash, append the next line to it + sed -e :a -e '/\\$/N; s/\\\n//; ta' + + +# 4.0 needs the backslash escaped AND the ] when referencing the element +06:09 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:09 declare -A FOOF='([test\\\]test]="test" )' +06:09 <> +06:11 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\\\]test']}" +06:11 declare -A FOOF='([test\\\]test]="test" )' +06:11 + +# 4.1, 4.2, 4.3 are consistent with this syntax +06:06 41# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:06 declare -A FOOF='(["test\\]test"]="test" )' +06:06 +06:08 42# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:08 declare -A FOOF='(["test\\]test"]="test" )' +06:08 +06:09 43# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:09 declare -A FOOF='(["test\\]test"]="test" )' +06:09 +#Works without escapes in 4.3: +06:08 43# declare -A FOOF=( ['test]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test]test']}" +06:08 declare -A FOOF='(["test]test"]="test" )' +06:08 + + + + [ [ invalid-section###3 ] $$ ] $ +[ invalid-section###3 ] $$X +# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g +_invalid_section_3_ +# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g +_________invalid_section___3_______ +# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g +__invalid_section___3_____ + + +#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g +# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/ +# s/[[:blank:]]*\][[:blank:]]*$/=(/ + +# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g +# s/[[:blank:]]+/ /g +# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/ +l 120 +# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g +# s/([^[:alnum:]]|_+)/_/g + } +}" + + s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g + s/([^[:alnum:]]|_+)/_/g + + +label regex jump back if s was done + + +# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/ +# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/ +# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/ + } +# /^(\)|declare -A)/ ! { +# s/^[[:blank:]]*/\[/ +# s/[[:blank:]]*=[[:blank:]]*/\]=\"/ +# s/$/\"/g +# } +}" + + +# Variables: +# INI_ENV_PREFIX="INI_" +# INI_GLOBAL_??="GLOBAL" +# INI_SECTION_??="SECTION" +# Options: +# + +exit + + /^[[:blank:]]*\[.*\]/ { + s/[[:blank:]]*\[/)\n/g + # s/(.*)\]/declare -A ${VAR}_\1=(/g + } + + + + -e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g" + + -e 's/^[[:blank:]]*\ 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:09 declare -A FOOF='([test\\\]test]="test" )' +06:09 <> +06:11 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\\\]test']}" +06:11 declare -A FOOF='([test\\\]test]="test" )' +06:11 + +# 4.1, 4.2, 4.3 are consistent with this syntax +06:06 41# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:06 declare -A FOOF='(["test\\]test"]="test" )' +06:06 +06:08 42# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:08 declare -A FOOF='(["test\\]test"]="test" )' +06:08 +06:09 43# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}" +06:09 declare -A FOOF='(["test\\]test"]="test" )' +06:09 +#Works without escapes in 4.3: +06:08 43# declare -A FOOF=( ['test]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test]test']}" +06:08 declare -A FOOF='(["test]test"]="test" )' +06:08 + + + + [ [ invalid-section###3 ] $$ ] $ +[ invalid-section###3 ] $$X +# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g +_invalid_section_3_ +# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g +_________invalid_section___3_______ +# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g +__invalid_section___3_____ + + +#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g +# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/ +# s/[[:blank:]]*\][[:blank:]]*$/=(/ + +# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g +# s/[[:blank:]]+/ /g +# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/ +l 120 +# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g +# s/([^[:alnum:]]|_+)/_/g + } +}" + + s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g + s/([^[:alnum:]]|_+)/_/g + + +label regex jump back if s was done + + +# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/ +# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/ +# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/ + } +# /^(\)|declare -A)/ ! { +# s/^[[:blank:]]*/\[/ +# s/[[:blank:]]*=[[:blank:]]*/\]=\"/ +# s/$/\"/g +# } +}" + + +# Variables: +# INI_ENV_PREFIX="INI_" +# INI_GLOBAL_??="GLOBAL" +# INI_SECTION_??="SECTION" +# Options: +# + +exit + + /^[[:blank:]]*\[.*\]/ { + s/[[:blank:]]*\[/)\n/g + # s/(.*)\]/declare -A ${VAR}_\1=(/g + } + + + + -e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g" + + -e 's/^[[:blank:]]*\ +Parse an ini file into environment variables which can be used natively in Bash. + +Options: + -e , --envvar= + The prefix of the environment variables set by the parser. + The default is 'INI'. + -d , --envdelim= + The character(s) to use as a deliminator between the environment variable + and the section name. This is used when creating the environment + variables which hold options belonging to a particular section of the ini + file. Only letters, numbers and underscores (_) may be used. To use no + deliminator at all, use -d '' or --envdelim=''. + The default deliminator is a single underscore '_' ??? + -i, --implied-boolean + Options usually require a parameter (after the =) in order to be set. + With this option, any option without a parameter contained in the ini file + if assumed to be a boolean 'true' and set accordingly. Likewise, any option + preceeded with 'no_' (eg: no_foo) will set the option 'foo' to boolean 'false'. + Cannot be used with --no-boolean. + -c, --case-sensitive + Be case sensitive with section names and properties. + Section names and property names will be used as is - no translation. + -g, --global-name + INI files can contain an optional implied "global" section - where there + are property names/values before any [section] header. This option + specified what section name the implied "global" section should be given + in the environment variables which are set. The default is 'GLOBAL'. + + -l, --lowercase + Usually, environment variables are converted to all uppercase before being set. + This option forces all environment variables to be converted to lowercase instead. + Note: This only effects the environment variable set with -e, and the section names + read from the ini file. Options are ?????????????????????????????????????? + -x, --export + Export environment variables. + + --no-boolean + Don't parse 'yes', 'true', 'on', 'no', 'false', 'off' into the corresponding boolean + values, and set the options strictly as is. Incompatible with -i. + --no-squash + Do not squash multiple consecutive occurances of punctuation characters + into a single _ when parsing section names and options. With this option + 'foo.-_bar' would become 'foo___bar' rather than 'foo_bar'. + --no-duplicates + If a duplicate section name or option name is found, report error and stop. + Usually sections with the same name will have their options merged, and + duplicate option values will overwrite previous ones. + + + --test + Test/validate the ini file by running it through the parser. Testing the + ini file will report any problems or syntax errors in the file, but will + not set up the environment variables as would happen in normal parsing. + Any parse errors are reported to stderr. When combined with the --debug + option, every detail of the parsing process is reported to stderr. + --debug + Show full details of the ini file parsing process. Detail is written to + stderr. Unless --test is used with this option, the parser will still + set up the environment as would happen normally, + -h, --help + Show (this) help. + -v, --version + Show version and copyright information. +EOF +} + +parser_version() { + #........1.........2.........3.........4.........5.........6.........7.........8.........9.........0.........1.........2.........3.........4.........5 + cat <<-EOF + Bash INI file parser v0.1.0. + Copyright (C) 2019 Darren 'Tadgy' Austin . + Licensed under the terms of the GNU General Public Licence version 3. + + This program comes with ABSOLUTELY NO WARRANTY. For details and a full copy of + the license terms, see: . This is free + software - you can modify and redistribute it under the terms of the GPL v3. + EOF +} + + + +parse_ini() { + # Bash v4.1+ is required. + if [[ -z "${BASH_VERSINFO[0]}" ]] || ((BASH_VERSINFO[0] < 4)) || ((BASH_VERSINFO[1] < 1)); then + echo "${0##*/}: minimum of bash v4.1 required" >&2 + return 1 + fi + + # Set defaults. + local PARSER_ENV_PREFIX="INI" + local PARSER_ENV_DELIM="_" + local PARSER_ALPHA_CLASS="[:alnum:]" # All alphanumeric characters. + local PARSER_PUNCT_CLASS="-+_. !\"£\$%^&*()="$'\t' # Characters that are converted to _ in [section] names. +!"£$%^&*()-_=+{}'@#~\|,<.>/? + # TEMP: + local PARSER_INIFILE="test.ini" + + + parser_getopts() { + while [ ! -z "$1" ]; do + case "$1" in + -h|-help|--help) + parser_help + return 0 + ;; + -v|-version|--version) + parser_version + return 0 + ;; + --) + # Stop option processing. + break + ;; + -*|--*) + echo "${0##*/}: invalid option: $1" + return 1 + ;; + esac + done + } + + # Parse arguments +# parser_getopts "$@" || return 1 + + # File accessability checks + if [ ! -e "$PARSER_INIFILE" ]; then + echo "${0##*/}: $PARSER_INIFILE: no such file" + return 1 + elif [ ! -f "$PARSER_INIFILE" ]; then + echo "${0##*/}: $PARSER_INIFILE: not a regular file" + return 1 + elif [ ! -r "$PARSER_INIFILE" ]; then + echo "${0##*/}: $PARSER_INIFILE: permission denied" + return 1 + fi + + # Open the ini file for reading + if ! exec {PARSER_INIFD}<"$PARSER_INIFILE"; then + echo "${0##*/}: $PARSER_INIFILE: failed to open" + return 1 + fi + + # FIXME: Need to handle this properly: + shopt -s extglob + + # Parse the ini file + local IFS=$'\n' PARSER_READLINE PARSER_READLINENO=0 REPLY +# local PARSER_CURSEC + while :; do + while :; do + # Read a line of input from the file descriptor + read -r -u $PARSER_INIFD || break + ((PARSER_READLINENO++)) + + # Skip any blank/empty or comment lines + [[ "$REPLY" =~ ^[[:blank:]]*([#;].*)*$ ]] && continue + + for ((I = 1; I < ${#REPLY}; I++)); do + if [[ "${REPLY: -$I:1}" =~ [[:space:]] ]]; then + continue + fi + done + + # If line ends in \, save the line and read next. + # if [[ "${REPLY:-1:1}" =~ "\" ]] + + done + +printf "<%s>\n" "$PARSER_READLINE" +exit + + # Strip any leading whitespace from the line +# Not required here, +# PARSER_READLINE="${PARSER_READLINE/#+([[:space:]])/}" + + # Is this a section header? + if [ "${PARSER_READLINE:0:1}" = "[" ]; then + if [[ "$PARSER_READLINE" =~ ^\[[$PARSER_PUNCT_CLASS$PARSER_ALPHA_CLASS]+\]$ ]]; then + # Strip the []s and any leading/trailing whitespace. + # FIXME: Allow leaving the leading/trailing whitespace in place with option? + PARSER_READLINE="${PARSER_READLINE/#\[*([[:space:]])/}" + PARSER_READLINE="${PARSER_READLINE/%*([[:space:]])\]/}" + + # FIXME: To convert single/consecutive punct_class into a single _ : + PARSER_READLINE="${PARSER_READLINE//+([$PARSER_PUNCT_CLASS])/_}" + # FIXME: To convert ALL occurances of punct_class into _ : + # PARSER_READLINE="${PARSER_READLINE//@([$PARSER_PUNCT_CLASS])/_}" + # FIXME: To convert single/consecutive punct_class into a single _ except for multiple _s already in line + # PARSER_READLINE="${PARSER_READLINE//+([${PARSER_PUNCT_CLASS/_//}])/_}" + + # FIXME: To convert section name to uppercase: + PARSER_READLINE="${PARSER_READLINE^^}" + # FIXME: To convert section name to lowercase: + # PARSER_READLINE="${PARSER_READLINE,,}" + + # Declare the associative array. + # FIXME: If doing validation only, don't declare here. + PARSER_CURSEC="$PARSER_READLINE" + declare -g -A $PARSER_ENV_PREFIX$PARSER_READLINE + + set | grep $PARSER_ENV_PREFIX$PARSER_READLINE + else + echo "${0##*/}: $PARSER_INIFILE:$PARSER_READLINENO: invalid section name or format" + # FIXME: If doing validation only, continue to process - with a flag indicating every option in this + # section will be ignored if (-?) option is set. + # If (-?) option, set flag to skip all further options until reaching next section marker. + return 1 + fi + else +# echo "Not header: $PARSER_READLINENO: $PARSER_READLINE" + true + fi + +# if first non-whitespace char after the first = is " or ', check the last non-whitespace char on the line. +# if that character is a matching " or ', skip to normal processing. +# if that character doesn't match the opening " or ', go to continued line processing +# else (no opening " or ') check the last non-whitespace char on the line; if its a \ (line continuation marker) +# go to continued line processing +# fi + +# Continued line processing +# Notes: If within a " or ' block, keep whitespace as entered - don't strip from begining of line. +# If here from a continueation marker, remove leading whitespace. +# Will need a flag to show if we're looking for an ending " or ' + +# Normal processing: +# Escape chars? + + # Close file descriptor for ini file + + # clean up the environment + # IFS=$INI_SAVED_IFS + # Remove any variables begining INI_ + + done +} + +parse_ini