5 # Copyright (C) 2003 Dan McMahill
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 # This script is used to renumber devices in a gschem (part of gEDA)
23 # schematic. This program works on single as well as multi-sheet
27 # renum.pl file1.sch [file2.sch [file3.sch ...]]
30 # for parsing input options
36 # don't allow -he to be interpreted as --help
37 $Getopt::Long
::autoabbrev
=0;
39 # my $clear; # reset all refdes
40 &GetOptions
(("help" => \
&usage
,
42 "pgskip:100" => \
$pgskip,
43 "verbose" => \
$verbose,
44 "version" => \
&version
,
50 usage
() if $Getopt::Long
::error
;
53 # By default pgskip is empty. But if the user gives
54 # the --pgskip option with no value, then assign pgskip
56 if (defined($pgskip) && ($pgskip == 0)) {
61 # This makes --gentle the default behavior. To
62 # force refdes renumbering, use --force.
64 if ( defined($force) || defined($clear) ) {
68 # Print usage string in event user didn't call out any args
71 # Make sure the input schematic exists and we can read it.
72 # Also count number of files to open.
75 $fname[$i]=shift(@ARGV);
76 die_sdb
(1, "Schematic file $fname[$i] does not exist or can not be read")
80 $filecnt = $i; # number of files to open
81 if($verbose) {print "Found $filecnt files to process\n";}
83 # To refdes an entire design, we normally just loop through all files
84 # and process each one in order. However if --gentle option is set,
85 # we need to make two passes through all files. First to create a hash
86 # of the highest refdeses used, and second to update unnumbered
87 # refdeses. The hash is used to know where to start the refdes numbering.
89 # It gets more complicated. If --pgskip is not set, then we only need
90 # to find the highest refdes overall. But if --pgskip is set, then
91 # we need to know the highest refdes on each *page*. This is accomplished
92 # on the first scan by creating the variable $highdev{$i, $pre} when --pgskip
93 # is defined, but using the variable $highdev{$pre} when it is not.
95 if (defined($gentle)) { # First scan through design to build hash
96 for($i=0; $i < $filecnt; $i++) { # $i is the file index.
97 print "Scanning input file #".($i+1).": $fname[$i]\n";
98 open(NETLIST
,"$fname[$i]") or die_sdb
(1, "Can't open $fname[$i]: $!\n");
100 while($line = <NETLIST
>) { # Iterate over lines found in .sch file.
101 unless( $line =~ /^refdes/) {
104 # Found refdes line. Eat the newline.
107 # Now extract component prefix and suffix.
108 if($verbose) {print ("Matching $line ....\n");}
109 $line =~ /refdes=([a-zA-Z_]+)(\d+|\??)/i;
111 #old behavior: my $suf = $2 ? $2 : "?";
112 # DJW: if neither number nor '?' defined, keep it so, this refdes
113 # is "non-conforming", assume the user wants this.
114 # e.g. multiple-symbol parts have the same refdes on purpose
116 if($verbose) {print "Refdes line \"$line\" has pre=$pre suf=$suf\n";}
118 # Now put highest refdes found into $highdev hash.
119 if (defined($pgskip)) {
121 # Part has no pre-existing refdes.
124 } elsif (!defined($highdev{$i, $pre})) {
125 # refdes is not cached, but refdes exists on part.
126 # Create new cache entry
127 if ($suf < $pgskip) {
128 # if pgskip=100, on pg 1, and suf = 23, set highdev=123.
129 $highdev{$i, $pre} = ($i+1)*$pgskip + $suf;
130 } elsif ( ( ($i+1)*$pgskip < $suf) &&
131 ( ($i+2)*$pgskip > $suf) ) {
132 # if pgskip=100, we're on pg 2, and suf = 204, set highdev=204.
133 $highdev{$i, $pre} = $suf;
135 # I don't know what to do!
136 die_sdb
(3, "Encountered refdes incompatable with --pgskip setting. Refdes=$pre$suf.\n");
139 } elsif ($highdev{$i, $pre} < $suf) {
140 # part has refdes and refdes is higher than cached
141 # value. Store this new value as highest value.
142 $highdev{$i, $pre} = $suf;
143 } elsif ($highdev{$i, $pre} >= $suf) {
144 # part has refdes, but refdes is lower than cached
145 # high value. Leave it alone.
148 # Should never get here
149 die_sdb
(4, "Invalid refdes with --pgskip set! Exiting....\n");
153 print "On page ".($i+1).", caching highest refdes $pre$highdev{$i, $pre}\n";
157 # Part has no pre-existing refdes.
159 } elsif (!defined($highdev{$pre}) ) {
160 # refdes is not cached, and refdes exists on part. Create new
162 $highdev{$pre} = $suf;
163 } elsif ($highdev{$pre} < $suf) {
164 # part has refdes and refdes is higher than cached
165 # value. Store this new value as highest value.
166 $highdev{$pre} = $suf;
167 } elsif ($highdev{$pre} >= $suf) {
168 # part has refdes, but refdes is lower than cached
169 # high value. Leave it alone.
172 # Should never get here
173 die_sdb
(4, "Invalid refdes! Exiting....\n");
176 print "Caching highest refdes $pre$highdev{$pre}\n";
180 } # while($line = <NETLIST>)
182 } # for($i=0; $i < $filecnt; $i++)
183 } # if (defined($gentle))
186 # OK, now we can read through the netlist file again, assign refdeses,
187 # and write the output file.
188 for($i=0; $i < $filecnt; $i++) { # $i is the file index.
189 print "Now processing input file #".($i+1).": $fname[$i]\n";
190 open(NETLIST
,"$fname[$i]") or die_sdb
(1, "Can't open $fname[$i]: $!\n");
192 # open output netlist
193 $outfname="$fname[$i].renum";
194 open(OUTNET
,">$outfname") or die_sdb
(2, "Can't open $outfname: $!\n");
196 # Iterate over lines found in .sch file.
197 while($line = <NETLIST
>) {
198 unless( $line =~ /^refdes/) {
203 # Found refdes line. Eat the newline.
206 # Now extract component prefix and suffix.
207 if($verbose) {print ("Processing $line ....\n");}
208 $line =~ /refdes=([a-zA-Z_]+)(\d+|\??)/i;
210 #old behavior: my $suf = $2 ? $2 : "?";
211 # DJW: if neither number nor '?' defined, keep it so, this refdes
212 # is "non-conforming", assume the user wants this.
213 # e.g. multiple-symbol parts have the same refdes on purpose
215 if($verbose) {print "Refdes line \"$line\" has pre=$pre suf=$suf\n";}
217 # Now finally update refdes
219 # Just overwrite all refdeses upon clear
220 if($verbose) {print ("Clearing refdes=$pre$suf\n");}
221 print OUTNET
"refdes=$pre?\n";
222 } elsif (defined($pgskip) && defined($gentle)) {
223 # If highdev exists, then start devcnt there, otherwise, start
224 # devcnt at correct value for each page.
225 if (!defined($devcnt{$i, $pre}) && defined($highdev{$i, $pre})) {
226 $devcnt{$i, $pre} = $highdev{$i, $pre};
227 } elsif (!defined($devcnt{$i, $pre}) && !defined($highdev{$i, $pre})) {
228 $devcnt{$i, $pre} = ($i+1)*$pgskip ;
233 if ($devcnt{$i, $pre} >= ($i+2)*$pgskip) {
234 print STDERR
"ERROR: You are numbering more than $pgskip elements with\n";
235 print STDERR
"prefix $pre on this sheet. You will need to either\n";
236 print STDERR
"reduce this number or specify a larger step with the\n";
237 print STDERR
"--pgskip argument.\n";
240 print "Renumbering $line to $pre$devcnt{$i, $pre}\n" if($verbose);
241 print OUTNET
"refdes=$pre$devcnt{$i, $pre}\n";
243 print "Leaving line=$line alone\n" if($verbose);
244 print OUTNET
"refdes=$pre$suf\n";
247 } elsif (defined($pgskip) && !defined($gentle)) {
248 if (!defined($devcnt{$i, $pre})) {
249 $devcnt{$i, $pre} = ($i+1)*$pgskip ;
252 if ($devcnt{$i, $pre} >= ($i+2)*$pgskip) {
253 print STDERR
"ERROR: You are numbering more than $pgskip elements with\n";
254 print STDERR
"prefix $pre on this sheet. You will need to either\n";
255 print STDERR
"reduce this number or specify a larger step with the\n";
256 print STDERR
"--pgskip argument.\n";
259 # DJW: "non-conforming" refdes, do not touch
261 print "Leaving non-conforming line=$line alone\n" if($verbose);
262 print OUTNET
"refdes=$pre$suf\n";
264 print "Renumbering $line to $pre$devcnt{$i, $pre}\n" if($verbose);
265 print OUTNET
"refdes=$pre$devcnt{$i, $pre}\n";
268 } elsif (!defined($pgskip) && defined($gentle)) {
269 if (!defined($devcnt{$pre}) && defined($highdev{$pre})) {
270 $devcnt{$pre} = $highdev{$pre};
271 } elsif (!defined($devcnt{$pre}) && !defined($highdev{$pre})) {
276 print "Renumbering $line to $pre$devcnt{$pre}\n" if($verbose);
277 print OUTNET
"refdes=$pre$devcnt{$pre}\n";
279 print "Leaving line=$line alone\n" if($verbose);
280 print OUTNET
"refdes=$pre$suf\n";
282 } elsif (!defined($pgskip) && !defined($gentle)) {
283 if (!defined($devcnt{$pre})) {
287 # DJW: "non-conforming" refdes, do not touch
289 print "Leaving non-conforming line=$line alone\n" if($verbose);
290 print OUTNET
"refdes=$pre$suf\n";
292 print "Renumbering $line to $pre$devcnt{$pre}\n" if($verbose);
293 print OUTNET
"refdes=$pre$devcnt{$pre}\n";
297 die_sdb
(4, "Invalid state when trying to update refdes! Exiting.....\n");
299 } # while($line = <NETLIST>)
304 # make this an option to not overwrite the original
306 print "Leaving page #",$i+1," output in $outfname\n";
309 system("mv $outfname $fname[$i]");
316 #######################################################################
320 #######################################################################
322 #---------------------------------
325 # prints program usage
326 #---------------------------------
333 print "\t$pname [--nocopy] [--pgskip [number] ] file1 [file2 [file3 ... ] ]\n";
334 print "\t$pname --help\n";
335 print "\t$pname --version\n";
337 print "$pname reads a gschem schematic file or files and renumbers all reference\n";
338 print "designators matching the regex ^([a-zA-Z_]+)(\\d+|\\??). The reference\n";
339 print "designators are numbered starting with 1 and the old schematic file is replaced\n";
340 print "by the modified schematic file.\n";
342 print "$pname accepts the following options:\n";
344 print " --help Displays this help message.\n";
346 print " --nocopy If given, this flag leaves the modified files in new files\n";
347 print " whose names are generated by appending a \".renum\" to the\n";
348 print " original file names. The default is to overwrite the original.\n";
350 print " --pgskip When this flag is used, components on the first schematic sheet\n";
351 print " are numbered starting with 101. On the second sheet, they start\n";
352 print " with 201, etc Specifying a value gives the step between pages.\n";
353 print " For example --pgskip 10 will start with 11, 21, 31, etc.\n";
355 print " --gentle This flag tells refdes_renum to leave any refdeses\n";
356 print " alone if they already have numbers. Use this option to number\n";
357 print " new components in a schematic which has already been numbered.\n";
358 print " Note that --gentle is set by default!\n";
360 print " --force Set this flag to renumber all conforming refdeses, whether they\n";
361 print " are already numbered or not.\n";
363 print " --verbose Enables verbose output.\n";
365 print " --version Shows the version of this program.\n";
367 print "Return codes:\n\n";
368 print "\t$pname returns the following codes to the shell upon completion:\n";
370 print " 0 Program ran successfully.\n";
371 print " 1 Error opening or reading input file.\n";
372 print " 2 Error opening or writing output file.\n";
373 print " 3 Too many components for --pgskip setting.\n";
374 print " 4 Internal error (program bug encountered).\n";
376 print "Usage examples:\n\n";
377 print "\tTo renumber the reference designators in a single page schematic\n";
378 print "\tmysch.sch:\n";
380 print "\t\t$pname mysch.sch\n";
382 print "\tTo renumber the reference designators in schematic pages pg1.sch,\n";
383 print "\tpg2.sch and pg3.sch, with the reference designators on pg1.sch\n";
384 print "\tbeginning at 101, the designators on pg2.sch beginning at 201,\n";
385 print "\tand the designators on pg3.sch beginning at 301:\n";
387 print "\t\t$pname --pgskip pg1.sch pg2.sch pg3.sch\n";
389 print "$pname was written by Dan McMahill <dmcmahill\@netbsd.org>\n";
394 #---------------------------------
397 # prints program version
398 #---------------------------------
401 open(PROG
,"$0") or die_sdb
(4, "Could not open \"$0\" to find version\n\n");
405 while($line = <PROG
>) {
406 if( $line =~ /^#\s*\$Id.*\$/) {
407 @words = split ' ',,$line;
408 $version = $words[3];
410 print "$pname ($0): Version $version, $date\n";
414 die_sdb
(4, "Could not determine version of \"$0\"\n\n");
417 #-------------------------------------------
418 # die_sdb(rc, string)
420 # Local version of die. Sets return code
421 # for shell, then calls die(string)
422 #--------------------------------------------
430 # ----------------------------------------------
434 # 2012-01-28 Dan White
435 # When '--force'ing renumbering, only do so for "conforming" refdes values.
436 # A refdes not matching the regex, nominally ending with a number or "?",
437 # remain unchanged. This keeps the script from mangling explicitly-named
438 # refdes' for e.g. multiple-symbol components (each having the same refdes).
441 # Revision 1.8 2007-04-17 20:19:23 pcjc2
442 # Merge changes from noscreen branch
444 # Revision 1.2.6.2 2007/04/17 16:19:01 pcjc2
447 # Revision 1.7 2007/04/15 23:20:31 sdb
448 # Made --gentle the default behavior of refdes_renum.
450 # Revision 1.7 2007/04/15 SDB
451 # Made --gentle default behavior. Now user must use --force
452 # to get old behavior, which renumbers all refdeses whether
453 # already numbered or not.
455 # Revision 1.6 2007/04/15 00:42:22 sdb
456 # Added --gentle flag to refdes_renum, which won't renumber refdeses
457 # which already have a number.
459 # Revision 1.5 4.9.2007 sdb.
460 # Added --gentle flag, and include logic to handle case
461 # where user mixes --gentle with --pgskip.
463 # Revision 1.4 2007/02/24 18:43:17 pcjc2
464 # Merge changes to date from noscreen branch.
466 # Revision 1.2.6.1 2007/02/11 23:59:10 pcjc2
469 # Revision 1.3 2007/02/10 20:46:17 sdb
470 # Added --clear option to clear refdeses. (* jcl *)
472 # Revision 1.2 2005/12/21 00:09:56 danmc
473 # - Fix a bug where when using the --pgskip option, components which were
474 # present on page n, but not on pages n+1 through n+j, and present again
475 # on page n+j+1 got numbered in a strange way. For example, J101 on page
476 # 1, no connectors on page 2, J201 on page 3 instead of J301. Noted by
479 # - While here allow the user to change the default increment from 100 to whatever
482 # - Also fix a bug where exactly 101 components with the same refdes prefix
483 # would cause a duplicate refdes on the next page.
485 # Revision 1.1 2003/02/21 03:21:12 ahvezda
486 # Added scripts/refdes_renum written by Dan McMahill