From 64fd933ae883b7b7e8b41eb5d43aa3c6c9704a0d Mon Sep 17 00:00:00 2001 From: crc Date: Mon, 3 May 2021 12:23:18 +0000 Subject: [PATCH] examples: add archive, archive-info, archive-extract FossilOrigin-Name: 17e2edec1ba3dc6941f233adb84d4fd64d6c176b6c6e657984ac4c96014fba8c --- RELEASE-NOTES | 2 + example/archive-extract.retro | 53 ++++++++++++++++++++++++ example/archive-info.retro | 32 +++++++++++++++ example/archive.retro | 77 +++++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100755 example/archive-extract.retro create mode 100755 example/archive-info.retro create mode 100755 example/archive.retro diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 37688ad..772534d 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -22,5 +22,7 @@ ## Examples +- add archive, archive-info, archive-extract + ## Documentation diff --git a/example/archive-extract.retro b/example/archive-extract.retro new file mode 100755 index 0000000..b1429f1 --- /dev/null +++ b/example/archive-extract.retro @@ -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 +~~~ diff --git a/example/archive-info.retro b/example/archive-info.retro new file mode 100755 index 0000000..bb8e810 --- /dev/null +++ b/example/archive-info.retro @@ -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 +~~~ diff --git a/example/archive.retro b/example/archive.retro new file mode 100755 index 0000000..d948e80 --- /dev/null +++ b/example/archive.retro @@ -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 +~~~