diff options
Diffstat (limited to 'src/control.sh')
-rw-r--r-- | src/control.sh | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/control.sh b/src/control.sh new file mode 100644 index 0000000..b25d00b --- /dev/null +++ b/src/control.sh @@ -0,0 +1,147 @@ +# Functions for parsing control files. +# +# Copyright (C) 2012, 2013 Patrick "P. J." McDermott +# +# This file is part of the ProteanOS Development Kit. +# +# The ProteanOS Development Kit 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 ProteanOS Development Kit 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 ProteanOS Development Kit. If not, see +# <http://www.gnu.org/licenses/>. + +control_file= +control_line_nr= + +parse_control() +{ + local field_cb="${2}" + local paragraph_cb="${3}" + local req_fields="${4}" + local in_paragraph= + local line= + local para_req_fields= + local got_fields= + local name= + local value= + + control_file="${1}" + control_line_nr=0 + + in_paragraph='false' + + while IFS='' read -r line; do + control_line_nr=$(($control_line_nr + 1)) + if [ "x$(echo ${line})" = 'x' ]; then + # Paragraph end. + if ${in_paragraph}; then + # The first line is blank to consolidate + # initialization code (see heredocument below). + in_paragraph='false' + if [ "x${name}" != 'x' ]; then + if ! "${field_cb}" "${name}" "${value}" + then + return 0 + fi + fi + if ! "${paragraph_cb}"; then + return 0 + fi + if [ "x${para_req_fields}" != 'x' ]; then + para_req_fields="$(printf "%s$(get_msg \ + 'list_item_separator')" \ + ${para_req_fields})" + parse_control_error \ + 'control_missing_fields' \ + "${para_req_fields}" + fi + fi + para_req_fields="$(printf '%s\n' ${req_fields})" + got_fields="${LF}" + name='' + value='' + elif [ "x${line#\#}" != "x${line}" ]; then + # Comment. + in_paragraph='true' + elif [ "x${line# }" = "x${line}" ]; then + # "Name: Value" line. + in_paragraph='true' + if [ "x${name}" != 'x' ]; then + if ! "${field_cb}" "${name}" "${value}"; then + return 0 + fi + fi + name="${line%%:*}" + value="${line#*:}" + value="${value# }" + if [ "x${name}" = 'x' -o "x${name}" = "x${line}" ]; then + parse_control_error 'control_bad_nv' + continue + fi + if [ "x${para_req_fields}" != 'x' ]; then + # Remove field from list of required fields. + para_req_fields="$(printf '%s' "${para_req_fields}" | \ + grep -Fv "${name}")" + fi + if [ "x${got_fields%${LF}${name}${LF}*}" != \ + "x${got_fields}" ]; then + # Duplicate field. + parse_control_error 'control_duplicate_field' \ + "${name}" + else + got_fields="${got_fields}${name}${LF}" + fi + else + # Continuation line. + in_paragraph='true' + if [ "x${name}" = 'x' ]; then + # Expecting a "Name: Value" line. + parse_control_error 'control_found_continuation' + continue + fi + value="${value}${LF}${line# }" + fi + done <<-EOF + + $(cat "${control_file}") + + EOF + # The first blank line above triggers the paragraph end code to + # consolidate initialization code. + # The second blank line above is needed because the command substitution + # removes any trailing newlines. + + if [ "x${name}" != 'x' ]; then + if ! "${field_cb}" "${name}" "${value}"; then + return 0 + fi + fi + + return 0 +} + +parse_control_error() +{ + local msgid="${1}" + local file_info= + shift 1 + + if [ ${control_line_nr} -eq 0 ]; then + file_info="$(printf '%20s:' "${control_file}")" + else + file_info="$(printf '%20s(l%d):' "${control_file}" \ + "${control_line_nr}")" + fi + + warn "${file_info} $(get_msg "${msgid}")" "${@}" + + return 0 +} |