support/librarian/sdcclib.c: Added option -l
[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 #define _POSIX_
19 #include <limits.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
24 #include <unistd.h>
25 #endif
26
27 char ProgName[PATH_MAX];
28 char LibName[PATH_MAX];
29 char LibNameTmp[PATH_MAX];
30 char IndexName[PATH_MAX];
31 char RelName[PATH_MAX];
32 char AdbName[PATH_MAX];
33 char ListName[PATH_MAX];
34
35 #define version "1.0"
36
37 #define OPT_ADD_REL 0
38 #define OPT_EXT_REL 1
39 #define OPT_DEL_REL 2
40 #define OPT_ADD_LIST 3
41 #define OPT_DUMP_SYM 4
42 #define OPT_DUMP_MOD 5
43
44 #define MAXLINE 254
45 #define EQ(A,B) !strcmp((A),(B))
46 #define NEQ(A,B) strcmp((A),(B))
47
48 int action=0;
49 FILE *lib, *newlib, *rel, *adb, *libindex;
50 char FLine[MAXLINE+1];
51 char ModName[MAXLINE+1];
52 int state=0;
53
54 void GetNameFromPath(char * path, char * name)
55 {
56         int i, j;
57
58         for(i=0; path[i]!=0; i++);
59         for(; (path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
60         for(j=0, i++; (path[i]!='.')&&(path[i]!=0); i++, j++) name[j]=path[i];
61         name[j]=0;
62 }
63
64 void ChangeExtension(char * path, char * ext)
65 {
66         int i;
67
68         for(i=0; path[i]!=0; i++);
69         for(; (path[i]!='.')&&(path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
70         if(path[i]=='.')
71         {
72             path[i+1]=0;
73         strcat(path, ext);
74         }
75         else
76         {
77             printf("ERROR: Filename '%s' must have an extension\n", path);
78             exit(1);
79         }
80 }
81
82 void CleanLine(char * buff)
83 {
84     int j, l;
85     l=strlen(buff);
86     for(j=0; j<l; j++)
87     {
88         if((buff[j]=='\n')||(buff[j]=='\r')) buff[j]=0;
89     }
90 }
91
92 int set_options (char * opt)
93 {
94         int rvalue=0, unknown=0;
95         static char Help[] =
96         "Usage: %s [-options] library relfile\n\n"
97         "available options:\n"
98         "a - Adds relfile to library.  If relfile exists, replaces it.\n"
99         "l - Adds relfile list to library.\n"
100         "d - Deletes relfile from library.\n"
101         "e - Extracts relfile from library.\n"
102         "s - Dumps symbols of library.\n"
103         "m - Dumps modules of library.\n"
104         "v - Displays program version.\n"
105         "h - This help.\n";
106
107         switch (opt[0])
108         {
109                 default:
110                     unknown=1;
111                 case 'h':
112                 case '?':
113                 case 'v':
114                     printf("%s: SDCC librarian version %s\n", ProgName, version);
115                     printf("by Jesus Calvino-Fraga\n\n");
116                         if (unknown) printf("Unknown option: %c\n", opt[0]);
117                     if (opt[0]=='v') exit(0);
118                         printf(Help, ProgName);
119                         exit(1);
120                 break;
121                 case 'a':
122                     action=OPT_ADD_REL;
123                 break;
124                 case 'l':
125                     action=OPT_ADD_LIST;
126                 break;
127                 case 'e':
128                     action=OPT_EXT_REL;
129                 break;
130                 case 'd':
131                     action=OPT_DEL_REL;
132                 break;
133                 case 's':
134                     action=OPT_DUMP_SYM;
135                 break;
136                 case 'm':
137                     action=OPT_DUMP_MOD;
138                 break;
139         }
140         return (rvalue);
141 }
142
143 void ProcLineOptions (int argc, char **argv)
144 {
145         int cont_par=0;
146         int i, j;
147
148         /*Get the program name*/
149     GetNameFromPath(argv[0], ProgName);
150
151         for (j=1; j<argc; j++)
152         {
153                 if(argv[j][0]=='-')
154                 {
155                         for(i=1; argv[j][i]!=0 ; i++)
156                                 if (set_options(&argv[j][i])) break;
157                 }
158                 else
159                 {
160                         switch(cont_par)
161                         {
162                                 case 0:
163                                         cont_par++;
164                                         strcpy(LibName, argv[j]);
165                                 break;
166
167                                 case 1:
168                                         cont_par++;
169                     if(action==OPT_ADD_LIST)
170                         strcpy(ListName, argv[j]);
171                     else
172                                             strcpy(RelName, argv[j]);
173                                 break;
174
175                                 default:
176                                         cont_par++;
177                                 break;
178                         }
179                 }
180         }
181
182         if ( (cont_par!=2) && (action<OPT_DUMP_SYM) )
183         {
184                 printf("ERROR: Too %s arguments.\n", cont_par<2?"few":"many");
185                 set_options("h"); /*Show help and exit*/
186         }
187         else if ( (cont_par!=1) && (action>=OPT_DUMP_SYM) )
188         {
189                 printf("ERROR: Too %s arguments.\n", cont_par<1?"few":"many");
190                 set_options("h"); /*Show help and exit*/
191         }
192 }
193
194 void AddRel(void)
195 {
196     int inrel=0;
197     long newlibpos, indexsize;
198     char symname[MAXLINE+1];
199     char c;
200     int IsDOSStyle=0;
201
202     strcpy(LibNameTmp, LibName);
203     ChangeExtension(LibNameTmp, "__L");
204
205     strcpy(IndexName, LibName);
206     ChangeExtension(IndexName, "__I");
207
208     strcpy(AdbName, RelName);
209     ChangeExtension(AdbName, "adb");
210
211     lib=fopen(LibName, "r");
212
213     if(action==OPT_ADD_REL)
214     {
215         rel=fopen(RelName, "r");
216         if(rel==NULL)
217         {
218             printf("ERROR: Couldn't open file '%s'\n", RelName);
219             if(lib!=NULL) fclose(lib);
220             return;
221         }
222     }
223     GetNameFromPath(RelName, ModName);
224
225     newlib=fopen(LibNameTmp, "w");
226     if(newlib==NULL)
227     {
228         printf("ERROR: Couldn't create temporary file '%s'\n", LibNameTmp);
229         if(lib!=NULL) fclose(lib);
230         fclose(rel);
231         return;
232     }
233     fprintf(newlib, "<FILES>\n\n");
234
235     libindex=fopen(IndexName, "w");
236     if(libindex==NULL)
237     {
238         printf("ERROR: Couldn't create temporary file '%s'\n", IndexName);
239         if(lib!=NULL) fclose(lib);
240         fclose(newlib);
241         fclose(rel);
242         return;
243     }
244
245     if(lib!=NULL) while(!feof(lib))
246     {
247         FLine[0]=0;
248         fgets(FLine, MAXLINE, lib);
249         CleanLine(FLine);
250
251         switch(state)
252         {
253             case 0:
254                 if(EQ(FLine, "<FILE>"))
255                 {
256                     FLine[0]=0;
257                     fgets(FLine, MAXLINE, lib);
258                     CleanLine(FLine);
259                     if(NEQ(FLine, ModName))
260                     {
261                         newlibpos=ftell(newlib);
262                         fprintf(newlib, "<FILE>\n%s\n", FLine);
263                         fprintf(libindex, "<MODULE>\n%s %ld\n", FLine, newlibpos);
264                         state++;
265                     }
266                 }                
267             break;
268             case 1:
269                 fprintf(newlib, "%s\n", FLine);
270                 if(EQ(FLine, "</FILE>"))
271                 {
272                     fprintf(newlib, "\n");
273                     fprintf(libindex, "</MODULE>\n\n");
274                     state=0;
275                     inrel=0;
276                 }
277                 else if(EQ(FLine, "<REL>")) inrel=1;
278                 else if(EQ(FLine, "</REL>")) inrel=0;
279                 if(inrel)
280                 {
281                     if(FLine[0]=='S')
282                     {
283                         sscanf(FLine, "S %s %c", symname, &c);
284                         if(c=='D') fprintf(libindex, "%s\n", symname);
285                     }
286                 }
287             break;
288         }
289     }
290
291     if(action==OPT_ADD_REL)
292     {
293         newlibpos=ftell(newlib);
294         fprintf(newlib, "<FILE>\n%s\n<REL>\n", ModName);
295         fprintf(libindex, "<MODULE>\n%s %ld\n", ModName, newlibpos);
296         while(!feof(rel))
297         {
298             FLine[0]=0;
299             fgets(FLine, MAXLINE, rel);
300             CleanLine(FLine);
301             if(strlen(FLine)>0)
302             {
303                 fprintf(newlib, "%s\n", FLine);
304             }
305             if(FLine[0]=='S')
306             {
307                 sscanf(FLine, "S %s %c", symname, &c);
308                 if(c=='D') fprintf(libindex, "%s\n", symname);
309             }
310         }
311         fclose(rel);
312         fprintf(libindex, "</MODULE>\n");
313         fprintf(newlib, "</REL>\n<ADB>\n");
314     
315         adb=fopen(AdbName, "r");
316         if(adb!=NULL)
317         {
318             while(!feof(rel))
319             {
320                 FLine[0]=0;
321                 fgets(FLine, MAXLINE, adb);
322                 CleanLine(FLine);
323                 if(strlen(FLine)>0)
324                 {
325                     fprintf(newlib, "%s\n", FLine);
326                 }
327             }
328             fclose(adb);
329         }
330         fprintf(newlib, "</ADB>\n</FILE>\n");
331     }
332
333     /*Put the temporary files together as a new library file*/
334     indexsize=ftell(libindex);
335     fflush(libindex);
336     fflush(newlib);
337     fclose(newlib);
338     if(lib!=NULL) fclose(lib);
339     fclose(libindex);
340
341     newlib=fopen(LibNameTmp, "r");
342     lib=fopen(LibName, "w");
343     libindex=fopen(IndexName, "r");
344
345     fprintf(lib, "<SDCCLIB>\n\n<INDEX>\n");
346
347     /*Find out if the \n is expanded to \r\n or not*/
348     if(ftell(lib)!=(long)strlen("<SDCCLIB>\n\n<INDEX>\n"))
349     {
350         IsDOSStyle=1;
351     }
352
353     indexsize+=ftell(lib)+strlen("0123456789\n\n</INDEX>\n\n");
354     if(IsDOSStyle) indexsize+=4;
355
356     fprintf(lib, "%10ld\n", indexsize);
357
358     while(!feof(libindex))
359     {
360         FLine[0]=0;
361         fgets(FLine, MAXLINE, libindex);
362         fprintf(lib, "%s", FLine);
363     }
364     fprintf(lib, "\n</INDEX>\n\n");
365
366     while(!feof(newlib))
367     {
368         FLine[0]=0;
369         fgets(FLine, MAXLINE, newlib);
370         fprintf(lib, "%s", FLine);
371     }
372     fprintf(lib, "\n</FILES>\n\n");
373     fprintf(lib, "</SDCCLIB>\n");
374
375     fclose(newlib);
376     fclose(lib);
377     fclose(libindex);
378
379     remove(LibNameTmp);
380     remove(IndexName);
381 }
382
383 void ExtractRel(void)
384 {
385     strcpy(AdbName, RelName);
386     ChangeExtension(AdbName, "adb");
387
388     lib=fopen(LibName, "r");
389     if(lib==NULL)
390     {
391         printf("ERROR: Couldn't open file '%s'\n", LibName);
392         return;
393     }
394
395     rel=fopen(RelName, "w");
396     if(rel==NULL)
397     {
398         printf("ERROR: Couldn't create file '%s'\n", RelName);
399         fclose(lib);
400         return;
401     }
402     GetNameFromPath(RelName, ModName);
403
404     adb=fopen(AdbName, "w");
405     if(adb==NULL)
406     {
407         printf("ERROR: Couldn't create file '%s'\n", AdbName);
408         fclose(lib);
409         fclose(rel);
410         return;
411     }
412
413     while(!feof(lib))
414     {
415         if(state==5) break;
416         FLine[0]=0;
417         fgets(FLine, MAXLINE, lib);
418         CleanLine(FLine);
419
420         switch(state)
421         {
422             case 0:
423                 if(EQ(FLine, "<FILE>"))
424                 {
425                     FLine[0]=0;
426                     fgets(FLine, MAXLINE, lib);
427                     CleanLine(FLine);
428                     if(EQ(FLine, ModName)) state=1;
429                 }                
430             break;
431             case 1:
432                 if(EQ(FLine, "<REL>")) state=2;
433             break;
434             case 2:
435                 if(EQ(FLine, "</REL>"))
436                     state=3;
437                 else
438                     fprintf(rel, "%s\n", FLine);
439             break;
440             case 3:
441                 if(EQ(FLine, "<ADB>")) state=4;
442             break;
443             case 4:
444                 if(EQ(FLine, "</ADB>"))
445                     state=5;
446                 else
447                     fprintf(adb, "%s\n", FLine);
448             break; 
449         }
450     }
451     
452     fclose(rel);
453     fclose(lib);
454     fclose(adb);
455 }
456
457 void DumpSymbols(void)
458 {
459     lib=fopen(LibName, "r");
460     if(lib==NULL)
461     {
462         printf("ERROR: Couldn't open file '%s'\n", LibName);
463         return;
464     }
465
466     FLine[0]=0;
467     fgets(FLine, MAXLINE, lib);
468     CleanLine(FLine);
469     if(NEQ(FLine, "<SDCCLIB>"))
470     {
471         printf("ERROR: File '%s' was not created with '%s'\n", LibName, ProgName); 
472         return;
473     }
474     
475     while(!feof(lib))
476     {
477         if(state==3) break;
478         FLine[0]=0;
479         fgets(FLine, MAXLINE, lib);
480         CleanLine(FLine);
481
482         switch(state)
483         {
484             case 0:
485                 if(EQ(FLine, "<INDEX>")) state=1;
486             break;
487             case 1:
488                 if(EQ(FLine, "<MODULE>"))
489                 {
490                     FLine[0]=0;
491                     fgets(FLine, MAXLINE, lib);
492                     sscanf(FLine, "%s", ModName);
493                     if(action==OPT_DUMP_SYM)
494                     {
495                         printf("%s.rel:\n", ModName);
496                         state=2;
497                     }
498                     else
499                     {
500                         printf("%s.rel\n", ModName);
501                     }
502                 }
503                 else if(EQ(FLine, "</INDEX>")) state=3;
504             break;
505             case 2:
506                 if(EQ(FLine, "</MODULE>"))
507                 {
508                     state=1;
509                     printf("\n");
510                 }
511                 else printf("   %s\n", FLine);
512             break;
513             default:
514                 state=3;
515             case 3:
516             break;
517         }
518     }
519     
520     fclose(lib);
521 }
522
523 int fileexist(char * fname)
524 {
525     FILE * fp;
526     
527     fp=fopen(fname, "r");
528     if(fp==NULL) return 0;
529     fclose(fp);
530     return 1;
531 }
532
533 void AddList(void)
534 {
535     FILE * list;
536
537     list=fopen(ListName, "r");
538     if(list==NULL)
539     {
540         printf("ERROR: Couldn't open list file '%s'\n", ListName);
541         return;
542     }
543
544     action=OPT_ADD_REL;
545     while(!feof(list))
546     {
547         RelName[0]=0;
548         fgets(RelName, PATH_MAX, list);
549         CleanLine(RelName);
550         if(strlen(RelName)>0) //Skip empty lines
551         {
552             if(strchr(RelName,'.')==NULL)
553             {
554                 //Try adding the default sdcc extensions
555                 strcat(RelName,".o");
556                 if(!fileexist(RelName))
557                     ChangeExtension(RelName, "rel");
558             }
559             printf("Adding: %s\n", RelName);
560             AddRel();
561         }
562     }
563     action=OPT_ADD_LIST;
564     fclose(list);
565 }
566
567 int main(int argc, char **argv)
568 {
569         ProcLineOptions (argc, argv);
570
571         switch(action)
572         {
573             default:
574                 action=OPT_ADD_REL;
575                 case OPT_ADD_REL:
576                 case OPT_DEL_REL:
577                     AddRel();
578                 break;
579                 
580         case OPT_ADD_LIST:
581             AddList();
582         break;
583
584                 case OPT_EXT_REL:
585             ExtractRel();
586         break;
587         
588                 case OPT_DUMP_SYM:
589                 case OPT_DUMP_MOD:
590                     DumpSymbols();
591                 break;
592         }
593         return 0; //Success!!!
594 }