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