| 1 | #!/usr/local/bin/perl5 |
|---|
| 2 | # |
|---|
| 3 | # You make have to change the path to perl above, unless you call this |
|---|
| 4 | # script with 'make update' |
|---|
| 5 | # |
|---|
| 6 | # update.pl - integrate previous options.h settings with new options.h.dist |
|---|
| 7 | # results appear in options.h |
|---|
| 8 | # |
|---|
| 9 | # Usage: update.pl old-file new-file |
|---|
| 10 | # e.g.: update.pl dune.h dune.h.dist |
|---|
| 11 | # |
|---|
| 12 | # 'make update' calls this twice: |
|---|
| 13 | # update.pl options.h options.h.dist |
|---|
| 14 | # update.pl dune.h dune.h.dist |
|---|
| 15 | # |
|---|
| 16 | # Here's how it works. |
|---|
| 17 | # First, we make a backup of your old-file to old-file.bak |
|---|
| 18 | # Then we read all the #def's in the old-file, and their |
|---|
| 19 | # associated comments. Associated comments means comments |
|---|
| 20 | # on the same line, after the define, or comments on lines |
|---|
| 21 | # preceding the define. We store the names of all the defines, |
|---|
| 22 | # their comments, and whether they're defined or not. |
|---|
| 23 | # Then we do the same for the new-file. If we find a define |
|---|
| 24 | # that wasn't in the old-file, we show the user the comment |
|---|
| 25 | # and ask them how they want it set. Every time we write out |
|---|
| 26 | # a define, we delete it from the list of defines from old-file |
|---|
| 27 | # Finally, if there's anything left from old-file that's not in |
|---|
| 28 | # new-file, we ask if the user would like to retain each one. |
|---|
| 29 | # Presumably users want to retain their custom defines, but don't |
|---|
| 30 | # want to retain obsoleted defines. Retained defines appear at |
|---|
| 31 | # the end of the file. |
|---|
| 32 | |
|---|
| 33 | die "Usage: update.pl old-file new-file\n" unless $#ARGV == 1; |
|---|
| 34 | |
|---|
| 35 | $old = $ARGV[0]; |
|---|
| 36 | $bak = $old . ".bak"; |
|---|
| 37 | $new = $ARGV[1]; |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | # Part 1 - back up the old file (inefficient but reliable method) |
|---|
| 41 | if (-r $old) { |
|---|
| 42 | print "*** Backing up $old to $bak...\n"; |
|---|
| 43 | die "update.pl: Unable to open $old\n" unless open(OLD,"$old"); |
|---|
| 44 | die "update.pl: Unable to open $bak\n" unless open(BAK,">$bak"); |
|---|
| 45 | print BAK <OLD>; |
|---|
| 46 | close(BAK); |
|---|
| 47 | close(OLD); |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | # Part 2 - read the settings from the old file and store them |
|---|
| 51 | if (-r $old) { |
|---|
| 52 | print "*** Reading your settings from $old...\n"; |
|---|
| 53 | die "update.pl: Unable to open $old\n" unless open(OLD,"$old"); |
|---|
| 54 | while (<OLD>) { |
|---|
| 55 | # There are a few possibilities for what we could have: |
|---|
| 56 | # an #ifdef, #ifndef, #else, #endif, #define, #undef, |
|---|
| 57 | # commented #define, comment text, etc. We only care |
|---|
| 58 | # about the settings of define/undefs |
|---|
| 59 | s#/\*\s*\*/##; |
|---|
| 60 | s#[ \t]+([\r\n]*)$#$1#; |
|---|
| 61 | if ( /^#define\s+([A-Z0-9_-]+).*\\$/ ) { |
|---|
| 62 | # A define with a continuation, we need the next line |
|---|
| 63 | chop($next = <OLD>); |
|---|
| 64 | $defs{$1} = $next; |
|---|
| 65 | $comment{$1} = $comment; |
|---|
| 66 | } elsif ( m!^#define\s+([A-Z0-9_-]+)\s+(.+)\s+(/\*.*\*/)! |
|---|
| 67 | ) { |
|---|
| 68 | # A define with a value and a comment |
|---|
| 69 | $name = $1; |
|---|
| 70 | $comment{$name} = $3; |
|---|
| 71 | $defs{$name} = $2; |
|---|
| 72 | undef $comment; |
|---|
| 73 | } elsif ( m!^#define\s+([A-Z0-9_-]+)\s+(.+)! |
|---|
| 74 | ) { |
|---|
| 75 | # A define with a value |
|---|
| 76 | $defs{$1} = $2; |
|---|
| 77 | $comment{$1} = $comment; |
|---|
| 78 | } elsif ( /^#undef\s+([A-Z0-9_-]+)/ |
|---|
| 79 | ) { |
|---|
| 80 | # an undef |
|---|
| 81 | $defs{$1} = 'undef'; |
|---|
| 82 | $comment{$1} = $comment; |
|---|
| 83 | } elsif ( /^(\/\*)*\s*#define\s+([A-Z0-9-][A-Z0-9_-]+)/ |
|---|
| 84 | ) { |
|---|
| 85 | # a define or commented define |
|---|
| 86 | $defs{$2} = ($1 eq "/*") ? 'undef' : 'define'; |
|---|
| 87 | $comment{$2} = $comment; |
|---|
| 88 | } else { |
|---|
| 89 | if (m#^\s*/\*#) { |
|---|
| 90 | # Start of a comment |
|---|
| 91 | $incomment = 1; |
|---|
| 92 | undef $comment; |
|---|
| 93 | } |
|---|
| 94 | if ($incomment) { |
|---|
| 95 | $comment = $comment . $_; |
|---|
| 96 | if (m#\*/\s+$#) { |
|---|
| 97 | # End of a comment |
|---|
| 98 | $incomment = 0; |
|---|
| 99 | } |
|---|
| 100 | } |
|---|
| 101 | } |
|---|
| 102 | } |
|---|
| 103 | close(OLD); |
|---|
| 104 | } |
|---|
| 105 | undef $comment; $incomment = 0; |
|---|
| 106 | |
|---|
| 107 | |
|---|
| 108 | # Part 3 - read in the new file, modifying its definition lines to |
|---|
| 109 | # match the old file. If we come across a definition that |
|---|
| 110 | # isn't in the old file, ask the user about it. |
|---|
| 111 | print "*** Updating $old from $new...\n"; |
|---|
| 112 | die "update.pl: Unable to open $old\n" unless open(OLD,">$old"); |
|---|
| 113 | die "update.pl: Unable to open $new\n" unless open(NEW,"$new"); |
|---|
| 114 | $_ = <NEW>; |
|---|
| 115 | while ($next = <NEW>) { |
|---|
| 116 | # Just like before, but we need to keep track of |
|---|
| 117 | # comments in the file so that we can describe options |
|---|
| 118 | s#[ \t]+([\r\n]*)$#$1#; |
|---|
| 119 | if ( /^#define\s+([A-Z0-9_-]+).*\\$/ |
|---|
| 120 | ) { |
|---|
| 121 | # A define with a continuation, we need the next line |
|---|
| 122 | print OLD "#define $1 \\\n"; |
|---|
| 123 | &ask_value($1,$next) if (!defined($defs{$1})); |
|---|
| 124 | print OLD $defs{$1}; |
|---|
| 125 | delete $defs{$1}; |
|---|
| 126 | $next = <NEW>; |
|---|
| 127 | } elsif ( /^#define\s+([A-Z0-9-][A-Z0-9_-]+)\s+\/\*\s*\*\//) { |
|---|
| 128 | # a define followed by /* */ |
|---|
| 129 | print OLD defined($defs{$1}) ? &def($1) |
|---|
| 130 | : &def(&ask_simple($1,'define')); |
|---|
| 131 | } elsif ( m!^#define\s+([A-Z0-9_-]+)\s+(.+)\s+(/\*.*\*/)!) { |
|---|
| 132 | # A define with a value and a comment |
|---|
| 133 | $comment = $3; $name = $1; |
|---|
| 134 | $def = $2; |
|---|
| 135 | print OLD defined($defs{$name}) |
|---|
| 136 | ? &def($name,$comment) : &def(&ask_value($name,$def),$comment); |
|---|
| 137 | } elsif ( m!^#define\s+([A-Z0-9_-]+)\s+(.+)!) { |
|---|
| 138 | # A define with a value |
|---|
| 139 | print OLD defined($defs{$1}) ? &def($1) : &def(&ask_value($1,$2)); |
|---|
| 140 | } elsif ( /^#undef\s+([A-Z0-9_-]+)/ |
|---|
| 141 | ) { |
|---|
| 142 | print OLD defined($defs{$1}) ? &def($1) |
|---|
| 143 | : &def(&ask_simple($1,'undef')); |
|---|
| 144 | } elsif ( /^(\/\*)*\s*#define\s+([A-Z0-9-][A-Z0-9_-]+)/ |
|---|
| 145 | ) { |
|---|
| 146 | # a define or commented define |
|---|
| 147 | print OLD defined($defs{$2}) ? |
|---|
| 148 | &def($2) |
|---|
| 149 | : &def(&ask_simple($2,($1 eq "/*" ? 'undef': 'define'))); |
|---|
| 150 | } else { |
|---|
| 151 | if (m#^\s*/\*#) { |
|---|
| 152 | # Start of a comment |
|---|
| 153 | $incomment = 1; |
|---|
| 154 | undef $comment; |
|---|
| 155 | } |
|---|
| 156 | if ($incomment) { |
|---|
| 157 | $comment = $comment . $_; |
|---|
| 158 | if (m#\*/\s+$#) { |
|---|
| 159 | # End of a comment |
|---|
| 160 | $incomment = 0; |
|---|
| 161 | } |
|---|
| 162 | } |
|---|
| 163 | print OLD; |
|---|
| 164 | } |
|---|
| 165 | $_ = $next; |
|---|
| 166 | } |
|---|
| 167 | # At the end of that loop, $_ contains the last line of the |
|---|
| 168 | # file, which should be the #endif. |
|---|
| 169 | $final = $_; |
|---|
| 170 | close(NEW); |
|---|
| 171 | |
|---|
| 172 | # Part 4 - if there are any definitions left from the old file, |
|---|
| 173 | # offer to delete them (or not) |
|---|
| 174 | print "\n*** Checking for leftover defines from $old...\n"; |
|---|
| 175 | foreach $d (keys %defs) { |
|---|
| 176 | print "\nI found: $d\n"; |
|---|
| 177 | if ($defs{$d} eq 'undef') { |
|---|
| 178 | print "Currently undefined\n"; |
|---|
| 179 | } elsif ($defs{$d} eq 'define') { |
|---|
| 180 | print "Currently defined\n"; |
|---|
| 181 | } else { |
|---|
| 182 | print "Definition: $defs{$d}\n"; |
|---|
| 183 | } |
|---|
| 184 | print $comment{$d}; |
|---|
| 185 | print "\n"; |
|---|
| 186 | print "If this is a define that you hacked in, you probably should retain it.\n"; |
|---|
| 187 | print "If not, it's probably an obsolete define from an earlier patchlevel,\n"; |
|---|
| 188 | print "and you need not retain it.\n"; |
|---|
| 189 | print "Do you want to retain this in your $old file? [y] "; |
|---|
| 190 | $yn = <STDIN>; |
|---|
| 191 | if ($yn !~ /^[Nn]/) { |
|---|
| 192 | print "Retaining definition. It will appear at the end of $old.\n"; |
|---|
| 193 | @retained = (@retained, $d); |
|---|
| 194 | print OLD $comment{$d}; |
|---|
| 195 | print OLD &def($d); |
|---|
| 196 | print OLD "\n"; |
|---|
| 197 | } else { |
|---|
| 198 | print "Deleting definition.\n"; |
|---|
| 199 | @deleted = (@deleted, $d); |
|---|
| 200 | } |
|---|
| 201 | } |
|---|
| 202 | |
|---|
| 203 | print OLD $final; |
|---|
| 204 | |
|---|
| 205 | close(OLD); |
|---|
| 206 | |
|---|
| 207 | print "\nSummary of changes:\n"; |
|---|
| 208 | print "New options from $new: ",join(" ",@newoptions),"\n"; |
|---|
| 209 | print "Old options retained: ",join(" ",@retained),"\n"; |
|---|
| 210 | print "Old options deleted: ",join(" ",@deleted),"\n"; |
|---|
| 211 | print "If this is wrong, you can recover $old from $bak.\n"; |
|---|
| 212 | print "Done!\n"; |
|---|
| 213 | exit 0; |
|---|
| 214 | |
|---|
| 215 | |
|---|
| 216 | # |
|---|
| 217 | # &def - Given a define name, return the appopriate C code |
|---|
| 218 | # to define/undefine it. And delete it. |
|---|
| 219 | # May also be given a comment as a second arg. |
|---|
| 220 | # |
|---|
| 221 | sub def { |
|---|
| 222 | # We should use my instead of local, but some folks have perl 4 |
|---|
| 223 | local($d) = $_[0]; |
|---|
| 224 | local($c) = $_[1]; |
|---|
| 225 | local($df) = $defs{$d}; |
|---|
| 226 | delete $defs{$d}; |
|---|
| 227 | $d =~ s/^\s+//; |
|---|
| 228 | $d =~ s/\s+$//; |
|---|
| 229 | $c =~ s/^\s+//; |
|---|
| 230 | $c =~ s/\s+$//; |
|---|
| 231 | $df =~ s/^\s+//; |
|---|
| 232 | $df =~ s/\s+$//; |
|---|
| 233 | return "/* #define $d /* */\n" if ($df eq 'undef'); |
|---|
| 234 | return "#define $d /* */\n" if ($df eq 'define'); |
|---|
| 235 | return "#define $d\t$df\t$c\n" if ($c); |
|---|
| 236 | return "#define $d\t$df\n"; |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | # |
|---|
| 240 | # &ask_simple - Given a define name and default setting, |
|---|
| 241 | # show the comment in $comment, |
|---|
| 242 | # and ask the user if they want to define it or not |
|---|
| 243 | # Set $defs{$d} and return the name given |
|---|
| 244 | # |
|---|
| 245 | sub ask_simple { |
|---|
| 246 | local($d,$s) = @_; |
|---|
| 247 | local($yn); |
|---|
| 248 | print "\nNew option: $d\n"; |
|---|
| 249 | print $comment; |
|---|
| 250 | $s = ($s eq 'define') ? 'y' : 'n'; |
|---|
| 251 | while (1) { |
|---|
| 252 | print "Define this option? [$s] "; |
|---|
| 253 | $yn = <STDIN>; |
|---|
| 254 | $yn = $s if $yn =~ /^$/; |
|---|
| 255 | last if $yn =~ /^[YyNn]/; |
|---|
| 256 | } |
|---|
| 257 | $defs{$d} = ($yn =~ /^[Yy]/) ? 'define' : 'undef'; |
|---|
| 258 | @newoptions = (@newoptions,$d); |
|---|
| 259 | return $d; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | |
|---|
| 263 | # |
|---|
| 264 | # &ask_value - Just like ask_simple, but instead of a yes/no, |
|---|
| 265 | # we're going to get a value |
|---|
| 266 | # |
|---|
| 267 | sub ask_value { |
|---|
| 268 | local($d,$s) = @_; |
|---|
| 269 | local($val); |
|---|
| 270 | print "\nNew option: $d\n"; |
|---|
| 271 | print $comment; |
|---|
| 272 | print "Default value: $s\n"; |
|---|
| 273 | print "Value for this option? [$s] "; |
|---|
| 274 | $val = <STDIN>; |
|---|
| 275 | $val = $s if $val =~ /^$/; |
|---|
| 276 | $defs{$d} = $val; |
|---|
| 277 | @newoptions = (@newoptions,$d); |
|---|
| 278 | return $d; |
|---|
| 279 | } |
|---|