]> Shamusworld >> Repos - rmac/blob - listing.c
First working 64-bit version of RMAC
[rmac] / listing.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // LISTING.C - Listing Output
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8 // --------------------------------------------------------------------------
9 // 0    0    1    1    2    2    3    3    4    4    5    5    6    6    7    7
10 // 012345678901234567890123456789012345678901234567890123456789012345678901234567
11 // filename....                         Reboot's Macro Assembler N.N.NN (Unknown)
12 // nnnnn  aaaaaaaa  dddddddddddddddddddd T source code
13 // nnnnn  aaaaaaaa  dddddddddddddddd
14 // nnnnn           =vvvvvvvv
15
16 #include "listing.h"
17 #include "version.h"
18 #include "token.h"
19 #include "procln.h"
20 #include "sect.h"
21 #include "error.h"
22
23 char * list_fname;                                          // Listing filename
24 char subttl[TITLESIZ];                                      // Current subtitle
25 int listing;                                                // Listing level 
26 int pagelen = 61;                                           // Lines on a page
27 int nlines;                                                 // #lines on page so far
28 LONG lsloc;                                                 // `sloc' at start of line 
29
30 // Private
31 static int lcursect;                                        // `cursect' at start of line
32 static int llineno;                                         // `curlineno' at start of line 
33 static int pageno;                                          // Current page number 
34 static int pagewidth;                                       // #columns on a page
35 static int subflag;                                         // 0, don't do .eject on subttl (set 1)
36 static char lnimage[IMAGESIZ];                              // Image of output line
37 static char title[TITLESIZ];                                // Current title
38 static char datestr[20];                                    // Current date dd-mon-yyyy 
39 static char timestr[20];                                    // Current time hh:mm:ss [am|pm]
40 static char buf[IMAGESIZ];                                  // Buffer for numbers
41
42 static char * month[16] = { "",    "Jan", "Feb", "Mar",
43                            "Apr", "May", "Jun", "Jul",
44                            "Aug", "Sep", "Oct", "Nov",
45                            "Dec", "",    "",    ""     };
46
47 //
48 // Eject the Page (Print Empty Lines), Reset the Line Count and Bump the Page Number
49 //
50 int eject(void)
51 {
52         if (listing > 0)
53         {
54                 println("\f");
55                 nlines = 0;
56         }
57
58         return 0;
59 }
60
61
62 //
63 // Return GEMDOS Format Date
64 //
65 VALUE dos_date(void)
66 {
67         VALUE v;
68         struct tm * tm;
69         time_t tloc;
70
71         time(&tloc);
72         tm = localtime(&tloc);
73         v = ((tm->tm_year - 80) << 9) | ((tm->tm_mon+1) << 5) | tm->tm_mday;
74
75         return v;
76 }
77
78
79 // 
80 // Return GEMDOS Format Time
81 //
82 VALUE dos_time(void)
83 {
84         VALUE v;
85         struct tm * tm;
86         time_t tloc;
87
88         time(&tloc);
89         tm = localtime(&tloc);
90         v = (tm->tm_hour << 11) | (tm->tm_min) << 5 | tm->tm_sec;
91
92         return v;
93 }
94
95
96 //
97 // Generate a Time String
98 //
99 void time_string(char * buf, VALUE time)
100 {
101         int hour;
102         char *ampm;
103
104         hour = (time >> 11);
105
106         if (hour > 12)
107         {
108                 hour -= 12;
109                 ampm = "pm";
110         }
111         else
112                 ampm = "am";
113
114         sprintf(buf, "%d:%02d:%02d %s",
115                 hour, (int)((time >> 5) & 0x3F), (int)((time & 0x1F) << 1), ampm);
116 }
117
118
119 //
120 // Generate a Date String
121 //
122 void date_string(char * buf, VALUE date)
123 {
124         sprintf(buf, "%d-%s-%d",
125                 (int)(date & 0x1F), month[(date >> 5) & 0xF], (int)((date >> 9) + 1980));
126 }
127
128
129 //
130 // Copy `n' Characters from `src' to `dest' (also stops on EOS in src).
131 // Does not null-terminate dest.
132 //
133 void scopy(char *dest, char *src, int len)
134 {
135         if (len < 0)
136                 len = 1000;                                           // Some large number
137
138         while (len-- && *src)
139                 *dest++ = *src++;
140 }
141
142
143 //
144 // Transform letters a-f in the address and data columns of the listing to
145 // uppercase. (People seem  to like uppercase hex better in assembly-language
146 // listings....)
147 //
148 void uc_ln(char * ln)
149 {
150         int i;
151         char j;
152
153         for(i=LOC_COL; i<SRC_COL; ++i)
154         {
155                 if ((j = ln[i]) >= 'a' && j <= 'f')
156                         ln[i] = (char)(j - 0x20);
157         }
158 }
159
160
161 //
162 // Fill Region `dest' with `len' Characters `c' and Null Terminate the Region
163 //
164 void lnfill(char * dest, int len, char chr)
165 {
166         while (len--)
167                 *dest++ = chr;
168
169         *dest = EOS;
170 }
171
172
173 // 
174 // Create Listing File with the Appropriate Name
175 //
176 void list_setup(void)
177 {
178         char fnbuf[FNSIZ];
179
180         strcpy(fnbuf, list_fname);
181
182         if (*fnbuf == EOS)
183         {
184                 strcpy(fnbuf, firstfname);
185                 fext(fnbuf, ".prn", 1);
186         }
187
188         list_fname = NULL;
189         
190         if ((list_fd = open(fnbuf, _OPEN_FLAGS, _PERM_MODE)) < 0)
191                 cantcreat(fnbuf);
192 }
193
194
195 //
196 // Tag Listing with a Character, Typically for Errors or Warnings
197 //
198 void taglist(char chr)
199 {
200         lnimage[TAG_COL+1] = chr;
201 }
202
203
204 //
205 // Print a Line to the Listing File
206 //
207 void println(const char * ln)
208 {
209         unsigned int length;
210
211         if (list_fname != NULL)                                   //  Create listing file, if necessary
212                 list_setup();
213
214         length = strlen(ln);
215         write(list_fd, ln, length);
216         write(list_fd, "\n", 1L);
217 }
218
219
220 //
221 // Ship Line `ln' Out; Do Page Breaks and Title Stuff
222 //
223 void ship_ln(const char * ln)
224 {
225         // If listing level is <= 0, then don't print anything
226         if (listing <= 0)
227                 return;
228
229         // Notice bottom of page
230         if (nlines >= pagelen - BOT_MAR)
231                 eject();
232
233         // Print title, boilerplate, and subtitle at top of page
234         if (nlines == 0)
235         {
236                 ++pageno;
237                 println("");
238                 date_string(datestr, dos_date());
239                 time_string(timestr, dos_time());
240                 sprintf(buf,
241                         "%-40s%-20s Page %-4d    %s %s        RMAC %01i.%01i.%02i (%s)",
242                         title, curfname, pageno, timestr, datestr, MAJOR, MINOR, PATCH, PLATFORM);
243                 println(buf);
244                 sprintf(buf, "%s", subttl);
245                 println(buf);
246                 println("");
247                 nlines = 4;
248         }
249
250         println(ln);
251         ++nlines;
252 }
253
254
255 //
256 // Initialize Listing Generator
257 //
258 void init_list(void)
259 {
260         extern VALUE dos_date(), dos_time();
261
262         subflag = 0;
263         pageno = 0;
264         nlines = 0;
265         pagelen = 61;
266         pagewidth = 132;
267         strcpy(title, "");
268         strcpy(subttl, "");
269         date_string(datestr, dos_date());
270         time_string(timestr, dos_time());
271 }
272
273
274 //
275 // Listing EOL
276 //
277 void listeol(void)
278 {
279         CHUNK * ch;
280         char * p;
281         int col;
282         LONG count;
283         int fixcount;
284
285         DEBUG printf("~list: lsloc=$%ux sloc=$%ux\n", lsloc, sloc);
286
287         if (lsloc != sloc)
288         {
289                 sprintf(buf, "%08ux", lsloc);
290                 scopy(lnimage+LOC_COL, buf, 8);
291         }
292
293         if (llineno != curlineno)
294         {
295                 sprintf(buf, "%5d", llineno);
296                 scopy(lnimage+LN_COL, buf, 5);
297         }
298
299         // List bytes only when section stayed the same and the section is not a
300         // "no-data" (SBSS) section. An extra annoyance is caused by "ds.b" in a
301         // microprocessor mode, which prints out bytes of zero as if they had been
302         // deposited with dcb. The fix (kludge) is an extra variable which records
303         // the fact that a 'ds.x' directive generated all the data, and it
304         // shouldn't be listed
305         savsect();                                               // Update section variables
306
307         if (lcursect == cursect && (sect[lcursect].scattr & SBSS) == 0
308                 && lsloc != sloc && just_bss == 0)
309         {
310                 ch = sect[lcursect].sfcode;
311
312                 for(; ch!=NULL; ch=ch->chnext)
313                 {
314                         if (lsloc >= ch->chloc && lsloc < (ch->chloc + ch->ch_size))
315                                 break;
316                 }
317
318                 // Fatal: Can't find chunk holding code
319                 if (ch == NULL)
320                 {
321 nochunk:
322                         interror(6);                                       // Can't find generated code in section
323                 }
324
325                 p =  ch->chptr + (lsloc - ch->chloc);
326                 col = DATA_COL;
327                 fixcount = 0;
328
329                 for(count=sloc-lsloc; count--; col+=2, ++lsloc)
330                 {
331                         if (col >= DATA_END)
332                         {                              // Ship the line
333                                 col = DATA_COL;
334                                 uc_ln(lnimage);
335                                 ship_ln(lnimage);
336                                 lnfill(lnimage, SRC_COL, SPACE);                // Fill with spaces
337                                 sprintf(buf, "%08ux", lsloc);
338                                 scopy(lnimage+LOC_COL, buf, 8);
339                         }
340
341                         if (lsloc >= (ch->chloc + ch->ch_size))
342                         {
343                                 if ((ch = ch->chnext) == NULL)
344                                         goto nochunk;
345
346                                 p = ch->chptr;
347                         }
348
349                         if (!fixcount)
350                                 fixcount = fixtest(lcursect, lsloc);
351
352                         if (fixcount)
353                         {
354                                 --fixcount;
355                                 strcpy(buf, "xx");
356                                 ++p;                                            // Advance anyway
357                         }
358                         else 
359                                 sprintf(buf, "%02x", *p++ & 0xff);
360
361                         scopy(lnimage+col, buf, 2);
362                 }
363
364                 // Flush partial line 
365                 if (col > DATA_COL)
366                 {
367                         uc_ln(lnimage);
368                         ship_ln(lnimage);
369                 }
370         }
371         else
372         {
373                 uc_ln(lnimage);
374                 ship_ln(lnimage);
375         }
376 }
377
378
379 //
380 // Copy Current (Saved) Line to Output Buffer and Tag it with a Character
381 //
382 void lstout(char tag)
383 {
384         char * s;
385         char * d;
386
387         lsloc = sloc;
388         lcursect = cursect;
389         llineno = curlineno;
390
391         lnfill(lnimage, SRC_COL, SPACE);                         // Fill with spaces
392         lnimage[TAG_COL] = tag;
393
394         // Copy line image and handle control characters
395         d = lnimage + SRC_COL;
396
397         for(s=lnbuf; *s; ++s)
398         {
399                 if (*s >= 0x20 || *s == '\t')
400                         *d++ = *s;
401                 else
402                 {
403                         *d++ = '^';
404                         *d++ = (char)(*s + 0x40);
405                 }
406         }
407
408         *d++ = EOS;
409 }
410
411
412 //
413 // Output a Value to Listing
414 //
415 int listvalue(VALUE v)
416 {
417         sprintf(buf, "=%08ux", v);
418         scopy(lnimage + DATA_COL - 1, buf, 9);
419         return 0;
420 }
421
422
423 /*
424  *  .subttl [-] "string"
425  *
426  *  Set subtitle;
427  *    o  leading '-' supresses page eject
428  *    o  don't .eject on first .subttl, but do so on all other ones,
429  *    o  arrange not to print the .subttl directive
430  *
431  */
432 int d_subttl(void)
433 {
434         int ejectok;
435         ejectok = 1;
436
437         if (*tok == '-')
438         {
439                 ejectok = 0;
440                 ++tok;
441         }
442
443         if (*tok != STRING)
444                 return error("missing string");
445
446 //      strcpy(subttl, (char *)tok[1]);
447         strcpy(subttl, string[tok[1]]);
448
449         tok += 2;
450
451         if (ejectok && (subflag || pageno > 1))                   // Always eject on pages 2+ 
452                 eject();
453
454         subflag = 1;
455
456         return 0;
457 }
458
459
460 //
461 // Set title on titles not on the first page, do an eject and clobber the subtitle
462 //
463 int d_title(void)
464 {
465         if (*tok != STRING)
466                 return error("missing string");
467         
468 //      strcpy(title, (char*)tok[1]);
469         strcpy(title, string[tok[1]]);
470         tok += 2;
471
472         if (pageno > 1)
473         {
474                 strcpy(subttl, "");
475                 eject();
476         }
477
478         return 0;
479 }