.COMMENT RMS/Pascal interface documentation file .COMMENT .COMMENT Kurt W. Papke .COMMENT ES&T - Bldg 518 .COMMENT 3M Center .COMMENT St Paul, MN. 55101 .COMMENT (612) 733-8307 .COMMENT .TITLE ########RMSPAS User's Manual .TAB STOPS 9,17,25,33,41,49,57,65 .PERIOD .AUTOPARAGRAPH .PAPER SIZE 60,75 .LEFT MARGIN 8 .LITERAL File: Dr:[7,37]RmsPas.Rno Author: Kurt W. Papke Date: November 24, 1980 .END LITERAL .SKIP 10 .CENTER 75 R M S P A S .SKIP 5 .CENTER 75 U S E R M A N U A L .PAGE .HL 1 ^&Introduction^\ When using RMS with OMSI Pascal, the user has a choice of two levels of interface. The lower level interface (RMS/Pascal) to RMS is described in this document. The higher level interface (PRM) is described in document PRMPas.Doc. RMS/Pascal interface allows control of RMS on the same level as the Macro-11 interface. The user has complete access to all RMS control fields and therefore must be careful to properly load all the necessary fields before performing any file or record operation. PRM (Pascal Record Management) is a higher level interface that loads the necessary fields for the user. PRM has more overhead (refer to PRM document) but eases the burden on the user to remember the necessary steps in accessing RMS files. By design this document is very sketchy. For further information pertaining to usage of the RMS calls the "RMS Macro Programmer's Guide" should be consulted. .HL 1 ^&Interface Contents^\ The interface is composed of three elements: .LIST 1 .LE A set of Pascal CONSTants equivalent to the RMS Macro constants. .LE A set of Pascal TYPEs equivalent to the RMS Macro FAB and RAB data types plus a few needed utility types. .LE A set of Macro procedures callable from Pascal that perform the RMS file and record primitives. .END LIST The constant and type declarations must be included in the Pascal source code. The primitive procedures may either be included as source or task-built in from a library as external procedures. .HL 2 Constant Declarations The file containing the RMS constants is named "RMSCONST.PAS". It may be included at compile time with SLP or some other "include" processor, or it may be inserted statically with an editor. RMS Macro constants for referencing FAB or RAB contents take the form respectively of "FB$xxx" and "RB$xxx". The form of the corresponding Pascal constants are "FBxxx" and "RBxxx" since the Pascal language does not allow dollar signs to be imbedded in identifiers. As examples, the Macro symbol "FB$FIX" becomes "FBFIX" in Pascal and "RB$EOF" becomes "RBEOF". The list of constants is complete for all fields in the FAB and RAB with the exception of the STS field. The numerous error codes which may be returned by RMS may be added to the user source file at his/her discretion, or they may be referred to numerically. .HL 2 Type Declarations The interface type declarations are contained in three files: "RMSTYPE.PAS", "FAB.PAS" and "RAB.PAS". These files may be inserted in the same manner as the constant declarations. The "RMSTYPE.PAS" file contains declarations that are used for both the FAB and RAB, such as bytes, words, doublewords, etc. There are several data types in the FAB and RAB declarations which must be entered by the user. They are: .LIST 1 .LE _^Filestring - the FAB requires a pointer to the user file name string which must be initialized by the user. The data type is commonly defined as "ARRAY [1..15] OF CHAR". .LE _^Datarecord - the RAB requires pointers to the user record buffer. The data type is commonly a record, possibly with variants if multiple files are being accessed. .LE _^Keystring - the RAB requires a pointer to a key buffer when accessing indexed files in random mode. The data type to be defined by the user depends upon the types of keys used. .END LIST Fields within the FAB and RAB data structures are accessed as normal Pascal record types. Note that data types must agree on assignments. All constants are defined as integers and many of the FAB and RAB elements are CHAR. For instance to set a FAB "org" field (defined as type BYTE = CHAR) an assignment such as "Fab.org := chr(fbseq)". .HL 2 Primitive Procedures The primitive procedures are divided into three categories: initialization, file operations and record operations. The primitives are commonly accessed as external procedures from the library file "RMSPAS.OLB". All primitives begin with the three letters "RMS" and end with the first three characters of the Macro primitive without the dollar sign. For example "$OPEN" becomes "rmsope", "$GET" becomes "rmsget", etc. .HL 3 Initialization There is only one initialization routine, "rmsini". It has no parameters. The routine calls the RMS initialization routine "$INIT" and sets up the GSA routine (see the section on buffer management). "Rmsini" also contains the "ORG$", which is currently set up to allow all sequential and indexed file operations, but no relative operations. .HL 3 File Operations There are three file operation primitives provided, all of which require the FAB as a "VAR" parameter. They are: .LIST 1 .LE "rmsclo" - does a "$CLOSE" .LE "rmscre" - does a "$CREATE" .LE "rmsope" - does a "$OPEN" .END LIST There are three additional RMS file operations that are not provided by the interface: "$DISPLAY", "$ERASE" and "$EXTEND". These haved not been required to date, however they may be added to the library as needed by the user. Although the "rmscre" primitive is provided it is currently able to create only sequential files, the reason being that an XAB data structure is not provided in the interface to allow key specifications. All applications to date have used only indexed files which were previously created using the RMS utility program "RMSDEF". There is nothing in the structure of the interface however to prevent the extension to providing XAB's to allow users to create indexed files on the fly. .HL 3 Record Operations There are nine record operation primitives provided by the interface, all of which require the RAB as a "VAR" parameter. They are: .LIST 1 .LE "rmscon" - does a "$CONNECT" .LE "rmsdel" - does a "$DELETE" .LE "rmsdis" - does a "$DISCONNECT" .LE "rmsfin" - does a "$FIND" .LE "rmsflu" - does a "$FLUSH" .LE "rmsget" - does a "$GET" .LE "rmsput" - does a "$PUT" .LE "rmsrew" - does a "$REWIND" .LE "rmsupd" - does a "$UPDATE" .END LIST There are four additional RMS record operations that are not provided by the interface. They are: "$FREE", "$NXTVOL", "$TRUNCATE" and "$WAIT". These haved not been required to date, however they may be added to the library as needed by the user. .HL 1 ^&Buffer Management^\ The RMS/Pascal interface employs the Pascal Heap for dynamic buffer allocation. The "rmsini" call to initialize RMS sets up a GSA routine which maps all RMS requests for buffer space to calls to the Pascal Operating-Time-System ($NEW and $DISPOSE). There are three ramifications of this technique: .LIST 1 .LE The user does not have to hassle with the formulas for buffer allocation. All buffers are obtained transparently to the Pascal program. .LE As of release 1.2 of the OMSI compiler the task will automatically extend itself if it runs out of heap space up to the limit set by MAXEXT. Note however that the task will NOT shrink as RMS gives up the buffers. .LE The GSA routine makes its requests for space to an internal routine which will NOT abort the task if the MAXEXT limit of the task is reached. Rather the GSA routine returns an error to RMS which in return sets the STS field in the FAB or RAB to ER$DME (-480.), hopefully allowing the task to recover gracefully !! .END LIST .HL 1 ^&FAB and RAB Initialization^\ The user must initialize ALL fields in the FAB's and RAB's used in his/her programs except for the "bid" and "bln" fields. Since these are the same for all programs, they are initialized by the "RmsOpe" and "RmsCon" procedures. .APPENDIX ^&RMSCONST.PAS^\ .LEFT MARGIN 8 .NOFILL .NOJUSTIFY fbdel = 4B; { fab fac field: delete access } fbget = 2B; { fab fac field: get access } fbput = 1B; { fab fac field: put access } fbrea = 42B; { fab fac field: read access } fbtrn = 20B; { fab fac field: truncate access } fbupd = 10B; { fab fac field: update access } fbwrt = 41B; { fab fac field: write access } fbctg = 200B; { fab fop field: contiguous file } fbdfw = 20000B; { fab fop field: deferred write } fbdlk = 20B; { fab fop field: unlock } fbfid = 10000B; { fab fop field: open by file id } fbmkd = 4000B; { fab fop field: mark for delete } fbnef = 1000B; { fab fop field: no EOF on magtape } fbpos = 10B; { fab fop field: position to last file } fbrwc = 2B; { fab fop field: rewind mag tape on close } fbrwo = 1B; { fab fop field: rewind mag tape on open } fbsup = 400B; { fab fop field: supersede if explicit vrsn } fbtmd = 6000B; { fab fop field: temp file - delete on close } fbtmp = 2000B; { fab fop field: temp file - no delete } fbseq = 0; { fab org field: sequential } fbrel = 20B; { fab org field: relative } fbidx = 40B; { fab org field: indexed } fbfix = 1B; { fab rfm field: fixed length records } fbwrt = 41B; { fab shr field: write sharing } rbkey = 1B; { rab rac field: random access } rbrfa = 2B; { rab rac field: record's file address } rbseq = 0; { rab rac field: sequential access } rbeof = 1B; { rab rop field: position to eof for append } rbfdl = 10000B; { rab rop field: fast delete } rbkge = 2000B; { rab rop field: >= key value } rbkgt = 4000B; { rab rop field: > key value } rbmas = 2B; { rab rop field: mass insert } rbloa = 20B; { rab rop field: obey fill numbers on load } rbloc = 100B; { rab rop field: locate mode (vs. move mode } ereof = -592; { rab sts field: end-of-file } .APPENDIX ^&RMSTYPE.PAS^\ .LEFT MARGIN 8 .NOFILL .NOJUSTIFY byte = char; word = integer; doubleword = { 2 words (VBN) } RECORD low : word; high : word END; { doubleword record } tripleword = { 3 words (RFA) } RECORD low : word; middle : word; high : word END; { tripleword record } fabptr = _^fabrec; { pointer to fab } .APPENDIX ^&FAB.PAS^\ .LEFT MARGIN 8 .NOFILL .NOJUSTIFY fabrec = RECORD bid : byte; { Fab identifier } bln : byte; { Rab length } ctx : word; { Available to user } ifi : word; { Pointer to ifab } sts : word; { Completion code } stv : word; { More error information } alq : doubleword; { Allocation quantity } deq : word; { * Automatic extension quantity } fac : byte; { Types of record operations } shr : byte; { File sharing } fop : word; { File processing options } rtv : byte; { Window size } org : byte; { * File organization } rat : byte; { * Record attributes } rfm : byte; { * Record format } xab : word; { Pointer to first xab } bpa : word; { Location of private I/O buffer } bps : word; { Size of private I/O buffer } mrs : word; { * Maximum record size } mrn : doubleword; { * Maximum record number } jnl : word; { Undocumented field (journal?) } nam : word; { Pointer to nam block } fna : _^filestring; { Location of filespec } dna : word; { Location of filepsec defaults } fns : byte; { Size of filespec } dns : byte; { Size of filespec defaults } bls : word; { * Block size } fsz : byte; { * Size of fixed area for VFC } bks : byte; { * Bucket size } dev : byte; { Device characteristics } lch : byte; { Logical channel } jnk : ARRAY [1..34B] OF char END; { fab rec } .SKIP 2 * Indicates field filled in by RMS on file open (RmsOpe) .APPENDIX ^&RAB.PAS^\ .LEFT MARGIN 8 .NOFILL .NOJUSTIFY rabrec = RECORD bid : byte; { rab block identifier } bln : byte; { rab block length } ctx : word; { user defineable area } isi : word; { pointer to irab } sts : word; { completion status code } stv : word; { status value } rfa : tripleword; { record's file address } rac : byte; { record access mode } ksz : byte; { key buffer size } rop : word; { record processing options } usz : word; { input record buffer size } ubf : _^datarecord; { input record buffer address } rsz : word; { size of output record } rbf : _^datarecord; { output record address } kbf : _^keystring; { key buffer address } krf : byte; { key of reference } mbf : byte; { multibuffer count } mbc : byte; { multiblock count } jnk1 : byte; { not used } rhb : word; { fixed control area buffer } fab : fabptr; { fab address } bkt : doubleword; { record number or VBN } jnk2 : ARRAY [1..46B] OF byte; { not used } END{ rab record } .APPENDIX ^&Example RMS Pascal Program^\ .LEFT MARGIN 8 .NOFILL .NOJUSTIFY PROGRAM RMSPRG; { Program to demonstate use of the RMS/Pascal interface. Echoes lines typed on the terminal until ctrl Z (end-of-file). } CONST fbdel = 4B; { fab fac field: delete access } fbget = 2B; { fab fac field: get access } fbput = 1B; { fab fac field: put access } fbrea = 42B; { fab fac field: read access } fbtrn = 20B; { fab fac field: truncate access } fbupd = 10B; { fab fac field: update access } fbwrt = 41B; { fab fac field: write access } fbctg = 200B; { fab fop field: contiguous file } fbdfw = 20000B;{ fab fop field: deferred write } fbdlk = 20B; { fab fop field: unlock } fbfid = 10000B;{ fab fop field: open by file id } fbmkd = 4000B; { fab fop field: mark for delete } fbnef = 1000B; { fab fop field: no EOF on magtape } fbpos = 10B; { fab fop field: position to last file } fbrwc = 2B; { fab fop field: rewind mag tape on close } fbrwo = 1B; { fab fop field: rewind mag tape on open } fbsup = 400B; { fab fop field: supersede if explicit vrsn } fbtmd = 6000B; { fab fop field: temp file - delete on close } fbtmp = 2000B; { fab fop field: temp file - no delete } fbseq = 0; { fab org field: sequential } fbrel = 20B; { fab org field: relative } fbidx = 40B; { fab org field: indexed } fbfix = 1B; { fab rfm field: fixed length records } rbkey = 1B; { rab rac field: random access } rbrfa = 2B; { rab rac field: record's file address } rbseq = 0; { rab rac field: sequential access } rbeof = 1B; { rab rop field: position to eof for append } rbfdl = 10000B;{ rab rop field: fast delete } rbkge = 2000B; { rab rop field: >= key value } rbkgt = 4000B; { rab rop field: > key value } rbmas = 2B; { rab rop field: mass insert } rbloa = 20B; { rab rop field: obey fill numbers on load } rbloc = 100B; { rab rop field: locate mode (vs. move mode } ereof = -592; { rab sts field: end-of-file } TYPE byte = char; word = integer; doubleword = { 2 words (VBN) } RECORD low : word; high : word END; { doubleword record } tripleword = { 3 words (RFA) } RECORD low : word; middle : word; high : word END; { tripleword record } fabptr = _^fabrec; { pointer to fab } fabrec = RECORD bid : byte; { Fab identifier } bln : byte; { Rab length } ctx : word; { Available to user } ifi : word; { Pointer to ifab } sts : word; { Completion code } stv : word; { More error information } alq : doubleword; { Allocation quantity } deq : word; { * Automatic extension quantity } fac : byte; { Types of record operations } shr : byte; { File sharing } fop : word; { File processing options } rtv : byte; { Window size } org : byte; { * File organization } rat : byte; { * Record attributes } rfm : byte; { * Record format } xab : word; { Pointer to first xab } bpa : word; { Location of private I/O buffer } bps : word; { Size of private I/O buffer } mrs : word; { * Maximum record size } mrn : doubleword; { * Maximum record number } jnl : word; { Undocumented field (journal?) } nam : word; { Pointer to nam block } fna : _^filestring; { Location of filespec } dna : word; { Location of filepsec defaults } fns : byte; { Size of filespec } dns : byte; { Size of filespec defaults } bls : word; { * Block size } fsz : byte; { * Size of fixed area for VFC } bks : byte; { * Bucket size } dev : byte; { Device characteristics } lch : byte; { Logical channel } jnk : ARRAY [1..34B] OF char END; { fab rec } rabrec = RECORD bid : byte; { rab block identifier } bln : byte; { rab block length } ctx : word; { user defineable area } isi : word; { pointer to irab } sts : word; { completion status code } stv : word; { status value } rfa : tripleword; { record's file address } rac : byte; { record access mode } ksz : byte; { key buffer size } rop : word; { record processing options } usz : word; { input record buffer size } ubf : _^datarecord; { input record buffer address } rsz : word; { size of output record } rbf : _^datarecord; { output record address } kbf : _^keystring; { key buffer address } krf : byte; { key of reference } mbf : byte; { multibuffer count } mbc : byte; { multiblock count } jnk1 : byte; { not used } rhb : word; { fixed control area buffer } fab : fabptr; { fab address } bkt : doubleword; { record number or VBN } jnk2 : ARRAY [1..46B] OF byte { not used } END; { rab record } filestring = ARRAY [1..3] OF char; datarecord = ARRAY [1..80] OF char; keystring = integer; { dummy data type } VAR fab:fabrec; rab:rabrec; filename : filestring; buffer : datarecord; PROCEDURE rmsini; EXTERNAL; PROCEDURE rmsope(VAR fab : fabrec); EXTERNAL; PROCEDURE rmscon(VAR rab : rabrec); EXTERNAL; PROCEDURE rmsget(VAR rab : rabrec); EXTERNAL; PROCEDURE rmsput(VAR rab : rabrec); EXTERNAL; PROCEDURE rmsclo(VAR fab : fabrec); EXTERNAL; .PAGE BEGIN { rmsprg } rmsini; { Init RMS } filename := 'TI:'; { Set the file name } fab.fna := @filename; { Set the file name pointer } fab.fns := chr(3); { Set the file name length } fab.lch := chr(7); { Set the LUN } rmsope(fab); { Open the file } IF fab.sts <> 1 THEN writeln('$OPEN error. STS: ',fab.sts:1, ' STV: ',fab.stv:1); rab.usz := 80; { Set user buffer size } rab.ubf := @buffer; { Set user buffer address } rab.rsz := 80; { Set record buffer size } rab.rbf := @buffer; { Set record buffer address } rab.fab := @fab; { set FAB address } rmscon(rab); { Connect access stream } IF rab.sts <> 1 THEN writeln('$CONNECT error. STS: ',rab.sts:1, ' STV: ',rab.stv:1); REPEAT rmsget(rab); { Get a line from the terminal } writeln(buffer:72) { Echo it back out } UNTIL rab.sts <> 1; writeln('$GET error. STS: ',rab.sts:1, ' STV: ',rab.stv:1); END. { rmsprg } .APPENDIX ^&Example RMS Pascal Program^\ .LEFT MARGIN 0 .NOFILL .NOJUSTIFY PROGRAM Spell; { * Program to demonstate use of the RMS/Pascal interface. * Performs a rudimentary spelling check on a text file. * * Spelling checking is done by looking up each word of the input file * in a dictionary file. If the word is in the dictionary, the * spelling is correct. If the word is not in the dictionary, the * operator is asked if the word is spelled correctly. If he answers * affirmatively, the word is added to the dictionary. * * The dictionary file contains three fields: * * Key: A character string of "MaxWord" length. This is the * actual word. It is the primary key of the indexed * file. * Usage: An integer with value = (9999-number times accessed) * This program only initializes this field, but does * not update it. This is a hook which will allow a * caching algorithm to be implemented at a later time. * * Verifier: The initials of the person who verified (with * Datatrieve) that the spelling of this dictionary * entry was correct. * * This program requires the following task-build commands: * * >TKB * TKB_>SPELL/CP/FP=SPELL,RMSPAS/LB,PASLIB/LB,RMSLIB/LB * TKB_>/ * TKB_>UNITS=7 * TKB_>TASK=...SPE * TKB_>// * _> * * The ordering of the input files to TKB is important. If Paslib and * Rmslib are reversed multiple definitions of the core allocation * routines will result * * Note that as with all programs using the RMS/Pascal interface the * dictionary must be pre-defined with RMSDEF, RMSDFN or Datatrieve. } CONST MaxWord = 26; { Maximum word length for spelling check } FileNameLength = 15; {-- RMS symbol definitions --} fbdel = 4B; { Fab fac field: delete access } fbget = 2B; { Fab fac field: get access } fbput = 1B; { Fab fac field: put access } fbrea = 42B; { Fab fac field: read access } fbtrn = 20B; { Fab fac field: truncate access } fbupd = 10B; { Fab fac field: update access } fbwrt = 41B; { Fab fac field: write access } fbctg = 200B; { Fab fop field: contiguous file } fbdfw = 20000B;{ Fab fop field: deferred write } fbdlk = 20B; { Fab fop field: unlock } fbfid = 10000B;{ Fab fop field: open by file id } fbmkd = 4000B; { Fab fop field: mark for delete } fbnef = 1000B; { Fab fop field: no EOF on magtape } fbpos = 10B; { Fab fop field: position to last file } fbrwc = 2B; { Fab fop field: rewind mag tape on close } fbrwo = 1B; { Fab fop field: rewind mag tape on open } fbsup = 400B; { Fab fop field: supersede if explicit vrsn } fbtmd = 6000B; { Fab fop field: temp file - delete on close } fbtmp = 2000B; { Fab fop field: temp file - no delete } fbseq = 0; { Fab org field: sequential } fbrel = 20B; { Fab org field: relative } fbidx = 40B; { Fab org field: indexed } fbfix = 1B; { Fab rfm field: fixed length records } rbkey = 1B; { Rab rac field: random access } rbrfa = 2B; { Rab rac field: record's file address } rbseq = 0; { Rab rac field: sequential access } rbeof = 1B; { Rab rop field: position to eof for append } rbfdl = 10000B;{ Rab rop field: fast delete } rbkge = 2000B; { Rab rop field: _>= key value } rbkgt = 4000B; { Rab rop field: _> key value } rbmas = 2B; { Rab rop field: mass insert } rbloa = 20B; { Rab rop field: obey fill numbers on load } rbloc = 100B; { Rab rop field: locate mode (vs. move mode } ereof = -592; { Rab sts field: end-of-file } errnf = -1472;{ Rab sts field: record not found } TYPE Byte = char; Word = integer; DoubleWord = { 2 words (VBN) } RECORD Low : Word; High : Word END; { doubleword record } TripleWord = { 3 words (RFA) } RECORD Low : Word; Middle : Word; High : Word END; { tripleword record } Fabptr = ^Fabrec; { pointer to Fab } Fabrec = RECORD bid : byte; { Fab identifier } bln : byte; { Rab length } ctx : word; { Available to user } ifi : word; { Pointer to iFab } sts : word; { Completion code } stv : word; { More error information } alq : doubleword; { Allocation quantity } deq : word; { * Automatic extension quantity } fac : byte; { Types of record operations } shr : byte; { File sharing } fop : word; { File processing options } rtv : byte; { Window size } org : byte; { * File organization } rat : byte; { * Record attributes } rfm : byte; { * Record format } xab : word; { Pointer to first xab } bpa : word; { Location of private I/O buffer } bps : word; { Size of private I/O buffer } mrs : word; { * Maximum record size } mrn : doubleword; { * Maximum record number } jnl : word; { Undocumented field (journal?) } nam : word; { Pointer to nam block } fna : _^filestring; { Location of filespec } dna : word; { Location of filepsec defaults } fns : byte; { Size of filespec } dns : byte; { Size of filespec defaults } bls : word; { * Block size } fsz : byte; { * Size of fixed area for VFC } bks : byte; { * Bucket size } dev : byte; { Device characteristics } lch : byte; { Logical channel } jnk : ARRAY [1..34B] OF char END; { Fab rec } Rabrec = RECORD bid : byte; { Rab block identifier } bln : byte; { Rab block length } ctx : word; { user defineable area } isi : word; { pointer to iRab } sts : word; { completion status code } stv : word; { status value } rfa : tripleword; { record's file address } rac : byte; { record access mode } ksz : byte; { key buffer size } rop : word; { record processing options } usz : word; { input record buffer size } ubf : _^datarecord; { input record buffer address } rsz : word; { size of output record } rbf : _^datarecord; { output record address } kbf : _^keystring; { key buffer address } krf : byte; { key of reference } mbf : byte; { multibuffer count } mbc : byte; { multiblock count } jnk1 : byte; { not used } rhb : word; { fixed control area buffer } Fab : Fabptr; { Fab address } bkt : doubleword; { record number or VBN } jnk2 : ARRAY [1..46B] OF byte { not used } END; { Rab record } FileString = ARRAY [1..FileNameLength] OF char; Words = ARRAY [1..MaxWord] OF char; Initials = ARRAY [1..3] OF char; DataRecord = RECORD Key : Words; { Primary key = the word itself } Usage : integer; { Usage count - common words bubble up } Verifier : Initials; END; { RECORD } KeyString = Words; VAR Fab:Fabrec; Rab:Rabrec; FileName : FileString; Buffer : DataRecord; Ch : char; length,i : integer; Key : Words; InFile : Text; PROCEDURE rmsini; EXTERNAL; PROCEDURE rmsope(VAR Fab : Fabrec); EXTERNAL; PROCEDURE rmscon(VAR Rab : Rabrec); EXTERNAL; PROCEDURE rmsget(VAR Rab : Rabrec); EXTERNAL; PROCEDURE rmsput(VAR Rab : Rabrec); EXTERNAL; PROCEDURE rmsclo(VAR Fab : Fabrec); EXTERNAL; BEGIN { Spell } rmsini; { Init RMS } FileName := 'DICO.DAT ';{ Set the file name } Fab.fna := @FileName; { Set the file name pointer } Fab.fns := chr(8); { Set the file name length } Fab.lch := chr(7); { Set the LUN } Fab.fac := chr(fbget OR fbput);{ Ask for write access } Fab.fop := fbdlk; { Don't lock on abort } RmsOpe(Fab); { Open the file } IF Fab.sts _<_> 1 THEN writeln('Dictionary $OPEN error. STS: ',Fab.sts:1,' STV: ',Fab.stv:1) ELSE BEGIN Rab.ubf := @Buffer; { Set user buffer address } Rab.usz := MaxWord+5; { Set user buffer size } Rab.rbf := @Buffer; { Set record buffer address } Rab.Fab := @Fab; { Set Fab address } Rab.kbf := @Key; { Set Key buffer address } Rab.krf := chr(0); { Set key of reference = primary } Rab.rac := chr(rbkey); { Set random access } Rab.rop := 0; { Zero record operations options } rmscon(Rab); { Connect access stream } IF Rab.sts _<_> 1 THEN writeln('Dictionary $CONNECT error. STS: ',Rab.sts:1,' STV: ',Rab.stv:1) ELSE BEGIN FOR i := 1 TO FileNameLength DO FileName[i] := ' '; IF Input_^ _<_> ' ' THEN BEGIN REPEAT Read(ch); UNTIL (Input_^ = ' ') or Eoln; IF NOT Eoln THEN REPEAT Read(ch); UNTIL (Input_^ _<_> ' ') OR Eoln; END; IF (Input_^ = ' ') OR Eoln THEN Write ('SPE_> '); IF Eoln THEN Readln; Readln(FileName); Reset(InFile, FileName); WHILE NOT Eof(InFile) DO BEGIN REPEAT i := 0; REPEAT Read(InFile,Ch); IF (('A' _<= Ch) AND (Ch _<= 'Z')) OR (('a' _<= Ch) AND (Ch _<= 'z')) THEN BEGIN i := i + 1; IF (('A' _<= Ch) AND (Ch _<= 'Z')) THEN Key[i] := Ch ELSE Key[i] := chr( ord('A') - ord('a') + ord(Ch) ) END UNTIL ((i _> 0) AND NOT((('A' _<= Ch) AND (Ch _<= 'Z')) OR (('a' _<= Ch) AND (Ch _<= 'z')))) OR (i = MaxWord) OR Eof(InFile); UNTIL (i _> 1) OR Eof(InFile); Length := i; WHILE i _< MaxWord DO BEGIN i := i + 1; Key[i] := ' ' END; { WHILE } Rab.Ksz := chr(MaxWord); Rab.usz := MaxWord+5; { Set user buffer size } Rab.rsz := Rab.usz; RmsGet(Rab); IF (Rab.sts _< 1) AND (Rab.sts _<_> errnf) THEN Writeln('Dictionary $GET error. STS: ',Rab.sts:1,' STV: ',Rab.stv:1) ELSE IF Rab.sts = errnf THEN BEGIN Writeln('Word "',key:length,'" is not in the dictionary.'); Write('Should it be (is it spelled correctly !!) [Y/N]? '); Readln(Ch); IF (Ch = 'y') OR (ch = 'Y') THEN BEGIN Buffer.Key := Key; Buffer.Usage := 9999; Buffer.Verifier := ' '; Rab.usz := MaxWord+5; { Set user buffer size } Rab.rsz := Rab.usz; RmsPut(Rab); IF Rab.Sts _< 1 THEN Writeln('$PUT error. STS: ',Rab.sts:1,' STV: ',Rab.stv:1) END END END; { WHILE } RmsClo(Fab) END END END. { Spell }