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