# opkbuild # lib/control.sh # 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 . [ x"${_OB_CONTROL_SM+set}" = x'set' ] && return 0 _OB_CONTROL_SM=1 ob_use messages ob_use locale _OB_SUBSTVARS_MAX_DEPTH=50 OB_CONTROL_NAME= OB_CONTROL_VALUE= ob_parse_control() { local file= local field_cb= local req_fields= local opt_fields= local check_fields= local all_fields= local got_fields= local line_nr= local line= local name= local value= if [ ${#} -eq 2 ]; then file="${1}" field_cb="${2}" check_fields='false' elif [ ${#} -eq 4 ]; then file="${1}" field_cb="${2}" req_fields="${3}" opt_fields="${4}" check_fields='true' all_fields=" ${req_fields} ${opt_fields} " else return 125 fi got_fields=' ' line_nr=0 while IFS= read -r line; do line_nr=$(($line_nr + 1)) if [ -z "$(echo ${line})" ]; then _ob_parse_control_error "${file}" "${line_nr}" \ 'control_empty_line' elif [ "${line#\#}" != "${line}" ]; then # Comment. : elif [ "${line# }" = "${line}" ]; then # "Name: Value" line. if [ -n "${name}" ]; then OB_CONTROL_NAME="${name}" OB_CONTROL_VALUE="${value}" "${field_cb}" if [ ${?} -ne 0 ]; then return 0 fi fi name="${line%%:*}" value="${line#*:}" value="${value# }" if [ -z "${name}" \ -o "${name}" = "${line}" ]; then # Badly formatted control field. _ob_parse_control_error "${file}" "${line_nr}" \ 'control_bad_nv' continue fi if ${check_fields}; then if [ "${all_fields% ${name} *}" = \ "${all_fields}" ]; then # Unknown field. _ob_parse_control_error \ "${file}" "${line_nr}" \ 'control_unknown_field' "${name}" else # Remove field from list of required fields. req_fields="$(echo "${req_fields}" | \ sed "s/${name}//")" fi fi if [ "${got_fields% ${name} *}" != \ "${got_fields}" ]; then # Duplicate field. _ob_parse_control_error "${file}" "${line_nr}" \ 'control_duplicate_field' "${name}" else got_fields="${got_fields}${name} " fi else # Continuation line. if [ -z "${name}" ]; then # Expecting a "Name: Value" line. _ob_parse_control_error "${file}" "${line_nr}" \ 'control_found_continuation' continue fi value="${value} ${line# }" fi done <<-EOF $(cat "${file}") EOF if [ -n "${name}" ]; then OB_CONTROL_NAME="${name}" OB_CONTROL_VALUE="${value}" "${field_cb}" if [ ${?} -ne 0 ]; then return 0 fi fi if ${check_fields}; then req_fields="${req_fields## }" req_fields="${req_fields%% }" if [ -n "${req_fields}" ]; then # Missing required control fields. req_fields="$(echo "${req_fields}" | sed 's/ / /g' | \ sed "s/ /$(ob_get_msg 'list_item_separator')/g")" _ob_parse_control_error "${file}" '0' \ 'control_missing_fields' "${req_fields}" fi fi return 0 } ob_set_substvar() { local name= local value= if [ ${#} -eq 2 ]; then name="${1}" value="${2}" else return 125 fi # Convert variable name to uppercase and validate. name="$(echo "${name}" | tr 'a-z-' 'A-Z_')" case "${name:- }" in *[!A-Z0-9_]*) return 125 ;; esac # Trim leading and trailing whitespace from value. value="$(echo "${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. value="$(printf '%s\n' "${value}" | sed "s/'/'\\\\''/g")" eval "_OB_SUBSTVAR_${name}='${value}'" return 125 } ob_substvars() { local string= local depth= local lhs= local name= local rhs= local old_rhs= local value= if [ ${#} -eq 1 ]; then string="${1}" else return 125 fi # Logic inspired by that of dpkg's Dpkg::Substvars::substvars() subroutine. depth=0 while true; do lhs="${string%%\$\{*}" if [ ${#lhs} -eq ${#string} ]; then # No "${" was found. break fi string="${string#*\$\{}" name="${string%%\}*}" rhs="${string#*\}}" if [ ${#rhs} -lt ${#old_rhs} ]; then # Reset the nesting counter if we've advanced the right side of the # matched space. depth=0 fi if [ ${depth} -ge ${_OB_SUBSTVARS_MAX_DEPTH} ]; then # Warn of possible recursion. ob_warn "$(ob_get_msg 'substvar_deep_nesting')" return 1 fi old_rhs="${rhs}" # Perform the substitution. name="$(echo "${name}" | tr 'a-z-' 'A-Z_')" value="$(eval echo \"\$\{"_OB_SUBSTVAR_${name}"\}\")" string="${lhs}${value}${rhs}" depth=$(($depth + 1)) done printf '%s\n' "${string}" return 0 } _ob_parse_control_error() { local file= local line_nr= local msg_id= local file_info= local orig_text_domain= file="${1}" line_nr="${2}" msg_id="${3}" shift 3 if [ ${line_nr} -eq 0 ]; then file_info="$(printf '%20s:' "${file}")" else file_info="$(printf '%20s(l%d):' "${file}" "${line_nr}")" fi orig_text_domain="$(ob_get_text_domain)" ob_set_text_domain "${_OB_INTERNAL_TEXT_DOMAIN}" ob_warn "${file_info} $(ob_get_msg "${msg_id}")" "${@}" ob_set_text_domain "${orig_text_domain}" return 0 }