* */Makefile.in: removed annoying warning:
[fw/sdcc] / as / link / hc08 / 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 #define EQ(A,B) !strcmp((A),(B))
19 #define MAXLINE 254 /*when using fgets*/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "aslink.h"
25
26 /*)Module   lklibr.c
27  *
28  *  The module lklibr.c contains the functions which
29  *  (1) specify the path(s) to library files [.LIB]
30  *  (2) specify the library file(s) [.LIB] to search
31  *  (3) search the library files for specific symbols
32  *      and link the module containing this symbol
33  *
34  *  lklibr.c contains the following functions:
35  *      VOID    addpath()
36  *      VOID    addlib()
37  *      VOID    addfile()
38  *      VOID    search()
39  *      VOID    fndsym()
40  *      VOID    library()
41  *      VOID    loadfile()
42  *
43  */
44
45 /*)Function VOID    addpath()
46  *
47  *  The function addpath() creates a linked structure containing
48  *  the paths to various object module library files.
49  *
50  *  local variables:
51  *      lbpath  *lbph       pointer to new path structure
52  *      lbpath  *lbp        temporary pointer
53  *
54  *  global variables:
55  *      lbpath  *lbphead    The pointer to the first
56  *                          path structure
57  *
58  *   functions called:
59  *      char    getnb()     lklex.c
60  *      VOID *  new()       lksym.c
61  *      int     strlen()    c_library
62  *      char *  strcpy()    c_library
63  *      VOID    unget()     lklex.c
64  *
65  *  side effects:
66  *      An lbpath structure may be created.
67  */
68
69 VOID
70 addpath()
71 {
72     struct lbpath *lbph, *lbp;
73
74     lbph = (struct lbpath *) new (sizeof(struct lbpath));
75     if (lbphead == NULL) {
76         lbphead = lbph;
77     } else {
78         lbp = lbphead;
79         while (lbp->next)
80             lbp = lbp->next;
81         lbp->next = lbph;
82     }
83     unget(getnb());
84     lbph->path = (char *) new (strlen(ip)+1);
85     strcpy(lbph->path, ip);
86 }
87
88 /*)Function VOID    addlib()
89  *
90  *  The function addlib() tests for the existance of a
91  *  library path structure to determine the method of
92  *  adding this library file to the library search structure.
93  *
94  *  This function calls the function addfile() to actually
95  *  add the library file to the search list.
96  *
97  *  local variables:
98  *      lbpath  *lbph       pointer to path structure
99  *
100  *  global variables:
101  *      lbpath  *lbphead    The pointer to the first
102  *                          path structure
103  *      ip a pointer to the library name
104  *
105  *   functions called:
106  *      VOID    addfile()   lklibr.c
107  *      char    getnb()     lklex.c
108  *      VOID    unget()     lklex.c
109  *
110  *  side effects:
111  *      The function addfile() may add the file to
112  *      the library search list.
113  */
114
115 VOID
116 addlib()
117 {
118     struct lbpath *lbph;
119     int foundcount=0;
120
121     unget(getnb());
122
123     if (lbphead == NULL)
124     {
125         foundcount=addfile(NULL, ip);
126     }
127     else
128     {
129         for (lbph=lbphead; lbph; lbph=lbph->next)
130         {
131             foundcount+=addfile(lbph->path, ip);
132         }
133     }
134     if(foundcount == 0)
135     {
136         fprintf(stderr, "?ASlink-Warning-Couldn't find library '%s'\n", ip);
137     }
138 }
139
140 /*)Function int addfile(path,libfil)
141  *
142  *      char    *path       library path specification
143  *      char    *libfil     library file specification
144  *
145  *  The function addfile() searches for the library file
146  *  by concatenating the path and libfil specifications.
147  *  if the library is found, an lbname structure is created
148  *  and linked to any previously defined structures.  This
149  *  linked list is used by the function fndsym() to attempt
150  *  to find any undefined symbols.
151  *
152  *  The function does not give report an error on invalid
153  *  path / file specifications or if the file is not found.
154  *
155  *  local variables:
156  *      lbname  *lbnh       pointer to new name structure
157  *      lbname  *lbn        temporary pointer
158  *
159  *  global variables:
160  *      lbname  *lbnhead    The pointer to the first
161  *                          path structure
162  *
163  *   functions called:
164  *      char    getnb()     lklex.c
165  *      VOID *  new()       lksym.c
166  *      int     strlen()    c_library
167  *      char *  strcpy()    c_library
168  *      VOID    unget()     lklex.c
169  *
170  *  side effects:
171  *      An lbname structure may be created.
172  *
173  *  return:
174  *      1: the library was found
175  *      0: the library was not found
176  */
177
178 int addfile(char * path, char * libfil)
179 {
180     FILE *fp;
181     char *str;
182     struct lbname *lbnh, *lbn;
183 #ifdef  OTHERSYSTEM
184     int libfilinc=0;
185 #endif
186
187     if (path != NULL)
188     {
189         str = (char *) new (strlen(path) + strlen(libfil) + 6);
190         strcpy(str,path);
191 #ifdef  OTHERSYSTEM
192         if (strlen(str) && (str[strlen(str)-1] != '/') && (str[strlen(str)-1] != '\\'))
193         {
194             strcat(str,"/");
195         }
196 #endif
197     }
198     else
199     {
200         str = (char *) new (strlen(libfil) + 5);
201     }
202
203 #ifdef  OTHERSYSTEM
204     if ((libfil[0] == '/') || (libfil[0] == '\\'))
205     {
206         libfil++;
207         libfilinc=1;
208     }
209 #endif
210
211     strcat(str, libfil);
212     if(strchr(libfil, FSEPX) == NULL)
213     {
214         sprintf(&str[strlen(str)], "%clib", FSEPX);
215     }
216
217     fp=fopen(str, "r");
218     if(fp == NULL)
219     {
220         /*Ok, that didn't work.  Try with the 'libfil' name only*/
221 #ifdef  OTHERSYSTEM
222         if(libfilinc) libfil--;
223 #endif
224         fp=fopen(libfil, "r");
225         if(fp != NULL)
226         {
227             /*Bingo!  'libfil' is the absolute path of the library*/
228             strcpy(str, libfil);
229             path=NULL;/*This way 'libfil' and 'path' will be rebuilt from 'str'*/
230         }
231     }
232
233     if(path==NULL)
234     {
235         /*'path' can not be null since it is needed to find the '.rel' files associated with
236         the library.  So, get 'path' from 'str' and then chop it off and recreate 'libfil'.
237         That way putting 'path' and 'libfil' together will result into the original filepath
238         as contained in 'str'.*/
239         int j;
240         path = (char *) new (strlen(str) + 1);
241         strcpy(path, str);
242         for(j=strlen(path)-1; j>=0; j--)
243         {
244             if((path[j] == '/') || (path[j] == '\\'))
245             {
246                 strcpy(libfil, &path[j+1]);
247                 path[j+1]=0;
248                 break;
249             }
250         }
251         if(j<=0) path[0]=0;
252     }
253
254     if (fp != NULL)
255     {
256         fclose(fp);
257         lbnh = (struct lbname *) new (sizeof(struct lbname));
258         if (lbnhead == NULL)
259         {
260             lbnhead = lbnh;
261         }
262         else
263         {
264             lbn = lbnhead;
265             while (lbn->next)
266                 lbn = lbn->next;
267             lbn->next = lbnh;
268         }
269
270         lbnh->path = path;
271         lbnh->libfil = (char *) new (strlen(libfil) + 1);
272         strcpy(lbnh->libfil,libfil);
273         lbnh->libspc = str;
274         return 1;
275     }
276     else
277     {
278         free(str);
279         return 0;
280     }
281 }
282
283 /*)Function VOID    search()
284  *
285  *  The function search() looks through all the symbol tables
286  *  at the end of pass 1.  If any undefined symbols are found
287  *  then the function fndsym() is called. Function fndsym()
288  *  searches any specified library files to automagically
289  *  import the object modules containing the needed symbol.
290  *
291  *  After a symbol is found and imported by the function
292  *  fndsym() the symbol tables are again searched.  The
293  *  symbol tables are search until no more symbols can be
294  *  resolved within the library files.  This ensures that
295  *  back references from one library module to another are
296  *  also resolved.
297  *
298  *  local variables:
299  *      int     i           temporary counter
300  *      sym     *sp         pointer to a symbol structure
301  *      int     symfnd      found a symbol flag
302  *
303  *  global variables:
304  *      sym     *symhash[]  array of pointers to symbol tables
305  *
306  *   functions called:
307  *      int     fndsym()    lklibr.c
308  *
309  *  side effects:
310  *      If a symbol is found then the library object module
311  *      containing the symbol will be imported and linked.
312  */
313
314 VOID
315 search()
316 {
317     register struct sym *sp;
318     register int i,symfnd;
319
320     /*
321      * Look for undefined symbols.  Keep
322      * searching until no more symbols are resolved.
323      */
324     symfnd = 1;
325     while (symfnd) {
326         symfnd = 0;
327         /*
328          * Look through all the symbols
329          */
330         for (i=0; i<NHASH; ++i) {
331             sp = symhash[i];
332             while (sp) {
333                 /* If we find an undefined symbol
334                  * (one where S_DEF is not set), then
335                  * try looking for it.  If we find it
336                  * in any of the libraries then
337                  * increment symfnd.  This will force
338                  * another pass of symbol searching and
339                  * make sure that back references work.
340                  */
341                 if ((sp->s_type & S_DEF) == 0) {
342                     if (fndsym(sp->s_id)) {
343                         symfnd++;
344                     }
345                 }
346                 sp = sp->s_sp;
347             }
348         }
349     }
350 }
351
352 /*Load a .rel file embedded in a sdcclib file*/
353 void LoadRel(FILE * libfp, char * ModName)
354 {
355     char str[NINPUT+2];
356     int state=0;
357
358     while (fgets(str, NINPUT, libfp) != NULL)
359     {
360         str[NINPUT+1] = '\0';
361         chop_crlf(str);
362         switch(state)
363         {
364             case 0:
365                 if(EQ(str, "<FILE>"))
366                 {
367                     fgets(str, NINPUT, libfp);
368                     str[NINPUT+1] = '\0';
369                     chop_crlf(str);
370                     if(EQ(str, ModName)) state=1;
371                     else
372                     {
373                         fprintf(stderr, "?ASlink-Error-Bad offset in library file str=%s, Modname=%s\n",
374                             str, ModName);
375                         lkexit(1);
376                     }
377                 }
378             break;
379             case 1:
380                 if(EQ(str, "<REL>")) state=2;
381             break;
382             case 2:
383                 if(EQ(str, "</REL>")) return;
384                 ip = str;
385                 link_main();
386             break;
387         }
388     }
389 }
390
391 /*Load an .adb file embedded in a sdcclib file.  If there is
392 something between <ADB> and </ADB> returns 1, otherwise returns 0.
393 This way the aomf51 will not have uselless empty modules. */
394
395 int LoadAdb(FILE * libfp)
396 {
397     char str[MAXLINE+1];
398     int state=0;
399     int ToReturn=0;
400
401     while (fgets(str, MAXLINE, libfp) != NULL)
402     {
403         str[NINPUT+1] = '\0';
404         chop_crlf(str);
405         switch(state)
406         {
407             case 0:
408                 if(EQ(str, "<ADB>")) state=1;
409             break;
410             case 1:
411                 if(EQ(str, "</ADB>")) return ToReturn;
412                 fprintf(dfp, "%s\n", str);
413                 ToReturn=1;
414             break;
415         }
416     }
417     return ToReturn;
418 }
419
420 /*Check for a symbol in a SDCC library.  If found, add the embedded .rel and
421 .adb files from the library.  The library must be created with the SDCC
422 librarian 'sdcclib' since the linking process depends on the correct file offsets
423 embedded in the library file.*/
424
425 int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName)
426 {
427     struct lbfile *lbfh, *lbf;
428     char ModName[NCPS]="";
429     char FLine[MAXLINE+1];
430     int state=0;
431     long IndexOffset=0, FileOffset;
432
433     while(!feof(libfp))
434     {
435         FLine[0]=0;
436         fgets(FLine, MAXLINE, libfp);
437         chop_crlf(FLine);
438
439         switch(state)
440         {
441             case 0:
442                 if(EQ(FLine, "<INDEX>"))
443                 {
444                     /*The next line has the size of the index*/
445                     FLine[0]=0;
446                     fgets(FLine, MAXLINE, libfp);
447                     chop_crlf(FLine);
448                     IndexOffset=atol(FLine);
449                     state=1;
450                 }
451             break;
452             case 1:
453                 if(EQ(FLine, "<MODULE>"))
454                 {
455                     /*The next line has the name of the module and the offset
456                     of the corresponding embedded file in the library*/
457                     FLine[0]=0;
458                     fgets(FLine, MAXLINE, libfp);
459                     chop_crlf(FLine);
460                     sscanf(FLine, "%s %ld", ModName, &FileOffset);
461                     state=2;
462                 }
463                 else if(EQ(FLine, "</INDEX>"))
464                 {
465                     /*Reached the end of the index.  The symbol is not in this library.*/
466                     return 0;
467                 }
468             break;
469             case 2:
470                 if(EQ(FLine, "</MODULE>"))
471                 {
472                     /*The symbol is not in this module, try the next one*/
473                     state=1;
474                 }
475                 else
476                 {
477                     /*Check if this is the symbol we are looking for.*/
478                     if (strncmp(SymName, FLine, NCPS)==0)
479                     {
480                         /*The symbol is in this module.*/
481
482                         /*As in the original library format, it is assumed that the .rel
483                         files reside in the same directory as the lib files.*/
484                         strcat(DirLib, ModName);
485                         sprintf(&DirLib[strlen(DirLib)], "%crel", FSEPX);
486
487                         /*If this module has been loaded already don't load it again.*/
488                         lbf = lbfhead;
489                         while (lbf)
490                         {
491                             if(EQ(DirLib, lbf->filspc)) return 1;/*Already loaded*/
492                             lbf=lbf->next;
493                         }
494
495                         /*Add the embedded file to the list of files to be loaded in
496                         the second pass.  That is performed latter by the function
497                         library() below.*/
498                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
499                         if (lbfhead == NULL)
500                         {
501                             lbfhead = lbfh;
502                         }
503                         else
504                         {
505                             lbf = lbfhead;
506                             while (lbf->next)
507                             lbf = lbf->next;
508                             lbf->next = lbfh;
509                         }
510
511                         lbfh->libspc = PathLib;
512                         lbfh->filspc = DirLib;
513                         lbfh->relfil = (char *) new (strlen(ModName) + 1);
514                         strcpy(lbfh->relfil, ModName);
515                         /*Library embedded file, so lbfh->offset must be >=0*/
516                         lbfh->offset = IndexOffset+FileOffset;
517
518                         /*Jump to where the .rel begins and load it.*/
519                         fseek(libfp, lbfh->offset, SEEK_SET);
520                         LoadRel(libfp, ModName);
521
522                         /* if cdb information required & .adb file present */
523                         if (dflag && dfp)
524                         {
525                             if(LoadAdb(libfp))
526                                 SaveLinkedFilePath(DirLib);
527                         }
528                         return 1; /*Found the symbol, so success!*/
529                     }
530                 }
531             break;
532
533             default:
534                 return 0; /*It should never reach this point, but just in case...*/
535             break;
536         }
537     }
538
539     return 0; /*The symbol is not in this library*/
540 }
541
542 /*)Function VOID    fndsym(name)
543  *
544  *      char    *name       symbol name to find
545  *
546  *  The function fndsym() searches through all combinations of the
547  *  library path specifications (input by the -k option) and the
548  *  library file specifications (input by the -l option) that
549  *  lead to an existing file.
550  *
551  *  The file specicifation may be formed in one of two ways:
552  *
553  *  (1) If the library file contained an absolute
554  *      path/file specification then this becomes filspc.
555  *      (i.e. C:\...)
556  *
557  *  (2) If the library file contains a relative path/file
558  *      specification then the concatenation of the path
559  *      and this file specification becomes filspc.
560  *      (i.e. \...)
561  *
562  *  The structure lbfile is created for the first library
563  *  object file which contains the definition for the
564  *  specified undefined symbol.
565  *
566  *  If the library file [.LIB] contains file specifications for
567  *  non existant files, no errors are returned.
568  *
569  *  local variables:
570  *      char    buf[]       [.REL] file input line
571  *      char    c           [.REL] file input character
572  *      FILE    *fp         file handle for object file
573  *      lbfile  *lbf        temporary pointer
574  *      lbfile  *lbfh       pointer to lbfile structure
575  *      FILE    *libfp      file handle for library file
576  *      lbname  *lbnh       pointer to lbname structure
577  *      char    *path       file specification path
578  *      char    relfil[]    [.REL] file specification
579  *      char    *str        combined path and file specification
580  *      char    symname[]   [.REL] file symbol string
581  *
582  *  global variables:
583  *      lbname  *lbnhead    The pointer to the first
584  *                          name structure
585  *      lbfile  *lbfhead    The pointer to the first
586  *                          file structure
587  *
588  *   functions called:
589  *      int     fclose()    c_library
590  *      int     fgets()     c_library
591  *      FILE    *fopen()    c_library
592  *      VOID    free()      c_library
593  *      char    getnb()     lklex.c
594  *      VOID    lkexit()    lkmain.c
595  *      VOID    loadfile()  lklibr.c
596  *      VOID *  new()       lksym.c
597  *      char *  sprintf()   c_library
598  *      int     sscanf()    c_library
599  *      char *  strcat()    c_library
600  *      char *  strchr()    c_library
601  *      char *  strcpy()    c_library
602  *      int     strlen()    c_library
603  *      int     strncmp()   c_library
604  *      VOID    unget()     lklex.c
605  *
606  *  side effects:
607  *      If the symbol is found then a new lbfile structure
608  *      is created and added to the linked list of lbfile
609  *      structures.  The file containing the found symbol
610  *      is linked.
611  */
612
613 int
614 fndsym(name)
615 char *name;
616 {
617     FILE *libfp, *fp;
618     struct lbname *lbnh;
619     struct lbfile *lbfh, *lbf;
620     char relfil[NINPUT+2];
621     char buf[NINPUT+2];
622     char symname[NINPUT];
623     char *path,*str;
624     char c;
625     int result;
626
627     /*
628      * Search through every library in the linked list "lbnhead".
629      */
630
631     for (lbnh=lbnhead; lbnh; lbnh=lbnh->next)
632     {
633         if ((libfp = fopen(lbnh->libspc, "r")) == NULL)
634         {
635             fprintf(stderr, "ASlink-Error-Cannot open library file %s\n",
636                 lbnh->libspc);
637             lkexit(1);
638         }
639         path = lbnh->path;
640
641         /*
642          * Read in a line from the library file.
643          * This is the relative file specification
644          * for a .REL file in this library.
645          */
646
647         while (fgets(relfil, NINPUT, libfp) != NULL)
648         {
649             relfil[NINPUT+1] = '\0';
650             chop_crlf(relfil);
651             if (path != NULL)
652             {
653                 str = (char *) new (strlen(path)+strlen(relfil)+6);
654                 strcpy(str,path);
655 #ifdef  OTHERSYSTEM
656                 if (strlen(str) && (str[strlen(str)-1] != '/') && (str[strlen(str)-1] != '\\'))
657                 {
658                     strcat(str,"/");
659                 }
660 #endif
661             }
662             else
663             {
664                 str = (char *) new (strlen(relfil) + 5);
665             }
666
667             if(strcmp(relfil, "<SDCCLIB>")==0)
668             {
669                 result=SdccLib(lbnh->libspc, libfp, str, name);
670                 fclose(libfp);
671                 if(result) return(1); /*Found the symbol*/
672                 free(str);
673                 /*The symbol is not in the current library,
674                 check the next library in the list*/
675                 break;
676             }
677
678             /*From here down is the support for libraries in the original format*/
679             if (relfil[0] == '\\')
680             {
681                 strcat(str,relfil+1);
682             }
683             else
684             {
685                 strcat(str,relfil);
686             }
687
688             if(strchr(relfil, FSEPX) == NULL)
689             {
690                 sprintf(&str[strlen(str)], "%crel", FSEPX);
691             }
692
693             if ((fp = fopen(str, "r")) != NULL)
694             {
695
696                 /*
697                  * Read in the object file.  Look for lines that
698                  * begin with "S" and end with "D".  These are
699                  * symbol table definitions.  If we find one, see
700                  * if it is our symbol.  Make sure we only read in
701                  * our object file and don't go into the next one.
702                  */
703
704                 while (fgets(buf, NINPUT, fp) != NULL)
705                 {
706                     buf[NINPUT+1] = '\0';
707                     chop_crlf(buf);
708                     /*
709                      * Skip everything that's not a symbol record.
710                      */
711                     if (buf[0] != 'S') continue;
712
713                     /*
714                     * When a 'T line' is found terminate file scan.
715                     * All 'S line's preceed 'T line's in .REL files.
716                     */
717                     if (buf[0] == 'T') break;
718
719                     sscanf(buf, "S %s %c", symname, &c);
720
721                     /*
722                     * If we find a symbol definition for the
723                     * symbol we're looking for, load in the
724                     * file and add it to lbfhead so it gets
725                     * loaded on pass number 2.
726                     */
727                     if (strncmp(symname, name, NCPS) == 0 && c == 'D')
728                     {
729                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
730                         if (lbfhead == NULL)
731                         {
732                             lbfhead = lbfh;
733                         }
734                         else
735                         {
736                             lbf = lbfhead;
737                             while (lbf->next)
738                             lbf = lbf->next;
739                             lbf->next = lbfh;
740                         }
741
742                         lbfh->libspc = lbnh->libspc;
743                         lbfh->filspc = str;
744                         lbfh->relfil = (char *) new (strlen(relfil) + 1);
745                         lbfh->offset = -1; /*Stand alone rel file*/
746                         strcpy(lbfh->relfil,relfil);
747                         fclose(fp);
748                         fclose(libfp);
749
750                         /* if cdb information required & adb file present */
751                         if (dflag && dfp)
752                         {
753                             FILE *xfp = afile(str,"adb",0); //JCF: Nov 30, 2002
754                             if (xfp)
755                             {
756                                 SaveLinkedFilePath(str);
757                                 copyfile(dfp,xfp);
758                                 fclose(xfp);
759                             }
760                         }
761                         loadfile(str);
762                         return (1);
763                     }
764                 }
765                 fclose(fp);
766             }
767             free(str);
768         }
769         fclose(libfp);
770     }
771     return(0);
772 }
773
774 void loadfile_SdccLib(char * libspc, char * module, long offset)
775 {
776     FILE *fp;
777
778     if ((fp = fopen(libspc,"r")) != NULL)
779     {
780         fseek(fp, offset, SEEK_SET);
781         LoadRel(fp, module);
782         fclose(fp);
783     }
784 }
785
786 /*)Function VOID    library()
787  *
788  *  The function library() links all the library object files
789  *  contained in the lbfile structures.
790  *
791  *  local variables:
792  *      lbfile  *lbfh       pointer to lbfile structure
793  *
794  *  global variables:
795  *      lbfile  *lbfhead    pointer to first lbfile structure
796  *
797  *   functions called:
798  *      VOID    loadfile    lklibr.c
799  *
800  *  side effects:
801  *      Links all files contained in the lbfile structures.
802  */
803
804 VOID
805 library()
806 {
807     struct lbfile *lbfh;
808
809     for (lbfh=lbfhead; lbfh; lbfh=lbfh->next)
810     {
811         if(lbfh->offset<0)
812         {
813             /*Stand alone rel file (original lib format)*/
814             loadfile(lbfh->filspc);
815         }
816         else
817         {
818             /*rel file embedded in lib (new lib format)*/
819             loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset);
820         }
821     }
822 }
823
824 /*)Function VOID    loadfile(filspc)
825  *
826  *      char    *filspc     library object file specification
827  *
828  *  The function loadfile() links the library object module.
829  *
830  *  local variables:
831  *      FILE    *fp         file handle
832  *      int     i           input line length
833  *      char    str[]       file input line
834  *
835  *  global variables:
836  *      char    *ip     pointer to linker input string
837  *
838  *   functions called:
839  *      int     fclose()    c_library
840  *      int     fgets()     c_library
841  *      FILE *  fopen()     c_library
842  *      VOID    link_main() lkmain.c
843  *      int     strlen()    c_library
844  *
845  *  side effects:
846  *      If file exists it is linked.
847  */
848
849 VOID
850 loadfile(filspc)
851 char *filspc;
852 {
853     FILE *fp;
854     char str[NINPUT+2];
855
856     if ((fp = fopen(filspc,"r")) != NULL) {
857         while (fgets(str, NINPUT, fp) != NULL) {
858             str[NINPUT+1] = '\0';
859             chop_crlf(str);
860             ip = str;
861             link_main();
862         }
863         fclose(fp);
864     }
865 }