@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H             LIB022
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                           ISSUE 11~
~V9 -1
~P
~V9 1
~YLIB022
~S1~M~OLIBRARY IMPLEMENTATION DESCRIPTION~
~S1~M~OSection 2  Version 2~
~S1~OSection 2.1 Library Organisation~
~S1~O1. General Description~
~BThis module contains the procedures which
provide for the creation and use of the MUSS executable binary
libraries and programs. The form that
these libraries and programs take is determined by
the MUTL implementation, therefore, this module is
sensitive to machine structure. This version applies to VAX
but it should also suit most other machines with large
segmented virtual memories.
~S1~O2. Interfaces~
~
Configuration Parameters~
   NO.OF.LIBS~
   NO.OF.CODESEGS~
   NO.OF.SCR.SEGS~
   NO.OF.PROCS~
   NO.OF.TYPES~
   NO.OF.MERGED.LIBS~
   P.LIST.SIZE~
   N.LIST.SIZE~
~
Library Procedures~
   FINDN (NAME,KIND) INDEX~
   FINDP (INDEX, PNO, PARAM) TYPE~
   FINDF (INDEX, TNO, FIELD) TYPE~
   LOOK.UP.N (INDEX, LIBNAME, NAME) INDEX~
   LIBRARY (FILENAME, MODE)~
   INIT.DIR (FILE, SEGMENT, NO.OF.PROCS) SEGMENT~
   ADD.PROC (SEGMENT, PROC.NAME, PROPERTIES) PNO~
   ADD.TYPE (SEGMENT, TYPE.NAME, TYPE.SPEC) TNO~
   ADD.SEGMENT (SEGMENT, COMP.SEG, RUN.SEG, ACCESS)~
   CLOSE.DIR (SEGMENT)~
   MERGE.DIR (LIB1, LIB2, LIB1.LIB2)~
   DELETE.LIB (FILENAME)~
   CUR.PROG (ENTRY.ADDRESS)~
   RUN (FILE)~
   LOOK.UP.LIB (SEGMENT)~
   LIST.LIB(LIB.NAME,SEARCH.STRING,PRINT.SWITCH)~
   TRAN.LIB(OLD.DIR,NEW.DIR,MACHINE,CODE.SEG.SIZE)~
LINK (NAME.LIST, ADDRESS.LIST)~
~S1~O3. Implementation~
~S1~O3.1 Outline of Operation~
~BThe MUSS library system is designed for
machines which provide a large segmented virtual
memory. It allows segments containing executable
binary code for groups of procedures to be
filed and treated as 'libraries'. The procedures
of such a library may be called from other libraries
or programs. However, before any library or
program using another library may be compiled
the library to be used must be opened by using the
LIBRARY command. Also a library that has been
used in this way must be open whenever
a library or program dependent upon it is to be
used.
A library is created by using an
appropriate setting of the MODE parameter of
a compiler.~
~BLibrary procedures may also be
called from interpreters, for example, by the
command language interpreter,
and the MUSL language contains built in functions
to assist in the implementation of interpretive library calls.~
~BIn fact, in order that the parameters of the procedures
of a library may be of user defined type, a library may involve
type definitions.  Thus the procedures implemented in this
module are concerned with~
~
~M1) adding type and procedure information to a~
~N   library at compile time~
~N2) obtaining information about the procedures~
~N   and types in a library~
~N3) managing the libraries in use in a process.~
~BFor a machine with a big virtual
memory the store layout will normally be as follows~
~
~M~O|STACK|USER PROG->  <-PRIVATE LIBS|O/S COMMANDS|SYSTEM LIB|~
~
Each library contained in the virtual store will be
at least two segments. One will contain the names of its procedures
and their properties and the other will
contain the code and a table of entry points, which is always
compiled at the same address,
so that a library may be recompiled without recompiling
the programs and libraries which use it.
This segment is called the 'principal code segment'. Because
TL segments may be up to 256K bytes, but MUSS segments, in particular machines,
may be
less than this, it is necessary to keep in
the library directory the first MUSS segment of each TL segment
and its size in bytes.
~BA system library containing the basic input/output
facilities and the standard system utilities is permanently
resident in the upper part of the virtual store. Conceptually the operating syst
em commands
are part of this library although entry to these procedures
will be through a special mechanism which causes
appropriate changes in processor status.
In order to compile the correct entry sequences
to procedures
the MUTL system must differentiate between organisational commands and other non
-privileged library commands.
This information is encoded in the INDEX
returned by FINDN,
together with the principal code segment number, the directory segment number,
and the procedure number, as follows~
~Q5
~
~Mbits  0 -  7    procedure number         ~
~Nbits  8 - 15    directory segment number
~Nbits 16 - 30    principal code segment number
~Nbit  31         =1 for an organisational command
~
~
For the system library including the organisational
commands the directory segment number will be returned as
~X%`
0. The system library is assumed to be the first one
entered in 'DIRY.SEGS' (see below).
~X%%
This library is the merger of at least
two libraries, the first of which is the
commands.
An encoded INDEX is also returned for a type. This gives
the type number in bits 0-7 and the directory segment number in
bits 8-15. Its only use is as a parameter of FINDT which
yields a MUTL type encoding of a specified field within the
type definition.
~S1~O3.2 Data Structures~
~
~T% 18
~
LIBS.OPEN -~Ithis is a count of the number of
libraries open~
LIB.F.NAMES -~Ithis vector contains the file names
of open libraries~
LIB.U.NAMES -~Ithis vector contains the user names
of the owners of open libraries~
DIRY.SEGS -~Ithis vector contains the directory
segment numbers of open libraries.~
Note~Ithese vectors are actually one entry longer
than the permitted number of libraries and the last
entry is for the 'current program'.~
RUN.ADDR~Ithis gives the code segment number of the current
program.~
~S1~O3.2.1 Library Directories~
~BThese data structures are special in that there are
many of them, one for each library, with identical names
for their component parts and they exist as files. They are
accessed by first opening the file into a segment
and then using the MAKE function to make a
pointer to the directory data structure LIB.DIR which contains the following
fields.~
~
NEXTCH -~Ithis is an index to the next free byte in the~ namelist (NAME.LIST).~
~
NO.OF.PROCS -~Ithis specifies the number of procedures
in the library.~
~
NO.OF.TYPES -~Ithis specifies the number of types in the library.~
~
NEXT.P -~Ithis is the index of the next free byte in
the area allocated to parameter specs and type specs (PROP.LIST).~
~
NO.OF.DIRS -~Ithis indicates the number of single
directories which have been merged to produce the given directory.
~
~
CODE.FILES -~Ithis is a vector of file names for the principle code files that c
omprise
the library. They are assumed to be under
the same user name as the directory.
~
~
CODE.SEGS -~Ithis is a vector of INTEGER16s giving the
runtime segment number of the first
MUSS segment of each TL segment.
If the segment is a principle code segment its most
significant bit will be set to 1.~
~
SEG.SIZE -~Ithis is a vector of INTEGER32's giving the size of each
(TL) segment in bytes.~
~
ACCESS -~Ithis is a vector of logical 8s giving the access
permission required on the segment.~
~
SCRATCH.SEGS -~Ithis is a vector of integers giving the segment numbers
of the scratch segments which are to be created when the
library is opened.~
~
S.S.SIZE -~Ithis is a vector of integers giving the required
size of each scratch segment.~
~
FIRST.PROC -~Ithis is a vector giving the index (in the
namelist) of the first procedure in each principle code file.~
~
FIRST.TYPE -~Ithis is a vector giving the index (in the namelist)
of the first type in each principle code file.
~
~
P.PROPS -~Ithis is a vector of integers giving the start of the
property spec of each procedure in the library, in PROP.LIST.~
~
T.PROPS -~Ithis is a vector of integers giving the start of the
type spec in PROP.LIST for each type in the library.~
~
PROP.LIST -~Ithis is a vector of bytes containing the MUTL encoded
parameter specs and type specs.~
~
NAME.LIST -~Ithis is a vector of bytes containing the characters of
the names of the procedures in the library.
Each name is preceded by a byte which
specifies the kind entity to which it refers, and gives the number of
characters it contains. The last name in
the list is followed by a zero byte.
In this implementation the least significant 7 bits give
the size of the name and the most significant bit indicates
procedure (0) or type (X).~
~S1~O3.3 Special Notes
~BCalls on library procedures are 'bound' at
compile time, and this leads to some special requirements
when libraries are cross compiled. One of these is for
a private library version of this module
operating for the target machine, but running on the
host machine. The compile jobs for these ('X')
versions of this module are contained
in the CONLIB modules for the
respective target machines. They carry out
some special editing on this module before
compiling it in order to make it a
self contained library. Thus when changes
are made to this module it may also
be necessary to change the 'X' compile
jobs. It will also be seen that these
compile jobs remove the comments~
~
~M::X ONLY
~BThe effect of these edits is to include
in the library, the procedure TRAN.LIB (LIB02.18),
which has the parameters.
~
~
~MP1 - name of a cross compiled library         ~
~NP2 - name for the transformed version of the library
~NP3 - a destination machine type
~N     0 means 'big end' ordering
~N     1 means 'little end' ordering
~NP4 - a destination machine segment size (bytes)~
~
It transforms the directory file from host
machine format
to destination machine format, and creates files for the TL
segments of the library which match the (specified) system segment size.
When files are transferred between machines they are
treated as byte strings and
the ordering of bytes is preserved.
The order of bytes in words is machine dependent,
hence the byte order of these needs to
be transformed appropriately for the destination machine.
The structure of words can be related to the invariant byte
order using the arithmetic significance of the bytes. The two
common orderings are referred to as 'big end' and 'little end'.
In the former the most significant byte is the first in the byte order and so on
through to the least significant byte which is the last in the byte order,
e.g.  MC68000.
The least significant byte of the latter is the first in the byte order and so o
n
through to the most significant byte which is the last in the byte order,
e.g.  VAX11.
~Y
~V9 -1
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H               LIB022
~V9 -1
~F
@TITLE LIB02(2,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
LIB022 MASTER
@BOX 2.0
INITIALISATION AND
DECLARATIONS
@BOX 3.0
PROCEDURES IN LIB02
LIB02.1   FINDN
LIB02.1.1 SEARCH NAME LIST
LIB02.1.2 FORM FINDN INDEX
LIB02.2   FINDP
LIB02.2.1 FIND.P.T
LIB02.3   LIBRARY
LIB02.3.1 OPEN.LIB.OR.PROG
LIB02.4   INIT.DIR
LIB02.5   ADD.PROC
LIB02.5.1 ADD NAME AND TYPE LIST
LIB02.6   CLOSE.DIR
LIB02.7   MERGE.DIR
LIB02.8   RELEASE.LIB
LIB02.8.1 DELETE.TL.SEG
LIB02.8.2 RELEASE LIB/PROG SEGMENTS
LIB02.9   CUR.PROG
LIB02.10  RUN
LIB02.11  ADD.TYPE
LIB02.12  ADD.SEGMENT
LIB02.13  LOOK UP LIB
LIB02.14  FIND.F
LIB02.15  LOOK.UP.N
LIB02.16  SPARE
LIB02.17  LIST.LIB
LIB02.18  TRANSFORM.LIBRARY
LIB02.19 LINK
LIB02.20 GET FILE NAME
LIB02.21 LOOK UP NAME
@BOX 4.0
END
@BOX 1.1
#LIB02/1
MODULE (libRARY, FINDN, FINDP, INIT.DIR, ADD.PROC, MERGE.DIR,
   INITLIB, CLOSE.DIR, rELEASE.lIB, CUR.PROG, RUN, FIND.F,
   LOOK.UP.LIB,LOOK.UP.N,LINK,
   lIST.lIB, ADD.TYPE, ADD.SEGMENT, TRAN.DIR);
@BOX 2.1
*GLOBAL 9;
LITERAL / ADDR [LOGICAL8] NIL.PTR =;
INTEGER LIBS.OPEN,NO.OF.SEGS;
LOGICAL32 RUN.ADDR, LIB.SEGS;
LITERAL LIBS.PLUS.1 = NO.OF.LIBS+1;
LITERAL LIB.FNAME.SIZE = 16 * LIBS.PLUS.1;
LOGICAL8 [LIB.FNAME.SIZE] LIB.F.NAMES;
INTEGER [LIBS.PLUS.1] DIRY.SEGS;
INTEGER [16] CUR.PROG.SEGS;
INTEGER LIB.SEG.NO;
TYPE T.LIB.DIR IS
INTEGER16 NEXTCH, NO.OF.PROCS, NO.OF.TYPES, NEXT.P, NO.OF.DIRS,NO.OF.TL.SEGS,F.N
.SIZE,D3
LOGICAL8 [16] CODE.FILE
INTEGER16 [NO.OF.CODESEGS] CODE.SEGS
LOGICAL32[NO.OF.CODESEGS] SEG.SIZE
LOGICAL32 [NO.OF.SCR.SEGS] SCRATCH.SEGS, S.S.SIZE
LOGICAL8 [NO.OF.CODESEGS] ACCESS
INTEGER16 [NO.OF.MERGED.LIBS] FIRST.PROC, FIRST.TYPE
INTEGER16 [NO.OF.PROCS] P.PROPS
INTEGER16[NO.OF.TYPES] T.PROPS
LOGICAL8 [P.LIST.SIZE] PROP.LIST
LOGICAL8 [N.LIST.SIZE] NAMELIST;
*CODE 1;
PSPEC GET.FILEN (ADDR [LOGICAL8])/INTEGER;
PSPEC LOOK.UP.LNAME (ADDR [LOGICAL8])/INTEGER;
PSPEC MAKE.NAME (LOGICAL64, ADDR [LOGICAL8])/ADDR [LOGICAL8];
LSPEC FINDN (ADDR[LOGICAL8],INTEGER) / LOGICAL32;
LSPEC FINDP (LOGICAL32,INTEGER,INTEGER) / INTEGER;
PSPEC FIND.P.T(LOGICAL32,INTEGER,INTEGER,INTEGER)/INTEGER;
LSPEC LIBRARY (ADDR [LOGICAL8], INTEGER);
PSPEC OPEN.LIB.OR.PROG(ADDR[LOGICAL8],INTEGER,INTEGER)/INTEGER;
LSPEC INIT.DIR (ADDR [LOGICAL8], INTEGER) / INTEGER;
LSPEC ADD.PROC (INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL])/$IN;
PSPEC ADD.N.AND.T(ADDR T.LIB.DIR,ADDR[LOGICAL8],ADDR[LOGICAL])/INTEGER;
LSPEC CLOSE.DIR (INTEGER);
LSPEC MERGE.DIR (ADDR [LOGICAL8], ADDR [LOGICAL8], ADDR [LOGICAL8]);
LSPEC RELEASE.LIB (ADDR [LOGICAL8]);
PSPEC REL.TL.SEG(INTEGER,LOGICAL32);
PSPEC REL.LIB.PROG(INTEGER);
LSPEC CUR.PROG (LOGICAL32);
LSPEC RUN (ADDR [LOGICAL8]);
LSPEC LOOK.UP.LIB (INTEGER)/ADDR [LOGICAL8];
LSPEC LOOK.UP.N (INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL8]) / LOGICAL32;
LSPEC ADD.TYPE(INTEGER,ADDR[$LO8],ADDR[$LO])/$IN;
LSPEC ADD.SEGMENT(INTEGER,INTEGER,$LO32,LOGICAL,INTEGER32);
LSPEC FIND.F(LOGICAL32,INTEGER,INTEGER)/INTEGER;
LSPEC LIST.LIB (ADDR[LOGICAL8], ADDR[LOGICAL8], INTEGER);
LSPEC INIT.LIB();
::X ONLY LSPEC TRAN.DIR(ADDR [LOGICAL8], ADDR [LOGICAL8], INTEGER, ADDR);
TYPE T IS ADDR DUMMYP PP;
LSPEC LINK (ADDR [$LO8], ADDR [T]) / INTEGER;
PSPEC SEARCH (ADDR[$LO8], ADDR[$LO8], $IN)/$IN;
PSPEC FNINDEX ($IN, $IN, $IN, ADDR T.LIB.DIR)/$LO32;
PROC INITLIB;
   -1 => NO.OF.SEGS;
   MAIN.LIB.DIR.SEG => DIRY.SEGS [0];
   1 => LIBS.OPEN;
   0 => LIB.SEGS => RUN.ADDR;
END
PROC MAKE.NAME (FILE.N, NAME);
INTEGER I, J;
FOR I < 8 DO
   I*8 => J;
   FILE.N ->> J => NAME^ [7 - I];
OD
NAME => MAKE.NAME;
END
@BOX 3.1
#LIB02.1
#LIB02.1.1
#LIB02.1.2
#LIB02.2
#LIB02.2.1
#LIB02.3
#LIB02.3.1
#LIB02.4
#LIB02.5
#LIB02.5.1
#LIB02.6
#LIB02.7
#LIB02.8
#LIB02.8.1
#LIB02.8.2
#LIB02.9
#LIB02.10
#LIB02.11
#LIB02.12
#LIB02.13
#LIB02.14
#LIB02.15
#LIB02.17
::X ONLY #LIB02.18
#LIB02.19
#LIB02.20
#LIB02.21
@BOX 4.1
*END
@END
@TITLE LIB02/1(2,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
EXTERNAL ENVIRONMENT
@BOX 2.0
DIRECTORY SPECS
@BOX 3.0
IMPORTED PROCS
AND LITERALS/VARS
@BOX4.0
END
@BOX1.1
::EXTERNALS
@BOX 2.1
LITERAL NO.OF.LIBS=7,NO.OF.CODESEGS=20,NO.OF.SCR.SEGS=16,
        NO.OF.PROCS=480,NO.OF.TYPES=16,NO.OF.MERGED.LIBS=16,
        P.LIST.SIZE=2000,N.LIST.SIZE=4500;
@BOX 3.1
LSPEC MAP (INTEGER, INTEGER, INTEGER);
LSPEC OPEN.FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER, LOGICAL);
LSPEC FILE (ADDR [LOGICAL8], LOGICAL64, INTEGER);
LSPEC CREATE.SEGMENT (INTEGER, ADDR);
LSPEC CREATE.FILE.SEGMENT (INTEGER, ADDR, ADDR [LOGICAL8], LOGICAL64);
LSPEC CREATE.FILE.X.SEGMENT (INTEGER, ADDR [LOGICAL8], LOGICAL64);
LSPEC RELEASE.SEGMENT (INTEGER);
::OMIT THIS SEQUENCE FROM XCOMPILE
PSPEC ENTER.TRAP (INTEGER, INTEGER);
PSPEC SPACES (INTEGER);
PSPEC NEWLINES (INTEGER);
PSPEC CAPTION  (ADDR [LOGICAL8]);
PSPEC PROCESS.NAME (ADDR [LOGICAL8]) / ADDR [LOGICAL8];
PSPEC OUT.I(INTEGER32,INTEGER);
PSPEC OUT.CH(INTEGER);
PSPEC TL.ENTER(INTEGER);
::END OF SEQUENCE
PSPEC DUMMYP ()
PSPEC ADDR.PROC (LOGICAL32) / ADDR DUMMYP;
ADDR PW0, PW1, PW2, PW3, PW4, PW5, PW6;
LOGICAL64 PWW1, PWW2;
IMPORT LITERAL SYS14.NO.OF.LOCAL.SEGS, SYS14.SEG.SHIFT;
IMPORT LITERAL SYS14.PAGE.SIZE,SYS14.PAGE.SHIFT;
IMPORT LITERAL ADDR SYS14.SEG.SIZE;
IMPORT LITERAL MAIN.LIB.DIR.SEG, NO.OF.PUBLIC.LIBS;
LOGICAL64 [NO.OF.PUBLIC.LIBS] PUBLIC.LIB;
INTEGER [NO.OF.PUBLIC.LIBS] PUB.LIB.DIR.SEG;
@BOX4.1
::END
@END
@TITLE LIB02A(2,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
LIB022 MASTER FOR CROSS COMPILE LIBRARY
@BOX 2.0
INITIALISATION AND
DECLARATIONS
@BOX 3.0
PROCEDURES IN LIB02
LIB02.1   FINDN
LIB02.1.1 SEARCH NAME LIST
LIB02.1.2 FORM FINDN INDEX
LIB02.2   FINDP
LIB02.2.1 FIND.P.T
LIB02.3   LIBRARY
LIB02.3.1 OPEN.LIB.OR.PROG
LIB02.4   INIT.DIR
LIB02.5   ADD.PROC
LIB02.5.1 ADD NAME AND TYPE LIST
LIB02.6   CLOSE.DIR
LIB02.7   MERGE.DIR
LIB02.8   RELEASE.LIB
LIB02.8.1 DELETE.TL.SEG
LIB02.8.2 RELEASE LIB/PROG SEGMENTS
LIB02.9   CUR.PROG
LIB02.10  RUN
LIB02.11  ADD.TYPE
LIB02.12  ADD.SEGMENT
LIB02.13  LOOK UP LIB
LIB02.14  FIND.F
LIB02.15  LOOK.UP.N
LIB02.16  SPARE
LIB02.17  LIST.LIB
LIB02.18  TRANSFORM.LIBRARY
LIB02.19  LINK
LIB02.20 GET FILE NAME
LIB02.21 LOOK UP NAME
@BOX 4.0
END
@BOX 1.1
#LIB02/1
MODULE (libRARY, FINDN, FINDP, INIT.DIR, ADD.PROC, MERGE.DIR,
   INITLIB, CLOSE.DIR, rELEASE.lIB, CUR.PROG, RUN, FIND.F,
    LOOK.UP.LIB, LOOK.UP.N,LINK,
   lIST.lIB, ADD.TYPE, ADD.SEGMENT, TRAN.DIR);
@BOX 2.1
*GLOBAL 9;
LITERAL / ADDR [LOGICAL8] NIL.PTR =;
INTEGER LIBS.OPEN,NO.OF.SEGS;
LOGICAL32 RUN.ADDR, LIB.SEGS;
::TARGET VAX LITERAL / INTEGER TRGT.SEG.SHIFT = 16;
::TARGET PTV LITERAL / INTEGER TRGT.SEG.SHIFT = 18;
::TARGET MU6G LITERAL / INTEGER TRGT.SEG.SHIFT = 18;
::TARGET GEM LITERAL / INTEGER TRGT.SEG.SHIFT = 16;
LITERAL LIBS.PLUS.1 = NO.OF.LIBS+1;
LITERAL LIB.FNAME.SIZE = 16 * LIBS.PLUS.1;
LOGICAL8 [LIB.FNAME.SIZE] LIB.F.NAMES;
INTEGER [LIBS.PLUS.1] DIRY.SEGS;
INTEGER [16] CUR.PROG.SEGS;
TYPE T.LIB.DIR IS
INTEGER16 NEXTCH, NO.OF.PROCS, NO.OF.TYPES, NEXT.P, NO.OF.DIRS,NO.OF.TL.SEGS,F.N
.SIZE,D3
LOGICAL8 [16] CODE.FILE
INTEGER16 [NO.OF.CODESEGS] CODE.SEGS
LOGICAL32[NO.OF.CODESEGS] SEG.SIZE
LOGICAL32 [NO.OF.SCR.SEGS] SCRATCH.SEGS, S.S.SIZE
LOGICAL8 [NO.OF.CODESEGS] ACCESS
INTEGER16 [NO.OF.MERGED.LIBS] FIRST.PROC, FIRST.TYPE
INTEGER16 [NO.OF.PROCS] P.PROPS
INTEGER16[NO.OF.TYPES] T.PROPS
LOGICAL8 [P.LIST.SIZE] PROP.LIST
LOGICAL8 [N.LIST.SIZE] NAMELIST;
*CODE 1;
PSPEC GET.FILEN (ADDR [LOGICAL8])/INTEGER;
PSPEC LOOK.UP.LNAME (ADDR [LOGICAL8])/INTEGER;
PSPEC MAKE.NAME ( LOGICAL64, ADDR [LOGICAL8])/ADDR [LOGICAL8];
LSPEC FINDN (ADDR[LOGICAL8],INTEGER) / LOGICAL32;
LSPEC FINDP (LOGICAL32,INTEGER,INTEGER) / INTEGER;
PSPEC FIND.P.T(LOGICAL32,INTEGER,INTEGER,INTEGER)/INTEGER;
LSPEC LIBRARY (ADDR [LOGICAL8], INTEGER);
PSPEC OPEN.LIB.OR.PROG(ADDR[LOGICAL8],INTEGER,INTEGER)/INTEGER;
LSPEC INIT.DIR (ADDR [LOGICAL8], INTEGER) / INTEGER;
LSPEC ADD.PROC (INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL])/$IN;
PSPEC ADD.N.AND.T(ADDR T.LIB.DIR,ADDR[LOGICAL8],ADDR[LOGICAL])/INTEGER;
LSPEC CLOSE.DIR (INTEGER);
LSPEC MERGE.DIR (ADDR [LOGICAL8], ADDR [LOGICAL8], ADDR [LOGICAL8]);
LSPEC RELEASE.LIB (ADDR [LOGICAL8]);
PSPEC REL.TL.SEG(INTEGER,LOGICAL32);
PSPEC REL.LIB.PROG(INTEGER);
LSPEC CUR.PROG (LOGICAL32);
LSPEC RUN (ADDR [LOGICAL8]);
LSPEC LOOK.UP.LIB (INTEGER)/ADDR [LOGICAL8];
LSPEC LOOK.UP.N (INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL8]) / LOGICAL32;
LSPEC ADD.TYPE(INTEGER,ADDR[$LO8],ADDR[$LO])/$IN;
LSPEC ADD.SEGMENT(INTEGER,INTEGER,$LO32,LOGICAL,INTEGER32);
LSPEC FIND.F(LOGICAL32,INTEGER,INTEGER)/INTEGER;
LSPEC LIST.LIB (ADDR[LOGICAL8], ADDR[LOGICAL8], INTEGER);
LSPEC INIT.LIB();
::X ONLY LSPEC TRAN.DIR(ADDR [LOGICAL8], ADDR [LOGICAL8], INTEGER, ADDR);
TYPE T IS ADDR DUMMYP PP;
LSPEC LINK (ADDR [$LO8], ADDR [T]) / INTEGER;
PSPEC SEARCH (ADDR[$LO8], ADDR[$LO8], $IN)/$IN;
PSPEC FNINDEX ($IN, $IN, $IN, ADDR T.LIB.DIR)/$LO32;
PROC INITLIB;
   MAIN.LIB.DIR.SEG => DIRY.SEGS [0];
   1 => LIBS.OPEN;
   0 => LIB.SEGS => RUN.ADDR;
END
PROC MAKE.NAME (FILE.N, NAME);
INTEGER I, J;
 FOR I < 8 DO
   I*8 => J;
   FILE.N ->> J => NAME^ [7 - I];
OD
NAME => MAKE.NAME;
END
@BOX 3.1
#LIB02.1
#LIB02.1.1
#LIB02.1.2
#LIB02.2
#LIB02.2.1
#LIB02.3
#LIB02.3.1
#LIB02.4
#LIB02.5
#LIB02.5.1
#LIB02.6
#LIB02.7
#LIB02.8
#LIB02.8.1
#LIB02.8.2
#LIB02.9
#LIB02.10
#LIB02.11
#LIB02.12
#LIB02.13
#LIB02.14
#LIB02.15
#LIB02.17
::X ONLY #LIB02.18
#LIB02.19
#LIB02.20
#LIB02.21
@BOX 4.1
*END
@END
@TITLE LIB02.1(2,8)

@COL 1S-2R-3T-4R-5T-6R-7R-8T-10R-11F
@COL 12R
@ROW 7-12
@FLOW 1-2-3NO-4-5Y-6-7-8Y-10-11
@FLOW 3YES-12
@FLOW 5N-12-11
@FLOW 8N-5
@BOX 1.0
FINDN
@BOX 2.0
DECLARATIONS
@BOX 3.0
REMOVE '.'S
EMPTY STRING?
@BOX 4.0
SET STRING POINTER TO NEW SIZE
@BOX 5.0
ANY PRIVATE LIBRARIES TO SCAN
@BOX 6.0
SET POINTER TO
PRIVATE LIB DIRECTORY
@BOX 7.0
SEARCH NAME LIST
@BOX 8.0
NAME FOUND
@BOX 10.0
FORM FINDN
INDEX
@BOX 11.0
RETURN
@BOX 12.0
SET RESULT = 0
@BOX 1.1
PROC FINDN(SNAME,P.OR.T);
@BOX 2.1
INTEGER PTR,OLD.S1,PTR1,PTR2,DIR.SEG.NO, NAME.SIZE, I, J;
0 => OLD.S1; LIBS.OPEN => PTR;
ADDR[LOGICAL8]NAMES;
ADDR T.LIB.DIR DIR.SEG;
MAKE(T.LIB.DIR,0,DIRY.SEGS[PTR]<<- SYS14.SEG.SHIFT) => DIR.SEG;
@BOX 3.1
SIZE (SNAME) => NAME.SIZE;
0 => J;
FOR I < NAME.SIZE DO
   IF SNAME^ [I] => SNAME^ [I-J] = "." THEN
      1 +> J;
   FI
OD
IF J -> NAME.SIZE = 0
@BOX 4.1
PART (SNAME, 0, NAME.SIZE - 1) => SNAME;
@BOX 5.1
IF 1 -> PTR < 0
@BOX 6.1
MAKE(T.LIB.DIR,0,DIRY.SEGS[PTR] <<- SYS14.SEG.SHIFT) => DIR.SEG;
SELECT DIR.SEG^;
@BOX 7.1
SEARCH(^NAME.LIST,SNAME,P.OR.T<<-7) => I;
@BOX 8.1
IF I = 0
@BOX 10.1
FNINDEX (PTR, I, 0, DIR.SEG) => FINDN;
@BOX 11.1
END
@BOX 12.1
0 => FINDN;
@END
@TITLE LIB02.1.1(2,8)

@COL 16N-5T-12R-13T
@COL 1S-2R-3R-4R-11T-15T-6T-7R-8T-9N-10F
@COL 14R
@ROW 5-7
@ROW 16-11
@ROW 13-9-14
@FLOW 1-2-3-4-11N-15Y-6Y-7-8Y-9-10
@FLOW 15N-4
@FLOW 11Y-14-10
@FLOW 5Y-12-13Y-10
@FLOW 6N-5N-16-4
@FLOW 8N-4
@FLOW 13N-16
@BOX 1.0
SEARCH NAMELIST
@BOX 2.0
SET POINTERS FOR SCAN
@BOX 3.0
COMPUTE HASH IF NAME < 4 CHS
@BOX 4.0
FIND THE NEXT PROC OR TYPE
IN NAMELIST AS REQUESTED
@BOX 5.0
IS SIZE OF NAME < 4CHS
@BOX 6.0
ARE SIZES EQUAL
@BOX 7.0
COMPARE FULL
NAMES
@BOX 8.0
DO NAMES MATCH
@BOX 10.0
END
@BOX 11.0
END OF LIST
@BOX 12.0
COMPUTE
HASH
@BOX 13.0
DO NAMES MATCH
@BOX 14.0
SET RESULT = 0
@BOX 15.0
IS KIND OF NAME = P.OR.T
@BOX 1.1
PROC SEARCH(NAMES,SNAME,P.OR.T);
INTEGER N.INDEX,SIZE.STRING,SIZE.NAME,I;
INTEGER32 HASH, HASH1;
@BOX 2.1
0 => HASH => N.INDEX => SIZE.STRING => SEARCH;
@BOX 3.1
IF SIZE (SNAME) => SIZE.NAME < 4 THEN
   FOR I < SIZE.NAME DO
      HASH <<- 8 + (SNAME^ [I] & %5F) => HASH;
   OD
FI
@BOX 4.1
1 +> SEARCH;
SIZE.STRING +> N.INDEX;
$WH NAMES^[N.INDEX] => SIZE.STRING /= 0
   AND SIZE.STRING & %80 /= P.OR.T
DO SIZE.STRING & %7F + 1 +> N.INDEX OD
1 +> N.INDEX;
@BOX 5.1
IF SIZE.NAME >= 4
@BOX 6.1
IF SIZE.NAME /= SIZE.STRING
@BOX 7.1
FOR I < SIZE.STRING DO
IF SNAME^[I] & %5F /= NAMES^[I + N.INDEX] & %5F THEN
-> ESC FI
OD ESC:;
@BOX 8.1
IF I /= SIZE.STRING
@BOX 10.1
END
@BOX 11.1
IF SIZE.STRING = 0
@BOX 12.1
0 => HASH1
FOR I < SIZE.STRING DO
   IF NAMES^ [I + N.INDEX] & %80 /= 0 THEN
      HASH1 <<- 8 + (NAMES^ [I+N.INDEX] & %5F)
         => HASH1;
   FI
OD
@BOX 13.1
IF HASH /= HASH1
@BOX 14.1
0 => SEARCH;
@BOX 15.1
SIZE.STRING & %80 => I;
P.OR.T -> SIZE.STRING;
IF I /= P.OR.T
@END
@TITLE LIB02.1.2(2,10)
@COL 1S-2R-3R-4R-5R-6R-7T-8R-9F
@FLOW 1-2-3-4-5-6-7Y-8-9
@FLOW 7N-9
@BOX1.0
FORM FINDN INDEX (DIRSEG,PROC,P.OR.T)
@BOX2.0
ENCODE DIRECTORY
SEGMENT NUMBER
@BOX 3.0
FORM POINTER TO
FIRST PROC/TYPE LIST
@BOX4.0
FIND LIBRARY
WHICH CONTAINS PROC.NO
@BOX5.0
FIND CORRESPONDING
PRINCIPAL CODE SEG
@BOX 6.0
FORM INDEX FROM
CODESEG-DIRYSEG-
@BOX 7.0
IS PROC A COMMAND
@BOX 8.0
SET THE COMMAND BIT
IN "INDEX"
@BOX 9.0
END
@BOX 1.1
PROC FNINDEX(DIR.SEG,PROC.NO,P.OR.T, CURLIB);
SELECT CURLIB^;
$IN PTR,PTR1,PTR2,DIR.SEG.NO;
ADDR [$IN16] FIRST.LIST;
@BOX 2.1
IF DIRY.SEGS[DIR.SEG] => DIR.SEG.NO = MAIN.LIB.DIR.SEG THEN
0 => DIR.SEG.NO
FI
@BOX 3.1
IF P.OR.T = 0
   THEN ^FIRST.PROC => FIRST.LIST
   ELSE ^FIRST.TYPE => FIRST.LIST
FI
@BOX 4.1
FOR PTR1 < NO.OF.MERGED.LIBS DO
   IF FIRST.LIST^[PTR1] >= PROC.NO, -> OUT
OD
OUT:
PTR1 - 1 => PTR2;
@BOX 5.1
FOR PTR < NO.OF.CODE.SEGS DO
IF CODESEGS [PTR] & %8000 /= 0
   THEN IF 1 -> PTR1 = 0, -> OUT1;
FI
OD
OUT1:
@BOX 6.1
CODE.SEGS[PTR] & %7FFF <<- 8 ! DIR.SEG.NO <<- 8 + PROCNO - FIRST.LIST^[PTR2] =>
FNINDEX;
@BOX 7.1
IF DIR.SEG /= 0 OR PTR /= 0
@BOX 8.1
%80000000 !> FNINDEX;
@BOX 9.1
END
@END
@TITLE LIB02.2(2,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
FINDP
@BOX 2.0
USE SUBPROCEDURE
FIND.P.T[LIB02.8.1]
@BOX 3.0
END
@BOX 1.1
PROC FIND.P(P1,P2,P3);
@BOX 2.1
FINDP.T(P1,P2,P3,0) => FIND.P;
@BOX 3.1
END
@END
@TITLE LIB02.2.1(2,10)
@COL 1S-2R-4R-3R-5F
@FLOW 1-2-4-3-5
@BOX 1.0
PROCEDURE FINDP.T(FINDN INDEX, P.OR.T.NO, PARAM, P.OR.T);
@BOX 2.0
SET POINTER TO DIRECTORY
@BOX 3.0
ACCESS REQUIRED
PARAMETER SPEC
@BOX 4.0
SELECT PROC OR TYPE LISTS
@BOX 5.0
END
@BOX 1.1
PROC FINDP.T(A,A1,B,P.OR.T);
INTEGER PTR,I;
ADDR T.LIB.DIR LIB.DIR;
ADDR[INTEGER16] PROPS,FIRST;
@BOX 2.1
IF A ->> 8 & 255 => I = 0 THEN
   MAIN.LIB.DIR.SEG => I;
FI
MAKE(T.LIB.DIR, 0, I <<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
@BOX 3.1
-1 => PTR;0 => I;
WHILE CODE.SEGS[1 +> PTR] & %7FFF /= A->>16 & %7FFF DO
IF CODE.SEGS[PTR] & %8000 /= 0 THEN 1 +> I FI
OD
IF A1 < 0 THEN A & %FF => A1 FI
PROPS^[A1- 1 + FIRST^[I]] + B=> I;
IF I & %8000 = 0 THEN
PROP.LIST[I] => FINDP.T;
ELSE
PROP.LIST[I&%7FFF+B] <<- 8 + PROPLIST[I&%7FFF+B+1] => FINDP.T;
FI
@BOX 4.1
IF P.OR.T = 0 THEN
   ^P.PROPS => PROPS;
   ^FIRST.PROC => FIRST;
ELSE
   ^T.PROPS => PROPS;
   ^FIRST.TYPE => FIRST;
FI
@BOX 5.1
END
@END
@TITLE LIB02.3(2,10)
@COL 1S-2T-3R-4R-5R-6F
@COL 7R
@ROW 3-7
@FLOW 1-2N-3-4-5-6
@FLOW 2Y-7
@BOX 1.0
OPEN LIBRARY
@BOX 2.0
TOO MANY LIBS OPEN
@BOX 3.0
OPEN SPECIFIED LIBRARY
AND NOTE FILE/USER NAMES
AND DIRECTORY SEGMENT NUMBER
[LIB02.13.1]
@BOX 4.0
INCREMENT LIBS.OPEN
@BOX 5.0
EXECUTE INITIALISATION CODE
@BOX 6.0
END
@BOX 7.0
ENTER.TRAP(FILE.N,MODE);
@BOX 1.1
PROC LIBRARY(FILE.N,MODE);
INTEGER I;
@BOX 2.1
IF LIBS.OPEN = NO.OF.LIBS
@BOX 3.1
OPEN.LIB.OR.PROG(FILE.N,LIBS.OPEN,MODE) => I;
@BOX 4.1
1 +> LIBS.OPEN;
@BOX 5.1
::OMIT THIS SEQUENCE FROM XCOMPILE
IF MODE & 6 = 0 THEN
TL.ENTER(I);
FI
::END OF SEQUENCE
@BOX 6.1
END
@BOX 7.1
ENTER.TRAP(9,10);
@END
@TITLE LIB02.3.1(2,11)
@COL 1S-2T-3R-5R-11T-16R-10R-13R-6F
@FLOW 1-2NO-3-5-11Y-13-6
@FLOW 2FAULT-10
@FLOW 11N-16-10
@BOX 1.0
OPEN LIBRARY OR PROGRAM SEGMENTS
@BOX 2.0
NOTE LIB OR PROG NAME
AND OPEN DIRECTORY
@BOX 3.0
NOTE DIRECTORY SEGMENT
IN 'DIRY.SEGS'
@BOX 5.0
OPEN CODE SEGMENTS
AND CREATE SCRATCH SEGMENTS
@BOX 6.0
END
@BOX 10.0
ENTER TRAP (9, 10)
(UNABLE TO OPEN LIBRARY)
@BOX 11.0
ABLE TO OPEN ALL SEGMENTS
@BOX 13.0
RETURN PRINCIPAL CODE
SEGMENT NUMBER
@BOX 16.0
RELEASE LIBRARY SEGMENTS JUST
CREATED
@BOX 1.1
PROC OPEN.LIB.OR.PROG(LPATH.NAME,NUMBER,MODE);
INTEGER I,J,L,M, LPATH.SIZE, FILE.N.SIZE, START.POS,
PREFIX.SIZE, PTR, END.PTR, C, NAME.START;
LOGICAL8 TEMP;
LOGICAL8 [80] CODE.FNAME;
LOGICAL32 K;
LOGICAL64 SAVED.PWW1;
ADDR T.LIB.DIR LIB.DIR;
INTEGER NAME.SIZE;
@BOX 2.1
PROCESS.NAME (LPATH.NAME) => LPATH.NAME;
PWW1 => SAVED.PWW1;
GET.FILEN (LPATH.NAME) => LPATH.SIZE;
PW1 => FILE.N.SIZE;
L.PATH.SIZE - FILE.N.SIZE => NAME.START;
NUMBER * 16 => START.POS;
FOR I < FILE.N.SIZE DO
   LPATH.NAME^ [NAME.START + I] => LIB.F.NAMES [START.POS + I];
OD
OPEN.FILE (LPATH.NAME, SAVED.PWW1, -1, %C);
IF PW0 /= 0
@BOX 3.1
PW1 => DIRY.SEGS[NUMBER];
MAP (PW1, -1, 0);
MAKE(T.LIB.DIR,0,PW6<<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
@BOX 5.1
-1 => END.PTR;
IF MODE & 4 = 0 THEN
   -1 => I => J;
::OMIT THIS SEQUENCE FROM XCOMPILE
   LPATH.SIZE - FILEN.SIZE => PREFIX.SIZE;
   IF CODE.SEGS [0] /= 0 AND PREFIX.SIZE + F.N.SIZE =< 80 THEN
     FOR C < PREFIX.SIZE DO
         LPATH.NAME^ [C] => CODE.FNAME [C];
      OD
      FOR C < F.N.SIZE DO
         CODE.FILE [C] => CODE.FNAME [PREFIX.SIZE + C]
      OD
      PREFIX.SIZE + F.N.SIZE - 1 => END.PTR;
   FI
   WHILE CODE.SEGS [1+>I] => K /= 0 DO
      "0" + I => CODE.FNAME [END.PTR - 1];
      SEG.SIZE [I] + SYS14.SEG.SIZE - 1 ->> SYS14.SEG.SHIFT => M;
      FOR L < M DO
         "0" + L => CODE.FNAME [END.PTR];
         OPEN.FILE(PART (^CODE.FNAME, 0, END.PTR), SAVED.PWW1, K & %7F + L, ACCE
SS[I]);
         IF PW0 /= 0 THEN
            CAPTION(PART (^CODE.FNAME, 0, END.PTR));CAPTION(%"  NOT AVAIL");
            -> OUT;
         FI
         MAP (K & %7F + L, -1, 0);
         IF PW0 /= 0, -> OUT;
      OD
   OD
   WHILE SCRATCH.SEGS[1+>J] /= 0 DO
      CREATE.SEGMENT(SCRATCH.SEGS[J],S.S.SIZE[J]);
      IF PW0 /= 0, -> OUT;
      MAP (SCRATCH.SEGS[J], -1, 0);
         IF PW0 /= 0, -> OUT;
   OD
   OUT:
::END OF SEQUENCE
FI
@BOX 6.1
END
@BOX 10.1
ENTER.TRAP (9, 10);
@BOX 11.1
IF PW0 = 0
@BOX 13.1
-1 => I;
$WH CODE.SEGS[1+>I] => K /= 0 DO
   IF K & %80000000 /= 0 THEN
K & %7F => OPEN.LIB.OR.PROG;
FI
OD
@BOX 16.1
FOR L < I DO
REL.TL.SEG(CODESEGS[L] & %7F,SEGSIZE[L]);
OD
FOR L < J DO
   RELEASE.SEGMENT(SCRATCH.SEGS [L]);
OD
RELEASE.SEGMENT(DIRY.SEGS[LIBS.OPEN]);
@END
@TITLE LIB02.4(2,11)
@COL 8R
@COL 1S-5T-2R-3R-4R-6R-7F
@FLOW 1-5N-2-3-4-6-7
@FLOW 5Y-8-6
@BOX 1.0
INIT.DIR
@BOX 2.0
CREATE A SEGMENT FOR
THE DIRECTORY AND
@BOX 3.0
INITIALISE THE SCALARS
@BOX 4.0
MAKE ENTRIES IN
DIRY.FILE
CODE.FILES
CODE.SEGS
AND FIRST.PROC
@BOX 5.0
???
@BOX 6.0
RETURN DIRECTORY SEGMENT
AS RESULT
@BOX 7.0
END
@BOX 8.0
DELETE CURRENT PROGRAM
@BOX 1.1
PROC INIT.DIR(FILE.N,PROCS);
INTEGER OLD.S1,DIRY.SEG,NO,I,REQU.SEGS, LIMIT, N.SIZE, J;
LOGICAL8 [8] F.NAME;
ADDR T.LIB.DIR LIB.DIR;
0 => DIRY.SEG;
@BOX 2.1
CREATE.FILE.SEGMENT(-1,8192, FILE.N, 0);
PW1 => DIRY.SEG;
MAP (DIRY.SEG, -1, 0);
MAKE(T.LIB.DIR,0,PW6<<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIBDIR^;
@BOX 3.1
0 => NO.OF.PROCS => NO.OF.TYPES => NEXTCH => NEXTP => NO.OF.TL.SEGS;
1=>NO.OF.DIRS;
@BOX 4.1
IF SIZE (FILE.N) + 2 => F.N.SIZE > 16 THEN
   F.N.SIZE - 16 => I;
   16 => F.N.SIZE;
ELSE
   0 => I;
FI
FOR J < (F.N.SIZE - 2) DO
   FILE.N^ [I + J] => CODE.FILE [J];
OD
@BOX 5.1
IF FILE.N = NIL.PTR
@BOX 6.1
DIRY.SEG => INIT.DIR;
@BOX 7.1
END
@BOX 8.1
FOR J < NO.OF.SEGS + 1 DO
   RELEASE.SEGMENT(CUR.PROG.SEGS[J]);
OD
-1 => NO.OF.SEGS;
IF DIRY.SEGS[NO.OF.LIBS] /= 0 THEN
   REL.LIB.PROG(NO.OF.LIBS);
FI
@END
@TITLE LIB02.5(2,10)
@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5
@BOX 1.0
ADD PROCEDURE TO LIB
@BOX 2.0
SELECT DIRECTORY
@BOX 3.0
MAKE ENTRY IN P.PROPS
ENTER NAME AND PROPERTIES
IN DIRECTORY [LIB02.5.1]
@BOX 4.0
UPDATE 'NO.OF.PROCS'
@BOX 5.0
END
@BOX 1.1
PROC ADD.PROC (DIRY.SEG,NAME,PROPS);
   ADDR T.LIB.DIR LIB.DIR;
@BOX 2.1
MAKE(T.LIB.DIR,0,DIRY.SEG <<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
@BOX 3.1
NEXTP + ADD.N.AND.T(LIB.DIR,NAME,PROPS) => P.PROPS[NO.OF.PROCS];
@BOX 4.1
1 +> NO.OF.PROCS => ADD.PROC;
@BOX 5.1
END
@END
@TITLE LIB02.5.1(2,10)
@COL 1S-2R-3R-7R-4R-5R-6F
@FLOW 1-2-3-7-4-5-6
@BOX 1.0
ADD NAME AND TYPES
OF PSPEC OR TDEFN
@BOX 2.0
SELECT DIRECTORY SEGMENT
@BOX 3.0
COPY NAME INTO 'NAMELIST'
AND UPDATE 'NEXTCH'
@BOX 7.0
SCAN TYPE LIST FOR
USER DEFINED TYPES
A SET TYPE.SIZE
@BOX 4.0
COPY PSPEC/TYPE DEFN INTO
1 BYTE ENTRIES IF NO USER
DEFINED TYPES ELSE
INTO 2 BYTE ENTRIES
UPDATE NEXT.P
@BOX 5.0
RETURN TYPE.SIZE
@BOX 6.0
END
@BOX 1.1
PROC ADD.N.AND.T(LIB.DIR,NAME,PROPERTIES);
INTEGER TYPE.SIZE,K,I;
@BOX 2.1
SELECT LIBDIR^;
@BOX 3.1
SIZE(NAME) => NAME.LIST[NEXTCH];
FOR I < SIZE(NAME) DO
NAME^[I] => NAME.LIST[1+>NEXTCH]
OD
1 +> NEXTCH;
@BOX 7.1
0 => TYPE.SIZE
FOR I < SIZE(PROPERTIES) DO
IF PROPERTIES^[I] & %FF00 /= 0 THEN
   %8000 => TYPE.SIZE
FI
OD
@BOX 4.1
FOR I < SIZE(PROPERTIES)DO
IF TYPE.SIZE = 0 THEN
PROPERTIES^[I] => PROP.LIST[I+NEXT.P]
ELSE
   PROPERTIES^[I] ->> 8 => PROP.LIST[I+I+NEXT.P];
   PROPERTIES^[I] => PROP.LIST[I+I+1+NEXT.P];
FI
OD
IF TYPE.SIZE /= 0 THEN
I +> NEXT.P
FI
I +> NEXT.P;
@BOX 5.1
TYPE.SIZE => ADD.N.AND.T;
@BOX 6.1
END
@END
@TITLE LIB02.6(2,11)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
CLOSE DIRECTORY
@BOX 2.0
FILE DIRECTORY SEGMENT
@BOX 3.0
END
@BOX 1.1
PROC CLOSE.DIR(SEG);
ADDR T.LIB.DIR LIB.DIR;
@BOX 2.1
MAKE(T.LIB.DIR,0,SEG<<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
1023 => FIRST.PROC[NO.OF.DIRS] => FIRST.TYPE[NO.OF.DIRS];
FILE (PART (^CODE.FILE, 0, F.N.SIZE - 3), 0, SEG);
RELEASESEGMENT(SEG);
@BOX 3.1
END
@END
@TITLE LIB02.7(2,11)
@COL 1S-2R-3R-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
MERGE DIRECTORIES
@BOX 2.0
INITIALISE NEW DIRECTORY
@BOX 3.0
OPEN AND COPY FIRST DIRECTORY
@BOX 4.0
OPEN AND COPY SECOND DIRECTORY
@BOX 5.0
CLOSE NEW DIRECTORY
@BOX 6.0
END
@BOX 1.1
PROC MERGE.DIR(DIR1,DIR2,DIR1.2);
ADDR T.LIB.DIR LIB.DIR;
PSPEC COPY.DIR(INTEGER,ADDR [LOGICAL8]);
INTEGER SEG, I, J;
@BOX 2.1
INIT.DIR(DIR1.2,0) => SEG;
MAKE(T.LIB.DIR,0,SEG<<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
1->NO.OF.DIRS;
0 => CODE.SEGS[0];
SIZE(DIR1.2) => I;
FOR J < I DO
   DIR1.2^[J] => CODEFILE[14-I+J];
OD
@BOX 3.1
COPY.DIR(SEG,DIR1);
@BOX 4.1
COPY.DIR(SEG,DIR2);
@BOX 5.1
CLOSE.DIR(SEG);
@BOX 6.1
#LIB02.7.1
END
@END
@TITLE LIB02.7.1(2,11)
@COL 1S-2R-3R-4R-5R-6R-7R-8R-9F
@FLOW 1-2-3-4-5-6-7-8-9
@BOX 1.0
COPY DIRECTORY
@BOX 2.0
OPEN FILE AND SET POINTERS TO
BOTH DIRECTORIES
@BOX 3.0
FIND NEXT POSITION
IN CODESEGS ETC
OF DIRECTORY 1
@BOX 4.0
COPY CODEFILE,CODESEGS,SIZES AND ACCESS FROM DIRECTORY 2 TO DIRECTORY 1
COPY FIRSTPROC(+INC) AND FIRST TYPE(+INC)
DIRECTORY 2 TO 1
@BOX 5.0
COPY PROPS POINTERS AND TYPE POINTERS FROM
DIRECTORY 2 TO 1
AND UPDATE NO.OF.PROCS AND NUMBER OF TYPES
@BOX 6.0
COPY NAMES AND UPDATE NEXTCH
@BOX 7.0
COPY PSPECS AND UPDATE NEXTP
@BOX 8.0
RELEASE FILE SEGMENT
@BOX 9
END
@BOX 1.1
PROC COPY.DIR(SEG1,FILE.N);
INTEGER SEG2,PTR,PTR2,T,START1,START2,I;
LOGICAL8 [8] F.NAME;
ADDR T.LIB.DIR DIR1,DIR2;
ADDR[$LO8] DESC1,DESC2;
@BOX 2.1
OPEN.FILE(FILE.N, 0,-1,%1E);
PW1 => SEG2;
MAP(SEG2,-1,0);
MAKE(T.LIB.DIR,0,SEG1<<- SYS14.SEG.SHIFT) => DIR1;
SELECT DIR1^;
MAKE(T.LIB.DIR,0,SEG2<<- SYS14.SEG.SHIFT) => DIR2;
^NAMELIST => DESC1;
^NAMELIST OF DIR2^ => DESC2;
@BOX 3.1
-1 => PTR;
WHILE CODESEGS[1+>PTR] /= 0 DO OD
@BOX 4.1
-1 => PTR2;
WHILE CODESEGS[1+>PTR2]OF DIR2^ /= 0 DO
ACCESS[PTR2] OF DIR2^ => ACCESS[PTR];
SEG.SIZE[PTR2] OF DIR2^ => SEG.SIZE[PTR];
CODESEGS[PTR2]OF DIR2^ => CODESEGS[PTR];
1 +> PTR;
OD
FOR PTR < NO.OF.DIRS OF DIR2^ DO
PTR + NO.OF.DIRS => T;
FIRST.PROC [PTR] OF DIR2^ + NO.OF.PROCS => FIRST.PROC[T];
FIRST.TYPE [PTR] OF DIR2^ + NO.OF.TYPES => FIRST.TYPE[T];
OD
NO.OF.DIRS OF DIR2^ +> NO.OF.DIRS;
@BOX 5.1
FOR PTR < NO.OF.PROCS OF DIR2^ DO
P.PROPS[PTR]OF DIR2^ + NEXT.P => P.PROPS[NO.OF.PROCS];
1+>NO.OF.PROCS;
OD
FOR PTR < NO.OF.TYPES OF DIR2^ DO
T.PROPS[PTR] OF DIR2^ + NEXT.P => T.PROPS[NO.OF.TYPES];
1 +> NO.OF.TYPES;
OD
@BOX 6.1
FOR PTR < NEXTCH OF DIR2^ DO
DESC2^[PTR] => DESC1^[NEXTCH];
1 +> NEXTCH;
OD
@BOX 7.1
FOR PTR < NEXT.P OF DIR2^ DO
PROP.LIST[PTR]OF DIR2^ => PROP.LIST[NEXT.P];
1 +> NEXT.P
OD
@BOX 8.1
RELEASESEGMENT(SEG2);
@BOX 9.1
END
@END
@TITLE LIB02.8(2,11)
@COL 1S-2R-3T-4R-5R-7F
@FLOW 1-2-3Y-4-5-7
@FLOW 3N-7
@BOX 1.0
RELEASE LIBRARY
@BOX 2.0
FIND ENTRY IN LIBNAMES
@BOX 3.0
FOUND?
@BOX 4.0
RELEASE CODE SEGMENTS
SCRATCH SEGMENTS
AND DIRECTORY SEGMENT
[LIB02.8.2]
@BOX 5.0
DELETE ENTRIES IN
LIB.SEGS AND LIBNAMES
AND DECREMENT LIBS.OPEN
@BOX 7.0
END
@BOX 1.1
PROC RELEASE.LIB(LNAME);
INTEGER I,J,L,LIB.SEG,START.POS1,START.POS2,FILEN.SIZE,LNAME.SIZE;
LOGICAL32 K;
LOOK.UP.LNAME (LNAME) => I;
@BOX 3.1
IF I = LIBS.OPEN
@BOX 4.1
REL.LIB.PROG(I);
@BOX 5.1
1 -> LIBS.OPEN;
FOR J < LIBS.OPEN-I DO
   DIRY.SEGS[I+J+1] => DIRY.SEGS[I+J];
   16 * (I + J) => START.POS1 + 16 => START.POS2;
   FOR L < 16 DO
      LIB.F.NAMES [START.POS2 + L] => LIB.F.NAMES [START.POS1 + L];
   OD
OD
LIBS.OPEN * 16 => START.POS1;
FOR I < 16 DO
   0 => LIB.F.NAMES [START.POS1 + I];
OD
0 => DIRY.SEGS[LIBS.OPEN];
@BOX 7.1
END
@END
@TITLE LIB02.8.1(2,9)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
RELEASE TL SEGMENT
@BOX 2.0
RELEASE EACH MUSS
SEGMENT IN THIS
TL SEGMENT
@BOX 3.0
END
@BOX 1.1
PROC REL.TL.SEG (SEG, SEGSIZE);
@BOX 2.1
FOR SEG.SIZE +SYS14.SEGSIZE -1 ->> SYS14.SEG.SHIFT DO
RELEASE.SEGMENT(SEG);
1 +> SEG;
OD
@BOX 3.1
END
@END
@TITLE LIB02.8.2(2,10)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
RELEASE SEGMENTS OF A LIB/PROG
@BOX 2.0
USING DIRECTORY INFORMATION
RELEASE CODE SEGMENTS
AND SCRATCH SEGMENTS
OF A GIVEN LIBRARY OR PROGRAM
@BOX 3.0
RELEASE THE DIRECTORY SEGMENT
@BOX 4.0
END
@BOX 1.1
PROC REL.LIB.PROG(I);
INTEGER LIB.SEG,L;
LOGICAL32 K;
ADDR T.LIB.DIR LIB.DIR;
@BOX 2.1
DIRY.SEGS[I] => LIB.SEG;
::OMIT THIS SEQUENCE FROM XCOMPILE
MAKE(T.LIB.DIR,0,LIB.SEG <<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIBDIR^;
-1 => L;
WHILE CODE.SEGS [1+>L] => K /= 0 DO
   REL.TL.SEG (K&%7FFF,SEGSIZE[L]);
OD
-1 => L;
WHILE SCRATCH.SEGS[1+>L] /= 0 DO
REL.TL.SEG (SCRATCHSEGS[L], S.S.SIZE[L]);
OD
::END OF SEQUENCE
@BOX 3.1
RELEASE.SEGMENT(LIB.SEG);
@BOX 4.1
END
@END
@TITLE LIB02.9(2,6)
@COL 1S-3R-4F
@FLOW 1-3-4
@BOX 1.0
CUR.PROG
@BOX 3.0
NOTE PROG START ADDRESS
IN 'RUN.ADDR'
@BOX 4.0
END
@BOX 1.1
PROC CUR.PROG (ADDRESS);
@BOX 3.1
ADDRESS => RUN.ADDR;
@BOX 4.1
END
@END
@TITLE LIB02.10(2,10)
@COL 1S-2T-3R-4R-6R-7F
@FLOW 1-2Y-3-4-6-7
@FLOW 2N-6
@BOX 1.0
RUN (NAME)
@BOX 2.0
NAME GIVEN
@BOX 3.0
DELETE PREVIOUS CURRENT PROGRAM
@BOX 4.0
OPEN SPECIFIED PROGRAM
[LIB02.3.1]
AND NOTE AS CURRENT PROGRAM
@BOX 6.0
ENTER CURRENT PROGRAM
@BOX 7.0
END
@BOX 1.1
PROC RUN (NAME);
INTEGER I,J;
@BOX 2.1
IF SIZE (NAME) = 0
@BOX 3.1
FOR J < NO.OF.SEGS + 1 DO
   RELEASE.SEGMENT(CUR.PROG.SEGS[J]);
OD
-1 => NO.OF.SEGS;
IF DIRY.SEGS[NO.OF.LIBS] /= 0
   THEN REL.LIB.PROG(NO.OF.LIBS)
FI
@BOX 4.1
OPEN.LIB.OR.PROG(NAME,NO.OF.LIBS,0) => RUN.ADDR;
@BOX 6.1
IF RUN.ADDR /= 0 THEN
   TL.ENTER(RUN.ADDR);
FI
@BOX 7.1
END
@END
@TITLE LIB02.11(2,10)
@COL 1S-2R-3R-4R-5F
@FLOW 1-2-3-4-5
@BOX 1.0
ADD TYPE DEFN TO LIB
@BOX 2.0
SELECT DIRECTORY
@BOX 3.0
ENTER NAME AND FIELD TYPES
IN DIRECTORY [LIB02.5.1]
AND MAKE ENTRY
IN T.PROPS
@BOX 4.0
UPDATE NO.OF.TYPES
@BOX 5.0
END
@BOX 1.1
PROC ADD.TYPE(DIRY.SEG,NAME,FIELDS);
  INTEGER FIRST.CH;
   ADDR T.LIB.DIR LIB.DIR;
@BOX 2.1
MAKE(T.LIB.DIR,0,DIRY.SEG <<- SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
@BOX 3.1
NEXT.CH => FIRST.CH;
NEXT.P + ADD.N.AND.T(LIB.DIR,NAME,FIELDS) => T.PROPS[NO.OF.TYPES];
%80 !> NAMELIST [FIRST.CH];
@BOX 4.1
1 +> NO.OF.TYPES => ADD.TYPE;
@BOX 5.1
END
@END
@TITLE LIB02.12(2,11)
@COL 11R
@COL 1S-10T-6T-2T-3R-4R-8R-5F
@COL 7R-9N
@ROW 11-2-7
@FLOW 1-10N-6N-2Y-3-4-8-5
@FLOW 10Y-11-5
@FLOW 6Y-7-9-5
@FLOW 2N-4
@BOX 1.0
ADD SEGMENT
@BOX 6.0
SCRATCH SEGMENT?
@BOX 2.0
PRINCIPLE CODE SEGMENT?
@BOX 3.0
SET MARKER
@BOX 4.0
MAKE ENTRY IN
'CODE.SEGS'
AND 'CODE.FILES'
@BOX 7.0
NOTE NO AND
SIZE
@BOX 8.0
FILE AND RELEASE
THE GIVEN SEGMENT
@BOX 5.0
END
@BOX 10.0
CURRENT PROG?
@BOX 11.0
MAKE ENTRY IN
SEG TABLE
@BOX 1.1
PROC ADD.SEGMENT(DIR,C.SEG,R.SEG,AC,S.SIZE);
INTEGER I,J,K,START1,PTR;
LOGICAL8 TEMP;
ADDR T.LIB.DIR LIB.DIR;
MAKE(T.LIB.DIR,0,DIR<<-SYS14.SEG.SHIFT) => LIB.DIR;
SELECT LIB.DIR^;
::X ONLY R.SEG ->> TRGT.SEG.SHIFT => R.SEG;
::OMIT THIS SEQUENCE FROM XCOMPILE
R.SEG ->> SYS14.SEG.SHIFT => R.SEG;
::END OF SEQUENCE
@BOX 6.1
IF C.SEG = 0
@BOX 2.1
%7FFF &> R.SEG;
IF CODE.SEGS[0] /= 0
@BOX 3.1
%8000 !> R.SEG;
@BOX 4.1
-1 => I;
$WH CODESEGS[1+>I] /= 0 DO OD
R.SEG => CODE.SEGS[I];
S.SIZE => SEG.SIZE[I];
AC => ACCESS [I];
@BOX 7.1
-1 => I;
$WH SCRATCH.SEGS[1+>I] /= 0 DO OD
R.SEG => SCRATCH.SEGS[I];
S.SIZE => S.S.SIZE[I];
@BOX 8.1
"0" + NO.OF.TL.SEGS => CODE.FILE [F.N.SIZE - 2];
FOR J < S.SIZE + SYS14.SEG.SIZE - 1 ->> SYS14.SEG.SHIFT DO
"0" + J => CODE.FILE [F.N.SIZE - 1];
   FILE(PART (^CODE.FILE, 0, F.N.SIZE - 1), 0,C.SEG+J);
   RELEASE.SEGMENT(C.SEG+J);
OD
1 +> NO.OF.TL.SEGS;
@BOX 5.1
END
@BOX 10.1
IF DIR = 0
@BOX 11.1
R.SEG & %7FFF => CUR.PROG.SEGS[1+>NO.OF.SEGS];
@END
@TITLE LIB02.13(2,11)

@COL 1S-2T-3T-4R-5R-6T-7R-8F
@COL 9R
@ROW 7-9
@FLOW 1-2YES-3NO-4-5-6YES-7-8
@FLOW 2NO-9-8
@FLOW 3YES-9
@FLOW 6NO-3
@BOX 1.0
LOOK UP LIB (LIB SEG NUMBER)
@BOX 2.0
VALID LIB SEG NUMBER?
@BOX 3.0
ALL LIBRARIES SEARCHED?
@BOX 4.0
SELECT DIRECTORY
@BOX 5.0
COMPARE SEG NUMBERS
@BOX 6.0
MATCH?
@BOX 7.0
RETURN FILENAME IN PWW1
AND USER NAME IN PWW2
@BOX 8.0
END
@BOX 9.0
SEARCH FAIL
ZERO IN PWW1 AND PWW2
@BOX 1.1
PROC LOOK.UP.LIB (LIB.SEG);
INTEGER I, J, CS;
ADDR T.LIB.DIR LIB.DIR;
LITERAL / ADDR [LOGICAL8] NIL.BYTES =;
0 => I;
@BOX 2.1
IF LIB.SEG < 1 OR LIB.SEG >= SYS14.NO.OF.LOCAL.SEGS
@BOX 3.1
IF 1 +> I = LIBS.OPEN
@BOX 4.1
MAKE (T.LIB.DIR, 0, DIRY.SEGS [I] <<- SYS14.SEG.SHIFT)
   => LIB.DIR;
SELECT LIB.DIR^;
@BOX 5.1
-1 => J;
WHILE 1 +> J < NO.OF.CODESEGS AND CODE.SEGS [J] & %7FFF => CS /= LIB.SEG /= 0 DO
 OD
@BOX 6.1
IF J = 16 OR CS = 0
@BOX 7.1
16 *> I;
FOR J < 16 DO
   IF LIB.F.NAMES [I + J] /= 0, ->OUT
OD
OUT:PART (^LIB.F.NAMES, I + J, I + 15) => LOOK.UP.LIB;
@BOX 8.1
END
@BOX 9.1
NIL.BYTES => LOOK.UP.LIB;
@END

@TITLE LIB02.14(2,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
FIND FIELD OF TYPE
@BOX 2.0
USE SUBPROCEDURE
FIND.P.T [LIB02.2.1]
@BOX 3.0
END
@BOX 1.1
PROC FINDF(P1,P2,P3);
@BOX 2.1
FIND.P.T(P1,P2,P3,1) => FINDF;
@BOX 3.1
END
@END
@TITLE LIB02.15(2,11)
@COL 1S-2T-3T-4R-5R-6F
@COL 7R
@ROW 5-7
@FLOW 1-2FOUND-3FOUND-4-5-6
@FLOW 2NOT FOUND-7-6
@FLOW 3NOT FOUND-7-6
@BOX 1.0
LOOK UP N
@BOX 2.0
FIND AND SELECT DIRECTORY
@BOX 3.0
FIND REQUESTED NAME
@BOX 4.0
COPY NAME TO RESULT STRING
@BOX 5.0
SET RESULT=FIND.N INDEX
@BOX 6.0
END
@BOX 7.0
SET RESULT ZERO
@BOX 1.1
PROC LOOK.UP.N (INDEX,LNAME,NSTRING);
$IN PTR,T,PTR1,I,J,LIBSEG;
$LO64 FNAME,UNAME;
$AD T.LIB.DIR LIB.DIR;
@BOX 2.1
LOOK.UP.LNAME (LNAME) => I;
IF I < LIBS.OPEN THEN
   DIRY.SEGS[I] => LIBSEG;
   MAKE(T.LIB.DIR,0,LIBSEG<<-SYS14.SEG.SHIFT) => LIBDIR;
   SELECT LIBDIR^;
FI
IF I = LIBS.OPEN
@BOX 3.1
0 => PTR => T;
FOR INDEX -1 DO
IF PTR < NEXTCH THEN
      IF NAMELIST[PTR] & %80 /= 0 THEN 1+>T FI
      1 + NAMELIST[PTR] & %7F +> PTR;
   ELSE ->OUT;
   FI
OD
OUT: IF PTR = NEXTCH
@BOX 4.1
-1 => PTR1;
PTR-1 => J;
FOR NAMELIST[PTR]+1 & %7F DO
   NAMELIST[1+>J] => N.STRING^[1+>PTR1];
OD
@BOX 5.1
IF NAMELIST[PTR]&%80 = 0 THEN
    FNINDEX(I,INDEX-T,0, LIB.DIR) => LOOK.UP.N
    ELSE
    FNINDEX(I,T+1,1, LIBDIR) => LOOK.UP.N
FI
@BOX6.1
END
@BOX7.1
0 => LOOK.UP.N;
@END
@TITLE LIB02.17(2,10)

@COL 1S-2R-3R-4R-5T-6T-7R-8T-17T-10T-15R-11R-12R-16N
@COL 13R-14F-9R
@ROW 6-13
@ROW 12-9
@FLOW 1-2-3-4-5NO-6YES-7-8YES-17NO-10YES-15-11-12-16-5
@FLOW 5YES-13-14
@FLOW 6NO-17Y-5
@FLOW 8NO-5
@FLOW 10NO-9-16
@BOX 1.0
LIST LIB(LIB.NAME,PARAMS,SEARCH.STRING)
@BOX 2.0
DECLARATIONS
@BOX 3.0
INITIALISE POINTER TO
CURRENT PARAMETER TO
FIRST IN LIBRARY
@BOX 4.0
PRINT HEADING
@BOX 5.0
MOVE TO NEXT PROCEDURE IN LIBRARY
END OF LIBRARY ?
@BOX 6.0
IS PATTERN MATCHING SELECTED ?
@BOX 7.0
TRY AND MATCH CURRENT PROCEDURE
NAME WITH THE SEARCH STRING
#LIB02.17.2
@BOX 8.0
SUCCESSFUL MATCH ?
@BOX 9.0
PRINT PROCEDURE NAME
@BOX 10.0
ARE PARAMETER DETAILS REQUIRED ?
@BOX 11.0
DETERMINE NUMBER OF PARAMETERS
@BOX 12.0
DETERMINE AND PRINT TYPE OF
 EACH PARAMETER AND RESULT
#LIB02.17.1
@BOX 13.0
PRINT "END OF LIBRARY" MESSAGE
@BOX 14.0
END
@BOX 15.0
PRINT PROCEDURE NAME
@BOX 17.0
IS IT A TYPE
@BOX 1.1
PROC LIST.LIB (LIBRARY.NAME, SEARCH.STRING, PRINT.SWITCH);
@BOX 2.1
DATAVEC TYPE.NUMBERS($IN);
%20 %01 %03 %24 %28 %2C %30 %34 %38
END;
DATAVEC TSCALAR($LO8); "BOOLEAN" END;
DATAVEC TDATA($LO8); "DATA" END;
DATAVEC TUDAT($LO8); "UNB.DATA" END;
DATAVEC TPROC($LO8); "PROC" END;
DATAVEC TPROC.ENV($LO8); "PROC.ENV" END;
DATAVEC TLAB($LO8); "$$LA" END;
DATAVEC TLAB.ENV($LO8); "$$LA.ENV" END;
DATAVEC TLOG ($LO8); "$$LO" END;
DATAVEC TINT ($LO8); "$$IN" END;
DATAVEC TDESC ($LO8); "[C]" END;
DATAVEC TYPE.CODES (ADDR [$LO8])
   TSCALAR TDATA TUDAT TPROC TPROC.ENV
   TLAB TLAB.ENV TLOG TINT
END;
$LI / ADDR[$LO8] NIL = ;
$LI  / $IN TABLE.SIZE = 9;
$LO8 [50] PROC.NAME;
 $LO16 ENCODED.TYPE;
$IN MATCHED, INDEX, I, NO.OF.PARAMS,
  NAME.SIZE, MAX.LINE;
$IN32 FIND.N.INDEX;
@BOX 3.1
5 => MAX.LINE; 0 => INDEX;
@BOX 4.1
CAPTION (%"LIBRARY : ");
IF LIBRARY.NAME = NIL THEN
   CAPTION (%"SYSTEM");
ELSE
   CAPTION (LIBRARY.NAME);
FI
NEWLINES (1);
@BOX 5.1
IF LOOK.UP.N (1 +> INDEX, LIBRARY.NAME, ^PROC.NAME)
   => FIND.N.INDEX = 0
@BOX 6.1
PROC.NAME [0] & %7F => NAME.SIZE;
IF SEARCH.STRING = NIL
@BOX 7.1
#LIB02.17.2
@BOX 8.1
IF MATCHED /= 1
@BOX 9.1
IF MAX.LINE =< 0 THEN
   NEW.LINES (1);
   5 => MAX.LINE;
FI
1 -> MAX.LINE;
CAPTION (PART (^PROC.NAME, 1, NAME.SIZE));
IF NAME.SIZE >= 15 AND MAX.LINE > 0 THEN
   1 -> MAX.LINE;
   SPACES (30 - NAME.SIZE);
ELSE
   SPACES (15 - NAME.SIZE);
FI
@BOX 10.1
IF PRINT.SWITCH = 0
@BOX 11.1
FIND.P (FIND.N.INDEX,-1, 0) => NO.OF.PARAMS;
@BOX 12.1
OUT.CH (" ");
OUT.CH ("(");
FOR I < NO.OF.PARAMS + 1 DO
   IF I = NO.OF.PARAMS THEN
      SPACES (2);
      OUT.CH (")");
   FI
   FIND.P (FIND.N.INDEX, -1, I + 1) => ENCODED.TYPE;
   IF ENCODED.TYPE /= 0 THEN
      #LIB02.17.1
   FI
OD
NEWLINES (1);
@BOX 13.1
NEW.LINES (0);
CAPTION (%"PROCEDURES IN LIBRARY = ");
OUT.I (INDEX - 1, 0);
NEW.LINES (1);
@BOX 14.1
END
@BOX 15.1
CAPTION (PART (^PROC.NAME, 1, NAME.SIZE));
@BOX 17.1
IF PROC.NAME[0] & %80 /= 0
@END

@TITLE LIB02.17.1(2,10)

@COL 1S-2R-3T-4R-5R-6R-8F
@COL 7R
@ROW 4-7
@FLOW 1-2-3Y-7-8
@FLOW 3N-4-5-6-8
@BOX 1.0
PRINT PARAMETER TYPES
@BOX 2.0
SEARCH FOR SPECIAL MUTL
TYPE CODES IN TABLE
@BOX 3.0
TYPE FOUND IN TABLE ?
@BOX 4.0
PRINT SORT OF MUTL ENTITY
@BOX 5.0
DETERMINE, DECODE AND PRINT TYPE
@BOX 6.0
DETERMINE AND PRINT SIZE OF TYPE
@BOX 7.0
PRINT CORRESPONDING TYPE FROM TABLE
@BOX 8.0
END
@BOX 1.1
:: PRINT PARAMETER TYPES
BEGIN
INTEGER BITVALUES, VECTOR, FOUND,
   TYPE.INDEX;
@BOX 2.1
-1 => TYPE.INDEX;
0 => FOUND;
WHILE FOUND = 0 AND 1 +> TYPE.INDEX < TABLE.SIZE DO
   IF TYPE.NUMBERS [TYPE.INDEX] = ENCODED.TYPE THEN
   1 => FOUND;
   FI
OD
SPACES (2);
@BOX 3.1
IF FOUND = 1
@BOX 4.1
0 => VECTOR;
IF ENCODED.TYPE & 3 => BITVALUES & 1 /= 0 THEN
   OUT.CH ("^");
   IF BITVALUES = 3 THEN
      OUT.CH ("[");
      1 => VECTOR;
   FI
FI
@BOX 5.1
IF ENCODED.TYPE ->> 6 & 3 => BITVALUES = 0 THEN
   CAPTION (%"$$RE");
ELSE
   IF BITVALUES = 2 THEN
      CAPTION (%"$$LO");
   ELSE
      CAPTION (%"$$IN");
   FI
FI
@BOX 6.1
ENCODED.TYPE ->> 2 & %F =>BITVALUES;
OUT.I ((BITVALUES + 1) * 8, 0);
IF VECTOR = 1 THEN
   OUT.CH ("]");
FI
@BOX 7.1
IF TYPE.INDEX /= 0 THEN
   OUT.CH ("^");
FI
CAPTION (TYPE.CODES [TYPE.INDEX]);
@BOX 8.1
END
@END
@TITLE LIB02.17.2(2,10)

@COL 1S-2T-3T-4T-5F
@FLOW 1-2NO-3NO-4RUN OUT-5
@FLOW 2YES-5
@FLOW 3YES-5
@FLOW 4OK-3
@BOX 1.0
PATTERN MATCHING
@BOX 2.0
IS SEARCH STRING TOO LONG?
@BOX 3.0
PATTERN MATCH IN THIS POSITION ?
@BOX 4.0
TRY NEXT CHARACTER POSITION FOR MATCH
@BOX 5.0
END
@BOX 1.1
BEGIN ::PATTERN MATCHING
INTEGER WIDTH, OFFSET, NAME.PTR, CONTINUE;
0 => MATCHED;
1 => NAME.PTR;
-1 => OFFSET;
@BOX 2.1
IF SIZE (SEARCH.STRING) - 1 => WIDTH >= NAME.SIZE
@BOX 3.1
1 => CONTINUE;
WHILE CONTINUE = 1 AND 1 +> OFFSET =< WIDTH DO
   IF SEARCH.STRING^ [OFFSET] & %5F /=
      PROC.NAME [NAME.PTR + OFFSET] & %5F THEN
      0 => CONTINUE;
      -1 => OFFSET;
   FI
OD
IF CONTINUE => MATCHED = 1
@BOX 4.1
IF 1 +> NAME.PTR + WIDTH =< NAME.SIZE
@BOX 5.1
END
@END

@TITLE LIB02.18(2,11)
@COL 1S-2R-3R-4R-5R-6R-7R-8R-9R-10R-13T-14R-11R-12F
@FLOW 1-2-3-4-5-6-7-8-9-10-13Y-14-11-12
@FLOW 13N-11
@BOX 1.0
TRANSFORM DIRECTORY
@BOX 2.0
INITIALISE SEGMENTS
FOR OLD.DIR AND NEW.DIR
@BOX 3.0
TRANSFORM SCALARS
@BOX 4.0
TRANSFORM CODEFILES, CODESEGS
SEG SIZE, AND ACCESS
@BOX 5.0
TRANSFORM SCRATCH SEGS/SIZES
@BOX 6.0
TRANSFORM FIRST PROC
AND FIRST TYPE
@BOX 7.0
TRANSFORM P.PROPS
@BOX 8.0
TRANSFORM T.PROPS
@BOX 9.0
TRANSFORM PROP.LIST
@BOX 10.0
TRANSFORM NAMELIST
@BOX 11.0
FILE NEW DIRECTORY
@BOX 12.0
END
@BOX 13.0
IS CODEFILE TRANSFORMATION REQUIRED
@BOX 14.0
TRANSFORM CODE FILE
TO SPECIFIED SIZE
@BOX 1.1
PROC TRAN.DIR(OLD,NEW,MC.TYPE,C.SEG.SIZE);
INTEGER OLD.SEG,NEW.SEG,I;
ADDR T.LIB.DIR OLD.DIR,NEW.DIR;
PSPEC TRAN16(LOGICAL16,ADDR $IN16,INTEGER);
PSPEC TRAN32(LOGICAL32,ADDR $LO32,INTEGER);
#LIB02.18.1
#LIB02.18.2
@BOX 2.1
OPEN.FILE(OLD, 0,-1,%1E);
PW1 => OLD.SEG;
MAKE(T.LIB.DIR,0,OLD.SEG<<-SYS14.SEG.SHIFT) => OLD.DIR;
CREATE.FILE.SEGMENT(-1,8192,NEW, 0);
PW1 => NEW.SEG;
MAKE(T.LIB.DIR,0,NEW.SEG<<-SYS14.SEG.SHIFT) => NEW.DIR;
SELECT OLD.DIR^;
@BOX 3.1
TRAN.16(NEXT.CH,^NEXTCH OF NEWDIR^,MC.TYPE);
TRAN.16(NO.OF.PROCS,^NO.OF.PROCS OF NEWDIR^,MC.TYPE);
TRAN.16(NO.OF.TYPES,^NO.OF.TYPES OF NEWDIR^,MC.TYPE);
TRAN.16(NEXT.P,^NEXT.P OF NEWDIR^,MC.TYPE);
TRAN.16(NO.OF.DIRS,^NO.OF.DIRS OF NEWDIR^,MC.TYPE);
TRAN.16(NO.OF.TL.SEGS,^NO.OF.TL.SEGS OF NEWDIR^,MC.TYPE);
TRAN.16(D3,^D3 OF NEWDIR^,MC.TYPE);
TRAN.16(SIZE(NEW)+2,^F.N.SIZE OF NEWDIR^,MCTYPE);
@BOX 4.1
FOR I < SIZE(NEW) DO
   NEW^ [I] => CODE.FILE [I] OF NEW.DIR^;
OD
FOR I < NO.OF.CODE.SEGS DO
TRAN16(CODESEGS[I],^CODESEGS[I] OF NEWDIR^,MC.TYPE);
TRAN32(SEG.SIZE[I], ^SEG.SIZE[I] OF NEWDIR^, MC.TYPE);
ACCESS[I] => ACCESS[I] OF NEW.DIR^;
OD
@BOX 5.1
FOR I < NO.OF.SCR.SEGS DO
TRAN32(SCRATCH.SEGS[I],^SCRATCH.SEGS[I] OF NEWDIR^,MC.TYPE);
TRAN32(S.S.SIZE[I],^S.S.SIZE[I] OF NEWDIR^,MC.TYPE);
OD
@BOX 6.1
FOR I < NO.OF.MERGED.LIBS DO
TRAN16(FIRST.PROC[I],^FIRST.PROC[I] OF NEWDIR^,MC.TYPE);
TRAN16(FIRST.TYPE[I],^FIRST.TYPE[I] OF NEWDIR^,MC.TYPE);
OD
@BOX 7.1
FOR I < NO.OF.PROCS DO
TRAN16(P.PROPS[I],^P.PROPS[I] OF NEWDIR^,MC.TYPE);
OD
@BOX 8.1
FOR I < NO.OF.TYPES DO
TRAN16(T.PROPS[I],^T.PROPS[I] OF NEWDIR^,MC.TYPE);
OD
@BOX 9.1
FOR I < P.LIST.SIZE DO
PROP.LIST[I] => PROP.LIST[I] OF NEW.DIR^;
OD
@BOX 10.1
FOR I < N.LIST.SIZE DO
NAMELIST[I] => NAMELIST[I] OF NEW.DIR^;
OD
@BOX 11.1
RELEASE.SEGMENT(OLD.SEG);
FILE(NEW, 0, NEW.SEG);
RELEASE.SEGMENT(NEW.SEG);
@BOX 12.1
END
@BOX 13.1
IF C.SEG.SIZE = 0
@BOX 14.1
#LIB02.18.4
@END
@TITLE LIB02.18.1(2,11)
@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
TRANSFORM 16-BIT WORD
@BOX 3.0
COMPUTE BYTE DESCRIPTOR
FOR VALUE
@BOX 4.0
PRODUCE BYTE STRING FORM
OF VALUE FOR SPECIFIED
MACHINE
@BOX 5.0
END
@BOX 1.1
PROC TRAN.16(VALUE,PTR,MACHINE);
INTEGER I;
ADDR [LOGICAL8] BYTE.PTR;
@BOX 3.1
MAKE(LOGICAL8, 2, BYTE(PTR)) => BYTE.PTR;
@BOX 4.1
ALTERNATIVE MACHINE FROM
BEGIN
  VALUE & %FF => BYTE.PTR^[1];
  VALUE ->> 8 & %FF => BYTE.PTR^[0];
END
BEGIN
   VALUE & %FF => BYTE.PTR^[0];
   VALUE ->> 8 & %FF => BYTE.PTR^[1];
END
END
@BOX 5.1
END
@END

@TITLE LIB02.18.2(2,11)
@COL 1S-3R-4R-5F
@FLOW 1-3-4-5
@BOX 1.0
TRANSFORM 32-BIT WORD
@BOX 3.0
COMPUTE BYTE DESCRIPTOR
FOR VALUE
@BOX 4.0
PRODUCE BYTE STRING FORM
OF VALUE FOR SPECIFIED
MACHINE
@BOX 5.0
END
@BOX 1.1
PROC TRAN.32(VALUE,PTR,MACHINE);
INTEGER I;
ADDR [LOGICAL8] BYTE.PTR;
@BOX 3.1
MAKE(LOGICAL8, 4, BYTE(PTR)) => BYTE.PTR;
@BOX 4.1
ALTERNATIVE MACHINE FROM
BEGIN
   VALUE & %FF => BYTE.PTR^[3];
   VALUE ->> 8 & %FF => BYTE.PTR^[2];
   VALUE ->> 16 & %FF => BYTE.PTR^[1];
   VALUE ->> 24 & %FF => BYTE.PTR^[0];
END
BEGIN
   VALUE & %FF => BYTE.PTR^[0];
   VALUE ->> 8 & %FF => BYTE.PTR^[1];
   VALUE ->> 16 & %FF => BYTE.PTR^[2];
   VALUE ->> 24 & %FF => BYTE.PTR^[3];
END
END
@BOX 5.1
END
@END
@TITLE LIB02.18.4(2,11)
@COL 1S-2R-3R-4R-5R-6R-7R-9R-8R-10T-11F
@FLOW 1-2-3-4-5-6-7-9-8-10N-11
@FLOW 10Y-3
@BOX 1.0
BEGIN
@BOX 2.0
SET PTR TO CODE FILES
@BOX 3.0
COMPUTE NUMBER OF SEGMENTS
OCCUPIED BY A CODE FILE IN BOTH
HOST AND DESTINATION MACHINES
AND NEW CODEFILE NAME
@BOX 4.0
FOR EACH DESTINATION SEGMENT
@BOX 5.0
CREATE AN X.SEGMENT
@BOX 6.0
COPY BLOCKS FROM HOST SEGMENTS
OPENING NEW HOST SEGMENTS
AS NECESSARY
@BOX 7.0
IF < 64K CONVERT TO NON-X SEGMENT
FILE AND RELEASE SEGMENT
@BOX 8.0
ALTER NAME IN DIRECTORY
@BOX 9.0
REPEAT FROM 4
@BOX 10.0
ANY MORE CODE FILES TO CONVERT
@BOX 11.0
END
@BOX 1.1
BEGIN
INTEGER PTR,H.SEGS,D.SEGS,I,IN.SEG,OUTSEG,IN.BLK,OUT.BLK,IN.SIZE,OUT.SIZE,LAST.O
LD, LAST.NEW,SEG;
ADDR[$LO8] NEW.F, OLD.F;
LOGICAL8 [16] NEW.LIB.NAME, C.FILE;
LOGICAL8  CH;
@BOX 2.1
F.N.SIZE - 1 => LAST.OLD; SIZE(NEW) + 1 => LAST.NEW;
PART(^C.FILE, 0, LAST.OLD) => OLD.F;
PART(^NEW.LIB.NAME, 0, LAST.NEW) => NEW.F;
FOR I < LAST.OLD +1 DO
CODEFILE[I] => C.FILE[I] OD
FOR I < LAST.NEW - 1 DO
NEW^[I] => NEW.LIB.NAME[I] OD
0 => PTR;
CAP(%"OLD-");CAP(OLD.F);CAP(%"-NEW-");CAP(NEWF);CAP(%"-$L");
@BOX 3.1
SEG.SIZE[PTR] + C.SEG.SIZE - 1/C.SEG.SIZE => D.SEGS;
SEG.SIZE[PTR] + SYS14.SEG.SIZE - 1 ->> SYS14.SEG.SHIFT => H.SEGS;
PTR + "0" => NEW.F^[LAST.NEW -1] => OLD.F^[LAST.OLD-1];
"0" => OLD.F^[LAST.OLD];
@BOX 4.1
0 => INSIZE;
-1 => INBLK => INSEG;
FOR I < D.SEGS DO
@BOX 5.1
"0" + I => NEW.F^[LAST.NEW];
C.SEG.SIZE+SYS14.PAGE.SIZE -1 ->>SYS14PAGE.SHIFT => OUTSIZE;
IF OUTSIZE = SYS.14.SEG.SIZE THEN
   CREATE.FILE.SEGMENT(-1,OUT.SIZE,NEW.F,0);
ELSE
   CREATE.FILE.X.SEGMENT(OUT.SIZE,NEW.F,0);
FI
PW1 => OUT.SEG;
@BOX 6.1
FOR OUTBLK<OUTSIZE DO
IF 1 +> INBLK = INSIZE THEN
   RELEASESEGMENT(INSEG);
   OPEN.FILE(OLD.F, 0, -1, %1E);
1 +> OLD.F^[LAST.OLD];
   PW1 => INSEG; PW2+SYS14.PAGE.SIZE-1 ->> SYS14.PAGE.SHIFT => INSIZE;
   IF PW0  /= 0 THEN
      CHANGE.SIZE(OUT.SEG,OUT.BLK <<- SYS14.PAGE.SHIFT);
   -> OUT;
   FI
   0 => INBLK;
FI
COPYBLOCK (INSEG,INBLK,OUTSEG,OUTBLK);
OD
OUT:
@BOX 7.1
IF C.SEG.SIZE =< %10000 THEN
   CREATE.SEGMENT(-1,C.SEG.SIZE);
   PW1 => SEG;
   FOR OUTBLK < OUTSIZE DO
      COPYBLOCK(OUTSEG,OUTBLK,SEG,OUTBLK);
   OD
   RELEASE.SEGMENT(OUTSEG);
   SEG => OUTSEG;
FI
CAP(%"FILE OLD-");CAP(OLD.F);CAP(%"-NEW-");CAP(NEW.F);CAP(%"-$L");
FILE(NEW.F, 0, OUTSEG);
RELEASE.SEGMENT(OUTSEG);
@BOX 8.1
@BOX 9.1
OD
@BOX 10.1
IF CODESEGS[1+>PTR] /= 0
@BOX 11.1
RELEASE.SEGMENT (INSEG);
END
@END
@TITLE LIB02.19(2,10)
@COL 1S-2R-3R-4T-5R-6T-7R-8F
@COL 9R
@ROW 7-9
@FLOW 1-2-3-4FOUND-5-6NO-7-8
@FLOW 6YES-3
@FLOW 4NOT FOUND-9-8
@BOX 1.0
LINK (NAMES, ADDRESSES)
@BOX 2.0
SET POINTERS TO
DEAL WITH CONSECUTIVE
ENTRIES IN
NAMES/ADDRESSES
@BOX 3.0
FORM A POINTER
TO A NAME
@BOX 4.0
OBTAIN THE FINDN
INDEX OF THE NAME
@BOX 5.0
COMPUTE A PROCEDURE
ADDRESS AND STORE
IT IN ADDRESSES
@BOX 6.0
ANY MORE NAMES
@BOX 7.0
RETURN 0 RESULT
@BOX 8.0
END
@BOX 9.0
RETURN -1 RESULT
@BOX 1.1
PROC LINK (NAMES, ADDRESSES);
INTEGER N.PTR, A.PTR, I,J, Z;
LOGICAL32 INDEX;
$LO8[50] NCOPY;
@BOX 2.1
SIZE (ADDRESSES) - 1 => Z;
-1 => I => A.PTR;
@BOX 3.1
I => N.PTR;
WHILE NAMES^[1 +> N.PTR] =< " " DO OD
N.PTR-1 => I;-1 => J;

WHILE NAMES^[1 +> I] => NCOPY[1+>J] > " " DO OD
@BOX 4.1
IF FINDN (PART (^NCOPY, 0, J - 1),0) => INDEX = 0
@BOX 5.1
ADDR.PROC (INDEX) =>PP OF  ADDRESSES^[1 +> A.PTR];
@BOX 6.1
IF A.PTR < Z
@BOX 7.1
0 => LINK;
@BOX 8.1
END
@BOX 9.1
-1 => LINK;
@END
@TITLE LIB02.20(2,11)
@COL 1S-2R-3R-4F
@FLOW 1-2-3-4
@BOX 1.0
PROC GET FILEN (NAME)
@BOX 2.0
FIND FIRST CHAR
OF FILE NAME
@BOX3.0
RETURN INDEX OF
FIRST CHAR
@BOX 4.0
END
@BOX 1.1
PROC GET.FILEN (NAME);
INTEGER  I,J,MAXCH;
LOGICAL8 CH;
-1 => J;
@BOX 2.1
SIZE (NAME) => MAXCH;
FOR I < MAXCH DO
   IF NAME^ [I] => CH = ":" OR CH = "/" THEN
      I => J;
   FI
OD
@BOX 3.1
MAXCH - (J + 1) => PW1;
MAXCH => GET.FILEN;
@BOX 4.1
END
@END
@TITLE LIB02.21(2,11)
@COL 1S-2R-3T-4R-6R-7F
@COL 5R
@ROW 4-5
@FLOW 1-2-3NO-4-6-7
@FLOW 3YES-5-6
@BOX 1.0
PROC LOOK UP NAME (LIB NAME)
@BOX 2.0
GET FILE NAME
@BOX 3.0
NAME > 16 CHAR?
@BOX 4.0
LOOK UP NAME
IN OPEN LIB TABLE
@BOX 5.0
NOT FOUND
@BOX 6.0
RETURN INDEX TO TABLE
@BOX 7.0
END
@BOX 1.1
PROC LOOK.UP.LNAME (LNAME);
INTEGER FILEN.SIZE,LNAME.SIZE,I,J,START, N.END, NAME.START;
@BOX 2.1
GET.FILEN (LNAME) => LNAME.SIZE;
PW1 => FILEN.SIZE;
@BOX 3.1
IF FILEN.SIZE > 16
@BOX 4.1
LNAME.SIZE - FILEN.SIZE => NAME.START;
FOR I < LIBS.OPEN DO
   I * 16 => START;
      FOR J < FILEN.SIZE  DO
         IF LNAME^ [NAME.START + J] /= LIB.F.NAMES [START + J], ->NEXT
      OD
      IF LIB.F.NAMES [START + J] = 0, -> OUT;
      NEXT:
OD
OUT:
@BOX 5.1
LIBS.OPEN => I;
@BOX 6.1
I => LOOK.UP.LNAME;
@BOX 7.1
END
@END

