fclose FILE * != NULL
[fw/sdcc] / support / librarian / sdcclib.c
1 /* sdcclib.c: sdcc librarian
2    Copyright (C) 2003, Jesus Calvino-Fraga jesusc(at)ece.ubc.ca
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any
7 later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #define _POSIX_
22 #include <limits.h>
23
24 char ProgName[PATH_MAX];
25 char LibName[PATH_MAX];
26 char LibNameTmp[PATH_MAX];
27 char IndexName[PATH_MAX];
28 char RelName[PATH_MAX];
29 char AdbName[PATH_MAX];
30
31 #define version "0.1"
32
33 #define OPT_ADD_REL 0
34 #define OPT_EXT_REL 1
35 #define OPT_DEL_REL 2
36 #define OPT_DUMP_SYM 3
37 #define OPT_DUMP_MOD 4
38
39 #define MAXLINE 254
40 #define EQ(A,B) !strcmp((A),(B))
41 #define NEQ(A,B) strcmp((A),(B))
42
43 int action=0;
44 FILE *lib, *newlib, *rel, *adb, *libindex;
45 char FLine[MAXLINE+1];
46 char ModName[MAXLINE+1];
47 int state=0;
48
49 void GetNameFromPath(char * path, char * name)
50 {
51         int i, j;
52
53         for(i=0; path[i]!=0; i++);
54         for(; (path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
55         for(j=0, i++; (path[i]!='.')&&(path[i]!=0); i++, j++) name[j]=path[i];
56         name[j]=0;
57 }
58
59 void ChangeExtension(char * path, char * ext)
60 {
61         int i, j;
62
63         for(i=0; path[i]!=0; i++);
64         for(; (path[i]!='.')&&(path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
65         if(path[i]=='.')
66         {
67             path[i+1]=0;
68         strcat(path, ext);
69         }
70         else
71         {
72             printf("ERROR: Filename '%s' must have an extension\n", path);
73             exit(1);
74         }
75 }
76
77 void CleanLine(char * buff)
78 {
79     int j, l;
80     l=strlen(buff);
81     for(j=0; j<l; j++)
82     {
83         if((buff[j]=='\n')||(buff[j]=='\r')) buff[j]=0;
84     }
85 }
86
87 int set_options (char * opt)
88 {
89         char temp[255];
90         int rvalue=0, unknown=0;
91         static char Help[] =
92         "Usage: %s [-options] library relfile\n\n"
93         "available options:\n"
94         "a - Adds relfile to library.  If relfile exists, replaces it.\n"
95         "d - Deletes relfile from library.\n"
96         "e - Extracts relfile from library.\n"
97         "s - Dumps symbols of library.\n"
98         "m - Dumps modules of library.\n"
99         "v - Displays program version.\n"
100         "h - This help.\n";
101
102         switch (opt[0])
103         {
104                 default:
105                     unknown=1;
106                 case 'h':
107                 case '?':
108                 case 'v':
109                     printf("%s: SDCC librarian version %s\n", ProgName, version);
110                     printf("by Jesus Calvino-Fraga\n\n");
111                         if (unknown) printf("Unknown option: %c\n", opt[0]);
112                     if (opt[0]=='v') exit(0);
113                         printf(Help, ProgName);
114                         exit(1);
115                 break;
116                 case 'a':
117                     action=OPT_ADD_REL;
118                 break;
119                 case 'e':
120                     action=OPT_EXT_REL;
121                 break;
122                 case 'd':
123                     action=OPT_DEL_REL;
124                 break;
125                 case 's':
126                     action=OPT_DUMP_SYM;
127                 break;
128                 case 'm':
129                     action=OPT_DUMP_MOD;
130                 break;
131         }
132         return (rvalue);
133 }
134
135 void ProcLineOptions (int argc, char **argv)
136 {
137         int cont_par=0;
138         int i, j;
139
140         /*Get the program name*/
141     GetNameFromPath(argv[0], ProgName);
142
143         for (j=1; j<argc; j++)
144         {
145                 if(argv[j][0]=='-')
146                 {
147                         for(i=1; argv[j][i]!=0 ; i++)
148                                 if (set_options(&argv[j][i])) break;
149                 }
150                 else
151                 {
152                         switch(cont_par)
153                         {
154                                 case 0:
155                                         cont_par++;
156                                         strcpy(LibName, argv[j]);
157                                 break;
158
159                                 case 1:
160                                         cont_par++;
161                                         strcpy(RelName, argv[j]);
162                                 break;
163
164                                 default:
165                                         cont_par++;
166                                 break;
167                         }
168                 }
169         }
170
171         if ( (cont_par!=2) && (action<OPT_DUMP_SYM) )
172         {
173                 printf("Error: Too %s arguments.\n", cont_par<2?"few":"many");
174                 set_options("h"); /*Show help and exit*/
175         }
176         else if ( (cont_par!=1) && (action>=OPT_DUMP_SYM) )
177         {
178                 printf("Error: Too %s arguments.\n", cont_par<1?"few":"many");
179                 set_options("h"); /*Show help and exit*/
180         }
181 }
182
183 void AddRel(void)
184 {
185     int inrel=0;
186     long newlibpos, indexsize;
187     char symname[MAXLINE+1];
188     char c;
189
190     strcpy(LibNameTmp, LibName);
191     ChangeExtension(LibNameTmp, "__L");
192
193     strcpy(IndexName, LibName);
194     ChangeExtension(IndexName, "__I");
195
196     strcpy(AdbName, RelName);
197     ChangeExtension(AdbName, "adb");
198
199     lib=fopen(LibName, "r");
200
201     if(action==OPT_ADD_REL)
202     {
203         rel=fopen(RelName, "r");
204         if(rel==NULL)
205         {
206             printf("ERROR: Couldn't open file '%s'", RelName);
207             if(lib!=NULL) fclose(lib);
208             return;
209         }
210     }
211     GetNameFromPath(RelName, ModName);
212
213     newlib=fopen(LibNameTmp, "w");
214     if(newlib==NULL)
215     {
216         printf("ERROR: Couldn't create temporary file '%s'", LibNameTmp);
217         if(lib!=NULL) fclose(lib);
218         fclose(rel);
219         return;
220     }
221     fprintf(newlib, "<FILES>\n\n");
222
223     libindex=fopen(IndexName, "w");
224     if(libindex==NULL)
225     {
226         printf("ERROR: Couldn't create temporary file '%s'", IndexName);
227         if(lib!=NULL) fclose(lib);
228         fclose(newlib);
229         fclose(rel);
230         return;
231     }
232
233     if(lib!=NULL) while(!feof(lib))
234     {
235         FLine[0]=0;
236         fgets(FLine, MAXLINE, lib);
237         CleanLine(FLine);
238
239         switch(state)
240         {
241             case 0:
242                 if(EQ(FLine, "<FILE>"))
243                 {
244                     FLine[0]=0;
245                     fgets(FLine, MAXLINE, lib);
246                     CleanLine(FLine);
247                     if(NEQ(FLine, ModName))
248                     {
249                         newlibpos=ftell(newlib);
250                         fprintf(newlib, "<FILE>\n%s\n", FLine);
251                         fprintf(libindex, "<MODULE>\n%s %ld\n", FLine, newlibpos);
252                         state++;
253                     }
254                 }                
255             break;
256             case 1:
257                 fprintf(newlib, "%s\n", FLine);
258                 if(EQ(FLine, "</FILE>"))
259                 {
260                     fprintf(newlib, "\n");
261                     fprintf(libindex, "</MODULE>\n\n");
262                     state=0;
263                     inrel=0;
264                 }
265                 else if(EQ(FLine, "<REL>")) inrel=1;
266                 else if(EQ(FLine, "</REL>")) inrel=0;
267                 if(inrel)
268                 {
269                     if(FLine[0]=='S')
270                     {
271                         sscanf(FLine, "S %s %c", symname, &c);
272                         if(c=='D') fprintf(libindex, "%s\n", symname);
273                     }
274                 }
275             break;
276         }
277     }
278
279     if(action==OPT_ADD_REL)
280     {
281         newlibpos=ftell(newlib);
282         fprintf(newlib, "<FILE>\n%s\n<REL>\n", ModName);
283         fprintf(libindex, "<MODULE>\n%s %ld\n", ModName, newlibpos);
284         while(!feof(rel))
285         {
286             FLine[0]=0;
287             fgets(FLine, MAXLINE, rel);
288             CleanLine(FLine);
289             if(strlen(FLine)>0)
290             {
291                 fprintf(newlib, "%s\n", FLine);
292             }
293             if(FLine[0]=='S')
294             {
295                 sscanf(FLine, "S %s %c", symname, &c);
296                 if(c=='D') fprintf(libindex, "%s\n", symname);
297             }
298         }
299         fclose(rel);
300         fprintf(libindex, "</MODULE>\n");
301         fprintf(newlib, "</REL>\n<ADB>\n");
302     
303         adb=fopen(AdbName, "r");
304         if(adb!=NULL)
305         {
306             while(!feof(rel))
307             {
308                 FLine[0]=0;
309                 fgets(FLine, MAXLINE, adb);
310                 CleanLine(FLine);
311                 if(strlen(FLine)>0)
312                 {
313                     fprintf(newlib, "%s\n", FLine);
314                 }
315             }
316             fclose(adb);
317         }
318         fprintf(newlib, "</ADB>\n</FILE>\n");
319     }
320
321     /*Put the temporary files together as a new library file*/
322     indexsize=ftell(libindex);
323     fflush(libindex);
324     fflush(newlib);
325     fclose(newlib);
326     if(lib!=NULL) fclose(lib);
327     fclose(libindex);
328
329     newlib=fopen(LibNameTmp, "r");
330     lib=fopen(LibName, "w");
331     libindex=fopen(IndexName, "r");
332
333     fprintf(lib, "<SDCCLIB>\n\n");
334     fprintf(lib, "<INDEX>\n");
335
336     indexsize+=ftell(lib)+12+14;
337     fprintf(lib, "%10ld\n", indexsize);
338
339     while(!feof(libindex))
340     {
341         FLine[0]=0;
342         fgets(FLine, MAXLINE, libindex);
343         fprintf(lib, "%s", FLine);
344     }
345     fprintf(lib, "\n</INDEX>\n\n");
346
347     while(!feof(newlib))
348     {
349         FLine[0]=0;
350         fgets(FLine, MAXLINE, newlib);
351         fprintf(lib, "%s", FLine);
352     }
353     fprintf(lib, "\n</FILES>\n\n");
354     fprintf(lib, "</SDCCLIB>\n");
355
356     fclose(newlib);
357     fclose(lib);
358     fclose(libindex);
359
360     unlink(LibNameTmp);
361     unlink(IndexName);
362 }
363
364 void ExtractRel(void)
365 {
366     strcpy(AdbName, RelName);
367     ChangeExtension(AdbName, "adb");
368
369     lib=fopen(LibName, "r");
370     if(lib==NULL)
371     {
372         printf("ERROR: Couldn't open file '%s'", LibName);
373         return;
374     }
375
376     rel=fopen(RelName, "w");
377     if(rel==NULL)
378     {
379         printf("ERROR: Couldn't create file '%s'", RelName);
380         fclose(lib);
381         return;
382     }
383     GetNameFromPath(RelName, ModName);
384
385     adb=fopen(AdbName, "w");
386     if(adb==NULL)
387     {
388         printf("ERROR: Couldn't create file '%s'", AdbName);
389         fclose(lib);
390         fclose(rel);
391         return;
392     }
393
394     while(!feof(lib))
395     {
396         if(state==5) break;
397         FLine[0]=0;
398         fgets(FLine, MAXLINE, lib);
399         CleanLine(FLine);
400
401         switch(state)
402         {
403             case 0:
404                 if(EQ(FLine, "<FILE>"))
405                 {
406                     FLine[0]=0;
407                     fgets(FLine, MAXLINE, lib);
408                     CleanLine(FLine);
409                     if(EQ(FLine, ModName)) state=1;
410                 }                
411             break;
412             case 1:
413                 if(EQ(FLine, "<REL>")) state=2;
414             break;
415             case 2:
416                 if(EQ(FLine, "</REL>"))
417                     state=3;
418                 else
419                     fprintf(rel, "%s\n", FLine);
420             break;
421             case 3:
422                 if(EQ(FLine, "<ADB>")) state=4;
423             break;
424             case 4:
425                 if(EQ(FLine, "</ADB>"))
426                     state=5;
427                 else
428                     fprintf(adb, "%s\n", FLine);
429             break; 
430         }
431     }
432     
433     fclose(rel);
434     fclose(lib);
435     fclose(adb);
436 }
437
438 void DumpSymbols(void)
439 {
440     lib=fopen(LibName, "r");
441     if(lib==NULL)
442     {
443         printf("ERROR: Couldn't open file '%s'", LibName);
444         return;
445     }
446
447     while(!feof(lib))
448     {
449         if(state==3) break;
450         FLine[0]=0;
451         fgets(FLine, MAXLINE, lib);
452         CleanLine(FLine);
453
454         switch(state)
455         {
456             case 0:
457                 if(EQ(FLine, "<INDEX>")) state=1;
458             break;
459             case 1:
460                 if(EQ(FLine, "<MODULE>"))
461                 {
462                     FLine[0]=0;
463                     fgets(FLine, MAXLINE, lib);
464                     sscanf(FLine, "%s", ModName);
465                     if(action==OPT_DUMP_SYM)
466                     {
467                         printf("%s.rel:\n", ModName);
468                         state=2;
469                     }
470                     else
471                     {
472                         printf("%s.rel\n", ModName);
473                     }
474                 }
475                 else if(EQ(FLine, "</INDEX>")) state=3;
476             break;
477             case 2:
478                 if(EQ(FLine, "</MODULE>"))
479                 {
480                     state=1;
481                     printf("\n");
482                 }
483                 else printf("   %s\n", FLine);
484             break;
485             default:
486                 state=3;
487             case 3:
488             break;
489         }
490     }
491     
492     fclose(lib);
493 }
494
495 int main(int argc, char **argv)
496 {
497         ProcLineOptions (argc, argv);
498
499         switch(action)
500         {
501             default:
502                 action=OPT_ADD_REL;
503                 case OPT_ADD_REL:
504                 case OPT_DEL_REL:
505                     AddRel();
506                 break;
507                 
508                 case OPT_EXT_REL:
509             ExtractRel();
510         break;
511         
512                 case OPT_DUMP_SYM:
513                 case OPT_DUMP_MOD:
514                     DumpSymbols();
515                 break;
516         }
517         return 0; //Success!!!
518 }