RxComp
RxComp ("ReXx COMPare") compares two files to determine if they contain the same program, irrespective of casing, continuations, line numbers, comments, etc. For example,
If a = b Then Say "Hello"
and
if - /* A continuation and
a multiline comment */
A=B
THEN
SAY, -- Another continuation
"Hello"
will compare equal.
RxComp returns 0 when two files compare equal, and 1 when help is displayed or files do not compare equal. Programs containing errors cannot be compared, as errors terminate the parsing process.
Usage
[rexx] rxcomp [options] file1 file2
Options
-it,
--itrace |
Print internal traceback on error |
-e,
--experimental |
Enable Experimental features (also -exp) |
-xtr,
--executor |
Enable Executor support |
-h, --help |
Display this information |
-u,
--unicode |
Enable TUTOR support |
--tutor |
Enable TUTOR support |
Program source
/******************************************************************************/
/* */
/* rxcomp.rex - Compare two rexx files element-wise */
/* ================================================ */
/* */
/* This program is part of the Rexx Parser package */
/* [See https://rexx.epbcn.com/rexx-parser/] */
/* */
/* Copyright (c) 2026-2026 Josep Maria Blasco <josep.maria.blasco@epbcn.com> */
/* */
/* License: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0) */
/* */
/* Version history: */
/* */
/* Date Version Details */
/* -------- ------- --------------------------------------------------------- */
/* 20260117 0.4a First release */
/* */
/******************************************************************************/
Signal On Syntax
package = .context~package
myName = package~name
Parse Caseless Value FileSpec( "Name", myName ) With myName".rex"
myHelp = ChangeStr( -
"myName", -
"https://rexx.epbcn.com/rexx-parser/doc/utilities/myName/", -
myName)
Parse Source . how .
If how == "COMMAND", .SysCArgs \== .Nil
Then args = .SysCArgs
Else args = ArgArray(Arg(1))
If args~items == 0 Then Signal Help
unicode = 0
experimental = 0
executor = 0
itrace = 0
ProcessOptions:
If args~items == 0 Then Signal Help
option = args[1]
args~delete(1)
If option[1] == "-" Then Do
Select Case Lower(option)
When "-h", "--help" Then Signal Help
When "-u", "--tutor", -
"--unicode" Then unicode = 1
When "-e", "-exp", "--exp", -
"--experimental" Then experimental = 1
When "-xtr", "--executor" Then executor = 1
When "-it", "--itrace" Then itrace = 1
Otherwise Call Error "Invalid option '"option"'."
End
Signal ProcessOptions
End
sfile1 = option -- Remember file1 as written
file1 = .context~package~findProgram(option)
If file1 == .Nil Then Call Error "File '"option"' does not exist."
If args~items == 0 Then Call Error "Missing filename after '"option"'."
option = args[1]
args~delete(1)
sfile2 = option -- Remember file2 as written
file2 = .context~package~findProgram(option)
If file2 == .Nil Then Call Error "File '"option"' does not exist."
If args~items > 0 Then Call Error "Invalid parameter '"args[1]"'."
Options = .Array~new
If Unicode Then Options~append(("UNICODE", 1))
If experimental Then Options~append(("EXPERIMENTAL", 1))
If executor Then Options~append(("EXECUTOR", 1))
source = CharIn(file1,1,Chars(file1))~makeArray
Call CharOut file1
fullpath = file1
parser1 = .Rexx.Parser~new(file1, source, Options)
element1 = parser1~firstElement
source = CharIn(file2,1,Chars(file2))~makeArray
Call CharOut file2
fullpath = file2
parser2 = .Rexx.Parser~new(file2, source, Options)
element2 = parser2~firstElement
Loop While element1 \< .EL.END_OF_SOURCE, element2 \< .EL.END_OF_SOURCE
Call Next
from1 = element1~from
from2 = element2~from
to1 = element1~to
to2 = element2~to
cat1 = element1~category
cat2 = element2~category
src1 = element1~source
src2 = element2~source
If cat1 \== cat2 Then Call CategoriesDiffer
If element1 < .ALL.SYMBOLS_AND_KEYWORDS Then Call CaselessCompare
Else If element1 < .EL.TAKEN_CONSTANT, Pos(src1[1], "'""") == 0 Then Call CaselessCompare
Else Call Compare
End
If element1 \< .EL.END_OF_SOURCE Then Do
Say file2 "exhausted but" file1 "continues at ["from1"-"to1"]: '"src1"'."
Exit 1
End
If element2 \< .EL.END_OF_SOURCE Then Do
Say file1 "exhausted but" file2 "continues at ["from2"-"to2"]: '"src2"'."
Exit 1
End
Exit
CategoriesDiffer:
Say sfile1 "@" from1"-"to1 "is '"src1"' (a" .Parser.CategoryName[cat1]"), but" .EndOfLine || -
sfile2 "@" from2"-"to2 "is '"src2"' (a" .Parser.CategoryName[cat2]")."
Exit 1
CaselessCompare:
val1 = element1~value
val2 = element2~value
If val1 == val2 Then Return
Say "Elements '"val1"' ["from1"-"to1"] and '"val2"' ["from2"-"to2"] differ."
Exit 1
Compare:
If src1 == src2 Then Return
Say "Elements '"src1"' ["from1"-"to1"] (a" .Parser.CategoryName[cat1]") and '"src2"' ["from2"-"to2"] (a" .Parser.CategoryName[cat2]") differ."
Exit 1
Next:
Call Next1
Call Next2
Return
Next1:
element1 = element1~next
If element1 < .EL.END_OF_SOURCE Then Return
If element1~ignorable Then Signal Next1
If element1~from == element1~to Then Signal Next1
Return
Next2:
element2 = element2~next
If element2 < .EL.END_OF_SOURCE Then Return
If element2~ignorable Then Signal Next2
If element2~from == element2~to Then Signal Next2
Return
--------------------------------------------------------------------------------
Error:
.Error~Say(Arg(1))
Exit 1
--------------------------------------------------------------------------------
Help:
Say .Resources[Help]~makeString -
~caselessChangeStr("myName", myName) -
~caselessChangeStr("myHelp", myHelp)
Exit 1
--------------------------------------------------------------------------------
-- Standard Rexx Parser error handler --
--------------------------------------------------------------------------------
Syntax:
co = condition("O")
If co~code \== 98.900 Then Do
.Error~Say( "Error" co~code "in" co~program", line" co~position":" )
Raise Propagate
End
additional = Condition("A")
section = additional~section(2)
extra = Additional~lastItem
line = extra~position
code = extra~code
Parse Var code major"."minor
.Error~Say( Right(line,6) "*-*" source[line] )
.Error~Say( "Error" major "in" fullpath", line" line": " ErrorText(major) )
.Error~Say( "Error" code": " Ansi.ErrorText( code, section ) )
If itrace Then Do
.Error~Say
.Error~Say( "Trace follows:" )
.Error~Say( Copies("-",80) )
.Error~Say( co~stackFrames~makeArray )
End
Exit -major
--------------------------------------------------------------------------------
::Requires "Rexx.Parser.cls"
::Requires "ANSI.ErrorText.cls"
::Requires "BaseClassesAndRoutines.cls"
::Requires "modules/print/print.cls"
--------------------------------------------------------------------------------
::Resource Help end "::End"
myname - Compare two Rexx files element-wise
Usage: myName [options] FILE1 FILE2
Options:
-xtr,--executor Enable support for Executor
-e, --experimental Enable Experimental features (also -exp)
--help Display this information
-it, --itrace Print internal traceback on error
--tutor Enable TUTOR-flavored Unicode
-u, --unicode Enable TUTOR-flavored Unicode
The 'myname' program is part of the Rexx Parser package,
see https://rexx.epbcn.com/rexx-parser/. It is distributed under
the Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0).
Copyright (c) 2024-2026 Josep Maria Blasco <josep.maria.blasco@epbcn.com>.
See myhelp for details.
::End
