# opkbuild # lib/control # Functions for parsing control files. # # Copyright (C) 2012 Patrick "P. J." McDermott # # This program 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 2 of the License, or # (at your option) any later version. # # This program 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 this program. If not, see . [ -n "${_OB_CONTROL_SM}" ] && return 0 _OB_CONTROL_SM='true' ob_use messages ob_use locale _OB_SUBSTVARS_MAX_DEPTH=50 OB_CONTROL_NAME= OB_CONTROL_VALUE= ob_parse_control() { _ob_local _obpco_file _obpco_field_cb _obpco_req_fields _obpco_opt_fields \ _obpco_check_fields _obpco_all_fields _obpco_got_fields \ _obpco_line_nr _obpco_line _obpco_name _obpco_value if [ ${#} -eq 2 ]; then _obpco_file="${1}" _obpco_field_cb="${2}" _obpco_check_fields='false' elif [ ${#} -eq 4 ]; then _obpco_file="${1}" _obpco_field_cb="${2}" _obpco_req_fields="${3}" _obpco_opt_fields="${4}" _obpco_check_fields='true' _obpco_all_fields=" ${_obpco_req_fields} ${_obpco_opt_fields} " else _ob_return 125 return ${?} fi _obpco_got_fields=' ' _obpco_line_nr=0 while IFS= read -r _obpco_line; do _obpco_line_nr=$(($_obpco_line_nr + 1)) if [ -z "$(echo ${_obpco_line})" ]; then _ob_parse_control_error "${_obpco_file}" "${_obpco_line_nr}" \ 'control_empty_line' elif [ "${_obpco_line#\#}" != "${_obpco_line}" ]; then # Comment. : elif [ "${_obpco_line# }" = "${_obpco_line}" ]; then # "Name: Value" line. if [ -n "${_obpco_name}" ]; then OB_CONTROL_NAME="${_obpco_name}" OB_CONTROL_VALUE="${_obpco_value}" "${_obpco_field_cb}" if [ ${?} -ne 0 ]; then _ob_return 0 return ${?} fi fi _obpco_name="${_obpco_line%%:*}" _obpco_value="${_obpco_line#*:}" _obpco_value="${_obpco_value# }" if [ -z "${_obpco_name}" \ -o "${_obpco_name}" = "${_obpco_line}" ]; then # Badly formatted control field. _ob_parse_control_error "${_obpco_file}" "${_obpco_line_nr}" \ 'control_bad_nv' continue fi if ${_obpco_check_fields}; then if [ "${_obpco_all_fields% ${_obpco_name} *}" = \ "${_obpco_all_fields}" ]; then # Unknown field. _ob_parse_control_error \ "${_obpco_file}" "${_obpco_line_nr}" \ 'control_unknown_field' "${_obpco_name}" else # Remove field from list of required fields. _obpco_req_fields="$(echo "${_obpco_req_fields}" | \ sed "s/${_obpco_name}//")" fi fi if [ "${_obpco_got_fields% ${_obpco_name} *}" != \ "${_obpco_got_fields}" ]; then # Duplicate field. _ob_parse_control_error "${_obpco_file}" "${_obpco_line_nr}" \ 'control_duplicate_field' "${_obpco_name}" else _obpco_got_fields="${_obpco_got_fields}${_obpco_name} " fi else # Continuation line. if [ -z "${_obpco_name}" ]; then # Expecting a "Name: Value" line. _ob_parse_control_error "${_obpco_file}" "${_obpco_line_nr}" \ 'control_found_continuation' continue fi _obpco_value="${_obpco_value} ${_obpco_line# }" fi done <<-EOF $(cat "${_obpco_file}") EOF if [ -n "${_obpco_name}" ]; then OB_CONTROL_NAME="${_obpco_name}" OB_CONTROL_VALUE="${_obpco_value}" "${_obpco_field_cb}" if [ ${?} -ne 0 ]; then _ob_return 0 return ${?} fi fi if ${_obpco_check_fields}; then _obpco_req_fields="${_obpco_req_fields## }" _obpco_req_fields="${_obpco_req_fields%% }" if [ -n "${_obpco_req_fields}" ]; then # Missing required control fields. _obpco_req_fields="$(echo "${_obpco_req_fields}" | \ sed 's/ / /g' | \ sed "s/ /$(ob_get_msg 'list_item_separator')/g")" _ob_parse_control_error "${_obpco_file}" '0' \ 'control_missing_fields' \ "${_obpco_req_fields}" fi fi _ob_return 0 return ${?} } ob_set_substvar() { _ob_local _obssv_name _obssv_value if [ ${#} -eq 2 ]; then _obssv_name="${1}" _obssv_value="${2}" else _ob_return 125 return ${?} fi # Convert variable name to uppercase and validate. _obssv_name="$(echo "${_obssv_name}" | tr 'a-z-' 'A-Z_')" case "${_obssv_name:- }" in *[!A-Z0-9_]*) _ob_return 125 return ${?} ;; esac # Trim leading and trailing whitespace from value. _obssv_value="$(echo "${_obssv_value}" | sed -n ' H; # Store each input line in the hold space. ${ # At the last line of input, … g; # … restore the hold space into the pattern space, … s/^[\n]*//; # … remove leading newline characters, … s/[\n]*$//; # … remove trailing newline characters, and … p; # … print the results. }; ')" # Escape single quotes in value. _obssv_value="$(printf '%s\n' "${_obssv_value}" | sed "s/'/'\\\\''/g")" eval "_OB_SUBSTVAR_${_obssv_name}='${_obssv_value}'" _ob_return 125 return ${?} } ob_substvars() { _ob_local _obsv_string _obsv_depth \ _obsv_lhs _obsv_name _obsv_rhs _obsv_old_rhs _obsv_value if [ ${#} -eq 1 ]; then _obsv_string="${1}" else _ob_return 125 return ${?} fi # Logic inspired by that of dpkg's Dpkg::Substvars::substvars() subroutine. _obsv_depth=0 while true; do _obsv_lhs="${_obsv_string%%\$\{*}" if [ ${#_obsv_lhs} -eq ${#_obsv_string} ]; then # No "${" was found. break fi _obsv_string="${_obsv_string#*\$\{}" _obsv_name="${_obsv_string%%\}*}" _obsv_rhs="${_obsv_string#*\}}" if [ ${#_obsv_rhs} -lt ${#_obsv_old_rhs} ]; then # Reset the nesting counter if we've advanced the right side of the # matched space. _obsv_depth=0 fi if [ ${_obsv_depth} -ge ${_OB_SUBSTVARS_MAX_DEPTH} ]; then # Warn of possible recursion. ob_warn "$(ob_get_msg 'substvar_deep_nesting')" _ob_return 1 return ${?} fi _obsv_old_rhs="${_obsv_rhs}" # Perform the substitution. _obsv_name="$(echo "${_obsv_name}" | tr 'a-z-' 'A-Z_')" _obsv_value="$(eval echo \"\$\{"_OB_SUBSTVAR_${_obsv_name}"\}\")" _obsv_string="${_obsv_lhs}${_obsv_value}${_obsv_rhs}" _obsv_depth=$(($_obsv_depth + 1)) done printf '%s\n' "${_obsv_string}" _ob_return 0 return ${?} } _ob_parse_control_error() { _ob_local _obpcoe_file _obpcoe_line_nr _obpcoe_msg_id \ _obpcoe_file_info _obpcoe_orig_text_domain _obpcoe_file="${1}" _obpcoe_line_nr="${2}" _obpcoe_msg_id="${3}" shift 3 if [ "${_obpcoe_line_nr}" -eq 0 ]; then _obpcoe_file_info="$(printf '%20s:' "${_obpcoe_file}")" else _obpcoe_file_info="$(printf '%20s(l%d):' "${_obpcoe_file}" \ "${_obpcoe_line_nr}")" fi _obpcoe_orig_text_domain="$(ob_get_text_domain)" ob_set_text_domain "${_OB_INTERNAL_TEXT_DOMAIN}" ob_warn "${_obpcoe_file_info} $(ob_get_msg "${_obpcoe_msg_id}")" "${@}" ob_set_text_domain "${_obpcoe_orig_text_domain}" _ob_return 0 return ${?} }