From af962aef3392ae23a5f851946e995bca3117d90e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 24 Mar 2020 18:35:30 +0100 Subject: [PATCH] updated to r2176 from official svn repo --- 64tass.1 | 6 +- 64tass.c | 3 +- 64tass.h | 6 +- Makefile | 2 +- Makefile.amigaos | 2 +- Makefile.amigaos4 | 2 +- Makefile.win | 2 +- README | 4 +- README.html | 8 +-- arguments.c | 9 ++- encoding.c | 6 +- error.c | 33 +++++----- file.c | 68 ++++++++++++------- functionobj.c | 9 +-- main.c | 5 +- mem.c | 162 +++++++++++++++++++++++++++++++--------------- 16 files changed, 205 insertions(+), 122 deletions(-) diff --git a/64tass.1 b/64tass.1 index fd71952..c5b0192 100644 --- a/64tass.1 +++ b/64tass.1 @@ -1,4 +1,4 @@ -.TH 64tass 1 "Feb 17 2019" "64tass 1.54" "64tass 1.54" +.TH 64tass 1 "Mar 23 2020" "64tass 1.55" "64tass 1.55" .SH NAME 64tass \- A multi pass optimizing macro assembler for the 65xx series of processors .SH SYNOPSIS @@ -379,9 +379,9 @@ Normally the exit status is 0 if no error occured. .SH AUTHOR Written by Zsolt Kajtar. .SH "REPORTING BUGS" -Online bug tracker: +Online bug tracker: .SH COPYRIGHT -Copyright \(co 2019 Zsolt Kajtar. +Copyright \(co 2020 Zsolt Kajtar. License GPLv2+: GNU GPL version 2 or later . .br This is free software: you are free to change and redistribute it. diff --git a/64tass.c b/64tass.c index 39ae6e9..8cdcc30 100644 --- a/64tass.c +++ b/64tass.c @@ -1,6 +1,6 @@ /* Turbo Assembler 6502/65C02/65816/DTV - $Id: 64tass.c 2156 2020-03-08 12:44:05Z soci $ + $Id: 64tass.c 2158 2020-03-22 07:58:51Z soci $ 6502/65C02 Turbo Assembler Version 1.3 (c) 1996 Taboo Productions, Marek Matula @@ -4879,6 +4879,7 @@ int main2(int *argc2, char **argv2[]) { int argc; err_init(*argv2[0]); + setvbuf(stdout, NULL, _IOLBF, 1024); avltree_init(&star_root); objects_init(); init_section(); diff --git a/64tass.h b/64tass.h index 0353d25..8d2ca4f 100644 --- a/64tass.h +++ b/64tass.h @@ -1,5 +1,5 @@ /* - $Id: 64tass.h 2050 2019-11-01 08:37:21Z soci $ + $Id: 64tass.h 2176 2020-03-23 20:12:04Z soci $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,10 +23,10 @@ #include "inttypes.h" #include "wait_e.h" #ifndef REVISION -#define REVISION "1900?" +#define REVISION "2176?" #endif #undef VERSION -#define VERSION "1.54." REVISION +#define VERSION "1.55." REVISION #define MAX_PASS 20 #define ignore() while(pline[lpoint.pos]==0x20 || pline[lpoint.pos]==0x09) lpoint.pos++ diff --git a/Makefile b/Makefile index 83698fb..8f4338a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ OBJ = 64tass.o opcodes.o str.o avl.o my_getopt.o eval.o error.o section.o \ errorobj.o macroobj.o mfuncobj.o identobj.o memblocksobj.o foldobj.o main.o LDLIBS = -lm LANG = C -REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "1900?") +REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "2176?") CFLAGS = -O2 -W -Wall -Wextra -Wwrite-strings -Wshadow -fstrict-aliasing -DREVISION="\"$(REVISION)\"" -Wstrict-aliasing=2 -Werror=missing-prototypes LDFLAGS = -g CFLAGS += $(LDFLAGS) diff --git a/Makefile.amigaos b/Makefile.amigaos index f7abe91..9c40f98 100644 --- a/Makefile.amigaos +++ b/Makefile.amigaos @@ -8,7 +8,7 @@ OBJ = 64tass.o opcodes.o str.o avl.o my_getopt.o eval.o error.o section.o \ errorobj.o macroobj.o mfuncobj.o identobj.o memblocksobj.o foldobj.o main.o LDLIBS = -lmsoft LANG = C -REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "1900?") +REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "2176?") CFLAGS = -c99 -soft-float LDFLAGS = CFLAGS += $(LDFLAGS) diff --git a/Makefile.amigaos4 b/Makefile.amigaos4 index fdf64e2..0ae2c4a 100644 --- a/Makefile.amigaos4 +++ b/Makefile.amigaos4 @@ -8,7 +8,7 @@ OBJ = 64tass.o opcodes.o str.o avl.o my_getopt.o eval.o error.o section.o \ errorobj.o macroobj.o mfuncobj.o identobj.o memblocksobj.o foldobj.o main.o LDLIBS = -lm LANG = C -REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "1900?") +REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "2176?") CFLAGS = -O2 -W -Wall -Wextra -DREVISION="\"$(REVISION)\"" LDFLAGS = -s CFLAGS += $(LDFLAGS) diff --git a/Makefile.win b/Makefile.win index 1725379..0d788d9 100644 --- a/Makefile.win +++ b/Makefile.win @@ -8,7 +8,7 @@ OBJ = 64tass.o opcodes.o str.o avl.o my_getopt.o eval.o error.o section.o \ errorobj.o macroobj.o mfuncobj.o identobj.o memblocksobj.o foldobj.o main.o LDLIBS = -lm LANG = C -REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "1900?") +REVISION := $(shell svnversion | grep --color=none "^[1-9]" || echo "2176?") CFLAGS = -O2 -march=i586 -W -Wall -Wextra -DREVISION="\"$(REVISION)\"" LDFLAGS = -s CFLAGS += $(LDFLAGS) diff --git a/README b/README index 9789b10..e4b279b 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -64tass v1.54 r1900 reference manual +64tass v1.55 r2176 reference manual This is the manual for 64tass, the multi pass optimizing macro assembler for the 65xx series of processors. Key features: @@ -27,7 +27,7 @@ This is a development version. Features or syntax may change as a result of corrections in non-backwards compatible ways in some rare cases. It's difficult to get everything `right' first time. -Project page: http://sourceforge.net/projects/tass64/ +Project page: https://sourceforge.net/projects/tass64/ The page hosts the latest and older versions with sources and a bug and a feature request tracker. diff --git a/README.html b/README.html index 55a4c7f..0a50ade 100644 --- a/README.html +++ b/README.html @@ -1,7 +1,7 @@ -64tass v1.54 r1900 reference manual +64tass v1.55 r2176 reference manual @@ -84,7 +84,7 @@
-

64tass v1.54 r1900 reference manual

+

64tass v1.55 r2176 reference manual

This is the manual for 64tass, the multi pass optimizing macro assembler for the 65xx series of processors. Key features:

@@ -112,7 +112,7 @@

64tass v1.54 r1900 reference manual

of corrections in non-backwards compatible ways in some rare cases. It's difficult to get everything right first time.

-

Project page: http://sourceforge.net/projects/tass64/

+

Project page: https://sourceforge.net/projects/tass64/

The page hosts the latest and older versions with sources and a bug and a feature request tracker.

@@ -279,7 +279,7 @@

Usage tips

There are also some useful parameters which are described later.

-

For comfortable compiling I use such Makefiles (for make):

+

For comfortable compiling I use such Makefiles (for make):

 demo.prg: source.asm macros.asm pic.drp music.bin
diff --git a/arguments.c b/arguments.c
index cb6d1b6..f6bebdb 100644
--- a/arguments.c
+++ b/arguments.c
@@ -1,5 +1,5 @@
 /*
-    $Id: arguments.c 2125 2019-12-23 19:50:58Z soci $
+    $Id: arguments.c 2172 2020-03-22 19:46:59Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -458,6 +458,7 @@ static MUST_CHECK char *read_one(FILE *f) {
 
 static address_t get_all_mem2(void) {
     size_t i;
+    bool tostdout = false;
     address_t min = 0xffffffff;
     for (i = 0; i < arguments.output_len; i++) {
         const struct output_s *output = &arguments.output[i];
@@ -471,7 +472,11 @@ static address_t get_all_mem2(void) {
         case OUTPUT_APPLE:
         case OUTPUT_XEX: min &= 0xffff; break;
         }
-        if (dash_name(output->name)) arguments.quiet = false;
+        if (dash_name(output->name)) tostdout = true;
+    }
+    if (tostdout) {
+        arguments.quiet = false;
+        setvbuf(stdout, NULL, _IOFBF, BUFSIZ);
     }
     return min;
 }
diff --git a/encoding.c b/encoding.c
index 213edca..c027190 100644
--- a/encoding.c
+++ b/encoding.c
@@ -1,5 +1,5 @@
 /*
-    $Id: encoding.c 2108 2019-12-10 19:16:03Z soci $
+    $Id: encoding.c 2175 2020-03-23 19:18:35Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@
 
 struct encoding_s *actual_encoding;
 
-#define identmap (const uint8_t *)petscii_esc
+#define identmap (const uint8_t *)petscii_trans
 
 struct encoding_s {
     str_t name;
@@ -840,7 +840,7 @@ int encode_string(void) {
         t = cavltree_container_of(c, struct trans_s, node);
         if (tmp.start >= t->start && tmp.end <= t->end) {
             encode_state.i += ln;
-            if ((ch & 0x80) == 0) {
+            if (ch < 0x80) {
                 actual_encoding->table_use[ch / 32] |= 1 << (ch % 32);
                 actual_encoding->table[ch] = (uint8_t)(ch - t->start + t->offset);
             }
diff --git a/error.c b/error.c
index 9bfdc77..1878b0e 100644
--- a/error.c
+++ b/error.c
@@ -1,5 +1,5 @@
 /*
-    $Id: error.c 2155 2020-03-08 09:33:08Z soci $
+    $Id: error.c 2175 2020-03-23 19:18:35Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -1350,11 +1350,15 @@ static void print_error(FILE *f, const struct errorentry_s *err, bool caret) {
 
 #ifdef COLOR_OUTPUT
 static void color_detect(FILE *f) {
-    char const *term = getenv ("TERM");
-    print_use_color = term != NULL && strcmp(term, "dumb") != 0 && isatty(fileno(f)) == 1;
+    static int terminal;
+    if (terminal == 0) {
+        char const *term = getenv("TERM");
+        terminal = (term != NULL && strcmp(term, "dumb") != 0) ? 1 : 2;
+    }
+    print_use_color = terminal == 1 && isatty(fileno(f)) == 1;
 }
 #else
-#define color_detect(f) {}
+#define color_detect(f) do {} while (false)
 #endif
 
 static inline bool caret_needed(const struct errorentry_s *err) {
@@ -1404,7 +1408,7 @@ bool error_print(void) {
         }
     } else ferr = stderr;
 
-    color_detect(ferr);
+    if (ferr != stderr) color_detect(ferr); else if (arguments.quiet) fflush(stdout);
 
     warnings = errors = 0;
     close_error();
@@ -1466,7 +1470,7 @@ bool error_print(void) {
     }
     if (err3 != NULL) print_error(ferr, err3, different_line(err2, err3));
     if (err2 != NULL) print_error(ferr, err2, caret_needed(err2));
-    color_detect(stderr);
+    if (ferr != stderr) color_detect(stderr);
     if (ferr != stderr && ferr != stdout) fclose(ferr); else fflush(ferr);
     return errors != 0;
 }
@@ -1546,9 +1550,6 @@ void err_msg_file(Error_types no, const char *prm, linepos_t epoint) {
     int err = errno;
     bool more;
 
-#ifdef _WIN32
-    setlocale(LC_ALL, "");
-#endif
     s = strerror(err);
     n = strlen(s);
 
@@ -1574,17 +1575,17 @@ void err_msg_file(Error_types no, const char *prm, linepos_t epoint) {
         adderror((char *)s2);
         i += (size_t)l;
     }
-#ifdef _WIN32
-    setlocale(LC_ALL, "C");
-#endif
     if (more) new_error_msg_more();
 }
 
+static void error_status_val(const char *head, unsigned int val) {
+    fputs(head, stdout);
+    if (val != 0) printf("%u\n", val); else puts("None");
+}
+
 void error_status(void) {
-    printf("Error messages:    ");
-    if (errors != 0) printf("%u\n", errors); else puts("None");
-    printf("Warning messages:  ");
-    if (warnings != 0) printf("%u\n", warnings); else puts("None");
+    error_status_val("Error messages:    ", errors);
+    error_status_val("Warning messages:  ", warnings);
 }
 
 linecpos_t interstring_position(linepos_t epoint, const uint8_t *data, size_t i) {
diff --git a/file.c b/file.c
index 8cbf931..f101750 100644
--- a/file.c
+++ b/file.c
@@ -1,5 +1,5 @@
 /*
-    $Id: file.c 2125 2019-12-23 19:50:58Z soci $
+    $Id: file.c 2163 2020-03-22 12:45:33Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -24,6 +24,9 @@
 #include 
 #include 
 #endif
+#if defined _POSIX_C_SOURCE || defined __MINGW32__
+#include 
+#endif
 #include "64tass.h"
 #include "unicode.h"
 #include "error.h"
@@ -355,6 +358,26 @@ static inline uchar_t fromiso(uchar_t c) {
     return conv[c];
 }
 
+static size_t fsize(FILE *f) {
+#if defined _POSIX_C_SOURCE || defined __MINGW32__
+    struct stat st;
+    if (fstat(fileno(f), &st) == 0) {
+        if (S_ISREG(st.st_mode) && st.st_size > 0) {
+            return (size_t)st.st_size;
+        }
+    }
+#else
+    if (fseek(f, 0, SEEK_END) == 0) {
+        long len = ftell(f);
+        rewind(f);
+        if (len > 0) {
+            return (size_t)len;
+        }
+    }
+#endif
+    return 0;
+}
+
 static struct file_s *command_line = NULL;
 static struct file_s *lastfi = NULL;
 static struct ubuff_s last_ubuff;
@@ -419,23 +442,23 @@ struct file_s *openfile(const char *name, const char *base, int ftype, const str
             if (path == NULL) path = s;
             tmp->realname = path;
             if (arguments.quiet) {
-                printf((ftype == 1) ? "Reading file:      " : "Assembling file:   ");
+                fputs((ftype == 1) ? "Reading file:      " : "Assembling file:   ", stdout);
                 argv_print(path, stdout);
                 putchar('\n');
             }
             if (f == NULL) goto openerr;
+#ifndef __DJGPP__
+            setvbuf(f, NULL, _IONBF, 0);
+#endif
             tmp->read_error = true;
             if (ftype == 1) {
-                bool check = true;
-                if (fseek(f, 0, SEEK_END) == 0) {
-                    long len = ftell(f);
-                    if (len > 0) {
-                        size_t len2 = (size_t)len;
-                        tmp->data = (uint8_t *)malloc(len2);
-                        if (tmp->data != NULL) tmp->len = len2;
-                    }
-                    rewind(f);
+                bool check;
+                size_t fs = fsize(f);
+                if (fs > 0) {
+                    tmp->data = (uint8_t *)malloc(fs);
+                    if (tmp->data != NULL) tmp->len = fs;
                 }
+                check = (tmp->data != NULL);
                 clearerr(f); errno = 0;
                 if (tmp->len != 0 || !extendfile(tmp)) {
                     for (;;) {
@@ -464,19 +487,16 @@ struct file_s *openfile(const char *name, const char *base, int ftype, const str
                 line_t lines = 0;
                 uint8_t buffer[BUFSIZ * 2];
                 size_t bp = 0, bl, qr = 1;
-                if (fseek(f, 0, SEEK_END) == 0) {
-                    long len = ftell(f);
-                    if (len > 0) {
-                        size_t len2 = (size_t)len + 4096;
-                        if (len2 < 4096) len2 = SIZE_MAX; /* overflow */
-                        tmp->data = (uint8_t *)malloc(len2);
-                        if (tmp->data != NULL) tmp->len = len2;
-                        max_lines = (len2 / 20 + 1024) & ~(size_t)1023;
-                        if (max_lines > SIZE_MAX / sizeof *tmp->line) max_lines = SIZE_MAX / sizeof *tmp->line; /* overflow */
-                        tmp->line = (size_t *)malloc(max_lines * sizeof *tmp->line);
-                        if (tmp->line == NULL) max_lines = 0;
-                    }
-                    rewind(f);
+                size_t fs = fsize(f);
+                if (fs > 0) {
+                    size_t len2 = fs + 4096;
+                    if (len2 < 4096) len2 = SIZE_MAX; /* overflow */
+                    tmp->data = (uint8_t *)malloc(len2);
+                    if (tmp->data != NULL) tmp->len = len2;
+                    max_lines = (len2 / 20 + 1024) & ~(size_t)1023;
+                    if (max_lines > SIZE_MAX / sizeof *tmp->line) max_lines = SIZE_MAX / sizeof *tmp->line; /* overflow */
+                    tmp->line = (size_t *)malloc(max_lines * sizeof *tmp->line);
+                    if (tmp->line == NULL) max_lines = 0;
                 }
                 clearerr(f); errno = 0;
                 bl = fread(buffer, 1, BUFSIZ, f);
diff --git a/functionobj.c b/functionobj.c
index b05a936..cb0cb3e 100644
--- a/functionobj.c
+++ b/functionobj.c
@@ -1,5 +1,5 @@
 /*
-    $Id: functionobj.c 2123 2019-12-21 06:42:26Z soci $
+    $Id: functionobj.c 2173 2020-03-22 23:37:40Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -104,10 +104,11 @@ static MUST_CHECK Obj *gen_broadcast(Funcargs *vals, linepos_t epoint, func_t f)
     struct values_s *v = vals->val;
     size_t args = vals->len;
     size_t j;
-    struct {
+    struct elements_s {
         Obj *oval;
         struct iter_s iters;
-    } elements3[3], *elements;
+    };
+    struct elements_s elements3[3], *elements;
     for (j = 0; j < args; j++) {
         const Type *objt2, *objt = v[j].val->obj;
         if (objt->iterable) {
@@ -117,7 +118,7 @@ static MUST_CHECK Obj *gen_broadcast(Funcargs *vals, linepos_t epoint, func_t f)
                 elements = elements3; 
             } else {
                 if (args > SIZE_MAX / sizeof *elements) goto failed; /* overflow */
-                elements = malloc(args * sizeof *elements);
+                elements = (struct elements_s *)malloc(args * sizeof *elements);
                 if (elements == NULL) goto failed;
             }
             elements[j].oval = v[j].val;
diff --git a/main.c b/main.c
index 88aa33c..c4b533d 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
 /*
     Turbo Assembler 6502/65C02/65816/DTV
-    $Id: main.c 2088 2019-11-17 06:44:48Z soci $
+    $Id: main.c 2167 2020-03-22 14:25:29Z soci $
 
     6502/65C02 Turbo Assembler  Version 1.3
     (c) 1996 Taboo Productions, Marek Matula
@@ -134,8 +134,7 @@ int main(int argc, char *argv[]) {
     int i, r;
     char **uargv;
 
-    setlocale(LC_ALL, "");
-    setlocale(LC_NUMERIC, "C");
+    setlocale(LC_CTYPE, "");
 
     uargv = (char **)malloc((argc < 1 ? 1 : (unsigned int)argc) * sizeof *uargv);
     if (uargv == NULL) err_msg_out_of_memory2();
diff --git a/mem.c b/mem.c
index c06b20d..f3c85c6 100644
--- a/mem.c
+++ b/mem.c
@@ -1,5 +1,5 @@
 /*
-    $Id: mem.c 2124 2019-12-23 16:00:22Z soci $
+    $Id: mem.c 2170 2020-03-22 15:18:53Z soci $
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -169,12 +169,8 @@ void memprint(Memblocks *memblocks) {
     }
 }
 
-static void putlw(unsigned int w, FILE *f) {
-    putc(w, f);
-    putc(w >> 8, f);
-}
-
 static void padding(size_t size, FILE *f) {
+    unsigned char nuls[256];
     while (size >= 0x80000000) {
         if (fseek(f, 0x40000000, SEEK_CUR) != 0) goto err;
         size -= 0x40000000;
@@ -182,25 +178,55 @@ static void padding(size_t size, FILE *f) {
     if ((long)size > 256 && fseek(f, (long)size, SEEK_CUR) == 0) {
         return;
     }
-err:while ((size--) != 0) if (putc(0, f) == EOF) break;
+err:
+    nuls[0] = 1;
+    while (size != 0) {
+        size_t db = size < sizeof nuls ? size : sizeof nuls;
+        size -= db;
+        if (nuls[0] != 0) memset(nuls, 0, db);
+        if (fwrite(nuls, db, 1, f) == 0) return;
+    }
+}
+
+#ifdef __DJGPP__
+#define set_unbuffered(f) do {} while (false)
+#else
+static void set_unbuffered(FILE *fout) {
+    setvbuf(fout, NULL, _IONBF, 0);
 }
+#endif
 
 static void output_mem_c64(FILE *fout, const Memblocks *memblocks, const struct output_s *output) {
     address_t pos, end;
     unsigned int i;
+    unsigned char header[4];
 
     if (memblocks->p == 0) return;
     pos = memblocks->data[0].addr;
-    if (output->mode == OUTPUT_CBM || output->mode == OUTPUT_APPLE) {
-        putlw(pos, fout);
-    }
-    if (output->mode == OUTPUT_APPLE) {
+    switch (output->mode) {
+    case OUTPUT_CBM:
+        header[0] = pos;
+        header[1] = pos >> 8;
+        if (output->longaddr) {
+            header[2] = pos >> 16;
+            i = 3;
+        } else i = 2;
+        break;
+    case OUTPUT_APPLE:
+        header[0] = pos;
+        header[1] = pos >> 8;
         end = memblocks->data[memblocks->p - 1].addr + memblocks->data[memblocks->p - 1].len;
         end -= pos;
-        putlw(end, fout);
-    } else if (output->mode == OUTPUT_CBM) {
-        if (output->longaddr) putc(pos >> 16, fout);
+        header[2] = end;
+        header[3] = end >> 8;
+        i = 4;
+        break;
+    default:
+        i = 0;
+        break;
     }
+    if (memblocks->p == 1) set_unbuffered(fout);
+    if (i != 0 && fwrite(header, i, 1, fout) == 0) return;
     for (i = 0; i < memblocks->p; i++) {
         const struct memblock_s *block = &memblocks->data[i];
         padding(block->addr - pos, fout);
@@ -211,6 +237,7 @@ static void output_mem_c64(FILE *fout, const Memblocks *memblocks, const struct
 
 static void output_mem_nonlinear(FILE *fout, const Memblocks *memblocks, bool longaddr) {
     size_t i, j;
+    unsigned char header[6];
     for (i = 0; i < memblocks->p;) {
         const struct memblock_s *block = &memblocks->data[i];
         address_t start = block->addr;
@@ -221,23 +248,32 @@ static void output_mem_nonlinear(FILE *fout, const Memblocks *memblocks, bool lo
             if (b->addr != addr || addr < start) break;
             size += b->len;
         }
-        putlw(size, fout);
-        if (longaddr) putc(size >> 16, fout);
-        putlw(start, fout);
-        if (longaddr) putc(start >> 16, fout);
+        header[0] = size;
+        header[1] = size >> 8;
+        if (longaddr) {
+            header[2] = size >> 16;
+            header[3] = start;
+            header[4] = start >> 8;
+            header[5] = start >> 16;
+        } else {
+            header[2] = start;
+            header[3] = start >> 8;
+        }
+        if (fwrite(header, longaddr ? 6 : 4, 1, fout) == 0) return;
         for (;i < j; i++) {
             const struct memblock_s *b = &memblocks->data[i];
             if (fwrite(memblocks->mem.data + b->p, b->len, 1, fout) == 0) return;
         }
     }
-    putlw(0, fout);
-    if (longaddr) putc(0, fout);
+    memset(header, 0, 4);
+    fwrite(header, longaddr ? 3 : 2, 1, fout);
 }
 
 static void output_mem_flat(FILE *fout, const Memblocks *memblocks) {
     address_t pos;
     size_t i;
 
+    if (memblocks->p == 1 && memblocks->data[0].addr == 0) set_unbuffered(fout);
     for (pos = i = 0; i < memblocks->p; i++) {
         const struct memblock_s *block = &memblocks->data[i];
         padding(block->addr - pos, fout);
@@ -248,9 +284,14 @@ static void output_mem_flat(FILE *fout, const Memblocks *memblocks) {
 
 static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) {
     size_t i, j;
+    unsigned char header[6];
+    header[0] = 0xff;
+    header[1] = 0xff;
+    if (memblocks->p == 1) set_unbuffered(fout);
     for (i = 0; i < memblocks->p;) {
         const struct memblock_s *block = &memblocks->data[i];
-        address_t start = block->addr;
+        bool special;
+        address_t end, start = block->addr;
         address_t size = block->len;
         for (j = i + 1; j < memblocks->p; j++) {
             const struct memblock_s *b = &memblocks->data[j];
@@ -258,9 +299,13 @@ static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) {
             if (b->addr != addr || addr < start) break;
             size += b->len;
         }
-        if (i == 0 || start == 0xffff) putlw(0xffff, fout);
-        putlw(start, fout);
-        putlw(start + size - 1, fout);
+        special = (i == 0 || start == 0xffff);
+        header[2] = start;
+        header[3] = start >> 8;
+        end = start + size - 1;
+        header[4] = end;
+        header[5] = end >> 8;
+        if (fwrite(special ? header : &header[2], special ? 6 : 4, 1, fout) == 0) return;
         for (;i < j; i++) {
             const struct memblock_s *b = &memblocks->data[i];
             if (fwrite(memblocks->mem.data + b->p, b->len, 1, fout) == 0) return;
@@ -268,11 +313,16 @@ static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) {
     }
 }
 
-static unsigned int hexput(FILE *fout, unsigned int b) {
+struct hexput_s {
+    char *line;
+    unsigned int sum;
+};
+
+static void hexput(struct hexput_s *h, unsigned int b) {
     const char *hex = "0123456789ABCDEF";
-    putc(hex[(b >> 4) & 0xf], fout);
-    putc(hex[b & 0xf], fout);
-    return b;
+    *h->line++ = hex[b >> 4];
+    *h->line++ = hex[b & 0xf];
+    h->sum += b;
 }
 
 struct ihex_s {
@@ -282,22 +332,25 @@ struct ihex_s {
     unsigned int length;
 };
 
-static void output_mem_ihex_line(FILE *fout, unsigned int length, address_t address, unsigned int type, const uint8_t *data) {
-    unsigned int i, sum;
-    putc(':', fout);
-    sum = hexput(fout, length);
-    sum += hexput(fout, address >> 8);
-    sum += hexput(fout, address);
-    sum += hexput(fout, type);
+static void output_mem_ihex_line(struct ihex_s *ihex, unsigned int length, address_t address, unsigned int type, const uint8_t *data) {
+    unsigned int i;
+    char line[1+(1+2+1+32+1)*2+1];
+    struct hexput_s h = { line + 1, 0 };
+    line[0] = ':';
+    hexput(&h, length);
+    hexput(&h, (address >> 8) & 0xff);
+    hexput(&h, address & 0xff);
+    hexput(&h, type);
     for (i = 0; i < length; i++) {
-        sum += hexput(fout, data[i]);
+        hexput(&h, data[i]);
     }
-    hexput(fout, -sum);
-    putc('\n', fout);
+    hexput(&h, (-h.sum) & 0xff);
+    *h.line++ = '\n';
+    fwrite(line, h.line - line, 1, ihex->file);
 }
 
 static void output_mem_ihex_data(struct ihex_s *ihex) {
-    uint8_t *data = ihex->data;
+    const uint8_t *data = ihex->data;
     if ((ihex->address & 0xffff) + ihex->length > 0x10000) {
         uint16_t length = (uint16_t)-ihex->address;
         unsigned int remains = ihex->length - length;
@@ -310,10 +363,10 @@ static void output_mem_ihex_data(struct ihex_s *ihex) {
         uint8_t ez[2];
         ez[0] = (uint8_t)(ihex->address >> 24);
         ez[1] = (uint8_t)(ihex->address >> 16);
-        output_mem_ihex_line(ihex->file, sizeof ez, 0, 4, ez);
+        output_mem_ihex_line(ihex, sizeof ez, 0, 4, ez);
         ihex->segment = ihex->address;
     }
-    output_mem_ihex_line(ihex->file, ihex->length, ihex->address, 0, data);
+    output_mem_ihex_line(ihex, ihex->length, ihex->address, 0, data);
     ihex->address += ihex->length;
     ihex->length = 0;
 }
@@ -348,7 +401,7 @@ static void output_mem_ihex(FILE *fout, const Memblocks *memblocks) {
         }
     }
     if (ihex.length != 0) output_mem_ihex_data(&ihex);
-    output_mem_ihex_line(fout, 0, 0, 1, NULL);
+    output_mem_ihex_line(&ihex, 0, 0, 1, NULL);
 }
 
 struct srecord_s {
@@ -360,21 +413,24 @@ struct srecord_s {
 };
 
 static void output_mem_srec_line(struct srecord_s *srec) {
-    unsigned int i, sum;
-    putc('S', srec->file);
-    putc(srec->length ? ('1' + srec->type) : ('9' - srec->type), srec->file);
-    sum = hexput(srec->file, srec->length + srec->type + 3);
-    if (srec->type > 1) sum += hexput(srec->file, srec->address >> 24);
-    if (srec->type > 0) sum += hexput(srec->file, srec->address >> 16);
-    sum += hexput(srec->file, srec->address >> 8);
-    sum += hexput(srec->file, srec->address);
+    unsigned int i;
+    char line[1+1+(1+4+32+1)*2+1];
+    struct hexput_s h = { line + 2, 0 };
+    line[0] = 'S';
+    line[1] = srec->length != 0 ? ('1' + srec->type) : ('9' - srec->type);
+    hexput(&h, srec->length + srec->type + 3);
+    if (srec->type > 1) hexput(&h, (srec->address >> 24) & 0xff);
+    if (srec->type > 0) hexput(&h, (srec->address >> 16) & 0xff);
+    hexput(&h, (srec->address >> 8) & 0xff);
+    hexput(&h, srec->address & 0xff);
     for (i = 0; i < srec->length; i++) {
-        sum += hexput(srec->file, srec->data[i]);
+        hexput(&h, srec->data[i]);
     }
-    hexput(srec->file, ~sum);
-    putc('\n', srec->file);
+    hexput(&h, (~h.sum) & 0xff);
+    *h.line++ = '\n';
     srec->address += srec->length;
     srec->length = 0;
+    fwrite(line, h.line - line, 1, srec->file);
 }
 
 static void output_mem_srec(FILE *fout, const Memblocks *memblocks) {