#! /bin/sh # changelog-extract --- extract entries from ChangeLog files # Copyright (C) 1993, 1995 Noah S. Friedman # Author: Noah Friedman # Created: 1993-03-26 # $Id: changelog-extract,v 1.8 1996/03/03 22:46:00 friedman Exp $ # 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, 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, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. # Commentary: # Usage: changelog-extract {--regexp} entry1 entry2 ... < ChangeLog # cat ChangeLog1 ChangeLog2 ... | changelog-extract ... # # --regexp [-r] option means entryN are regular expressions instead of # exact patterns. # Code: # Name by which this script was invoked. progname=`echo "$0" | sed -e 's/[^\/]*\///g'` # To prevent hairy quoting and escaping later. bq='`' eq="'" usage="Usage: $progname {options} [entry1] {entry2 {...}} Options are: -D, --debug Turn on shell debugging ($bq${bq}set -x$eq$eq). -f, --file CHANGELOG Read entries from CHANGELOG file. There may be multiple instances of this option. -h, --help You're looking at it. -r, --regexp Entries are regular expressions, not literal text. The ${bq}AWK$eq environment variable determines which awk implementation to use. By default, ${bq}gawk$eq is used. " # Initialize variables. # Don't use `unset' since old bourne shells don't have this command. # Instead, assign them an empty value. debug= regexp=nil # Usage: filename=foo; eval "$save_filename" # eval "$restore_filename" _saved_args= _saved_args_index=0 save_filename=' { eval _saved_args$_saved_args_index=\$filename _saved_args="$_saved_args \"\$_saved_args$_saved_args_index\"" _saved_args_index=`expr $_saved_args_index + 1` }' restore_filenames=' { eval '\''{ eval set fnord $_saved_args ; }'\'' shift }' # Usage: eval "$getopt"; value=$optarg # or optarg_optional=t; eval "$getopt"; value=$optarg # # This function automatically shifts the positional args as appropriate. # The argument to an option is optional if the variable `optarg_optional' # is non-empty. Otherwise, the argument is required and getopt will cause # the program to exit on an error. optarg_optional is reset to be empty # after every call to getopt. The argument (if any) is stored in the # variable `optarg'. # # Long option syntax is `--foo=bar' or `--foo bar'. 2nd argument # won't get used if first long option syntax was used. # # Note: because of broken bourne shells, using --foo=bar syntax can # actually screw the quoting of args that end with trailing newlines. # Specifically, most shells strip trailing newlines from substituted # output, regardless of quoting. getopt=' { optarg= case "$1" in --*=* ) optarg=`echo "$1" | sed -e "1s/^[^=]*=//"` shift ;; * ) case ${2+set} in set ) optarg="$2" shift shift ;; * ) case "$optarg_optional" in "" ) case "$1" in --*=* ) option=`echo "$1" | sed -e "1s/=.*//;q"` ;; * ) option="$1" ;; esac exec 1>&2 echo "$progname: option $bq$option$eq requires argument." echo "$progname: use $bq--help$eq to list option syntax." exit 1 ;; esac ;; esac ;; esac optarg_optional= }' # Parse command line arguments. # Make sure that all wildcarded options are long enough to be unambiguous. # It's a good idea to document the full long option name in each case. # Long options which take arguments will need a `*' appended to the # canonical name to match the value appended after the `=' character. while : ; do case $# in 0) break ;; esac case "$1" in -D | --debug | --d* ) debug=t shift ;; -h | --help | --h ) echo "$usage" 1>&2 exit 1 ;; -f | --file* | --f* ) eval "$getopt" filename="$optarg" eval "$save_filename" ;; -r | --regexp | --r* ) regexp=t shift ;; -- ) # Stop option processing shift break ;; -? | --* ) case "$1" in --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;; * ) arg="$1" ;; esac exec 1>&2 echo "$progname: unknown or ambiguous option $bq$arg$eq" echo "$progname: Use $bq--help$eq for a list of options." exit 1 ;; -??* ) # Split grouped single options into separate args and try again optarg="$1" shift set fnord `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` ${1+"$@"} shift ;; * ) break ;; esac done case "$debug" in t ) set -x ;; esac case $# in 0 ) cat exit $? ;; esac case "$regexp" in t ) sed_re_quote= ;; * ) sed_re_quote='s/\([][*.\?+&|^$]\)/\\\1/g;' ;; esac sed_file_quote='s=/=\\/=g;' sed_gather='H ${ x s/^\n// s/\n/|/g /|/s/\(.*\)/(\1\)/ p }' re_filenames=` { for f in ${1+"$@"} ; do echo "$f" done } | sed -ne "$sed_re_quote $sed_file_quote $sed_gather" ` eval "$restore_filenames" ${AWK-gawk} ' BEGIN { ChangeLog_entry = ""; old_ChangeLog_entry = ""; entry_found=""; lines_index = 0; lines["array_initializer"] = "" ; delete lines["array_initializer"]; } /^[^ \t]/ { old_ChangeLog_entry = ChangeLog_entry; ChangeLog_entry = $0; next; } /(^$)|(^[ \t]*$)/ { if (entry_found) { if (ChangeLog_entry != old_ChangeLog_entry) { print ChangeLog_entry "\n"; old_ChangeLog_entry = ChangeLog_entry; } for (i = 0; i < lines_index ; i++) print lines[i]; print ""; } for (i in lines) delete lines[i]; entry_found=""; lines_index=0; next; } /^[ \t][ \t]*[^ \t]/ { lines[lines_index] = $0; lines_index++; } /[ \t,]'"$re_filenames"'([ \t,].*:|:)/ { entry_found="yes"; next; }' ${1+"$@"} # changelog-extract ends here