retroforth/example/archive.retro
crc 64fd933ae8 examples: add archive, archive-info, archive-extract
FossilOrigin-Name: 17e2edec1ba3dc6941f233adb84d4fd64d6c176b6c6e657984ac4c96014fba8c
2021-05-03 12:23:18 +00:00

77 lines
1.7 KiB
Forth
Executable file

This generates an archive of files. It's currently only tested
with plain text, so use caution if archiving binary files.
The file format is currently very simple. An archive starts
with a line containing the number of entries. This is followed
by a file name, then the file size in bytes. Then data for the
file, a newline, and then any other files.
It's not robust, it's not scalable, and it's definitely not a
thing that most people should use. But it's simple, and works
well enough for my small tasks.
#Entries
filename
length
...
filename
length
...
The output file handle is stored in the `Out` variable.
~~~
'Out var
~~~
I define `file:put` to write to the `Out` file. This will be
mapped in place of `c:put` later.
~~~
:file:put @Out file:write ;
~~~
Each entry has a file name, size, and data. These words write
the relevant information to the archive.
~~~
:name dup s:put nl ;
:size n:put nl ;
:copy [ [ file:read c:put ] sip ] times nl ;
:data file:open-for-reading swap [ size ] [ copy ] bi file:close ;
:archive name data ;
~~~
The top level part gets the filename for the archive and stores
the file pointer in `Out`.
~~~
#0 script:get-argument file:open-for-writing !Out
~~~
Then I replace `c:put` with `file:put` so I can just use the
standard output words to write to the archive.
~~~
&file:put &c:put set-hook
~~~
The first line in the archive is the number of files in the
archive.
~~~
script:arguments n:dec n:put nl
~~~
Then loop over the files, copying them in
~~~
script:arguments n:dec
[ I n:inc script:get-argument archive ] indexed-times
~~~
And cleanup by reverting `c:put` and closing the archive file.
~~~
&c:put unhook
@Out file:close
~~~