68d041c1118042319f744ea0fa162e87580de67d
[fw/sdcc] / as / link / lklist.c
1 /* lklist.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  * 28-Oct-97 JLH: 
12  *           - lstarea: show s_id as string rather than array [NCPS]
13  *           - lstarea: show a_id as string rather than array [NCPS]
14  * 31-Oct-97 JLH: add NoICE output file genration in lstarea
15  * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
16  */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include "aslink.h"
22
23 /*)Module       lklist.c
24  *
25  *      The module lklist.c contains the functions which
26  *      output the linker .map file and produce a relocated
27  *      listing .rst file.
28  *
29  *      lklist.c contains the following functions:
30  *              int     dgt()
31  *              VOID    lstarea()
32  *              VOID    lkulist()
33  *              VOID    lkalist()
34  *              VOID    lkglist()
35  *              VOID    newpag()
36  *              VOID    slew()
37  *
38  *      lklist.c contains no local variables.
39  */
40
41 /*)Function     VOID    slew(fp)
42  *
43  *              FILE *  fp              output file handle
44  *
45  *      The function slew() increments the page line counter.
46  *      If the number of lines exceeds the maximum number of
47  *      lines per page then a page skip and a page header are
48  *      output.
49  *
50  *      local variables:
51  *              int     i               loop counter
52  *
53  *      global variables:
54  *              int     lop             current line number on page
55  *              int     xflag           Map file radix type flag
56  *
57  *      functions called:
58  *              int     fprintf()       c_library
59  *              VOID    newpag()        lklist.c
60  *
61  *      side effects:
62  *              The page line and the page count may be updated.
63  */
64
65 VOID
66 slew(fp)
67 FILE *fp;
68 {
69         register int i;
70
71         if (lop++ >= NLPP) {
72                 newpag(fp);
73                 if (xflag == 0) {
74                         fprintf(fp, "Hexadecimal\n\n");
75                 } else
76                 if (xflag == 1) {
77                         fprintf(fp, "Octal\n\n");
78                 } else
79                 if (xflag == 2) {
80                         fprintf(fp, "Decimal\n\n");
81                 }
82                 fprintf(fp, "Area       Addr   Size");
83                 fprintf(fp, "   Decimal Bytes (Attributes)\n");
84                 for(i=0;i<4;++i)
85                         fprintf(fp, "      Value--Global");
86                 fprintf(fp, "\n\n");
87                 lop += 6;
88         }
89 }
90
91 /*)Function     VOID    newpag()
92  *
93  *      The function newpag() outputs a page skip, writes the
94  *      first page header line, sets the line count to 1, and
95  *      increments the page counter.
96  *
97  *      local variables:
98  *              none
99  *
100  *      global variables:
101  *              int     lop             current line number on page
102  *              int     page            current page number
103  *
104  *      functions called:
105  *              int     fprintf()       c_library
106  *
107  *      side effects:
108  *              The page and line counters are updated.
109  */
110
111 VOID
112 newpag(fp)
113 FILE *fp;
114 {
115         fprintf(fp, "\fASxxxx Linker %s,  page %u.\n", VERSION, ++page);
116         lop = 1;
117 }
118
119 /* Used for qsort call in lstsym */
120 static int _cmpSymByAddr(const void *p1, const void *p2)
121 {
122     struct sym **s1 = (struct sym **)(p1);
123     struct sym **s2 = (struct sym **)(p2);
124     int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
125                 ((*s2)->s_addr + (*s2)->s_axp->a_addr);
126
127     /* Sort first by address, then by name. */
128     if (delta)
129     {
130         return delta;
131     }
132     return strcmp((*s1)->s_id,(*s2)->s_id);    
133 }
134
135
136 #if     NCPS-8
137
138 /* NCPS != 8 */
139 /*)Function     VOID    lstarea(xp)
140  *
141  *              area *  xp              pointer to an area structure
142  *
143  *      The function lstarea() creates the linker map output for
144  *      the area specified by pointer xp.  The generated output
145  *      area header includes the area name, starting address,
146  *      size of area, number of words (in decimal), and the
147  *      area attributes.  The symbols defined in this area are
148  *      sorted by ascending address and output one per line
149  *      in the selected radix.
150  *
151  *      local variables:
152  *              areax * oxp             pointer to an area extension structure
153  *              int     c               character value
154  *              int     i               loop counter
155  *              char *  ptr             pointer to an id string
156  *              int     nmsym           number of symbols in area
157  *              Addr_T  ai              temporary
158  *              Addr_T  aj              temporary
159  *              sym *   sp              pointer to a symbol structure
160  *              sym **  p               pointer to an array of
161  *                                      pointers to symbol structures
162  *
163  *      global variables:
164  *              FILE    *mfp            Map output file handle
165  *              sym *symhash[NHASH]     array of pointers to NHASH
166  *                                      linked symbol lists
167  *              int     xflag           Map file radix type flag
168  *
169  *      functions called:
170  *              int     fprintf()       c_library
171  *              VOID    free()          c_library
172  *              char *  malloc()        c_library
173  *              char    putc()          c_library
174  *              VOID    slew()          lklist.c
175  *
176  *      side effects:
177  *              Map output generated.
178  */
179
180 VOID
181 lstarea(struct area *xp)
182 {
183         register struct areax *oxp;
184         register int i;
185         register char *ptr;
186         int nmsym;
187         Addr_T     ai, aj;
188         struct sym *sp;
189         struct sym **p;
190         int memPage;
191
192         putc('\n', mfp);
193
194         /*
195          * Find number of symbols in area
196          */
197         nmsym = 0;
198         oxp = xp->a_axp;
199         while (oxp) {
200                 for (i=0; i<NHASH; i++) {
201                         sp = symhash[i];
202                         while (sp != NULL) {
203                                 if (oxp == sp->s_axp)
204                                         ++nmsym;
205                                 sp = sp->s_sp;
206                         }
207                 }
208                 oxp = oxp->a_axp;
209         }
210         if (nmsym == 0) {
211                 return;
212         }
213
214         if (xflag == 0) {
215                 fprintf(mfp, "Hexadecimal\n\n");
216         } else
217         if (xflag == 1) {
218                 fprintf(mfp, "Octal\n\n");
219         } else
220         if (xflag == 2) {
221                 fprintf(mfp, "Decimal\n\n");
222         }
223         fprintf(mfp, "Area                               ");
224         fprintf(mfp, "Addr   Size   Decimal %s (Attributes)\n",
225                 (xp->a_flag & A_BIT)?"Bits ":"Bytes");/* JCF: For BIT print bits...*/
226         fprintf(mfp, "--------------------------------   ");
227         fprintf(mfp, "----   ----   ------- ----- ------------\n");
228         /*
229          * Output Area Header
230          */
231         ptr = &xp->a_id[0];
232         fprintf(mfp, "%-32s", ptr );    /* JLH: width matches --- above */
233         ai = xp->a_addr;
234         aj = xp->a_size;
235         if (xflag == 0) {
236                 fprintf(mfp, "   %04X   %04X", ai, aj);
237         } else
238         if (xflag == 1) {
239                 fprintf(mfp, " %06o %06o", ai, aj);
240         } else
241         if (xflag == 2) {
242                 fprintf(mfp, "  %05u  %05u", ai, aj);
243         }
244         fprintf(mfp, " = %6u. %s ", aj,
245                 (xp->a_flag & A_BIT)?"bits ":"bytes"); /* JCF: For BIT print bits...*/
246         if (xp->a_flag & A_ABS) {
247                 fprintf(mfp, "(ABS");
248         } else {
249                 fprintf(mfp, "(REL");
250         }
251         if (xp->a_flag & A_OVR) {
252                 fprintf(mfp, ",OVR");
253         } else {
254                 fprintf(mfp, ",CON");
255         }
256         if (xp->a_flag & A_PAG) {
257                 fprintf(mfp, ",PAG");
258         }
259
260         memPage = 0x00;
261         if (xp->a_flag & A_CODE) {
262                 fprintf(mfp, ",CODE");
263                 memPage = 0x0C;
264         }
265         if (xp->a_flag & A_XDATA) {
266                 fprintf(mfp, ",XDATA");
267                 memPage = 0x0D;
268         }
269         if (xp->a_flag & A_BIT) {
270                 fprintf(mfp, ",BIT");
271                 memPage = 0x0B;
272         }
273         fprintf(mfp, ")");
274         if (xp->a_flag & A_PAG) {
275                 ai = (ai & 0xFF);
276                 aj = (aj > 256);
277                 if (ai || aj) { fprintf(mfp, "  "); }
278                 if (ai)      { fprintf(mfp, " Boundary"); }
279                 if (ai & aj)  { fprintf(mfp, " /"); }
280                 if (aj)      { fprintf(mfp, " Length"); }
281                 if (ai || aj) { fprintf(mfp, " Error"); }
282         }
283
284         /*
285          * Allocate space for an array of pointers to symbols
286          * and load array.
287          */
288         if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
289                 == NULL) {
290                 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
291                 return;
292         }
293         nmsym = 0;
294         oxp = xp->a_axp;
295         while (oxp) {
296                 for (i=0; i<NHASH; i++) {
297                         sp = symhash[i];
298                         while (sp != NULL) {
299                                 if (oxp == sp->s_axp) {
300                                         p[nmsym++] = sp;
301                                 }
302                                 sp = sp->s_sp;
303                         }
304                 }
305                 oxp = oxp->a_axp;
306         }
307
308         qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
309
310         /*
311          * Symbol Table Output
312          */
313
314         i = 0;
315         fprintf(mfp, "\n\n");
316         fprintf(mfp, "      Value  Global\n");
317         fprintf(mfp, "   --------  --------------------------------");
318         while (i < nmsym) {
319                 fprintf(mfp, "\n");
320                 if (memPage != 0) 
321                         fprintf(mfp, "  %02X:", memPage);
322                 else
323                         fprintf(mfp, "     ");
324
325                 sp = p[i];
326                 aj = sp->s_addr + sp->s_axp->a_addr;
327                 if (xflag == 0) {
328                         fprintf(mfp, "%04X    ", aj);
329                 } else
330                 if (xflag == 1) {
331                         fprintf(mfp, "%06o  ", aj);
332                 } else
333                 if (xflag == 2) {
334                         fprintf(mfp, "%05u   ", aj);
335                 }
336                 ptr = &sp->s_id[0];
337                 fprintf(mfp, "%s", ptr );
338                 
339                 /* if cdb flag set the output cdb Information 
340                    and the symbol has a '$' sign in it then */
341                 if (dflag &&
342                     strchr(ptr,'$'))
343                     fprintf(dfp,"L:%s:%X\n",ptr,aj);
344
345                 /* NoICE output of symbol */
346                 if (jflag) DefineNoICE( ptr, aj, memPage );
347
348                 i++;
349         }
350         putc('\n', mfp);
351         free(p);
352 }
353
354 #else
355
356 /* NCPS == 8 */
357 /*)Function     VOID    lstarea(xp)
358  *
359  *              area *  xp              pointer to an area structure
360  *
361  *      The function lstarea() creates the linker map output for
362  *      the area specified by pointer xp.  The generated output
363  *      area header includes the area name, starting address,
364  *      size of area, number of words (in decimal), and the
365  *      area attributes.  The symbols defined in this area are
366  *      sorted by ascending address and output four per line
367  *      in the selected radix.
368  *
369  *      local variables:
370  *              areax * oxp             pointer to an area extension structure
371  *              int     c               character value
372  *              int     i               loop counter
373  *              char *  ptr             pointer to an id string
374  *              int     nmsym           number of symbols in area
375  *              Addr_T  ai              temporary
376  *              Addr_T  aj              temporary
377  *              sym *   sp              pointer to a symbol structure
378  *              sym **  p               pointer to an array of
379  *                                      pointers to symbol structures
380  *
381  *      global variables:
382  *              FILE    *mfp            Map output file handle
383  *              sym *symhash[NHASH]     array of pointers to NHASH
384  *                                      linked symbol lists
385  *              int     xflag           Map file radix type flag
386  *
387  *      functions called:
388  *              int     fprintf()       c_library
389  *              VOID    free()          c_library
390  *              char *  malloc()        c_library
391  *              char    putc()          c_library
392  *              VOID    slew()          lklist.c
393  *
394  *      side effects:
395  *              Map output generated.
396  */
397
398 VOID
399 lstarea(struct area *xp)
400 {
401         register struct areax *oxp;
402         register int c, i;
403         register char *ptr;
404         int nmsym;
405         Addr_T ai, aj;
406         struct sym *sp;
407         struct sym **p;
408         int page;
409
410         putc('\n', mfp);
411         slew(mfp);
412         /*
413          * Output Area Header
414          */
415         ptr = &xp->a_id[0];
416         while (ptr < &xp->a_id[NCPS]) {
417                 if ((c = *ptr++) != 0) {
418                         putc(c, mfp);
419                 } else {
420                         putc(' ', mfp);
421                 }
422         }
423         ai = xp->a_addr;
424         aj = xp->a_size;
425         if (xflag == 0) {
426                 fprintf(mfp, "   %04X   %04X", ai, aj);
427         } else
428         if (xflag == 1) {
429                 fprintf(mfp, " %06o %06o", ai, aj);
430         } else
431         if (xflag == 2) {
432                 fprintf(mfp, "  %05u  %05u", ai, aj);
433         }
434         fprintf(mfp, " = %6u. bytes ", aj);
435         if (xp->a_flag & A_ABS) {
436                 fprintf(mfp, "(ABS");
437         } else {
438                 fprintf(mfp, "(REL");
439         }
440         if (xp->a_flag & A_OVR) {
441                 fprintf(mfp, ",OVR");
442         } else {
443                 fprintf(mfp, ",CON");
444         }
445         if (xp->a_flag & A_PAG) {
446                 fprintf(mfp, ",PAG");
447         }
448
449         page = 0x00;
450         if (xp->a_flag & A_CODE) {
451                 fprintf(mfp, ",CODE");
452                 memPage = 0x0C;
453         }
454         if (xp->a_flag & A_XDATA) {
455                 fprintf(mfp, ",XDATA");
456                 memPage = 0x0D;
457         }
458         if (xp->a_flag & A_BIT) {
459                 fprintf(mfp, ",BIT");
460                 memPage = 0x0B;
461         }
462         fprintf(mfp, ")");
463         if (xp->a_flag & A_PAG) {
464                 ai = (ai & 0xFF);
465                 aj = (aj > 256);
466                 if (ai || aj) { fprintf(mfp, "  "); }
467                 if (ai)      { fprintf(mfp, " Boundary"); }
468                 if (ai & aj)  { fprintf(mfp, " /"); }
469                 if (aj)      { fprintf(mfp, " Length"); }
470                 if (ai || aj) { fprintf(mfp, " Error"); }
471         }
472
473         /*
474          * Find number of symbols in area
475          */
476         nmsym = 0;
477         oxp = xp->a_axp;
478         while (oxp) {
479                 for (i=0; i<NHASH; i++) {
480                         sp = symhash[i];
481                         while (sp != NULL) {
482                                 if (oxp == sp->s_axp)
483                                         ++nmsym;
484                                 sp = sp->s_sp;
485                         }
486                 }
487                 oxp = oxp->a_axp;
488         }
489         if (nmsym == 0) {
490                 putc('\n', mfp);
491                 slew(mfp);
492                 return;
493         }
494
495         /*
496          * Allocate space for an array of pointers to symbols
497          * and load array.
498          */
499         if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
500                 == NULL) {
501                 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
502                 slew(mfp);
503                 return;
504         }
505         nmsym = 0;
506         oxp = xp->a_axp;
507         while (oxp) {
508                 for (i=0; i<NHASH; i++) {
509                         sp = symhash[i];
510                         while (sp != NULL) {
511                                 if (oxp == sp->s_axp) {
512                                         p[nmsym++] = sp;
513                                 }
514                                 sp = sp->s_sp;
515                         }
516                 }
517                 oxp = oxp->a_axp;
518         }
519
520         qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
521
522         /*
523          * Symbol Table Output
524          */
525         i = 0;
526         while (i < nmsym) {
527                 fprintf(mfp, "\n");
528                 slew(mfp);
529                 fprintf(mfp, "     ");
530                 sp = p[i];
531                 aj = sp->s_addr + sp->s_axp->a_addr;
532                 if (xflag == 0) {
533                         fprintf(mfp, "  %04X  ", aj);
534                 } else
535                 if (xflag == 1) {
536                         fprintf(mfp, "%06o  ", aj);
537                 } else
538                 if (xflag == 2) {
539                         fprintf(mfp, " %05u  ", aj);
540                 }
541                 ptr = &sp->s_id[0];
542                 fprintf(mfp, "%*s", NCPS, ptr );
543
544                 /* NoICE output of symbol */
545                 if (jflag) DefineNoICE( ptr, aj, memPage );
546         }
547         putc('\n', mfp);
548         free(p);
549         slew(mfp);
550 }
551 #endif
552
553 #ifdef SDK
554 VOID lstareatosym(struct area *xp)
555 {
556         /* Output the current area symbols to a NO$GMB .sym file */
557         register struct areax *oxp;
558         register int i;
559         int nmsym;
560         Addr_T a0;
561         struct sym *sp;
562         struct sym **p;
563
564         /*
565          * Find number of symbols in area
566          */
567         nmsym = 0;
568         oxp = xp->a_axp;
569         while (oxp) {
570                 for (i=0; i<NHASH; i++) {
571                         sp = symhash[i];
572                         while (sp != NULL) {
573                                 if (oxp == sp->s_axp)
574                                         ++nmsym;
575                                 sp = sp->s_sp;
576                         }
577                 }
578                 oxp = oxp->a_axp;
579         }
580
581         /*
582          * Symbol Table Output
583          */
584         if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) {
585                 /* Dont worry about any area information */
586                 fprintf(mfp, "; Area: %s\n", xp->a_id );
587                 if (nmsym>0) {
588                         /*
589                          * Allocate space for an array of pointers to symbols
590                          * and load array.
591                          */
592                         if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *)))
593                             == NULL) {
594                                 fprintf(mfp, "\nInsufficient space to build Map Segment.\n");
595                                 return;
596                         }
597                         nmsym = 0;
598                         oxp = xp->a_axp;
599                         while (oxp) {
600                                 for (i=0; i<NHASH; i++) {
601                                         sp = symhash[i];
602                                         while (sp != NULL) {
603                                                 if (oxp == sp->s_axp) {
604                                                         p[nmsym++] = sp;
605                                                 }
606                                                 sp = sp->s_sp;
607                                         }
608                                 }
609                                 oxp = oxp->a_axp;
610                         }
611
612                         qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
613
614                         i = 0;
615                         while (i < nmsym) {
616                                 /* no$gmb requires the symbol names to be less than 32 chars long.  Truncate. */
617                                 char name[32];
618                                 strncpy(name, p[i]->s_id, 31);
619                                 name[31] = '\0';
620                                 if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) {
621                                         a0=p[i]->s_addr + p[i]->s_axp->a_addr;
622                                         if (a0>0x7FFFU) {
623                                                 /* Not inside the ROM, so treat as being in bank zero */
624                                                 fprintf(mfp, "00:%04X %s\n", a0, name);
625                                         }
626                                         else {
627                                                 fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name);
628                                         }
629                                 }
630                                 i++;
631                         }
632                         free(p);
633                 }
634         }
635 }
636 #endif
637
638 /*)Function     VOID    lkulist(i)
639  *
640  *              int     i       i # 0   process LST to RST file
641  *                              i = 0   copy remainder of LST file
642  *                                      to RST file and close files
643  *
644  *      The function lkulist() creates a relocated listing (.rst)
645  *      output file from the ASxxxx assembler listing (.lst)
646  *      files.  The .lst file's program address and code bytes
647  *      are changed to reflect the changes made by ASlink as
648  *      the .rel files are combined into a single relocated
649  *      output file.
650  *
651  *      local variables:
652  *              Addr_T  pc              current program counter address
653  *
654  *      global variables:
655  *              int     hilo            byte order
656  *              int     gline           get a line from the LST file
657  *                                      to translate for the RST file
658  *              char    rb[]            read listing file text line
659  *              FILE    *rfp            The file handle to the current
660  *                                      output RST file
661  *              int     rtcnt           count of data words
662  *              int     rtflg[]         output the data flag
663  *              Addr_T  rtval[]         relocated data
664  *              FILE    *tfp            The file handle to the current
665  *                                      LST file being scanned
666  *
667  *      functions called:
668  *              int     fclose()        c_library
669  *              int     fgets()         c_library
670  *              int     fprintf()       c_library
671  *              VOID    lkalist()       lklist.c
672  *              VOID    lkglist()       lklist.c
673  *
674  *      side effects:
675  *              A .rst file is created for each available .lst
676  *              file associated with a .rel file.
677  */
678
679 VOID
680 lkulist(int i)
681 {
682         Addr_T pc;
683
684         /*
685          * Exit if listing file is not open
686          */
687         if (tfp == NULL)
688                 return;
689
690         /*
691          * Normal processing of LST to RST
692          */
693         if (i) {
694                 /*
695                  * Evaluate current code address
696                  */
697                 if (hilo == 0) {
698                         pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF);
699                 } else {
700                         pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF);
701                 }
702
703                 /*
704                  * Line with only address
705                  */
706                 if (rtcnt == 2) {
707                         lkalist(pc);
708
709                 /*
710                  * Line with address and code
711                  */
712                 } else {
713                         for (i=2; i < rtcnt; i++) {
714                                 if (rtflg[i]) {
715                                         lkglist(pc++, rtval[i] & 0xFF);
716                                 }
717                         }
718                 }
719
720         /*
721          * Copy remainder of LST to RST
722          */
723         } else {
724                 if (gline == 0)
725                         fprintf(rfp, "%s", rb);
726
727                 while (fgets(rb, sizeof(rb), tfp) != 0) {
728                         fprintf(rfp, "%s", rb);
729                 }
730                 fclose(tfp);
731                 tfp = NULL;
732                 fclose(rfp);
733                 rfp = NULL;
734         }
735 }
736
737 /*)Function     VOID    lkalist(pc)
738  *
739  *              int     pc              current program counter value
740  *
741  *      The function lkalist() performs the following functions:
742  *
743  *      (1)     if the value of gline = 0 then the current listing
744  *              file line is copied to the relocated listing file output.
745  *
746  *      (2)     the listing file is read line by line and copied to
747  *              the relocated listing file until a valid source
748  *              line number and a program counter value of the correct
749  *              radix is found.  The new relocated pc value is substituted
750  *              and the line is written to the RST file.
751  *
752  *      local variables:
753  *              int     i               loop counter
754  *              char    str[]           temporary string
755  *
756  *      global variables:
757  *              int     gcntr           data byte counter
758  *              int     gline           get a line from the LST file
759  *                                      to translate for the RST file
760  *              char    rb[]            read listing file text line
761  *              char    *rp             pointer to listing file text line
762  *              FILE    *rfp            The file handle to the current
763  *                                      output RST file
764  *              FILE    *tfp            The file handle to the current
765  *                                      LST file being scanned
766  *
767  *      functions called:
768  *              int     dgt()           lklist.c
769  *              int     fclose()        c_library
770  *              int     fgets()         c_library
771  *              int     fprintf()       c_library
772  *              int     sprintf()       c_library
773  *              char *  strncpy()       c_library
774  *
775  *      side effects:
776  *              Lines of the LST file are copied to the RST file,
777  *              the last line copied has the code address
778  *              updated to reflect the program relocation.
779  */
780
781 VOID
782 lkalist(Addr_T pc)
783 {
784         char str[8];
785         int i;
786
787         /*
788          * Exit if listing file is not open
789          */
790 loop:   if (tfp == NULL)
791                 return;
792
793         /*
794          * Copy current LST to RST
795          */
796         if (gline == 0) {
797                 fprintf(rfp, "%s", rb);
798                 gline = 1;
799         }
800
801         /*
802          * Clear text line buffer
803          */
804         for (i=0,rp=rb; i<sizeof(rb); i++) {
805                 *rp++ = 0;
806         }
807
808         /*
809          * Get next LST text line
810          */
811         if (fgets(rb, sizeof(rb), tfp) == NULL) {
812                 fclose(tfp);
813                 tfp = NULL;
814                 fclose(rfp);
815                 rfp = NULL;
816                 return;
817         }
818
819         /*
820          * Must have an ASxxxx Listing line number
821          */
822         if (!dgt(RAD10, &rb[30], 1)) {
823                 fprintf(rfp, "%s", rb);
824                 goto loop;
825         }
826
827         /*
828          * Must have an address in the expected radix
829          */
830         if (radix == 16) {
831                 if (!dgt(RAD16, &rb[3], 4)) {
832                         fprintf(rfp, "%s", rb);
833                         goto loop;
834                 }
835                 sprintf(str, "%04X", pc);
836                 strncpy(&rb[3], str, 4);
837         } else
838         if (radix == 10) {
839                 if (!dgt(RAD10, &rb[3], 5)) {
840                         fprintf(rfp, "%s", rb);
841                         goto loop;
842                 }
843                 sprintf(str, "%05d", pc);
844                 strncpy(&rb[3], str, 5);
845         } else
846         if (radix == 8) {
847                 if (!dgt(RAD8, &rb[3], 6)) {
848                         fprintf(rfp, "%s", rb);
849                         goto loop;
850                 }
851                 sprintf(str, "%06o", pc);
852                 strncpy(&rb[3], str, 6);
853         }
854
855         /*
856          * Copy updated LST text line to RST
857          */
858         fprintf(rfp, "%s", rb);
859         gcntr = 0;
860 }
861
862 /*)Function     VOID    lkglist(pc,v)
863  *
864  *              int     pc              current program counter value
865  *              int     v               value of byte at this address
866  *
867  *      The function lkglist() performs the following functions:
868  *
869  *      (1)     if the value of gline = 1 then the listing file
870  *              is read line by line and copied to the
871  *              relocated listing file until a valid source
872  *              line number and a program counter value of the correct
873  *              radix is found.
874  *
875  *      (2)     The new relocated values and code address are
876  *              substituted and the line may be written to the RST file.
877  *
878  *      local variables:
879  *              int     i               loop counter
880  *              char    str[]           temporary string
881  *
882  *      global variables:
883  *              int     gcntr           data byte counter
884  *                                      set to -1 for a continuation line
885  *              int     gline           get a line from the LST file
886  *                                      to translate for the RST file
887  *              char    rb[]            read listing file text line
888  *              char    *rp             pointer to listing file text line
889  *              FILE    *rfp            The file handle to the current
890  *                                      output RST file
891  *              FILE    *tfp            The file handle to the current
892  *                                      LST file being scanned
893  *
894  *      functions called:
895  *              int     dgt()           lklist.c
896  *              int     fclose()        c_library
897  *              int     fgets()         c_library
898  *              int     fprintf()       c_library
899  *              int     sprintf()       c_library
900  *              char *  strncpy()       c_library
901  *
902  *      side effects:
903  *              Lines of the LST file are copied to the RST file
904  *              with updated data values and code addresses.
905  */
906
907 VOID
908 lkglist(Addr_T pc, int v)
909 {
910         char str[8];
911         int i;
912
913         /*
914          * Exit if listing file is not open
915          */
916 loop:   if (tfp == NULL)
917                 return;
918
919         /*
920          * Get next LST text line
921          */
922         if (gline) {
923                 /*
924                  * Clear text line buffer
925                  */
926                 for (i=0,rp=rb; i<sizeof(rb); i++) {
927                         *rp++ = 0;
928                 }
929
930                 /*
931                  * Get next LST text line
932                  */
933                 if (fgets(rb, sizeof(rb), tfp) == NULL) {
934                         fclose(tfp);
935                         tfp = NULL;
936                         fclose(rfp);
937                         rfp = NULL;
938                         return;
939                 }
940
941                 /*
942                  * Check for a listing line number if required
943                  */
944                 if (gcntr != -1) {
945                         if (!dgt(RAD10, &rb[30], 1)) {
946                                 fprintf(rfp, "%s", rb);
947                                 goto loop;
948                         }
949                         gcntr = 0;
950                 }
951                 gline = 0;
952         }
953
954         /*
955          * Hex Listing
956          */
957         if (radix == 16) {
958                 /*
959                  * Data Byte Pointer
960                  */
961                 if (gcntr == -1) {
962                         rp = &rb[8];
963                 } else {
964                         rp = &rb[8 + (3 * gcntr)];
965                 }
966                 /*
967                  * Number must be of proper radix
968                  */
969                 if (!dgt(RAD16, rp, 2)) {
970                         fprintf(rfp, "%s", rb);
971                         gline = 1;
972                         goto loop;
973                 }
974                 /*
975                  * Output new data value, overwrite relocation codes
976                  */
977                 sprintf(str, " %02X", v);
978                 strncpy(rp-1, str, 3);
979                 if (gcntr == -1) {
980                         gcntr = 0;
981                 }
982                 /*
983                  * Output relocated code address
984                  */
985                 if (gcntr == 0) {
986                         if (dgt(RAD16, &rb[3], 4)) {
987                                 sprintf(str, "%04X", pc);
988                                 strncpy(&rb[3], str, 4);
989                         }
990                 }
991                 /*
992                  * Output text line when updates finished
993                  */
994                 if (++gcntr == 6) {
995                         fprintf(rfp, "%s", rb);
996                         gline = 1;
997                         gcntr = -1;
998                 }
999         } else
1000         /*
1001          * Decimal Listing
1002          */
1003         if (radix == 10) {
1004                 /*
1005                  * Data Byte Pointer
1006                  */
1007                 if (gcntr == -1) {
1008                         rp = &rb[9];
1009                 } else {
1010                         rp = &rb[9 + (3 * gcntr)];
1011                 }
1012                 /*
1013                  * Number must be of proper radix
1014                  */
1015                 if (!dgt(RAD10, rp, 3)) {
1016                         fprintf(rfp, "%s", rb);
1017                         gline = 1;
1018                         goto loop;
1019                 }
1020                 /*
1021                  * Output new data value, overwrite relocation codes
1022                  */
1023                 sprintf(str, " %03d", v);
1024                 strncpy(rp-1, str, 4);
1025                 if (gcntr == -1) {
1026                         gcntr = 0;
1027                 }
1028                 /*
1029                  * Output relocated code address
1030                  */
1031                 if (gcntr == 0) {
1032                         if (dgt(RAD10, &rb[3], 5)) {
1033                                 sprintf(str, "%05d", pc);
1034                                 strncpy(&rb[3], str, 5);
1035                         }
1036                 }
1037                 /*
1038                  * Output text line when updates finished
1039                  */
1040                 if (++gcntr == 4) {
1041                         fprintf(rfp, "%s", rb);
1042                         gline = 1;
1043                         gcntr = -1;
1044                 }
1045         } else
1046         /*
1047          * Octal Listing
1048          */
1049         if (radix == 8) {
1050                 /*
1051                  * Data Byte Pointer
1052                  */
1053                 if (gcntr == -1) {
1054                         rp = &rb[10];
1055                 } else {
1056                         rp = &rb[10 + (3 * gcntr)];
1057                 }
1058                 /*
1059                  * Number must be of proper radix
1060                  */
1061                 if (!dgt(RAD8, rp, 3)) {
1062                         fprintf(rfp, "%s", rb);
1063                         gline = 1;
1064                         goto loop;
1065                 }
1066                 /*
1067                  * Output new data value, overwrite relocation codes
1068                  */
1069                 sprintf(str, " %03o", v);
1070                 strncpy(rp-1, str, 4);
1071                 if (gcntr == -1) {
1072                         gcntr = 0;
1073                 }
1074                 /*
1075                  * Output relocated code address
1076                  */
1077                 if (gcntr == 0) {
1078                         if (dgt(RAD8, &rb[3], 6)) {
1079                                 sprintf(str, "%06o", pc);
1080                                 strncpy(&rb[3], str, 6);
1081                         }
1082                 }
1083                 /*
1084                  * Output text line when updates finished
1085                  */
1086                 if (++gcntr == 4) {
1087                         fprintf(rfp, "%s", rb);
1088                         gline = 1;
1089                         gcntr = -1;
1090                 }
1091         }
1092 }
1093
1094 /*)Function     int     dgt(rdx,str,n)
1095  *
1096  *              int     rdx             radix bit code
1097  *              char    *str            pointer to the test string
1098  *              int     n               number of characters to check
1099  *
1100  *      The function dgt() verifies that the string under test
1101  *      is of the specified radix.
1102  *
1103  *      local variables:
1104  *              int     i               loop counter
1105  *
1106  *      global variables:
1107  *              ctype[]                 array of character types
1108  *
1109  *      functions called:
1110  *              none
1111  *
1112  *      side effects:
1113  *              none
1114  */
1115
1116 int
1117 dgt(int rdx, char *str, int n)
1118 {
1119         int i;
1120
1121         for (i=0; i<n; i++) {
1122                 if ((ctype[(unsigned char)(*str++)] & rdx) == 0)
1123                         return(0);
1124         }
1125         return(1);
1126 }