| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- IMPLEMENTATION MODULE AltKeys;
- (*
- * REPERTOIRE
- * Release 1.6
- * By Charles Bradford and Cole Brecheen
- * (c) Copyright 1985-1992 PMI
- * Green Bay, Wisconsin
- * All rights reserved
- * (414) 468-6040
- *
- * $Header: D:/logfiles/mods/altkeys.mov 1.5 10 Mar 1991 15:24:44 coleb $
- *
- *)
- IMPORT ErrorNames;
- IMPORT GenLists;
- IMPORT ListUtils;
- IMPORT LowLevel;
- IMPORT M2Strings;
- IMPORT NdxBones;
- IMPORT NdxFiles;
- IMPORT NdxTypes;
- IMPORT PosUtils;
- IMPORT StrEdit;
- IMPORT StrLogic;
- IMPORT SYSTEM;
- VAR
- Initialized : BOOLEAN;
- PROCEDURE Init();
- BEGIN
- IF Initialized THEN
- RETURN;
- ELSE
- Initialized := TRUE;
- END;
- ErrorNames.Init();
- GenLists.Init();
- ListUtils.Init();
- LowLevel.Init();
- M2Strings.Init();
- NdxBones.Init();
- NdxFiles.Init();
- NdxTypes.Init();
- PosUtils.Init();
- StrEdit.Init();
- StrLogic.Init();
- END Init;
- PROCEDURE FieldLoaded( NdxFile: NdxTypes.NdxFileType; FieldName:
- ARRAY OF CHAR; VAR spot: CARDINAL): BOOLEAN;
- (*FieldLoaded returns true if FieldName is found, false if not.
- If it returns a true, spot will represent the actual position
- of FieldName in the NameList. If false, spot will represent
- the length of the NameList.*)
- VAR
- NameList: GenLists.GenList;
- TypeCode, NameListLen, TmpSpot: CARDINAL;
- TmpName: ARRAY [0..127] OF CHAR;
- BEGIN
- spot := 1;
- WITH NdxFile^ DO
- IF (NOT GenLists.Initialized(AltKeys))
- OR (GenLists.ListLength(AltKeys) = 0) THEN
- spot := 0;
- RETURN FALSE;
- END;
- GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
- END;
- TmpSpot := 1;
- NameListLen := GenLists.ListLength( NameList );
- IF NameListLen > 0 THEN
- REPEAT
- GenLists.GetElmt( NameList, TmpSpot, TmpName, TypeCode );
- IF PosUtils.Equal( FieldName, TmpName ) THEN
- spot := TmpSpot;
- RETURN TRUE;
- END;
- INC(TmpSpot);
- UNTIL TmpSpot > NameListLen;
- END;
- spot := NameListLen;
- RETURN FALSE;
- END FieldLoaded;
- PROCEDURE CreateAltList( VAR NdxFile: NdxTypes.NdxFileType; FieldName:
- ARRAY OF CHAR; VAR SpotUsed: CARDINAL);
- (*Each element of the AltKey list is, in turn, a list. The
- first one contains a list of the field names associated with
- the others. The others are lists of selected field values,
- each of which contains in its first two bytes a CARDINAL
- indicating the position of the corresponding record in the
- file's main Ndx list. CreateAltList returns in its SpotUsed
- parameter the position in NdxFile^.AltKeys where it put the
- AltList.*)
- VAR
- FieldList, NameList: GenLists.GenList;
- spot, AltKeysLen: CARDINAL;
- BEGIN
- IF NOT GenLists.Initialized( NdxFile^.AltKeys ) THEN
- GenLists.NewList( NdxFile^.AltKeys );
- END;
- AltKeysLen := GenLists.ListLength( NdxFile^.AltKeys );
- IF AltKeysLen = 0 THEN
- (*Create the first list.*)
- GenLists.NewList( NameList );
- GenLists.ListInsert( NameList, GenLists.ListCode, NdxFile^.AltKeys, 1 );
- INC(AltKeysLen);
- ELSE
- GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
- IF GenLists.ListLength(NameList) # (AltKeysLen - 1) THEN
- (*You could take this check out if you're not worried about
- corruption.*)
- ErrorNames.WarningName( 'BadAlt' );
- RETURN;
- END;
- END;
- GenLists.NewList( FieldList );
- IF FieldLoaded( NdxFile, FieldName, spot ) THEN
- SpotUsed := spot;
- GenLists.ListReplace(FieldList, GenLists.ListCode,
- NdxFile^.AltKeys, SpotUsed + 1);
- (*ListReplace will dispose of the old list.*)
- ELSE
- GenLists.ListInsert( FieldName, GenLists.StrCode, NameList,
- spot + 1);
- SpotUsed := spot + 1;
- GenLists.ListInsert( FieldList, GenLists.ListCode,
- NdxFile^.AltKeys, SpotUsed + 1 );
- END;
- END CreateAltList;
- PROCEDURE CriteriaMet( NdxFile: NdxTypes.NdxFileType; Criteria:
- GenLists.GenList; VAR CriteriaValid: BOOLEAN ): BOOLEAN;
- VAR
- FieldSize, FieldSpot, lngth, ListSpot, TypeCode: CARDINAL;
- TmpCriterion: Criterion;
- RunningResult, TmpResult: BOOLEAN;
- FieldList: GenLists.GenList;
- FieldAdr: SYSTEM.ADDRESS;
- BEGIN
- CriteriaValid := TRUE;
- IF (NOT GenLists.Initialized(Criteria))
- OR (GenLists.ListLength(Criteria) = 0) THEN
- RETURN TRUE;
- (*Means that if you don't pass a criteria list, everything
- will match.*)
- END;
- ListSpot := 1;
- lngth := GenLists.ListLength(Criteria);
- RunningResult := FALSE;
- REPEAT
- GenLists.GetElmt( Criteria, ListSpot, TmpCriterion, TypeCode );
- FieldList := NdxFile^.ListBuf;
- FieldSpot := 0;
- IF (GenLists.ErrorFlag # GenLists.NoListError) OR
- (TypeCode # CriterionCode) THEN
- ErrorNames.WarningName( 'Crit' );
- TmpResult := FALSE;
- ELSIF NdxFiles.FindField(NdxFile^.StructLst,
- TmpCriterion.field, FieldList, FieldSpot) THEN
- GenLists.GetElmtAdr( FieldList, FieldSpot, FieldAdr,
- FieldSize, TypeCode );
- TmpResult := TmpCriterion.determiner( FieldAdr,
- FieldSize, TypeCode, TmpCriterion.rule, CriteriaValid );
- ELSE
- TmpResult := FALSE;
- END;
- CASE TmpCriterion.operator OF
- and: RunningResult := RunningResult AND TmpResult;
- | or: RunningResult := RunningResult OR TmpResult;
- | AndNot: RunningResult := RunningResult AND (NOT TmpResult);
- ELSE
- (*I'm assuming we can get here if range-checking is off.*)
- ErrorNames.WarningName( 'Crit' );
- END;
- INC( ListSpot );
- UNTIL ListSpot > lngth;
- RETURN RunningResult;
- END CriteriaMet;
- PROCEDURE AddFieldContents( NdxFile: NdxTypes.NdxFileType; RecName,
- FieldName: ARRAY OF CHAR; ElmtAdr: SYSTEM.ADDRESS; ElmtSize: CARDINAL );
- VAR
- FieldList: GenLists.GenList;
- duml: LONGINT;
- TypeCode, spot, dumc: CARDINAL;
- BEGIN
- IF NOT FieldLoaded( NdxFile, FieldName, spot ) THEN
- ErrorNames.WarningName( 'AFC' );
- RETURN;
- END;
- IF NOT NdxBones.FindRecord(NdxFile, RecName, duml, dumc, dumc) THEN
- ErrorNames.WarningName( 'RecNam' );
- RETURN;
- END;
- GenLists.GetChildList( NdxFile^.AltKeys, spot + 1, FieldList );
- dumc := GenLists.ElmtNow( NdxFile^.Ndx );
- GenLists.ListInsertAdr( ElmtAdr, ElmtSize + 2, TypeCode, FieldList,
- GenLists.ListLength(FieldList) + 1 );
- GenLists.GetElmtAdr( FieldList, GenLists.ListLength(FieldList), ElmtAdr,
- ElmtSize, TypeCode );
- (*Get the element's new data area.*)
- LowLevel.ShiftArrayRight( ElmtAdr, ElmtSize, 2 );
- (*Make room for the record identifier at the start of the
- element's data area.*)
- LowLevel.PokeWord( dumc, LowLevel.seg(ElmtAdr), LowLevel.ofs(ElmtAdr) );
- (*Put the record identifier in the first two bytes of the
- data area.*)
- END AddFieldContents;
- PROCEDURE LoadAltList( VAR NdxFile: NdxTypes.NdxFileType;
- InList: GenLists.GenList; FieldName: ARRAY OF CHAR; Criteria:
- GenLists.GenList): BOOLEAN;
- VAR
- ListType, ListSpot, NameListLength, InListLength, TypeCode,
- ElmtSize, AltFieldSpot, AltKeyListSpot: CARDINAL;
- ElmtAdr: SYSTEM.ADDRESS;
- AltFieldList, AltKeyList: GenLists.GenList;
- TmpNdxRec: NdxTypes.NdxElement;
- CriteriaValid: BOOLEAN;
- RecName: ARRAY [0..(NdxTypes.RecNameLength - 1)] OF CHAR;
- BEGIN
- (*LoadAltList*)
- CriteriaValid := TRUE;
- AltKeyListSpot := 1;
- InListLength := GenLists.ListLength(InList);
- IF InListLength = 0 THEN
- NameListLength := GenLists.ListLength(NdxFile^.Ndx);
- ListType := NdxTypes.NdxTypeCode;
- (*We set ListType to NdxTypeCode if there's no InList
- because we're going to use the file's entire Ndx in this
- situation.*)
- ELSE
- NameListLength := GenLists.ListLength(InList);
- ListType := ListUtils.TypeCheck( InList, 1 );
- END;
- ListSpot := 1;
- REPEAT
- CASE ListType OF
- NdxTypes.NdxTypeCode:
- IF GenLists.ListLength( NdxFile^.Ndx ) > 0 THEN
- GenLists.GetElmt( NdxFile^.Ndx, ListSpot, TmpNdxRec, TypeCode );
- StrEdit.AssignStr( TmpNdxRec.RecName, RecName );
- ELSE
- RETURN FALSE;
- END;
- | AltKeyCode:
- GetMatchingKey( NdxFile, InList, ListSpot, RecName );
- ELSE
- (*We assume we have a list of valid record names.*)
- GenLists.GetElmt( InList, ListSpot, RecName, TypeCode );
- END;
- IF (M2Strings.Length( RecName ) > 0) AND
- NdxBones.InitBuffer( NdxFile, RecName) THEN
- (*If Length(RecName) = 0, it's a garbage record.*)
- (*InitBuffer does the actual record read, and returns
- FALSE if the record does not exist *)
- IF NOT FieldLoaded( NdxFile, FieldName, AltKeyListSpot ) THEN
- (*AltKeyListSpot now represents the length of the
- NameList, but CreateAltList will INC it.*)
- CreateAltList( NdxFile, FieldName, AltKeyListSpot );
- END;
- IF PosUtils.Equal('KEY', FieldName) THEN
- (*They just want the matching record names.*)
- GenLists.GetChildList( NdxFile^.AltKeys, AltKeyListSpot + 1,
- AltKeyList );
- IF CriteriaMet(NdxFile, Criteria, CriteriaValid) THEN
- GenLists.ListInsert( RecName, GenLists.StrCode, AltKeyList,
- GenLists.ListLength(AltKeyList) + 1 );
- END;
- ELSE
- AltFieldList := NdxFile^.ListBuf;
- AltFieldSpot := 0;
- IF NdxFiles.FindField(NdxFile^.StructLst, FieldName, AltFieldList,
- AltFieldSpot) THEN
- IF CriteriaMet( NdxFile, Criteria, CriteriaValid ) THEN
- GenLists.GetElmtAdr( AltFieldList, AltFieldSpot, ElmtAdr,
- ElmtSize, TypeCode );
- IF (NOT (TypeCode = GenLists.ListCode)) THEN
- AddFieldContents( NdxFile, RecName, FieldName,
- ElmtAdr, ElmtSize );
- ELSE
- ErrorNames.WarningName( 'LstAlt' );
- END;
- END;
- END;
- END;
- END;
- INC(ListSpot);
- UNTIL (ListSpot > NameListLength) OR (NOT CriteriaValid);
- (*We're at the end of the InList.*)
- RETURN TRUE;
- END LoadAltList;
- PROCEDURE DisposeAltList( VAR NdxFile: NdxTypes.NdxFileType; FieldName:
- ARRAY OF CHAR);
- VAR
- NameList: GenLists.GenList;
- spot: CARDINAL;
- BEGIN
- IF NOT GenLists.Initialized( NdxFile^.AltKeys ) THEN
- ErrorNames.WarningName('BadLst');
- RETURN;
- END;
- IF GenLists.ListLength( NdxFile^.AltKeys ) > 0 THEN
- IF FieldLoaded( NdxFile, FieldName, spot ) THEN
- GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
- GenLists.ListDelete( NameList, spot, 1 );
- (*Delete the FieldName.*)
- GenLists.ListDelete( NdxFile^.AltKeys, spot + 1, 1 );
- (*Delete the list itself.*)
- RETURN;
- END;
- END;
- ErrorNames.WarningName( 'AltNam' );
- END DisposeAltList;
- PROCEDURE TallyAltLists(NdxFile: NdxTypes.NdxFileType; VAR
- TheList: GenLists.GenList);
- (*Returns a list of the field names that have AltLists
- presently loaded.*)
- VAR
- NameList: GenLists.GenList;
- BEGIN
- IF (GenLists.Initialized( NdxFile^.AltKeys ))
- AND (GenLists.ListLength( NdxFile^.AltKeys ) > 0) THEN
- GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
- GenLists.CopyList( NameList, TheList );
- ELSE
- ErrorNames.WarningName( 'AltNam' );
- END;
- END TallyAltLists;
- PROCEDURE GetAltList( NdxFile: NdxTypes.NdxFileType; FieldName: ARRAY OF
- CHAR; VAR AltList: GenLists.GenList): BOOLEAN;
- (*Note that this returns the real AltList, so the first two
- bytes of each data area will be the record identifier. You
- have to get rid of those things with ShiftArrayLeft.*)
- VAR
- spot: CARDINAL;
- BEGIN
- IF FieldLoaded( NdxFile, FieldName, spot ) THEN
- GenLists.GetChildList( NdxFile^.AltKeys, spot + 1, AltList );
- IF GenLists.ErrorFlag = GenLists.NoListError THEN
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- ELSE
- RETURN FALSE;
- END;
- END GetAltList;
- PROCEDURE GetMatchingKey( NdxFile: NdxTypes.NdxFileType; AltList:
- GenLists.GenList; spot: CARDINAL; VAR RecName: ARRAY OF CHAR );
- (*Pass this procedure an AltKeyList (i.e., the kind of list
- that has a record number and a field value in every
- element) and the position of an element in that list, and
- it returns in RecName the name of the record from which the
- field value was read.*)
- VAR
- RecordNumber, AltKeySize, TypeCode: CARDINAL;
- AltKeyAdr: SYSTEM.ADDRESS;
- TmpNdxRec: NdxTypes.NdxElement;
- BEGIN
- GenLists.GetElmtAdr( AltList, spot, AltKeyAdr, AltKeySize, TypeCode );
- IF (TypeCode # AltKeyCode) THEN
- LowLevel.Move( AltKeyAdr, SYSTEM.ADR(RecName), AltKeySize );
- (* 28 Nov 88: added this so that GetMatchingKey can be
- used with AltKeyLists that contain only record names. *)
- ELSE
- LowLevel.Move( AltKeyAdr, SYSTEM.ADR(RecordNumber), 2 );
- GenLists.GetElmt( NdxFile^.Ndx, RecordNumber, TmpNdxRec, TypeCode );
- StrEdit.AssignStr( TmpNdxRec.RecName, RecName );
- END;
- END GetMatchingKey;
- PROCEDURE GetMatchingKeys( NdxFile: NdxTypes.NdxFileType; AltList:
- GenLists.GenList; VAR KeyList: GenLists.GenList): BOOLEAN;
- (*Returns a RecNameList that contains only records presently in
- the AltList.*)
- VAR
- spot, lngth: CARDINAL;
- RecName: ARRAY [0..(NdxTypes.RecNameLength - 1)] OF CHAR;
- BEGIN
- IF NOT GenLists.Initialized(AltList) THEN
- ErrorNames.WarningName('BadLst');
- RETURN FALSE;
- END;
- lngth := GenLists.ListLength( AltList );
- FOR spot := 1 TO lngth DO
- GetMatchingKey( NdxFile, AltList, spot, RecName );
- IF GenLists.ErrorFlag = GenLists.NoListError THEN
- GenLists.ListInsert( RecName, RecNameCode, KeyList, spot );
- END;
- END;
- RETURN TRUE;
- END GetMatchingKeys;
- PROCEDURE StrSelector( TheAdr: SYSTEM.ADDRESS; TheSize, TypeCode:
- CARDINAL; TheRule: ARRAY OF CHAR; VAR CriteriaValid:
- BOOLEAN): BOOLEAN;
- (*This will be assigned to a SelectProc variable.*)
- VAR
- TmpStr: ARRAY [0..255] OF CHAR;
- TmpResult, SubSize, SubType, leng, cnt: CARDINAL;
- SubAddr: SYSTEM.ADDRESS;
- SubList: GenLists.GenList;
- found: BOOLEAN;
- BEGIN
- IF (TypeCode = GenLists.StrCode) THEN
- IF M2Strings.Length( TheRule ) = 0 THEN
- RETURN TRUE;
- END;
- IF TheSize > (HIGH(TmpStr)+1) THEN
- TheSize := (HIGH(TmpStr)+1);
- END;
- LowLevel.Move( TheAdr, SYSTEM.ADR(TmpStr), TheSize );
- TmpResult := StrLogic.ExpressionTest( TmpStr, TheRule );
- CriteriaValid := StrLogic.StrLogicErrorLevel = 0;
- RETURN ( TmpResult > 0);
- ELSIF (TypeCode = GenLists.ListCode) THEN
- IF NOT GenLists.AdrToList( TheAdr, TheSize, SubList ) THEN
- RETURN FALSE;
- END;
- leng := GenLists.ListLength(SubList);
- found := FALSE;
- cnt := 1;
- WHILE (cnt <= leng) AND (NOT found) DO
- GenLists.GetElmtAdr( SubList, cnt, SubAddr, SubSize, SubType );
- (*We ought to be able to do a recursive call here, but for
- some reason it causes a stack overflow.*)
- IF (SubType = GenLists.StrCode) THEN
- IF M2Strings.Length( TheRule ) = 0 THEN
- RETURN TRUE;
- END;
- IF SubSize > (HIGH(TmpStr)+1) THEN
- SubSize := (HIGH(TmpStr)+1);
- END;
- LowLevel.Move( SubAddr, SYSTEM.ADR(TmpStr), SubSize );
- TmpResult := StrLogic.ExpressionTest( TmpStr, TheRule );
- CriteriaValid := StrLogic.StrLogicErrorLevel = 0;
- found := TmpResult > 0;
- END;
- INC(cnt);
- END;
- RETURN found;
- END;
- RETURN FALSE;
- END StrSelector;
- PROCEDURE AddCriteria( CriteriaList: GenLists.GenList; op: LogicOperator;
- TheSelectProc: SelectProc; TheRule, FieldName: ARRAY OF CHAR );
- VAR
- TmpCriterion: Criterion;
- BEGIN
- IF NOT GenLists.Initialized( CriteriaList ) THEN
- ErrorNames.WarningName('BadLst');
- RETURN;
- END;
- StrEdit.AssignStr( FieldName, TmpCriterion.field );
- StrEdit.AssignStr( TheRule, TmpCriterion.rule );
- TmpCriterion.operator := op;
- TmpCriterion.determiner := TheSelectProc;
- GenLists.ListInsert( TmpCriterion, CriterionCode,
- CriteriaList, GenLists.ListLength(CriteriaList) + 1 );
- END AddCriteria;
- BEGIN
- Initialized := FALSE;
- Init();
- END AltKeys.
|