ALTKEYS.MOD 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. IMPLEMENTATION MODULE AltKeys;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1992 PMI
  7. * Green Bay, Wisconsin
  8. * All rights reserved
  9. * (414) 468-6040
  10. *
  11. * $Header: D:/logfiles/mods/altkeys.mov 1.5 10 Mar 1991 15:24:44 coleb $
  12. *
  13. *)
  14. IMPORT ErrorNames;
  15. IMPORT GenLists;
  16. IMPORT ListUtils;
  17. IMPORT LowLevel;
  18. IMPORT M2Strings;
  19. IMPORT NdxBones;
  20. IMPORT NdxFiles;
  21. IMPORT NdxTypes;
  22. IMPORT PosUtils;
  23. IMPORT StrEdit;
  24. IMPORT StrLogic;
  25. IMPORT SYSTEM;
  26. VAR
  27. Initialized : BOOLEAN;
  28. PROCEDURE Init();
  29. BEGIN
  30. IF Initialized THEN
  31. RETURN;
  32. ELSE
  33. Initialized := TRUE;
  34. END;
  35. ErrorNames.Init();
  36. GenLists.Init();
  37. ListUtils.Init();
  38. LowLevel.Init();
  39. M2Strings.Init();
  40. NdxBones.Init();
  41. NdxFiles.Init();
  42. NdxTypes.Init();
  43. PosUtils.Init();
  44. StrEdit.Init();
  45. StrLogic.Init();
  46. END Init;
  47. PROCEDURE FieldLoaded( NdxFile: NdxTypes.NdxFileType; FieldName:
  48. ARRAY OF CHAR; VAR spot: CARDINAL): BOOLEAN;
  49. (*FieldLoaded returns true if FieldName is found, false if not.
  50. If it returns a true, spot will represent the actual position
  51. of FieldName in the NameList. If false, spot will represent
  52. the length of the NameList.*)
  53. VAR
  54. NameList: GenLists.GenList;
  55. TypeCode, NameListLen, TmpSpot: CARDINAL;
  56. TmpName: ARRAY [0..127] OF CHAR;
  57. BEGIN
  58. spot := 1;
  59. WITH NdxFile^ DO
  60. IF (NOT GenLists.Initialized(AltKeys))
  61. OR (GenLists.ListLength(AltKeys) = 0) THEN
  62. spot := 0;
  63. RETURN FALSE;
  64. END;
  65. GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
  66. END;
  67. TmpSpot := 1;
  68. NameListLen := GenLists.ListLength( NameList );
  69. IF NameListLen > 0 THEN
  70. REPEAT
  71. GenLists.GetElmt( NameList, TmpSpot, TmpName, TypeCode );
  72. IF PosUtils.Equal( FieldName, TmpName ) THEN
  73. spot := TmpSpot;
  74. RETURN TRUE;
  75. END;
  76. INC(TmpSpot);
  77. UNTIL TmpSpot > NameListLen;
  78. END;
  79. spot := NameListLen;
  80. RETURN FALSE;
  81. END FieldLoaded;
  82. PROCEDURE CreateAltList( VAR NdxFile: NdxTypes.NdxFileType; FieldName:
  83. ARRAY OF CHAR; VAR SpotUsed: CARDINAL);
  84. (*Each element of the AltKey list is, in turn, a list. The
  85. first one contains a list of the field names associated with
  86. the others. The others are lists of selected field values,
  87. each of which contains in its first two bytes a CARDINAL
  88. indicating the position of the corresponding record in the
  89. file's main Ndx list. CreateAltList returns in its SpotUsed
  90. parameter the position in NdxFile^.AltKeys where it put the
  91. AltList.*)
  92. VAR
  93. FieldList, NameList: GenLists.GenList;
  94. spot, AltKeysLen: CARDINAL;
  95. BEGIN
  96. IF NOT GenLists.Initialized( NdxFile^.AltKeys ) THEN
  97. GenLists.NewList( NdxFile^.AltKeys );
  98. END;
  99. AltKeysLen := GenLists.ListLength( NdxFile^.AltKeys );
  100. IF AltKeysLen = 0 THEN
  101. (*Create the first list.*)
  102. GenLists.NewList( NameList );
  103. GenLists.ListInsert( NameList, GenLists.ListCode, NdxFile^.AltKeys, 1 );
  104. INC(AltKeysLen);
  105. ELSE
  106. GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
  107. IF GenLists.ListLength(NameList) # (AltKeysLen - 1) THEN
  108. (*You could take this check out if you're not worried about
  109. corruption.*)
  110. ErrorNames.WarningName( 'BadAlt' );
  111. RETURN;
  112. END;
  113. END;
  114. GenLists.NewList( FieldList );
  115. IF FieldLoaded( NdxFile, FieldName, spot ) THEN
  116. SpotUsed := spot;
  117. GenLists.ListReplace(FieldList, GenLists.ListCode,
  118. NdxFile^.AltKeys, SpotUsed + 1);
  119. (*ListReplace will dispose of the old list.*)
  120. ELSE
  121. GenLists.ListInsert( FieldName, GenLists.StrCode, NameList,
  122. spot + 1);
  123. SpotUsed := spot + 1;
  124. GenLists.ListInsert( FieldList, GenLists.ListCode,
  125. NdxFile^.AltKeys, SpotUsed + 1 );
  126. END;
  127. END CreateAltList;
  128. PROCEDURE CriteriaMet( NdxFile: NdxTypes.NdxFileType; Criteria:
  129. GenLists.GenList; VAR CriteriaValid: BOOLEAN ): BOOLEAN;
  130. VAR
  131. FieldSize, FieldSpot, lngth, ListSpot, TypeCode: CARDINAL;
  132. TmpCriterion: Criterion;
  133. RunningResult, TmpResult: BOOLEAN;
  134. FieldList: GenLists.GenList;
  135. FieldAdr: SYSTEM.ADDRESS;
  136. BEGIN
  137. CriteriaValid := TRUE;
  138. IF (NOT GenLists.Initialized(Criteria))
  139. OR (GenLists.ListLength(Criteria) = 0) THEN
  140. RETURN TRUE;
  141. (*Means that if you don't pass a criteria list, everything
  142. will match.*)
  143. END;
  144. ListSpot := 1;
  145. lngth := GenLists.ListLength(Criteria);
  146. RunningResult := FALSE;
  147. REPEAT
  148. GenLists.GetElmt( Criteria, ListSpot, TmpCriterion, TypeCode );
  149. FieldList := NdxFile^.ListBuf;
  150. FieldSpot := 0;
  151. IF (GenLists.ErrorFlag # GenLists.NoListError) OR
  152. (TypeCode # CriterionCode) THEN
  153. ErrorNames.WarningName( 'Crit' );
  154. TmpResult := FALSE;
  155. ELSIF NdxFiles.FindField(NdxFile^.StructLst,
  156. TmpCriterion.field, FieldList, FieldSpot) THEN
  157. GenLists.GetElmtAdr( FieldList, FieldSpot, FieldAdr,
  158. FieldSize, TypeCode );
  159. TmpResult := TmpCriterion.determiner( FieldAdr,
  160. FieldSize, TypeCode, TmpCriterion.rule, CriteriaValid );
  161. ELSE
  162. TmpResult := FALSE;
  163. END;
  164. CASE TmpCriterion.operator OF
  165. and: RunningResult := RunningResult AND TmpResult;
  166. | or: RunningResult := RunningResult OR TmpResult;
  167. | AndNot: RunningResult := RunningResult AND (NOT TmpResult);
  168. ELSE
  169. (*I'm assuming we can get here if range-checking is off.*)
  170. ErrorNames.WarningName( 'Crit' );
  171. END;
  172. INC( ListSpot );
  173. UNTIL ListSpot > lngth;
  174. RETURN RunningResult;
  175. END CriteriaMet;
  176. PROCEDURE AddFieldContents( NdxFile: NdxTypes.NdxFileType; RecName,
  177. FieldName: ARRAY OF CHAR; ElmtAdr: SYSTEM.ADDRESS; ElmtSize: CARDINAL );
  178. VAR
  179. FieldList: GenLists.GenList;
  180. duml: LONGINT;
  181. TypeCode, spot, dumc: CARDINAL;
  182. BEGIN
  183. IF NOT FieldLoaded( NdxFile, FieldName, spot ) THEN
  184. ErrorNames.WarningName( 'AFC' );
  185. RETURN;
  186. END;
  187. IF NOT NdxBones.FindRecord(NdxFile, RecName, duml, dumc, dumc) THEN
  188. ErrorNames.WarningName( 'RecNam' );
  189. RETURN;
  190. END;
  191. GenLists.GetChildList( NdxFile^.AltKeys, spot + 1, FieldList );
  192. dumc := GenLists.ElmtNow( NdxFile^.Ndx );
  193. GenLists.ListInsertAdr( ElmtAdr, ElmtSize + 2, TypeCode, FieldList,
  194. GenLists.ListLength(FieldList) + 1 );
  195. GenLists.GetElmtAdr( FieldList, GenLists.ListLength(FieldList), ElmtAdr,
  196. ElmtSize, TypeCode );
  197. (*Get the element's new data area.*)
  198. LowLevel.ShiftArrayRight( ElmtAdr, ElmtSize, 2 );
  199. (*Make room for the record identifier at the start of the
  200. element's data area.*)
  201. LowLevel.PokeWord( dumc, LowLevel.seg(ElmtAdr), LowLevel.ofs(ElmtAdr) );
  202. (*Put the record identifier in the first two bytes of the
  203. data area.*)
  204. END AddFieldContents;
  205. PROCEDURE LoadAltList( VAR NdxFile: NdxTypes.NdxFileType;
  206. InList: GenLists.GenList; FieldName: ARRAY OF CHAR; Criteria:
  207. GenLists.GenList): BOOLEAN;
  208. VAR
  209. ListType, ListSpot, NameListLength, InListLength, TypeCode,
  210. ElmtSize, AltFieldSpot, AltKeyListSpot: CARDINAL;
  211. ElmtAdr: SYSTEM.ADDRESS;
  212. AltFieldList, AltKeyList: GenLists.GenList;
  213. TmpNdxRec: NdxTypes.NdxElement;
  214. CriteriaValid: BOOLEAN;
  215. RecName: ARRAY [0..(NdxTypes.RecNameLength - 1)] OF CHAR;
  216. BEGIN
  217. (*LoadAltList*)
  218. CriteriaValid := TRUE;
  219. AltKeyListSpot := 1;
  220. InListLength := GenLists.ListLength(InList);
  221. IF InListLength = 0 THEN
  222. NameListLength := GenLists.ListLength(NdxFile^.Ndx);
  223. ListType := NdxTypes.NdxTypeCode;
  224. (*We set ListType to NdxTypeCode if there's no InList
  225. because we're going to use the file's entire Ndx in this
  226. situation.*)
  227. ELSE
  228. NameListLength := GenLists.ListLength(InList);
  229. ListType := ListUtils.TypeCheck( InList, 1 );
  230. END;
  231. ListSpot := 1;
  232. REPEAT
  233. CASE ListType OF
  234. NdxTypes.NdxTypeCode:
  235. IF GenLists.ListLength( NdxFile^.Ndx ) > 0 THEN
  236. GenLists.GetElmt( NdxFile^.Ndx, ListSpot, TmpNdxRec, TypeCode );
  237. StrEdit.AssignStr( TmpNdxRec.RecName, RecName );
  238. ELSE
  239. RETURN FALSE;
  240. END;
  241. | AltKeyCode:
  242. GetMatchingKey( NdxFile, InList, ListSpot, RecName );
  243. ELSE
  244. (*We assume we have a list of valid record names.*)
  245. GenLists.GetElmt( InList, ListSpot, RecName, TypeCode );
  246. END;
  247. IF (M2Strings.Length( RecName ) > 0) AND
  248. NdxBones.InitBuffer( NdxFile, RecName) THEN
  249. (*If Length(RecName) = 0, it's a garbage record.*)
  250. (*InitBuffer does the actual record read, and returns
  251. FALSE if the record does not exist *)
  252. IF NOT FieldLoaded( NdxFile, FieldName, AltKeyListSpot ) THEN
  253. (*AltKeyListSpot now represents the length of the
  254. NameList, but CreateAltList will INC it.*)
  255. CreateAltList( NdxFile, FieldName, AltKeyListSpot );
  256. END;
  257. IF PosUtils.Equal('KEY', FieldName) THEN
  258. (*They just want the matching record names.*)
  259. GenLists.GetChildList( NdxFile^.AltKeys, AltKeyListSpot + 1,
  260. AltKeyList );
  261. IF CriteriaMet(NdxFile, Criteria, CriteriaValid) THEN
  262. GenLists.ListInsert( RecName, GenLists.StrCode, AltKeyList,
  263. GenLists.ListLength(AltKeyList) + 1 );
  264. END;
  265. ELSE
  266. AltFieldList := NdxFile^.ListBuf;
  267. AltFieldSpot := 0;
  268. IF NdxFiles.FindField(NdxFile^.StructLst, FieldName, AltFieldList,
  269. AltFieldSpot) THEN
  270. IF CriteriaMet( NdxFile, Criteria, CriteriaValid ) THEN
  271. GenLists.GetElmtAdr( AltFieldList, AltFieldSpot, ElmtAdr,
  272. ElmtSize, TypeCode );
  273. IF (NOT (TypeCode = GenLists.ListCode)) THEN
  274. AddFieldContents( NdxFile, RecName, FieldName,
  275. ElmtAdr, ElmtSize );
  276. ELSE
  277. ErrorNames.WarningName( 'LstAlt' );
  278. END;
  279. END;
  280. END;
  281. END;
  282. END;
  283. INC(ListSpot);
  284. UNTIL (ListSpot > NameListLength) OR (NOT CriteriaValid);
  285. (*We're at the end of the InList.*)
  286. RETURN TRUE;
  287. END LoadAltList;
  288. PROCEDURE DisposeAltList( VAR NdxFile: NdxTypes.NdxFileType; FieldName:
  289. ARRAY OF CHAR);
  290. VAR
  291. NameList: GenLists.GenList;
  292. spot: CARDINAL;
  293. BEGIN
  294. IF NOT GenLists.Initialized( NdxFile^.AltKeys ) THEN
  295. ErrorNames.WarningName('BadLst');
  296. RETURN;
  297. END;
  298. IF GenLists.ListLength( NdxFile^.AltKeys ) > 0 THEN
  299. IF FieldLoaded( NdxFile, FieldName, spot ) THEN
  300. GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
  301. GenLists.ListDelete( NameList, spot, 1 );
  302. (*Delete the FieldName.*)
  303. GenLists.ListDelete( NdxFile^.AltKeys, spot + 1, 1 );
  304. (*Delete the list itself.*)
  305. RETURN;
  306. END;
  307. END;
  308. ErrorNames.WarningName( 'AltNam' );
  309. END DisposeAltList;
  310. PROCEDURE TallyAltLists(NdxFile: NdxTypes.NdxFileType; VAR
  311. TheList: GenLists.GenList);
  312. (*Returns a list of the field names that have AltLists
  313. presently loaded.*)
  314. VAR
  315. NameList: GenLists.GenList;
  316. BEGIN
  317. IF (GenLists.Initialized( NdxFile^.AltKeys ))
  318. AND (GenLists.ListLength( NdxFile^.AltKeys ) > 0) THEN
  319. GenLists.GetChildList( NdxFile^.AltKeys, 1, NameList );
  320. GenLists.CopyList( NameList, TheList );
  321. ELSE
  322. ErrorNames.WarningName( 'AltNam' );
  323. END;
  324. END TallyAltLists;
  325. PROCEDURE GetAltList( NdxFile: NdxTypes.NdxFileType; FieldName: ARRAY OF
  326. CHAR; VAR AltList: GenLists.GenList): BOOLEAN;
  327. (*Note that this returns the real AltList, so the first two
  328. bytes of each data area will be the record identifier. You
  329. have to get rid of those things with ShiftArrayLeft.*)
  330. VAR
  331. spot: CARDINAL;
  332. BEGIN
  333. IF FieldLoaded( NdxFile, FieldName, spot ) THEN
  334. GenLists.GetChildList( NdxFile^.AltKeys, spot + 1, AltList );
  335. IF GenLists.ErrorFlag = GenLists.NoListError THEN
  336. RETURN TRUE;
  337. ELSE
  338. RETURN FALSE;
  339. END;
  340. ELSE
  341. RETURN FALSE;
  342. END;
  343. END GetAltList;
  344. PROCEDURE GetMatchingKey( NdxFile: NdxTypes.NdxFileType; AltList:
  345. GenLists.GenList; spot: CARDINAL; VAR RecName: ARRAY OF CHAR );
  346. (*Pass this procedure an AltKeyList (i.e., the kind of list
  347. that has a record number and a field value in every
  348. element) and the position of an element in that list, and
  349. it returns in RecName the name of the record from which the
  350. field value was read.*)
  351. VAR
  352. RecordNumber, AltKeySize, TypeCode: CARDINAL;
  353. AltKeyAdr: SYSTEM.ADDRESS;
  354. TmpNdxRec: NdxTypes.NdxElement;
  355. BEGIN
  356. GenLists.GetElmtAdr( AltList, spot, AltKeyAdr, AltKeySize, TypeCode );
  357. IF (TypeCode # AltKeyCode) THEN
  358. LowLevel.Move( AltKeyAdr, SYSTEM.ADR(RecName), AltKeySize );
  359. (* 28 Nov 88: added this so that GetMatchingKey can be
  360. used with AltKeyLists that contain only record names. *)
  361. ELSE
  362. LowLevel.Move( AltKeyAdr, SYSTEM.ADR(RecordNumber), 2 );
  363. GenLists.GetElmt( NdxFile^.Ndx, RecordNumber, TmpNdxRec, TypeCode );
  364. StrEdit.AssignStr( TmpNdxRec.RecName, RecName );
  365. END;
  366. END GetMatchingKey;
  367. PROCEDURE GetMatchingKeys( NdxFile: NdxTypes.NdxFileType; AltList:
  368. GenLists.GenList; VAR KeyList: GenLists.GenList): BOOLEAN;
  369. (*Returns a RecNameList that contains only records presently in
  370. the AltList.*)
  371. VAR
  372. spot, lngth: CARDINAL;
  373. RecName: ARRAY [0..(NdxTypes.RecNameLength - 1)] OF CHAR;
  374. BEGIN
  375. IF NOT GenLists.Initialized(AltList) THEN
  376. ErrorNames.WarningName('BadLst');
  377. RETURN FALSE;
  378. END;
  379. lngth := GenLists.ListLength( AltList );
  380. FOR spot := 1 TO lngth DO
  381. GetMatchingKey( NdxFile, AltList, spot, RecName );
  382. IF GenLists.ErrorFlag = GenLists.NoListError THEN
  383. GenLists.ListInsert( RecName, RecNameCode, KeyList, spot );
  384. END;
  385. END;
  386. RETURN TRUE;
  387. END GetMatchingKeys;
  388. PROCEDURE StrSelector( TheAdr: SYSTEM.ADDRESS; TheSize, TypeCode:
  389. CARDINAL; TheRule: ARRAY OF CHAR; VAR CriteriaValid:
  390. BOOLEAN): BOOLEAN;
  391. (*This will be assigned to a SelectProc variable.*)
  392. VAR
  393. TmpStr: ARRAY [0..255] OF CHAR;
  394. TmpResult, SubSize, SubType, leng, cnt: CARDINAL;
  395. SubAddr: SYSTEM.ADDRESS;
  396. SubList: GenLists.GenList;
  397. found: BOOLEAN;
  398. BEGIN
  399. IF (TypeCode = GenLists.StrCode) THEN
  400. IF M2Strings.Length( TheRule ) = 0 THEN
  401. RETURN TRUE;
  402. END;
  403. IF TheSize > (HIGH(TmpStr)+1) THEN
  404. TheSize := (HIGH(TmpStr)+1);
  405. END;
  406. LowLevel.Move( TheAdr, SYSTEM.ADR(TmpStr), TheSize );
  407. TmpResult := StrLogic.ExpressionTest( TmpStr, TheRule );
  408. CriteriaValid := StrLogic.StrLogicErrorLevel = 0;
  409. RETURN ( TmpResult > 0);
  410. ELSIF (TypeCode = GenLists.ListCode) THEN
  411. IF NOT GenLists.AdrToList( TheAdr, TheSize, SubList ) THEN
  412. RETURN FALSE;
  413. END;
  414. leng := GenLists.ListLength(SubList);
  415. found := FALSE;
  416. cnt := 1;
  417. WHILE (cnt <= leng) AND (NOT found) DO
  418. GenLists.GetElmtAdr( SubList, cnt, SubAddr, SubSize, SubType );
  419. (*We ought to be able to do a recursive call here, but for
  420. some reason it causes a stack overflow.*)
  421. IF (SubType = GenLists.StrCode) THEN
  422. IF M2Strings.Length( TheRule ) = 0 THEN
  423. RETURN TRUE;
  424. END;
  425. IF SubSize > (HIGH(TmpStr)+1) THEN
  426. SubSize := (HIGH(TmpStr)+1);
  427. END;
  428. LowLevel.Move( SubAddr, SYSTEM.ADR(TmpStr), SubSize );
  429. TmpResult := StrLogic.ExpressionTest( TmpStr, TheRule );
  430. CriteriaValid := StrLogic.StrLogicErrorLevel = 0;
  431. found := TmpResult > 0;
  432. END;
  433. INC(cnt);
  434. END;
  435. RETURN found;
  436. END;
  437. RETURN FALSE;
  438. END StrSelector;
  439. PROCEDURE AddCriteria( CriteriaList: GenLists.GenList; op: LogicOperator;
  440. TheSelectProc: SelectProc; TheRule, FieldName: ARRAY OF CHAR );
  441. VAR
  442. TmpCriterion: Criterion;
  443. BEGIN
  444. IF NOT GenLists.Initialized( CriteriaList ) THEN
  445. ErrorNames.WarningName('BadLst');
  446. RETURN;
  447. END;
  448. StrEdit.AssignStr( FieldName, TmpCriterion.field );
  449. StrEdit.AssignStr( TheRule, TmpCriterion.rule );
  450. TmpCriterion.operator := op;
  451. TmpCriterion.determiner := TheSelectProc;
  452. GenLists.ListInsert( TmpCriterion, CriterionCode,
  453. CriteriaList, GenLists.ListLength(CriteriaList) + 1 );
  454. END AddCriteria;
  455. BEGIN
  456. Initialized := FALSE;
  457. Init();
  458. END AltKeys.