1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
.\" 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-18" "0.1.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 or extracts 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.
.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 \fBwildcard\fP arguments are provided, files will only be
listed or extracted if they match one of the wildcards. See \fBWILDCARDS\fP
below for details.
.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 \-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.
.
.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.
.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":
.INDENT 0.0
.TP
.B \fBthis is an ARC file, not ALF\fP
Self\-explanatory. Use the \fBarc\fP(1) utility for this file.
.TP
.B \fBnot 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 \fBjunk at EOF (ignored)\fP
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
If you see this message, you can ignore it. It\(aqs intended to let
you know that this .alf file can\(aqt be appended to by the \fBALF.COM\fP
aka \fBLZ.COM\fP Atari utility.
.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.
.TP
.B \fBstack underrun/overrun\fP
Generally means the archive is corrupt. Valid ALF files should never
cause these errors.
.sp
If you have an ALF file that does this, try it with the Atari
\fBUNALF14.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 \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.
.UNINDENT
.SH NOTES
.sp
This \fBunalf\fP is 100% compatible with the original Atari \fBUNALF14.COM\fP
aka \fBDZ.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 \fBUNALF14.COM\fP actually use the dates/times
stored in the archive. Extracted files will have their timestamps set
to the current date/time.
.SH COPYRIGHT
.sp
\fBunalf\fP is released under the WTPFL: Do WTF you want with this.
.SH AUTHOR
.INDENT 0.0
.IP B. 3
Watson <\fI\%urchlay@slackware.uk\fP>
.UNINDENT
.SH SEE ALSO
.sp
\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.
.
|