# Functions for parsing changelogs
#
# Copyright (C) 2012, 2018, 2019 Patrick McDermott
#
# This file is part of opkbuild.
#
# opkbuild 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.
#
# opkbuild 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 opkbuild. If not, see .
_ob_parse_changelog_error()
{
local file="${1}"
local line_nr="${2}"
local msg_id="${3}"
shift 3 || _ob_abort
local file_info=
file_info="$(printf '%20s(l%d)' "${file}" "${line_nr}")"
_ob_warn_msg "${msg_id}" "${file_info}" "${@}"
return 0
}
_ob_get_changelog_expect_str()
{
_ob_get_msg "changelog_expect_${1}"
return 0
}
## @brief Parse a changelog file
## @details \fBob_parse_changelog\fP parses a \fIchangelog\fP file, formatted as
## specified at
## . For
## each version entry, \fBob_parse_changelog\fP calls \fIentry_cb\fP
## with the source package name, the source package version, the list
## of distributions into which the package should be installed, the
## formatted heading (source package name, source package version, and
## distributions list) and change details, the name and e-mail address
## of the package maintainer, and the date of packaging as arguments.
## \fBob_parse_changelog\fP stops parsing either at the end of the
## \fIchangelog\fP file or when \fIentry_cb\fP returns non-zero.
## @operand file req The file to parse, or "-" for standard input.
## @operand entry_cb req Callback to run for each entry.
## @return Returns 0 after parsing.
## @stderr Prints error messages on parse errors.
## @pure maybe This function has no side effects. Whether this function is
## subshell-safe in practice depends on whether \fIentry_cb\fP is
## subshell-safe.
ob_parse_changelog()
{
local file="${1}"
local entry_cb="${2}"
shift 2 || _ob_abort
local line_nr=
local line=
local line_=
local expect=
local changes=
local blank_lines=
local source=
local distribution=
local version=
local maintainer=
local date=
# Parsing logic based on that of dpkg.
line_nr=0
expect='first_heading'
while IFS='' read line; do
line_nr=$(($line_nr + 1))
case "${line}" in
'')
if [ "${expect}" = 'start_changes' ]; then
changes="${changes}${_OB_LF}${line}"
elif [ "${expect}" = 'next_or_eof' ]; then
:
elif [ "${expect}" != 'changes_or_trailer' ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_found_blank_line' \
"$(_ob_get_changelog_expect_str "${expect}")"
else
blank_lines="${blank_lines}${_OB_LF}${line}"
fi
;;
[!\ ]*)
if [ "${expect}" != 'first_heading' -a \
"${expect}" != 'next_or_eof' ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_found_heading' \
"$(_ob_get_changelog_expect_str "${expect}")"
fi
source="${line%% (*}"
line_="${line#* (}"
distribution="${line_##*) }"
line_="${line_%) *}"
version="${line_}"
if [ -z "${source}" -o -z "${distribution}" -o \
-z "${version}" -o \
"${version% *}" != "${version}" ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_bad_heading'
source=''
version=''
distribution=''
changes=''
else
if ! ob_validate_source_name "${source}"; then
_ob_parse_changelog_error \
"${file}" "${line_nr}" \
'changelog_bad_source' "${source}"
fi
if ! ob_parse_version "${version}"; then
_ob_parse_changelog_error \
"${file}" "${line_nr}" \
'changelog_bad_source_version' "${version}"
fi
changes="${line}"
fi
expect='start_changes'
blank_lines=''
;;
' -- '*)
if [ "${expect}" != 'changes_or_trailer' ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_found_trailer' \
"$(_ob_get_changelog_expect_str "${expect}")"
fi
line="${line# -- }"
maintainer="${line%% *}"
date="${line#* }"
if [ -z "${maintainer}" -o -z "${date}" -o \
"${maintainer}" = "${date}" ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_bad_trailer'
maintainer=''
date=''
elif [ -n "${source}" ]; then
"${entry_cb}" "${source}" "${version}" \
"${distribution}" "${changes}" \
"${maintainer}" "${date}" || \
return 0
fi
expect='next_or_eof'
blank_lines=''
;;
' --'*)
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_bad_trailer'
;;
' '*)
if [ "${expect}" != 'start_changes' -a \
"${expect}" != 'changes_or_trailer' ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_found_change' \
"$(_ob_get_changelog_expect_str "${expect}")"
fi
changes="${changes}${_OB_LF}${blank_lines}${line}"
expect='changes_or_trailer'
blank_lines=''
;;
*)
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_bad_line'
blank_lines=''
;;
esac
done <<-EOF
$(cat "${file}")
EOF
if [ "${expect}" != 'next_or_eof' ]; then
_ob_parse_changelog_error "${file}" "${line_nr}" \
'changelog_found_eof' \
"$(_ob_get_changelog_expect_str "${expect}")"
fi
return 0
}