utils/grenum: Remove non-reproducibility
[geda-gaf.git] / utils / src / grenum.c
blob4d910e977bed303e8f74a2b677d1fc418d47f68a
1 /* $Id$ */
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
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
28 #include "version.h"
30 #include <stdio.h>
31 #include <stdlib.h>
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
37 //#define _GNU_SOURCE
39 #ifdef HAVE_GETOPT_H
40 #include <getopt.h>
41 #endif
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
47 #include <errno.h>
49 #include "grenum.h"
50 /*#define DEBUG*/
52 int main(int argc, char *argv[])
54 FILE *infile,*outfile;
55 char buff[BUFFSIZE], infilename[FILENAMESIZE], outfilename[FILENAMESIZE];
56 unsigned char flags;
57 int c, pages, ret;
58 unsigned int i;
60 #ifdef HAVE_GETOPT_LONG
61 int opt_idx;
62 const struct option long_opts[]={
63 {"version", no_argument, NULL, 'v'},
64 {"help", no_argument, NULL, 'h'},
65 {"pagejump", no_argument, NULL, 'p'},
66 {0,0,0,0}};
67 #endif
68 const char *opt_options = "vhp";
70 struct refdes_ refdes, refdes_db[MAX_PREFIX_COUNT];
72 flags=0x00; /*Clear all flags*/
74 while(1)
76 #ifdef HAVE_GETOPT_LONG
77 c = getopt_long(argc, argv, opt_options, long_opts, &opt_idx);
78 #else
79 c = getopt(argc, argv, opt_options);
80 #endif
81 if(c == -1)
82 break;
83 switch(c)
85 case 'h':
86 printhelp();
87 return 0;
88 case 'v':
89 printver();
90 return 0;
91 case 'p':
92 flags|=PAGEJUMP; /*Set the pagejump flag*/
93 break;
96 if(optind==argc)
98 printf("grenum: no input file\n");
99 printhelp();
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*/
131 #ifdef DEBUG
132 printf("%s\n",&buff[0]); /*Print out what is read*/
133 #endif
134 switch(ret)
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*/
141 fclose(outfile);
142 return FILE_OP_ERROR;
144 continue;
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);
147 switch(c)
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 :-)*/
153 break;
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*/
157 fclose(outfile);
158 return OUT_OF_MEMORY;
159 default:
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;
163 break;
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;
172 break;
175 if(i!=refdes.value)
176 flags|=GAP_DETECTED;
177 else
178 flags|=~GAP_DETECTED;
179 break;
181 break; /*continue our job*/
182 case REFDES_WITHOUT_VALUE:
183 c=refdes_lookup(refdes_db, &refdes);
184 switch(c)
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';
190 break;
191 case MAX_PREFIX_COUNT:
192 printf("grenum: out of memory. Too much refdes prefixes.\n");
193 fclose(infile); /*Close the files*/
194 fclose(outfile);
195 return OUT_OF_MEMORY;
196 default:
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;
202 else
203 refdes.value=++refdes_db[c].value; /*renumber*/
204 break;
206 sprintf(buff, "refdes=%s%d\n", &refdes.prefix[0], refdes.value);
207 break;
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*/
211 fclose(outfile);
212 return PARSE_ERROR;
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*/
218 fclose(outfile);
219 return FILE_OP_ERROR;
221 } /*Process ends here*/
223 fclose(outfile);
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");
228 if(outfile==NULL)
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*/
240 fclose(outfile);
241 return FILE_OP_ERROR;
244 fclose(infile);
245 fclose(outfile);
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
260 * saved in buff.
262 * Return according to parse_refdes(). The buff will contain the current line too.
265 if(fgets(buff, BUFFSIZE, fp)==NULL)
266 return END_OF_FILE;
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)
274 fpos_t filepos;
275 int ret;
276 struct refdes_ refdes;
277 char buff[BUFFSIZE];
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);
286 return VALUE_FOUND;
289 fsetpos(fp,&filepos);
290 return VALUE_NOT_FOUND;
293 int parse_refdes(struct refdes_ *refdes, char *ref_str)
295 int i;
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*/
321 return REFDES_ERROR;
322 cp=strstr(ref_str,"?");
323 /*refdes=U1 refdes=IC?
324 * | |
325 * *cpr cp
327 if(cp!=NULL)
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';
332 #ifdef DEBUG
333 printf("Prefix=%s\n",&refdes->prefix[0]);
334 #endif
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*/
341 #ifdef DEBUG
342 printf("Prefix=%s\n",&buff[0]);
343 #endif
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*/
348 #ifdef DEBUG
349 printf("Value=%s\n",&buff[0]);
350 #endif
351 refdes->value=abs(atoi(&buff[0]));
352 return REFDES_WITH_VALUE;
355 int refdes_lookup(struct refdes_ *db, struct refdes_ *ref)
357 int c=0;
359 for(c=0;c<MAX_PREFIX_COUNT;++c)
361 if(strcmp(ref->prefix,(*(db+c)).prefix)==0)
362 break;
363 else if((*(db+c)).prefix[0]=='\0')
365 ref->prefixes=c;
366 return REFDES_NOT_FOUND;
369 return c;
372 void printhelp()
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";
378 #else
379 const char *v_opt="-v";
380 const char *h_opt="-h";
381 const char *p_opt="-p";
382 #endif
384 printver();
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");
393 void printver()
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);