# pro-archman # src/control.sh # Functions for parsing control files. # # Copyright (C) 2012, 2018, 2019 Patrick McDermott # # This file is part of the ProteanOS Archive Manager. # # The ProteanOS Archive Manager 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 Archive Manager 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 Archive Manager. If not, see # . _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:%d' "${file}" "${line_nr}")" fi warn "${file_info}: $(get_msg "${msg_id}")" "${@}" return 0 } parse_control() { local file="${1}" local field_cb="${2}" local req_fields="${3}" local opt_fields="${4}" shift 4 local got_fields= local line_nr= local line= local name= local value= local sep= req_fields=" $(printf '%s ' ${req_fields})" opt_fields=" $(printf '%s ' ${opt_fields})" got_fields=' ' line_nr=0 while IFS='' read -r line; do 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}" then return 0 fi fi IFS=': ' read name value 0<<-EOF ${line} EOF if [ -z "${name}" ]; then # Badly formatted control field. _parse_control_error "${file}" \ "${line_nr}" 'control_bad_nv' continue fi 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 case "${opt_fields}" in *" ${name} "*) # Optional field. continue esac # Unknown field. _parse_control_error \ "${file}" "${line_nr}" \ 'control_unknown_field' "${name}" ;; ' '*) # Continuation line. if [ -z "${name}" ]; then # Expecting a "Name: Value" line. _parse_control_error "${file}" \ "${line_nr}" \ 'control_found_continuation' continue fi value="${value}${LF}${line# }" ;; esac done 0<<-EOF $(cat -- "${file}") EOF if [ -n "${name}" ]; then if ! "${field_cb}" "${name}" "${value}"; then return 0 fi fi 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}" return 1 esac return 0 }