Lyster wrote:
>I'm still not comfortable with the conditions
>evaluated in the When statements. I think that the conditions need
>more-descriptive names than they currently have.
>[After reviewing the code whilst constructing v0.9, I'm especially unclear
>on the usage of the stem variable ?Key in the When statements.]
Ok, the When statements have a general comment right before them as to
what the code does. Specifically, maybe a better description of what I'm
doing with the compound symbol concept would help.
?Key = 'filekey' <-code default pattern for identifying an .iq's filekey
or to clairify, the map key, contentkey/iqkey
(see above)
?Key.1 = 'word:' <-.iq filekey definable (i.e. ':') - default is 'word:'
This is the "wordkey" to test for.
?Key.2 = 'sub:' <-.iq filekey definable (i.e. '::')- default is 'sub:'
This is the "subkey" to test for.
?Key.3 = 'file:' <-.iq filekey definable ("" ':::') - "" is 'file:'
This is the "filekey" to test for. To clairify, the
linkkey (see above)
?Key.4 = 1 <- switch for identifying current line potential for
being output. It's set to '1' by a positive test
result from matching 'word' or 'sub'. If 'word' or
'sub' doesn't match then set to '0'
?Key.1.!Result <- holds result of line test for wordkey existance
?Key.2.!Result <- holds result of line test for subkey existance
?Key.3.!Result <- holds result of line test for file/linkkey existance
?Key.4.!Level <- holds depth value. 0 for outside word. 1 for inside
word. 2 for inside of sub.
So as you can see, these symbols are all related to each other in what
they are used for. We could make nine independant simple symbols, but
since they are related, a compound symbol fits. Besides if we made simple
symbols then we have to figure out a way to increment what is now 1 to 3.
True '4' could be a non-number but I'm being consistant "enough" to tie it
to the compound symbol (human wise). Hmmm, maybe '?Key' should be '?Key.'
(making it a stem symbol proper) but I'm not sure how the use of this and
initialization would effect the compound symbol. Probably wouldn't hurt
since we do initialize each anyway.
----
------------------------------>8----------------------------
/* $VER: IQ 0.9 (12.11.98)
** IQ command SYNTAX: IQ.rexx TO FROM WORD SUBS...
** Copyright 1998 Timothy Rue - VIC IQ command: version 0.31-arexx
**
** V0.3 Edited 9809.02-9809.03 by Lyster E. Wick Jr.
** Changes Copyright (C) 1998 by Lyster E. Wick Jr.
**
** to make script more readable, and to remove a couple VERY MINOR bugs.
** Larger changes defered until next edit session.
**
** V0.4 Edited 9809.10 by Lyster E. Wick Jr.
** Changes Copyright (C) 1998 by Lyster E. Wick Jr.
**
** Reworked the options parsing routine --heck, replaced it with 99% new
** code! New version uses Abbrev() to allow variable-length abbreviations
** of the command-line switches, instead of the all-or-nothing approach
** used before, and to allow MULTIPLE switches to be specified when needed.
**
** A new switch was added, -WARNINGS, as a synonym for -S, whose presumed
** full-length alias was somewhat less than mnemonic.
**
** Added a version string.
**
** Changed the main loop to use Abbrev() to check for the EXISTANCE of
** special lines, which always have their ID bytes at the beginning of the
** line. rexxtricks.library's RxTr_MatchPattern() is still used to match
** the pattern itself, once the line is identified.
**
** Uses rexxtricks.library (available on Aminet) for ADOS style pattern
** matching
**
** V0.5 Edited 9809.17 by Lyster E. Wick Jr.
** Changes Copyright (C) 1998 by Lyster E. Wick Jr.
**
** Fixed a bug introduced by me whereby the script would loop at the first
** non-filekey line of the data file.
**
** V0.6 Edited 9809.23 by Lyster E. Wick Jr.
** Changes Copyright (C) 1998 by Lyster E. Wick Jr.
**
** Fixed a bug introduced by me whereby the line-counter wasn't getting
** incremented when a new line was read.
**
** V0.7 Created by Timothy Rue from his v0.31 with features from my v0.4 added.
**
** V0.8 Created 9811.12 from v0.6 with new features from v0.7 folded in.
** Changes Copyright (C) 1998 by Lyster E. Wick Jr.
**
** V0.9 Edited 9811.26 [Happy Thanksgiving Day!] by Lyster E. Wick Jr.
**
** Simplified some logical tests by removing redundant explicit tests of
** boolian variables. As comparison expressions generate only 0 and 1
** values, there is no point in explicitly comparing a variable to 0 or 1
** when these are the only values that the variable in question CAN have.
**
** Fixed a bug --I forgot to copy one occurance of the new variable
** FlipFlop into v0.8
*/
/*
** Variables and their uses
**
** ?CP Character Position within file
** ?FlipFlop Unknown
** ?From Name of file being processed
** ?FromT Name of file to process NEXT, before we know that we want to
** ?I Loop counter
** ?InLine Text of current line
** ?IQSC IQ "stack" count
** ?IQ_Stack. Stack of files currently being processed
** ?IQ_StackT Temporary storage of entry from stack of current files
** ?IQ_StackU. List of files already processed
** ?IQSU IQ used-list count
** ?J Temporary loop variable, one larger than the loop's control variable
** ?Key String constant containing the Magic Cookie that identifies non-standard IQ files
** ?Key. Keywords for file parsing
** ?Key_Count. ? Unclear. "Key array base and counter" doesn't amplify enough, Timothy.
** ?LineNumbers Switch to enable debugging output
** ?LineTest ? Result of matching the current line against the wildcards [only compared to zero]
** ?LN Number of current line
** ?Ports List of system ports, used when -P switch is used
** ?Position Position of an entry in a list or stack
** ?Subn Number of words in second-level pattern
** ?SubPattern Individual word within second-level pattern, only used in one place
** ?Subs Second-level pattern
** ?T Loop counter
** ?TN "Tell Number"? Used several places to count something
** ?To_Port Name of port to send output to
** ?Word First-level pattern
*/
/*
** Constants and their uses
**
** !IQFile I/O handle for current file
** !Level Stem variable qualifier
** !Result Stem variable qualifier
*/
/*
** Exit codes
**
** 0 OK, nothing wrong
** 10 Fatal error, resource not available
*/
/*
** Variables added:
**
** 9809.10 ?ArgLine Used to hold the command-line arguments for processing
** 9809.10 ?Switch Used to hold the command-line switch
** 9811.26 ?ShowKeys Internal form of -K switch, formerly ?Tell
**
** Variables removed:
**
** 9809.10 ?Key Uppercase copy of ?To_Port, tested against the -K switch
** 9809.10 ?Subl Catch second-level pattern when -S switch is used
** 9811.26 ?Tell Internal form of -K switch, changed to ?ShowKeys
**
** Variables renamed:
**
** Old New
** 9809.10 ?TellNot ?Warnings Internal form of -S switch
** Enable/disable warnings;
** Default: Enabled
** 9811.12 ?SN ?T Loop counter, only used in one place,
** 9811.12 ?Test ?T Loop counter, only used in two places
** [both within the debugging output block]
** [?SN and ?Test both changed to ?T
** to match Timothy's latest version]
** 9811.26 ?Tell ?ShowKeys Internal form of -K switch
*/
/*
** set ?LineNumbers to 1 to show line numbers & IQ stacks.
** set to 0 otherwise
*/
?LineNumbers = 0
/*
** Set parameter defaults.
*/
?Warnings = 1
?ShowKeys = 0
/*
** check for and AddLib rexxtricks.library
*/
If ~Show('L', "rexxtricks.library")
Then If ~AddLib("rexxtricks.library", 0, -30, 0)
Then Do
Echo 'rexxtricks.library not available, exiting'
Exit 10
End
/*
** Parse command line options.
*/
?ArgLine=Arg(1)
If Abbrev('HELP', ?ArgLine) | ?ArgLine='?' | ?ArgLine='-?' Then Signal Help
Do Forever
?Switch=Upper(Word(?ArgLine, 1))
Select
When Abbrev('-HELP', ?Switch, 2) Then Signal Help
When Abbrev('-PORTS', ?Switch, 2)
Then Do
/*
** show available ports
*/
Echo 'Ports Available:'
Echo '----------------'
?Ports = Show('P')
Do ?I = 1 To Words(?Ports)
Echo Word(?Ports, ?I)
End ?I
Echo
Exit 0
End /* When Ports */
When '-S' == ?Switch Then ?Warnings = 0 /* Suppress
warnings */ When Abbrev('-WARNINGS', ?Switch, 2) Then ?Warnings = 0 /*
Suppress warnings */ When Abbrev('-KEYS', ?Switch, 2) Then ?ShowKeys =
1 Otherwise Leave /* Forever */
End /* Select */
?ArgLine = DelWord(?ArgLine, 1, 1)
End /* Forever */
/*
** parse command line arguements
*/
Parse Var ?ArgLine ?To_Port ?From ?Word ?Subs
/*
** Check to see if specified putput port exists
*/
If ~Show('p', ?To_Port)
Then Do
If ~?Warnings
Then Echo "WARNING: Cannot find port «"?To_Port"» - Defaulting to
STDOUT"
End
Else Shell Value ?To_Port
If ?ShowKeys
Then Echo 'Listing Unique KEYS (first time found - filekeys and w/word and
sub pattern matching):'
/*
** Set default file keywords
*/
?Key = 'filekey' /* Should be something like "!IQ:" or "!VIC.IQ:" */
?Key.1 = 'word:'
?Key.2 = 'sub:'
?Key.3 = 'file:'
?Key.4 = 1
?IQSU = 0
?IQSC = 0
?TN = 1
/*
** test for valid file arguement
*/
If ~Open(!IQFile, ?From, 'R')
Then Do
Echo 'ERROR: IQ file «'?From'» not found!'
Exit 10
End
/*
** File opened OK; check for signature and read first data line
*/
?InLine = ReadLn(!IQFile)
?LN = 1
?Key_Count.0 = Strip(?InLine)
If Abbrev(?InLine, ?Key)
Then Do
Do ?I = 1 To 3
?Key.?I = Word(?InLine, ?I+1)
End ?I
/*
** We have a filekey; read next line
*/
?InLine = ReadLn(!IQFile)
?LN = 2
End /* If */
?Subn=Words(?Subs) /* Count "sub" words */
/* DO IT */
Do Forever
?FlipFlop = 0 /* What's this for? */
/*
** Test line for key.
*/
Do ?I = 1 To 3
?Key.?I.!Result = Abbrev(?InLine, ?Key.?I)
End ?I
?LineTest = ?Key.1.!Result + ?Key.2.!Result + ?Key.3.!Result
Select
/*
** Skip unselected data lines.
*/
When ?LineTest == 0 & ?Key.4 == 0 Then Nop
/*
** Output selected data lines.
*/
When ?LineTest == 0 & ?Key.4 == 1 & ~?ShowKeys
Then If Address() == ?To_Port
Then ''?InLine
Else Echo ?InLine
/*
** When file.
*/
When ?Key.3.!Result & ?Key.4 == 1
Then Do
?FromT = Strip(?InLine, 'L', ?Key.3)
If ?From == ?FromT /* Is file self-recursive? */
Then Break /* from Select */
/* set/reset IQ_stacks position and break variable */
?Position = 0
If ?IQSU > 0 /* Do we have any previous files to check for? */
Then Do ?I = 1 To ?IQSU
If ?IQ_StackU.?I == ?FromT /* Is the new file already on the list?
*/
Then ?Position = ?I
End ?I
If ?Position > 0
Then Break /* from Select */
If ~Exists(?FromT) /* Does the file exist? */
Then Do
If ~?Warnings
Then Echo 'WARNING: File «'?From'» Line' ?LN': File «'?FromT'» not
found.'
?Position = -1
End
If ?Position == -1
Then Break /* from Select */
/*
** check if in current stack - if so save current settings,
** read in previous settings, sort stack, seek to cp
*/
If ?IQSU > 0 /* Do we have any previous files to check for? */
Then Do ?I = 1 To ?IQSC /* Look for it. */
If Word(?IQ_Stack.?I, 1) == ?FromT /* Is this it? */
Then ?Position = ?I /* Remember it! */
End ?I
If ?Position > 0 /* Did we find it? */
Then Do
?CP = Seek(!IQFile, 0)
?IQ_StackT = ?From ?Key.1 ?Key.2 ?Key.3 ?Key.4 ?Key.4.!Level ?LN ?CP
Parse Var ?IQ_Stack.?Position ?From ?Key.1 ?Key.2 ?Key.3 ?Key.4
?Key.4.!Level ?LN ?CP
/*
** Ripple stack downward one place to remove file from list.
*/
Do ?I = ?Position To ?IQSC
?J = ?I + 1
?IQ_Stack.?I = ?IQ_Stack.?J
End ?I
?IQ_Stack.?IQSC = ?IQ_StackT
Call Close(!IQFile)
Call Open(!IQFile, ?From, 'R')
Call Seek(!IQFile, ?CP, 'BEGIN')
?Position = -1
End /* If */
If ?Position == -1
Then Break /* from Select */
/*
** if not in either stack - save current settings and
** read in key of new file if exist
*/
If ?Position == 0
Then Do
?CP = Seek(!IQFile, 0)
?IQSC = ?IQSC + 1
?IQ_Stack.?IQSC = ?From ?Key.1 ?Key.2 ?Key.3 ?Key.4 ?Key.4.!Level
?LN ?CP
?From = ?FromT
Call Close(!IQFile)
If ?ShowKeys & ?Key.4 == 1
Then Do
/*
** Check and build array of words, subs and files
*/
?InLine = Strip(?InLine)
Do ?T = 0 To ?Tn -1
If Compare(?Key_Count.?T, ?InLine) ~= 0
Then Iterate ?T
Else Leave ?T
End ?T
If ?T = ?TN
Then Do
?Key_Count.?T = ?InLine
?TN = ?TN + 1
End
End /* If */
Call Open(!IQFile, ?From, 'R')
/*
** File opened OK; check for signature and read first data line
*/
?InLine = ReadLn(!IQFile)
?LN = 1
?Key.4.!Level = 0
If Abbrev(?InLine, ?Key)
Then Do
Do ?I = 1 To 3
?Key.?I = Word(?InLine, ?I+1)
End ?I
/*
** We have a filekey; read next line
*/
?InLine = ReadLn(!IQFile)
?LN = 2
End /* If */
Else ?FlipFlop = 1 /* Why? */
End /* If */
End /* When File */
/* When sub from sub or word level*/
When ?Key.2.!Result & ?Key.4.!Level > 0
Then Do
?Key.4 = 0
?Key.4.!Level = 1
/* Test arg sub match (within matching word) */
Do ?T = 1 To ?Subn
?SubPattern = ?Key.2 || Word(?Subs, ?T)
If RxTr_MatchPattern(?InLine, ?SubPattern)
Then Do
?Key.4.!Level = 2
?Key.4 = 1
Break /* Select */
End
End ?T
/* if w/blank sub */
If ?InLine == ?Key.2 & ?Key.4.!Level == 1
Then ?Key.4 = 1
End /* When */
/* When word */
When ?Key.1.!Result
Then Do
?Key.4 = 0
?Key.4.!Level = 0
/* If arg word match */
If RxTr_MatchPattern(?InLine, ?Key.1 || ?Word)
Then Do
?Key.4.!Level = 1
?Key.4 = 1
End
/* If exiting word w/blank word */
If ?InLine == ?Key.1
Then ?Key.4 = 1
End
When ?ShowKeys Then Nop /* What's this doing? */
/* ??? can this ever happen ??? */
Otherwise Echo 'INTERNAL ERROR: File «'?From'» Line' ?LN': How did this
happen?'
End /* Select */
/*
**** begin multi-file test/IQ_stacks output.
**** Set '?LineNumbers' ~= 0, to use
*/
If ?LineNumbers
Then Do
If ?IQSC > 0
Then Do
?Result = Word(?IQ_Stack.1, 1)'@Line#'Word(?IQ_Stack.1, 7)
Do ?T = 2 To ?IQSC
?Result = ?Result Word(?IQ_Stack.?T, 1)'@Line#'Word(?IQ_Stack.?T, 7)
End ?T
Echo 'IQ Stack>'?Result ?From'@Line#'?LN /* This is the PK file's IQ
stack. */
End /* If */
Else Echo 'IQ Stack>'?From'@Line#'?LN /* This is the PK file's IQ
stack*/
If ?IQSU > 0
Then Do
?Result = ?IQ_StackU.1
Do ?T = 2 To ?IQSU
?Result = ?Result ?IQ_StackU.?T
End ?T
Echo 'IQ completely scanned file list> '?Result
End /* If ?IQSU */
End /* If ?LineNumbers */
/*
**** end of multi-file test output
*/
/*
** Make list of unique Keys if -k option selected.
*/
If ?LineTest ~= 0 & ?ShowKeys & ?Key.4 = 1 & ~?FlipFlop
Then Do
/* Check and build array of words, subs and files */
?InLine = Strip(?InLine)
Do ?T = 0 To ?TN -1
If Compare(?Key_Count.?T, ?InLine) ~= 0
Then Iterate ?T
Else Leave ?T
End ?T
If ?T = ?TN
Then Do
?Key_Count.?T = ?InLine
?TN = ?TN + 1
End /* If */
End /* If */
/* handle EOF and IQ stacks*/
If Eof(!IQFile)
Then If ?IQSC > 0
Then Do
Call Close(!IQFile)
?IQSU = ?IQSU + 1
?IQ_StackU.?IQSU = ?From
Parse Var ?IQ_Stack.?IQSC ?From ?Key.1 ?Key.2 ?Key.3 ?Key.4
?Key.4.!Level ?LN ?CP
?IQSC = ?IQSC -1
Call Open(!IQFile, ?From, 'R')
Call Seek(!IQFile, ?CP, 'BEGIN')
End /* If */
Else Break /* from do forever */
?InLine = ReadLn(!IQFile)
?LN = ?LN + 1
End /* Do Forever */
/*
** List unique keys if option -k selected
*/
If ?ShowKeys
Then Do ?T = 0 To ?TN
Echo ?Key_Count.?T
End ?T
Exit 0
/*
** help options
*/
Help:
Echo "FOR HELP:"
Echo "rx IQ.rexx -OR- rx IQ.rexx [ ? | -? | -h | help ]"
Echo
Echo "COMMAND LINE:"
Echo "rx IQ.rexx [word|pattern] {sub|pattern}"
Echo
Echo "OPTIONAL REDIRECTION COMMAND LINE (may be used with any '-' option):"
Echo "rx IQ.rexx [>dev:path/filename | pipe:name] [word|pattern] {sub|pattern}"
Echo
Echo "TO SILENCE WARNINGS:"
Echo "rx IQ.rexx < -s | -S > [word|pattern] {sub|pattern}"
Echo Echo "FOR UNIQUE KEYS LIST (filekeys and w/word and sub pattern matching):"
Echo "rx IQ.rexx < -k | -K | -Keys | -KEYS > [word|pattern] {sub|pattern}"
Echo
Echo "FOR AVAILABLE PORTS LIST:"
Echo "rx IQ.rexx [ -p | -P | -Ports | -PORTS ]"
Echo
Exit 0
----------------------------8<-----------------------------------