# 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 # . [ "x${_CONTROL_SM+set}" = 'xset' ] && return 0 _CONTROL_SM=1 use output use locale 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 }