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,
45 "version" => \
&version
,
51 usage
() if $Getopt::Long
::error
;
54 # By default pgskip is empty. But if the user gives
55 # the --pgskip option with no value, then assign pgskip
57 if (defined($pgskip) && ($pgskip == 0)) {
62 # This makes --gentle the default behavior. To
63 # force refdes renumbering, use --force.
65 if ( defined($force) || defined($clear) ) {
70 # Option --debug implies --verbose
71 if ( defined($debug) ) {
76 # Print usage string in event user didn't call out any args
79 # Make sure the input schematic exists and we can read it.
80 # Also count number of files to open.
83 $fname[$i]=shift(@ARGV);
84 die_sdb
(1, "Schematic file $fname[$i] does not exist or can not be read")
88 $filecnt = $i; # number of files to open
89 if($debug) {print "Found $filecnt files to process\n";}
91 # To refdes an entire design, we normally just loop through all files
92 # and process each one in order. However if --gentle option is set,
93 # we need to make two passes through all files. First to create a hash
94 # of the highest refdeses used, and second to update unnumbered
95 # refdeses. The hash is used to know where to start the refdes numbering.
97 # It gets more complicated. If --pgskip is not set, then we only need
98 # to find the highest refdes overall. But if --pgskip is set, then
99 # we need to know the highest refdes on each *page*. This is accomplished
100 # on the first scan by creating the variable $highdev{$i, $pre} when --pgskip
101 # is defined, but using the variable $highdev{$pre} when it is not.
103 if (defined($gentle)) { # First scan through design to build hash
104 for($i=0; $i < $filecnt; $i++) { # $i is the file index.
105 print "Scanning input file #".($i+1).": $fname[$i]\n";
106 open(NETLIST
,"$fname[$i]") or die_sdb
(1, "Can't open $fname[$i]: $!\n");
108 while($line = <NETLIST
>) { # Iterate over lines found in .sch file.
109 unless( $line =~ /^refdes/) {
112 # Found refdes line. Eat the newline.
115 # Now extract component prefix, number, and suffix.
116 if($debug) {print ("Matching $line ....\n");}
117 $line =~ /refdes=([a-zA-Z_]+)(\d+|\??)(.*)/i;
119 #old behavior: my $num = $2 ? $2 : "?";
120 # DJW: if (neither number nor '?' defined) or there is a suffix,
121 # keep it so, this refdes is "non-conforming", assume the user wants this.
122 # e.g. multiple-symbol parts have the same refdes on purpose
125 if($debug) {print "Refdes line \"$line\" has pre=$pre num=$num suf=$suf\n";}
127 # Now put highest refdes found into $highdev hash.
128 if (defined($pgskip)) {
129 if (!($num =~ /\d+/)) {
130 # Part has no pre-existing refdes.
133 } elsif (!defined($highdev{$i, $pre})) {
134 # refdes is not cached, but refdes exists on part.
135 # Create new cache entry
136 if ($num < $pgskip) {
137 # if pgskip=100, on pg 1, and suf = 23, set highdev=123.
138 $highdev{$i, $pre} = ($i+1)*$pgskip + $num;
139 } elsif ( ( ($i+1)*$pgskip < $num) &&
140 ( ($i+2)*$pgskip > $num) ) {
141 # if pgskip=100, we're on pg 2, and suf = 204, set highdev=204.
142 $highdev{$i, $pre} = $num;
144 # I don't know what to do!
145 die_sdb
(3, "Encountered refdes incompatable with --pgskip setting. Refdes=$pre$num$suf.\n");
148 } elsif ($highdev{$i, $pre} < $num) {
149 # part has refdes and refdes is higher than cached
150 # value. Store this new value as highest value.
151 $highdev{$i, $pre} = $num;
152 } elsif ($highdev{$i, $pre} >= $num) {
153 # part has refdes, but refdes is lower than cached
154 # high value. Leave it alone.
157 # Should never get here
158 die_sdb
(4, "Invalid refdes with --pgskip set! Exiting....\n");
162 print "On page ".($i+1).", caching highest refdes $pre$highdev{$i, $pre}\n";
165 if (!($num =~ /\d+/)) {
166 # Part has no pre-existing refdes.
168 } elsif (!defined($highdev{$pre}) ) {
169 # refdes is not cached, and refdes exists on part. Create new
171 $highdev{$pre} = $num;
172 } elsif ($highdev{$pre} < $num) {
173 # part has refdes and refdes is higher than cached
174 # value. Store this new value as highest value.
175 $highdev{$pre} = $num;
176 } elsif ($highdev{$pre} >= $num) {
177 # part has refdes, but refdes is lower than cached
178 # high value. Leave it alone.
181 # Should never get here
182 die_sdb
(4, "Invalid refdes! Exiting....\n");
185 print "Caching highest refdes $pre$highdev{$pre}\n";
189 } # while($line = <NETLIST>)
191 } # for($i=0; $i < $filecnt; $i++)
192 } # if (defined($gentle))
195 # OK, now we can read through the netlist file again, assign refdeses,
196 # and write the output file.
197 for($i=0; $i < $filecnt; $i++) { # $i is the file index.
198 print "Now processing input file #".($i+1).": $fname[$i]\n";
199 open(NETLIST
,"$fname[$i]") or die_sdb
(1, "Can't open $fname[$i]: $!\n");
201 # open output netlist
202 $outfname="$fname[$i].renum";
203 open(OUTNET
,">$outfname") or die_sdb
(2, "Can't open $outfname: $!\n");
205 # Iterate over lines found in .sch file.
206 while($line = <NETLIST
>) {
207 unless( $line =~ /^refdes/) {
212 # Found refdes line. Eat the newline.
215 # Now extract component prefix, number, and suffix.
216 if($debug) {print ("Processing $line ....\n");}
217 $line =~ /refdes=([a-zA-Z_]+)(\d+|\??)(.*)/i;
219 #old behavior: my $num = $2 ? $2 : "?";
220 # DJW: if neither number nor '?' defined, keep it so, this refdes
221 # is "non-conforming", assume the user wants this.
222 # e.g. multiple-symbol parts have the same refdes on purpose
225 if($debug) {print "Refdes line \"$line\" has pre=$pre num=$num suf=$suf\n";}
227 # Now finally update refdes
229 # Just overwrite all refdeses upon clear
230 if($verbose) {print ("Clearing refdes=$pre$num$suf\n");}
231 print OUTNET
"refdes=$pre?\n";
232 } elsif (defined($pgskip) && defined($gentle)) {
233 # If highdev exists, then start devcnt there, otherwise, start
234 # devcnt at correct value for each page.
235 if (!defined($devcnt{$i, $pre}) && defined($highdev{$i, $pre})) {
236 $devcnt{$i, $pre} = $highdev{$i, $pre};
237 } elsif (!defined($devcnt{$i, $pre}) && !defined($highdev{$i, $pre})) {
238 $devcnt{$i, $pre} = ($i+1)*$pgskip ;
241 if ($num eq "?" and $suf eq "") {
243 if ($devcnt{$i, $pre} >= ($i+2)*$pgskip) {
244 print STDERR
"ERROR: You are numbering more than $pgskip elements with\n";
245 print STDERR
"prefix $pre on this sheet. You will need to either\n";
246 print STDERR
"reduce this number or specify a larger step with the\n";
247 print STDERR
"--pgskip argument.\n";
250 print "Renumbering $line to $pre$devcnt{$i, $pre}\n" if($verbose);
251 print OUTNET
"refdes=$pre$devcnt{$i, $pre}\n";
254 print STDERR
"*** WARNING: Leaving line=$line alone in --gentle mode\n";
255 print "*** WARNING: Leaving line=$line alone in --gentle mode\n";
257 print "Leaving line=$line alone\n" if($debug);
258 print OUTNET
"refdes=$pre$num$suf\n";
261 } elsif (defined($pgskip) && !defined($gentle)) {
262 if (!defined($devcnt{$i, $pre})) {
263 $devcnt{$i, $pre} = ($i+1)*$pgskip ;
266 if ($devcnt{$i, $pre} >= ($i+2)*$pgskip) {
267 print STDERR
"ERROR: You are numbering more than $pgskip elements with\n";
268 print STDERR
"prefix $pre on this sheet. You will need to either\n";
269 print STDERR
"reduce this number or specify a larger step with the\n";
270 print STDERR
"--pgskip argument.\n";
273 # DJW: "non-conforming" refdes, do not touch
274 if ($num eq "" or $suf ne "") {
275 if ($num ne "" and $num <= $devcnt{$i, $pre}) {
276 print STDERR
"WARNING: number $num is already used, possible conflict with $pre$num$suf\n";
277 print "WARNING: number $num is already used, possible conflict with $pre$num$suf\n";
279 print "Leaving non-conforming line=$line alone\n" if($verbose);
280 print OUTNET
"refdes=$pre$num$suf\n";
282 print "Renumbering $line to $pre$devcnt{$i, $pre}\n" if($verbose);
283 print OUTNET
"refdes=$pre$devcnt{$i, $pre}\n";
286 } elsif (!defined($pgskip) && defined($gentle)) {
287 if (!defined($devcnt{$pre}) && defined($highdev{$pre})) {
288 $devcnt{$pre} = $highdev{$pre};
289 } elsif (!defined($devcnt{$pre}) && !defined($highdev{$pre})) {
292 if ($num eq "?" and $suf eq "") {
294 print "Renumbering $line to $pre$devcnt{$pre}\n" if($verbose);
295 print OUTNET
"refdes=$pre$devcnt{$pre}\n";
298 print STDERR
"*** WARNING: Leaving line=$line alone in --gentle mode\n";
299 print "*** WARNING: Leaving line=$line alone in --gentle mode\n";
301 print "Leaving line=$line alone\n" if($debug);
302 print OUTNET
"refdes=$pre$num$suf\n";
304 } elsif (!defined($pgskip) && !defined($gentle)) {
305 if (!defined($devcnt{$pre})) {
309 # DJW: "non-conforming" refdes, do not touch
310 if ($num eq "" or $suf ne "") {
311 if ($num ne "" and $num <= $devcnt{$i, $pre}) {
312 print STDERR
"WARNING: number $num is already used, possible conflict with $pre$num$suf\n";
313 print "WARNING: number $num is already used, possible conflict with $pre$num$suf\n";
315 print "Leaving non-conforming line=$line alone\n" if($verbose);
316 print OUTNET
"refdes=$pre$num$suf\n";
318 print "Renumbering $line to $pre$devcnt{$pre}\n" if($verbose);
319 print OUTNET
"refdes=$pre$devcnt{$pre}\n";
323 die_sdb
(4, "Invalid state when trying to update refdes! Exiting.....\n");
325 } # while($line = <NETLIST>)
330 # make this an option to not overwrite the original
332 print "Leaving page #",$i+1," output in $outfname\n";
335 system("mv $outfname $fname[$i]");
342 #######################################################################
346 #######################################################################
348 #---------------------------------
351 # prints program usage
352 #---------------------------------
359 print "\t$pname [--nocopy] [--pgskip [number] ] file1 [file2 [file3 ... ] ]\n";
360 print "\t$pname --help\n";
361 print "\t$pname --version\n";
363 print "$pname reads a gschem schematic file or files and renumbers all reference\n";
364 print "designators matching the regex ^([a-zA-Z_]+)(\\d+|\\??)\$. Values with a\n";
365 print "suffix after the number or placeholder are detected but left untouched in\n";
366 print "all modes. The reference designators are numbered starting with 1 and the old\n";
367 print "schematic file is replaced by the modified schematic file.\n";
369 print "$pname accepts the following options:\n";
371 print " --help Displays this help message.\n";
373 print " --nocopy If given, this flag leaves the modified files in new files\n";
374 print " whose names are generated by appending a \".renum\" to the\n";
375 print " original file names. The default is to overwrite the original.\n";
377 print " --pgskip When this flag is used, components on the first schematic sheet\n";
378 print " are numbered starting with 101. On the second sheet, they start\n";
379 print " with 201, etc Specifying a value gives the step between pages.\n";
380 print " For example --pgskip 10 will start with 11, 21, 31, etc.\n";
382 print " --gentle This flag tells refdes_renum to leave any refdeses\n";
383 print " alone if they already have numbers. Use this option to number\n";
384 print " new components in a schematic which has already been numbered.\n";
385 print " Note that --gentle is set by default!\n";
387 print " --force Set this flag to renumber all conforming refdeses, whether they\n";
388 print " are already numbered or not.\n";
390 print " --verbose Enables verbose output.\n";
392 print " --debug Enables extra-verbose output.\n";
394 print " --version Shows the version of this program.\n";
396 print "Return codes:\n\n";
397 print "\t$pname returns the following codes to the shell upon completion:\n";
399 print " 0 Program ran successfully.\n";
400 print " 1 Error opening or reading input file.\n";
401 print " 2 Error opening or writing output file.\n";
402 print " 3 Too many components for --pgskip setting.\n";
403 print " 4 Internal error (program bug encountered).\n";
405 print "Usage examples:\n\n";
406 print "\tTo renumber the reference designators in a single page schematic\n";
407 print "\tmysch.sch:\n";
409 print "\t\t$pname mysch.sch\n";
411 print "\tTo renumber the reference designators in schematic pages pg1.sch,\n";
412 print "\tpg2.sch and pg3.sch, with the reference designators on pg1.sch\n";
413 print "\tbeginning at 101, the designators on pg2.sch beginning at 201,\n";
414 print "\tand the designators on pg3.sch beginning at 301:\n";
416 print "\t\t$pname --pgskip pg1.sch pg2.sch pg3.sch\n";
418 print "$pname was written by Dan McMahill <dmcmahill\@netbsd.org>\n";
423 #---------------------------------
426 # prints program version
427 #---------------------------------
430 open(PROG
,"$0") or die_sdb
(4, "Could not open \"$0\" to find version\n\n");
434 while($line = <PROG
>) {
435 if( $line =~ /^#\s*\$Id.*\$/) {
436 @words = split ' ',,$line;
437 $version = $words[3];
439 print "$pname ($0): Version $version, $date\n";
443 die_sdb
(4, "Could not determine version of \"$0\"\n\n");
446 #-------------------------------------------
447 # die_sdb(rc, string)
449 # Local version of die. Sets return code
450 # for shell, then calls die(string)
451 #--------------------------------------------
459 # ----------------------------------------------
463 # 2012-01-28 Dan White
464 # When '--force'ing renumbering, only do so for "conforming" refdes values.
465 # A refdes not matching the regex, nominally ending with a number or "?",
466 # remain unchanged. This keeps the script from mangling explicitly-named
467 # refdes' for e.g. multiple-symbol components (each having the same refdes).
470 # Revision 1.8 2007-04-17 20:19:23 pcjc2
471 # Merge changes from noscreen branch
473 # Revision 1.2.6.2 2007/04/17 16:19:01 pcjc2
476 # Revision 1.7 2007/04/15 23:20:31 sdb
477 # Made --gentle the default behavior of refdes_renum.
479 # Revision 1.7 2007/04/15 SDB
480 # Made --gentle default behavior. Now user must use --force
481 # to get old behavior, which renumbers all refdeses whether
482 # already numbered or not.
484 # Revision 1.6 2007/04/15 00:42:22 sdb
485 # Added --gentle flag to refdes_renum, which won't renumber refdeses
486 # which already have a number.
488 # Revision 1.5 4.9.2007 sdb.
489 # Added --gentle flag, and include logic to handle case
490 # where user mixes --gentle with --pgskip.
492 # Revision 1.4 2007/02/24 18:43:17 pcjc2
493 # Merge changes to date from noscreen branch.
495 # Revision 1.2.6.1 2007/02/11 23:59:10 pcjc2
498 # Revision 1.3 2007/02/10 20:46:17 sdb
499 # Added --clear option to clear refdeses. (* jcl *)
501 # Revision 1.2 2005/12/21 00:09:56 danmc
502 # - Fix a bug where when using the --pgskip option, components which were
503 # present on page n, but not on pages n+1 through n+j, and present again
504 # on page n+j+1 got numbered in a strange way. For example, J101 on page
505 # 1, no connectors on page 2, J201 on page 3 instead of J301. Noted by
508 # - While here allow the user to change the default increment from 100 to whatever
511 # - Also fix a bug where exactly 101 components with the same refdes prefix
512 # would cause a duplicate refdes on the next page.
514 # Revision 1.1 2003/02/21 03:21:12 ahvezda
515 # Added scripts/refdes_renum written by Dan McMahill