diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/control.sh | 192 |
1 files changed, 107 insertions, 85 deletions
diff --git a/src/control.sh b/src/control.sh index f7c4bcf..283e3d4 100644 --- a/src/control.sh +++ b/src/control.sh @@ -2,7 +2,7 @@ # src/control.sh # Functions for parsing control files. # -# Copyright (C) 2012, 2013 Patrick McDermott +# Copyright (C) 2012, 2018, 2019 Patrick McDermott # # This file is part of the ProteanOS Archive Manager. # @@ -20,115 +20,137 @@ # along with the ProteanOS Archive Manager. If not, see # <http://www.gnu.org/licenses/>. -control_file= -control_line_nr= +_parse_control_error() +{ + file="${1}" + line_nr="${2}" + msg_id="${3}" + shift 3 + local file_info= + + if [ ${line_nr} -eq 0 ]; then + file_info="$(printf '%s' "${file}")" + else + file_info="$(printf '%s(l%d)' "${file}" "${line_nr}")" + fi + + warn "${file_info} $(get_msg "${msg_id}")" "${@}" + + return 0 +} parse_control() { - control_file="${1}" + local file="${1}" local field_cb="${2}" - local req_fields="${3}" - local opt_fields="${4}" - shift 4 - local all_fields= + local user_data="${3}" + shift 3 + local check_fields= + local req_fields= + local opt_fields= local got_fields= + local line_nr= local line= local name= local value= + local sep= + + check_fields='false' + if [ ${#} -eq 2 ]; then + req_fields=" ${1} " + opt_fields=" ${2} " + shift 2 + check_fields='true' + fi - control_line_nr=0 + got_fields=' ' - req_fields="$(printf '%s\n' ${req_fields})" - opt_fields="$(printf '%s\n' ${opt_fields})" - all_fields="${LF}${req_fields}${LF}${opt_fields}${LF}" - got_fields="${LF}" + line_nr=0 while IFS='' read -r line; do - control_line_nr=$((${control_line_nr} + 1)) - if [ "x$(echo ${line})" = 'x' ]; then - parse_control_error 'control_empty_line' - elif [ "x${line#\#}" != "x${line}" ]; then - # Comment. - : - elif [ "x${line# }" = "x${line}" ]; then - # "Name: Value" line. - if [ "x${name}" != 'x' ]; then - if ! "${field_cb}" "${name}" "${value}"; then - return 0 + line_nr=$((${line_nr} + 1)) + case "${line}" in + '') + _parse_control_error "${file}" "${line_nr}" \ + 'control_empty_line' + ;; + '#'*) # Comment. + ;; + [!\ ]*':'*) # "Name: Value" line. + if [ -n "${name}" ]; then + if ! "${field_cb}" "${name}" "${value}"\ + "${user_data}"; then + return 0 + fi + fi + IFS=': ' read name value <<-EOF + ${line} + EOF + if [ -z "${name}" ]; then + # Badly formatted control field. + _parse_control_error "${file}" \ + "${line_nr}" 'control_bad_nv' + continue 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${req_fields}" != 'x' ]; then - if [ "x${all_fields%${LF}${name}${LF}*}" = \ - "x${all_fields}" ]; then + case "${got_fields}" in *" ${name} "*) + # Duplicate field. + _parse_control_error \ + "${file}" "${line_nr}" \ + 'control_duplicate_field' \ + "${name}" + continue + esac + got_fields="${got_fields}${name} " + case "${req_fields}" in *" ${name} "*) + # Required field: remove from list. + req_fields="${req_fields% ${name} *}$(:\ + ) ${req_fields#* ${name} }" + continue + esac + if ${check_fields}; then + case "${opt_fields}" in *" ${name} "*) + # Optional field. + continue + esac # Unknown field. - parse_control_error \ + _parse_control_error \ + "${file}" "${line_nr}" \ 'control_unknown_field' \ "${name}" - else - # Remove field from list of required - # fields. - req_fields="$(printf '%s' \ - "${req_fields}" | \ - grep -Fv "${name}")" fi - 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. - if [ "x${name}" = 'x' ]; then - # Expecting a "Name: Value" line. - parse_control_error 'control_found_continuation' - continue - fi - value="${value}${LF}${line# }" - fi + ;; + ' '*) # Continuation line. + if [ -z "${name}" ]; then + # Expecting a "Name: Value" line. + _parse_control_error "${file}" \ + "${line_nr}" \ + 'control_found_continuation' + continue + fi + value="${value}${OB_LF}${line# }" + ;; + esac done <<-EOF - $(cat "${control_file}") + $(cat -- "${file}") EOF - if [ "x${name}" != 'x' ]; then - if ! "${field_cb}" "${name}" "${value}"; then + if [ -n "${name}" ]; then + if ! "${field_cb}" "${name}" "${value}" "${user_data}"; then return 0 fi fi - if [ "x${req_fields}" != 'x' ]; then - req_fields="$(printf "%s$(get_msg 'list_item_separator')" \ - ${req_fields})" - parse_control_error 'control_missing_fields' "${req_fields}" - fi - - return 0 -} - -parse_control_error() -{ - local msgid="${1}" - shift 1 - local file_info= - - 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}")" + if ${check_fields}; then + case "${req_fields}" in *[!\ ]*) + # Missing required control fields. + sep="$(get_msg 'list_item_separator')" + req_fields="$(printf "%s${sep}" ${req_fields}; \ + printf 'x')" + req_fields="${req_fields%${sep}x}" + _parse_control_error "${file}" '0' \ + 'control_missing_fields' "${req_fields}" + esac fi - warn "${file_info} $(get_msg "${msgid}")" "${@}" - return 0 } |