remove output of empty line
[fw/sdcc] / as / mcs51 / lkmain.c
1 /* lkmain.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  * 31-Oct-97 JLH:
12  *           - add jflag and jfp to control NoICE output file genration
13  *  3-Nov-97 JLH: 
14  *           - use a_type == 0 as "virgin area" flag: set == 1 if -b
15  */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include "aslink.h"
21
22 /* yuck - but including unistd.h causes problems on Cygwin by redefining
23  * Addr_T.
24  */
25 extern int unlink(const char *);
26
27 /*)Module       lkmain.c
28  *
29  *      The module lkmain.c contains the functions which
30  *      (1) input the linker options, parameters, and specifications
31  *      (2) perform a two pass link
32  *      (3) produce the appropriate linked data output and/or
33  *          link map file and/or relocated listing files.
34  *
35  *      lkmain.c contains the following functions:
36  *              FILE *  afile(fn,ft,wf)
37  *              VOID    bassav()
38  *              VOID    gblsav()
39   *             VOID    link_main()
40  *              VOID    lkexit()
41  *              VOID    main(argc,argv)
42  *              VOID    map()
43  *              int     parse()
44  *              VOID    setbas()
45  *              VOID    setgbl()
46  *              VOID    usage()
47  *
48  *      lkmain.c contains the following local variables:
49  *              char *  usetext[]       array of pointers to the
50  *                                      command option tect lines
51  *
52  */
53
54 /*)Function     VOID    main(argc,argv)
55  *
56  *              int     argc            number of command line arguments + 1
57  *              char *  argv[]          array of pointers to the command line
58  *                                      arguments
59  *
60  *      The function main() evaluates the command line arguments to
61  *      determine if the linker parameters are to input through 'stdin'
62  *      or read from a command file.  The functiond getline() and parse()
63  *      are to input and evaluate the linker parameters.  The linking process
64  *      proceeds by making the first pass through each .rel file in the order
65  *      presented to the linker.  At the end of the first pass the setbase(),
66  *      lnkarea(), setgbl(), and symdef() functions are called to evaluate
67  *      the base address terms, link all areas, define global variables,
68  *      and look for undefined symbols.  Following these routines a linker
69  *      map file may be produced and the linker output files may be opened.
70  *      The second pass through the .rel files will output the linked data
71  *      in one of the four supported formats.
72  *
73  *      local variables:
74  *              char *  p               pointer to an argument string
75  *              int     c               character from argument string
76  *              int     i               loop counter
77  *
78  *      global variables:
79  *                                              text line in ib[]
80  *              lfile   *cfp            The pointer *cfp points to the
81  *                                              current lfile structure
82  *              char    ctype[]         array of character types, one per
83  *                                              ASCII character
84  *              lfile   *filep                  The pointer *filep points to the
85  *                                              beginning of a linked list of
86  *                                              lfile structures.
87  *              head    *hp             Pointer to the current
88  *                                              head structure
89  *              char    ib[NINPUT]      .rel file text line
90  *              char    *ip             pointer into the .rel file
91  *              lfile   *linkp          pointer to first lfile structure
92  *                                              containing an input .rel file
93  *                                              specification
94  *              int     lkerr           error flag
95  *              int     mflag           Map output flag
96  *              int     oflag           Output file type flag
97  *              FILE    *ofp            Output file handle
98  *                                              for word formats
99  *              FILE    *ofph           Output file handle
100  *                                              for high byte format
101  *              FILE    *ofpl           Output file handle
102  *                                              for low byte format
103  *              int     pass            linker pass number
104  *              int     pflag           print linker command file flag
105  *              int     radix           current number conversion radix
106  *              FILE    *sfp            The file handle sfp points to the
107  *                                              currently open file
108  *              lfile   *startp         asmlnk startup file structure
109  *              FILE *  stdin           c_library
110  *              FILE *  stdout          c_library
111  *
112  *      functions called:
113  *              FILE *  afile()         lkmain.c
114  *              int     fclose()        c_library
115  *              int     fprintf()       c_library
116  *              int     getline()       lklex.c
117  *              VOID    library()       lklibr.c
118  *              VOID    link_main()     lkmain.c
119  *              VOID    lkexit()        lkmain.c
120  *              VOID    lnkarea()       lkarea.c
121  *              VOID    map()           lkmain.c
122  *              VOID    new()           lksym.c
123  *              int     parse()         lkmain.c
124  *              VOID    reloc()         lkreloc.c
125  *              VOID    search()        lklibr.c
126  *              VOID    setbas()        lkmain.c
127  *              VOID    setgbl()        lkmain.c
128  *              VOID    symdef()        lksym.c
129  *              VOID    usage()         lkmain.c
130  *
131  *      side effects:
132  *              Completion of main() completes the linking process
133  *              and may produce a map file (.map) and/or a linked
134  *              data files (.ihx or .s19) and/or one or more
135  *              relocated listing files (.rst).
136  */
137
138 int
139 main(argc, argv)
140 char *argv[];
141 {
142         register char *p;
143         register int c, i;
144
145         startp = (struct lfile *) new (sizeof (struct lfile));
146
147         pflag = 1;
148         for (i=1; i<argc; ++i) {
149                 p = argv[i];
150                 if (*p == '-') {
151                         while (ctype[c = *(++p)] & LETTER) {
152                                 switch(c) {
153
154                                 case 'c':
155                                 case 'C':
156                                         startp->f_type = F_STD;
157                                         break;
158
159                                 case 'f':
160                                 case 'F':
161                                         startp->f_type = F_LNK;
162                                         break;
163         
164                                 case 'n':
165                                 case 'N':
166                                         pflag = 0;
167                                         break;
168
169                                 case 'p':
170                                 case 'P':
171                                         pflag = 1;
172                                         break;
173
174                                 default:
175                                         usage();
176                                 }
177                         }
178                 } else {
179                         if (startp->f_type == F_LNK) {
180                                 startp->f_idp = p;
181                         }
182                 }
183         }
184        if (startp->f_type == 0)
185                 usage();
186         if (startp->f_type == F_LNK && startp->f_idp == NULL)
187                 usage();
188
189         cfp = NULL;
190         sfp = NULL;
191         filep = startp;
192         while (1) {
193                 ip = ib;
194                 if (getline() == 0)
195                         break;
196                 if (pflag && sfp != stdin)
197                         fprintf(stdout, "%s\n", ip);
198                if (*ip == '\0' || parse())
199                         break;
200         }
201
202         if (sfp) {
203             fclose(sfp);
204             sfp = NULL;
205         }
206
207         if (linkp == NULL)
208                 usage();
209
210         syminit();
211         
212         if (dflag){
213             dfp = afile("temp", "cdb", 1);
214             if (dfp == NULL) 
215                 lkexit(1);
216         }
217
218         for (pass=0; pass<2; ++pass) {
219                 cfp = NULL;
220                 sfp = NULL;
221                 filep = linkp;
222                 hp = NULL;
223                 radix = 10;
224
225                 while (getline()) {
226                         ip = ib;
227
228                         /* pass any "magic comments" to NoICE output */
229                         if ((ip[0] == ';') && (ip[1] == '!') && jfp) {
230                                 fprintf( jfp, "%s\n", &ip[2] );
231                         }
232                         link_main();
233                 }
234                 if (pass == 0) {
235                         /*
236                          * Search libraries for global symbols
237                          */
238                         search();
239                         /*
240                          * Set area base addresses.
241                          */
242                         setbas();
243                         /*
244                          * Link all area addresses.
245                          */
246                         lnkarea();
247                         /*
248                          * Process global definitions.
249                          */
250                         setgbl();
251                         /*
252                          * Check for undefined globals.
253                          */
254                         symdef(stderr);
255
256                         /* Open NoICE output file if requested */
257                         if (jflag) {
258                                 jfp = afile(linkp->f_idp, "NOI", 1);
259                                 if (jfp == NULL) {
260                                         lkexit(1);
261                                 }
262                         }
263
264                         /*
265                          * Output Link Map if requested,
266                          * or if NoICE output requested (since NoICE
267                          * file is generated in part by map() processing)
268                          */
269                         if (mflag || jflag)
270                                 map();
271
272                         if (iram_size)
273                                 iramcheck();
274
275                         /*
276                          * Open output file
277                          */
278                         if (oflag == 1) {
279                                 ofp = afile(linkp->f_idp, "ihx", 1);
280                                 if (ofp == NULL) {
281                                         lkexit(1);
282                                 }
283                                 /* include NoICE command to load hex file */
284                                 if (jfp) fprintf( jfp, "LOAD %s.IHX\n", linkp->f_idp );
285
286                         } else
287                         if (oflag == 2) {
288                                 ofp = afile(linkp->f_idp, "S19", 1);
289                                 if (ofp == NULL) {
290                                         lkexit(1);
291                                 }
292                                 /* include NoICE command to load hex file */
293                                 if (jfp) fprintf( jfp, "LOAD %s.S19\n", linkp->f_idp );
294                         }
295                 } else {
296                         /*
297                          * Link in library files
298                          */
299                         library();
300                         reloc('E');
301                 }
302         }
303         lkexit(lkerr);
304         return 0;
305 }
306
307 /*)Function     VOID    lkexit(i)
308  *
309  *                      int     i       exit code
310  *
311  *      The function lkexit() explicitly closes all open
312  *      files and then terminates the program.
313  *
314  *      local variables:
315  *              none
316  *
317  *      global variables:
318  *              FILE *  mfp             file handle for .map
319  *              FILE *  ofp             file handle for .ihx/.s19
320  *              FILE *  rfp             file hanlde for .rst
321  *              FILE *  sfp             file handle for .rel
322  *              FILE *  tfp             file handle for .lst
323  *
324  *      functions called:
325  *              int     fclose()        c_library
326  *              VOID    exit()          c_library
327  *
328  *      side effects:
329  *              All files closed. Program terminates.
330  */
331
332 VOID
333 lkexit(i)
334 int i;
335 {
336         if (mfp != NULL) fclose(mfp);
337         if (jfp != NULL) fclose(jfp);
338         if (ofp != NULL) fclose(ofp);
339         if (rfp != NULL) fclose(rfp);
340         if (sfp != NULL) fclose(sfp);
341         if (tfp != NULL) fclose(tfp);
342         if (dfp != NULL) {
343             FILE *xfp = afile(linkp->f_idp,"cdb",1);
344             dfp = freopen("temp.cdb","r",dfp);
345             copyfile(xfp,dfp);
346             fclose(xfp);
347             fclose(dfp);
348             unlink("temp.cdb");
349         }
350         exit(i);
351 }
352
353 /*)Function     link_main()
354  *
355  *      The function link_main() evaluates the directives for each line of
356  *      text read from the .rel file(s).  The valid directives processed
357  *      are:
358  *              X, D, Q, H, M, A, S, T, R, and P.
359  *
360  *      local variables:
361  *              int     c               first non blank character of a line
362  *
363  *      global variables:
364  *              head    *headp          The pointer to the first
365  *                                              head structure of a linked list
366  *              head    *hp             Pointer to the current
367  *                                              head structure
368  *              int     pass            linker pass number
369  *              int     radix           current number conversion radix
370  *
371  *      functions called:
372  *              char    endline()       lklex.c
373  *              VOID    module()        lkhead.c
374  *              VOID    newarea()       lkarea.c
375  *              VOID    newhead()       lkhead.c
376  *              sym *   newsym()        lksym.c
377  *              VOID    reloc()         lkreloc.c
378  *
379  *      side effects:
380  *              Head, area, and symbol structures are created and
381  *              the radix is set as the .rel file(s) are read.
382  */
383
384 VOID
385 link_main()
386 {
387         register int c;
388
389         if ((c=endline()) == 0) { return; }
390         switch (c) {
391
392         case 'X':
393                 radix = 16;
394                 break;
395
396         case 'D':
397                 radix = 10;
398                 break;
399
400         case 'Q':
401                 radix = 8;
402                 break;
403
404         case 'H':
405                 if (pass == 0) {
406                         newhead();
407                 } else {
408                         if (hp == 0) {
409                                 hp = headp;
410                         } else {
411                                 hp = hp->h_hp;
412                         }
413                 }
414                 sdp.s_area = NULL;
415                 sdp.s_areax = NULL;
416                 sdp.s_addr = 0;
417                 // jwk lastExtendedAddress = -1;
418                 break;
419
420         case 'M':
421                 if (pass == 0)
422                         module();
423                 break;
424
425         case 'A':
426                 if (pass == 0)
427                         newarea();
428                 if (sdp.s_area == NULL) {
429                         sdp.s_area = areap;
430                         sdp.s_areax = areap->a_axp;
431                         sdp.s_addr = 0;
432                 }
433                 break;
434
435         case 'S':
436                 if (pass == 0)
437                         newsym();
438                 break;
439
440         case 'T':
441         case 'R':
442         case 'P':
443                 if (pass == 0)
444                         break;
445                 reloc(c);
446                 break;
447
448         default:
449                 break;
450         }
451         if (c == 'X' || c == 'D' || c == 'Q') {
452                 if ((c = get()) == 'H') {
453                         hilo = 1;
454                 } else
455                 if (c == 'L') {
456                         hilo = 0;
457                 }
458         }
459 }
460
461
462 /*)Function     VOID    map()
463  *
464  *      The function map() opens the output map file and calls the various
465  *      routines to
466  *      (1) output the variables in each area,
467  *      (2) list the files processed with module names,
468  *      (3) list the libraries file processed,
469  *      (4) list base address definitions,
470  *      (5) list global variable definitions, and
471  *      (6) list any undefined variables.
472  *
473  *      local variables:
474  *              int             i               counter
475  *              head *  hdp             pointer to head structure
476  *              lbfile *lbfh            pointer to library file structure
477  *
478  *      global variables:
479  *              area    *ap             Pointer to the current
480  *                                              area structure
481  *              area    *areap          The pointer to the first
482  *                                              area structure of a linked list
483  *              base    *basep          The pointer to the first
484  *                                              base structure
485  *              base    *bsp            Pointer to the current
486  *                                              base structure
487  *              lfile   *filep                  The pointer *filep points to the
488  *                                              beginning of a linked list of
489  *                                              lfile structures.
490  *              globl   *globlp         The pointer to the first
491  *                                              globl structure
492  *              globl   *gsp            Pointer to the current
493  *                                              globl structure
494  *              head    *headp          The pointer to the first
495  *                                              head structure of a linked list
496  *              lbfile  *lbfhead        The pointer to the first
497  *                                      lbfile structure of a linked list
498  *              lfile   *linkp          pointer to first lfile structure
499  *                                              containing an input REL file
500  *                                              specification
501  *              int     lop             current line number on page
502  *              FILE    *mfp            Map output file handle
503  *              int     page            current page number
504  *
505  *      functions called:
506  *              FILE *  afile()         lkmain.c
507  *              int     fprintf()       c_library
508  *              VOID    lkexit()        lkmain.c
509  *              VOID    lstarea()       lklist.c
510  *              VOID    newpag()        lklist.c
511  *              VOID    symdef()        lksym.c
512  *
513  *      side effects:
514  *              The map file is created.
515  */
516
517 VOID
518 map()
519 {
520         register int i;
521         register struct head *hdp;
522         register struct lbfile *lbfh;
523
524         /*
525          * Open Map File
526          */
527         mfp = afile(linkp->f_idp, "map", 1);
528         if (mfp == NULL) {
529                 lkexit(1);
530         }
531
532         /*
533          * Output Map Area Lists
534          */
535         page = 0;
536         lop  = NLPP;
537         ap = areap;
538         while (ap) {
539                 lstarea(ap);
540                 ap = ap->a_ap;
541         }
542         /*
543          * List Linked Files
544          */
545         newpag(mfp);
546         fprintf(mfp, "\nFiles Linked      [ module(s) ]\n\n");
547         hdp = headp;
548         filep = linkp;
549         while (filep) {
550                 fprintf(mfp, "%-16s", filep->f_idp);
551                 i = 0;
552                 while ((hdp != NULL) && (hdp->h_lfile == filep)) {
553                         if (i % 5) {
554                             fprintf(mfp, ", %8.8s", hdp->m_id);
555                         } else {
556                             if (i) {
557                                 fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id);
558                             } else {
559                                 fprintf(mfp, "  [ %8.8s", hdp->m_id);
560                             }
561                         }
562                         hdp = hdp->h_hp;
563                         i++;
564                 }
565                 if (i)
566                         fprintf(mfp, " ]");
567                 fprintf(mfp, "\n");
568                 filep = filep->f_flp;
569         }
570         /*
571          * List Linked Libraries
572          */
573         if (lbfhead != NULL) {
574                 fprintf(mfp,
575         "\nLibraries Linked                    [   object  file   ]\n\n");
576                 for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
577                         fprintf(mfp, "%-32s    [ %16.16s ]\n",
578                                 lbfh->libspc, lbfh->relfil);
579                 }
580                 fprintf(mfp, "\n");
581         }
582         /*
583          * List Base Address Definitions
584          */
585         if (basep) {
586                 newpag(mfp);
587                 fprintf(mfp, "\nUser Base Address Definitions\n\n");
588                 bsp = basep;
589                 while (bsp) {
590                         fprintf(mfp, "%s\n", bsp->b_strp);
591                         bsp = bsp->b_base;
592                 }
593         }
594         /*
595          * List Global Definitions
596          */
597         if (globlp) {
598                 newpag(mfp);
599                 fprintf(mfp, "\nUser Global Definitions\n\n");
600                 gsp = globlp;
601                 while (gsp) {
602                         fprintf(mfp, "%s\n", gsp->g_strp);
603                         gsp = gsp->g_globl;
604                 }
605         }
606         fprintf(mfp, "\n\f");
607         symdef(mfp);
608 }
609
610 /*)Function     int     parse()
611  *
612  *      The function parse() evaluates all command line or file input
613  *      linker directives and updates the appropriate variables.
614  *
615  *      local variables:
616  *              int     c               character value
617  *              char    fid[]           file id string
618  *
619  *      global variables:
620  *              char    ctype[]         array of character types, one per
621  *                                              ASCII character
622  *              lfile   *lfp            pointer to current lfile structure
623  *                                              being processed by parse()
624  *              lfile   *linkp          pointer to first lfile structure
625  *                                              containing an input REL file
626  *                                              specification
627  *              int     mflag           Map output flag
628  *              int     oflag           Output file type flag
629  *              int     pflag           print linker command file flag
630  *              FILE *  stderr          c_library
631  *              int     uflag           Relocated listing flag
632  *              int     xflag           Map file radix type flag
633  *
634  *      Functions called:
635  *              VOID    addlib()        lklibr.c
636  *              VOID    addpath()       lklibr.c
637  *              VOID    bassav()        lkmain.c
638  *              int     fprintf()       c_library
639  *              VOID    gblsav()        lkmain.c
640  *              VOID    getfid()        lklex.c
641  *              char    getnb()         lklex.c
642  *              VOID    lkexit()        lkmain.c
643  *              char *  strcpy()        c_library
644  *              int     strlen()        c_library
645  *
646  *      side effects:
647  *              Various linker flags are updated and the linked
648  *              structure lfile is created.
649  */
650
651 int
652 parse()
653 {
654         register int c;
655         char fid[NINPUT];
656
657         while ((c = getnb()) != 0) {
658                 if ( c == '-') {
659                         while (ctype[c=get()] & LETTER) {
660                                 switch(c) {
661
662                                 case 'i':
663                                 case 'I':
664                                         oflag = 1;
665                                         break;
666
667                                 case 's':
668                                 case 'S':
669                                         oflag = 2;
670                                         break;
671
672                                 case 'm':
673                                 case 'M':
674                                         ++mflag;
675                                         break;
676
677                                 case 'j':
678                                 case 'J':
679                                         jflag = 1;
680                                         break;
681
682                                 case 'u':
683                                 case 'U':
684                                         uflag = 1;
685                                         break;
686                                 case 'r':
687                                 case 'R':
688                                         rflag = 1;
689                                         break;
690                                 case 'x':
691                                 case 'X':
692                                         xflag = 0;
693                                         break;
694
695                                 case 'q':
696                                 case 'Q':
697                                         xflag = 1;
698                                         break;
699
700                                 case 'd':
701                                 case 'D':
702                                         xflag = 2;
703                                         break;
704
705                                 case 'e':
706                                 case 'E':
707                                         return(1);
708
709                                 case 'n':
710                                 case 'N':
711                                         pflag = 0;
712                                         break;
713
714                                 case 'p':
715                                 case 'P':
716                                         pflag = 1;
717                                         break;
718
719                                 case 'b':
720                                 case 'B':
721                                         bassav();
722                                         return(0);
723
724                                 case 'g':
725                                 case 'G':
726                                         gblsav();
727                                         return(0);
728
729                                 case 'k':
730                                 case 'K':
731                                         addpath();
732                                         return(0);
733
734                                 case 'l':
735                                 case 'L':
736                                         addlib();
737                                         return(0);
738
739                                 case 'a':
740                                 case 'A':
741                                         iramsav();
742                                         return(0);
743
744                                 case 'z':
745                                 case 'Z':
746                                         dflag = 1;                                      
747                                         return(0);
748                                 default:
749                                         fprintf(stderr, "Invalid option\n");
750                                         lkexit(1);
751                                 }
752                         }
753                 } else
754                if (ctype[c] & ILL) {
755                        fprintf(stderr, "Invalid input");
756                        lkexit(1);
757                } else {
758                         if (linkp == NULL) {
759                                 linkp = (struct lfile *)
760                                         new (sizeof (struct lfile));
761                                 lfp = linkp;
762                         } else {
763                                 lfp->f_flp = (struct lfile *)
764                                                 new (sizeof (struct lfile));
765                                 lfp = lfp->f_flp;
766                         }
767                         getfid(fid, c);
768                         lfp->f_idp = (char *) new (strlen(fid)+1);
769                         strcpy(lfp->f_idp, fid);
770                         lfp->f_type = F_REL;
771                 }
772         }
773         return(0);
774 }
775
776 /*)Function     VOID    bassav()
777  *
778  *      The function bassav() creates a linked structure containing
779  *      the base address strings input to the linker.
780  *
781  *      local variables:
782  *              none
783  *
784  *      global variables:
785  *              base    *basep          The pointer to the first
786  *                                              base structure
787  *              base    *bsp            Pointer to the current
788  *                                              base structure
789  *              char    *ip             pointer into the REL file
790  *                                              text line in ib[]
791  *
792  *       functions called:
793  *              char    getnb()         lklex.c
794  *              VOID *  new()           lksym.c
795  *              int     strlen()        c_library
796  *              char *  strcpy()        c_library
797  *              VOID    unget()         lklex.c
798  *
799  *      side effects:
800  *              The basep structure is created.
801  */
802
803 VOID
804 bassav()
805 {
806         if (basep == NULL) {
807                 basep = (struct base *)
808                         new (sizeof (struct base));
809                 bsp = basep;
810         } else {
811                 bsp->b_base = (struct base *)
812                                 new (sizeof (struct base));
813                 bsp = bsp->b_base;
814         }
815         unget(getnb());
816         bsp->b_strp = (char *) new (strlen(ip)+1);
817         strcpy(bsp->b_strp, ip);
818 }
819
820 /*)Function     VOID    setbas()
821  *
822  *      The function setbas() scans the base address lines in hte
823  *      basep structure, evaluates the arguments, and sets beginning
824  *      address of the specified areas.
825  *
826  *      local variables:
827  *              int     v               expression value
828  *              char    id[]            base id string
829  *
830  *      global variables:
831  *              area    *ap             Pointer to the current
832  *                                              area structure
833  *              area    *areap          The pointer to the first
834  *                                              area structure of a linked list
835  *              base    *basep          The pointer to the first
836  *                                              base structure
837  *              base    *bsp            Pointer to the current
838  *                                              base structure
839  *              char    *ip             pointer into the REL file
840  *                                              text line in ib[]
841  *              int     lkerr           error flag
842  *
843  *       functions called:
844  *              Addr_T  expr()          lkeval.c
845  *              int     fprintf()       c_library
846  *              VOID    getid()         lklex.c
847  *              char    getnb()         lklex.c
848  *              int     symeq()         lksym.c
849  *
850  *      side effects:
851  *              The base address of an area is set.
852  */
853
854 VOID
855 setbas()
856 {
857         register int v;
858         char id[NCPS];
859
860         bsp = basep;
861         while (bsp) {
862                 ip = bsp->b_strp;
863                 getid(id, -1);
864                 if (getnb() == '=') {
865                         v = expr(0);
866                         for (ap = areap; ap != NULL; ap = ap->a_ap) {
867                                 if (symeq(id, ap->a_id))
868                                         break;
869                         }
870                         if (ap == NULL) {
871                                 fprintf(stderr,
872                                 "No definition of area %s\n", id);
873                                 lkerr++;
874                         } else {
875                                 ap->a_addr = v;
876                                 ap->a_type = 1; /* JLH: value set */
877                         }
878                 } else {
879                         fprintf(stderr, "No '=' in base expression");
880                         lkerr++;
881                 }
882                 bsp = bsp->b_base;
883         }
884 }
885
886 /*)Function     VOID    gblsav()
887  *
888  *      The function gblsav() creates a linked structure containing
889  *      the global variable strings input to the linker.
890  *
891  *      local variable:
892  *              none
893  *
894  *      global variables:
895  *              globl   *globlp         The pointer to the first
896  *                                              globl structure
897  *              globl   *gsp            Pointer to the current
898  *                                              globl structure
899  *              char    *ip             pointer into the REL file
900  *                                              text line in ib[]
901  *              int     lkerr           error flag
902  *
903  *      functions called:
904  *              char    getnb()         lklex.c
905  *              VOID *  new()           lksym.c
906  *              int     strlen()        c_library
907  *              char *  strcpy()        c_library
908  *              VOID    unget()         lklex.c
909  *
910  *      side effects:
911  *              The globlp structure is created.
912  */
913
914 VOID
915 gblsav()
916 {
917         if (globlp == NULL) {
918                 globlp = (struct globl *)
919                         new (sizeof (struct globl));
920                 gsp = globlp;
921         } else {
922                 gsp->g_globl = (struct globl *)
923                                 new (sizeof (struct globl));
924                 gsp = gsp->g_globl;
925         }
926         unget(getnb());
927         gsp->g_strp = (char *) new (strlen(ip)+1);
928         strcpy(gsp->g_strp, ip);
929 }
930         
931 /*)Function     VOID    setgbl()
932  *
933  *      The function setgbl() scans the global variable lines in hte
934  *      globlp structure, evaluates the arguments, and sets a variable
935  *      to this value.
936  *
937  *      local variables:
938  *              int     v               expression value
939  *              char    id[]            base id string
940  *              sym *   sp              pointer to a symbol structure
941  *
942  *      global variables:
943  *              char    *ip             pointer into the REL file
944  *                                              text line in ib[]
945  *              globl   *globlp         The pointer to the first
946  *                                              globl structure
947  *              globl   *gsp            Pointer to the current
948  *                                              globl structure
949  *              FILE *  stderr          c_library
950  *              int     lkerr           error flag
951  *
952  *       functions called:
953  *              Addr_T  expr()          lkeval.c
954  *              int     fprintf()       c_library
955  *              VOID    getid()         lklex.c
956  *              char    getnb()         lklex.c
957  *              sym *   lkpsym()        lksym.c
958  *
959  *      side effects:
960  *              The value of a variable is set.
961  */
962
963 VOID
964 setgbl()
965 {
966         register int v;
967         register struct sym *sp;
968         char id[NCPS];
969
970         gsp = globlp;
971         while (gsp) {
972                 ip = gsp->g_strp;
973                 getid(id, -1);
974                 if (getnb() == '=') {
975                         v = expr(0);
976                         sp = lkpsym(id, 0);
977                         if (sp == NULL) {
978                                 fprintf(stderr,
979                                 "No definition of symbol %s\n", id);
980                                 lkerr++;
981                         } else {
982                                 if (sp->s_flag & S_DEF) {
983                                         fprintf(stderr,
984                                         "Redefinition of symbol %s\n", id);
985                                         lkerr++;
986                                         sp->s_axp = NULL;
987                                 }
988                                 sp->s_addr = v;
989                                 sp->s_type |= S_DEF;
990                         }
991                 } else {
992                         fprintf(stderr, "No '=' in global expression");
993                         lkerr++;
994                 }
995                 gsp = gsp->g_globl;
996         }
997 }
998
999 /*)Function     FILE *  afile(fn,, ft, wf)
1000  *
1001  *              char *  fn              file specification string
1002  *              char *  ft              file type string
1003  *              int     wf              read(0)/write(1) flag
1004  *
1005  *      The function afile() opens a file for reading or writing.
1006  *              (1)     If the file type specification string ft
1007  *                      is not NULL then a file specification is
1008  *                      constructed with the file path\name in fn
1009  *                      and the extension in ft.
1010  *              (2)     If the file type specification string ft
1011  *                      is NULL then the file specification is
1012  *                      constructed from fn.  If fn does not have
1013  *                      a file type then the default .rel file
1014  *                      type is appended to the file specification.
1015  *
1016  *      afile() returns a file handle for the opened file or aborts
1017  *      the assembler on an open error.
1018  *
1019  *      local variables:
1020  *              int     c               character value
1021  *              char    fb[]            constructed file specification string
1022  *              FILE *  fp              filehandle for opened file
1023  *              char *  p1              pointer to filespec string fn
1024  *              char *  p2              pointer to filespec string fb
1025  *              char *  p3              pointer to filetype string ft
1026  *
1027  *      global variables:
1028  *              int     lkerr           error flag
1029  *
1030  *      functions called:
1031  *              FILE *  fopen()         c_library
1032  *              int     fprintf()       c_library
1033  *
1034  *      side effects:
1035  *              File is opened for read or write.
1036  */
1037
1038 FILE *
1039 afile(fn, ft, wf)
1040 char *fn;
1041 char *ft;
1042 {
1043         register char *p1, *p2, *p3;
1044         register int c;
1045         FILE *fp;
1046         char fb[PATH_MAX];
1047         char *omode = (wf ? (wf == 2 ? "a" : "w") : "r");
1048
1049         p1 = fn;
1050         p2 = fb;
1051         p3 = ft;
1052         while ((c = *p1++) != 0 && c != FSEPX) {
1053                 if (p2 < &fb[PATH_MAX-4])
1054                         *p2++ = c;
1055         }
1056         *p2++ = FSEPX;
1057         if (*p3 == 0) {
1058                 if (c == FSEPX) {
1059                         p3 = p1;
1060                 } else {
1061                         p3 = "rel";
1062                 }
1063         }
1064         while ((c = *p3++) != 0) {
1065                 if (p2 < &fb[PATH_MAX-1])
1066                         *p2++ = c;
1067         }
1068         *p2++ = 0;      
1069         if ((fp = fopen(fb, omode)) == NULL) {
1070             if (strcmp(ft,"cdb")) {
1071                 fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open");
1072                 lkerr++;
1073             }
1074         }
1075         return (fp);
1076 }
1077
1078 /*)Function     VOID    iramsav()
1079  *
1080  *      The function iramsav() stores the size of the chip's internal RAM.
1081  *      This is used after linking to check that variable assignment to this
1082  *      dataspace didn't overflow into adjoining segments.  Variables in the
1083  *      DSEG, OSEG, and ISEG are assigned to this dataspace.
1084  *
1085  *      local variables:
1086  *              none
1087  *
1088  *      global variables:
1089  *              char    *ip             pointer into the REL file
1090  *                                              text line in ib[]
1091  *              unsigned int            size of chip's internal
1092  *                      iram_size               RAM segment
1093  *
1094  *       functions called:
1095  *              char    getnb()         lklex.c
1096  *              VOID    unget()         lklex.c
1097  *              Addr_T  expr()          lkeval.c
1098  *
1099  *      side effects:
1100  *              The iram_size may be modified.
1101  */
1102
1103 VOID
1104 iramsav()
1105 {
1106   unget(getnb());
1107   if (ip && *ip)
1108     //iram_size = atoi(ip);
1109     iram_size = expr(0);        /* evaluate size expression */
1110   else
1111     iram_size = 128;            /* Default is 128 (0x80) bytes */
1112 }
1113
1114 /*)Function     VOID    iramcheck()
1115  *
1116  *      The function iramcheck() is used at the end of linking to check that
1117  *      the internal RAM area wasn't overflowed by too many variable
1118  *      assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
1119  *      the chip's internal RAM.
1120  *
1121  *      local variables:
1122  *              none
1123  *
1124  *      global variables:
1125  *              unsigned int            size of chip's internal
1126  *                      iram_size               RAM segment
1127  *              struct area             linked list of memory
1128  *                      *areap                  areas
1129  *
1130  *       functions called:
1131  *
1132  *      side effects:
1133  */
1134
1135 VOID
1136 iramcheck()
1137 {
1138   register unsigned int last_addr;
1139   register struct area *ap;
1140
1141   for (ap = areap; ap; ap=ap->a_ap) {
1142     if ((ap->a_size != 0) &&
1143         (!strcmp(ap->a_id, "DSEG") ||
1144          !strcmp(ap->a_id, "OSEG") ||
1145          !strcmp(ap->a_id, "ISEG")
1146         )
1147        )
1148     {
1149       last_addr = ap->a_addr + ap->a_size - 1;
1150       if (last_addr >= iram_size)
1151         fprintf(stderr,
1152                 "\nWARNING! Segment %s extends past the end\n"
1153                 "         of internal RAM.  Check map file.\n",
1154                 ap->a_id);
1155     }
1156   }
1157 }
1158
1159 char *usetxt[] = {
1160         "Startup:",
1161         "  -c   Command line input",
1162         "  -f   file[LNK] File input",
1163         "  -p   Prompt and echo of file[LNK] to stdout (default)",
1164         "  -n   No echo of file[LNK] to stdout",
1165 /*      "Usage: [-Options] file [file ...]", */
1166         "Libraries:",
1167         "  -k   Library path specification, one per -k",
1168         "  -l   Library file specification, one per -l",
1169         "Relocation:",
1170         "  -b   area base address = expression",
1171         "  -g   global symbol = expression",
1172         "Map format:",
1173         "  -m   Map output generated as file[MAP]",
1174         "  -x   Hexadecimal (default),  -d  Decimal,  -q  Octal",
1175         "Output:",
1176         "  -i   Intel Hex as file[IHX]",
1177         "  -s   Motorola S19 as file[S19]",
1178         "  -j   Produce NoICE debug as file[NOI]",
1179         "  -z   Produce SDCdb debug as file[cdb]",
1180 /*      "List:", */
1181         "  -u   Update listing file(s) with link data as file(s)[.RST]",
1182         "Miscellaneous:\n"
1183         "  -a   [iram-size] Check for internal RAM overflow",
1184         "End:",
1185         "  -e   or null line terminates input",
1186         0
1187 };
1188
1189 /*)Function     VOID    usage()
1190  *
1191  *      The function usage() outputs to the stderr device the
1192  *      assembler name and version and a list of valid assembler options.
1193  *
1194  *      local variables:
1195  *              char ** dp              pointer to an array of
1196  *                                      text string pointers.
1197  *
1198  *      global variables:
1199  *              FILE *  stderr          c_library
1200  *
1201  *      functions called:
1202  *              int     fprintf()       c_library
1203  *
1204  *      side effects:
1205  *              none
1206  */
1207
1208 VOID
1209 usage()
1210 {
1211         register char   **dp;
1212
1213         fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION);
1214         for (dp = usetxt; *dp; dp++)
1215                 fprintf(stderr, "%s\n", *dp);
1216         lkexit(1);
1217 }
1218
1219 /*)Function     VOID    copyfile()
1220  *              
1221  *              FILE    *dest           destination file
1222  *              FILE    *src            source file
1223  *
1224  *      function will copy source file to destination file
1225  *
1226  *
1227  *      functions called:
1228  *              int     fgetc()         c_library
1229  *              int     fputc()         c_library
1230  *
1231  *      side effects:
1232  *              none
1233  */
1234 VOID copyfile (dest,src)
1235 FILE *src,*dest ;
1236 {    
1237     int ch;
1238     while ((ch = fgetc(src)) != EOF) {
1239
1240         fputc(ch,dest);
1241     }
1242 }