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