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