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