hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit dee84dc6e09e463f1eb785ad4d5f0222de14e7ef
parent f39768b5f7fbf44ae698329bf135e90731981e7e
Author: Umar Getagazov <umar@handlerug.me>
Date:   Sat, 26 Mar 2022 21:59:32 +0700

contrib: fix copyright.sh

Commit 3928a02c5cc148fa9c14645627695e1f038784a0 silently broke this
script. Instead of passing variables as format strings into printf, it
made them be passed as separate arguments, therefore not interpolating
any flag characters (which is a good thing). However, this also meant
that printf now did not interpolate any escape sequences, including \n.
The shell does not interpolate them either, so all line-munging routines
broke.

The most obvious solution is to move \n to the format string, like this:

	info=$(printf '%s\n' "${info}${author} ${mail};${year}")

If blindly applied, however, one more issue comes up. Per IEEE Std
1003.1-2017 (POSIX.1-2017), section 2.6.3 (emphasis mine):

> The shell shall expand the command substitution by executing command in
> a subshell environment (see Shell Execution Environment) and replacing
> the command substitution (the text of command plus the enclosing "$()"
> or backquotes) with the standard output of the command, **removing
> sequences of one or more <newline> characters at the end of the
> substitution**. Embedded <newline> characters before the end of the
> output shall not be removed; however, they may be treated as field
> delimiters and eliminated during field splitting, depending on the value
> of IFS and quoting that is in effect. If the output contains any null
> bytes, the behavior is unspecified.

Yes, the newline gets trimmed. However, from the very same excerpt we
can stumble upon another solution:

	info=$(printf '%s\n%s' "${info}" "${author} ${mail};${year}")

This way, the newline is not removed, and we can join strings just like
before. One last thing we need to take care of is to remove the leading
newline when we're finished, using tail -n +2 (to start outputting from
the second line), and the script is working again.

Signed-off-by: Umar Getagazov <umar@handlerug.me>

Diffstat:
Mcontrib/copyright.sh | 20++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/contrib/copyright.sh b/contrib/copyright.sh @@ -27,7 +27,7 @@ for file in $files; do "author-time "*) timestamp=$(printf '%s' "$line" | sed 's/author-time //' ) ;; "filename "*) year=$(date +%Y -d @${timestamp}) - year_authorinfo="${year_authorinfo}${author} ${mail};${year}\n" + year_authorinfo=$(printf '%s\n%s' "${year_authorinfo}" "${author} ${mail};${year}") ;; *) ;; esac @@ -37,7 +37,7 @@ for file in $files; do EOF # Get only the unique author names - uniq_authors="$(printf '%s' "$year_authorinfo" | awk -F ';' '{print $1}' | sort -u)" + uniq_authors="$(printf '%s\n' "$year_authorinfo" | tail -n +2 | awk -F ';' '{print $1}' | sort -u)" # Get all years for each author, and condense them into one line per author, # with the earliest contribution as the start year, and the latest @@ -47,21 +47,21 @@ EOF years_for_author="$(printf '%s' "$year_authorinfo" | awk -F ';' "{if (\$1 == \"$author\") print \$2}")" min_year="$(printf '%s' "$years_for_author" | sort | head -n 1)" max_year="$(printf '%s' "$years_for_author" | sort | tail -n 1)" - if [ $min_year = $max_year ]; then - condensed_authorinfo="${condensed_authorinfo}${author};${min_year}\n" + if [ "$min_year" = "$max_year" ]; then + condensed_authorinfo=$(printf '%s\n%s' "$condensed_authorinfo" "$author;$min_year") else - condensed_authorinfo="${condensed_authorinfo}${author};${min_year}-${max_year}\n" + condensed_authorinfo=$(printf '%s\n%s' "$condensed_authorinfo" "$author;$min_year-$max_year") fi done <<EOF $uniq_authors EOF - sorted_condensed_authorinfo="$(printf '%s' "$condensed_authorinfo" | sort -u)" + sorted_condensed_authorinfo="$(printf '%s' "$condensed_authorinfo" | tail -n +2 | sort -u)" formatted_authorinfo="$(printf '%s' "$sorted_condensed_authorinfo" | awk -F ';' '{print "// (c) " $2 " " $1}')" case $file in - "./cmd/"*) header="// License: GPL-3.0\n$formatted_authorinfo\n" ;; - *) header="// License: MPL-2.0\n$formatted_authorinfo\n" ;; + "./cmd/"*) header="// License: GPL-3.0" ;; + *) header="// License: MPL-2.0" ;; esac n_existing_license_lines=$(sed '/\(^\/\/ License\|^\/\/ (c)\|^$\)/! Q' $file | wc -l) @@ -71,10 +71,10 @@ EOF if [ -z "$(sed -n '1{/^use/p};q' copyright_tmp)" ]; then # File does not start with "use" - printf '%s\n' "$header" | cat - copyright_tmp > $file + printf '%s\n%s\n\n' "$header" "$formatted_authorinfo" | cat - copyright_tmp > $file else # File starts with "use" - printf '%s' "$header" | cat - copyright_tmp > $file + printf '%s\n%s\n' "$header" "$formatted_authorinfo" | cat - copyright_tmp > $file fi rm copyright_tmp