2 /* This is grenum, an advanced refdes renumber utility for gEDA's gschem.
4 * Copyright (C) 2005-2010 Levente Kovacs
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Levente.Kovacs@interware.hu
52 int main(int argc
, char *argv
[])
54 FILE *infile
,*outfile
;
55 char buff
[BUFFSIZE
], infilename
[FILENAMESIZE
], outfilename
[FILENAMESIZE
];
60 #ifdef HAVE_GETOPT_LONG
62 const struct option long_opts
[]={
63 {"version", no_argument
, NULL
, 'v'},
64 {"help", no_argument
, NULL
, 'h'},
65 {"pagejump", no_argument
, NULL
, 'p'},
68 const char *opt_options
= "vhp";
70 struct refdes_ refdes
, refdes_db
[MAX_PREFIX_COUNT
];
72 flags
=0x00; /*Clear all flags*/
76 #ifdef HAVE_GETOPT_LONG
77 c
= getopt_long(argc
, argv
, opt_options
, long_opts
, &opt_idx
);
79 c
= getopt(argc
, argv
, opt_options
);
92 flags
|=PAGEJUMP
; /*Set the pagejump flag*/
98 printf("grenum: no input file\n");
100 return NO_INPUT_FILE
;
102 for(c
=0;c
<MAX_PREFIX_COUNT
;++c
)
104 refdes_db
[c
].prefix
[0]='\0'; /*Zero all the strings in the database.*/
105 refdes_db
[c
].value
=COUNT_START
;
108 for(pages
=1;optind
<argc
;++optind
,++pages
)
110 if((flags
&PAGEJUMP
)==PAGEJUMP
) /*pagejumps*/
112 for(c
=0;c
<MAX_PREFIX_COUNT
;++c
)
113 refdes_db
[c
].value
=PAGE_JMP
*pages
+COUNT_START
; /*Reset the counters according to page numbers*/
115 strcpy(&infilename
[0],argv
[optind
]); /*Copy the filename to the buffer*/
116 if((infile
=fopen(infilename
, "r")) == NULL
) /*Open file, use r+ for read and write*/
118 perror("grenum: unable to open input file");
119 return FILE_OP_ERROR
;
121 strcpy(&outfilename
[0],&infilename
[0]);
122 if((outfile
=fopen(strcat(&outfilename
[0],".tmp"),"wb"))==NULL
)
124 perror("grenum: could not create tmp file");
125 fclose(infile
); /*Close the file*/
126 return FILE_OP_ERROR
;
128 printf("grenum: processing file %s\n",&infilename
[0]);
129 while((ret
=get_refdes_from_file(infile
, &refdes
, buff
))!=END_OF_FILE
) /*Read one line.*/
130 { /*Process starts here*/
132 printf("%s\n",&buff
[0]); /*Print out what is read*/
136 case NOT_REFDES_LINE
:
137 if(fputs(buff
,outfile
)==-1)
139 perror("grenum: could not write to tmp file");
140 fclose(infile
); /*Close the files*/
142 return FILE_OP_ERROR
;
145 case REFDES_WITH_VALUE
: /*We shall compare the maximum value, shall search for gaps, and set the refes_db.value to the next free value*/
146 c
=refdes_lookup(refdes_db
, &refdes
);
149 case REFDES_NOT_FOUND
: /*No such prefix*/
150 strcpy(&refdes_db
[refdes
.prefixes
].prefix
[0],&refdes
.prefix
[0]); /*Register the prefix to the database*/
151 refdes_db
[refdes
.prefixes
+1].prefix
[0]='\0';
152 refdes_db
[refdes
.prefixes
].value
=refdes
.value
; /*Renumber... Finally :-)*/
154 case MAX_PREFIX_COUNT
: /*Out of memory*/
155 printf("grenum: out of memory. Too much refdes prefixes.\n");
156 fclose(infile
); /*Close the files*/
158 return OUT_OF_MEMORY
;
160 if(refdes
.value
-refdes_db
[c
].value
==1) /*If we have the next value, don't do anything, just update the database.*/
162 refdes_db
[c
].value
=refdes
.value
;
165 /*Now we have a hole in numbering. Let's see if it'll be fixed, and seek for the maximum value. eg. R1,R2,R5,R3. So, we have to search for R3,R4, and set the db to R3.*/
167 for(i
=refdes_db
[c
].value
+1; i
<refdes
.value
; ++i
)
169 if(seek_value(c
, infile
, i
, refdes_db
)==VALUE_NOT_FOUND
)
171 refdes_db
[c
].value
=i
-1;
178 flags
|=~GAP_DETECTED
;
181 break; /*continue our job*/
182 case REFDES_WITHOUT_VALUE
:
183 c
=refdes_lookup(refdes_db
, &refdes
);
186 case -1: /*No such prefix*/
187 strcpy(&refdes_db
[refdes
.prefixes
].prefix
[0],&refdes
.prefix
[0]);
188 refdes
.value
=++refdes_db
[refdes
.prefixes
].value
;
189 refdes_db
[refdes
.prefixes
+1].prefix
[0]='\0';
191 case MAX_PREFIX_COUNT
:
192 printf("grenum: out of memory. Too much refdes prefixes.\n");
193 fclose(infile
); /*Close the files*/
195 return OUT_OF_MEMORY
;
197 if((flags
&GAP_DETECTED
)==GAP_DETECTED
)
199 for(i
=refdes_db
[c
].value
+1; seek_value(c
, infile
, i
, refdes_db
)!=VALUE_NOT_FOUND
; ++i
);
200 refdes
.value
=refdes_db
[c
].value
=i
;
203 refdes
.value
=++refdes_db
[c
].value
; /*renumber*/
206 sprintf(buff
, "refdes=%s%d\n", &refdes
.prefix
[0], refdes
.value
);
208 case REFDES_ERROR
: /*e.g. awdf#$%WSf82f8 :-) No "=" signal in the refdes string.*/
209 printf("grenum: parse error\n");
210 fclose(infile
); /*Close the files*/
214 if(fputs(buff
,outfile
)==-1) /*Finally, write the refdes line to the output file*/
216 perror("grenum: could not write to tmp file");
217 fclose(infile
); /*Close the files*/
219 return FILE_OP_ERROR
;
221 } /*Process ends here*/
224 strcpy(&buff
[0],&infilename
[0]); /*buff has the original infilename*/
225 /*The next few lines implements the copy program*/
226 fseek(infile
,0L,SEEK_SET
); /*Go to the begining of the infile*/
227 outfile
=fopen(strcat(&buff
[0],".save"),"wb");
230 perror("grenum: ould not create backup file");
231 fclose(infile
); /*Close the file*/
232 return FILE_OP_ERROR
;
234 while(fgets(&buff
[0],BUFFSIZE
,infile
)!=NULL
) /*Read one line.*/
236 if(fputs(&buff
[0],outfile
)==-1)
238 perror("grenum: could not write to backup file");
239 fclose(infile
); /*Close the files*/
241 return FILE_OP_ERROR
;
246 rename(outfilename
, infilename
); /*Move the tmpfile to the original*/
248 printf("grenum: file(s) successfully processed\n");
249 return OK
; /*Everything is okay*/
252 int get_refdes_from_file(FILE *fp
, struct refdes_
*refdes
, char *buff
)
255 /* Read one line from file, and return the following things:
257 * END_OF_FILE if file reaches its end. The content of buff is unknown!
259 * NOT_REFDES_LINE if the current line is not a refdes. The line will
262 * Return according to parse_refdes(). The buff will contain the current line too.
265 if(fgets(buff
, BUFFSIZE
, fp
)==NULL
)
267 if(strstr(buff
, "refdes=")==NULL
)
268 return NOT_REFDES_LINE
;
269 return parse_refdes(refdes
, buff
);
272 int seek_value(int prefix
, FILE *fp
, unsigned int value
, struct refdes_
*db
)
276 struct refdes_ refdes
;
279 fgetpos(fp
, &filepos
); /*First of all, save the file pos.*/
280 rewind(fp
); /*Rewind*/
281 while((ret
=get_refdes_from_file(fp
, &refdes
, buff
))!=END_OF_FILE
)
283 if(ret
==REFDES_WITH_VALUE
&& prefix
==refdes_lookup(db
, &refdes
) && refdes
.value
==value
)
285 fsetpos(fp
,&filepos
);
289 fsetpos(fp
,&filepos
);
290 return VALUE_NOT_FOUND
;
293 int parse_refdes(struct refdes_
*refdes
, char *ref_str
)
296 char buff
[BUFFSIZE
],*cpr
,*cp
;
299 * This function parses the refdes line from the .sch file. It takes a pointer to the
300 * complete refdes definition string, and a pointer which points to a refdes structure
301 * where it'll store the info.
303 * parse_refdes() will return
305 * REFDES_WITH_VALUE if there was a prefix with renumbered value
306 * (for example R1,IC3,U5);
308 * REFDES_WITHOUT_VALUE if there was a "?" mark found, and it has to be
309 * renumbered (e.g. U?);
311 * REFDES_ERROR, if there was some uncool thing.
313 * The refdes structure is filled with the prefix and the value.
315 * Note that if a "?" is found, the value member remains untouched.
319 cpr
=strstr(ref_str
,"="); /*seek for the "="*/
320 if(cpr
==NULL
) /*This should not happen*/
322 cp
=strstr(ref_str
,"?");
323 /*refdes=U1 refdes=IC?
328 { /*Not renumbered yet*/
329 strncpy(&refdes
->prefix
[0],cpr
+1,cp
-cpr
-1); /*Copy the prefix to the refdes structure*/
330 refdes
->prefix
[cp
-cpr
-1]='\0';
333 printf("Prefix=%s\n",&refdes
->prefix
[0]);
336 return REFDES_WITHOUT_VALUE
;
338 for(cp
=cpr
+1,i
=0;(*cp
!= '\n' && *cp
>='A' && *cp
<='z');++i
,++cp
) /*No "?". Copy the prefix*/
339 buff
[i
]=*cp
; /*Fill the buffer from char to char*/
340 buff
[i
]='\0'; /*Terminate with NULL to be a string*/
342 printf("Prefix=%s\n",&buff
[0]);
344 strcpy(&refdes
->prefix
[0],&buff
[0]); /*Copy to refdes structure*/
345 for(i
=0;(*cp
!= '\n' && *cp
>='0' && *cp
<='9');++cp
,++i
)
346 buff
[i
]=*cp
; /*Fill the buffer from char to char*/
347 buff
[i
]='\0'; /*Terminate with NULL to be a string*/
349 printf("Value=%s\n",&buff
[0]);
351 refdes
->value
=abs(atoi(&buff
[0]));
352 return REFDES_WITH_VALUE
;
355 int refdes_lookup(struct refdes_
*db
, struct refdes_
*ref
)
359 for(c
=0;c
<MAX_PREFIX_COUNT
;++c
)
361 if(strcmp(ref
->prefix
,(*(db
+c
)).prefix
)==0)
363 else if((*(db
+c
)).prefix
[0]=='\0')
366 return REFDES_NOT_FOUND
;
374 #ifdef HAVE_GETOPT_LONG
375 const char *v_opt
="-v | --version";
376 const char *h_opt
="-h | --help";
377 const char *p_opt
="-p | --pagejump";
379 const char *v_opt
="-v";
380 const char *h_opt
="-h";
381 const char *p_opt
="-p";
385 printf("Usage: grenum [%s] [%s] [%s] file1.sch file2.sch ...\n\n",
386 v_opt
, h_opt
, p_opt
);
387 printf("\t%s\tprints version info\n\t%s\tprints this help\n\t%s\tsets pagejump mode on\n",
388 v_opt
, h_opt
, p_opt
);
389 printf("For more information read the README file and/or the manual.\n");
395 printf("This is grenum, an advanced refdes renumber utility for gEDA's gschem.\n");
396 printf("Version %s. gEDA/gaf version %s.%s\n",GRVERSION
,
397 PACKAGE_DOTTED_VERSION
, PACKAGE_DATE_VERSION
);