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