Initial revision
[fw/sdcc] / link / z80 / lklibr.c
1 /* lklibr.c */
2
3 /*
4  * (C) Copyright 1989-1995
5  * All Rights Reserved
6  *
7  * Alan R. Baldwin
8  * 721 Berkeley St.
9  * Kent, Ohio  44240
10  *
11  * With contributions for the
12  * object libraries from
13  * Ken Hornstein
14  * kenh@cmf.nrl.navy.mil
15  *
16  */
17
18 /*
19  * Extensions: P. Felber
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <alloc.h>
25 #include "aslink.h"
26
27 /*)Module       lklibr.c
28  *
29  *      The module lklibr.c contains the functions which
30  *      (1) specify the path(s) to library files [.LIB]
31  *      (2) specify the library file(s) [.LIB] to search
32  *      (3) search the library files for specific symbols
33  *          and link the module containing this symbol
34  *
35  *      lklibr.c contains the following functions:
36  *              VOID    addpath()
37  *              VOID    addlib()
38  *              VOID    addfile()
39  *              VOID    search()
40  *              VOID    fndsym()
41  *              VOID    library()
42  *              VOID    loadfile()
43  *
44  */
45
46 #ifdef INDEXLIB
47 typedef struct slibrarysymbol mlibrarysymbol;
48 typedef struct slibrarysymbol *pmlibrarysymbol;
49
50 struct slibrarysymbol {
51         char name[40];
52         pmlibrarysymbol next;
53 };
54
55 typedef struct slibraryfile mlibraryfile;
56 typedef struct slibraryfile *pmlibraryfile;
57
58 struct slibraryfile {
59         int loaded;
60         char *libspc;
61         char *str;
62         char relfil[80];
63         char filename[80];
64         pmlibrarysymbol symbols;
65         pmlibraryfile next;
66 };
67
68 int buildlibraryindex();
69 #endif /* INDEXLIB */
70
71 /*)Function     VOID    addpath()
72  *
73  *      The function addpath() creates a linked structure containing
74  *      the paths to various object module library files.
75  *
76  *      local variables:
77  *              lbpath  *lbph           pointer to new path structure
78  *              lbpath  *lbp            temporary pointer
79  *
80  *      global variables:
81  *              lbpath  *lbphead        The pointer to the first
82  *                                      path structure
83  *
84  *       functions called:
85  *              char    getnb()         lklex.c
86  *              VOID *  new()           lksym.c
87  *              int     strlen()        c_library
88  *              char *  strcpy()        c_library
89  *              VOID    unget()         lklex.c
90  *
91  *      side effects:
92  *              An lbpath structure may be created.
93  */
94
95 VOID
96 addpath()
97 {
98         struct lbpath *lbph, *lbp;
99
100         lbph = (struct lbpath *) new (sizeof(struct lbpath));
101         if (lbphead == NULL) {
102                 lbphead = lbph;
103         } else {
104                 lbp = lbphead;
105                 while (lbp->next)
106                         lbp = lbp->next;
107                 lbp->next = lbph;
108         }
109         unget(getnb());
110         lbph->path = (char *) new (strlen(ip)+1);
111         strcpy(lbph->path, ip);
112 }
113
114 /*)Function     VOID    addlib()
115  *
116  *      The function addlib() tests for the existance of a
117  *      library path structure to determine the method of
118  *      adding this library file to the library search structure.
119  *
120  *      This function calls the function addfile() to actually
121  *      add the library file to the search list.
122  *
123  *      local variables:
124  *              lbpath  *lbph           pointer to path structure
125  *
126  *      global variables:
127  *              lbpath  *lbphead        The pointer to the first
128  *                                      path structure
129  *
130  *       functions called:
131  *              VOID    addfile()       lklibr.c
132  *              char    getnb()         lklex.c
133  *              VOID    unget()         lklex.c
134  *
135  *      side effects:
136  *              The function addfile() may add the file to
137  *              the library search list.
138  */
139
140 VOID
141 addlib()
142 {
143         struct lbpath *lbph;
144
145         unget(getnb());
146
147         if (lbphead == NULL) {
148                 addfile(NULL,ip);
149                 return;
150         }       
151         for (lbph=lbphead; lbph; lbph=lbph->next) {
152                 addfile(lbph->path,ip);
153         }
154 }
155
156 /*)Function     VOID    addfile(path,libfil)
157  *
158  *              char    *path           library path specification
159  *              char    *libfil         library file specification
160  *
161  *      The function addfile() searches for the library file
162  *      by concatenating the path and libfil specifications.
163  *      if the library is found, an lbname structure is created
164  *      and linked to any previously defined structures.  This
165  *      linked list is used by the function fndsym() to attempt
166  *      to find any undefined symbols.
167  *
168  *      The function does not give report an error on invalid
169  *      path / file specifications or if the file is not found.
170  *
171  *      local variables:
172  *              lbname  *lbnh           pointer to new name structure
173  *              lbname  *lbn            temporary pointer
174  *
175  *      global variables:
176  *              lbname  *lbnhead        The pointer to the first
177  *                                      path structure
178  *
179  *       functions called:
180  *              char    getnb()         lklex.c
181  *              VOID *  new()           lksym.c
182  *              int     strlen()        c_library
183  *              char *  strcpy()        c_library
184  *              VOID    unget()         lklex.c
185  *
186  *      side effects:
187  *              An lbname structure may be created.
188  */
189
190 VOID
191 addfile(path,libfil)
192 char *path;
193 char *libfil;
194 {
195         FILE *fp;
196         char *str;
197         struct lbname *lbnh, *lbn;
198
199         if ((path != NULL) && (strchr(libfil,':') == NULL)){
200                 str = (char *) new (strlen(path) + strlen(libfil) + 6);
201                 strcpy(str,path);
202 #ifdef  OTHERSYSTEM
203 #ifdef SDK
204 #ifdef UNIX
205                 if (str[strlen(str)-1] != '/') {
206                         strcat(str,"/");
207 #else /* UNIX */
208                 if (str[strlen(str)-1] != '\\') {
209                         strcat(str,"\\");
210 #endif /* UNIX */
211 #else /* SDK */
212                 if (str[strlen(str)-1] != '\\') {
213                         strcat(str,"\\");
214 #endif /* SDK */
215                 }
216 #endif
217         } else {
218                 str = (char *) new (strlen(libfil) + 5);
219         }
220 #ifdef  OTHERSYSTEM
221 #ifdef SDK
222 #ifdef UNIX
223         if (libfil[0] == '/') { libfil++; }
224 #else /* UNIX */
225         if (libfil[0] == '\\') { libfil++; }
226 #endif /* UNIX */
227 #else /* SDK */
228         if (libfil[0] == '\\') { libfil++; }
229 #endif /* SDK */
230 #endif
231         strcat(str,libfil);
232         if(strchr(str,FSEPX) == NULL) {
233                 sprintf(&str[strlen(str)], "%clib", FSEPX);
234         }
235         if ((fp = fopen(str, "r")) != NULL) {
236                 fclose(fp);
237                 lbnh = (struct lbname *) new (sizeof(struct lbname));
238                 if (lbnhead == NULL) {
239                         lbnhead = lbnh;
240                 } else {
241                         lbn = lbnhead;
242                         while (lbn->next)
243                                 lbn = lbn->next;
244                         lbn->next = lbnh;
245                 }
246                 if ((path != NULL) && (strchr(libfil,':') == NULL)){
247                         lbnh->path = path;
248                 }
249                 lbnh->libfil = (char *) new (strlen(libfil) + 1);
250                 strcpy(lbnh->libfil,libfil);
251                 lbnh->libspc = str;
252         } else {
253                 free(str);
254         }
255 }
256
257 /*)Function     VOID    search()
258  *
259  *      The function search() looks through all the symbol tables
260  *      at the end of pass 1.  If any undefined symbols are found
261  *      then the function fndsym() is called. Function fndsym()
262  *      searches any specified library files to automagically
263  *      import the object modules containing the needed symbol.
264  *
265  *      After a symbol is found and imported by the function
266  *      fndsym() the symbol tables are again searched.  The
267  *      symbol tables are search until no more symbols can be
268  *      resolved within the library files.  This ensures that
269  *      back references from one library module to another are
270  *      also resolved.
271  *
272  *      local variables:
273  *              int     i               temporary counter
274  *              sym     *sp             pointer to a symbol structure
275  *              int     symfnd          found a symbol flag
276  *
277  *      global variables:
278  *              sym     *symhash[]      array of pointers to symbol tables
279  *
280  *       functions called:
281  *              int     fndsym()        lklibr.c
282  *
283  *      side effects:
284  *              If a symbol is found then the library object module
285  *              containing the symbol will be imported and linked.
286  */
287
288 VOID
289 search()
290 {
291         register struct sym *sp;
292         register i,symfnd;
293
294         /*
295          * Look for undefined symbols.  Keep
296          * searching until no more symbols are resolved.
297          */
298         symfnd = 1;
299         while (symfnd) {
300                 symfnd = 0;
301                 /*
302                  * Look through all the symbols
303                  */
304                 for (i=0; i<NHASH; ++i) {
305                         sp = symhash[i];
306                         while (sp) {
307                                 /* If we find an undefined symbol
308                                  * (one where S_DEF is not set), then
309                                  * try looking for it.  If we find it
310                                  * in any of the libraries then
311                                  * increment symfnd.  This will force
312                                  * another pass of symbol searching and
313                                  * make sure that back references work.
314                                  */
315                                 if ((sp->s_type & S_DEF) == 0) {
316                                         if (fndsym(sp->s_id)) {
317                                                 symfnd++;
318                                         }
319                                 }
320                                 sp = sp->s_sp;
321                         }
322                 }
323         }
324 }
325
326
327 /*)Function     VOID    fndsym(name)
328  *
329  *              char    *name           symbol name to find
330  *
331  *      The function fndsym() searches through all combinations of the
332  *      library path specifications (input by the -k option) and the
333  *      library file specifications (input by the -l option) that
334  *      lead to an existing file.
335  *
336  *      The file specicifation may be formed in one of two ways:
337  *
338  *      (1)     If the library file contained an absolute
339  *              path/file specification then this becomes filspc.
340  *              (i.e. C:\...)
341  *
342  *      (2)     If the library file contains a relative path/file
343  *              specification then the concatenation of the path
344  *              and this file specification becomes filspc.
345  *              (i.e. \...)
346  *
347  *      The structure lbfile is created for the first library
348  *      object file which contains the definition for the
349  *      specified undefined symbol.
350  *
351  *      If the library file [.LIB] contains file specifications for
352  *      non existant files, no errors are returned.
353  *
354  *      local variables:
355  *              char    buf[]           [.REL] file input line
356  *              char    c               [.REL] file input character
357  *              FILE    *fp             file handle for object file
358  *              lbfile  *lbf            temporary pointer
359  *              lbfile  *lbfh           pointer to lbfile structure
360  *              FILE    *libfp          file handle for library file
361  *              lbname  *lbnh           pointer to lbname structure
362  *              char    *path           file specification path
363  *              char    relfil[]        [.REL] file specification
364  *              char    *str            combined path and file specification
365  *              char    symname[]       [.REL] file symbol string
366  *
367  *      global variables:
368  *              lbname  *lbnhead        The pointer to the first
369  *                                      name structure
370  *              lbfile  *lbfhead        The pointer to the first
371  *                                      file structure
372  *
373  *       functions called:
374  *              int     fclose()        c_library
375  *              int     fgets()         c_library
376  *              FILE    *fopen()        c_library
377  *              VOID    free()          c_library
378  *              char    getnb()         lklex.c
379  *              VOID    lkexit()        lkmain.c
380  *              VOID    loadfile()      lklibr.c
381  *              VOID *  new()           lksym.c
382  *              char *  sprintf()       c_library
383  *              int     sscanf()        c_library
384  *              char *  strcat()        c_library
385  *              char *  strchr()        c_library
386  *              char *  strcpy()        c_library
387  *              int     strlen()        c_library
388  *              int     strncmp()       c_library
389  *              VOID    unget()         lklex.c
390  *
391  *      side effects:
392  *              If the symbol is found then a new lbfile structure
393  *              is created and added to the linked list of lbfile
394  *              structures.  The file containing the found symbol
395  *              is linked.
396  */
397
398 #ifdef INDEXLIB
399
400 /* First entry in the library object symbol cache */
401 mlibraryfile libr = {
402         "", NULL, NULL
403 };
404
405 int fndsym( char *name )
406 {
407         struct lbfile *lbfh, *lbf;
408         pmlibraryfile ThisLibr;
409         pmlibrarysymbol ThisSym = NULL;
410
411         /* Build the index if this is the first call to fndsym */
412         if (libr.next==NULL)
413                 buildlibraryindex();
414         
415         /* Iterate through all library object files */
416         ThisLibr = libr.next;
417         while (ThisLibr) {
418
419                 /* Iterate through all symbols in an object file */
420                 ThisSym = ThisLibr->symbols->next;
421
422                 while (ThisSym) {
423                         if (!strcmp(ThisSym->name, name)) {
424                                 if (!ThisLibr->loaded) {
425                                         /* Object file is not loaded - add it to the list */
426                                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
427                                         if (lbfhead == NULL) {
428                                                 lbfhead = lbfh;
429                                         } else {
430                                                 lbf = lbfhead;
431                                                 while (lbf->next)
432                                                 lbf = lbf->next;
433                                                 lbf->next = lbfh;
434                                         }
435                                         lbfh->libspc = ThisLibr->libspc;
436                                         lbfh->filspc = ThisLibr->str;
437                                         lbfh->relfil = (char *) new (strlen(ThisLibr->relfil) + 1);
438                                         strcpy(lbfh->relfil,ThisLibr->relfil);
439                                         loadfile(lbfh->filspc);
440                                         ThisLibr->loaded=1;
441                                 }
442                                 return (1);     /* Found the symbol, return */
443                         }
444                         ThisSym=ThisSym->next;  /* Next sym in library */
445                 }
446                 ThisLibr=ThisLibr->next; /* Next library in list */
447         }
448         return 0;       /* Failure - symbol not found in any library */
449 };
450
451 /* buildlibraryindex - build an in-memory cache of the symbols contained in
452  *                      the libraries
453  */
454
455 int buildlibraryindex()
456 {
457         FILE *libfp, *fp;
458         struct lbname *lbnh;
459         char relfil[NINPUT+2], *str, *path;
460         char buf[NINPUT+2], c;
461         char symname[NINPUT+2];
462         pmlibraryfile This;
463         pmlibrarysymbol ThisSym;
464
465         This=&libr;
466
467         /* Iterate through all library files */
468 /*1*/   for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
469                 libfp = fopen( lbnh->libspc, "r" );
470                 if (libfp) {
471                         path=lbnh->path;
472
473                         /*
474                          * Read in a line from the library file.
475                          * This is the relative file specification
476                          * for a .REL file in this library.
477                          */
478
479 /*2*/                   while (fgets(relfil, NINPUT, libfp) != NULL) {
480                                 relfil[NINPUT+1] = '\0';
481                                 relfil[strlen(relfil) - 1] = '\0';
482                                 if (path != NULL) {
483                                         str = (char *)malloc(strlen(path)+strlen(relfil)+6);
484                                         strcpy(str,path);
485 #ifdef  OTHERSYSTEM
486 #ifdef SDK
487 #ifdef UNIX
488                                         if (str[strlen(str)-1] != '/') {
489                                                 strcat(str,"/");
490 #else /* UNIX */
491                                         if (str[strlen(str)-1] != '\\') {
492                                                 strcat(str,"\\");
493 #endif /* UNIX */
494 #else /* SDK */
495                                         if (str[strlen(str)-1] != '\\') {
496                                                 strcat(str,"\\");
497 #endif /* SDK */
498                                         }
499 #endif
500                                 } else {
501                                         str = (char *)malloc(strlen(relfil) + 5);
502                                 }
503 #ifdef SDK
504 #ifdef UNIX
505                                 if (relfil[0] == '/') {
506 #else /* UNIX */
507                                 if (relfil[0] == '\\') {
508 #endif /* UNIX */
509 #else /* SDK */
510                                 if (relfil[0] == '\\') {
511 #endif /* SDK */
512                                         strcat(str,relfil+1);
513                                 } else {
514                                         strcat(str,relfil);
515                                 }
516                                 if(strchr(str,FSEPX) == NULL) {
517 #ifdef SDK
518                                         sprintf(&str[strlen(str)], "%co", FSEPX);
519 #else /* SDK */
520                                         sprintf(&str[strlen(str)], "%crel", FSEPX);
521 #endif /* SDK */
522                                 }
523 /*3*/                           if ((fp = fopen(str, "r")) != NULL) {
524
525                                         /* Opened OK - create a new libraryfile object for it */
526                                         This->next = (pmlibraryfile)malloc( sizeof( mlibraryfile ));
527                                         if (This->next == NULL) {
528                                                 printf("panic: cant allocate memory.\n");
529                                                 exit(-1);
530                                         }
531
532                                         This=This->next;
533                                         This->next = NULL;
534                                         This->loaded=-1;
535
536                                         strcpy( This->filename, str );
537
538                                         ThisSym = This->symbols = (pmlibrarysymbol)malloc( sizeof(mlibrarysymbol));
539                                         ThisSym->next = NULL;
540
541                                         /*
542                                          * Read in the object file.  Look for lines that
543                                          * begin with "S" and end with "D".  These are
544                                          * symbol table definitions.  If we find one, see
545                                          * if it is our symbol.  Make sure we only read in
546                                          * our object file and don't go into the next one.
547                                          */
548                         
549 /*4*/                                   while (fgets(buf, NINPUT, fp) != NULL) {
550
551                                         buf[NINPUT+1] = '\0';
552                                         buf[strlen(buf) - 1] = '\0';
553
554                                         /*
555                                          * Skip everything that's not a symbol record.
556                                          */
557                                         if (buf[0] != 'S')
558                                                 continue;
559
560                                         /*
561                                          * When a 'T line' is found terminate file scan.
562                                          * All 'S line's preceed 'T line's in .REL files.
563                                          */
564                                         if (buf[0] == 'T')
565                                                 break;
566
567                                         sscanf(buf, "S %s %c", symname, &c);
568
569                                         /* If it's an actual symbol, record it */
570 /*5*/                                   if (c == 'D') {
571                                                 ThisSym->next = (pmlibrarysymbol)malloc(sizeof(mlibrarysymbol));
572                                                 ThisSym=ThisSym->next;
573                                                 if (ThisSym == NULL) {
574                                                         printf("panic: cant allocate memory.\n");
575                                                         exit(-2);
576                                                 }
577                                                 This->loaded=0;
578                                                 ThisSym->next=NULL;
579                                                 This->str = str;
580                                                 strcpy(This->relfil,relfil);
581                                                 strcpy(ThisSym->name, symname);
582                                                 This->libspc = lbnh->libspc;
583                                         }
584                                 } /* Closes while - read object file */
585                                 fclose(fp);
586                         } /* Closes if object file opened OK */
587                 } /* Ends while - processing all in libr */
588                 fclose(libfp);
589         } /* Ends good open of libr file */
590         }
591         return 0;
592 }
593 #else /* INDEXLIB */
594
595 int
596 fndsym(name)
597 char *name;
598 {
599         FILE *libfp, *fp;
600         struct lbname *lbnh;
601         struct lbfile *lbfh, *lbf;
602         char relfil[NINPUT+2];
603         char buf[NINPUT+2];
604         char symname[NINPUT];
605         char *path,*str;
606         char c;
607
608         /*
609          * Search through every library in the linked list "lbnhead".
610          */
611
612 /*1*/   for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) {
613                 if ((libfp = fopen(lbnh->libspc, "r")) == NULL) {
614                         fprintf(stderr, "Cannot open library file %s\n",
615                                 lbnh->libspc);
616                         lkexit(1);
617                 }
618                 path = lbnh->path;
619
620                 /*
621                  * Read in a line from the library file.
622                  * This is the relative file specification
623                  * for a .REL file in this library.
624                  */
625
626 /*2*/           while (fgets(relfil, NINPUT, libfp) != NULL) {
627                     relfil[NINPUT+1] = '\0';
628                     relfil[strlen(relfil) - 1] = '\0';
629                     if (path != NULL) {
630                         str = (char *) new (strlen(path)+strlen(relfil)+6);
631                         strcpy(str,path);
632 #ifdef  OTHERSYSTEM
633 #ifdef SDK
634 #ifdef UNIX
635                         if (str[strlen(str)-1] != '/') {
636                                 strcat(str,"/");
637 #else /* UNIX */
638                         if (str[strlen(str)-1] != '\\') {
639                                 strcat(str,"\\");
640 #endif /* UNIX */
641 #else /* SDK */
642                         if (str[strlen(str)-1] != '\\') {
643                                 strcat(str,"\\");
644 #endif /* SDK */
645                         }
646 #endif
647                     } else {
648                         str = (char *) new (strlen(relfil) + 5);
649                     }
650 #ifdef SDK
651 #ifdef UNIX
652                     if (relfil[0] == '/') {
653 #else /* UNIX */
654                     if (relfil[0] == '\\') {
655 #endif /* UNIX */
656 #else /* SDK */
657                     if (relfil[0] == '\\') {
658 #endif /* SDK */
659                         strcat(str,relfil+1);
660                     } else {
661                         strcat(str,relfil);
662                     }
663                     if(strchr(str,FSEPX) == NULL) {
664 #ifdef SDK
665                         sprintf(&str[strlen(str)], "%co", FSEPX);
666 #else /* SDK */
667                         sprintf(&str[strlen(str)], "%crel", FSEPX);
668 #endif /* SDK */
669                     }
670 /*3*/               if ((fp = fopen(str, "r")) != NULL) {
671
672                         /*
673                          * Read in the object file.  Look for lines that
674                          * begin with "S" and end with "D".  These are
675                          * symbol table definitions.  If we find one, see
676                          * if it is our symbol.  Make sure we only read in
677                          * our object file and don't go into the next one.
678                          */
679                         
680 /*4*/                   while (fgets(buf, NINPUT, fp) != NULL) {
681
682                         buf[NINPUT+1] = '\0';
683                         buf[strlen(buf) - 1] = '\0';
684
685                         /*
686                          * Skip everything that's not a symbol record.
687                          */
688                         if (buf[0] != 'S')
689                                 continue;
690
691                         /*
692                          * When a 'T line' is found terminate file scan.
693                          * All 'S line's preceed 'T line's in .REL files.
694                          */
695                         if (buf[0] == 'T')
696                                 break;
697
698                         sscanf(buf, "S %s %c", symname, &c);
699
700                         /*
701                          * If we find a symbol definition for the
702                          * symbol we're looking for, load in the
703                          * file and add it to lbfhead so it gets
704                          * loaded on pass number 2.
705                          */
706 /*5*/                   if (strncmp(symname, name, NCPS) == 0 && c == 'D') {
707
708                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
709                         if (lbfhead == NULL) {
710                                 lbfhead = lbfh;
711                         } else {
712                                 lbf = lbfhead;
713                                 while (lbf->next)
714                                         lbf = lbf->next;
715                                 lbf->next = lbfh;
716                         }
717                         lbfh->libspc = lbnh->libspc;
718                         lbfh->filspc = str;
719                         lbfh->relfil = (char *) new (strlen(relfil) + 1);
720                         strcpy(lbfh->relfil,relfil);
721                         fclose(fp);
722                         fclose(libfp);
723                         loadfile(str);
724                         return (1);
725
726 /*5*/                   }
727
728 /*4*/                   }
729                     fclose(fp);
730 /*3*/               }
731
732                     free(str);
733 /*2*/           }
734                 fclose(libfp);
735 /*1*/   }
736         return(0);
737 }
738 #endif /* INDEXLIB */
739
740 /*)Function     VOID    library()
741  *
742  *      The function library() links all the library object files
743  *      contained in the lbfile structures.
744  *
745  *      local variables:
746  *              lbfile  *lbfh           pointer to lbfile structure
747  *
748  *      global variables:
749  *              lbfile  *lbfhead        pointer to first lbfile structure
750  *
751  *       functions called:
752  *              VOID    loadfile        lklibr.c
753  *
754  *      side effects:
755  *              Links all files contained in the lbfile structures.
756  */
757
758 VOID
759 library()
760 {
761         struct lbfile *lbfh;
762
763         for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
764                 loadfile(lbfh->filspc);
765         }
766 }
767
768 /*)Function     VOID    loadfile(filspc)
769  *
770  *              char    *filspc         library object file specification
771  *
772  *      The function loadfile() links the library object module.
773  *
774  *      local variables:
775  *              FILE    *fp             file handle
776  *              int     i               input line length
777  *              char    str[]           file input line
778  *
779  *      global variables:
780  *              char    *ip             pointer to linker input string
781  *
782  *       functions called:
783  *              int     fclose()        c_library
784  *              int     fgets()         c_library
785  *              FILE *  fopen()         c_library
786  *              VOID    link()          lkmain.c
787  *              int     strlen()        c_library
788  *
789  *      side effects:
790  *              If file exists it is linked.
791  */
792
793 VOID
794 loadfile(filspc)
795 char *filspc;
796 {
797         FILE *fp;
798         char str[NINPUT+2];
799         int i;
800
801         if ((fp = fopen(filspc,"r")) != NULL) {
802                 while (fgets(str, NINPUT, fp) != NULL) {
803                         str[NINPUT+1] = '\0';
804                         i = strlen(str) - 1;
805                         if (str[i] == '\n')
806                                 str[i] = '\0';
807                         ip = str;
808                         link();
809                 }
810                 fclose(fp);
811         }
812 }