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