aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile150
-rw-r--r--src/README_Windows.txt.in17
-rw-r--r--src/addrs.h86
-rw-r--r--src/alf.1214
-rw-r--r--src/alf.c441
-rw-r--r--src/alf.rst186
-rw-r--r--src/alfsum.1107
-rw-r--r--src/alfsum.c54
-rw-r--r--src/alfsum.rst85
-rw-r--r--src/alfusage.c11
-rw-r--r--src/asmcode.c650
-rw-r--r--src/extract.c197
-rw-r--r--src/glob.c115
-rw-r--r--src/io.c163
-rw-r--r--src/listalf.c125
-rw-r--r--src/manftr.rst8
-rw-r--r--src/mkusage.pl19
-rw-r--r--src/opts.c78
-rw-r--r--src/self.c13
-rw-r--r--src/self.h3
-rw-r--r--src/unalf.1412
-rw-r--r--src/unalf.c79
-rw-r--r--src/unalf.h93
-rw-r--r--src/unalf.rst358
-rw-r--r--src/usage.c19
-rw-r--r--src/ver.rst1
26 files changed, 0 insertions, 3684 deletions
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index da19876..0000000
--- a/src/Makefile
+++ /dev/null
@@ -1,150 +0,0 @@
-# Makefile for alftools, by B. Watson. WTFPL.
-# Tested with GNU make, BSD make, makepp, and Schily's dmake.
-
-### Override these variables as needed. Don't override CFLAGS; use
-# COPT instead.
-
-# C compiler to use. PATH is searched unless you give an absolute path.
-CC=cc
-
-# C compiler options (flags):
-COPT=-O3
-
-# Path to the GNU or BSD 'install' program.
-INSTALL=install
-
-# Path to the rst2man command. Only needed if modifying/rebuilding the
-# man pages and/or windows HTML docs.
-RST2MAN=rst2man
-
-# These only affect the 'install' target (they don't get compiled
-# into the binary).
-
-PREFIX=/usr
-MANDIR=$(PREFIX)/man
-MAN1DIR=$(MANDIR)/man1
-BINDIR=$(PREFIX)/bin
-DOCDIR=$(PREFIX)/doc/$(PROJ)-$(VERSION)
-DESTDIR=
-INSTALL_DATA=$(INSTALL) -m0644
-INSTALL_PROGRAM=$(INSTALL) -m0755
-GZIP=gzip -9
-GZIP_MAN=yes
-STRIP=yes
-
-#
-### No user-serviceable parts below.
-
-PROJ=alftools
-VERSION=0.2.0
-
-CFLAGS=-DVERSION='"$(VERSION)"' -Wall -I../f65 $(COPT)
-
-BINS=alf alfsum unalf
-MANS=alf.1 alfsum.1 unalf.1
-
-UNALF_OBJS=unalf.o io.o listalf.o extract.o f65.o glob.o opts.o usage.o self.o asmcode.o
-ALFSUM_OBJS=alfsum.o self.o
-ALF_OBJS=alf.o self.o alfusage.o
-
-.PHONY: all clean install crosswin windows windows-upload realclean
-
-all: $(BINS) $(MANS)
-
-# unalf and alfsum need explicit rules for BSD make compatibility.
-# without them, bmake tries to run "cc -o unalf unalf.c" which ain't
-# gonna ever work.
-unalf: $(UNALF_OBJS)
- $(CC) $(LDFLAGS) -o $@ $(UNALF_OBJS)
-
-alfsum: $(ALFSUM_OBJS)
- $(CC) $(LDFLAGS) -o $@ $(ALFSUM_OBJS)
-
-alf: $(ALF_OBJS)
- $(CC) $(LDFLAGS) -o $@ $(ALF_OBJS)
-
-usage.o: usage.c
-
-alfusage.o: usage.c
-
-f65.o: ../f65/f65.c ../f65/f65.h
- $(CC) $(CFLAGS) -c -o f65.o ../f65/f65.c
-
-usage.c: mkusage.pl unalf.rst
- perl mkusage.pl unalf.rst > usage.c
-
-alfusage.c: mkusage.pl alf.rst
- perl mkusage.pl alf.rst > alfusage.c
-
-unalf.o: unalf.c unalf.h ../f65/f65.h
-
-glob.o: glob.c unalf.h
-
-opts.o: opts.c unalf.h
-
-io.o: io.c unalf.h addrs.h ../f65/f65.h
-
-listalf.o: listalf.c addrs.h unalf.h ../f65/f65.h
-
-extract.o: extract.c addrs.h unalf.h ../f65/f65.h
-
-ver.rst:
- echo '.. |version| replace:: $(VERSION)' > ver.rst
-
-unalf.1: unalf.rst ver.rst manftr.rst
- $(RST2MAN) unalf.rst > unalf.1
-
-alfsum.1: alfsum.rst ver.rst manftr.rst
- $(RST2MAN) alfsum.rst > alfsum.1
-
-alf.1: alf.rst ver.rst manftr.rst
- $(RST2MAN) alf.rst > alf.1
-
-clean:
- rm -rf *.o $(BINS) *.exe wintmp \
- alf.html unalf.html alfsum.html *.aarch64.elf *.com.dbg
-
-# these are generated files, but they *are* checked into git.
-realclean: clean
- rm -f unalf.1 alfsum.1 usage.c alfusage.c
-
-install: all
- [ "$(STRIP)" = "yes" ] && strip alf unalf alfsum || true
- mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MAN1DIR) $(DESTDIR)$(DOCDIR)
- $(INSTALL_DATA) alf.1 $(DESTDIR)$(MAN1DIR)
- $(INSTALL_DATA) unalf.1 $(DESTDIR)$(MAN1DIR)
- $(INSTALL_DATA) alfsum.1 $(DESTDIR)$(MAN1DIR)
- [ "$(GZIP_MAN)" = "yes" ] && $(GZIP) $(DESTDIR)$(MAN1DIR)/alf.1 || true
- [ "$(GZIP_MAN)" = "yes" ] && $(GZIP) $(DESTDIR)$(MAN1DIR)/unalf.1 || true
- [ "$(GZIP_MAN)" = "yes" ] && $(GZIP) $(DESTDIR)$(MAN1DIR)/alfsum.1 || true
- $(INSTALL_PROGRAM) alf $(DESTDIR)$(BINDIR)
- $(INSTALL_PROGRAM) unalf $(DESTDIR)$(BINDIR)
- $(INSTALL_PROGRAM) alfsum $(DESTDIR)$(BINDIR)
- cp -r ../README.txt ../LICENSE.txt ../TODO.txt ../doc ../examples $(DESTDIR)$(DOCDIR)
-
-crosswin: clean
- $(MAKE) CC=~/x-tools/x86_64-w64-mingw32/bin/x86_64-w64-mingw32-gcc
-
-html: alfsum.html unalf.html alf.html
-
-alf.html: alf.rst
- rst2html alf.rst > alf.html
-
-alfsum.html: alfsum.rst
- rst2html alfsum.rst > alfsum.html
-
-unalf.html: unalf.rst
- rst2html unalf.rst > unalf.html
-
-windows: crosswin html
- rm -rf wintmp ../$(PROJ)-$(VERSION)-win64.zip
- mkdir -p wintmp/{doc,examples}
- cp alf.exe unalf.exe alfsum.exe wintmp
- cd .. ; for i in README.txt TODO.txt doc/*.txt doc/Arcinfo examples/*.txt; do perl -pe 's,\n,\r\n,;' $$i > src/wintmp/$$i; done
- perl -p -e 's,\n,\r\n,;' -e 's,\@VERSION\@,$(VERSION),g;' README_Windows.txt.in > wintmp/README_Windows.txt
- cp ../examples/*.alf wintmp/examples
- cp alfsum.html unalf.html alf.html wintmp
- cd wintmp ; zip -r ../../$(PROJ)-$(VERSION)-win64.zip *
-
-windows-upload: windows
- scp ../$(PROJ)-$(VERSION)-win64.zip sluk:public_html/html/$(PROJ)4win/
diff --git a/src/README_Windows.txt.in b/src/README_Windows.txt.in
deleted file mode 100644
index 338a495..0000000
--- a/src/README_Windows.txt.in
+++ /dev/null
@@ -1,17 +0,0 @@
-This is the Windows binary release of alftools-@VERSION@.
-
-See README.txt, unalf.html, and alfsum.html for full documentation.
-
-This is a command-line program. Just double-clicking on the .exe won't
-do anything useful. You should copy unalf.exe and alfsum.exe to some
-directory that's in your PATH, or else run them from the directory you
-extracted them to, using the command prompt (CMD.EXE).
-
-The binaries (alf.exe, unalf.exe, alfsum.exe) were built with a cross
-gcc compiler on a Linux system. They should run on any recent 64-bit
-Windows OS. The author doesn't actually use Windows, so if you run
-into problems, please let me know.
-
-I can be reached by email at:
-
-urchlay@slackware.uk
diff --git a/src/addrs.h b/src/addrs.h
deleted file mode 100644
index 47e0e32..0000000
--- a/src/addrs.h
+++ /dev/null
@@ -1,86 +0,0 @@
-
-#define buf_adr_l 0x7A7B
-#define buf_adr_h 0x7A7C
-#define buf_len_l 0x7A7D
-#define buf_len_h 0x7A7E
-#define zp_b0 0x00B0
-#define zp_b1 0x00B1
-#define acc16_l 0x00B2
-#define acc16_h 0x00B3
-#define zp_b4 0x00B4
-#define zp_b5 0x00B5
-#define stackptr_l 0x00B6
-#define stackptr_h 0x00B7
-#define zp_b8 0x00B8
-#define zp_b9 0x00B9
-#define outbuf_ptr_l 0x00BA
-#define outbuf_ptr_h 0x00BB
-#define zp_bc 0x00BC
-#define zp_bd 0x00BD
-#define zp_be 0x00BE
-#define zp_bf 0x00BF
-#define MEMTOP 0x02E5
-#define MEMTOP_lo 0x02E5
-#define MEMTOP_hi 0x02E6
-#define MEMLO 0x02E7
-#define MEMLO_hi 0x02E8
-#define input_file 0x7000
-#define output_dir 0x7050
-#define outfile_l 0x70A0
-#define outfile_h 0x70A1
-#define linbuf 0x7120
-#define L7174 0x7174
-#define L7175 0x7175
-#define L7176 0x7176
-#define L7177 0x7177
-#define L7178 0x7178
-#define L7179 0x7179
-#define L717A 0x717A
-#define L717B 0x717B
-#define L717C 0x717C
-#define L717D 0x717D
-#define L717E 0x717E
-#define cksum_l 0x717F
-#define cksum_h 0x7180
-#define L7181 0x7181
-#define L7182 0x7182
-#define inbuf_len_l 0x7183
-#define inbuf_len_h 0x7184
-#define inbuf_adr_l 0x7185
-#define inbuf_adr_h 0x7186
-#define outbuf_adr_l 0x7187
-#define outbuf_adr_h 0x7188
-#define L7189 0x7189
-#define L718A 0x718A
-#define L718B 0x718B
-#define L718C 0x718C
-#define alf_header 0x718D
-#define alf_hdr_sig 0x718E
-#define alf_hdr_filename 0x718F
-#define alf_hdr_compsize0 0x719C
-#define alf_hdr_compsize1 0x719D
-#define alf_hdr_compsize2 0x719E
-#define alf_hdr_compsize3 0x719F
-#define alf_hdr_date0 0x71A0
-#define alf_hdr_date1 0x71A1
-#define alf_hdr_time0 0x71A2
-#define alf_hdr_time1 0x71A3
-#define alf_hdr_cksum_l 0x71A4
-#define alf_hdr_cksum_h 0x71A5
-#define alf_hdr_origsize0 0x71A6
-#define alf_hdr_origsize1 0x71A7
-#define alf_hdr_origsize2 0x71A8
-#define alf_hdr_origsize3 0x71A9
-#define L71AA 0x71AA
-#define L71AB 0x71AB
-#define shift_counter 0x71AC
-#define L71AD 0x71AD
-#define L71AE 0x71AE
-#define L71AF 0x71AF
-#define L71B0 0x71B0
-#define outbuf_len_l 0x71B1
-#define outbuf_len_h 0x71B2
-#define L71B4 0x71B4
-#define L71B5 0x71B5
-#define L71B6 0x71B6
-#define L71B7 0x71B7
diff --git a/src/alf.1 b/src/alf.1
deleted file mode 100644
index f2efb38..0000000
--- a/src/alf.1
+++ /dev/null
@@ -1,214 +0,0 @@
-.\" Man page generated from reStructuredText.
-.
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.TH "ALF" 1 "2025-11-27" "0.2.0" "Urchlay's Atari 8-bit Tools"
-.SH NAME
-alf \- create Atari 8-bit ALF archives
-.\" RST source for alf(1) man page. Convert with:
-.
-.\" rst2man.py alf.rst > alf.1
-.
-.SH SYNOPSIS
-.sp
-alf [\fB\-\-help\fP] | [\fB\-a\fP | \fB\-o\fP ] [\fB\-t[dgz]\fP] \fIalf\-file\fP \fIfile\fP [\fIfile\fP ...]
-.SH DESCRIPTION
-.sp
-\fBalf\fP creates \fIALF\fP archives.
-.sp
-\fIALF\fP is a compressed archive format similar to \fBarc\fP(1), though
-not compatible with it. It was used on the Atari 8\-bit platform
-beginning in the late 1980s. The Atari executables are \fBLZ.COM\fP
-for the compressor and \fBDZ.COM\fP for the decompressor. \fBalf\fP is a
-rewrite of \fBLZ.COM\fP for modern operating systems, with added features.
-.sp
-By default, the \fIalf\-file\fP is created, and the \fIfile\fPs are compressed
-and added to it. If \fIalf\-file\fP already existed, it is backed up by adding
-a \fB~\fP to the filename.
-.sp
-The \fBALF\fP file format only supports uppercase "8.3" filenames
-(Atari DOS or MS\-DOS style), and does not support subdirectories. The
-filenames you give will be stored in the \fBALF\fP file uppercased
-and truncated to fit the 8.3 scheme. This could result in duplicate
-filenames in the archive, if you\(aqre not careful.
-.SH OPTIONS
-.INDENT 0.0
-.TP
-.B \-a
-Append to \fIalf\-file\fP\&. The files are added to the end of the archive. Be
-careful not to add a file with the same name as as existing member of
-the archive. If \fIalf\-file\fP doesn\(aqt exist, it will be created. No backup
-is made with \fB\-a\fP\&.
-.UNINDENT
-.\" append to alf file.
-.
-.INDENT 0.0
-.TP
-.B \-A
-Convert line endings and tabs from ASCII to ATASCII in all input
-files. This will corrupt any executables or non\-text data files,
-so use with caution. There is no way to autodetect text files,
-unlike \fBunalf\fP\&.
-.UNINDENT
-.\" convert EOLs and tabs in all input files.
-.
-.INDENT 0.0
-.TP
-.B \-h\fP,\fB \-\-help
-Show built\-in help message.
-.UNINDENT
-.\" show this help message.
-.
-.INDENT 0.0
-.TP
-.B \-o
-Overwrite \fIalf\-file\fP if it exists; do not make a \fB~\fP backup.
-.UNINDENT
-.\" overwrite alf file if exists (do not create file~ backup).
-.
-.INDENT 0.0
-.TP
-.B \fB\-td\fP
-Use default \fBLZ.COM\fP timestamps (8 Dec 82 12:24).
-.UNINDENT
-.\" use default LZ.COM timestamps.
-.
-.INDENT 0.0
-.TP
-.B \fB\-tu\fP
-Use UTC for timestamps (default is local timezone).
-.UNINDENT
-.\" use UTC timestamps.
-.
-.INDENT 0.0
-.TP
-.B \fB\-tz\fP
-Use zero for timestamps (0 ??? 80 12:00a).
-.UNINDENT
-.\" use zero timestamps.
-.
-.INDENT 0.0
-.TP
-.B \-V\fP,\fB \-\-version
-Show \fBunalf\fP version number and exit.
-.UNINDENT
-.\" show version number.
-.
-.\" ENDOPTS
-.
-.SH EXIT STATUS
-.INDENT 0.0
-.TP
-.B 0
-Success.
-.TP
-.B 1
-Fatal error (I/O or bad command\-line arguments).
-.UNINDENT
-.SH NOTES
-.SS Compatibility
-.sp
-This \fBalf\fP is \fIintended\fP to be 100% compatible with the original
-Atari \fBLZ.COM\fP aka \fBALF.COM\fP, with the following differences:
-.INDENT 0.0
-.IP \(bu 2
-There is no interactive mode. The file to create and the files to add
-must be given as command\-line arguments.
-.IP \(bu 2
-\fBLZ.COM\fP always appends to a file that already exists. This \fBalf\fP
-overwrites (making a backup) by default, and can append with the \fB\-a\fP
-option.
-.IP \(bu 2
-Turning the screen off for speed makes no sense on modern operating
-systems, so there\(aqs no option for that.
-.UNINDENT
-.sp
-Note that \fBalf\fP is a complete reverse\-engineered rewrite in C, \fInot\fP
-a port of the original 6502 code as \fBunalf\fP is. It\(aqs still being
-tested, and may still contain bugs.
-.SS File Size Limits
-.sp
-\fBalf\fP (and \fBLZ.COM\fP) have a 16MB file size limit. \fBuanlf\fP
-actually can\(aqt handle files above about 15MB, if you compress one with
-\fBalf\fP\&. Real Atari 8\-bit files are never this large anyway, so it\(aqs
-a pathological case. A real Atari would take hours or even days to
-compress/decompress such files, and you\(aqd have to have a hard disk and
-a DOS capable of handling multi\-megabyte files...
-.sp
-It\(aqs also impossible to compress empty (0\-byte) files. \fBalf\fP will
-skip them, if any are found.
-.SS Performance
-.sp
-Performance is \fIhorrible\fP\&. This shouldn\(aqt be a real problem on
-modern multi\-GHz CPU, especially since most Atari 8\-bit files are
-small (usually under 64KB). Interestingly, it\(aqs not O(n^2), it scales
-linearly, O(1): Compressing a 1.3MB text file takes 0.7 seconds on the
-author\(aqs (rather modest) Intel i7 workstation, and a file 10x as large
-takes approximately 10x as long (7 seconds). A 50KB file is almost
-instantaneous, 0.05 seconds, which is more typical of the files you\(aqd
-actually use this with.
-.SS Timestamps
-.sp
-The date/time stamps stored in the archive are the \fBmtime\fPs of
-the files (which is the same time \fBls\fP(1) shows, by default), and
-your local timezone is assumed. Only a 2\-digit year is displayed by
-\fBunalf\fP, but the year stored in the \fIALF\fP file doesn\(aqt have a Y2K
-problem. It does, however, have a Y2108 problem...
-.SH COPYRIGHT
-.sp
-The original AlfCrunch (\fBDZ.COM\fP and \fBLZ.COM\fP) for the Atari 8\-bit
-was released into the Public Domain. \fBalf\fP contains no code from
-AlfCrunch.
-.sp
-\fBalf\fP is released under the WTPFL: Do WTF you want with this.
-.SH AUTHOR
-.sp
-The original AlfCrunch for the Atari 8\-bit was written by Alfred, who
-can be reached via the AtariAge.com forums with the username "Alfred".
-.sp
-This \fBalf\fP was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
-.SH SEE ALSO
-.sp
-\fBunalf\fP(1), \fBalfls\fP(1)
-.sp
-The git repository for \fBunalf\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/unalf\fP
-.UNINDENT
-.UNINDENT
-.sp
-Other Atari\-related projects by the author, including \fBbw\-atari8\-tools\fP
-and \fBunmac65\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/\fP
-.UNINDENT
-.UNINDENT
-.\" Generated by docutils manpage writer.
-.
diff --git a/src/alf.c b/src/alf.c
deleted file mode 100644
index fb79fcf..0000000
--- a/src/alf.c
+++ /dev/null
@@ -1,441 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "self.h"
-
-#ifndef u8
-#define u8 unsigned char
-#define u16 unsigned short
-#endif
-
-#define INITIAL_BITS 9
-#define MAX_BITS 12
-#define MAX_TOKENS (1 << MAX_BITS)
-#define TOK_RESET 256
-#define TOK_END 257
-#define INIT_TOKEN 258 /* 256 = reset dict, 257 = token_bits++ */
-
-#define MAX_INPUT_SIZE (1 << 24)
-
-u8 input_buf[MAX_INPUT_SIZE];
-u8 output_buf[MAX_INPUT_SIZE];
-u8 byte_tokens[256];
-unsigned int input_len, output_len, out_bitpos;
-
-int opt_append = 0;
-int opt_overwrite = 0;
-int opt_zerotime = 0;
-int opt_alftime = 0;
-int opt_gmtime = 0;
-int opt_txtconv = 0;
-
-struct stat in_file_stat;
-
-typedef struct s_token {
- u8 *start;
- u16 length;
-} token_t;
-
-token_t tokentab[MAX_TOKENS];
-
-FILE *out_file, *in_file;
-const char *out_filename, *in_filename;
-int token_bits;
-int max_token;
-int curr_token;
-long hdr_compsize_pos;
-int in_pos;
-
-void init_table(void) {
- int i;
-
- memset(tokentab, 0, sizeof(tokentab));
-
- token_bits = INITIAL_BITS;
- max_token = 1 << INITIAL_BITS;
- curr_token = INIT_TOKEN;
-
- for(i = 0; i < 256; i++) {
- byte_tokens[i] = (u8)i;
- tokentab[i].start = &byte_tokens[i];
- tokentab[i].length = 1;
- }
-}
-
-void store_quad(int pos, unsigned long data) {
- int i;
-
- for(i = 0; i < 4; i++) {
- output_buf[pos++] = data & 0xff;
- data >>= 8;
- }
-}
-
-void store_cksum(void) {
- int i;
- u16 cksum = 0;
-
- for(i = 0; i < input_len; i++)
- cksum += input_buf[i];
-
- output_buf[23] = cksum & 0xff;
- output_buf[24] = cksum >> 8;
-}
-
-/* examples:
- foo => FOO.
- toolongfile => TOOLONGF. (really should be TOOLONGF.ILE)
- regular.txt => REGULAR.TXT
- too.many.dots => TOO.MAN
- */
-void atarify_filename(char *result) {
- int i;
- char name[9] = { 0 }, ext[4] = { 0 }, *p;
-
- p = strrchr(in_filename, '/');
- if(p)
- p++;
- else
- p = (char *)in_filename;
-
- strncpy(name, p, 8);
- for(i = 0; i < 8; i++) {
- if(!name[i]) break;
- if(name[i] == '.') {
- name[i] = '\0';
- break;
- }
- }
-
- strcpy(result, name);
- strcat(result, ".");
-
- p = strchr(in_filename, '.');
- if(p) {
- p++;
- strncpy(ext, p, 3);
- for(p = ext; *p; p++)
- if(*p == '.') *p = 0;
- strcat(result, ext);
- }
-
- for(p = result; *p; p++)
- *p = toupper(*p);
-}
-
-/* see Arcinfo for the gory details. */
-unsigned long get_msdos_date_time(void) {
- time_t t = in_file_stat.st_mtime;
- struct tm *tm;
- int msdos_year;
- u16 ms_date, ms_time;
-
- if(opt_gmtime)
- tm = gmtime(&t);
- else
- tm = localtime(&t);
-
- msdos_year = tm->tm_year + 1900 - 1980;
-
- ms_date = tm->tm_mday | (tm->tm_mon << 5) | (msdos_year << 9);
- ms_time = (tm->tm_min << 5) | (tm->tm_hour << 11);
- return ms_date | (ms_time << 16);
-}
-
-void create_header(void) {
- char hdr_filename[13];
- unsigned long time;
-
- atarify_filename(hdr_filename);
- printf("Crunching %s\n", hdr_filename);
-
- if(opt_alftime)
- time = 0x03130588;
- else if(opt_zerotime)
- time = 0;
- else
- time = get_msdos_date_time();
-
- output_buf[0] = 0x1a;
- output_buf[1] = 0x0f;
- memset(&output_buf[3], 0x20, 13);
- strncat((char *)&output_buf[2], hdr_filename, 13);
- output_buf[14] = 0x00;
- store_quad(15, 0); /* compressed size, fill in later */
- store_quad(19, time);
- store_cksum();
- store_quad(25, input_len);
- output_len = 29;
-}
-
-void update_header(void) {
- store_quad(15, output_len - 29);
-}
-
-void open_input(const char *filename) {
- in_filename = filename;
- if(!(in_file = fopen(in_filename, "rb"))) {
- perror(in_filename);
- exit(1);
- }
-}
-
-void inc_output_len(void) {
- if(++output_len == MAX_INPUT_SIZE) {
- fprintf(stderr, "%s: fatal: compressed file would be >16MB.\n", self);
- exit(1);
- }
-}
-
-void append_bit(int bit) {
- output_buf[output_len] |= (bit << (7 - out_bitpos));
- out_bitpos++;
- if(out_bitpos == 8) {
- out_bitpos = 0;
- inc_output_len();
- }
-}
-
-void store_token(int tok) {
- int mask;
-
- for(mask = 1 << (token_bits - 1); mask; mask >>= 1) {
- append_bit(tok & mask ? 1 : 0);
- }
-}
-
-/* match_token() is a brute-force search, which is why alf is so slow.
- I'll do something smarter at some point.
- search backwards, the tokens are stored with longer ones later
- in the list. */
-int match_token(int pos) {
- int i, len, maxlen;
- token_t *t;
- u8 *p, *q;
-
- maxlen = input_len - pos;
-
- for(i = curr_token - 1; i >= INIT_TOKEN; i--) {
- t = &tokentab[i];
-
- /* don't search past the end of the input */
- if(t->length > maxlen) continue;
-
- /* if the first char doesn't match, don't bother with memcmp.
- this is a 5x speedup (!) */
- if(input_buf[pos] != *(t->start)) continue;
-
- /* this is where alf spends most of its time.
- using memcmp is noticeably slower than the code below. */
- /*
- if(memcmp(&input_buf[pos], t->start, t->length) == 0)
- return i;
- */
-
- /* inline memcmp replacement of sorts. I don't think it's really
- faster than memcmp(), it only seems that way because there's
- no function call overhead. ~20% speedup. */
- len = t->length;
- p = &input_buf[pos];
- q = t->start;
- while(len) {
- if(*p != *q) break;
- p++; q++;
- len--;
- }
- if(!len) return i;
- }
-
- /* hard-coded single character tokens map to their values, no need
- to search. */
- return input_buf[pos];
-}
-
-void make_token(int start, int end) {
- /* if the token table is full, reset it. basically start over like
- we would with a new file. */
- if(curr_token == max_token) {
- if(token_bits == MAX_BITS) {
- store_token(TOK_RESET); /* stored at the *old* token size! */
- token_bits = INITIAL_BITS;
- init_table();
- return; /* since we're starting over, *don't* make a token */
- } else {
- token_bits++;
- }
- max_token = 1 << token_bits;
- }
- tokentab[curr_token].start = &input_buf[start];
- tokentab[curr_token].length = end - start + 1;
- curr_token++;
-}
-
-void crunch(void) {
- int new_pos;
- in_pos = 0;
- int token;
-
- out_bitpos = 0;
-
- store_token(TOK_RESET);
-
- while(in_pos < input_len) {
- token = match_token(in_pos);
- store_token(token);
- new_pos = in_pos + tokentab[token].length;
- // printf(" in_pos %d, new_pos %d\n", in_pos, new_pos);
- if(new_pos < input_len)
- make_token(in_pos, new_pos);
- in_pos = new_pos;
- }
-
- store_token(TOK_END);
- if(out_bitpos) inc_output_len();
- update_header();
-}
-
-void make_backup(void) {
- char bak[PATH_MAX + 2];
- strncpy(bak, out_filename, PATH_MAX);
- strcat(bak, "~");
- rename(out_filename, bak);
-}
-
-void convert_eols(void) {
- int i;
-
- for(i = 0; i < input_len; i++) {
- if(input_buf[i] == '\n')
- input_buf[i] = 0x9b;
- else if(input_buf[i] == '\t')
- input_buf[i] = 0x7f;
- }
-}
-
-void crunch_file(const char *filename) {
- init_table();
-
- open_input(filename);
-
- /* read in entire input, couldn't do it this way on the Atari */
- input_len = fread(input_buf, 1, MAX_INPUT_SIZE - 1, in_file);
-
- if(!feof(in_file)) {
- fprintf(stderr, "%s: %s: this file is too large; only compressing the first 16MB.\n", self, filename);
- }
-
- if(!input_len) {
- fprintf(stderr, "%s: %s: can't compress a 0-byte (empty) file, skipping.\n", self, filename);
- return;
- }
-
- if(opt_txtconv)
- convert_eols();
-
- output_len = 0;
- fstat(fileno(in_file), &in_file_stat); /* for timestamp */
- fclose(in_file);
-
- memset(output_buf, 0, sizeof(output_buf));
-
- create_header();
-
- /* crunches the entire input to memory! */
- crunch();
-
- /* don't open the output file until crunch() has succeeded once.
- this avoids leaving 0-byte turds */
- if(!out_file) {
- if(!opt_overwrite) make_backup();
- out_file = fopen(out_filename, opt_append ? "ab" : "wb");
- if(!out_file) {
- fprintf(stderr, "%s: fatal: ", self);
- perror(out_filename);
- exit(1);
- }
- }
-
- fwrite(output_buf, 1, output_len, out_file);
-}
-
-void usage(void) {
- extern char *usage_msg[];
- char **line;
-
- puts("alf (ALF compressor) v" VERSION " by B. Watson, WTFPL.");
- printf("Usage: %s [-a|-o] archive.alf file [file ...]\n", self);
- puts("Options:");
-
- for(line = usage_msg; *line; line++)
- puts(*line);
-
- exit(0);
-}
-
-int main(int argc, char **argv) {
- int opt;
-
- set_self(argv[0]);
-
- if(argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
- usage();
- }
-
- if(!strcmp(argv[1], "--version")) {
- puts(VERSION);
- exit(0);
- }
-
- /* don't let getopt() print error message for us. */
- opterr = 0;
-
- while((opt = getopt(argc, argv, "aAt:oV")) != -1) {
- switch(opt) {
- case 'A': opt_txtconv = 1; break;
- case 'a': opt_append = 1; opt_overwrite = 1; break;
- case 'o': opt_overwrite = 1; opt_append = 0; break;
- case 't': opt_zerotime = opt_alftime = opt_gmtime = 0;
- switch(*optarg) {
- case 'z': opt_zerotime = 1; break;
- case 'd': opt_alftime = 1; break;
- case 'u': opt_gmtime = 1; break;
- default:
- fprintf(stderr, "%s: fatal: invalid -t suboption '-%c' (try -h or --help)\n", self, *optarg);
- exit(1);
- }
- break;
- case 'V': puts(VERSION); exit(0); break;
- default:
- fprintf(stderr, "%s: fatal: invalid option '-%c' (try -h or --help)\n", self, optopt);
- exit(1);
- }
- }
-
- if(optind >= argc) {
- fprintf(stderr, "%s: fatal: missing alf file argument (try -h or --help)\n", self);
- exit(1);
- }
-
- out_filename = argv[optind];
-
- optind++;
-
- if(optind >= argc) {
- fprintf(stderr, "%s: fatal: no filenames (nothing to compress) (try -h or --help)\n", self);
- exit(1);
- }
-
- while(optind < argc) {
- crunch_file(argv[optind++]);
- }
-
- if(out_file) fclose(out_file);
-
- exit(0);
-}
diff --git a/src/alf.rst b/src/alf.rst
deleted file mode 100644
index 3110180..0000000
--- a/src/alf.rst
+++ /dev/null
@@ -1,186 +0,0 @@
-.. RST source for alf(1) man page. Convert with:
-.. rst2man.py alf.rst > alf.1
-
-.. include:: ver.rst
-
-.. |date| date::
-
-===
-alf
-===
-
--------------------------------
-create Atari 8-bit ALF archives
--------------------------------
-
-:Manual section: 1
-:Manual group: Urchlay's Atari 8-bit Tools
-:Date: |date|
-:Version: |version|
-
-SYNOPSIS
-========
-
-alf [**--help**] | [**-a** | **-o** ] [**-t[dgz]**] *alf-file* *file* [*file* ...]
-
-DESCRIPTION
-===========
-
-**alf** creates *ALF* archives.
-
-*ALF* is a compressed archive format similar to **arc**\(1), though
-not compatible with it. It was used on the Atari 8-bit platform
-beginning in the late 1980s. The Atari executables are **LZ.COM**
-for the compressor and **DZ.COM** for the decompressor. **alf** is a
-rewrite of **LZ.COM** for modern operating systems, with added features.
-
-By default, the *alf-file* is created, and the *file*\s are compressed
-and added to it. If *alf-file* already existed, it is backed up by adding
-a **~** to the filename.
-
-The **ALF** file format only supports uppercase "8.3" filenames
-(Atari DOS or MS-DOS style), and does not support subdirectories. The
-filenames you give will be stored in the **ALF** file uppercased
-and truncated to fit the 8.3 scheme. This could result in duplicate
-filenames in the archive, if you're not careful.
-
-OPTIONS
-=======
-
--a
- Append to *alf-file*. The files are added to the end of the archive. Be
- careful not to add a file with the same name as as existing member of
- the archive. If *alf-file* doesn't exist, it will be created. No backup
- is made with **-a**.
-
-.. append to alf file.
-
--A
- Convert line endings and tabs from ASCII to ATASCII in all input
- files. This will corrupt any executables or non-text data files,
- so use with caution. There is no way to autodetect text files,
- unlike **unalf**.
-
-.. convert EOLs and tabs in all input files.
-
--h, --help
- Show built-in help message.
-
-.. show this help message.
-
--o
- Overwrite *alf-file* if it exists; do not make a **~** backup.
-
-.. overwrite alf file if exists (do not create file~ backup).
-
-**-td**
- Use default **LZ.COM** timestamps (8 Dec 82 12:24).
-
-.. use default LZ.COM timestamps.
-
-**-tu**
- Use UTC for timestamps (default is local timezone).
-
-.. use UTC timestamps.
-
-**-tz**
- Use zero for timestamps (0 ??? 80 12:00a).
-
-.. use zero timestamps.
-
--V, --version
- Show **unalf** version number and exit.
-
-.. show version number.
-
-.. ENDOPTS
-
-EXIT STATUS
-===========
-
-0
- Success.
-
-1
- Fatal error (I/O or bad command-line arguments).
-
-NOTES
-=====
-
-Compatibility
--------------
-
-This **alf** is *intended* to be 100% compatible with the original
-Atari **LZ.COM** aka **ALF.COM**, with the following differences:
-
-- There is no interactive mode. The file to create and the files to add
- must be given as command-line arguments.
-
-- **LZ.COM** always appends to a file that already exists. This **alf**
- overwrites (making a backup) by default, and can append with the **-a**
- option.
-
-- Turning the screen off for speed makes no sense on modern operating
- systems, so there's no option for that.
-
-Note that **alf** is a complete reverse-engineered rewrite in C, *not*
-a port of the original 6502 code as **unalf** is. It's still being
-tested, and may still contain bugs.
-
-File Size Limits
-----------------
-
-**alf** (and **LZ.COM**) have a 16MB file size limit. **uanlf**
-actually can't handle files above about 15MB, if you compress one with
-**alf**. Real Atari 8-bit files are never this large anyway, so it's
-a pathological case. A real Atari would take hours or even days to
-compress/decompress such files, and you'd have to have a hard disk and
-a DOS capable of handling multi-megabyte files...
-
-It's also impossible to compress empty (0-byte) files. **alf** will
-skip them, if any are found.
-
-Performance
------------
-
-Performance is *horrible*. This shouldn't be a real problem on
-modern multi-GHz CPU, especially since most Atari 8-bit files are
-small (usually under 64KB). Interestingly, it's not O(n^2), it scales
-linearly, O(1): Compressing a 1.3MB text file takes 0.7 seconds on the
-author's (rather modest) Intel i7 workstation, and a file 10x as large
-takes approximately 10x as long (7 seconds). A 50KB file is almost
-instantaneous, 0.05 seconds, which is more typical of the files you'd
-actually use this with.
-
-Timestamps
-----------
-
-The date/time stamps stored in the archive are the **mtime**\s of
-the files (which is the same time **ls**\(1) shows, by default), and
-your local timezone is assumed. Only a 2-digit year is displayed by
-**unalf**, but the year stored in the *ALF* file doesn't have a Y2K
-problem. It does, however, have a Y2108 problem...
-
-COPYRIGHT
-=========
-
-The original AlfCrunch (**DZ.COM** and **LZ.COM**) for the Atari 8-bit
-was released into the Public Domain. **alf** contains no code from
-AlfCrunch.
-
-**alf** is released under the WTPFL: Do WTF you want with this.
-
-AUTHOR
-======
-
-The original AlfCrunch for the Atari 8-bit was written by Alfred, who
-can be reached via the AtariAge.com forums with the username "Alfred".
-
-This **alf** was written by B. Watson <urchlay@slackware.uk>.
-
-SEE ALSO
-========
-
-**unalf**\(1), **alfls**\(1)
-
-.. include:: manftr.rst
diff --git a/src/alfsum.1 b/src/alfsum.1
deleted file mode 100644
index 6b4ea04..0000000
--- a/src/alfsum.1
+++ /dev/null
@@ -1,107 +0,0 @@
-.\" Man page generated from reStructuredText.
-.
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.TH "ALFSUM" 1 "2025-11-26" "0.2.0" "Urchlay's Atari 8-bit Tools"
-.SH NAME
-alfsum \- calculate ALF checksums
-.\" RST source for alfsum(1) man page. Convert with:
-.
-.\" rst2man.py alfsum.rst > alfsum.1
-.
-.SH SYNOPSIS
-.sp
-alfsum \fBfile\fP [\fBfile\fP ...] | [\fB\-\-help\fP | \fB\-h\fP] | [\fB\-\-version\fP | \fB\-V\fP]
-.SH DESCRIPTION
-.sp
-\fBalfsum\fP calculates the checksums used by the \fBALF\fP compression
-utility on the Atari 8\-bit platform.
-.sp
-To read from standard input, use \fB\-\fP as a filename.
-.sp
-Output lines have a tab separating the checksum and filename, for ease
-of scripting (e.g. with \fBcut\fP(1) or \fBawk\fP(1)).
-.sp
-\fBalfsum\fP\(aqs primary use is to check files extracted from \fBALF\fP
-archives against the checksums stored in the archive. The \fBunalf\fP
-program already does this, but \fBalfsum\fP is a separate (much simpler)
-program. It serves as a second opinion, in case you suspect a bug in
-\fBunalf\fP\&.
-.SH OPTIONS
-.INDENT 0.0
-.TP
-.B \-h\fP,\fB \-\-help
-Show built\-in help message.
-.TP
-.B \-V\fP,\fB \-\-version
-Show \fBalfsum\fP version number and exit.
-.UNINDENT
-.SH NOTES
-.sp
-The checksum algorithm is very simple: all the bytes in the file are
-added together, and the low 16 bits of the result are the checksum.
-.SH EXIT STATUS
-.INDENT 0.0
-.TP
-.B 0
-Success.
-.TP
-.B 1 to 254
-File I/O error count. If there are more than 254 I/O errors, 254 is returned.
-.TP
-.B 255
-Error in command\-line arguments: no filenames given.
-.UNINDENT
-.SH COPYRIGHT
-.sp
-\fBalfsum\fP is released under the WTPFL: Do WTF you want with this.
-.SH AUTHORS
-.INDENT 0.0
-.IP B. 3
-Watson <\fI\%urchlay@slackware.uk\fP>
-.UNINDENT
-.SH SEE ALSO
-.sp
-\fBalf\fP(1), \fBunalf\fP(1)
-.sp
-The git repository for \fBunalf\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/unalf\fP
-.UNINDENT
-.UNINDENT
-.sp
-Other Atari\-related projects by the author, including \fBbw\-atari8\-tools\fP
-and \fBunmac65\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/\fP
-.UNINDENT
-.UNINDENT
-.\" Generated by docutils manpage writer.
-.
diff --git a/src/alfsum.c b/src/alfsum.c
deleted file mode 100644
index 2456e60..0000000
--- a/src/alfsum.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "unalf.h"
-
-/* 20251104 bkw: implement the simple checksum used by ALF.
- Dumbest possible algo: all the bytes are added together and
- the bottom 16 bits of the result is the checksum. */
-
-void alfsum(const char *file, FILE *f) {
- int c;
- unsigned long sum = 0;
-
- while((c = fgetc(f)) != EOF)
- sum += c;
-
- printf("%04x\t%s\n", (unsigned int)(sum & 0xffff), file);
-}
-
-int main(int argc, char **argv) {
- int errs = 0;
- char *file;
- FILE *f;
-
- set_self(argv[0]);
-
- if(argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
- printf("alfsum v" VERSION " by B. Watson. WTFPL.\n"
- "Usage: %s filename [filename(s) ...]\n"
- "\t(use - to read from standard input)\n",
- self);
- return (argc < 2) ? -1 : 0;
- }
-
- if(!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
- puts(VERSION);
- exit(0);
- }
-
- while((file = *++argv)) {
- if(argv[0][0] == '-' && !argv[0][1]) {
- if(isatty(0))
- fprintf(stderr, "%s: reading from stdin...\n", self);
- f = stdin;
- file = " (stdin)";
- } else if(!(f = fopen(file, "rb"))) {
- fprintf(stderr, "%s: ", self);
- perror(file);
- errs++;
- continue;
- }
- alfsum(file, f);
- fclose(f);
- }
-
- return errs > 254 ? 254 : errs;
-}
diff --git a/src/alfsum.rst b/src/alfsum.rst
deleted file mode 100644
index d613626..0000000
--- a/src/alfsum.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-.. RST source for alfsum(1) man page. Convert with:
-.. rst2man.py alfsum.rst > alfsum.1
-
-.. include:: ver.rst
-
-.. |date| date::
-
-======
-alfsum
-======
-
------------------------
-calculate ALF checksums
------------------------
-
-:Manual section: 1
-:Manual group: Urchlay's Atari 8-bit Tools
-:Date: |date|
-:Version: |version|
-
-SYNOPSIS
-========
-
-alfsum **file** [**file** ...] | [**--help** | **-h**] | [**--version** | **-V**]
-
-DESCRIPTION
-===========
-
-**alfsum** calculates the checksums used by the **ALF** compression
-utility on the Atari 8-bit platform.
-
-To read from standard input, use **-** as a filename.
-
-Output lines have a tab separating the checksum and filename, for ease
-of scripting (e.g. with **cut**\(1) or **awk**\(1)).
-
-**alfsum**'s primary use is to check files extracted from **ALF**
-archives against the checksums stored in the archive. The **unalf**
-program already does this, but **alfsum** is a separate (much simpler)
-program. It serves as a second opinion, in case you suspect a bug in
-**unalf**.
-
-OPTIONS
-=======
-
--h, --help
- Show built-in help message.
-
--V, --version
- Show **alfsum** version number and exit.
-
-NOTES
-=====
-
-The checksum algorithm is very simple: all the bytes in the file are
-added together, and the low 16 bits of the result are the checksum.
-
-EXIT STATUS
-===========
-
-0
- Success.
-
-1 to 254
- File I/O error count. If there are more than 254 I/O errors, 254 is returned.
-
-255
- Error in command-line arguments: no filenames given.
-
-COPYRIGHT
-=========
-
-**alfsum** is released under the WTPFL: Do WTF you want with this.
-
-AUTHORS
-=======
-
-B. Watson <urchlay@slackware.uk>
-
-SEE ALSO
-========
-
-**alf**\(1), **unalf**\(1)
-
-.. include:: manftr.rst
diff --git a/src/alfusage.c b/src/alfusage.c
deleted file mode 100644
index 98eb6f2..0000000
--- a/src/alfusage.c
+++ /dev/null
@@ -1,11 +0,0 @@
-const char *usage_msg[] = {
- " -a: append to alf file.",
- " -A: convert EOLs and tabs in all input files.",
- " -h: show this help message.",
- " -o: overwrite alf file if exists (do not create file~ backup).",
- " -td: use default LZ.COM timestamps.",
- " -tu: use UTC timestamps.",
- " -tz: use zero timestamps.",
- " -V: show version number.",
- (const char*)0
-};
diff --git a/src/asmcode.c b/src/asmcode.c
deleted file mode 100644
index 831ba1c..0000000
--- a/src/asmcode.c
+++ /dev/null
@@ -1,650 +0,0 @@
-#include "unalf.h"
-#include "addrs.h"
-
-extern void chksum_err(void);
-extern void truncated_err(void);
-extern void stack_underrun(void);
-extern void stack_overrun(void);
-
-void uncrunch_file(void) {
- lda_i(0x00);
- sta(L71AF);
- sta(L71B0);
- sta(outbuf_len_l);
- sta(outbuf_len_h);
- sta(L71B6);
- sta(L71B7);
- sta(L718C);
- sta(cksum_l);
- sta(cksum_h);
- lda_i(0x09);
- sta(shift_counter);
- lda_i(0x00);
- sta(L71AD);
- lda_i(0x02);
- sta(L71AE);
- lda_i(0x00);
- sta(stackptr_l);
- lda_i(0x60);
- sta(stackptr_h);
- jsr(setup_io_bufs);
- ldx_i(0x10);
- lda(inbuf_adr_l);
- sta(buf_adr_l);
- lda(inbuf_adr_h);
- sta(buf_adr_h);
- lda(inbuf_len_l);
- sta(buf_len_l);
- lda(inbuf_len_h);
- sta(buf_len_h);
- jsr(L7A19);
- sty(L718C);
- jsr(L79E7);
- lda(buf_len_l);
- ora(buf_len_h);
- bne(L75B1);
- rts();
-
-L75B1:
- jsr(L76D0);
- lda(acc16_h);
- cmp_i(0x01);
- bne(uncrunch_blk);
- lda(acc16_l);
- cmp_i(0x01);
- bne(uncrunch_blk);
- jsr(write_output);
- lda(alf_hdr_cksum_l);
- cmp(cksum_l);
- bne(print_emsg_checksum);
- lda(alf_hdr_cksum_h);
- cmp(cksum_h);
- beq(cksum_ok);
-print_emsg_checksum:
- chksum_err(); /* does not exit */
-cksum_ok:
- rts();
-
-uncrunch_blk:
- lda(acc16_l);
- cmp_i(0x00);
- bne(L760B);
- lda(acc16_h);
- cmp_i(0x01);
- bne(L760B);
- jsr(init_counters);
- jsr(L76D0);
- lda(acc16_l);
- sta(L717D);
- sta(L7179);
- lda(acc16_h);
- sta(L717E);
- sta(L717A);
- lda(acc16_l);
- sta(L7177);
- sta(L7178);
- jsr(store_outbyte);
- jmp(L75B1);
-
-L760B:
- lda(acc16_l);
- sta(L717D);
- sta(L7175);
- lda(acc16_h);
- sta(L717E);
- sta(L7176);
- lda(acc16_h);
- cmp(L717C);
- bcc(L7641);
- lda(acc16_l);
- cmp(L717B);
- bcc(L7641);
- lda(L7179);
- sta(acc16_l);
- sta(L717D);
- lda(L717A);
- sta(acc16_h);
- sta(L717E);
- lda(L7178);
- sta(acc16_l);
- jsr(push_acc16);
-
-L7641:
- lda(L717E);
- beq(L7670);
- lda(L717D);
- sta(zp_b4);
- lda(L717E);
- sta(zp_b5);
- jsr(L7899);
- ldy_i(0x02);
- lda_ind_y(zp_b0);
- sta(acc16_l);
- jsr(push_acc16);
- ldy_i(0x00);
- lda_ind_y(zp_b0);
- sta(acc16_l);
- sta(L717D);
- iny();
- lda_ind_y(zp_b0);
- sta(acc16_h);
- sta(L717E);
- jmp(L7641);
-
-L7670:
- lda(L717D);
- sta(acc16_l);
- sta(L7178);
- sta(L7177);
- lda(L717E);
- sta(acc16_h);
- jsr(push_acc16);
-L7683:
- lda(L71AF);
- ora(L71B0);
- beq(L7694);
- jsr(pop_acc16);
- jsr(store_outbyte);
- jmp(L7683);
-
-L7694:
- jsr(L78C2);
- lda(L7175);
- sta(acc16_l);
- sta(L7179);
- lda(L7176);
- sta(acc16_h);
- sta(L717A);
- lda(L717B);
- sta(zp_b4);
- lda(L717C);
- sta(zp_b5);
- cmp(L71AE);
- bcc(L76CD);
- lda(zp_b4);
- cmp(L71AD);
- bcc(L76CD);
- lda(shift_counter);
- cmp_i(0x0C);
- beq(L76CD);
- inc(shift_counter);
- asl(L71AD);
- rol(L71AE);
-L76CD:
- jmp(L75B1);
-}
-
-void L76D0(void) {
-L76D0:
- lda(L71B6);
- sta(zp_b8);
- lda(L71B7);
- sta(zp_b9);
- ldx_i(0x02);
-L76DC:
- lsr(zp_b9);
- ror(zp_b8);
- dex();
- bpl(L76DC);
- lda(zp_b8);
- sta(L71AA);
- lda(zp_b9);
- sta(L71AB);
- lda(inbuf_len_l);
- sec();
- sbc(zp_b8);
- sta(zp_bc);
- lda(inbuf_len_h);
- sbc(zp_b9);
- sta(zp_bd);
- lda(zp_bd);
- bne(L770F);
- lda(zp_bc);
- cmp_i(0x03);
- bcs(L770F);
- ldx(L718C);
- bpl(L771C);
- cmp_i(0x02);
- bcc(L7712);
-L770F:
- jmp(L779B);
-/* ---------------------------------------------------------------------------- */
-L7712:
- truncated_err(); /* exits! */
-/* ---------------------------------------------------------------------------- */
-L771C:
- tay();
- dey();
- ldx(inbuf_adr_l);
- stx(zp_be);
- ldx(inbuf_adr_h);
- stx(zp_bf);
- lda(inbuf_adr_l);
- clc();
- adc(zp_b8);
- sta(zp_b8);
- lda(inbuf_adr_h);
- adc(zp_b9);
- sta(zp_b9);
-L7737:
- lda_ind_y(zp_b8);
- sta_ind_y(zp_be);
- dey();
- bpl(L7737);
- lda(inbuf_len_l);
- sec();
- sbc(zp_bc);
- sta(buf_len_l);
- lda(inbuf_len_h);
- sbc_i(0x00);
- sta(buf_len_h);
- lda(inbuf_adr_l);
- clc();
- adc(zp_bc);
- sta(buf_adr_l);
- lda(inbuf_adr_h);
- adc_i(0x00);
- sta(buf_adr_h);
- ldx_i(0x10);
- jsr(L7A19);
- sty(L718C);
- bpl(L7771);
- cpy_i(0x88);
- beq(L7771);
- // jmp(cleanup_and_exit);
- exit(0);
-/* ---------------------------------------------------------------------------- */
-L7771:
- jsr(L79E7);
- lda(L71AA);
- sta(zp_b8);
- lda(L71AB);
- sta(zp_b9);
- ldx_i(0x02);
-L7780:
- asl(zp_b8);
- rol(zp_b9);
- dex();
- bpl(L7780);
- lda(L71B6);
- sec();
- sbc(zp_b8);
- sta(L71B6);
- lda(L71B7);
- sbc(zp_b9);
- sta(L71B7);
- jmp(L76D0);
-/* ---------------------------------------------------------------------------- */
-L779B:
- lda(zp_b8);
- sta(zp_bc);
- clc();
- adc(inbuf_adr_l);
- sta(zp_b8);
- lda(zp_b9);
- sta(zp_bd);
- adc(inbuf_adr_h);
- sta(zp_b9);
- ldy_i(0x00);
- lda(L71B6);
- and_i(0x07);
- bne(L77E1);
- lda_ind_y(zp_b8);
- sta(acc16_h);
- iny();
- lda_ind_y(zp_b8);
- sta(acc16_l);
-L77C0:
- lda_i(0x0F);
- sec();
- sbc(shift_counter);
- tax();
-L77C7:
- lsr(acc16_h);
- ror(acc16_l);
- dex();
- bpl(L77C7);
- lda(shift_counter);
- clc();
- adc(L71B6);
- sta(L71B6);
- lda_i(0x00);
- adc(L71B7);
- sta(L71B7);
- rts();
-
-/* ---------------------------------------------------------------------------- */
-L77E1:
- ldx_i(0x02);
-L77E3:
- lda_ind_y(zp_b8);
- sta_abs_x(L7189);
- iny();
- dex();
- bpl(L77E3);
- lda(L71B6);
- and_i(0x07);
- tax();
- dex();
-L77F3:
- asl(L7189);
- rol(L718A);
- rol(L718B);
- dex();
- bpl(L77F3);
- lda(L718A);
- sta(acc16_l);
- lda(L718B);
- sta(acc16_h);
- jmp(L77C0);
-}
-
-void L7A19(void) {
- lda(alf_hdr_compsize2);
- ora(alf_hdr_compsize3);
- beq(L7A28);
-L7A21:
- jsr(readblock);
- Y = 1; /* CIO would set this */
- jsr(L7A5D);
- rts();
-L7A28:
- lda(alf_hdr_compsize1);
- cmp(buf_len_h);
- bcc(L7A40);
- beq(L7A34);
- bcs(L7A21);
-L7A34:
- lda(alf_hdr_compsize0);
- cmp(buf_len_l);
- bcc(L7A40);
- beq(L7A40);
- bcs(L7A21);
-L7A40:
- lda(alf_hdr_compsize0);
- sta(buf_len_l);
- lda(alf_hdr_compsize1);
- sta(buf_len_h);
- lda(buf_len_l);
- ora(buf_len_h);
- beq(L7A57);
- jsr(readblock);
- Y = 1; /* CIO would set this */
-L7A57:
- ldy_i(0x88);
- jsr(L7A5D);
- rts();
-}
-
-void L7A5D(void) {
- lda(alf_hdr_compsize0);
- sec();
- sbc(buf_len_l);
- sta(alf_hdr_compsize0);
- lda(alf_hdr_compsize1);
- sbc(buf_len_h);
- sta(alf_hdr_compsize1);
- lda(alf_hdr_compsize2);
- sbc_i(0x00);
- sta(alf_hdr_compsize2);
- rts();
-}
-
-void setup_io_bufs(void) {
- lda(MEMTOP_lo);
- sec();
- sbc_i(0xDC);
- sta(inbuf_len_l);
- lda(MEMTOP_hi);
- sbc_i(0x7F);
- sta(inbuf_len_h);
- lsr(inbuf_len_h);
- ror(inbuf_len_l);
- lda(inbuf_len_h);
- cmp_i(0x1F);
- bcc(L79A0);
- lda_i(0x00);
- sta(inbuf_len_l);
- lda_i(0x1F);
- sta(inbuf_len_h);
-L79A0:
- lda_i(0xDC);
- sta(inbuf_adr_l);
- lda_i(0x7F);
- sta(inbuf_adr_h);
- lda_i(0xDC);
- clc();
- adc(inbuf_len_l);
- sta(outbuf_adr_l);
- sta(outbuf_ptr_l);
- lda_i(0x7F);
- adc(inbuf_len_h);
- sta(outbuf_adr_h);
- sta(outbuf_ptr_h);
- rts();
-}
-
-void init_counters(void) {
- lda_i(0x09);
- sta(shift_counter);
- lda_i(0x00);
- sta(L71AD);
- lda_i(0x02);
- sta(L71AE);
- lda_i(0x02);
- sta(L717B);
- lda_i(0x01);
- sta(L717C);
- rts();
-}
-
-/* save decrunched byte in outbuf, update checksum, write outbuf if full */
-void store_outbyte(void) {
- ldy_i(0x00);
- lda(acc16_l);
- sta_ind_y(outbuf_ptr_l);
- clc();
- adc(cksum_l);
- sta(cksum_l);
- lda_i(0x00);
- adc(cksum_h);
- sta(cksum_h);
- inc(outbuf_ptr_l);
- bne(out_ptr_hi_ok);
- inc(outbuf_ptr_h);
-out_ptr_hi_ok:
- inc(outbuf_len_l);
- bne(out_len_hi_ok);
- inc(outbuf_len_h);
-out_len_hi_ok:
- lda(outbuf_len_h);
- cmp(inbuf_len_h);
- bcc(outbuf_not_full);
- lda(outbuf_len_l);
- cmp(inbuf_len_l);
- bcc(outbuf_not_full);
- lda(outbuf_adr_l);
- sta(buf_adr_l);
- lda(outbuf_adr_h);
- sta(buf_adr_h);
- lda(outbuf_len_l);
- sta(buf_len_l);
- lda(outbuf_len_h);
- sta(buf_len_h);
- ldx_i(0x30);
- jsr(writeblock);
- bpl(init_outbuf); /* writeblock() never sets N flag, so always branch */
- chksum_err(); /* does not exit */
-/* ---------------------------------------------------------------------------- */
-init_outbuf:
- lda(outbuf_adr_l);
- sta(outbuf_ptr_l);
- lda(outbuf_adr_h);
- sta(outbuf_ptr_h);
- lda_i(0x00);
- sta(outbuf_len_l);
- sta(outbuf_len_h);
-outbuf_not_full:
- rts();
-}
-
-
-/* ---------------------------------------------------------------------------- */
-/* push 2 byte 'register' to software stack */
-void push_acc16(void) {
- ldy_i(0x00);
- lda(acc16_l);
- sta_ind_y(stackptr_l);
- iny();
- lda(acc16_h);
- sta_ind_y(stackptr_l);
- lda(stackptr_l);
- clc();
- adc_i(0x02);
- sta(stackptr_l);
- bcc(L790C);
- inc(stackptr_h);
-L790C:
- lda(stackptr_h);
- cmp_i(0x70);
- bcc(L791C);
- stack_overrun(); /* exits! */
-/* ---------------------------------------------------------------------------- */
-L791C:
- inc(L71AF);
- bne(L7924);
- inc(L71B0);
-L7924:
- rts();
-}
-
-void pop_acc16(void) {
-/* pop 2 byte 'register' from software stack */
- lda(stackptr_l);
- sec();
- sbc_i(0x02);
- sta(stackptr_l);
- lda(stackptr_h);
- sbc_i(0x00);
- sta(stackptr_h);
- ldy_i(0x00);
- lda_ind_y(stackptr_l);
- sta(acc16_l);
- iny();
- lda_ind_y(stackptr_l);
- sta(acc16_h);
- lda(stackptr_h);
- cmp_i(0x60);
- bcs(L796C);
- stack_underrun(); /* exits! */
-/* ---------------------------------------------------------------------------- */
-L796C:
- lda(L71AF);
- bne(L7974);
- dec(L71B0);
-L7974:
- dec(L71AF);
- rts();
-}
-
-void L79E7(void) {
- lda(buf_adr_l);
- clc();
- adc(buf_len_l);
- sta(zp_be);
- lda(buf_adr_h);
- adc(buf_len_h);
- sta(zp_bf);
- ldx_i(0x02);
- bne(L7A0A);
-L79FC:
- ldy_i(0x00);
- tya();
- sta_ind_y(zp_be);
- inc(zp_be);
- bne(L7A07);
- inc(zp_bf);
-L7A07:
- dex();
- bmi(L7A18);
-L7A0A:
- lda(zp_bf);
- cmp(outbuf_adr_h);
- bcc(L79FC);
- lda(zp_be);
- cmp(outbuf_adr_l);
- bcc(L79FC);
-L7A18:
- rts();
-}
-
-void L7899(void) {
- lda(zp_b4);
- sta(zp_b0);
- lda(zp_b5);
- sta(zp_b1);
- asl(zp_b0);
- rol(zp_b1);
- lda(zp_b0);
- clc();
- adc(zp_b4);
- sta(zp_b0);
- lda(zp_b1);
- adc(zp_b5);
- sta(zp_b1);
- lda(zp_b0);
- clc();
- adc(L7181);
- sta(zp_b0);
- lda(zp_b1);
- adc(L7182);
- sta(zp_b1);
- rts();
-}
-
-void L78C2(void) {
- lda(L717B);
- sta(zp_b4);
- lda(L717C);
- sta(zp_b5);
- jsr(L7899);
- lda(L7177);
- sta(acc16_l);
- ldy_i(0x02);
- sta_ind_y(zp_b0);
- lda(L7179);
- sta(acc16_l);
- lda(L717A);
- sta(acc16_h);
- ldy_i(0x00);
- lda(acc16_l);
- sta_ind_y(zp_b0);
- iny();
- lda(acc16_h);
- sta_ind_y(zp_b0);
- inc(L717B);
- bne(L78F5);
- inc(L717C);
-L78F5:
- rts();
-}
-
-void write_output(void) {
- lda(outbuf_len_l);
- ora(outbuf_len_h);
- bne(have_output);
- rts();
-/* ---------------------------------------------------------------------------- */
-have_output:
- lda(outbuf_adr_l);
- sta(buf_adr_l);
- lda(outbuf_adr_h);
- sta(buf_adr_h);
- lda(outbuf_len_l);
- sta(buf_len_l);
- lda(outbuf_len_h);
- sta(buf_len_h);
- ldx_i(0x30);
- jsr(writeblock);
- rts();
-}
diff --git a/src/extract.c b/src/extract.c
deleted file mode 100644
index 305cd4a..0000000
--- a/src/extract.c
+++ /dev/null
@@ -1,197 +0,0 @@
-#include "unalf.h"
-#include "addrs.h"
-
-int bad_checksum, bad_checksum_count = 0;
-int new_file = 0;
-unsigned int bytes_written = 0;
-char *out_filename;
-
-void dpoke(int addr, u16 value) {
- mem[addr] = value & 0xff;
- mem[addr + 1] = value >> 8;
-}
-
-u16 dpeek(int addr) {
- return mem[addr] | (mem[addr + 1] << 8);
-}
-
-static void bad_atari_filename(const char *msg) {
- char fn[50] = "";
- char xbuf[5];
- int i;
- u8 c;
-
- for(i = 0; (c = (u8)out_filename[i]) && i < 12; i++) {
- if(c < ' ' || c > '|') {
- /* not printable, insert a hex escape */
- sprintf(xbuf, "$%02X", c);
- strcat(fn, xbuf);
- } else {
- strncat(fn, (char *)&c, 1);
- }
- }
-
- fprintf(stderr, "%s: bad Atari filename \"%s\": %s\n", self, fn, msg);
-}
-
-/* note to self: it's tempting to use isalpha(), isprint(), etc
- from ctype.h... but those are locale-aware. we want ASCII-only
- versions. */
-static void sanity_check_filename(void) {
- u8 c;
- unsigned int i, bad = 0, dots = 0, uscore = 0;
-
- c = out_filename[0];
- if(!c) {
- bad_atari_filename("empty! corrupt ALF file?");
- return;
- } else if(c < 'A' || c > 'Z') {
- bad_atari_filename("does not begin with A-Z");
- }
-
- for(i = 0; (c = out_filename[i]) && i < 12; i++) {
- if(c >= 'A' && c <= 'Z')
- continue;
- if(c >= '0' && c <= '9')
- continue;
- if(c == '_') {
- uscore++;
- continue;
- }
- if(c == '.') {
- dots++;
- continue;
- }
- bad++;
- }
-
- if(!dots) {
- bad_atari_filename("no \".\"");
- } else if(dots > 1) {
- bad_atari_filename("more than one \".\"");
- }
-
- if(bad)
- bad_atari_filename("invalid characters. corrupt ALF file?");
- else if(uscore)
- fprintf(stderr, "%s: filename has underscore, OK on Sparta/MyDOS, not Atari DOS 2.x\n", self);
-}
-
-void fix_filename(void) {
- char *p;
-
- if(!out_filename) return;
-
- if(strlen(out_filename) > 12) {
- fprintf(stderr, "%s: filename in ALF header not null-terminated, fixing.\n", self);
- out_filename[12] = '\0';
- }
-
- sanity_check_filename();
-
- if(opts.lowercase) {
- for(p = out_filename; *p; p++)
- *p = tolower(*p);
- }
-
- if(!opts.keepdot) {
- for(p = out_filename; *p; p++)
- if(p[0] == '.' && !p[1])
- *p = '\0';
- }
-}
-
-void make_backup(void) {
- /* up to 12-char FILENAME.EXT, plus a ~, plus null terminator = 14 */
- char backup[14];
-
- strncpy(backup, out_filename, 13);
- strncat(backup, "~", 13);
-
- /* silently ignore errors! */
- rename(out_filename, backup);
-}
-
-void extract_alf(void) {
- /* get ready to call fake 6502 stuff. set up memory like the Atari. */
- dpoke(MEMTOP, 0xbc1f);
-
- while(read_alf_header()) {
- out_filename = (char *)(mem + alf_hdr_filename);
-
- fix_filename();
-
- if(!file_wanted(out_filename)) {
- if(fseek(in_file, getquad(alf_hdr_compsize0), SEEK_CUR) != 0) {
- fprintf(stderr, "%s: fatal: seek failed on input!\n", self);
- exit(1);
- }
- out_filename = 0;
- continue;
- }
-
- if(!opts.quiet) {
- printf("%s %s\n", opts.testonly ? "Testing" : "Uncrunching", out_filename);
- }
-
- if(opts.extract_to_stdout) {
- out_file = stdout;
- } else {
- char *realname = out_filename;
-
- if(opts.testonly) {
- out_filename = "/dev/null";
- } else if(!opts.overwrite) {
- make_backup();
- }
-
- if(!(out_file = fopen(out_filename, "wb"))) {
- fprintf(stderr, "%s: fatal: ", self);
- perror(out_filename);
- exit(1);
- }
-
- out_filename = realname;
- }
-
- bad_checksum = bytes_written = 0;
- new_file = 1;
- uncrunch_file();
- if(bad_checksum) bad_checksum_count++;
- if(bytes_written != getquad(alf_hdr_origsize0))
- fprintf(stderr, "%s: %s should be %u bytes, but extracted to %u.\n",
- self, out_filename, getquad(alf_hdr_origsize0), bytes_written);
-
- if(!opts.extract_to_stdout) fclose(out_file);
- out_filename = 0;
- }
-
- if(opts.testonly && !opts.quiet) {
- if(bad_checksum_count)
- printf("%d file%s with bad checksum!\n",
- bad_checksum_count,
- bad_checksum_count == 1 ? "" : "s");
- else
- printf("All files OK.\n");
- }
-}
-
-void chksum_err(void) {
- bad_checksum = 1;
- fprintf(stderr, "%s: checksum error on %s\n", self, out_filename);
-}
-
-void truncated_err(void){
- fprintf(stderr, "%s: fatal: compressed data is truncated, EOF before end marker\n", self);
- exit(1);
-}
-
-void stack_underrun(void){
- fprintf(stderr, "%s: fatal: stack underrun\n", self);
- exit(1);
-}
-
-void stack_overrun(void){
- fprintf(stderr, "%s: fatal: stack overrun\n", self);
- exit(1);
-}
diff --git a/src/glob.c b/src/glob.c
deleted file mode 100644
index c816964..0000000
--- a/src/glob.c
+++ /dev/null
@@ -1,115 +0,0 @@
-#include "unalf.h"
-
-/* this is an Atari DOS or MS-DOS style match: "*.*" matches everything,
- even files with no extension (no dot). "*" by itself matches only
- files with no extension, as does "*."
- matching is case-insensitive. */
-
-static void split_filename(const char *fname, char *name, const char **ext) {
- int i;
-
- for(i = 0; i < 8; i++) {
- if(fname[i] == '.' || fname[i] == '\0')
- break;
- name[i] = fname[i];
- }
- name[i] = '\0';
-
- *ext = strchr(fname, '.');
- if(*ext) {
- (*ext)++;
- if(!**ext) *ext = 0;
- }
-
- // fprintf(stderr, "split %s into: '%s' and '%s'\n",
- // fname, name, (*ext ? *ext : "<none>"));
-}
-
-static int match_part(const char *pat, const char *arg) {
- char p;
-
- if(arg && arg[0] == '\0') arg = 0;
-
- if(!pat) {
- if(arg)
- return 0;
- else
- return 1;
- }
-
- while((p = toupper(*pat++))) {
- // fprintf(stderr, "p == %c\n", p);
- switch(p) {
- case '*': return 1;
- case '?':
- if(!arg || *arg == '\0')
- return 0;
- arg++;
- break;
- default:
- if(!arg || toupper(*arg) != p)
- return 0;
- arg++;
- break;
- }
- }
-
- return *arg ? 0 : 1;
-}
-
-int globmatch(const char *pat, const char *arg) {
- char npat[9], name[9];
- const char *epat = 0, *ext = 0;
-
- split_filename(pat, npat, &epat);
- split_filename(arg, name, &ext);
-
- return match_part(npat, name) && match_part(epat, ext);
-}
-
-int file_wanted(const char *filename) {
- int i;
- char **ig;
-
- /* if excluded, always return false */
- for(i = 0; i < exclude_count; i++) {
- if(globmatch(exclude_globs[i], filename))
- return 0;
- }
-
- /* if no include globs, always match (as though *.* were given) */
- if(!*include_globs)
- return 1;
-
- ig = (char **)include_globs;
- while(*ig) {
- if(globmatch(*ig, filename))
- return 1;
- ig++;
- }
-
- return 0;
-}
-
-/* for testing: */
-#if 0
-int main(int argc, char **argv) {
- int matched;
- const char *pattern;
-
- if(argc < 3) {
- fprintf(stderr, "usage: %s <glob-pattern> <filename> ...\n", argv[0]);
- return 1;
- }
-
- pattern = argv[1];
- argv++;
-
- while(*++argv) {
- matched = globmatch(pattern, *argv);
- printf("%s %s %s\n", *argv, matched ? "matches" : "DOES NOT match", pattern);
- }
-
- return 0;
-}
-#endif
diff --git a/src/io.c b/src/io.c
deleted file mode 100644
index 53bc0dd..0000000
--- a/src/io.c
+++ /dev/null
@@ -1,163 +0,0 @@
-#include "unalf.h"
-#include "addrs.h"
-
-static int headers_read = 0;
-static int convert_eols = 0;
-
-static void die_arc(void) {
- fprintf(stderr, "%s: fatal: this is an ARC file, not ALF\n", self);
- exit(1);
-}
-
-static void die_not_alf(void) {
- fprintf(stderr, "%s: fatal: not an ALF file\n", self);
- exit(1);
-}
-
-/* truncating the file by name could be a race condition, but I don't
- think it's going to be a real-world problem for anyone. */
-static void eof_junk(long pos) {
- fprintf(stderr, "%s: junk at EOF (%s)\n", self, opts.fixjunk ? "removing" : "ignoring");
- if(opts.fixjunk) {
- if(truncate(in_filename, pos) < 0) {
- fprintf(stderr, "%s: could not remove junk: ", self);
- perror(in_filename);
- }
- }
-}
-
-static void check_hdr_size(const char *name, unsigned long size) {
- const char *desc;
-
- /* fits on a double-density disk? */
- if(size < 184320)
- return;
-
- /* >= 16MB files are impossible because the decrunch algorithm
- ignores the high byte of the 4-byte length. */
- if(size >= 16777216L)
- desc = "impossibly large (>=16MB)";
- /* >1MB files are possible (e.g. with a hard drive on SpartaDOS X)
- but exceedingly rare in the Atari world. */
- else if(size > 1048576L)
- desc = "suspiciously large (>1MB)";
- else
- desc = "too large for a floppy disk (>180KB)";
-
- fprintf(stderr, "%s: header #%d %s size is %s.\n",
- self, headers_read, name, desc);
-}
-
-static void sanity_check_header(void) {
- check_hdr_size("original", getquad(alf_hdr_origsize0));
- check_hdr_size("compressed", getquad(alf_hdr_compsize0));
-}
-
-/* return 1 if a header is read, 0 if not */
-int read_alf_header(void) {
- u8 h1, h2;
- int bytes;
- long read_pos;
-
- read_pos = ftell(in_file);
-
- bytes = fread(mem + alf_header, 1, 29, in_file);
-
- if(!bytes) {
- if(headers_read)
- return 0;
- else
- die_not_alf();
- } else if(bytes < 29) {
- if(headers_read) {
- eof_junk(read_pos);
- return 0;
- } else {
- die_not_alf();
- }
- }
-
- h1 = mem[alf_header];
- h2 = mem[alf_hdr_sig];
-
- if(h1 == 0x1a) {
- if(h2 < 0x0f) die_arc();
- if(h2 == 0x0f) {
- headers_read++;
- sanity_check_header();
- return 1; /* signature matches */
- }
- }
-
- if(headers_read)
- eof_junk(read_pos);
- else
- die_not_alf();
-
- return 0;
-}
-
-/* read buf_len_l/h bytes into buf_adr_l/h, then store the number
- of bytes actually read in buf_len_l/h. TODO: what about EOF? */
-void readblock(void) {
- int bytes, len, bufadr;
- u8 *buf;
-
- bufadr = dpeek(buf_adr_l);
- buf = mem + bufadr;
- len = dpeek(buf_len_l);
-
- // fprintf(stderr, "readblock, bufadr = $%04x, len = $%04x\n", bufadr, len);
-
- bytes = fread(buf, 1, len, in_file);
- dpoke(buf_len_l, bytes);
-}
-
-static int is_printable(u8 c) {
- return (c == 0x9b || (c >= ' ' && c <= 124));
-}
-
-static int is_text_file(u8 *buf) {
- return is_printable(buf[0]) && is_printable(buf[1]);
-}
-
-/* mirror of readblock(), plus EOL conversion if needed. With -a,
- a file is considered text if its first 2 bytes are printable ATASCII,
- including EOLs. With -aa, all files are converted. */
-void writeblock(void) {
- int i, bytes, len, bufadr;
- u8 *buf;
-
- bufadr = dpeek(buf_adr_l);
- buf = mem + bufadr;
- len = dpeek(buf_len_l);
-
- if(new_file) {
- if(opts.txtconv > 1) {
- convert_eols = 1;
- } else if(opts.txtconv == 1 && len > 1) {
- convert_eols = is_text_file(buf);
- } else {
- convert_eols = 0;
- }
- }
- new_file = 0;
-
- if(convert_eols) {
- for(i = 0; i < len; i++) {
- if(buf[i] == 0x9b) buf[i] = '\n';
- if(buf[i] == 0x7f) buf[i] = '\t';
- }
- }
-
- // fprintf(stderr, "writeblock, bufadr = $%04x, len = $%04x\n", bufadr, len);
-
- bytes = fwrite(buf, 1, len, out_file);
- if(bytes < 0) {
- fprintf(stderr, "%s: fatal: ", self);
- perror("write failed"); /* TODO: out_filename */
- exit(1);
- }
- bytes_written += bytes;
- dpoke(buf_len_l, bytes);
-}
diff --git a/src/listalf.c b/src/listalf.c
deleted file mode 100644
index 8082d11..0000000
--- a/src/listalf.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "unalf.h"
-#include "addrs.h"
-
-static const char *monthnames[] = {
- "???",
- "Jan", "Feb", "Mar", "Apr",
- "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec",
- "???", "???", "???",
-};
-
-u16 getword(int offs) {
- return mem[offs] | (mem[offs + 1] << 8);
-}
-
-unsigned int getquad(int offs) {
- return getword(offs) | ((getword(offs + 2) << 16));
-}
-
-/* see Arcinfo for details */
-void format_msdos_time(char *buf) {
- u16 t, hour, min;
- char ampm;
-
- t = getword(alf_hdr_time0);
-
- /* don't bother with seconds (arc doesn't print them either) */
- hour = t >> 11;
- min = (t >> 5) & 0x3f;
-
- /* midnight is 12:00a (unlike arc, which uses 0:00a). noon
- is 12:00p (same as arc). could just use a 24h clock like
- unzip does, but AM/PM are more intuitive to me. */
- ampm = (hour > 11 ? 'p' : 'a');
- hour %= 12;
-
- /* midnight and noon print as 12, not 0 */
- if(hour == 0) hour = 12;
-
- snprintf(buf, 7, "%2d:%02d%c", hour, min, ampm);
-}
-
-/* see Arcinfo for details */
-void format_msdos_date(char *buf) {
- u16 d, year, month, day;
-
- d = getword(alf_hdr_date0);
-
- /* year actually ranges 1980 to 2107... */
- year = (d >> 9) + 1980;
- year %= 100; /* ...but only print last 2 digits */
-
- /* valid months range 1 to 12. values 0, 13, 14, 15 are possible
- but invalid (print as ???) */
- month = (d >> 5) & 0x0f;
-
- /* valid day range is 1 to 31. 0 is invalid, print as-is. */
- day = d & 0x1f;
-
- snprintf(buf, 10, "%2d %3s %02d", day, monthnames[month], year);
-}
-
-/* small files may be "compressed" larger than the original, so this
- has to return a signed type. */
-static int comp_percent(unsigned int orig, unsigned int comp) {
- if(orig == 0) return 0; /* no division by zero please */
- return 100 - (int)((float)comp / (float)orig * 100.0);
-}
-
-/* output similar to "arc v", except we omit the compression type column
- since there's only one type. also, don't call the checksum a CRC, it
- isn't. */
-void list_alf(void) {
- unsigned int c = 0, orig_size, comp_size, total_osize = 0, total_csize = 0;
- char buf[100];
- extern char *out_filename;
-
- if(opts.verbose_list) {
- puts("Name Length Size now Comp Date Time CkSum");
- puts("============ ======== ======== ==== ========= ====== =====");
- }
-
- while(read_alf_header()) {
- c++;
- orig_size = getquad(alf_hdr_origsize0);
- comp_size = getquad(alf_hdr_compsize0);
- out_filename = (char *)(mem + alf_hdr_filename);
-
- if(!opts.verbose_list)
- fix_filename();
-
- total_osize += orig_size;
- total_csize += comp_size;
-
- if(opts.verbose_list) {
- printf("%-12s ", out_filename);
- printf("%8d ", orig_size);
- printf("%8d ", comp_size);
- printf("%3d%% ", comp_percent(orig_size, comp_size));
- format_msdos_date(buf);
- printf("%9s ", buf);
- format_msdos_time(buf);
- printf("%6s ", buf);
- printf(" %04x", getword(alf_hdr_cksum_l));
- putchar('\n');
- } else {
- if(file_wanted(out_filename))
- printf("%s\n", out_filename);
- }
-
- if(fseek(in_file, comp_size, SEEK_CUR) != 0) {
- fprintf(stderr, "%s: fatal: seek failed on input!\n", self);
- exit(1);
- }
- }
-
- if(opts.verbose_list) {
- fputs(" ==== ======== ======== ====\nTotal ", stdout);
- printf("%4d ", c);
- printf("%8d ", total_osize);
- printf("%8d ", total_csize);
- printf("%3d%% ", comp_percent(total_osize, total_csize));
- putchar('\n');
- }
-}
diff --git a/src/manftr.rst b/src/manftr.rst
deleted file mode 100644
index bb4c7ff..0000000
--- a/src/manftr.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-The git repository for **unalf**:
-
- https://slackware.uk/~urchlay/repos/unalf
-
-Other Atari-related projects by the author, including **bw-atari8-tools**
-and **unmac65**:
-
- https://slackware.uk/~urchlay/repos/
diff --git a/src/mkusage.pl b/src/mkusage.pl
deleted file mode 100644
index 1c6a1bf..0000000
--- a/src/mkusage.pl
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/perl -w
-
-print "const char *usage_msg[] = {\n";
-
-while(<>) {
- chomp;
- next if /^---/;
- last if /^\.\. ENFOPTS/;
- if(/^(?:\*\*)?(-[-a-zA-Z\d]+)/) {
- $opt = $1;
- next;
- }
- if($opt && (/^\.\. (.*)$/)) {
- print "\t\" $opt: $1\",\n";
- undef $opt;
- }
-}
-
-print "\t(const char*)0\n};\n";
diff --git a/src/opts.c b/src/opts.c
deleted file mode 100644
index 416163c..0000000
--- a/src/opts.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "unalf.h"
-
-#define OPTIONS "aefklLopqtvVd:x:"
-
-/* uncomment to test exclude/include glob lists */
-// #define DEBUG_GLOBS
-
-static void add_exclude(const char *glob) {
- if(exclude_count == MAX_EXCLUDES)
- return;
- exclude_globs[exclude_count++] = glob;
-}
-
-#ifdef DEBUG_GLOBS
-static void show_globs(void) {
- int i;
-
- printf("Include globs:\n");
- while(*include_globs)
- printf(" + %s\n", *include_globs++);
- printf("Exclude globs:\n");
- for(i = 0; i < exclude_count; i++)
- printf(" - %s\n", exclude_globs[i]);
- exit(0);
-}
-#endif
-
-void parse_opts(int argc, char * const *argv) {
- int opt;
- char **ig;
-
- /* don't let getopt() print error message for us. */
- opterr = 0;
-
- while((opt = getopt(argc, argv, OPTIONS)) != -1) {
- switch(opt) {
- case 'a': opts.txtconv++; break;
- case 'e': opts.listonly = opts.testonly = 0; break;
- case 'k': opts.keepdot++; break;
- case 'f': opts.fixjunk++; opts.testonly = 1; opts.listonly = 0; opts.quiet = 1; break;
- case 'l': opts.listonly++; opts.testonly = 0; break;
- case 'L': opts.lowercase++; break;
- case 'o': opts.overwrite++; break;
- case 'p': opts.extract_to_stdout++; opts.quiet++; break;
- case 'q': opts.quiet++; break;
- case 't': opts.testonly++; opts.listonly = 0; break;
- case 'v': opts.listonly = 1; opts.testonly = 0; opts.verbose_list++; break;
- case 'V': puts(VERSION); exit(0); break;
- case 'd': opts.outdir = optarg; break;
- case 'x': add_exclude(optarg); break;
- default:
- fprintf(stderr, "%s: fatal: invalid option '-%c' (try -h or --help)\n", self, optopt);
- exit(1);
- }
- }
-
- if(optind >= argc) {
- fprintf(stderr, "%s: fatal: missing alf file argument (try -h or --help)\n", self);
- exit(1);
- }
-
- in_filename = argv[optind];
- if(optind < argc)
- include_globs = &argv[optind + 1]; /* might be null, that's OK */
-
- ig = (char **)include_globs;
- while(*ig) {
- if(globmatch("*.alf", *ig)) {
- fprintf(stderr, "%s: ALF files don't normally contain other ALF files, are you trying to extract/list multiple ALF files at once?\n", self);
- break;
- }
- ig++;
- }
-
-#ifdef DEBUG_GLOBS
- show_globs();
-#endif
-}
diff --git a/src/self.c b/src/self.c
deleted file mode 100644
index 298608a..0000000
--- a/src/self.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "unalf.h"
-
-char *self;
-
-void set_self(char *argv0) {
- char *p;
-
- self = argv0;
- p = strrchr(self, '/');
- if(!p) p = strrchr(self, '\\'); // windows exe needs this
- if(p) self = p + 1;
-}
-
diff --git a/src/self.h b/src/self.h
deleted file mode 100644
index aba1de2..0000000
--- a/src/self.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* self.c */
-extern char *self;
-void set_self(char *argv0);
diff --git a/src/unalf.1 b/src/unalf.1
deleted file mode 100644
index 3343162..0000000
--- a/src/unalf.1
+++ /dev/null
@@ -1,412 +0,0 @@
-.\" Man page generated from reStructuredText.
-.
-.
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-.TH "UNALF" 1 "2025-11-28" "0.2.0" "Urchlay's Atari 8-bit Tools"
-.SH NAME
-unalf \- extract Atari 8-bit ALF archives
-.\" RST source for unalf(1) man page. Convert with:
-.
-.\" rst2man.py unalf.rst > unalf.1
-.
-.SH SYNOPSIS
-.sp
-unalf [\fB\-\-help\fP] [\fB\-aehtklLopqtv\fP] [\fB\-d\fP \fIdir\fP] [\fB\-x\fP \fIwildcard\fP] \fIalf\-file\fP [\fIwildcard\fP ...]
-.SH DESCRIPTION
-.sp
-\fBunalf\fP lists, extracts, or tests the contents of an \fIALF\fP archive.
-.sp
-\fIALF\fP is a compressed archive format similar to \fBarc\fP(1), though
-not compatible with it. It was used on the Atari 8\-bit platform
-beginning in the late 1980s. The Atari executables are \fBLZ.COM\fP
-for the compressor and \fBDZ.COM\fP for the decompressor. \fBunalf\fP is a
-port of \fBDZ.COM\fP for modern operating systems, with added features.
-.sp
-Extracted files are written to the current directory by
-default. Existing files are backed up by default (by adding a \fB~\fP
-suffix to the filename).
-.sp
-If one or more \fIwildcard\fP arguments are provided, files will only be
-listed or extracted if they match one of the wildcards. See \fBWILDCARDS\fP
-below for details.
-.sp
-Only one \fIalf\-file\fP argument is allowed. It\(aqs impossible to process
-multiple ALF files per run of \fBunalf\fP\&. If you need bulk extraction,
-use e.g. a \fBfor\fP loop in a shell script.
-.sp
-\fBunalf\fP can\(aqt read an ALF file on standard input; \fIalf\-file\fP must be
-a real file.
-.SH OPTIONS
-.INDENT 0.0
-.TP
-.B \-a
-Convert text file line endings and tabs from ATASCII to ASCII. Text
-files are detected by looking at the first 2 bytes of the extracted
-file. If both are printable ASCII (including ATASCII EOL, aka \fB$9B\fP), the
-file is considered text.
-.sp
-Note that \fIonly\fP line\-endings and tabs are converted. Other ATASCII
-characters are left alone. If you need anything more in\-depth, use
-\fBa8cat\fP(1).
-.UNINDENT
-.\" convert EOLs and tabs in text files.
-.
-.INDENT 0.0
-.TP
-.B \fB\-aa\fP
-Convert line endings and tabs in \fIall\fP extracted files. This will
-corrupt any executables or non\-text data files, so use with caution.
-.UNINDENT
-.\" convert EOLs and tabs in ALL files.
-.
-.INDENT 0.0
-.TP
-.BI \-d \ output\-dir
-Write extracted files to this directory, which will be created if it
-does not exist. The default is the current directory.
-.UNINDENT
-.\" set output directory (created if needed).
-.
-.INDENT 0.0
-.TP
-.B \-e
-Extract files. This is actually a no\-op, as extraction is the
-default action.
-.UNINDENT
-.\" extract files (redundant; this is the default action).
-.
-.INDENT 0.0
-.TP
-.B \-f
-Fix (remove) junk at EOF. This option truncates the \fIalf\-file\fP\&.
-It is the only \fBunalf\fP option that writes to the input file. No
-backup is made.
-.UNINDENT
-.\" fix (remove) junk at EOF.
-.
-.INDENT 0.0
-.TP
-.B \-h\fP,\fB \-\-help
-Show built\-in help message.
-.UNINDENT
-.\" show this help message.
-.
-.INDENT 0.0
-.TP
-.B \-k
-Keep trailing periods. In most (all?) ALF files, filenames that have no
-extension are stored with a trailing period, e.g. \(aq\fBFOO\fP\(aq would
-be stored as \(aq\fBFOO.\fP\(aq. On the Atari, the extracted file would be
-named \(aq\fBFOO\fP\(aq, so \fBunalf\fP does the same by default. With \fB\-k\fP,
-the file will be named \(aq\fBFOO.\fP\(aq.
-.UNINDENT
-.\" keep trailing periods (dots) in filenames.
-.
-.INDENT 0.0
-.TP
-.B \-l
-List filenames in archive, one per line, but do not extract. Use
-\fB\-v\fP for more information (file size, etc). Obeys \fIwildcards\fP and
-the \fB\-x\fP, \fB\-L\fP, \fB\-k\fP options.
-.UNINDENT
-.\" list files in archive (filenames only).
-.
-.INDENT 0.0
-.TP
-.B \-L
-Lowercase filenames. Example: \fBFOO.TXT\fP will extract to \fBfoo.txt\fP\&.
-.UNINDENT
-.\" use lowercase filenames.
-.
-.INDENT 0.0
-.TP
-.B \-o
-Overwrite files, if they already exist. The default is to rename
-existing files, adding a \fB~\fP suffix. Note that renaming \fBfile\fP
-to \fBfile~\fP \fIwill\fP overwrite \fBfile~\fP if it already exists.
-.UNINDENT
-.\" overwrite files (do not create file~ backups).
-.
-.INDENT 0.0
-.TP
-.B \-p
-Extract to standard output. All the files that get extracted will be
-printed to stdout with no delimiters, so this is most useful when
-only extracting one file. \fB\-q\fP is automatically enabled by this option.
-.sp
-\fIWarning:\fP No checking is done to see whether stdout is a terminal.
-Printing binary files to a terminal is a good way to make a mess.
-Even text files with the EOLs translated can still contain ATASCII
-formatting/graphics codes that can confuse your terminal. You have
-been warned.
-.UNINDENT
-.\" extract to stdout (enables -q).
-.
-.INDENT 0.0
-.TP
-.B \-q
-Quiet extraction or testing: do not print "Uncrunching \fIfile\fP"
-or "Testing \fIfile\fP" messages. Errors and warnings will still be
-printed. This is the default when \fB\-p\fP is used. This option
-doesn\(aqt do anything when used with \fB\-l\fP or \fB\-v\fP\&.
-.UNINDENT
-.\" quiet: don't print filenames during extraction/testing.
-.
-.INDENT 0.0
-.TP
-.B \-t
-Test archive. Same as extraction, except the files are not written
-anywhere.
-.UNINDENT
-.\" test archive.
-.
-.INDENT 0.0
-.TP
-.B \-v
-Verbose listing of archive contents, with compressed and original
-sizes, compression ration, date/time stamps, and checksum. The
-output format is similar to that of \fBarc \-v\fP, minus the \fIStowage\fP
-column, since \fIALF\fP doesn\(aqt support multiple compression types. The
-date and time are displayed, but in most .alf files these are the
-default values of "8 Jan 82 12:24a".
-.sp
-Unlike \fB\-l\fP, the \fB\-v\fP listing shows the filenames exactly as
-stored in the archive (ignores \fB\-L\fP, enables \fB\-k\fP), and always
-shows all the files (ignores \fIwildcards\fP and \fB\-x\fP).
-.UNINDENT
-.\" verbose listing of archive contents.
-.
-.INDENT 0.0
-.TP
-.B \-V\fP,\fB \-\-version
-Show \fBunalf\fP version number and exit.
-.UNINDENT
-.\" show version number.
-.
-.INDENT 0.0
-.TP
-.BI \-x \ wildcard
-Exclude (do not list or extract) files matching \fIwildcard\fP\&. See
-\fBWILDCARDS\fP below. This option can be given multiple times
-to exclude multiple patterns.
-.UNINDENT
-.\" exclude <wildcard>. may be given multiple times.
-.
-.\" ENDOPTS
-.
-.SH WILDCARDS
-.sp
-Wildcard (aka glob) matching works like it does on the Atari: \fI*.*\fP
-matches any filename (whether or not it has an extension), and \fI*\fP
-or \fI*.\fP only match filenames with no extension.
-.sp
-A \fI*\fP matches any number of characters (including zero). A \fI?\fP
-matches a single character. All other characters match themselves, so
-a wildcard with no \fI*\fP or \fI?\fP must match exactly.
-.sp
-Like the Atari, anything in the name or extension following a \fI*\fP is
-ignored: \fBFOO*BAR.TXT\fP is equivalent to \fBFOO*.TXT\fP, and
-\fBFOO.T*T\fP is equivalent to \fBFOO.T*\fP\&. \fBFOO*TXT\fP is
-equivalent to \fBFOO*\fP, and \fIwill not\fP match the file \fBFOO.TXT\fP\&.
-.sp
-Unlike the Atari, matching is case\-insensitive.
-.sp
-To avoid your shell trying to expand the wildcards, always quote them!
-Example:
-.INDENT 0.0
-.INDENT 3.5
-.sp
-.nf
-.ft C
-unalf filename.alf \(aq*.txt\(aq
-.ft P
-.fi
-.UNINDENT
-.UNINDENT
-.SH EXIT STATUS
-.INDENT 0.0
-.TP
-.B 0
-Success.
-.TP
-.B 1
-Fatal error (I/O or bad command\-line arguments, stack under/overrun).
-.TP
-.B 2
-Processing completed OK, but at least one file in the archive
-has a bad checksum.
-.UNINDENT
-.SH DIAGNOSTICS
-.sp
-Besides the standard error messages such as "no such file or directory":
-.SS Fatal errors
-.sp
-\fBunalf\fP will exit with status 1 immediately after these errors:
-.INDENT 0.0
-.TP
-.B \fBfatal: this is an ARC file, not ALF\fP
-Self\-explanatory. Use the \fBarc\fP(1) utility for this file.
-.TP
-.B \fBfatal: not an ALF file\fP
-Self\-explanatory. Either the file is too small (less than 29 bytes)
-or its first two bytes don\(aqt match the \fIALF\fP signature \fB0x1a\fP \fB0x0f\fP\&.
-.TP
-.B \fBfatal: stack underrun/overrun\fP
-Generally means the archive is corrupt. Valid ALF files should never
-cause these errors.
-.TP
-.B \fBfatal: compressed data is truncated, EOF before end marker\fP
-Self\-explanatory. The ALF file ends before the compressed data does.
-.UNINDENT
-.SS Warnings
-.sp
-\fBunalf\fP will continue after these messages occur.
-.INDENT 0.0
-.TP
-.B \fBjunk at EOF (ignoring)\fP
-Mostly harmless: does \fInot\fP imply data corruption.
-.sp
-Usually this is caused by the .alf file being stored on a CP/M disk
-at some time, or by a dumb file transfer protocol. Either way, the
-file gets padded to the block size of the filesystem or protocol.
-Usually, the padding characters are \fB0x1a\fP, aka ASCII control\-Z.
-.sp
-This message means you can\(aqt append to the ALF file with \fBalf \-a\fP
-or \fBLZ.COM\fP\&. You can, however, use \fBunalf \-f\fP to remove the junk.
-.TP
-.B \fBchecksum error on\fP \fI<file>\fP
-The archive is corrupt. If \fI<file>\fP is a text file, it may be
-partially readable. If it\(aqs an executable or other binary file, it\(aqs
-probably unrecoverable. \fBunalf\fP will try to extract the rest of
-the archive, but will exit with status 2 when it\(aqs done.
-.sp
-If you have an ALF file that does this, try it with the Atari
-\fBDZ.COM\fP and see if it has the same problem. If it doesn\(aqt,
-you\(aqve found a bug in \fBunalf\fP, please send me the .alf file via
-email (see \fBAUTHOR\fP, below). Actually, I\(aqd be interested to see
-the .alf file even if it doesn\(aqt work on the Atari either.
-.TP
-.B \fI<file>\fP \fBshould be\fP \fI<size>\fP \fBbytes, but extracted to\fP \fI<size>\fP
-The archive is corrupt. If this happens on the last (or only) file, it
-probably means the ALF file was truncated. You\(aqll almost certainly
-get a checksum error for \fI<file>\fP, too.
-.TP
-.B \fBbad Atari filename\fP \fI<filename>\fP \fI<reason>\fP
-The filename stored in the ALF header doesn\(aqt follow the rules for
-Atari DOS filenames. \fI<reason>\fP will be something like "doesn\(aqt start
-with A\-Z" or "invalid character". The filename will be printed with
-any unprintable characters as hex values (e.g. \fB$01\fP).
-.TP
-.B \fBheader #<n> (compressed|original) size is...\fP
-Followed by "impossibly large", "suspiciously large", or "too large
-to fit on a floppy disk". May indicate a corrupt archive, or someone
-really might have created an ALF file with files this big... though
-"impossibly large" means >=16MB. \fBunalf\fP can\(aqt extract a file
-that big.
-.TP
-.B \fBfilename has underscore, OK on Sparta/MyDOS, not Atari DOS 2.x\fP
-Not an actual problem, unless you try to extract this ALF file on
-an Atari running Atari DOS 2.0/2.5, or any other DOS that doesn\(aqt
-allow underscores in filenames.
-.TP
-.B \fBALF files don\(aqt normally contain other ALF files, are you trying to extract/list multiple ALF files at once?\fP
-You gave a \fIwildcard\fP argument that ends with \fI\&.alf\fP\&. This is OK if
-your \fIALF\fP file actually contains another \fIALF\fP file, but that would
-be a pathological case. Most likely, you\(aqre trying to extract multiple
-\fIALF\fP files with one command, which doesn\(aqt work. Use one \fBunalf\fP
-command per file.
-.UNINDENT
-.SH NOTES
-.sp
-This \fBunalf\fP is 100% compatible with the original Atari \fBDZ.COM\fP
-aka \fBUNALF.COM\fP, with the following differences:
-.INDENT 0.0
-.IP \(bu 2
-There is no interactive mode. The file to extract must be given as
-a command\-line argument, and the output directory must be given
-with the \fB\-d\fP option.
-.IP \(bu 2
-This \fBunalf\fP is capable of listing or testing the contents of an archive
-without extracting it, plus other handy features such as extracting
-to standard output and text file EOL conversion.
-.IP \(bu 2
-Turning the screen off for speed makes no sense on modern operating
-systems, so there\(aqs no option for that.
-.UNINDENT
-.sp
-Neither this \fBunalf\fP nor \fBDZ.COM\fP actually use the dates/times
-stored in the archive. Extracted files will have their timestamps set
-to the current date/time.
-.sp
-A note about the Atari filenames: \fBDZ.COM\fP is sometimes found on
-old disk images as \fBUNALF.COM\fP, and \fBLZ.COM\fP is sometimes called
-\fBALF.COM\fP or \fBALFER.COM\fP\&. I\(aqve used the original names partly
-out of respect for the original author, and partly to avoid confusion
-between my \fBunalf\fP and the Atari one.
-.SH BUGS
-.sp
-A minor one: \fBunalf\fP can\(aqt correctly extract files larger than about
-15MB. This could be a problem in \fBalf\fP (though the archives look
-OK to me), or it could be a bug I introduced when porting \fBunalf\fP,
-or it could be a bug in the original \fBDZ.COM\fP\&. Files this large are
-a pathological case for \fIALF\fP, anyway, since nobody ever used them on
-the Atari 8\-bit.
-.SH COPYRIGHT
-.sp
-The original AlfCrunch (\fBDZ.COM\fP and \fBLZ.COM\fP) for the Atari
-8\-bit was released into the Public Domain. Portions of the \fBDZ.COM\fP
-code are included in \fBunalf\fP, converted from 6502 instructions to
-C macros.
-.sp
-\fBunalf\fP is released under the WTPFL: Do WTF you want with this.
-.SH AUTHOR
-.sp
-The original AlfCrunch for the Atari 8\-bit was written by Alfred, who
-can be reached via the AtariAge.com forums with the username "Alfred".
-.sp
-This \fBunalf\fP was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
-.SH SEE ALSO
-.sp
-\fBalf\fP(1), \fBalfls\fP(1)
-.sp
-The git repository for \fBunalf\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/unalf\fP
-.UNINDENT
-.UNINDENT
-.sp
-Other Atari\-related projects by the author, including \fBbw\-atari8\-tools\fP
-and \fBunmac65\fP:
-.INDENT 0.0
-.INDENT 3.5
-\fI\%https://slackware.uk/~urchlay/repos/\fP
-.UNINDENT
-.UNINDENT
-.\" Generated by docutils manpage writer.
-.
diff --git a/src/unalf.c b/src/unalf.c
deleted file mode 100644
index 545a5c2..0000000
--- a/src/unalf.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "unalf.h"
-
-FILE *in_file, *out_file;
-char *in_filename;
-opts_t opts;
-const char *exclude_globs[MAX_EXCLUDES];
-int exclude_count;
-char * const *include_globs;
-static void create_outdir(void);
-
-/* like "mkdir -p" (no error if dir already exists),
- followed by "cd" (which will error if the existing
- "directory" turns out to be a file or broken symlink */
-static void create_outdir(void) {
- int r;
-
- r =
-#if defined(__MINGW32__) || defined(__MINGW64__)
- mkdir(opts.outdir);
-#else
- mkdir(opts.outdir, 0777);
-#endif
- if(r < 0 && errno != EEXIST) {
- fprintf(stderr, "%s: fatal: ", self);
- perror(opts.outdir);
- exit(1);
- }
-
- if(chdir(opts.outdir) < 0) {
- fprintf(stderr, "%s: fatal: ", self);
- perror(opts.outdir);
- exit(1);
- }
-}
-
-void usage(void) {
- extern char *usage_msg[];
- char **line;
-
- puts("unalf (ALF extractor) v" VERSION " by B. Watson. WTFPL.");
- printf("Usage: %s -[options] <file> [wildcard ...]\n", self);
- puts("Options:");
- puts(" wildcards: extract only matching files.");
-
- for(line = usage_msg; *line; line++)
- puts(*line);
-
- exit(0);
-}
-
-int main(int argc, char **argv) {
- set_self(argv[0]);
-
- if(argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) usage();
-
- if(!strcmp(argv[1], "--version")) {
- puts(VERSION);
- exit(0);
- }
-
- parse_opts(argc, argv);
-
- if(!(in_file = fopen(in_filename, "rb"))) {
- fprintf(stderr, "%s: fatal: ", self);
- perror(in_filename);
- exit(1);
- }
-
- if(opts.outdir) create_outdir();
-
- if(opts.listonly)
- list_alf();
- else
- extract_alf();
-
- fclose(in_file);
-
- exit(bad_checksum_count ? 2 : 0);
-}
diff --git a/src/unalf.h b/src/unalf.h
deleted file mode 100644
index 743282d..0000000
--- a/src/unalf.h
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <f65.h>
-#include "self.h"
-
-#ifndef VERSION
-#define VERSION "???"
-#warning "VERSION not defined, defaulting to \"???\""
-#endif
-
-#ifndef u8
-#define u8 unsigned char
-#define u16 unsigned short
-#endif
-
-/* asmcode.c (converted from asm) */
-void uncrunch_file(void);
-void setup_io_bufs(void);
-void L7A19(void);
-void L79E7(void);
-void L76D0(void);
-void write_output(void);
-void init_counters(void);
-void store_outbyte(void);
-void push_acc16(void);
-void L7899(void);
-void pop_acc16(void);
-void L78C2(void);
-void L7A19(void);
-void L79E7(void);
-void writeblock(void);
-void L7A5D(void);
-
-/* glob.c */
-int globmatch(const char *pat, const char *arg);
-int file_wanted(const char *filename);
-
-/* io.c - asm rewritten in C */
-int read_alf_header(void);
-void readblock(void);
-void writeblock(void);
-void write_output(void);
-
-/* io.c - just C */
-void open_output(void);
-
-/* listalf.c */
-void list_alf(void);
-unsigned int getquad(int offs);
-
-/* extract.c */
-extern int bad_checksum_count;
-extern int new_file;
-extern unsigned int bytes_written;
-void extract_alf(void);
-void dpoke(int addr, u16 value);
-u16 dpeek(int addr);
-void fix_filename(void);
-
-/* opts.c */
-void parse_opts(int argc, char * const *argv);
-
-/* unalf.c */
-extern char *self;
-extern FILE *out_file;
-extern FILE *in_file;
-extern char *in_filename;
-
-typedef struct {
- int txtconv;
- int testonly;
- int keepdot;
- int listonly;
- int lowercase;
- const char *outdir;
- int overwrite;
- int extract_to_stdout;
- int quiet;
- int verbose_list;
- int fixjunk;
-} opts_t;
-
-#define MAX_EXCLUDES 256
-
-extern opts_t opts;
-extern const char *exclude_globs[MAX_EXCLUDES];
-extern char * const *include_globs;
-extern int exclude_count;
diff --git a/src/unalf.rst b/src/unalf.rst
deleted file mode 100644
index e94fc21..0000000
--- a/src/unalf.rst
+++ /dev/null
@@ -1,358 +0,0 @@
-.. RST source for unalf(1) man page. Convert with:
-.. rst2man.py unalf.rst > unalf.1
-
-.. include:: ver.rst
-
-.. |date| date::
-
-=====
-unalf
-=====
-
---------------------------------
-extract Atari 8-bit ALF archives
---------------------------------
-
-:Manual section: 1
-:Manual group: Urchlay's Atari 8-bit Tools
-:Date: |date|
-:Version: |version|
-
-SYNOPSIS
-========
-
-unalf [**--help**] [**-aehtklLopqtv**] [**-d** *dir*] [**-x** *wildcard*] *alf-file* [*wildcard* ...]
-
-DESCRIPTION
-===========
-
-**unalf** lists, extracts, or tests the contents of an *ALF* archive.
-
-*ALF* is a compressed archive format similar to **arc**\(1), though
-not compatible with it. It was used on the Atari 8-bit platform
-beginning in the late 1980s. The Atari executables are **LZ.COM**
-for the compressor and **DZ.COM** for the decompressor. **unalf** is a
-port of **DZ.COM** for modern operating systems, with added features.
-
-Extracted files are written to the current directory by
-default. Existing files are backed up by default (by adding a **~**
-suffix to the filename).
-
-If one or more *wildcard* arguments are provided, files will only be
-listed or extracted if they match one of the wildcards. See **WILDCARDS**
-below for details.
-
-Only one *alf-file* argument is allowed. It's impossible to process
-multiple ALF files per run of **unalf**. If you need bulk extraction,
-use e.g. a **for** loop in a shell script.
-
-**unalf** can't read an ALF file on standard input; *alf-file* must be
-a real file.
-
-OPTIONS
-=======
-
--a
- Convert text file line endings and tabs from ATASCII to ASCII. Text
- files are detected by looking at the first 2 bytes of the extracted
- file. If both are printable ASCII (including ATASCII EOL, aka **$9B**), the
- file is considered text.
-
- Note that *only* line-endings and tabs are converted. Other ATASCII
- characters are left alone. If you need anything more in-depth, use
- **a8cat**\(1).
-
-.. convert EOLs and tabs in text files.
-
-**-aa**
- Convert line endings and tabs in *all* extracted files. This will
- corrupt any executables or non-text data files, so use with caution.
-
-.. convert EOLs and tabs in ALL files.
-
--d output-dir
- Write extracted files to this directory, which will be created if it
- does not exist. The default is the current directory.
-
-.. set output directory (created if needed).
-
--e
- Extract files. This is actually a no-op, as extraction is the
- default action.
-
-.. extract files (redundant; this is the default action).
-
--f
- Fix (remove) junk at EOF. This option truncates the *alf-file*.
- It is the only **unalf** option that writes to the input file. No
- backup is made.
-
-.. fix (remove) junk at EOF.
-
--h, --help
- Show built-in help message.
-
-.. show this help message.
-
--k
- Keep trailing periods. In most (all?) ALF files, filenames that have no
- extension are stored with a trailing period, e.g. '**FOO**' would
- be stored as '**FOO.**'. On the Atari, the extracted file would be
- named '**FOO**', so **unalf** does the same by default. With **-k**,
- the file will be named '**FOO.**'.
-
-.. keep trailing periods (dots) in filenames.
-
--l
- List filenames in archive, one per line, but do not extract. Use
- **-v** for more information (file size, etc). Obeys *wildcards* and
- the **-x**, **-L**, **-k** options.
-
-.. list files in archive (filenames only).
-
--L
- Lowercase filenames. Example: **FOO.TXT** will extract to **foo.txt**.
-
-.. use lowercase filenames.
-
--o
- Overwrite files, if they already exist. The default is to rename
- existing files, adding a **~** suffix. Note that renaming **file**
- to **file~** *will* overwrite **file~** if it already exists.
-
-.. overwrite files (do not create file~ backups).
-
--p
- Extract to standard output. All the files that get extracted will be
- printed to stdout with no delimiters, so this is most useful when
- only extracting one file. **-q** is automatically enabled by this option.
-
- *Warning:* No checking is done to see whether stdout is a terminal.
- Printing binary files to a terminal is a good way to make a mess.
- Even text files with the EOLs translated can still contain ATASCII
- formatting/graphics codes that can confuse your terminal. You have
- been warned.
-
-.. extract to stdout (enables -q).
-
--q
- Quiet extraction or testing: do not print "Uncrunching *file*"
- or "Testing *file*" messages. Errors and warnings will still be
- printed. This is the default when **-p** is used. This option
- doesn't do anything when used with **-l** or **-v**.
-
-.. quiet: don't print filenames during extraction/testing.
-
--t
- Test archive. Same as extraction, except the files are not written
- anywhere.
-
-.. test archive.
-
--v
- Verbose listing of archive contents, with compressed and original
- sizes, compression ration, date/time stamps, and checksum. The
- output format is similar to that of **arc -v**, minus the *Stowage*
- column, since *ALF* doesn't support multiple compression types. The
- date and time are displayed, but in most .alf files these are the
- default values of "8 Jan 82 12:24a".
-
- Unlike **-l**, the **-v** listing shows the filenames exactly as
- stored in the archive (ignores **-L**, enables **-k**), and always
- shows all the files (ignores *wildcards* and **-x**).
-
-.. verbose listing of archive contents.
-
--V, --version
- Show **unalf** version number and exit.
-
-.. show version number.
-
--x wildcard
- Exclude (do not list or extract) files matching *wildcard*. See
- **WILDCARDS** below. This option can be given multiple times
- to exclude multiple patterns.
-
-.. exclude <wildcard>. may be given multiple times.
-
-.. ENDOPTS
-
-WILDCARDS
-=========
-
-Wildcard (aka glob) matching works like it does on the Atari: *\*.\**
-matches any filename (whether or not it has an extension), and *\**
-or *\*.* only match filenames with no extension.
-
-A *\** matches any number of characters (including zero). A *?*
-matches a single character. All other characters match themselves, so
-a wildcard with no *\** or *?* must match exactly.
-
-Like the Atari, anything in the name or extension following a *\** is
-ignored: **FOO\*BAR.TXT** is equivalent to **FOO\*.TXT**, and
-**FOO.T\*T** is equivalent to **FOO.T\***. **FOO\*TXT** is
-equivalent to **FOO\***, and *will not* match the file **FOO.TXT**.
-
-Unlike the Atari, matching is case-insensitive.
-
-To avoid your shell trying to expand the wildcards, always quote them!
-Example::
-
- unalf filename.alf '*.txt'
-
-EXIT STATUS
-===========
-
-0
- Success.
-
-1
- Fatal error (I/O or bad command-line arguments, stack under/overrun).
-
-2
- Processing completed OK, but at least one file in the archive
- has a bad checksum.
-
-DIAGNOSTICS
-===========
-
-Besides the standard error messages such as "no such file or directory":
-
-Fatal errors
-------------
-
-**unalf** will exit with status 1 immediately after these errors:
-
-**fatal: this is an ARC file, not ALF**
- Self-explanatory. Use the **arc**\(1) utility for this file.
-
-**fatal: not an ALF file**
- Self-explanatory. Either the file is too small (less than 29 bytes)
- or its first two bytes don't match the *ALF* signature **0x1a** **0x0f**\.
-
-**fatal: stack underrun/overrun**
- Generally means the archive is corrupt. Valid ALF files should never
- cause these errors.
-
-**fatal: compressed data is truncated, EOF before end marker**
- Self-explanatory. The ALF file ends before the compressed data does.
-
-Warnings
---------
-
-**unalf** will continue after these messages occur.
-
-**junk at EOF (ignoring)**
- Mostly harmless: does *not* imply data corruption.
-
- Usually this is caused by the .alf file being stored on a CP/M disk
- at some time, or by a dumb file transfer protocol. Either way, the
- file gets padded to the block size of the filesystem or protocol.
- Usually, the padding characters are **0x1a**, aka ASCII control-Z.
-
- This message means you can't append to the ALF file with **alf -a**
- or **LZ.COM**. You can, however, use **unalf -f** to remove the junk.
-
-**checksum error on** *<file>*
- The archive is corrupt. If *<file>* is a text file, it may be
- partially readable. If it's an executable or other binary file, it's
- probably unrecoverable. **unalf** will try to extract the rest of
- the archive, but will exit with status 2 when it's done.
-
- If you have an ALF file that does this, try it with the Atari
- **DZ.COM** and see if it has the same problem. If it doesn't,
- you've found a bug in **unalf**, please send me the .alf file via
- email (see **AUTHOR**, below). Actually, I'd be interested to see
- the .alf file even if it doesn't work on the Atari either.
-
-*<file>* **should be** *<size>* **bytes, but extracted to** *<size>*
- The archive is corrupt. If this happens on the last (or only) file, it
- probably means the ALF file was truncated. You'll almost certainly
- get a checksum error for *<file>*, too.
-
-**bad Atari filename** *<filename>* *<reason>*
- The filename stored in the ALF header doesn't follow the rules for
- Atari DOS filenames. *<reason>* will be something like "doesn't start
- with A-Z" or "invalid character". The filename will be printed with
- any unprintable characters as hex values (e.g. **$01**).
-
-**header #<n> (compressed|original) size is...**
- Followed by "impossibly large", "suspiciously large", or "too large
- to fit on a floppy disk". May indicate a corrupt archive, or someone
- really might have created an ALF file with files this big... though
- "impossibly large" means >=16MB. **unalf** can't extract a file
- that big.
-
-**filename has underscore, OK on Sparta/MyDOS, not Atari DOS 2.x**
- Not an actual problem, unless you try to extract this ALF file on
- an Atari running Atari DOS 2.0/2.5, or any other DOS that doesn't
- allow underscores in filenames.
-
-**ALF files don't normally contain other ALF files, are you trying to extract/list multiple ALF files at once?**
- You gave a *wildcard* argument that ends with *.alf*. This is OK if
- your *ALF* file actually contains another *ALF* file, but that would
- be a pathological case. Most likely, you're trying to extract multiple
- *ALF* files with one command, which doesn't work. Use one **unalf**
- command per file.
-
-NOTES
-=====
-
-This **unalf** is 100% compatible with the original Atari **DZ.COM**
-aka **UNALF.COM**, with the following differences:
-
-- There is no interactive mode. The file to extract must be given as
- a command-line argument, and the output directory must be given
- with the **-d** option.
-
-- This **unalf** is capable of listing or testing the contents of an archive
- without extracting it, plus other handy features such as extracting
- to standard output and text file EOL conversion.
-
-- Turning the screen off for speed makes no sense on modern operating
- systems, so there's no option for that.
-
-Neither this **unalf** nor **DZ.COM** actually use the dates/times
-stored in the archive. Extracted files will have their timestamps set
-to the current date/time.
-
-A note about the Atari filenames: **DZ.COM** is sometimes found on
-old disk images as **UNALF.COM**, and **LZ.COM** is sometimes called
-**ALF.COM** or **ALFER.COM**. I've used the original names partly
-out of respect for the original author, and partly to avoid confusion
-between my **unalf** and the Atari one.
-
-BUGS
-====
-
-A minor one: **unalf** can't correctly extract files larger than about
-15MB. This could be a problem in **alf** (though the archives look
-OK to me), or it could be a bug I introduced when porting **unalf**,
-or it could be a bug in the original **DZ.COM**. Files this large are
-a pathological case for *ALF*, anyway, since nobody ever used them on
-the Atari 8-bit.
-
-COPYRIGHT
-=========
-
-The original AlfCrunch (**DZ.COM** and **LZ.COM**) for the Atari
-8-bit was released into the Public Domain. Portions of the **DZ.COM**
-code are included in **unalf**, converted from 6502 instructions to
-C macros.
-
-**unalf** is released under the WTPFL: Do WTF you want with this.
-
-AUTHOR
-======
-
-The original AlfCrunch for the Atari 8-bit was written by Alfred, who
-can be reached via the AtariAge.com forums with the username "Alfred".
-
-This **unalf** was written by B. Watson <urchlay@slackware.uk>.
-
-SEE ALSO
-========
-
-**alf**\(1), **alfls**\(1)
-
-.. include:: manftr.rst
diff --git a/src/usage.c b/src/usage.c
deleted file mode 100644
index 7615d2e..0000000
--- a/src/usage.c
+++ /dev/null
@@ -1,19 +0,0 @@
-const char *usage_msg[] = {
- " -a: convert EOLs and tabs in text files.",
- " -aa: convert EOLs and tabs in ALL files.",
- " -d: set output directory (created if needed).",
- " -e: extract files (redundant; this is the default action).",
- " -f: fix (remove) junk at EOF.",
- " -h: show this help message.",
- " -k: keep trailing periods (dots) in filenames.",
- " -l: list files in archive (filenames only).",
- " -L: use lowercase filenames.",
- " -o: overwrite files (do not create file~ backups).",
- " -p: extract to stdout (enables -q).",
- " -q: quiet: don't print filenames during extraction/testing.",
- " -t: test archive.",
- " -v: verbose listing of archive contents.",
- " -V: show version number.",
- " -x: exclude <wildcard>. may be given multiple times.",
- (const char*)0
-};
diff --git a/src/ver.rst b/src/ver.rst
deleted file mode 100644
index 2c33076..0000000
--- a/src/ver.rst
+++ /dev/null
@@ -1 +0,0 @@
-.. |version| replace:: 0.2.0