utils

grenum.c

Go to the documentation of this file.
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     }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines