replace .cc with .c
[fw/sdcc] / as / 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         printf("?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                         printf("Bad offset in library file str=%s, Modname=%s\n", str, ModName);
374                         lkexit(1);
375                     }
376                 }
377             break;
378             case 1:
379                 if(EQ(str, "<REL>")) state=2;
380             break;
381             case 2:
382                 if(EQ(str, "</REL>")) return;
383                 ip = str;
384                 link_main();
385             break;
386         }
387     }
388 }
389
390 /*Load an .adb file embedded in a sdcclib file.  If there is
391 something between <ADB> and </ADB> returns 1, otherwise returns 0.
392 This way the aomf51 will not have uselless empty modules. */
393
394 int LoadAdb(FILE * libfp)
395 {
396     char str[MAXLINE+1];
397     int state=0;
398     int ToReturn=0;
399
400     while (fgets(str, MAXLINE, libfp) != NULL)
401     {
402         str[NINPUT+1] = '\0';
403         chop_crlf(str);
404         switch(state)
405         {
406             case 0:
407                 if(EQ(str, "<ADB>")) state=1;
408             break;
409             case 1:
410                 if(EQ(str, "</ADB>")) return ToReturn;
411                 fprintf(dfp, "%s\n", str);
412                 ToReturn=1;
413             break;
414         }
415     }
416     return ToReturn;
417 }
418
419 /*Check for a symbol in a SDCC library.  If found, add the embedded .rel and
420 .adb files from the library.  The library must be created with the SDCC
421 librarian 'sdcclib' since the linking process depends on the correct file offsets
422 embedded in the library file.*/
423
424 int SdccLib(char * PathLib, FILE * libfp, char * DirLib, char * SymName)
425 {
426     struct lbfile *lbfh, *lbf;
427     char ModName[NCPS]="";
428     char FLine[MAXLINE+1];
429     int state=0;
430     long IndexOffset=0, FileOffset;
431
432     while(!feof(libfp))
433     {
434         FLine[0]=0;
435         fgets(FLine, MAXLINE, libfp);
436         chop_crlf(FLine);
437
438         switch(state)
439         {
440             case 0:
441                 if(EQ(FLine, "<INDEX>"))
442                 {
443                     /*The next line has the size of the index*/
444                     FLine[0]=0;
445                     fgets(FLine, MAXLINE, libfp);
446                     chop_crlf(FLine);
447                     IndexOffset=atol(FLine);
448                     state=1;
449                 }
450             break;
451             case 1:
452                 if(EQ(FLine, "<MODULE>"))
453                 {
454                     /*The next line has the name of the module and the offset
455                     of the corresponding embedded file in the library*/
456                     FLine[0]=0;
457                     fgets(FLine, MAXLINE, libfp);
458                     chop_crlf(FLine);
459                     sscanf(FLine, "%s %ld", ModName, &FileOffset);
460                     state=2;
461                 }
462                 else if(EQ(FLine, "</INDEX>"))
463                 {
464                     /*Reached the end of the index.  The symbol is not in this library.*/
465                     return 0;
466                 }
467             break;
468             case 2:
469                 if(EQ(FLine, "</MODULE>"))
470                 {
471                     /*The symbol is not in this module, try the next one*/
472                     state=1;
473                 }
474                 else
475                 {
476                     /*Check if this is the symbol we are looking for.*/
477                     if (strncmp(SymName, FLine, NCPS)==0)
478                     {
479                         /*The symbol is in this module.*/
480
481                         /*As in the original library format, it is assumed that the .rel
482                         files reside in the same directory as the lib files.*/
483                         strcat(DirLib, ModName);
484                         sprintf(&DirLib[strlen(DirLib)], "%crel", FSEPX);
485
486                         /*If this module has been loaded already don't load it again.*/
487                         lbf = lbfhead;
488                         while (lbf)
489                         {
490                             if(EQ(DirLib, lbf->filspc)) return 1;/*Already loaded*/
491                             lbf=lbf->next;
492                         }
493
494                         /*Add the embedded file to the list of files to be loaded in
495                         the second pass.  That is performed latter by the function
496                         library() below.*/
497                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
498                         if (lbfhead == NULL)
499                         {
500                             lbfhead = lbfh;
501                         }
502                         else
503                         {
504                             lbf = lbfhead;
505                             while (lbf->next)
506                             lbf = lbf->next;
507                             lbf->next = lbfh;
508                         }
509
510                         lbfh->libspc = PathLib;
511                         lbfh->filspc = DirLib;
512                         lbfh->relfil = (char *) new (strlen(ModName) + 1);
513                         strcpy(lbfh->relfil, ModName);
514                         /*Library embedded file, so lbfh->offset must be >=0*/
515                         lbfh->offset = IndexOffset+FileOffset;
516
517                         /*Jump to where the .rel begins and load it.*/
518                         fseek(libfp, lbfh->offset, SEEK_SET);
519                         LoadRel(libfp, ModName);
520
521                         /* if cdb information required & .adb file present */
522                         if (dflag && dfp)
523                         {
524                             if(LoadAdb(libfp))
525                                 SaveLinkedFilePath(DirLib);
526                         }
527                         return 1; /*Found the symbol, so success!*/
528                     }
529                 }
530             break;
531
532             default:
533                 return 0; /*It should never reach this point, but just in case...*/
534             break;
535         }
536     }
537
538     return 0; /*The symbol is not in this library*/
539 }
540
541 /*)Function VOID    fndsym(name)
542  *
543  *      char    *name       symbol name to find
544  *
545  *  The function fndsym() searches through all combinations of the
546  *  library path specifications (input by the -k option) and the
547  *  library file specifications (input by the -l option) that
548  *  lead to an existing file.
549  *
550  *  The file specicifation may be formed in one of two ways:
551  *
552  *  (1) If the library file contained an absolute
553  *      path/file specification then this becomes filspc.
554  *      (i.e. C:\...)
555  *
556  *  (2) If the library file contains a relative path/file
557  *      specification then the concatenation of the path
558  *      and this file specification becomes filspc.
559  *      (i.e. \...)
560  *
561  *  The structure lbfile is created for the first library
562  *  object file which contains the definition for the
563  *  specified undefined symbol.
564  *
565  *  If the library file [.LIB] contains file specifications for
566  *  non existant files, no errors are returned.
567  *
568  *  local variables:
569  *      char    buf[]       [.REL] file input line
570  *      char    c           [.REL] file input character
571  *      FILE    *fp         file handle for object file
572  *      lbfile  *lbf        temporary pointer
573  *      lbfile  *lbfh       pointer to lbfile structure
574  *      FILE    *libfp      file handle for library file
575  *      lbname  *lbnh       pointer to lbname structure
576  *      char    *path       file specification path
577  *      char    relfil[]    [.REL] file specification
578  *      char    *str        combined path and file specification
579  *      char    symname[]   [.REL] file symbol string
580  *
581  *  global variables:
582  *      lbname  *lbnhead    The pointer to the first
583  *                          name structure
584  *      lbfile  *lbfhead    The pointer to the first
585  *                          file structure
586  *
587  *   functions called:
588  *      int     fclose()    c_library
589  *      int     fgets()     c_library
590  *      FILE    *fopen()    c_library
591  *      VOID    free()      c_library
592  *      char    getnb()     lklex.c
593  *      VOID    lkexit()    lkmain.c
594  *      VOID    loadfile()  lklibr.c
595  *      VOID *  new()       lksym.c
596  *      char *  sprintf()   c_library
597  *      int     sscanf()    c_library
598  *      char *  strcat()    c_library
599  *      char *  strchr()    c_library
600  *      char *  strcpy()    c_library
601  *      int     strlen()    c_library
602  *      int     strncmp()   c_library
603  *      VOID    unget()     lklex.c
604  *
605  *  side effects:
606  *      If the symbol is found then a new lbfile structure
607  *      is created and added to the linked list of lbfile
608  *      structures.  The file containing the found symbol
609  *      is linked.
610  */
611
612 int
613 fndsym(name)
614 char *name;
615 {
616     FILE *libfp, *fp;
617     struct lbname *lbnh;
618     struct lbfile *lbfh, *lbf;
619     char relfil[NINPUT+2];
620     char buf[NINPUT+2];
621     char symname[NINPUT];
622     char *path,*str;
623     char c;
624     int result;
625
626     /*
627      * Search through every library in the linked list "lbnhead".
628      */
629
630     for (lbnh=lbnhead; lbnh; lbnh=lbnh->next)
631     {
632         if ((libfp = fopen(lbnh->libspc, "r")) == NULL)
633         {
634             fprintf(stderr, "Cannot open library file %s\n",
635                 lbnh->libspc);
636             lkexit(1);
637         }
638         path = lbnh->path;
639
640         /*
641          * Read in a line from the library file.
642          * This is the relative file specification
643          * for a .REL file in this library.
644          */
645
646         while (fgets(relfil, NINPUT, libfp) != NULL)
647         {
648             relfil[NINPUT+1] = '\0';
649             chop_crlf(relfil);
650             if (path != NULL)
651             {
652                 str = (char *) new (strlen(path)+strlen(relfil)+6);
653                 strcpy(str,path);
654 #ifdef  OTHERSYSTEM
655                 if (strlen(str) && (str[strlen(str)-1] != '/') && (str[strlen(str)-1] != '\\'))
656                 {
657                     strcat(str,"/");
658                 }
659 #endif
660             }
661             else
662             {
663                 str = (char *) new (strlen(relfil) + 5);
664             }
665
666             if(strcmp(relfil, "<SDCCLIB>")==0)
667             {
668                 result=SdccLib(lbnh->libspc, libfp, str, name);
669                 fclose(libfp);
670                 if(result) return(1); /*Found the symbol*/
671                 free(str);
672                 /*The symbol is not in the current library,
673                 check the next library in the list*/
674                 break;
675             }
676
677             /*From here down is the support for libraries in the original format*/
678             if (relfil[0] == '\\')
679             {
680                 strcat(str,relfil+1);
681             }
682             else
683             {
684                 strcat(str,relfil);
685             }
686
687             if(strchr(relfil, FSEPX) == NULL)
688             {
689                 sprintf(&str[strlen(str)], "%crel", FSEPX);
690             }
691
692             if ((fp = fopen(str, "r")) != NULL)
693             {
694
695                 /*
696                  * Read in the object file.  Look for lines that
697                  * begin with "S" and end with "D".  These are
698                  * symbol table definitions.  If we find one, see
699                  * if it is our symbol.  Make sure we only read in
700                  * our object file and don't go into the next one.
701                  */
702
703                 while (fgets(buf, NINPUT, fp) != NULL)
704                 {
705                     buf[NINPUT+1] = '\0';
706                     chop_crlf(buf);
707                     /*
708                      * Skip everything that's not a symbol record.
709                      */
710                     if (buf[0] != 'S') continue;
711
712                     /*
713                     * When a 'T line' is found terminate file scan.
714                     * All 'S line's preceed 'T line's in .REL files.
715                     */
716                     if (buf[0] == 'T') break;
717
718                     sscanf(buf, "S %s %c", symname, &c);
719
720                     /*
721                     * If we find a symbol definition for the
722                     * symbol we're looking for, load in the
723                     * file and add it to lbfhead so it gets
724                     * loaded on pass number 2.
725                     */
726                     if (strncmp(symname, name, NCPS) == 0 && c == 'D')
727                     {
728                         lbfh = (struct lbfile *) new (sizeof(struct lbfile));
729                         if (lbfhead == NULL)
730                         {
731                             lbfhead = lbfh;
732                         }
733                         else
734                         {
735                             lbf = lbfhead;
736                             while (lbf->next)
737                             lbf = lbf->next;
738                             lbf->next = lbfh;
739                         }
740
741                         lbfh->libspc = lbnh->libspc;
742                         lbfh->filspc = str;
743                         lbfh->relfil = (char *) new (strlen(relfil) + 1);
744                         lbfh->offset = -1; /*Stand alone rel file*/
745                         strcpy(lbfh->relfil,relfil);
746                         fclose(fp);
747                         fclose(libfp);
748
749                         /* if cdb information required & adb file present */
750                         if (dflag && dfp)
751                         {
752                             FILE *xfp = afile(str,"adb",0); //JCF: Nov 30, 2002
753                             if (xfp)
754                             {
755                                 SaveLinkedFilePath(str);
756                                 copyfile(dfp,xfp);
757                                 fclose(xfp);
758                             }
759                         }
760                         loadfile(str);
761                         return (1);
762                     }
763                 }
764                 fclose(fp);
765             }
766             free(str);
767         }
768         fclose(libfp);
769     }
770     return(0);
771 }
772
773 void loadfile_SdccLib(char * libspc, char * module, long offset)
774 {
775     FILE *fp;
776
777     if ((fp = fopen(libspc,"r")) != NULL)
778     {
779         fseek(fp, offset, SEEK_SET);
780         LoadRel(fp, module);
781         fclose(fp);
782     }
783 }
784
785 /*)Function VOID    library()
786  *
787  *  The function library() links all the library object files
788  *  contained in the lbfile structures.
789  *
790  *  local variables:
791  *      lbfile  *lbfh       pointer to lbfile structure
792  *
793  *  global variables:
794  *      lbfile  *lbfhead    pointer to first lbfile structure
795  *
796  *   functions called:
797  *      VOID    loadfile    lklibr.c
798  *
799  *  side effects:
800  *      Links all files contained in the lbfile structures.
801  */
802
803 VOID
804 library()
805 {
806     struct lbfile *lbfh;
807
808     for (lbfh=lbfhead; lbfh; lbfh=lbfh->next)
809     {
810         if(lbfh->offset<0)
811         {
812             /*Stand alone rel file (original lib format)*/
813             loadfile(lbfh->filspc);
814         }
815         else
816         {
817             /*rel file embedded in lib (new lib format)*/
818             loadfile_SdccLib(lbfh->libspc, lbfh->relfil, lbfh->offset);
819         }
820     }
821 }
822
823 /*)Function VOID    loadfile(filspc)
824  *
825  *      char    *filspc     library object file specification
826  *
827  *  The function loadfile() links the library object module.
828  *
829  *  local variables:
830  *      FILE    *fp         file handle
831  *      int     i           input line length
832  *      char    str[]       file input line
833  *
834  *  global variables:
835  *      char    *ip     pointer to linker input string
836  *
837  *   functions called:
838  *      int     fclose()    c_library
839  *      int     fgets()     c_library
840  *      FILE *  fopen()     c_library
841  *      VOID    link_main() lkmain.c
842  *      int     strlen()    c_library
843  *
844  *  side effects:
845  *      If file exists it is linked.
846  */
847
848 VOID
849 loadfile(filspc)
850 char *filspc;
851 {
852     FILE *fp;
853     char str[NINPUT+2];
854
855     if ((fp = fopen(filspc,"r")) != NULL) {
856         while (fgets(str, NINPUT, fp) != NULL) {
857             str[NINPUT+1] = '\0';
858             chop_crlf(str);
859             ip = str;
860             link_main();
861         }
862         fclose(fp);
863     }
864 }