Fixed a few tests to pass make check
[geda-gaf/peter-b.git] / utils / src / grenum.c
blob98958c17033e47dd8d84d4d9043fb0a45f1071e0
1 /* $Id$ */
2 /* This is grenum, an advanced refdes renumber utility for gEDA's gschem.
4 * Copyright (C) 2005-2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Levente.Kovacs@interware.hu
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #endif
35 //#define _GNU_SOURCE
37 #ifdef HAVE_GETOPT_H
38 #include <getopt.h>
39 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
45 #include <errno.h>
47 #include "grenum.h"
48 /*#define DEBUG*/
50 int main(int argc, char *argv[])
52 FILE *infile,*outfile;
53 char buff[BUFFSIZE], infilename[FILENAMESIZE], outfilename[FILENAMESIZE];
54 unsigned char flags;
55 int c, pages, ret;
56 unsigned int i;
58 #ifdef HAVE_GETOPT_LONG
59 int opt_idx;
60 const struct option long_opts[]={
61 {"version", no_argument, NULL, 'v'},
62 {"help", no_argument, NULL, 'h'},
63 {"pagejump", no_argument, NULL, 'p'},
64 {0,0,0,0}};
65 #endif
66 const char *opt_options = "vhp";
68 struct refdes_ refdes, refdes_db[MAX_PREFIX_COUNT];
70 flags=0x00; /*Clear all flags*/
72 while(1)
74 #ifdef HAVE_GETOPT_LONG
75 c = getopt_long(argc, argv, opt_options, long_opts, &opt_idx);
76 #else
77 c = getopt(argc, argv, opt_options);
78 #endif
79 if(c == -1)
80 break;
81 switch(c)
83 case 'h':
84 printhelp();
85 return 0;
86 case 'v':
87 printver();
88 return 0;
89 case 'p':
90 flags|=PAGEJUMP; /*Set the pagejump flag*/
91 break;
94 if(optind==argc)
96 printf("grenum: no input file\n");
97 printhelp();
98 return NO_INPUT_FILE;
100 for(c=0;c<MAX_PREFIX_COUNT;++c)
102 refdes_db[c].prefix[0]='\0'; /*Zero all the strings in the database.*/
103 refdes_db[c].value=COUNT_START;
106 for(pages=1;optind<argc;++optind,++pages)
108 if((flags&PAGEJUMP)==PAGEJUMP) /*pagejumps*/
110 for(c=0;c<MAX_PREFIX_COUNT;++c)
111 refdes_db[c].value=PAGE_JMP*pages+COUNT_START; /*Reset the counters according to page numbers*/
113 strcpy(&infilename[0],argv[optind]); /*Copy the filename to the buffer*/
114 if((infile=fopen(infilename, "r")) == NULL) /*Open file, use r+ for read and write*/
116 perror("grenum: unable to open input file");
117 return FILE_OP_ERROR;
119 strcpy(&outfilename[0],&infilename[0]);
120 if((outfile=fopen(strcat(&outfilename[0],".tmp"),"w"))==NULL)
122 perror("grenum: could not create tmp file");
123 fclose(infile); /*Close the file*/
124 return FILE_OP_ERROR;
126 printf("grenum: processing file %s\n",&infilename[0]);
127 while((ret=get_refdes_from_file(infile, &refdes, buff))!=END_OF_FILE) /*Read one line.*/
128 { /*Process starts here*/
129 #ifdef DEBUG
130 printf("%s\n",&buff[0]); /*Print out what is read*/
131 #endif
132 switch(ret)
134 case NOT_REFDES_LINE:
135 if(fputs(buff,outfile)==-1)
137 perror("grenum: could not write to tmp file");
138 fclose(infile); /*Close the files*/
139 fclose(outfile);
140 return FILE_OP_ERROR;
142 continue;
143 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*/
144 c=refdes_lookup(refdes_db, &refdes);
145 switch(c)
147 case REFDES_NOT_FOUND: /*No such prefix*/
148 strcpy(&refdes_db[refdes.prefixes].prefix[0],&refdes.prefix[0]); /*Register the prefix to the database*/
149 refdes_db[refdes.prefixes+1].prefix[0]='\0';
150 refdes_db[refdes.prefixes].value=refdes.value; /*Renumber... Finally :-)*/
151 break;
152 case MAX_PREFIX_COUNT: /*Out of memory*/
153 printf("grenum: out of memory. Too much refdes prefixes.\n");
154 fclose(infile); /*Close the files*/
155 fclose(outfile);
156 return OUT_OF_MEMORY;
157 default:
158 if(refdes.value-refdes_db[c].value==1) /*If we have the next value, don't do anything, just update the database.*/
160 refdes_db[c].value=refdes.value;
161 break;
163 /*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.*/
165 for(i=refdes_db[c].value+1; i<refdes.value; ++i)
167 if(seek_value(c, infile, i, refdes_db)==VALUE_NOT_FOUND)
169 refdes_db[c].value=i-1;
170 break;
173 if(i!=refdes.value)
174 flags|=GAP_DETECTED;
175 else
176 flags|=~GAP_DETECTED;
177 break;
179 break; /*continue our job*/
180 case REFDES_WITHOUT_VALUE:
181 c=refdes_lookup(refdes_db, &refdes);
182 switch(c)
184 case -1: /*No such prefix*/
185 strcpy(&refdes_db[refdes.prefixes].prefix[0],&refdes.prefix[0]);
186 refdes.value=++refdes_db[refdes.prefixes].value;
187 refdes_db[refdes.prefixes+1].prefix[0]='\0';
188 break;
189 case MAX_PREFIX_COUNT:
190 printf("grenum: out of memory. Too much refdes prefixes.\n");
191 fclose(infile); /*Close the files*/
192 fclose(outfile);
193 return OUT_OF_MEMORY;
194 default:
195 if((flags&GAP_DETECTED)==GAP_DETECTED)
197 for(i=refdes_db[c].value+1; seek_value(c, infile, i, refdes_db)!=VALUE_NOT_FOUND; ++i);
198 refdes.value=refdes_db[c].value=i;
200 else
201 refdes.value=++refdes_db[c].value; /*renumber*/
202 break;
204 sprintf(buff, "refdes=%s%d\n", &refdes.prefix[0], refdes.value);
205 break;
206 case REFDES_ERROR: /*e.g. awdf#$%WSf82f8 :-) No "=" signal in the refdes string.*/
207 printf("grenum: parse error\n");
208 fclose(infile); /*Close the files*/
209 fclose(outfile);
210 return PARSE_ERROR;
212 if(fputs(buff,outfile)==-1) /*Finally, write the refdes line to the output file*/
214 perror("grenum: could not write to tmp file");
215 fclose(infile); /*Close the files*/
216 fclose(outfile);
217 return FILE_OP_ERROR;
219 } /*Process ends here*/
221 fclose(outfile);
222 strcpy(&buff[0],&infilename[0]); /*buff has the original infilename*/
223 /*The next few lines implements the copy program*/
224 fseek(infile,0L,SEEK_SET); /*Go to the begining of the infile*/
225 outfile=fopen(strcat(&buff[0],".save"),"w");
226 if(outfile==NULL)
228 perror("grenum: ould not create backup file");
229 fclose(infile); /*Close the file*/
230 return FILE_OP_ERROR;
232 while(fgets(&buff[0],BUFFSIZE,infile)!=NULL) /*Read one line.*/
234 if(fputs(&buff[0],outfile)==-1)
236 perror("grenum: could not write to backup file");
237 fclose(infile); /*Close the files*/
238 fclose(outfile);
239 return FILE_OP_ERROR;
242 fclose(infile);
243 fclose(outfile);
244 rename(outfilename, infilename); /*Move the tmpfile to the original*/
246 printf("grenum: file(s) successfully processed\n");
247 return OK; /*Everything is okay*/
250 int get_refdes_from_file(FILE *fp, struct refdes_ *refdes, char *buff)
253 /* Read one line from file, and return the following things:
255 * END_OF_FILE if file reaches its end. The content of buff is unknown!
257 * NOT_REFDES_LINE if the current line is not a refdes. The line will
258 * saved in buff.
260 * Return according to parse_refdes(). The buff will contain the current line too.
263 if(fgets(buff, BUFFSIZE, fp)==NULL)
264 return END_OF_FILE;
265 if(strstr(buff, "refdes=")==NULL)
266 return NOT_REFDES_LINE;
267 return parse_refdes(refdes, buff);
270 int seek_value(int prefix, FILE *fp, unsigned int value, struct refdes_ *db)
272 fpos_t filepos;
273 int ret;
274 struct refdes_ refdes;
275 char buff[BUFFSIZE];
277 fgetpos(fp, &filepos); /*First of all, save the file pos.*/
278 rewind(fp); /*Rewind*/
279 while((ret=get_refdes_from_file(fp, &refdes, buff))!=END_OF_FILE)
281 if(ret==REFDES_WITH_VALUE && prefix==refdes_lookup(db, &refdes) && refdes.value==value)
283 fsetpos(fp,&filepos);
284 return VALUE_FOUND;
287 fsetpos(fp,&filepos);
288 return VALUE_NOT_FOUND;
291 int parse_refdes(struct refdes_ *refdes, char *ref_str)
293 int i;
294 char buff[BUFFSIZE],*cpr,*cp;
297 * This function parses the refdes line from the .sch file. It takes a pointer to the
298 * complete refdes definition string, and a pointer which points to a refdes structure
299 * where it'll store the info.
301 * parse_refdes() will return
303 * REFDES_WITH_VALUE if there was a prefix with renumbered value
304 * (for example R1,IC3,U5);
306 * REFDES_WITHOUT_VALUE if there was a "?" mark found, and it has to be
307 * renumbered (e.g. U?);
309 * REFDES_ERROR, if there was some uncool thing.
311 * The refdes structure is filled with the prefix and the value.
313 * Note that if a "?" is found, the value member remains untouched.
317 cpr=strstr(ref_str,"="); /*seek for the "="*/
318 if(cpr==NULL) /*This should not happen*/
319 return REFDES_ERROR;
320 cp=strstr(ref_str,"?");
321 /*refdes=U1 refdes=IC?
322 * | |
323 * *cpr cp
325 if(cp!=NULL)
326 { /*Not renumbered yet*/
327 strncpy(&refdes->prefix[0],cpr+1,cp-cpr-1); /*Copy the prefix to the refdes structure*/
328 refdes->prefix[cp-cpr-1]='\0';
330 #ifdef DEBUG
331 printf("Prefix=%s\n",&refdes->prefix[0]);
332 #endif
334 return REFDES_WITHOUT_VALUE;
336 for(cp=cpr+1,i=0;(*cp != '\n' && *cp>='A' && *cp<='z');++i,++cp) /*No "?". Copy the prefix*/
337 buff[i]=*cp; /*Fill the buffer from char to char*/
338 buff[i]='\0'; /*Terminate with NULL to be a string*/
339 #ifdef DEBUG
340 printf("Prefix=%s\n",&buff[0]);
341 #endif
342 strcpy(&refdes->prefix[0],&buff[0]); /*Copy to refdes structure*/
343 for(i=0,cp;(*cp != '\n' && *cp>='0' && *cp<='9');++cp,++i)
344 buff[i]=*cp; /*Fill the buffer from char to char*/
345 buff[i]='\0'; /*Terminate with NULL to be a string*/
346 #ifdef DEBUG
347 printf("Value=%s\n",&buff[0]);
348 #endif
349 refdes->value=abs(atoi(&buff[0]));
350 return REFDES_WITH_VALUE;
353 int refdes_lookup(struct refdes_ *db, struct refdes_ *ref)
355 int c=0;
357 for(c=0;c<MAX_PREFIX_COUNT;++c)
359 if(strcmp(ref->prefix,(*(db+c)).prefix)==0)
360 break;
361 else if((*(db+c)).prefix[0]=='\0')
363 ref->prefixes=c;
364 return REFDES_NOT_FOUND;
367 return c;
370 void printhelp()
372 #ifdef HAVE_GETOPT_LONG
373 const char *v_opt="-v | --version";
374 const char *h_opt="-h | --help";
375 const char *p_opt="-p | --pagejump";
376 #else
377 const char *v_opt="-v";
378 const char *h_opt="-h";
379 const char *p_opt="-p";
380 #endif
382 printver();
383 printf("Usage: grenum [%s] [%s] [%s] file1.sch file2.sch ...\n\n",
384 v_opt, h_opt, p_opt);
385 printf("\t%s\tprints version info\n\t%s\tprints this help\n\t%s\tsets pagejump mode on\n",
386 v_opt, h_opt, p_opt);
387 printf("For more information read the README file and/or the manual.\n");
391 void printver()
393 printf("This is grenum, an advanced refdes renumber utility for gEDA's gschem.\n");
394 printf("Version %s. gEDA/gaf version %s\n",GRVERSION, VERSION);
395 printf("Compiled on %s at %s\n",COMP_DATE,COMP_TIME);