# FNortPth.Icn (Full Norton Path) - Will Mengarini - 10 Aug 92
# Filter Norton FA | FS output so each line is 1 full file path
# The Norton Utilities v4.00 contain programs FA & FS, for displaying
# File Attributes & File Sizes. There was some reason why under DOS 3.30
# I needed to prefer those over Dir to get bare whole-path listings.
# This was the code I wrote to do that. It's interesting as a demonstration
# of a structured approach to Icon string scanning, even if the particular
# application is no longer useful.
# Sample FA output excerpts preceded by column-ruler line:
#
# 123456789012345678901234567890
# D:\-\I
# deldupln.icn
# fnortpth.icn Archive
# gug Archive
#
# 33 files shown
# no files changed
#
# D:\-\I\^
# deldupln.asv
# deldupln.icn Archive
# reverse.icn
# scrap.b Archive
# _.rst Archive
#
# 9 files shown
# no files changed
#
# Total of all files
# 42 files shown
# no files changed
# Sample FS output excerpts preceded by column-ruler line:
#
# 123456789012345678901234567890
# D:\-\I
# whug 1,344 bytes
# fnortpth.icn 215 bytes
#
# 30,272 total bytes in 33 files
# 77,824 bytes disk space occupied, 61% slack
#
# D:\-\I\^
# deldupln.asv 1,122 bytes
# deldupln.icn 1,058 bytes
#
# 12,399 total bytes in 9 files
# 24,576 bytes disk space occupied, 50% slack
#
# Total of all files found
# 42,671 total bytes in 42 files
# 102,400 bytes disk space occupied, 58% slack
#
# Drive usage
# 33,435,648 bytes available on drive D:
# 12,103,680 bytes unused on drive D:, 36% unused
procedure main()
while read() ?(
# All & only lines containing "\\" are directories. They begin (after
# leading whitespace) with the drive letter, & end with "\\" only if
# they specify the root. There are no other words on such lines.
tab(many(' ')),
dir := tab(upto('\\')) || tab(0) || (move(-1) ~== "\\" | "")
)|(
# Lines containing file names begin with leading whitespace. Then
# come the name & extension as a single word with a separating ".";
# there's no whitespace between the name & extension, unlike the
# columnar format of FI & Dir. If the extension is empty, the "." is
# omitted. In FS, all file names are on lines ending with "bytes"; no
# other lines end with "bytes". In FA, file names are followed by a
# list of attributes like "Archive"; no other lines contain the words
# denoting those attributes; the list may be empty, in which case the
# line has only 1 word; no other lines have only 1 word except
# directory lines. Therefore, file names are all & only the initial
# words on lines that either have no other words & are not directory
# lines, | end with "bytes" | a word denoting an attribute.
((
(
tab(many(' ')), tab(many(~' \\')), pos(0)
# We already know this isn't a directory line since control
# can't get this far unless the alternative that handles
# directory lines fails. However, the code is more robust if
# it doesn't depend on that, & inserting an extra char in a
# cset entails no extra run-time computation.
)|(
reverse(&subject) ? match(reverse(
"bytes" | "hive" | "d-Only" | "dden" | "stem"
))
)
) & &pos:=1 & (
tab(many(' ')), write( dir || tab(upto(' ')|0) )
))
)|1
end
# All of FNortPth.Icn's main() fits in a single 43x80 screen, & only 18
# lines are code; the rest is documentation. That's not bad.
# This was the first Icon program I wrote using string scanning, & I came out
# of it with designs for scanning structures that do anything AWK can do just
# as easily, & of course much more since in Icon it's all an integrated
# expressional syntax instead of a collection of special features. This
# while read() ?(
# action 1
# )|(
# action 2
# )|(
# action 3
# )|1
# performs for each line of standard input the first action that succeeds.
# Replacing the final
# )|1
# with
# )
# processes standard input only down to the first line for which no action
# succeeds. This
# while read() ?((
# action 1
# )|1,&pos:=1,(
# action 2
# )|1,&pos:=1,(
# action 3
# )|1)
# is exactly equivalent to AWK's protocol of applying to every line of
# standard input every "pattern/action statement" in the program, so
# mismatches don't prevent later patterns from matching the same line.
# Patterns & actions can be interleaved in Icon, but in one case in
# FNortPth this was too complex, so I coded
# ((
# (
# condition 1
# )|(
# condition 2
# )
# ) & &pos:=1 & (
# action
# ))
# using conjunction instead of mutual evaluation to clarify that in this
# case it was my intention to fail the expression & therefore not perform
# the action unless one of the conditions succeeded.
# I seem to be particularly enamoured of languages
# that let me avoid assigning variables; switching from
# while line := read() do line ?(
# [...]
# )
# to
# while read() ?(
# [...]
# )|1
# was very satisfying. I think this is because I recognize this as an
# approach that helps me get away from the procedural diddledydoodling that I
# find so frustrating with Algol-family languages; while I'm trying to design
# algorithms & analyze systems, I keep getting distracted by the need to dip
# down to what should be an isolated lower level of abstraction.