NDXBONES.MOD 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. IMPLEMENTATION MODULE NdxBones;
  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/ndxbones.mov 1.7 10 Mar 1991 15:30:02 coleb $
  12. *
  13. *)
  14. (*EntryDiag:
  15. IMPORT Diagnostics;
  16. :EntryDiag*)
  17. IMPORT ErrorNames;
  18. IMPORT HandleIO;
  19. IMPORT GenLists;
  20. IMPORT ListUtils;
  21. IMPORT LowLevel;
  22. IMPORT M2Strings;
  23. IMPORT NdxTypes;
  24. IMPORT Numbers;
  25. IMPORT NumTypes;
  26. IMPORT PosUtils;
  27. IMPORT StrEdit;
  28. IMPORT StringIO;
  29. IMPORT SYSTEM;
  30. IMPORT VStorage;
  31. VAR
  32. Initialized : BOOLEAN;
  33. CONST
  34. StartChar = 'B';
  35. EndChar = 'E';
  36. EncodedChar = 'R';
  37. NdxMarkChar = 'X';
  38. (*This character marks the start of the ndx list. We use it
  39. to make sure we've got the right file offset when we back
  40. up and read the list.*)
  41. blank = ' ';
  42. null = '';
  43. AfterLastElmt = 65535;
  44. PROCEDURE BiggestRecord( NdxFile: NdxTypes.NdxFileType ): CARDINAL;
  45. VAR
  46. TmpElmt: NdxTypes.NdxElement;
  47. TypeCode, LstLngth, TmpResult: CARDINAL;
  48. BEGIN
  49. IF GenLists.ListLength( NdxFile^.Ndx ) = 0 THEN
  50. RETURN 0;
  51. END;
  52. GenLists.GetElmt( NdxFile^.Ndx, 1, TmpElmt, TypeCode );
  53. TmpResult := TmpElmt.UsedChars;
  54. LstLngth := GenLists.ListLength( NdxFile^.Ndx );
  55. WHILE GenLists.ElmtNow( NdxFile^.Ndx ) < LstLngth DO
  56. GenLists.NextElmt( NdxFile^.Ndx, 1, TmpElmt, TypeCode );
  57. IF TmpElmt.UsedChars > TmpResult THEN
  58. TmpResult := TmpElmt.UsedChars;
  59. END;
  60. END;
  61. RETURN TmpResult;
  62. END BiggestRecord;
  63. PROCEDURE FindRecord( NdxFile: NdxTypes.NdxFileType; VAR
  64. RecordName : ARRAY OF CHAR; VAR offset : LONGINT; VAR
  65. UsedRecSize, AllocSize: CARDINAL) : BOOLEAN;
  66. (* Move in the record list to this record. If can't find
  67. record, AllocSize is set to the collating position where
  68. record requested would be inserted. All other VAR results
  69. are meaningless *)
  70. VAR
  71. found, StillLooking: BOOLEAN;
  72. HiBound, LoBound, distance, ListPos, TypeCode: CARDINAL;
  73. CompResult: INTEGER;
  74. TmpElmt : NdxTypes.NdxElement;
  75. PROCEDURE AtCurrentPtr( VAR InsertionPoint: CARDINAL ): BOOLEAN;
  76. (*Because lots of routines call FindRecord, sometimes
  77. in sequence when they're all looking for the same record,
  78. it's usually a good bet that the record you want is
  79. either at the current pointer for the ndx list or at
  80. least needs to be inserted there. This routine
  81. determines whether that is true, and if it is, allows us
  82. to skip the binary search through the whole list.*)
  83. VAR
  84. CompResult: INTEGER;
  85. now: CARDINAL;
  86. BEGIN
  87. InsertionPoint := 0;
  88. (*If AtCurrentPtr comes back FALSE but with a non-zero
  89. value in its parameter, it means we didn't find the
  90. record but we know its insertion point.*)
  91. now := GenLists.ElmtNow(NdxFile^.Ndx);
  92. IF (now = 0) OR (now > GenLists.ListLength(NdxFile^.Ndx)) THEN
  93. (* list has not been used at all yet (or is empty) *)
  94. RETURN FALSE;
  95. END;
  96. GenLists.GetElmt( NdxFile^.Ndx, now, TmpElmt, TypeCode );
  97. CompResult := CompareProc(RecordName, TmpElmt.RecName);
  98. CASE CompResult OF
  99. 0 :
  100. M2Strings.Assign( TmpElmt.RecName, RecordName );
  101. RETURN TRUE;
  102. | 1 :
  103. IF GenLists.ElmtNow( NdxFile^.Ndx ) = 1 THEN
  104. (*We were at the first of the list and RecordName was
  105. less than TmpElmt.RecName, so we know the
  106. insertion point.*)
  107. InsertionPoint := 1;
  108. RETURN FALSE;
  109. END;
  110. GenLists.NextElmt( NdxFile^.Ndx, -1, TmpElmt, TypeCode );
  111. CompResult := CompareProc( RecordName, TmpElmt.RecName );
  112. IF CompResult = 0 THEN
  113. M2Strings.Assign( TmpElmt.RecName, RecordName );
  114. RETURN TRUE;
  115. ELSIF CompResult = -1 THEN
  116. (*We know the insertion point is between this
  117. element and the last one we tried.*)
  118. InsertionPoint := GenLists.ElmtNow(NdxFile^.Ndx) + 1;
  119. END;
  120. RETURN FALSE;
  121. |-1 :
  122. IF now = GenLists.ListLength(NdxFile^.Ndx) THEN
  123. (*We were at the end of the list and RecordName was
  124. greater than TmpElmt.RecName, so we know the insertion
  125. point.*)
  126. InsertionPoint := now + 1;
  127. RETURN FALSE;
  128. END;
  129. GenLists.NextElmt( NdxFile^.Ndx, 1, TmpElmt, TypeCode );
  130. CompResult := CompareProc( RecordName, TmpElmt.RecName );
  131. IF CompResult = 0 THEN
  132. M2Strings.Assign( TmpElmt.RecName, RecordName );
  133. RETURN TRUE;
  134. ELSIF CompResult = 1 THEN
  135. (*We know the insertion point is between this
  136. element and the last one we tried.*)
  137. InsertionPoint := GenLists.ElmtNow(NdxFile^.Ndx);
  138. END;
  139. RETURN FALSE;
  140. END;
  141. RETURN FALSE;
  142. END AtCurrentPtr;
  143. BEGIN
  144. IF AtCurrentPtr( AllocSize ) THEN
  145. found := TRUE;
  146. ELSE
  147. IF AllocSize # 0 THEN
  148. RETURN FALSE;
  149. END;
  150. found := FALSE;
  151. offset := Numbers.Lc( 0);
  152. UsedRecSize := 0;
  153. ListPos := 1;
  154. HiBound := GenLists.ListLength(NdxFile^.Ndx) + 1;
  155. IF HiBound = 1 THEN
  156. AllocSize := 1;
  157. RETURN FALSE;
  158. END;
  159. LoBound := 0;
  160. StillLooking := TRUE;
  161. GenLists.GetElmt( NdxFile^.Ndx, 1, TmpElmt, TypeCode );
  162. END;
  163. WHILE (NOT found) AND StillLooking DO
  164. CompResult := CompareProc(RecordName,
  165. TmpElmt.RecName);
  166. IF CompResult = 0 THEN
  167. M2Strings.Assign( TmpElmt.RecName, RecordName );
  168. found := TRUE;
  169. ELSIF CompResult < 0 THEN
  170. (* new name is higher than current spot in list;
  171. so try to move higher in list *)
  172. distance := (HiBound - ListPos) DIV 2;
  173. LoBound := ListPos;
  174. INC( ListPos, distance );
  175. IF distance = 0 THEN
  176. StillLooking := FALSE;
  177. AllocSize := ListPos + 1;
  178. ELSE
  179. GenLists.NextElmt(NdxFile^.Ndx, distance, TmpElmt, TypeCode);
  180. END;
  181. ELSE
  182. distance := (ListPos - LoBound) DIV 2;
  183. HiBound := ListPos;
  184. DEC( ListPos, distance );
  185. IF distance = 0 THEN
  186. StillLooking := FALSE;
  187. AllocSize := ListPos;
  188. ELSE
  189. GenLists.NextElmt(NdxFile^.Ndx, -INTEGER(distance),
  190. TmpElmt, TypeCode);
  191. END;
  192. END;
  193. END;
  194. IF NOT found THEN
  195. (*If we can't find RecordName in the list ... *)
  196. RETURN FALSE;
  197. ELSE
  198. (*Return file location of record.*)
  199. offset := TmpElmt.FilePos;
  200. UsedRecSize := TmpElmt.UsedChars;
  201. AllocSize := TmpElmt.Allocated;
  202. RETURN TRUE;
  203. END;
  204. END FindRecord;
  205. PROCEDURE RemoveCodes( Source: SYSTEM.ADDRESS; VAR TheSize: CARDINAL);
  206. (* Removes all chars that follow CodeChars, and changes
  207. TheSize to reflect number of chars removed. *)
  208. VAR
  209. tmpsize, toskip : CARDINAL;
  210. badspot : SYSTEM.ADDRESS;
  211. tmpchar : CHAR;
  212. BEGIN
  213. tmpsize := TheSize;
  214. tmpchar := CodeChar;
  215. LOOP
  216. toskip := PosUtils.PatternScan( SYSTEM.ADR(tmpchar),
  217. 1, Source, tmpsize );
  218. IF toskip >= tmpsize THEN
  219. RETURN
  220. END;
  221. badspot := LowLevel.AddAddr( Source, toskip + 1 );
  222. DEC( tmpsize, toskip + 1);
  223. LowLevel.ShiftArrayLeft( badspot, tmpsize, 1 );
  224. Source := badspot;
  225. DEC( TheSize);
  226. END;
  227. END RemoveCodes;
  228. PROCEDURE StripList( VAR TheList: GenLists.GenList);
  229. (* Converts CodedStrs to CodeChars in TheList *)
  230. VAR
  231. OldSize, NewSize, ElmntType, cnt, leng: CARDINAL;
  232. SubList: GenLists.GenList;
  233. GenAddr: SYSTEM.ADDRESS;
  234. BEGIN
  235. leng := GenLists.ListLength( TheList );
  236. FOR cnt := 1 TO leng DO
  237. GenLists.GetElmtAdr( TheList, cnt, GenAddr, OldSize, ElmntType);
  238. NewSize := OldSize;
  239. IF ElmntType # GenLists.ListCode THEN
  240. RemoveCodes( GenAddr, NewSize );
  241. IF OldSize # NewSize THEN
  242. (* do not replace unless code chars found *)
  243. GenLists.ListReplaceAdr( GenAddr, NewSize, ElmntType,
  244. TheList, cnt);
  245. END;
  246. ELSE
  247. (* this element is a list *)
  248. GenLists.GetChildList( TheList, cnt, SubList);
  249. StripList( SubList );
  250. (* strip this sub list *)
  251. END;
  252. END;
  253. END StripList;
  254. PROCEDURE ReadStructure( NdxFile: NdxTypes.NdxFileType;
  255. VAR HadToRebuild: BOOLEAN): BOOLEAN;
  256. (*Note that this is the first procedure that will have an
  257. opportunity to determine whether the user is trying to open
  258. a file that is not a valid NdxFile. It has to be very
  259. careful about relying on values it gets from the file.*)
  260. VAR
  261. tmpstr: ARRAY [0..80] OF CHAR;
  262. checkchar: CHAR;
  263. bufsize, dumcard: CARDINAL;
  264. ReadBuf : SYSTEM.ADDRESS;
  265. TmpHandle: VStorage.MemHandle;
  266. BEGIN
  267. (*ReadStructure*)
  268. HadToRebuild := FALSE;
  269. bufsize := 0;
  270. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, NumTypes.L0 );
  271. CASE HandleIO.BlockRead( NdxFile^.handle, SYSTEM.ADR(bufsize), 2) OF
  272. (*Read the file's first two bytes into bufsize.*)
  273. StringIO.NoError: (*fall through*);
  274. ELSE
  275. RETURN FALSE;
  276. END;
  277. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, Numbers.Lc( 2));
  278. (*Put the pointer on the third byte in the file.*)
  279. IF NOT VStorage.IsAvailable( bufsize ) THEN
  280. ErrorNames.WarningName('Mem');
  281. RETURN FALSE;
  282. END;
  283. IF NOT VStorage.AllocMem( TmpHandle, bufsize ) THEN
  284. ErrorNames.WarningName('Mem');
  285. RETURN FALSE;
  286. END;
  287. ReadBuf := VStorage.LockMem( TmpHandle );
  288. CASE HandleIO.BlockRead( NdxFile^.handle, ReadBuf, bufsize) OF
  289. (*Read the structure record into the ReadBuf.*)
  290. StringIO.NoError, StringIO.EndOfFile: (*fall through*);
  291. ELSE
  292. VStorage.DeallocMem( TmpHandle, bufsize);
  293. RETURN FALSE;
  294. END;
  295. (*
  296. Diagnostics.diagBlock( NdxFile^.name, ReadBuf, bufsize );
  297. *)
  298. LowLevel.Fill( ReadBuf, 4, 0C );
  299. LowLevel.Fill( LowLevel.AddAddr(ReadBuf, bufsize - 2), 2, 0C );
  300. (*Wipe out the startsep and endsep that brackets the whole
  301. structure.*)
  302. VStorage.UnLockMem( TmpHandle );
  303. GenLists.NewList( NdxFile^.StructLst );
  304. ListUtils.HandleToList( TmpHandle, bufsize, StartSep, EndSep, 0, 0,
  305. NdxFile^.StructLst);
  306. IF GenLists.ListLength( NdxFile^.StructLst ) = 0 THEN
  307. GenLists.DisposeList( NdxFile^.StructLst);
  308. RETURN FALSE;
  309. END;
  310. GenLists.GetElmt( NdxFile^.StructLst, 1, tmpstr, dumcard);
  311. checkchar := tmpstr[0];
  312. M2Strings.Delete(tmpstr, 0, 1);
  313. IF NOT PosUtils.Equal( tmpstr, StructName) THEN
  314. GenLists.DisposeList( NdxFile^.StructLst);
  315. RETURN FALSE;
  316. ELSIF checkchar = IsGarbageByte THEN
  317. (*
  318. Diagnostics.diagS( 'STRUCTURE record is marked garbage', checkchar );
  319. *)
  320. RebuildProc( NdxFile );
  321. (*Structure record gets marked as garbage when you write a
  322. record but don't update the ndx. Gets marked okay when
  323. the ndx gets written.*)
  324. HadToRebuild := TRUE;
  325. END;
  326. GenLists.ListDelete( NdxFile^.StructLst, 1, 1);
  327. (* deletes the StructName from the Structure *)
  328. StripList( NdxFile^.StructLst );
  329. (*Removes CodedStrs from StructLst.*)
  330. RETURN TRUE;
  331. END ReadStructure;
  332. PROCEDURE MakeEmptyBuf( VAR StruList, BufList: GenLists.GenList);
  333. VAR
  334. LastCode, TheType, cnt, StructLstLength : CARDINAL;
  335. SubStruList, EmptyList: GenLists.GenList;
  336. BEGIN
  337. StructLstLength := GenLists.ListLength( StruList);
  338. LastCode := GenLists.ListCode;
  339. FOR cnt := 1 TO StructLstLength DO
  340. (* write a ListBuf element for each structure element *)
  341. TheType := ListUtils.TypeCheck( StruList, cnt );
  342. (* get next element from structure list *)
  343. IF TheType = GenLists.ListCode THEN
  344. IF LastCode = GenLists.ListCode THEN
  345. ErrorNames.WarningName( 'BadStruc' );
  346. END;
  347. GenLists.NewList( EmptyList);
  348. GenLists.ListInsert( EmptyList, GenLists.ListCode,
  349. BufList, AfterLastElmt);
  350. GenLists.GetChildList( StruList, cnt, SubStruList);
  351. MakeEmptyBuf( SubStruList, EmptyList);
  352. ELSE
  353. IF LastCode # GenLists.ListCode THEN
  354. GenLists.ListInsert( 0C, GenLists.StrCode, BufList,
  355. AfterLastElmt);
  356. END;
  357. END;
  358. LastCode := TheType;
  359. END;
  360. IF LastCode # GenLists.ListCode THEN
  361. GenLists.ListInsert( 0C, GenLists.StrCode, BufList,
  362. AfterLastElmt);
  363. END;
  364. END MakeEmptyBuf;
  365. PROCEDURE OpenNdxFile( VAR NdxFile: NdxTypes.NdxFileType;
  366. FileName: ARRAY OF CHAR): BOOLEAN;
  367. (*Uses HandleIO FindFile routine to open NdxFile. Returns
  368. FALSE if not found. Otherwise initializes NdxFile and
  369. creates linked list of record names, record sizes, and file
  370. offsets from the ndx stored at the end of NdxFile.*)
  371. PROCEDURE ReadNdx( NdxFile: NdxTypes.NdxFileType );
  372. VAR
  373. TmpAvail, len1, len2, FilePos, BytesToRead : LONGINT;
  374. CheckStr: ARRAY [0..1] OF CHAR;
  375. NdxAddr : SYSTEM.ADDRESS;
  376. TmpHandle : VStorage.MemHandle;
  377. TmpNdx: GenLists.GenList;
  378. ThisChunk: CARDINAL;
  379. BEGIN
  380. (*ReadNdx*)
  381. HandleIO.SetFilePtr(NdxFile^.handle, HandleIO.FromEnd,
  382. Numbers.Li( -4) );
  383. (*Goto end of file and read Ndx offset*)
  384. IF StringIO.NoError <> HandleIO.BlockRead(NdxFile^.handle,
  385. SYSTEM.ADR(FilePos), 4) THEN
  386. ErrorNames.WarningName( 'FRead' );
  387. RETURN;
  388. END;
  389. IF (FilePos < NumTypes.L0) OR
  390. ( FilePos > HandleIO.FileLength(NdxFile^.handle)) THEN
  391. (*
  392. Diagnostics.diagL( 'FilePos', FilePos );
  393. *)
  394. RebuildProc( NdxFile );
  395. RETURN;
  396. END;
  397. HandleIO.SetFilePtr(NdxFile^.handle, HandleIO.FromStart, FilePos);
  398. (*Now we should be sitting on the NdxMarker.*)
  399. NdxFile^.NdxFilePtr := FilePos;
  400. (*Set file pointer to start of the index.*)
  401. len1 := HandleIO.FileLength(NdxFile^.handle) - FilePos;
  402. (* len1 is the file size minus the data *)
  403. BytesToRead := len1 - Numbers.Lc( 6);
  404. (* the index size *)
  405. IF BytesToRead = NumTypes.L0 THEN
  406. (* return empty index if index area of file is empty *)
  407. GenLists.NewList( NdxFile^.Ndx );
  408. RETURN;
  409. END;
  410. (*Now we check to make sure our offset numbers are valid by
  411. looking for the NdxMarker.*)
  412. IF HandleIO.BlockRead(NdxFile^.handle, SYSTEM.ADR(CheckStr),
  413. 2) # StringIO.NoError THEN
  414. (*
  415. Diagnostics.diagL( 'BlockRead failure at', FilePos );
  416. *)
  417. RebuildProc( NdxFile );
  418. RETURN;
  419. END;
  420. IF NOT PosUtils.Equal( CheckStr, NdxMarker) THEN
  421. (*
  422. Diagnostics.diagS( 'Invalid CheckStr:', CheckStr );
  423. *)
  424. RebuildProc( NdxFile );
  425. RETURN;
  426. END;
  427. IF (BytesToRead MOD Numbers.Lc( SYSTEM.TSIZE(NdxTypes.NdxElement)))
  428. # NumTypes.L0 THEN
  429. (*If the size of the index does not divide evenly by the
  430. size of an NdxElement, then the size of an NdxElement
  431. has been changed since the file was last used, and we
  432. have to rebuild.*)
  433. (*
  434. Diagnostics.diagL( 'BytesToRead', BytesToRead );
  435. *)
  436. RebuildProc( NdxFile );
  437. RETURN;
  438. END;
  439. (* Next, read in the index *)
  440. GenLists.NewList( NdxFile^.Ndx );
  441. WHILE BytesToRead > NumTypes.L0 DO
  442. TmpAvail := VStorage.AvailMem();
  443. (*If EMS is installed, more than 64K may be available,
  444. so we do this in two steps.*)
  445. IF TmpAvail > NumTypes.L65535 THEN
  446. ThisChunk := 65535;
  447. ELSE
  448. ThisChunk := Numbers.C( TmpAvail );
  449. END;
  450. DEC( ThisChunk, ThisChunk MOD SYSTEM.TSIZE(NdxTypes.NdxElement) );
  451. IF ThisChunk < SYSTEM.TSIZE(NdxTypes.NdxElement) THEN
  452. ErrorNames.WarningName('Mem');
  453. RETURN;
  454. END;
  455. IF BytesToRead > Numbers.Lc( ThisChunk) THEN
  456. BytesToRead := BytesToRead - Numbers.Lc( ThisChunk );
  457. ELSE
  458. ThisChunk := Numbers.C( BytesToRead);
  459. BytesToRead := NumTypes.L0;
  460. END;
  461. IF NOT VStorage.AllocMem( TmpHandle, ThisChunk ) THEN
  462. ErrorNames.WarningName('Mem');
  463. RETURN;
  464. END;
  465. NdxAddr := VStorage.LockMem( TmpHandle );
  466. IF HandleIO.BlockRead(NdxFile^.handle, NdxAddr, ThisChunk)
  467. # StringIO.NoError THEN
  468. VStorage.UnLockMem( TmpHandle );
  469. VStorage.DeallocMem( TmpHandle, ThisChunk );
  470. (*
  471. Diagnostics.diagC( 'Unable to read ThisChunk # of bytes:', ThisChunk );
  472. *)
  473. RebuildProc( NdxFile );
  474. RETURN;
  475. END;
  476. VStorage.UnLockMem( TmpHandle );
  477. GenLists.NewList( TmpNdx );
  478. ListUtils.HandleToList( TmpHandle, ThisChunk, '', '',
  479. SYSTEM.TSIZE(NdxTypes.NdxElement), NdxTypes.NdxTypeCode,
  480. TmpNdx );
  481. (*The nulls mean "there are no delimiters in the
  482. block."*)
  483. len1 := Numbers.Lc( GenLists.ListLength(TmpNdx));
  484. len2 := Numbers.Lc( GenLists.ListLength(NdxFile^.Ndx));
  485. IF (len1 + len2) > NumTypes.L65535 THEN
  486. ErrorNames.WarningName('RecLim');
  487. END;
  488. GenLists.JoinLists( TmpNdx, NdxFile^.Ndx,
  489. GenLists.ListLength(NdxFile^.Ndx) + 1 );
  490. END;
  491. END ReadNdx;
  492. VAR
  493. NdxRebuilt : BOOLEAN;
  494. BEGIN
  495. (*OpenNdxFile*)
  496. NdxTypes.InitNdxFile( NdxFile );
  497. M2Strings.Assign( FileName, NdxFile^.name );
  498. IF HandleIO.FindFile( NdxFile^.handle, NdxFile^.name, "path" )
  499. # StringIO.NoError THEN
  500. (*Find and open the ndx file if it exists.*)
  501. NdxFile^.name := "";
  502. VStorage.DosDealloc( NdxFile, SYSTEM.TSIZE(NdxTypes.NdxRecord) );
  503. NdxFile := NIL;
  504. (*Some Storage modules don't nil out the pointer after
  505. deallocating it, so we do it ourselves.*)
  506. RETURN FALSE;
  507. END;
  508. IF NOT ReadStructure( NdxFile, NdxRebuilt) THEN
  509. (*Reads the zero record and fills the StructLst in
  510. NdxFile^.*)
  511. VStorage.DosDealloc( NdxFile, SYSTEM.TSIZE(NdxTypes.NdxRecord) );
  512. NdxFile := NIL;
  513. RETURN FALSE;
  514. END;
  515. IF NOT NdxRebuilt THEN
  516. ReadNdx( NdxFile);
  517. (*Load a linked list with the record index for this file.*)
  518. END;
  519. NdxFile^.FileBufPtr := NIL;
  520. GenLists.NewList( NdxFile^.ListBuf );
  521. MakeEmptyBuf( NdxFile^.StructLst, NdxFile^.ListBuf );
  522. RETURN TRUE;
  523. END OpenNdxFile;
  524. PROCEDURE InitBuffer( VAR NdxFile: NdxTypes.NdxFileType; RecName: ARRAY
  525. OF CHAR): BOOLEAN;
  526. (* called by PutField and GetField to load the record data
  527. into the list buffer. If RecordName is already in BufRecName
  528. RETURNs TRUE. If not, checks to see if RecName exists in
  529. index. If no, returns FALSE. If OK, retrieves record,
  530. then moves read buffer into GenList in ListBuf. IF all OK,
  531. returns TRUE.*)
  532. VAR
  533. NameFound: ARRAY [0..NdxTypes.RecNameLength] OF CHAR;
  534. NameAdr : SYSTEM.ADDRESS;
  535. NameSize : CARDINAL;
  536. checkchar: CHAR;
  537. OffSet: LONGINT;
  538. UsedSize, AllocatedSize, dumcard: CARDINAL;
  539. BEGIN
  540. NdxTypes.CheckInit( NdxFile);
  541. StrEdit.CrunchBlanks( RecName );
  542. IF PosUtils.Equal(RecName, NdxFile^.BufRecName) THEN
  543. RETURN TRUE;
  544. ELSIF M2Strings.Length(RecName) = 0 THEN
  545. RETURN FALSE;
  546. END;
  547. IF GenLists.Initialized( NdxFile^.ListBuf ) THEN
  548. GenLists.DisposeList( NdxFile^.ListBuf );
  549. END;
  550. IF NOT FindRecord( NdxFile, RecName, OffSet, UsedSize,
  551. AllocatedSize ) THEN
  552. GenLists.NewList( NdxFile^.ListBuf );
  553. MakeEmptyBuf( NdxFile^.StructLst, NdxFile^.ListBuf );
  554. M2Strings.Assign( RecName, NdxFile^.BufRecName );
  555. RETURN FALSE;
  556. END;
  557. VStorage.DosAlloc( NdxFile^.FileBufPtr, UsedSize );
  558. NdxFile^.BufSizeNow := UsedSize;
  559. HandleIO.SetFilePtr(NdxFile^.handle, HandleIO.FromStart, OffSet );
  560. IF NOT (StringIO.NoError = HandleIO.BlockRead( NdxFile^.handle,
  561. NdxFile^.FileBufPtr, UsedSize)) THEN
  562. VStorage.DosDealloc( NdxFile^.FileBufPtr, UsedSize );
  563. NdxFile^.BufSizeNow := 0;
  564. RETURN FALSE;
  565. END;
  566. LowLevel.Fill( NdxFile^.FileBufPtr, 4 (*SIZE(StartSep) +
  567. SIZE(TypeCode)*), 0C );
  568. LowLevel.Fill( LowLevel.AddAddr( NdxFile^.FileBufPtr,
  569. UsedSize - 2 ), 2, 0C );
  570. (*These two fills wipe out the startsep and endsep that begin
  571. and end each record.*)
  572. M2Strings.Assign( RecName, NdxFile^.BufRecName );
  573. (* put current record name in BufRecName *)
  574. GenLists.NewList( NdxFile^.ListBuf );
  575. GenLists.BlockToList( NdxFile^.FileBufPtr, NdxFile^.BufSizeNow,
  576. StartSep, EndSep, 0, 0, NdxFile^.ListBuf);
  577. IF GenLists.ErrorFlag # GenLists.NoListError THEN
  578. RETURN FALSE;
  579. END;
  580. IF GenLists.ListLength( NdxFile^.ListBuf ) > 0 THEN
  581. StripList( NdxFile^.ListBuf );
  582. GenLists.GetElmtAdr( NdxFile^.ListBuf, 1, NameAdr,
  583. NameSize, dumcard );
  584. (* We want to store the record name in NameFound, but first we
  585. have to check it so that we can warn intelligently
  586. in case of file damage. *)
  587. NameSize := LowLevel.ScanEQ( NameSize, 0C, NameAdr );
  588. (* Reduce NameSize to length of string before the null. *)
  589. IF NameSize <= NdxTypes.RecNameLength THEN
  590. LowLevel.Move( NameAdr, SYSTEM.ADR(NameFound), NameSize + 1 );
  591. (* It's NameSize + 1 because we have to make sure the trailing
  592. null gets included in the move. *)
  593. ELSE
  594. ErrorNames.WarningName( 'RecDam' );
  595. END;
  596. GenLists.ListDelete( NdxFile^.ListBuf, 1, 1 );
  597. (*Delete the record name from the ListBuf.*)
  598. ELSE
  599. MakeEmptyBuf( NdxFile^.StructLst, NdxFile^.ListBuf );
  600. RETURN TRUE;
  601. (*Actually something has probably gone wrong here--a
  602. record has apparently been written to the file that
  603. doesn't even have the record-bracketing StartSep and
  604. EndSep. But maybe we're about to correct it, so we
  605. return TRUE.*)
  606. END;
  607. checkchar := NameFound[0];
  608. M2Strings.Delete(NameFound, 0, 1);
  609. RETURN PosUtils.Equal( NameFound, RecName )
  610. (* RecName stored in record read *)
  611. AND (checkchar # IsGarbageByte);
  612. (* Successful closing of file last time it was used *)
  613. END InitBuffer;
  614. PROCEDURE Retrieve( NdxFile: NdxTypes.NdxFileType; RecordName: ARRAY OF
  615. CHAR; BufAddr: SYSTEM.ADDRESS; VAR RecSize: CARDINAL): BOOLEAN;
  616. (* Reads record named into file buffer. Returns TRUE if found,
  617. FALSE if not. *)
  618. VAR
  619. offset: LONGINT;
  620. ListSpot: CARDINAL;
  621. BEGIN
  622. NdxTypes.CheckInit( NdxFile );
  623. IF NOT FindRecord( NdxFile, RecordName, offset, RecSize,
  624. ListSpot ) THEN
  625. (* if RecordName not in index list, return FALSE *)
  626. RETURN FALSE;
  627. END;
  628. HandleIO.SetFilePtr(NdxFile^.handle, HandleIO.FromStart, offset );
  629. RETURN StringIO.NoError = HandleIO.BlockRead( NdxFile^.handle,
  630. BufAddr, RecSize);
  631. END Retrieve;
  632. PROCEDURE NoRebuild( VAR NdxFile: NdxTypes.NdxFileType );
  633. BEGIN
  634. ErrorNames.WarningName( 'NdxDam' );
  635. END NoRebuild;
  636. PROCEDURE Init();
  637. BEGIN
  638. IF Initialized THEN
  639. RETURN;
  640. ELSE
  641. Initialized := TRUE;
  642. END;
  643. (*EntryDiag:
  644. Diagnostics.Init();
  645. :EntryDiag*)
  646. ErrorNames.Init();
  647. HandleIO.Init();
  648. GenLists.Init();
  649. ListUtils.Init();
  650. LowLevel.Init();
  651. M2Strings.Init();
  652. NdxTypes.Init();
  653. Numbers.Init();
  654. NumTypes.Init();
  655. PosUtils.Init();
  656. StrEdit.Init();
  657. StringIO.Init();
  658. VStorage.Init();
  659. (*EntryDiag:
  660. Diagnostics.diagS( 'Entering NdxBones', '' );
  661. :EntryDiag*)
  662. RebuildProc := NoRebuild;
  663. CompareProc := M2Strings.CompareStr;
  664. StartSep[0] := CodeChar;
  665. StartSep[1] := StartChar;
  666. EndSep[0] := CodeChar;
  667. EndSep[1] := EndChar;
  668. CodedStr[0] := CodeChar;
  669. CodedStr[1] := EncodedChar;
  670. NdxMarker[0] := CodeChar;
  671. NdxMarker[1] := NdxMarkChar;
  672. StrEdit.AssignStr( "STRUCTURE", StructName);
  673. (*EntryDiag:
  674. Diagnostics.diagS( 'Exiting NdxBones', '' );
  675. :EntryDiag*)
  676. END Init;
  677. BEGIN
  678. Initialized := FALSE;
  679. Init();
  680. END NdxBones.