examples: add archive, archive-info, archive-extract

FossilOrigin-Name: 17e2edec1ba3dc6941f233adb84d4fd64d6c176b6c6e657984ac4c96014fba8c
This commit is contained in:
crc 2021-05-03 12:23:18 +00:00
parent 1be0d4b85f
commit 64fd933ae8
4 changed files with 164 additions and 0 deletions

View file

@ -22,5 +22,7 @@
## Examples
- add archive, archive-info, archive-extract
## Documentation

53
example/archive-extract.retro Executable file
View file

@ -0,0 +1,53 @@
This is archive-extract, an un-archiver. Pass it a file created
by `archive.retro` to extract the files.
As a recap of the file format.
# of files
filename
length in bytes
... data ...
filename
length in bytes
... data ...
[ ... repeat for each file ... ]
I track the input (the archive) in `In` and the current file
being extracted in `Out`.
~~~
'In var
'Out var
~~~
The filename is passed in via the command line. Open it, save
the pointer.
~~~
#0 script:get-argument file:open-for-reading nip !In
~~~
I define a helper that will be used write data to the output
file.
~~~
:write @Out file:write ;
~~~
Define words to process the archive data.
~~~
:get-count @In file:read-line s:to-number ;
:filename @In file:read-line file:open-for-writing !Out ;
:size @In file:read-line s:to-number ;
:extract [ @In file:read write ] times ;
:skip-nl @In file:read-line drop ;
:close @Out file:close ;
~~~
Then use them to process the file.
~~~
get-count [ filename size extract close skip-nl ] times
@In file:close
~~~

32
example/archive-info.retro Executable file
View file

@ -0,0 +1,32 @@
This displays the contents (file names, sizes) of an archive.
I track the input (the archive) in `In`.
~~~
'In var
~~~
The filename is passed in via the command line. Open it, save
the pointer.
~~~
#0 script:get-argument file:open-for-reading nip !In
~~~
Define words to process the archive data.
~~~
:get-count @In file:read-line s:to-number dup n:put '_files s:put nl ;
:pad s:length #32 swap - #0 n:max [ sp ] times ;
:filename @In file:read-line dup s:put pad ;
:size @In file:read-line s:to-number dup n:put '_bytes s:put nl ;
:skip [ @In file:read drop ] times ;
:skip-nl @In file:read-line drop ;
~~~
Then use them to process the file.
~~~
get-count [ filename size skip skip-nl ] times
@In file:close
~~~

77
example/archive.retro Executable file
View file

@ -0,0 +1,77 @@
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
~~~