utils
|
00001 /* $Id$ */ 00002 /* This is grenum, an advanced refdes renumber utility for gEDA's gschem. 00003 * 00004 * Copyright (C) 2005-2010 Levente Kovacs 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 * 00020 * Levente.Kovacs@interware.hu 00021 * 00022 */ 00023 00024 #ifdef HAVE_CONFIG_H 00025 #include "config.h" 00026 #endif 00027 00028 #include "version.h" 00029 00030 #include <stdio.h> 00031 #include <stdlib.h> 00032 00033 #ifdef HAVE_STRING_H 00034 #include <string.h> 00035 #endif 00036 00037 //#define _GNU_SOURCE 00038 00039 #ifdef HAVE_GETOPT_H 00040 #include <getopt.h> 00041 #endif 00042 00043 #ifdef HAVE_UNISTD_H 00044 #include <unistd.h> 00045 #endif 00046 00047 #include <errno.h> 00048 00049 #include "grenum.h" 00050 /*#define DEBUG*/ 00051 00052 int main(int argc, char *argv[]) 00053 { 00054 FILE *infile,*outfile; 00055 char buff[BUFFSIZE], infilename[FILENAMESIZE], outfilename[FILENAMESIZE]; 00056 unsigned char flags; 00057 int c, pages, ret; 00058 unsigned int i; 00059 00060 #ifdef HAVE_GETOPT_LONG 00061 int opt_idx; 00062 const struct option long_opts[]={ 00063 {"version", no_argument, NULL, 'v'}, 00064 {"help", no_argument, NULL, 'h'}, 00065 {"pagejump", no_argument, NULL, 'p'}, 00066 {0,0,0,0}}; 00067 #endif 00068 const char *opt_options = "vhp"; 00069 00070 struct refdes_ refdes, refdes_db[MAX_PREFIX_COUNT]; 00071 00072 flags=0x00; /*Clear all flags*/ 00073 00074 while(1) 00075 { 00076 #ifdef HAVE_GETOPT_LONG 00077 c = getopt_long(argc, argv, opt_options, long_opts, &opt_idx); 00078 #else 00079 c = getopt(argc, argv, opt_options); 00080 #endif 00081 if(c == -1) 00082 break; 00083 switch(c) 00084 { 00085 case 'h': 00086 printhelp(); 00087 return 0; 00088 case 'v': 00089 printver(); 00090 return 0; 00091 case 'p': 00092 flags|=PAGEJUMP; /*Set the pagejump flag*/ 00093 break; 00094 } 00095 } 00096 if(optind==argc) 00097 { 00098 printf("grenum: no input file\n"); 00099 printhelp(); 00100 return NO_INPUT_FILE; 00101 } 00102 for(c=0;c<MAX_PREFIX_COUNT;++c) 00103 { 00104 refdes_db[c].prefix[0]='\0'; /*Zero all the strings in the database.*/ 00105 refdes_db[c].value=COUNT_START; 00106 } 00107 00108 for(pages=1;optind<argc;++optind,++pages) 00109 { 00110 if((flags&PAGEJUMP)==PAGEJUMP) /*pagejumps*/ 00111 { 00112 for(c=0;c<MAX_PREFIX_COUNT;++c) 00113 refdes_db[c].value=PAGE_JMP*pages+COUNT_START; /*Reset the counters according to page numbers*/ 00114 } 00115 strcpy(&infilename[0],argv[optind]); /*Copy the filename to the buffer*/ 00116 if((infile=fopen(infilename, "r")) == NULL) /*Open file, use r+ for read and write*/ 00117 { 00118 perror("grenum: unable to open input file"); 00119 return FILE_OP_ERROR; 00120 } 00121 strcpy(&outfilename[0],&infilename[0]); 00122 if((outfile=fopen(strcat(&outfilename[0],".tmp"),"wb"))==NULL) 00123 { 00124 perror("grenum: could not create tmp file"); 00125 fclose(infile); /*Close the file*/ 00126 return FILE_OP_ERROR; 00127 } 00128 printf("grenum: processing file %s\n",&infilename[0]); 00129 while((ret=get_refdes_from_file(infile, &refdes, buff))!=END_OF_FILE) /*Read one line.*/ 00130 { /*Process starts here*/ 00131 #ifdef DEBUG 00132 printf("%s\n",&buff[0]); /*Print out what is read*/ 00133 #endif 00134 switch(ret) 00135 { 00136 case NOT_REFDES_LINE: 00137 if(fputs(buff,outfile)==-1) 00138 { 00139 perror("grenum: could not write to tmp file"); 00140 fclose(infile); /*Close the files*/ 00141 fclose(outfile); 00142 return FILE_OP_ERROR; 00143 } 00144 continue; 00145 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*/ 00146 c=refdes_lookup(refdes_db, &refdes); 00147 switch(c) 00148 { 00149 case REFDES_NOT_FOUND: /*No such prefix*/ 00150 strcpy(&refdes_db[refdes.prefixes].prefix[0],&refdes.prefix[0]); /*Register the prefix to the database*/ 00151 refdes_db[refdes.prefixes+1].prefix[0]='\0'; 00152 refdes_db[refdes.prefixes].value=refdes.value; /*Renumber... Finally :-)*/ 00153 break; 00154 case MAX_PREFIX_COUNT: /*Out of memory*/ 00155 printf("grenum: out of memory. Too much refdes prefixes.\n"); 00156 fclose(infile); /*Close the files*/ 00157 fclose(outfile); 00158 return OUT_OF_MEMORY; 00159 default: 00160 if(refdes.value-refdes_db[c].value==1) /*If we have the next value, don't do anything, just update the database.*/ 00161 { 00162 refdes_db[c].value=refdes.value; 00163 break; 00164 } 00165 /*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.*/ 00166 00167 for(i=refdes_db[c].value+1; i<refdes.value; ++i) 00168 { 00169 if(seek_value(c, infile, i, refdes_db)==VALUE_NOT_FOUND) 00170 { 00171 refdes_db[c].value=i-1; 00172 break; 00173 } 00174 } 00175 if(i!=refdes.value) 00176 flags|=GAP_DETECTED; 00177 else 00178 flags|=~GAP_DETECTED; 00179 break; 00180 } 00181 break; /*continue our job*/ 00182 case REFDES_WITHOUT_VALUE: 00183 c=refdes_lookup(refdes_db, &refdes); 00184 switch(c) 00185 { 00186 case -1: /*No such prefix*/ 00187 strcpy(&refdes_db[refdes.prefixes].prefix[0],&refdes.prefix[0]); 00188 refdes.value=++refdes_db[refdes.prefixes].value; 00189 refdes_db[refdes.prefixes+1].prefix[0]='\0'; 00190 break; 00191 case MAX_PREFIX_COUNT: 00192 printf("grenum: out of memory. Too much refdes prefixes.\n"); 00193 fclose(infile); /*Close the files*/ 00194 fclose(outfile); 00195 return OUT_OF_MEMORY; 00196 default: 00197 if((flags&GAP_DETECTED)==GAP_DETECTED) 00198 { 00199 for(i=refdes_db[c].value+1; seek_value(c, infile, i, refdes_db)!=VALUE_NOT_FOUND; ++i); 00200 refdes.value=refdes_db[c].value=i; 00201 } 00202 else 00203 refdes.value=++refdes_db[c].value; /*renumber*/ 00204 break; 00205 } 00206 sprintf(buff, "refdes=%s%d\n", &refdes.prefix[0], refdes.value); 00207 break; 00208 case REFDES_ERROR: /*e.g. awdf#$%WSf82f8 :-) No "=" signal in the refdes string.*/ 00209 printf("grenum: parse error\n"); 00210 fclose(infile); /*Close the files*/ 00211 fclose(outfile); 00212 return PARSE_ERROR; 00213 } 00214 if(fputs(buff,outfile)==-1) /*Finally, write the refdes line to the output file*/ 00215 { 00216 perror("grenum: could not write to tmp file"); 00217 fclose(infile); /*Close the files*/ 00218 fclose(outfile); 00219 return FILE_OP_ERROR; 00220 } 00221 } /*Process ends here*/ 00222 00223 fclose(outfile); 00224 strcpy(&buff[0],&infilename[0]); /*buff has the original infilename*/ 00225 /*The next few lines implements the copy program*/ 00226 fseek(infile,0L,SEEK_SET); /*Go to the begining of the infile*/ 00227 outfile=fopen(strcat(&buff[0],".save"),"wb"); 00228 if(outfile==NULL) 00229 { 00230 perror("grenum: ould not create backup file"); 00231 fclose(infile); /*Close the file*/ 00232 return FILE_OP_ERROR; 00233 } 00234 while(fgets(&buff[0],BUFFSIZE,infile)!=NULL) /*Read one line.*/ 00235 { 00236 if(fputs(&buff[0],outfile)==-1) 00237 { 00238 perror("grenum: could not write to backup file"); 00239 fclose(infile); /*Close the files*/ 00240 fclose(outfile); 00241 return FILE_OP_ERROR; 00242 } 00243 } 00244 fclose(infile); 00245 fclose(outfile); 00246 rename(outfilename, infilename); /*Move the tmpfile to the original*/ 00247 } 00248 printf("grenum: file(s) successfully processed\n"); 00249 return OK; /*Everything is okay*/ 00250 } 00251 00252 int get_refdes_from_file(FILE *fp, struct refdes_ *refdes, char *buff) 00253 { 00254 00255 /* Read one line from file, and return the following things: 00256 * 00257 * END_OF_FILE if file reaches its end. The content of buff is unknown! 00258 * 00259 * NOT_REFDES_LINE if the current line is not a refdes. The line will 00260 * saved in buff. 00261 * 00262 * Return according to parse_refdes(). The buff will contain the current line too. 00263 */ 00264 00265 if(fgets(buff, BUFFSIZE, fp)==NULL) 00266 return END_OF_FILE; 00267 if(strstr(buff, "refdes=")==NULL) 00268 return NOT_REFDES_LINE; 00269 return parse_refdes(refdes, buff); 00270 } 00271 00272 int seek_value(int prefix, FILE *fp, unsigned int value, struct refdes_ *db) 00273 { 00274 fpos_t filepos; 00275 int ret; 00276 struct refdes_ refdes; 00277 char buff[BUFFSIZE]; 00278 00279 fgetpos(fp, &filepos); /*First of all, save the file pos.*/ 00280 rewind(fp); /*Rewind*/ 00281 while((ret=get_refdes_from_file(fp, &refdes, buff))!=END_OF_FILE) 00282 { 00283 if(ret==REFDES_WITH_VALUE && prefix==refdes_lookup(db, &refdes) && refdes.value==value) 00284 { 00285 fsetpos(fp,&filepos); 00286 return VALUE_FOUND; 00287 } 00288 } 00289 fsetpos(fp,&filepos); 00290 return VALUE_NOT_FOUND; 00291 } 00292 00293 int parse_refdes(struct refdes_ *refdes, char *ref_str) 00294 { 00295 int i; 00296 char buff[BUFFSIZE],*cpr,*cp; 00297 00298 /* 00299 * This function parses the refdes line from the .sch file. It takes a pointer to the 00300 * complete refdes definition string, and a pointer which points to a refdes structure 00301 * where it'll store the info. 00302 * 00303 * parse_refdes() will return 00304 * 00305 * REFDES_WITH_VALUE if there was a prefix with renumbered value 00306 * (for example R1,IC3,U5); 00307 * 00308 * REFDES_WITHOUT_VALUE if there was a "?" mark found, and it has to be 00309 * renumbered (e.g. U?); 00310 * 00311 * REFDES_ERROR, if there was some uncool thing. 00312 * 00313 * The refdes structure is filled with the prefix and the value. 00314 * 00315 * Note that if a "?" is found, the value member remains untouched. 00316 */ 00317 00318 00319 cpr=strstr(ref_str,"="); /*seek for the "="*/ 00320 if(cpr==NULL) /*This should not happen*/ 00321 return REFDES_ERROR; 00322 cp=strstr(ref_str,"?"); 00323 /*refdes=U1 refdes=IC? 00324 * | | 00325 * *cpr cp 00326 */ 00327 if(cp!=NULL) 00328 { /*Not renumbered yet*/ 00329 strncpy(&refdes->prefix[0],cpr+1,cp-cpr-1); /*Copy the prefix to the refdes structure*/ 00330 refdes->prefix[cp-cpr-1]='\0'; 00331 00332 #ifdef DEBUG 00333 printf("Prefix=%s\n",&refdes->prefix[0]); 00334 #endif 00335 00336 return REFDES_WITHOUT_VALUE; 00337 } 00338 for(cp=cpr+1,i=0;(*cp != '\n' && *cp>='A' && *cp<='z');++i,++cp) /*No "?". Copy the prefix*/ 00339 buff[i]=*cp; /*Fill the buffer from char to char*/ 00340 buff[i]='\0'; /*Terminate with NULL to be a string*/ 00341 #ifdef DEBUG 00342 printf("Prefix=%s\n",&buff[0]); 00343 #endif 00344 strcpy(&refdes->prefix[0],&buff[0]); /*Copy to refdes structure*/ 00345 for(i=0,cp;(*cp != '\n' && *cp>='0' && *cp<='9');++cp,++i) 00346 buff[i]=*cp; /*Fill the buffer from char to char*/ 00347 buff[i]='\0'; /*Terminate with NULL to be a string*/ 00348 #ifdef DEBUG 00349 printf("Value=%s\n",&buff[0]); 00350 #endif 00351 refdes->value=abs(atoi(&buff[0])); 00352 return REFDES_WITH_VALUE; 00353 } 00354 00355 int refdes_lookup(struct refdes_ *db, struct refdes_ *ref) 00356 { 00357 int c=0; 00358 00359 for(c=0;c<MAX_PREFIX_COUNT;++c) 00360 { 00361 if(strcmp(ref->prefix,(*(db+c)).prefix)==0) 00362 break; 00363 else if((*(db+c)).prefix[0]=='\0') 00364 { 00365 ref->prefixes=c; 00366 return REFDES_NOT_FOUND; 00367 } 00368 } 00369 return c; 00370 } 00371 00372 void printhelp() 00373 { 00374 #ifdef HAVE_GETOPT_LONG 00375 const char *v_opt="-v | --version"; 00376 const char *h_opt="-h | --help"; 00377 const char *p_opt="-p | --pagejump"; 00378 #else 00379 const char *v_opt="-v"; 00380 const char *h_opt="-h"; 00381 const char *p_opt="-p"; 00382 #endif 00383 00384 printver(); 00385 printf("Usage: grenum [%s] [%s] [%s] file1.sch file2.sch ...\n\n", 00386 v_opt, h_opt, p_opt); 00387 printf("\t%s\tprints version info\n\t%s\tprints this help\n\t%s\tsets pagejump mode on\n", 00388 v_opt, h_opt, p_opt); 00389 printf("For more information read the README file and/or the manual.\n"); 00390 } 00391 00392 00393 void printver() 00394 { 00395 printf("This is grenum, an advanced refdes renumber utility for gEDA's gschem.\n"); 00396 printf("Version %s. gEDA/gaf version %s.%s\n",GRVERSION, 00397 PACKAGE_DOTTED_VERSION, PACKAGE_DATE_VERSION); 00398 printf("Compiled on %s at %s\n",COMP_DATE,COMP_TIME); 00399 }