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