[net.sources] Software Tools in Pascal 5/8

jp@lanl.ARPA (10/06/85)

{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Grep -- Globally look for Regular Expressions and Print }
program Grep;
%include swtools
%include patdef
%include matchdef
var
    arg, lin, pat: StringType;
    returnCode: Integer;
begin
    ToolInit;
    returnCode := 4;
    if (not GetArg(1, arg, MAXSTR)) then
        Error('Usage: Grep pattern');
    if (not GetPat(arg, pat)) then
        Error('Grep: illegal pattern');
    while (GetLine(lin, STDIN, MAXSTR)) do
        if (Match(lin, pat)) then begin
            returnCode := 0;
            PutStr(lin, STDOUT)
        end;
    ProgExit(returnCode)
end.
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Hash -- compute hash function of a name }
segment Hash;
%include swtools
%include defdef
%include defref
%include defproc
function Hash;
var
    i, h: Integer;
begin
    h := 0;
    for i := 1 to StrLength(name) do
        h := (3 * h + Ord(name[i])) mod HASHSIZE;
    Hash := h + 1
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ HashFind -- find name in hash table }
segment HashFind;
%include swtools
%include defdef
%include defref
%include defproc
function HashFind;
var
    p: NDPtr;
    tempName: StringType;
    found: Boolean;
begin
    found := false;
    p := hashTab[Hash(name)];
    while (not found) and (p <> nil) do begin
        CSCopy(NDTable, p->.name, tempName);
        if (Equal(name, tempName)) then
            found := true
        else
            p := p->.nextPtr
    end;
    HashFind := p
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Includ -- replace include file by contents }
Program Includ;
%include swtools
var incl: StringType;
{ FInclude -- include file desc f }
procedure FInclude(f: FileDesc);
var
    line,strg: StringType;
    loc, i:   Integer;
    f1: FileDesc;
begin
    while(GetLine(line,f,MAXSTR)) do begin
        loc := GetWord(line,1,strg);
        if (not Equal(strg,incl)) then
            PutStr(line,STDOUT)
        else begin
            if GetFid(line, loc, strg) then begin
                f1 := MustOpen(strg,IOREAD);
                FInclude(f1);
                FClose(f1);
            end
            else
                Error('Bad file name');
        end
    end
end;
begin
    ToolInit;
    CvtSST('#include', incl);
    FInclude(STDIN)
end.
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ InitHash -- initialize hash table to nil }
segment InitHash;
%include swtools
%include defdef
%include defref
%include defproc
procedure InitHash;
var
    i: 1..HASHSIZE;
begin
    nextTab := 1;   { first free slot in table }
    for i := 1 to HASHSIZE do
        hashTab[i] := nil
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ InitMacro -- initialize variables for macro }
segment InitMacro;
%include swtools
%include macdefs
%include macproc
procedure InitMacro;
begin
    null[1] := ENDSTR;
    CvtSST('define', defName);
    CvtSST('substr', subName);
    CvtSST('expr', exprName);
    CvtSST('ifelse', ifName);
    CvtSST('len', lenName);
    CvtSST('changeq', chqName);
    bp := 0;  { push back buffer pointer }
    traceing := false;
    if NArgs > 0 then traceing := true;
    InitHash;
    lQuote := GRAVE;
    rQuote := ACUTE;
end {InitMacro};
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Install -- add name, definition and type to table }
segment Install;
%include swtools
%include defdef
%include defref
%include defproc
procedure Install;
var
    h, dlen, nlen: Integer;
    p: NDPtr;
begin
    nlen := StrLength(name) + 1;   { 1 for ENDSTR }
    dlen := StrLength(defn) + 1;
    if (nextTab + nlen + dlen > MAXCHARS) then begin
        PutStr(name, STDERR);
        Error(': too many definitions')
    end
    else begin
        h := Hash(name);
        new(p);
        p->.nextPtr := hashTab[h];
        hashTab[h] := p;
        p->.name := nextTab;
        SCCopy(name, ndTable, nextTab);
        nextTab := nextTab + nlen;
        p->.defn := nextTab;
        SCCopy(defn, ndTable, nextTab);
        nextTab := nextTab + dlen;
        p->.kind := t
    end
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ IsAlphaNum -- true if c is letter or digit }
segment IsAlphaNum;
%include swtools
function IsAlphaNum;
begin
    IsAlphaNum := ((c >= LETA) and (c <= LETI)) or
                  ((c >= LETJ) and (c <= LETR)) or
                  ((c >= LETS) and (c <= LETZ)) or
                  ((c >= BIGA) and (c <= BIGI)) or
                  ((c >= BIGJ) and (c <= BIGR)) or
                  ((c >= BIGS) and (c <= BIGZ)) or
                  ((c >= DIG0) and (c <= DIG9))
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ IsDigit -- true if c is a digit }
segment IsDigit;
%include swtools
function IsDigit;
begin
    IsDigit := c in [DIG0..DIG9];
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ IsLetter -- true if c is a letter of either case }
segment IsLetter;
%include swtools
%include chardef
function IsLetter;
begin
    IsLetter := ChLetter in CharClass(c)
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ IToC -- convert integer n to char string in s[i] ... }
segment IToC;
%include swtools
function IToC;
begin
    if (n < 0) then begin
        s[i] := MINUS;
        IToC := IToC(-n, s, i+1);
    end
    else begin
        if (n >= 10) then
            i := IToC(n div 10, s, i);
        s[i] := Chr(n mod 10 + Ord(DIG0));
        s[i+1] := ENDSTR;
        IToC := i + 1;
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Kopy -- move line1 thru line2 after line3 }
segment Kopy;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
function Kopy;
var
    i: Integer;
    curSave, lastSave: Integer;
    tempLine: StringType;
begin
    if (line1 <= 0) or ((line3 >= line1) and (line3 < line2)) then
        Kopy := ERR
    else begin
        curSave := curLn;
        lastSave := lastLn;
        curLn := lastLn;
        for i := line1 to line2 do begin
            GetTxt(i, tempLine);
            if PutTxt(tempLine) = ERR then begin
                curLn := curSave;
                lastLn := lastSave;
                Kopy := ERR;
                return
           end
       end; {if}
        BlkMove(lastSave+1, lastSave+1+line2-line1, line3);
       if (line3 > line1) then
           curLn := line3
       else
           curLn := line3 + (line2 - line1 + 1);
       Kopy := OK
    end
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Kwic -- make Keyword in Context index }
program Kwic;
%include swtools
%include cms
const
    FOLD = DOLLAR;
var
    buf: StringType;
    tempFile1: FileDesc;
    tempFile2: FileDesc;
    fileName: StringType;
    RCode: Integer;
{ Rotate -- output rotated lines }
procedure Rotate (var buf: StringType; n: Integer);
var
    i: Integer;
begin
    i := n;
    while (buf[i] <> NEWLINE) and (buf[i] <> ENDSTR) do begin
        PutCF(buf[i], tempFile1);
        i := i + 1
    end;
    PutCF(FOLD, tempFile1);
    for i := 1 to n - 1 do
        PutCF(buf[i], tempFile1);
    PutCF(NEWLINE, tempFile1)
end;
{ PutRot -- create lines with keyword at front }
procedure PutRot(var buf: StringType);
var
    i: Integer;
begin
    i := 1;
    while (buf[i] <> NEWLINE) and (buf[i] <> ENDSTR) do begin
        if (IsAlphaNum(buf[i])) then begin
            Rotate(buf, i); { token starts at "i" }
            repeat
                i := i + 1
            until (not IsAlphaNum(buf[i]))
        end;
        i := i + 1
    end
end;
/* temporarily commented out until CMS cmd works
{ UnRotate -- Unrotate lines rotated by first half of KWIC }
procedure UnRotate;
const
    MAXOUT = 80;
    MIDDLE = 40;
var
    inBuf, outBuf: StringType;
    i, j, f: Integer;
begin
    while (GetLine(inBuf, tempFile2, MAXSTR)) do begin
        for i := 1 to MAXOUT -1 do
             outBuf[i] := BLANK;
        f := StrIndex(inBuf, FOLD);
        j := MIDDLE - 1;
        for i := StrLength(inBuf)-1 downto f+1 do begin
             outBuf[j] := inBuf[i];
             j := j - 1;
             if (j <= 0) then
                 j := MAXOUT - 1
        end;
        j := MIDDLE + 3;
        for i := 1 to f-1 do begin
             outBuf[j] := inBuf[i];
             j := j mod (MAXOUT - 1) + 1
        end;
        for j := 1 to MAXOUT - 1 do
             if (outBuf[j] <> BLANK) then
                 i := j;
        outBuf[i+1] := ENDSTR;
        PutStr(outBuf, STDOUT);
        PutC(NEWLINE)
    end
end;
*/
{ Main program for Kwic }
begin
    ToolInit;
/* Cannot get CMS to call sort properly
    CvtSST('KWIC1 TEMP A', fileName);
    tempFile1 := FOpen(fileName, IOWRITE);
    if tempFile1 = IOERROR then
        Error('Cannot open first KWIC temporary');
*/
/* */
    tempFile1 := STDOUT;
/* */
    while (GetLine(buf, STDIN, MAXSTR)) do
        PutRot(buf);
/*
    Cms('EXEC OSSORT KWIC1 TEMP A KWIC2 TEMP A 1 10', RCode);
    if RCode <> 0 then
         Error('KWIC: BNRSORT failed');
    CvtSST('KWIC2 TEMP A', fileName);
    tempFile2 := FOpen(fileName, IOREAD);
    if tempFile2 = IOERROR then
         Error('KWIC: cannot open sorted rotated file');
    UnRotate
*/
end.
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ LnDelete -- delete lines n1 thru n2 }
segment LnDelete;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
function LnDelete;
begin
    if (n1 <= 0) then
        status := ERR
    else begin
        BlkMove(n1, n2, lastLn);
        lastLn := lastLn - (n2 - n1 + 1);
        curLn := PrevLn(n1);
        status := OK
    end;
    LnDelete := status
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Locate -- look for c in character class at pat[offset] }
segment Locate;
%include swtools
%include matchdef
function Locate;
var
    i: Integer;
begin
    { size of class is at pat[offset], characters follow }
    Locate := false;
    i := offset + Ord(pat[offset]);   { last position }
    while (i > offset) do
        if (c = pat[i]) then begin
            locate := true;
            i := offset { force loop termination }
        end
        else
            i := i - 1
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Lookup -- locate name, get defn and type from table }
segment Lookup;
%include swtools
%include defdef
%include defref
%include defproc
function Lookup;
var
    p: ndPtr;
begin
    p := HashFind(name);
    if (p = nil) then
        Lookup := false
    else begin
        Lookup := true;
        CSCopy(NDTable, p->.defn, defn);
        t := p->.kind
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Macro -- expand macros with arguments }
program Macro;
%include swtools
%include macdefs
%include macproc
begin
    ToolInit;
    InitMacro;
    Install(defName, null, DEFTYPE);
    Install(exprName, null, EXPRTYPE);
    Install(subName, null, SUBTYPE);
    Install(ifName, null, IFTYPE);
    Install(lenName, null, LENTYPE);
    Install(chqName, null, CHQTYPE);

    cp := 0;
    ap := 1;
    ep := 1;
    while (GetTok(token, MAXTOK) <> ENDFILE) do
        if (IsLetter(token[1])) then begin
            if (not Lookup(token, defn, tokType)) then
                PutTok(token)
            else begin
                cp := cp + 1;
                if (cp > CALLSIZE) then
                    Error('Macro: call stack overflow');
                callStk[cp] := ap;
                typeStk[cp] := tokType;
                ap := Push(ep, argStk, ap);
                PutTok(defn);      { push definition }
                PutChr(ENDSTR);
                ap := Push(ep, argStk, ap);
                PutTok(token);    { stack name }
                PutChr(ENDSTR);
                ap := Push(ep, argStk, ap);
                t := GetTok(token, MAXTOK); { peek at next }
                PBStr(token);
                if (t <> LPAREN) then begin { add () }
                    PutBack(RPAREN);
                    PutBack(LPAREN);
                end;
                pLev[cp] := 0
            end
        end
        else if (token[1] = lQuote) then begin { strip quotes }
            nlPar := 1;
            repeat
                t := GetTok(token, MAXTOK);
                if (t = rQuote) then
                    nlPar := nlPar - 1
                else if (t = lQuote) then
                    nlPar := nlPar + 1
                else if (t = ENDFILE) then
                    Error('Macro: missing right quote');
                if nlPar > 0 then
                    PutTok(token)
            until (nlPar = 0)
        end
        else if (cp = 0) then { not in macro at all }
            PutTok(token)
        else if (token[1] = LPAREN) then begin
            if (pLev[cp] > 0) then
                PutTok(token);
            pLev[cp] := pLev[cp] + 1
        end {then}
        else if (token[1] = RPAREN) then begin
            pLev[cp] := pLev[cp] - 1;
            if (pLev[cp] > 0) then
                PutTok(token)
            else begin { end of argument list }
                PutChr(ENDSTR);
                Eval(argStk, typeStk[cp], callStk[cp], ap - 1);
                ap := callStk[cp];  { pop eval stack }
                ep := argStk[ap];
                cp := cp - 1
            end
        end
        else if (token[1] = COMMA) and (pLev[cp] = 1) then begin
            PutChr(ENDSTR);   { new argument }
            ap := Push(ep, argStk, ap)
        end {then}
        else
            PutTok(token);   { just stack it }
    if (cp <> 0) then
        Error('Macro: unexpected end of input')
end.
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ MakePat -- make pattern from arg[i], terminate at delim }
segment MakePat;
%include swtools
%include patdef
%include metadef
function MakePat;
var
    i,j, lastJ, lj: Integer;
    k: Integer;
    done, junk: Boolean;
begin
    j := 1;  { pat index}
    i := start;  { arg index}
    metaStackPointer := 0;
    metaIndex := 1;
    done := false;
    k := start;
    while (arg[k] <> delim) and ((k + 2) <= MAXSTR) do
        if (arg[k] = NEWLINE) or (arg[k] = ENDSTR) then begin
            arg[k] := delim;
            arg[k+1] := NEWLINE;
            arg[k+2] := ENDSTR;
        end
        else
            k := k + 1;

    while (not done) and (arg[i] <> delim) and
          (arg[i] <> ENDSTR) do begin
        lj := j;
        if (arg[i] = ANY) then
            junk := AddStr(ANY, pat, j, MAXPAT)
        else if (arg[i] = BOL) and (i = start) then
            junk := AddStr(BOL, pat, j, MAXPAT)
        else if (arg[i] = BOM) then begin
             junk := AddStr(BOM, pat, j, MAXPAT);
             metaStackPointer := metaStackPointer + 1;
             metaIndex := metaIndex + 1;
             if (metaStackPointer > 9) or
               (metaIndex > 9) then
                 done := true
        end
        else if (arg[i] = EOM) and (metaStackPointer > 0) then begin
            junk := AddStr(EOM, pat, j, MAXPAT);
            metaStackPointer := metaStackPointer - 1;
            if (metaStackPointer < 0) then
                done := true
        end
        else if (arg[i] = EOL) and (arg[i+1] = delim) then
            junk := AddStr(EOL, pat, j, MAXPAT)
        else if (arg[i] = CCL) then
            done := (GetCCL(arg, i, pat, j) = false)
        else if (arg[i] = CLOSURE) and (i > start) then begin
            lj := lastJ;
            if (pat[lj] in [BOL, EOL, CLOSURE]) then
                done := true             { force loop termination }
            else
                STClose(pat, j, lastJ)
        end
        else begin
            junk := AddStr(LITCHAR, pat, j, MAXPAT);
            junk := AddStr(Esc(arg,i), pat, j, MAXPAT)
        end;
        lastJ := lj;
        if (not done) then
            i := i + 1;
    end;
    if (done) or (arg[i] <> delim) or (metaStackPointer <> 0) then
        MakePat := 0
    else if (not AddStr(ENDSTR, pat, j, MAXPAT)) then
        MakePat := 0                { no room}
    else
        MakePat := i;
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ MakeSet -- make set from inset(k) in outset }
segment MakeSet;
%include swtools
%include patdef
function MakeSet;
var
    j: Integer;
begin
    j := 1;
    DoDash(ENDSTR, inSet, k, outSet, j, maxSet);
    makeSet := AddStr(ENDSTR, outSet, j, maxSet)
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ MakeSub -- make substitution string from arg into sub }
segment MakeSub;
%include swtools
%include patdef
%include subdef
%include metadef
value
    nullMetaTable := MetaTableType(
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0),
        MetaElementType(0,0));
function MakeSub;
var
    k: Integer;
    i, j: Integer;
    l: Integer;
    junk: Boolean;
begin
    j := 1;
    i := from;
    k := from;
    while (arg[k] <> delim) and (k <= (MAXSTR - 2)) do
        if (arg[k] = NEWLINE) or (arg[k] = ENDSTR) then begin
            arg[k] := delim;
            arg[k+1] := NEWLINE;
            arg[k+2] := ENDSTR;
        end
        else
            k := k + 1;
    while (arg[i] <> delim) and (arg[i] <> ENDSTR) do begin
        if (arg[i] = AMPER) then begin
            junk := AddStr(DITTO, sub, j, MAXPAT);
            { &n handler for meta brackets }
            if (arg[i+1] in [DIG0..DIG9]) then begin
                i := i + 1;
                junk := AddStr(Chr(Ord(arg[i]) - Ord(DIG0)),
                    sub, j, MAXPAT)
            end
        end
        else
            junk := AddStr(Esc(arg,i), sub, j, MAXPAT);
        i := i + 1
    end;
    if (arg[i] <> delim) then   { missing delim }
        MakeSub := 0
    else if (not AddStr(ENDSTR, sub, j, MAXPAT)) then
        MakeSub := 0
    else
        MakeSub := i
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Match -- find match anywhere on line + support fcns }
segment Match;
%include swtools
%include patdef
%include matchdef
function Match;
var
    i, pos: Integer;
begin
    pos := 0;
    i := 1;
    while (lin[i] <> ENDSTR) and (pos = 0) do begin
        pos := AMatch(lin, i, pat, 1);
        i := i + 1;
    end;
    Match := (pos > 0)
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Message -- print a PASCALVS string on STDERR }
segment Message;
%include swtools
procedure Message;
var
    i: 1..MAXSTR;
begin
    for i := 1 to Length(s) do
         PutCF(s[i], STDERR);
    PutCF(NEWLINE,STDERR);
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Move -- move line1 thru line2 after line3 }
segment Move;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
function Move;
begin
    if (line1 <= 0) or ((line3 >= line1) and (line3 < line2)) then
        Move := ERR
    else begin
        BlkMove(line1, line2, line3);
       if (line3 > line1) then
           curLn := line3
       else
           curLn := line3 + (line2 - line1 + 1);
       Move := OK
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ MPutStr -- put meta'd string out on file }
segment MPutStr;
%include swtools
%include ioref
procedure MPutStr;
var
    i: Integer;
    j: integer;
    len: Integer;
    outString: StringType;
begin
    i := 1;
    j := 1;
    len := StrLength(str);
    while i <= len do begin
        if str[i] = DOLLAR then begin
            i := i + 1;
            if (str[i] = BIGN) or (str[i] = LETN) then begin
                if j = 1 then WriteLn(openList[fd].fileVar,' ')
                         else WriteLn(openList[fd].fileVar,
                              outString:j-1);
                j := 1
            end
            else if (str[i] = BIGE) or (str[i] = LETE) then
                return
            else
                i := i - 1
        end else
        if str[i] = NEWLINE then begin
            if j = 1 then WriteLn(openList[fd].fileVar,' ')
                     else WriteLn(openList[fd].fileVar, outString:j-1);
            j := 1;
        end {then}
        else begin
            outString[j] := str[i];
            j := j + 1;
        end; {if}
        i := i + 1
    end; {while}
    if j <> 1 then write(openList[fd].fileVar, outString:j-1);
end; {MPutStr}
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ MustOpen -- same as FOpen except for no allowance of failure }
segment MustOpen;
{ mustopen -- open file or die }
%include swtools
function MustOpen;
var
    fd: FileDesc;
begin
    fd := FOpen(fname, fMode);
    if (fd = IOERROR) then begin
        PutStr(fname, STDERR);
        Error(': can''t open file')
    end;
    MustOpen := fd
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Nargs (CMS) -- return number of arguments }
segment Nargs;
%include swtools
%include ioref
function NArgs;
begin
    NArgs := cmdArgs
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ NextLn/PrevLn -- get next/previous line number }
segment NextLn;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
function NextLn;
begin
    if (n >= lastLn) then
        nextLn := 0
    else
        nextLn := n + 1
end;
function PrevLn;
begin
    if (n <= 0) then
        PrevLn := lastLn
    else
        PrevLn := n - 1
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ OMatch -- match one pattern element at pat[j] }
segment OMatch;
%include swtools
%include matchdef
%include patdef
%include metadef
function OMatch;
var
    advance: -1..1;
    mIndex: Integer;
begin
    advance := -1;
    if (lin[i] = ENDSTR) then
        OMatch := false
    else
        case pat[j] of
            LITCHAR:
                if (lin[i] = pat[j+1]) then
                    advance := 1;
            BOM:
                if (metaStackPointer <= 9) and
                  (metaIndex <= 9) then begin
                    metaStack[metaStackPointer] := metaIndex;
                    metaTable[metaIndex].first := i;
                    metaIndex := metaIndex + 1;
                    metaStackPointer := metaStackPointer + 1;
                    advance := 0
                end
                else
                    Error('OMatch/meta: can''t happen');
            EOM:
                if (metaStackPointer >= 1) then begin
                    metaStackPointer := metaStackPointer - 1;
                    mIndex := metaStack[metaStackPointer];
                    metaTable[mIndex].last := i;
                    advance := 0
                end
                else
                    Error('OMatch/meta/EOM can''t happen');
            BOL:
                if (i = 1) then
                    advance := 0;
            ANY:
                if (lin[i] <> NEWLINE) then
                    advance := 1;
            EOL:
                if (lin[i] = NEWLINE) then
                    advance := 0;
            CCL:
                if (Locate(lin[i], pat, j+1)) then
                    advance := 1;
            NCCL:
                if (lin[i] <> NEWLINE) and
                  (not Locate(lin[i], pat, j+1)) then
                    advance := 1
            otherwise
                Error('in omatch: can''t happen')
        end;
    if (advance >= 0) then begin
        i := i + advance;
        OMatch := true
    end
    else
        OMatch := false
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ OnError -- intercept pascalvs run-time errors }
segment OnError;
def ERRORIO: Boolean;
def ATTENTION: Boolean;
def OUTOFSPACE: Boolean;
value
    ERRORIO := false;
    ATTENTION := false;
    OUTOFSPACE := false;
%include onerror
procedure OnError;
var
    statementNumber: String(10);
    procName: String(10);
    errorNo: String(10);
begin
    if (FERROR in [41..53,75..78]) then begin
        ERRORIO := true;
        FACTION := [];
    end
    else if FERROR = 30 then begin
        ATTENTION := true;
        FACTION := [];
    end
    else if (FERROR = 64) and (not OUTOFSPACE) then begin
        OUTOFSPACE := true;
        FACTION := []
    end
    else if FERROR = 36 then begin
        FACTION := [XUMSG,XTRACE,XHALT];
        WriteStr(statementNumber, FSTMTNO:5);
        WriteStr(procName, FPROCNAME:8);
        WriteStr(errorNo, FERROR:5);
        FRETMSG := 'SWTOOLS ASSERT FAILURE: RID=' || PROCNAME||
                   '; S#=' || statementNumber ||
                   '; EID' || errorNo || ';';
    end
    else begin
        FACTION := [XUMSG,XTRACE];
        WriteStr(statementNumber, FSTMTNO:5);
        WriteStr(procName, FPROCNAME:8);
        WriteStr(errorNo, FERROR: 5);
        FRETMSG := '***SWTOOLS error: RID=' || procName
                   || '; S#=' || statementNumber ||
                   '; EID=' || errorNo || ';';
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ OptPat -- get optional pattern from lin[i], increment i }
segment OptPat;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
%include patdef
function OptPat;
begin
    if (lin[i] = ENDSTR) then
        i := 0
    else if (lin[i + 1] = ENDSTR) then
        i := 0
    else if (lin[I + 1] = lin[i]) then { leave existing pattern alone }
        i := i + 1
    else
        i := MakePat(lin, i+1, lin[i], pat);
    if (pat[1] = ENDSTR) then
        i := 0;
    if (i = 0) then begin
        pat[1] := ENDSTR;
        OptPat := ERR
    end
    else
        OptPat := OK
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PatScan -- find next occurance of pattern after line n }
segment PatScan;
%include swtools
%include editcons
%include edittype
%include editproc
%include editref
%include matchdef
function PatScan;
var
    done: Boolean;
    line: StringType;
begin
    n := curLn;
    PatScan := ERR;
    done := false;
    repeat
        if (way = SCAN) then
            n := NextLn(n)
        else
            n := PrevLn(n);
        GetTxt(n, line);
        if (Match(line, pat)) then begin
            PatScan := OK;
            done := true
        end
    until (n = curLn) or (done)
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PatSize -- returns size of pattern entry at pat[n] }
segment PatSize;
%include swtools
%include patdef
%include matchdef
%include metadef
function PatSize;
begin
    case pat[n] of
        LITCHAR:
            PatSize := 2;
        BOL, EOL, ANY, BOM, EOM:
            PatSize := 1;
        CCL, NCCL:
            PatSize := Ord(pat[n+1]) + 2;
        CLOSURE:
            PatSize := CLOSIZE
        otherwise
            Error('in PatSize: Can''t happen');
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PBNum -- Convert number to string, push back on input }
segment PBNum;
%include swtools
%include macdefs
%include macproc
procedure PBNum;
var
    temp: StringType;
    junk: Integer;
begin
    junk := IToC(n, temp, 1);
    PBStr(temp)
end {PBNum};
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PBStr -- push string back onto input }
segment PBStr;
%include swtools
%include defdef
%include defproc
procedure PBStr;
var
    i: Integer;
begin
    for i := StrLength(s) downto 1 do
        PutBack(s[i])
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ ProgExit -- Returns a return code and quits }
segment ProgExit;
%include swtools
procedure ProgExit;
begin
    RetCode(returnCode);
    HALT
end; {ProgExit}
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Push -- push ep onto argStk, return new position ap }
segment Push;
%include swtools
%include macdefs
%include macproc
function Push;
begin
    if (ap > ARGSIZE) then
        Error('Macro: argument stack overflow');
    argStk[ap] := ep;
    Push := ap + 1
end {Push};
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutBack -- push character back onto input }
segment PutBack;
%include swtools
%include defdef
%include defref
%include defproc
procedure PutBack;
begin
    if (bp >= BUFSIZE) then
        Error('Too many characters pushed back');
    bp := bp + 1;
    buf[bp] := c
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutC -- print character to STDOUT }
segment PutC;
%include swtools
procedure PutC;
begin
    PutCF(c, STDOUT)
end;
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutCF -- put string out on file }
segment PutCF;
%include swtools
%include ioref
procedure PutCF;
begin
    if openList[fd].mode = IOAVAIL then
        Error('putcf on unopen file');
    if c = NEWLINE then
        writeln(openList[fd].fileVar)
    else
        write(openList[fd].fileVar, c)
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutChr -- put single char on output or eval stack }
segment PutChr;
%include swtools
%include macdefs
%include macproc
procedure PutChr;
begin
    if (cp <= 0) then
        PutC(c)
    else begin
        if (ep > EVALSIZE) then
            Error('Macro: evaluation stack overflow');
        evalStk[ep] := c;
        ep := ep + 1
    end {if}
end {PutChr};
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutDec -- put decimal integer n in field width >= w }
segment PutDec;
%include swtools
procedure PutDec;
var
    i, nd: Integer;
    s: StringType;
begin
    nd := itoc(n, s, 1);
    for i := nd to w do
        PutC(BLANK);
    for i := 1 to nd-1 do
        PutC(s[i])
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutStr -- put string out on file }
segment PutStr;
%include swtools
%include ioref
procedure PutStr;
var
    i: Integer;
    j: integer;
    len: Integer;
    outString: StringType;
begin
    i := 1;
    j := 1;
    len := StrLength(str);
    while i <= len do begin
        if str[i] = NEWLINE then begin
            if j = 1 then WriteLn(openList[fd].fileVar)
                     else WriteLn(openList[fd].fileVar, outString:j-1);
            j := 1;
        end {then}
        else begin
            outString[j] := str[i];
            j := j + 1;
        end; {if}
        i := i + 1
    end; {while}
    if j <> 1 then write(openList[fd].fileVar, outString:j-1);
end; {PutStr}
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutSub -- output substitution text }
segment PutSub;
%include swtools
%include subdef
procedure PutSub;
var
    i, j: Integer;
    junk: Boolean;
begin
    i := 1;
    while (sub[i] <> ENDSTR) do begin
        if (sub[i] = DITTO) then
            for j := s1 to s2-1 do
                PutC(lin[j])
        else
            PutC(sub[i]);
        i := i + 1
    end
end;
{
	Copyright (c) 1981
	By:	Bell Telephone Laboratories, Inc. and
		Whitesmiths, Ltd.,

	This software is derived from the book
		"Software Tools In Pascal", by
		Brian W. Kernighan and P.J. Plauger
		Addison-Wesley, 1981
		ISBN 0-201-10342-7

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ PutTok -- put token on output or evaluation stack }
segment PutTok;
%include swtools
%include macdefs
%include macproc
procedure PutTok;
var
    i: Integer;
begin
    i := 1;
    while s[i] <> ENDSTR do begin
        PutChr(s[i]);
        i := i + 1
    end {while};
end {PutTok};
{
	Copyright (c) 1982
	By:	Chris Lewis

	Right is hereby granted to freely distribute or duplicate this
	software, providing distribution or duplication is not for profit
	or other commerical gain and that this copyright notice remains 
	intact.
}
{ Remove -- remove a file - very tricky }
segment Remove;
%include swtools
%include cms
procedure Remove;
var
    cmsString: String(MAXSTR);
    returnCode: Integer;
    i: 1..MAXSTR;
begin
    cmsString := 'ERASE ';
    for i := 1 TO StrLength(name) do
        if name[i] in [NEWLINE, PERIOD] then
            cmsString := cmsString || Str(' ')
        else
            cmsString := cmsString || Str(name[i]);
    Cms(cmsString, returnCode);
end;