* support/librarian/sdcclib.c: moved include <limits.h> up to enable
[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 RelName[PATH_MAX];
32 char AdbName[PATH_MAX];
33
34 #define version "0.1"
35
36 #define OPT_ADD_REL 0
37 #define OPT_EXT_REL 1
38 #define OPT_DEL_REL 2
39 #define OPT_DUMP_SYM 3
40 #define OPT_DUMP_MOD 4
41
42 #define MAXLINE 254
43 #define EQ(A,B) !strcmp((A),(B))
44 #define NEQ(A,B) strcmp((A),(B))
45
46 int action=0;
47 FILE *lib, *newlib, *rel, *adb, *libindex;
48 char FLine[MAXLINE+1];
49 char ModName[MAXLINE+1];
50 int state=0;
51
52 void GetNameFromPath(char * path, char * name)
53 {
54         int i, j;
55
56         for(i=0; path[i]!=0; i++);
57         for(; (path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
58         for(j=0, i++; (path[i]!='.')&&(path[i]!=0); i++, j++) name[j]=path[i];
59         name[j]=0;
60 }
61
62 void ChangeExtension(char * path, char * ext)
63 {
64         int i;
65
66         for(i=0; path[i]!=0; i++);
67         for(; (path[i]!='.')&&(path[i]!='\\')&&(path[i]!='/')&&(i>=0); i--);
68         if(path[i]=='.')
69         {
70             path[i+1]=0;
71         strcat(path, ext);
72         }
73         else
74         {
75             printf("ERROR: Filename '%s' must have an extension\n", path);
76             exit(1);
77         }
78 }
79
80 void CleanLine(char * buff)
81 {
82     int j, l;
83     l=strlen(buff);
84     for(j=0; j<l; j++)
85     {
86         if((buff[j]=='\n')||(buff[j]=='\r')) buff[j]=0;
87     }
88 }
89
90 int set_options (char * opt)
91 {
92         int rvalue=0, unknown=0;
93         static char Help[] =
94         "Usage: %s [-options] library relfile\n\n"
95         "available options:\n"
96         "a - Adds relfile to library.  If relfile exists, replaces it.\n"
97         "d - Deletes relfile from library.\n"
98         "e - Extracts relfile from library.\n"
99         "s - Dumps symbols of library.\n"
100         "m - Dumps modules of library.\n"
101         "v - Displays program version.\n"
102         "h - This help.\n";
103
104         switch (opt[0])
105         {
106                 default:
107                     unknown=1;
108                 case 'h':
109                 case '?':
110                 case 'v':
111                     printf("%s: SDCC librarian version %s\n", ProgName, version);
112                     printf("by Jesus Calvino-Fraga\n\n");
113                         if (unknown) printf("Unknown option: %c\n", opt[0]);
114                     if (opt[0]=='v') exit(0);
115                         printf(Help, ProgName);
116                         exit(1);
117                 break;
118                 case 'a':
119                     action=OPT_ADD_REL;
120                 break;
121                 case 'e':
122                     action=OPT_EXT_REL;
123                 break;
124                 case 'd':
125                     action=OPT_DEL_REL;
126                 break;
127                 case 's':
128                     action=OPT_DUMP_SYM;
129                 break;
130                 case 'm':
131                     action=OPT_DUMP_MOD;
132                 break;
133         }
134         return (rvalue);
135 }
136
137 void ProcLineOptions (int argc, char **argv)
138 {
139         int cont_par=0;
140         int i, j;
141
142         /*Get the program name*/
143     GetNameFromPath(argv[0], ProgName);
144
145         for (j=1; j<argc; j++)
146         {
147                 if(argv[j][0]=='-')
148                 {
149                         for(i=1; argv[j][i]!=0 ; i++)
150                                 if (set_options(&argv[j][i])) break;
151                 }
152                 else
153                 {
154                         switch(cont_par)
155                         {
156                                 case 0:
157                                         cont_par++;
158                                         strcpy(LibName, argv[j]);
159                                 break;
160
161                                 case 1:
162                                         cont_par++;
163                                         strcpy(RelName, argv[j]);
164                                 break;
165
166                                 default:
167                                         cont_par++;
168                                 break;
169                         }
170                 }
171         }
172
173         if ( (cont_par!=2) && (action<OPT_DUMP_SYM) )
174         {
175                 printf("Error: Too %s arguments.\n", cont_par<2?"few":"many");
176                 set_options("h"); /*Show help and exit*/
177         }
178         else if ( (cont_par!=1) && (action>=OPT_DUMP_SYM) )
179         {
180                 printf("Error: Too %s arguments.\n", cont_par<1?"few":"many");
181                 set_options("h"); /*Show help and exit*/
182         }
183 }
184
185 void AddRel(void)
186 {
187     int inrel=0;
188     long newlibpos, indexsize;
189     char symname[MAXLINE+1];
190     char c;
191     int IsDOSStyle=0;
192
193     strcpy(LibNameTmp, LibName);
194     ChangeExtension(LibNameTmp, "__L");
195
196     strcpy(IndexName, LibName);
197     ChangeExtension(IndexName, "__I");
198
199     strcpy(AdbName, RelName);
200     ChangeExtension(AdbName, "adb");
201
202     lib=fopen(LibName, "r");
203
204     if(action==OPT_ADD_REL)
205     {
206         rel=fopen(RelName, "r");
207         if(rel==NULL)
208         {
209             printf("ERROR: Couldn't open file '%s'", RelName);
210             if(lib!=NULL) fclose(lib);
211             return;
212         }
213     }
214     GetNameFromPath(RelName, ModName);
215
216     newlib=fopen(LibNameTmp, "w");
217     if(newlib==NULL)
218     {
219         printf("ERROR: Couldn't create temporary file '%s'", LibNameTmp);
220         if(lib!=NULL) fclose(lib);
221         fclose(rel);
222         return;
223     }
224     fprintf(newlib, "<FILES>\n\n");
225
226     libindex=fopen(IndexName, "w");
227     if(libindex==NULL)
228     {
229         printf("ERROR: Couldn't create temporary file '%s'", IndexName);
230         if(lib!=NULL) fclose(lib);
231         fclose(newlib);
232         fclose(rel);
233         return;
234     }
235
236     if(lib!=NULL) while(!feof(lib))
237     {
238         FLine[0]=0;
239         fgets(FLine, MAXLINE, lib);
240         CleanLine(FLine);
241
242         switch(state)
243         {
244             case 0:
245                 if(EQ(FLine, "<FILE>"))
246                 {
247                     FLine[0]=0;
248                     fgets(FLine, MAXLINE, lib);
249                     CleanLine(FLine);
250                     if(NEQ(FLine, ModName))
251                     {
252                         newlibpos=ftell(newlib);
253                         fprintf(newlib, "<FILE>\n%s\n", FLine);
254                         fprintf(libindex, "<MODULE>\n%s %ld\n", FLine, newlibpos);
255                         state++;
256                     }
257                 }                
258             break;
259             case 1:
260                 fprintf(newlib, "%s\n", FLine);
261                 if(EQ(FLine, "</FILE>"))
262                 {
263                     fprintf(newlib, "\n");
264                     fprintf(libindex, "</MODULE>\n\n");
265                     state=0;
266                     inrel=0;
267                 }
268                 else if(EQ(FLine, "<REL>")) inrel=1;
269                 else if(EQ(FLine, "</REL>")) inrel=0;
270                 if(inrel)
271                 {
272                     if(FLine[0]=='S')
273                     {
274                         sscanf(FLine, "S %s %c", symname, &c);
275                         if(c=='D') fprintf(libindex, "%s\n", symname);
276                     }
277                 }
278             break;
279         }
280     }
281
282     if(action==OPT_ADD_REL)
283     {
284         newlibpos=ftell(newlib);
285         fprintf(newlib, "<FILE>\n%s\n<REL>\n", ModName);
286         fprintf(libindex, "<MODULE>\n%s %ld\n", ModName, newlibpos);
287         while(!feof(rel))
288         {
289             FLine[0]=0;
290             fgets(FLine, MAXLINE, rel);
291             CleanLine(FLine);
292             if(strlen(FLine)>0)
293             {
294                 fprintf(newlib, "%s\n", FLine);
295             }
296             if(FLine[0]=='S')
297             {
298                 sscanf(FLine, "S %s %c", symname, &c);
299                 if(c=='D') fprintf(libindex, "%s\n", symname);
300             }
301         }
302         fclose(rel);
303         fprintf(libindex, "</MODULE>\n");
304         fprintf(newlib, "</REL>\n<ADB>\n");
305     
306         adb=fopen(AdbName, "r");
307         if(adb!=NULL)
308         {
309             while(!feof(rel))
310             {
311                 FLine[0]=0;
312                 fgets(FLine, MAXLINE, adb);
313                 CleanLine(FLine);
314                 if(strlen(FLine)>0)
315                 {
316                     fprintf(newlib, "%s\n", FLine);
317                 }
318             }
319             fclose(adb);
320         }
321         fprintf(newlib, "</ADB>\n</FILE>\n");
322     }
323
324     /*Put the temporary files together as a new library file*/
325     indexsize=ftell(libindex);
326     fflush(libindex);
327     fflush(newlib);
328     fclose(newlib);
329     if(lib!=NULL) fclose(lib);
330     fclose(libindex);
331
332     newlib=fopen(LibNameTmp, "r");
333     lib=fopen(LibName, "w");
334     libindex=fopen(IndexName, "r");
335
336     fprintf(lib, "<SDCCLIB>\n\n<INDEX>\n");
337
338     /*Find out if the \n is expanded to \r\n or not*/
339     if(ftell(lib)!=(long)strlen("<SDCCLIB>\n\n<INDEX>\n"))
340     {
341         IsDOSStyle=1;
342     }
343
344     indexsize+=ftell(lib)+strlen("0123456789\n\n</INDEX>\n\n");
345     if(IsDOSStyle) indexsize+=4;
346
347     fprintf(lib, "%10ld\n", indexsize);
348
349     while(!feof(libindex))
350     {
351         FLine[0]=0;
352         fgets(FLine, MAXLINE, libindex);
353         fprintf(lib, "%s", FLine);
354     }
355     fprintf(lib, "\n</INDEX>\n\n");
356
357     while(!feof(newlib))
358     {
359         FLine[0]=0;
360         fgets(FLine, MAXLINE, newlib);
361         fprintf(lib, "%s", FLine);
362     }
363     fprintf(lib, "\n</FILES>\n\n");
364     fprintf(lib, "</SDCCLIB>\n");
365
366     fclose(newlib);
367     fclose(lib);
368     fclose(libindex);
369
370     unlink(LibNameTmp);
371     unlink(IndexName);
372 }
373
374 void ExtractRel(void)
375 {
376     strcpy(AdbName, RelName);
377     ChangeExtension(AdbName, "adb");
378
379     lib=fopen(LibName, "r");
380     if(lib==NULL)
381     {
382         printf("ERROR: Couldn't open file '%s'", LibName);
383         return;
384     }
385
386     rel=fopen(RelName, "w");
387     if(rel==NULL)
388     {
389         printf("ERROR: Couldn't create file '%s'", RelName);
390         fclose(lib);
391         return;
392     }
393     GetNameFromPath(RelName, ModName);
394
395     adb=fopen(AdbName, "w");
396     if(adb==NULL)
397     {
398         printf("ERROR: Couldn't create file '%s'", AdbName);
399         fclose(lib);
400         fclose(rel);
401         return;
402     }
403
404     while(!feof(lib))
405     {
406         if(state==5) break;
407         FLine[0]=0;
408         fgets(FLine, MAXLINE, lib);
409         CleanLine(FLine);
410
411         switch(state)
412         {
413             case 0:
414                 if(EQ(FLine, "<FILE>"))
415                 {
416                     FLine[0]=0;
417                     fgets(FLine, MAXLINE, lib);
418                     CleanLine(FLine);
419                     if(EQ(FLine, ModName)) state=1;
420                 }                
421             break;
422             case 1:
423                 if(EQ(FLine, "<REL>")) state=2;
424             break;
425             case 2:
426                 if(EQ(FLine, "</REL>"))
427                     state=3;
428                 else
429                     fprintf(rel, "%s\n", FLine);
430             break;
431             case 3:
432                 if(EQ(FLine, "<ADB>")) state=4;
433             break;
434             case 4:
435                 if(EQ(FLine, "</ADB>"))
436                     state=5;
437                 else
438                     fprintf(adb, "%s\n", FLine);
439             break; 
440         }
441     }
442     
443     fclose(rel);
444     fclose(lib);
445     fclose(adb);
446 }
447
448 void DumpSymbols(void)
449 {
450     lib=fopen(LibName, "r");
451     if(lib==NULL)
452     {
453         printf("ERROR: Couldn't open file '%s'", LibName);
454         return;
455     }
456
457     while(!feof(lib))
458     {
459         if(state==3) break;
460         FLine[0]=0;
461         fgets(FLine, MAXLINE, lib);
462         CleanLine(FLine);
463
464         switch(state)
465         {
466             case 0:
467                 if(EQ(FLine, "<INDEX>")) state=1;
468             break;
469             case 1:
470                 if(EQ(FLine, "<MODULE>"))
471                 {
472                     FLine[0]=0;
473                     fgets(FLine, MAXLINE, lib);
474                     sscanf(FLine, "%s", ModName);
475                     if(action==OPT_DUMP_SYM)
476                     {
477                         printf("%s.rel:\n", ModName);
478                         state=2;
479                     }
480                     else
481                     {
482                         printf("%s.rel\n", ModName);
483                     }
484                 }
485                 else if(EQ(FLine, "</INDEX>")) state=3;
486             break;
487             case 2:
488                 if(EQ(FLine, "</MODULE>"))
489                 {
490                     state=1;
491                     printf("\n");
492                 }
493                 else printf("   %s\n", FLine);
494             break;
495             default:
496                 state=3;
497             case 3:
498             break;
499         }
500     }
501     
502     fclose(lib);
503 }
504
505 int main(int argc, char **argv)
506 {
507         ProcLineOptions (argc, argv);
508
509         switch(action)
510         {
511             default:
512                 action=OPT_ADD_REL;
513                 case OPT_ADD_REL:
514                 case OPT_DEL_REL:
515                     AddRel();
516                 break;
517                 
518                 case OPT_EXT_REL:
519             ExtractRel();
520         break;
521         
522                 case OPT_DUMP_SYM:
523                 case OPT_DUMP_MOD:
524                     DumpSymbols();
525                 break;
526         }
527         return 0; //Success!!!
528 }