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