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