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