2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // LISTING.C - Listing Output
4 // Copyright (C) 199x Landon Dyer, 2011 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 // 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7
9 // 012345678901234567890123456789012345678901234567890123456789012345678901234567
10 // filename.... Reboot's Macro Assembler N.N.NN (Unknown)
11 // nnnnn aaaaaaaa dddddddddddddddddddd T source code
12 // nnnnn aaaaaaaa dddddddddddddddd
22 char *list_fname; // Listing filename
23 char subttl[TITLESIZ]; // Current subtitle
24 int listing; // Listing level
25 int pagelen = 61; // Lines on a page
26 int nlines; // #lines on page so far
27 LONG lsloc; // `sloc' at start of line
30 static int lcursect; // `cursect' at start of line
31 static int llineno; // `curlineno' at start of line
32 static int pageno; // Current page number
33 static int pagewidth; // #columns on a page
34 static int subflag; // 0, don't do .eject on subttl (set 1)
35 static char lnimage[IMAGESIZ]; // Image of output line
36 static char title[TITLESIZ]; // Current title
37 static char datestr[20]; // Current date dd-mon-yyyy
38 static char timestr[20]; // Current time hh:mm:ss [am|pm]
39 static char buf[IMAGESIZ]; // Buffer for numbers
41 static char *month[16] = { "", "Jan", "Feb", "Mar",
42 "Apr", "May", "Jun", "Jul",
43 "Aug", "Sep", "Oct", "Nov",
47 // --- Eject the Page (Print Empty Lines), Reset the Line Count and Bump the Page Number -----------
59 // --- Return GEMDOS Format Date -------------------------------------------------------------------
62 VALUE dos_date(void) {
68 tm = localtime(&tloc);
69 v = ((tm->tm_year - 80) << 9) | ((tm->tm_mon+1) << 5) | tm->tm_mday;
75 // --- Return GEMDOS Format Time -------------------------------------------------------------------
78 VALUE dos_time(void) {
84 tm = localtime(&tloc);
85 v = (tm->tm_hour << 11) | (tm->tm_min) << 5 | tm->tm_sec;
91 // --- Generate a Time String ----------------------------------------------------------------------
94 void time_string(char *buf, VALUE time) {
104 sprintf(buf, "%d:%02d:%02d %s",
105 hour, (int)((time >> 5) & 0x3f), (int)((time & 0x1f) << 1), ampm);
109 // --- Generate a Date String ----------------------------------------------------------------------
112 void date_string(char *buf, VALUE date) {
113 sprintf(buf, "%d-%s-%d",
114 (int)(date & 0x1f), month[(date >> 5) & 0xf], (int)((date >> 9) + 1980));
118 // -------------------------------------------------------------------------------------------------
119 // Copy `n' Characters from `src' to `dest' (also stops on EOS in src).
120 // Does not null-terminate dest.
121 // -------------------------------------------------------------------------------------------------
124 void scopy(char *dest, char *src, int len) {
126 len = 1000; // Some large number
132 // -------------------------------------------------------------------------------------------------
133 // Transform letters a-f in the address and data columns of the listing to uppercase. (People seem
134 // to like uppercase hex better in assembly-language listings....)
135 // -------------------------------------------------------------------------------------------------
138 void uc_ln(char *ln) {
142 for(i = LOC_COL; i < SRC_COL; ++i)
143 if((j = ln[i]) >= 'a' && j <= 'f')
144 ln[i] = (char)(j - 0x20);
148 // --- Fill Region `dest' with `len' Characters `c' and Null Terminate the Region ------------------
151 void lnfill(char *dest, int len, char chr) {
158 // --- Create Listing File with the Appropriate Name -----------------------------------------------
161 void list_setup(void) {
164 strcpy(fnbuf, list_fname);
166 strcpy(fnbuf, firstfname);
167 fext(fnbuf, ".prn", 1);
171 if((list_fd = open(fnbuf, _OPEN_FLAGS, _PERM_MODE)) < 0)
176 // --- Tag Listing with a Character, Typically for Errors or Warnings ------------------------------
178 void taglist(char chr) {
179 lnimage[TAG_COL+1] = chr;
183 // --- Print a Line to the Listing File ------------------------------------------------------------
186 void println(char *ln) {
189 if(list_fname != NULL) // Create listing file, if necessary
193 write(list_fd, ln, length);
194 write(list_fd, "\n", 1L);
198 // --- Ship Line `ln' Out; Do Page Breaks and Title Stuff ------------------------------------------
201 void ship_ln(char *ln) {
202 // If listing level is <= 0, then don't print anything
206 // Notice bottom of page
207 if(nlines >= pagelen - BOT_MAR)
210 // Print title, boilerplate, and subtitle at top of page
214 date_string(datestr, dos_date());
215 time_string(timestr, dos_time());
217 "%-40s%-20s Page %-4d %s %s RMAC %01i.%01i.%02i (%s)",
218 title, curfname, pageno, timestr, datestr, MAJOR, MINOR, PATCH, PLATFORM);
220 sprintf(buf, "%s", subttl);
231 // --- Initialize Listing Generator ----------------------------------------------------------------
234 void init_list(void) {
235 extern VALUE dos_date(), dos_time();
244 date_string(datestr, dos_date());
245 time_string(timestr, dos_time());
249 // --- Listing EOL ---------------------------------------------------------------------------------
259 DEBUG printf("~list: lsloc=$%lx sloc=$%lx\n", lsloc, sloc);
262 sprintf(buf, "%08lx", lsloc);
263 scopy(lnimage+LOC_COL, buf, 8);
266 if(llineno != curlineno) {
267 sprintf(buf, "%5d", llineno);
268 scopy(lnimage+LN_COL, buf, 5);
271 // List bytes only when section stayed the same and the section is not a "no-data" (SBSS)
272 // section. An extra annoyance is caused by "ds.b" in a microprocessor mode, which prints
273 // out bytes of zero as if they had been deposited with dcb. The fix (kludge) is an extra
274 // variable which records the fact that a 'ds.x' directive generated all the data, and it
275 // shouldn't be listed
276 savsect(); // Update section variables
277 if(lcursect == cursect && (sect[lcursect].scattr & SBSS) == 0 && lsloc != sloc && just_bss==0) {
278 ch = sect[lcursect].sfcode;
279 for(; ch != NULL; ch = ch->chnext)
280 if(lsloc >= ch->chloc && lsloc < (ch->chloc + ch->ch_size))
283 if(ch == NULL) { // Fatal: Can't find chunk holding code
287 interror(6); // Can't find generated code in section
290 p = ch->chptr + (lsloc - ch->chloc);
293 for(count = sloc - lsloc; count--; col += 2, ++lsloc) {
294 if(col >= DATA_END) { // Ship the line
298 lnfill(lnimage, SRC_COL, SPACE); // Fill with spaces
299 sprintf(buf, "%08lx", lsloc);
300 scopy(lnimage+LOC_COL, buf, 8);
303 if(lsloc >= (ch->chloc + ch->ch_size)) {
304 if((ch = ch->chnext) == NULL)
310 fixcount = fixtest(lcursect, lsloc);
315 ++p; // Advance anyway
317 sprintf(buf, "%02x", *p++ & 0xff);
318 scopy(lnimage+col, buf, 2);
321 if(col > DATA_COL) { // Flush partial line
332 // --- Copy Current (Saved) Line to Output Buffer and Tag it with a Character ----------------------
335 void lstout(char tag) {
343 lnfill(lnimage, SRC_COL, SPACE); // Fill with spaces
344 lnimage[TAG_COL] = tag;
346 // Copy line image and handle control characters
347 d = lnimage + SRC_COL;
348 for(s = lnbuf; *s; ++s)
349 if(*s >= 0x20 || *s == '\t')
353 *d++ = (char)(*s + 0x40);
359 // --- Output a Value to Listing -------------------------------------------------------------------
362 int listvalue(VALUE v) {
363 sprintf(buf, "=%08lx", v);
364 scopy(lnimage+DATA_COL-1, buf, 9);
369 * .subttl [-] "string"
372 * o leading '-' supresses page eject
373 * o don't .eject on first .subttl, but do so on all other ones,
374 * o arrange not to print the .subttl directive
387 return(error("missing string"));
388 strcpy(subttl, (char*)tok[1]);
391 if(ejectok && (subflag || pageno > 1)) // Always eject on pages 2+
399 // --- Set title on titles not on the first page, do an eject and clobber the subtitle -------------
404 return(error("missing string"));
405 strcpy(title, (char*)tok[1]);