I've used Factor to build several common unix programs including copy, cat, fortune, wc, move, uniq, and others.
Today, I wanted to show how to build the tree
program. If we look at the man page, we can see that it is used to:
Tree
is a recursive directory listing program that produces a depth indented listing of files. With no arguments,tree
lists the files in the current directory. When directory arguments are given,tree
lists all the files and/or directories found in the given directories each in turn. Upon completion of listing all files/directories found,tree
returns the total number of files and/or directories listed.
We need to keep track of files and directories that are traversed:
SYMBOL: #files SYMBOL: #directories
Each file name is indented according to a specified depth:
: indent ( n -- ) [ [ "| " write ] times ] unless-zero "+-- " write ; : write-name ( indent entry -- ) [ indent ] [ name>> write ] bi* ;
File names are written and increment the #files
counter:
: write-file ( indent entry -- ) write-name #files [ 1 + ] change-global ;
Directory names are written, increase the indent, recurse writing their directory tree, and increment the #directories
counter:
DEFER: write-tree : write-dir ( indent entry -- ) [ write-name ] [ [ [ 1 + ] [ name>> ] bi* write-tree ] [ 3drop " [error opening dir]" write ] recover ] 2bi #directories [ 1 + ] change-global ;
Using write-file
and write-dir
, we can implement write-tree
to sort the entries and then write each according to their type (e.g., file or directory):
: write-tree ( indent path -- ) [ [ name>> ] sort-with [ nl [ dup ] bi@ type>> +directory+ = [ write-dir ] [ write-file ] if ] each drop ] with-directory-entries ;
Finally, we can implement the tree
command, initializing the file and directory count, recursing on the path specified, and then printing out the number of files and directories observed:
: tree ( path -- ) 0 #directories set-global 0 #files set-global [ write ] [ 0 swap write-tree ] bi nl #directories get-global #files get-global "\n%d directories, %d files\n" printf ;
Our command-line word will either operate on the arguments specifying a list of directories to process, or the current directory if none are provided:
: run-tree ( -- ) command-line get [ current-directory get tree ] [ [ tree ] each ] if-empty ; MAIN: run-tree
This is available on my GitHub.
No comments:
Post a Comment