NDXFILES.MOD 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. IMPLEMENTATION MODULE NdxFiles;
  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/ndxfiles.mov 1.8 10 Mar 1991 15:30:18 coleb $
  12. *
  13. *)
  14. IMPORT FAPI;
  15. (*EntryDiag:
  16. IMPORT Diagnostics;
  17. :EntryDiag*)
  18. IMPORT Drectory;
  19. IMPORT ErrorManager;
  20. IMPORT ErrorNames;
  21. IMPORT HandleIO;
  22. IMPORT GenLists;
  23. IMPORT ListUtils;
  24. IMPORT LowLevel;
  25. IMPORT M2Strings;
  26. IMPORT NdxBones;
  27. IMPORT NdxTypes;
  28. FROM NdxTypes IMPORT NdxRecord;
  29. IMPORT Numbers;
  30. IMPORT NumTypes;
  31. IMPORT PosUtils;
  32. IMPORT StrEdit;
  33. IMPORT StringIO;
  34. IMPORT SYSTEM;
  35. IMPORT VStorage;
  36. VAR
  37. Initialized : BOOLEAN;
  38. VAR
  39. NulHandle: VStorage.MemHandle;
  40. PROCEDURE NoMemMessage( message: ARRAY OF CHAR );
  41. VAR
  42. tmpstr: ARRAY [0..79] OF CHAR;
  43. BEGIN
  44. StrEdit.AssignStr( 'Ran out of memory in ', tmpstr );
  45. StrEdit.Append( tmpstr, message );
  46. ErrorManager.WARN( tmpstr );
  47. END NoMemMessage;
  48. PROCEDURE CreateNdxFile( VAR NdxFile: NdxTypes.NdxFileType; fname,
  49. Structure: ARRAY OF CHAR );
  50. (*Structure should look something like this:
  51. "Name, Password, AcctBal, Address {Street, City, State}'
  52. Names listed here can be used to access specific fields
  53. within records, using the Get and Put procedures below.
  54. All procedures that use field names are case sensitive. *)
  55. VAR
  56. TmpName: ARRAY [0..255] OF CHAR;
  57. StruSize: CARDINAL;
  58. BytesWritten: LONGINT;
  59. SavedMessage: CARDINAL;
  60. PROCEDURE MakeStructure( VAR StruList: GenLists.GenList; Structure:
  61. ARRAY OF CHAR );
  62. VAR
  63. NextSpot, BraceSpot, CommaSpot: CARDINAL;
  64. SubList: GenLists.GenList;
  65. NameStr: ARRAY [0..255] OF CHAR;
  66. PROCEDURE PosCloseBrace( Start: CARDINAL; Structure:
  67. ARRAY OF CHAR): CARDINAL;
  68. (* find the closing brace that matches this open brace *)
  69. VAR
  70. OpenSpot, CloseSpot: CARDINAL;
  71. BEGIN
  72. CloseSpot := PosUtils.Positn( '}', Structure, Start);
  73. OpenSpot := PosUtils.Positn( '{', Structure, Start);
  74. IF (CloseSpot < OpenSpot) OR
  75. (CloseSpot > HIGH( Structure)) THEN
  76. RETURN CloseSpot;
  77. ELSE
  78. RETURN PosCloseBrace( 1+PosCloseBrace( OpenSpot + 1,
  79. Structure), Structure);
  80. END;
  81. END PosCloseBrace;
  82. BEGIN
  83. (*MakeStructure*)
  84. IF M2Strings.Length(Structure) = 0 THEN
  85. RETURN;
  86. END;
  87. IF Structure[ M2Strings.Length(Structure) - 1 ] # ',' THEN
  88. StrEdit.Append(Structure, ",");
  89. (*Makes all names end the same way for the
  90. convenience of the loop below; nothing will
  91. be appended, however, if a constant structure
  92. string was passed because it completely fills
  93. its array.*)
  94. END;
  95. WHILE M2Strings.Length(Structure) > 0 DO
  96. CommaSpot := PosUtils.Pos(',', Structure);
  97. (*OK if no comma*)
  98. BraceSpot := PosUtils.Pos('{', Structure);
  99. IF CommaSpot < BraceSpot THEN
  100. NextSpot := CommaSpot;
  101. ELSE
  102. NextSpot := BraceSpot;
  103. END;
  104. IF NextSpot = 0 THEN
  105. ErrorNames.WarningName( 'NoNam' );
  106. RETURN;
  107. END;
  108. M2Strings.Copy( Structure, 0, NextSpot, NameStr );
  109. (*Copy everything up to the next separator, but not the
  110. separator itself.*)
  111. M2Strings.Delete( Structure, 0, NextSpot );
  112. (*Delete everything up to but not including
  113. the separator.*)
  114. IF M2Strings.Length( Structure ) > 0 THEN
  115. M2Strings.Delete( Structure, 0, 1 );
  116. (*Delete the separator, if present.*)
  117. END;
  118. GenLists.ListInsert( NameStr, GenLists.StrCode, StruList, 65535);
  119. (* insert this name into the list *)
  120. IF (NextSpot = BraceSpot) AND (BraceSpot <= HIGH(Structure)) THEN
  121. (* the preceeding name has a sublist *)
  122. GenLists.NewList( SubList);
  123. GenLists.ListInsert( SubList, GenLists.ListCode, StruList, 65535);
  124. (* insert a sublist into the list *)
  125. BraceSpot := PosCloseBrace( 0, Structure);
  126. IF BraceSpot > HIGH( Structure) THEN
  127. ErrorNames.WarningName( 'NdxBrac' );
  128. RETURN;
  129. END;
  130. M2Strings.Copy( Structure, 0, BraceSpot, NameStr );
  131. (*Copy everything up to the next brace, but not the
  132. brace itself.*)
  133. M2Strings.Delete( Structure, 0, BraceSpot + 1 );
  134. (*Delete everything up to and including the brace.*)
  135. IF M2Strings.Length( Structure) > 0 THEN
  136. (* now delete comma after closing brace *)
  137. IF Structure[0] # ',' THEN
  138. ErrorNames.WarningName( 'NdxCmm' );
  139. RETURN;
  140. ELSE
  141. M2Strings.Delete( Structure, 0, 1);
  142. END;
  143. END;
  144. MakeStructure( SubList, NameStr);
  145. END;
  146. END;
  147. END MakeStructure;
  148. BEGIN
  149. (*CreateNdxFile*)
  150. NdxTypes.InitNdxFile( NdxFile );
  151. StrEdit.AssignStr( fname, NdxFile^.name );
  152. WITH NdxFile^ DO
  153. StringIO.PrintMessage( HandleIO.CreateFile( handle, name ) );
  154. UpdateNeeded := TRUE;
  155. GenLists.NewList( Ndx);
  156. GenLists.NilList( AltKeys );
  157. GenLists.NewList( ListBuf);
  158. GenLists.NewList( StructLst);
  159. END;
  160. StrEdit.DeleteChar( ' ', Structure );
  161. StrEdit.CAPstr(Structure);
  162. StringIO.WriteStr( NdxFile^.handle, '00' );
  163. (* space at start of file for size of structure to be put *)
  164. MakeStructure( NdxFile^.StructLst, Structure);
  165. M2Strings.Concat( NdxBones.IsGarbageByte, NdxBones.StructName, TmpName);
  166. GenLists.ListInsert( TmpName, GenLists.StrCode, NdxFile^.StructLst, 1);
  167. (* add structure name to structure list *)
  168. SavedMessage := ListUtils.ListToFileHandle(
  169. NdxFile^.StructLst, NdxFile^.handle, NdxBones.StartSep,
  170. NdxBones.EndSep, 0, BytesWritten );
  171. StruSize := Numbers.C( BytesWritten );
  172. IF (SavedMessage # StringIO.NoError) THEN
  173. ErrorNames.WarningName( 'StructCreate' );
  174. END;
  175. GenLists.ListDelete( NdxFile^.StructLst, 1, 1);
  176. (* deletes the StructName from the Structure *)
  177. NdxFile^.NdxFilePtr := Numbers.Lc( 2 + StruSize);
  178. (* Point to NdxMarker *)
  179. StringIO.WriteStr( NdxFile^.handle, NdxBones.NdxMarker );
  180. StringIO.PrintMessage( HandleIO.BlockWrite( NdxFile^.handle,
  181. SYSTEM.ADR(NdxFile^.NdxFilePtr), 4));
  182. (* write ndxmarker & position out to end of file *)
  183. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, Numbers.Lc( 0));
  184. StringIO.PrintMessage( HandleIO.BlockWrite( NdxFile^.handle,
  185. SYSTEM.ADR( StruSize), 2));
  186. (* write size of structure out to start of file *)
  187. NdxBones.MakeEmptyBuf( NdxFile^.StructLst, NdxFile^.ListBuf );
  188. END CreateNdxFile;
  189. PROCEDURE WriteNdx( NdxFile: NdxTypes.NdxFileType );
  190. VAR
  191. BytesWritten: LONGINT;
  192. BEGIN
  193. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart,
  194. NdxFile^.NdxFilePtr );
  195. (*Go to end of data area.*)
  196. StringIO.WriteStr( NdxFile^.handle, NdxBones.NdxMarker);
  197. (*Write NdxMarker.*)
  198. IF StringIO.NoError # ListUtils.ListToFileHandle(
  199. NdxFile^.Ndx, NdxFile^.handle, '', '', 0, BytesWritten ) THEN
  200. (*The nulls mean "don't write delimiters."*)
  201. ErrorNames.WarningName( 'NdxWrt' );
  202. END;
  203. StringIO.PrintMessage( HandleIO.BlockWrite( NdxFile^.handle,
  204. SYSTEM.ADR(NdxFile^.NdxFilePtr), 4) );
  205. (* write starting position of index *)
  206. StringIO.PrintMessage(Drectory.SetFileLength(NdxFile^.handle,
  207. HandleIO.GetFilePtr(NdxFile^.handle)));
  208. HandleIO.UpdateDisk(NdxFile^.handle);
  209. SetFileUpdate( NdxFile^.handle, NdxBones.NotGarbageByte);
  210. NdxFile^.UpdateNeeded := FALSE;
  211. END WriteNdx;
  212. PROCEDURE SetFileUpdate( handle: CARDINAL; GbgByte: CHAR);
  213. BEGIN
  214. (* Puts the passed character in the file's UpdateNeeded
  215. Byte (use IsGarbageByte when file index needs update,
  216. and NotGarbageByte when update no longer needed). *)
  217. HandleIO.SetFilePtr( handle, HandleIO.FromStart, Numbers.Lc( 10));
  218. StringIO.WriteStr( handle, GbgByte);
  219. END SetFileUpdate;
  220. PROCEDURE CloseNdxFile( VAR NdxFile: NdxTypes.NdxFileType );
  221. BEGIN
  222. NdxTypes.CheckInit( NdxFile );
  223. IF NdxFile^.UpdateNeeded THEN
  224. WriteNdx( NdxFile);
  225. (* Write Ndx if it has been changed *)
  226. END;
  227. WITH NdxFile^ DO
  228. GenLists.DisposeList( ListBuf);
  229. GenLists.DisposeList( StructLst);
  230. GenLists.DisposeList( Ndx );
  231. GenLists.DisposeList( AltKeys );
  232. (*Note that we don't dispose of the FileBufPtr because
  233. it should always have been absorbed into the ListBuf.*)
  234. IF handle # 0 THEN
  235. (*handle may be 0 if the NdxFile record was initialized
  236. but never passed to OpenNdxFile.*)
  237. StringIO.PrintMessage( HandleIO.CloseHandle( handle) );
  238. END;
  239. END;
  240. VStorage.DosDealloc( NdxFile, SYSTEM.TSIZE(NdxRecord) );
  241. END CloseNdxFile;
  242. PROCEDURE ChangedIndex(NdxFile: NdxTypes.NdxFileType);
  243. BEGIN
  244. (* need to account for small changes to index or just big?? *)
  245. IF NdxFile^.SafetyOn THEN
  246. WriteNdx( NdxFile);
  247. HandleIO.UpdateDisk( NdxFile^.handle );
  248. (* writes entire index at end of file *)
  249. ELSE
  250. IF NOT NdxFile^.UpdateNeeded THEN
  251. SetFileUpdate( NdxFile^.handle, NdxBones.IsGarbageByte);
  252. NdxFile^.UpdateNeeded := TRUE;
  253. END;
  254. END;
  255. END ChangedIndex;
  256. PROCEDURE DeleteRecord( VAR NdxFile: NdxTypes.NdxFileType;
  257. RecName: ARRAY OF CHAR ): BOOLEAN;
  258. (*Marks RecName as garbage in the linked list so that
  259. CrunchNdxFile can delete it from the file, sets garbage
  260. byte in file record, and erases in current buffer (if
  261. there). If SafetyOn is set for this NdxFile, also writes
  262. the linked list out to the file.*)
  263. VAR
  264. FilePos: LONGINT;
  265. UsedSize, AllocSize : CARDINAL;
  266. BEGIN
  267. NdxTypes.CheckInit( NdxFile );
  268. StrEdit.CrunchBlanks( RecName );
  269. IF (M2Strings.Length(RecName) = 0) OR
  270. (NOT NdxBones.FindRecord( NdxFile, RecName, FilePos, UsedSize,
  271. AllocSize)) THEN
  272. (* If don't find record in index, return FALSE *)
  273. RETURN FALSE;
  274. END;
  275. IF NOT ChangeNdxEntry( RecName, '', FilePos, AllocSize,
  276. NdxFile) THEN
  277. RETURN FALSE;
  278. END;
  279. (* change index entry to garbage *)
  280. INC( FilePos, 8 );
  281. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, FilePos);
  282. StringIO.WriteStr( NdxFile^.handle, NdxBones.IsGarbageByte);
  283. (* write garbage byte in old record *)
  284. IF PosUtils.Equal(RecName, NdxFile^.BufRecName) THEN
  285. (* if record is now in buffer, erase it *)
  286. StrEdit.SetLength( NdxFile^.BufRecName, 0);
  287. END;
  288. ChangedIndex( NdxFile);
  289. RETURN TRUE;
  290. END DeleteRecord;
  291. PROCEDURE EncodeList( VAR TheList: GenLists.GenList);
  292. PROCEDURE EnCodeField( OldAddr: SYSTEM.ADDRESS; OldSize,
  293. NumberFound: CARDINAL; VAR NewAddr: SYSTEM.ADDRESS;
  294. VAR NewSize: CARDINAL);
  295. (* Change all occurences of CodeChar to CodedStr *)
  296. VAR
  297. tmpsize, toskip : CARDINAL;
  298. Source, Dest: SYSTEM.ADDRESS;
  299. BEGIN
  300. NewSize := NumberFound + OldSize;
  301. VStorage.DosAlloc( NewAddr, NewSize);
  302. (* max size needed *)
  303. tmpsize := OldSize;
  304. Source := OldAddr;
  305. (* starting address *)
  306. Dest := NewAddr;
  307. LOOP
  308. toskip := LowLevel.ScanEQ( tmpsize, NdxBones.CodeChar, Source);
  309. (* look for next CodeChar *)
  310. LowLevel.Move( Source, Dest, toskip);
  311. IF toskip >= tmpsize THEN
  312. EXIT;
  313. END;
  314. Dest := LowLevel.AddAddr( Dest, toskip );
  315. LowLevel.Move( SYSTEM.ADR( NdxBones.CodedStr), Dest, 2);
  316. Dest := LowLevel.AddAddr( Dest, 2 );
  317. INC( OldSize);
  318. Source := LowLevel.AddAddr( Source, toskip + 1 );
  319. DEC( tmpsize, toskip + 1);
  320. END;
  321. END EnCodeField;
  322. VAR
  323. NumberFound, OldSize, NewSize, ElmntType, cnt, leng: CARDINAL;
  324. SubList: GenLists.GenList;
  325. OldAddr, NewAddr: SYSTEM.ADDRESS;
  326. BEGIN
  327. leng := GenLists.ListLength( TheList );
  328. FOR cnt := 1 TO leng DO
  329. GenLists.GetElmtAdr( TheList, cnt, OldAddr, OldSize, ElmntType);
  330. IF ElmntType # GenLists.ListCode THEN
  331. NumberFound := PosUtils.ByteCount( OldSize,
  332. NdxBones.CodeChar, OldAddr );
  333. IF NumberFound > 0 THEN
  334. (* do not replace unless code chars found *)
  335. EnCodeField( OldAddr, OldSize, NumberFound, NewAddr, NewSize );
  336. GenLists.ListReplaceAdr( NewAddr, NewSize, ElmntType,
  337. TheList, cnt);
  338. VStorage.DosDealloc( NewAddr,NewSize ); (* 9/14/91
  339. per report from J March *)
  340. END;
  341. ELSE
  342. (* this element is a list *)
  343. GenLists.GetChildList( TheList, cnt, SubList);
  344. IF GenLists.Initialized( SubList ) THEN
  345. (*Make sure it's not a nil list.*)
  346. EncodeList( SubList );
  347. (* encode this sublist *)
  348. END;
  349. END;
  350. END;
  351. END EncodeList;
  352. PROCEDURE WriteRecord( VAR NdxFile: NdxTypes.NdxFileType;
  353. RecName: ARRAY OF CHAR ): BOOLEAN;
  354. (*First checks to see whether RecName is in the List buffer
  355. created by the Put routines below. Returns FALSE if it
  356. isn't. If it is, then checks to see whether RecName is in
  357. the list of existing record names. If so, and if the
  358. record will still fit in its old spot in the file,
  359. WriteRecord overwrites the old spot in the file with the
  360. data in the list buffer. Otherwise, it adds the record to
  361. the end of the NdxFile, overwriting the ndx, and if the
  362. record is not new, marks the spot it formerly occupied as
  363. garbage. If the NdxFile's SafetyOn feature has been turned
  364. on, a new ndx will be written each time a record is added
  365. to the end of the NdxFile. Otherwise, the new ndx will be
  366. written only when CloseNdxFile is called.*)
  367. VAR
  368. OldTotalBytes, OldUsedBytes, NewTotData, NumLsts:
  369. CARDINAL;
  370. BytesWritten, NumElmts, NewFilePtr, offset, TotMem: LONGINT;
  371. OldEntry, RecordExists: BOOLEAN;
  372. TmpStr: ARRAY [0..79] OF CHAR;
  373. SavedMessage: CARDINAL;
  374. BEGIN
  375. (* WriteRecord *)
  376. NdxTypes.CheckInit( NdxFile );
  377. StrEdit.CrunchBlanks( RecName );
  378. IF NOT PosUtils.Equal(RecName, NdxFile^.BufRecName) THEN
  379. (* if record not in buffer, return FALSE *)
  380. RETURN( FALSE );
  381. END;
  382. StrEdit.AssignStr( RecName, TmpStr );
  383. M2Strings.Insert( NdxBones.NotGarbageByte, TmpStr, 0 );
  384. GenLists.ListInsert( TmpStr, GenLists.StrCode,
  385. NdxFile^.ListBuf, 1 );
  386. (*Put the record name into the ListBuf.*)
  387. StrEdit.SetLength( NdxFile^.BufRecName, 0);
  388. (*We set BufRecName to null to guarantee that this record
  389. gets read from the file next time it is needed, because
  390. we are about to encode it.*)
  391. OldTotalBytes := 0;
  392. RecordExists := NdxBones.FindRecord( NdxFile, RecName,
  393. offset, OldUsedBytes, OldTotalBytes);
  394. EncodeList( NdxFile^.ListBuf );
  395. NewTotData := Numbers.C( GenLists.ListSize( NdxFile^.ListBuf,
  396. NumElmts, NumLsts, TotMem));
  397. (* find out maximum size of data in record to be written *)
  398. INC( NewTotData, 6 + 6 * Numbers.C( NumElmts));
  399. (* add room for: 2 char start & end seps for record,
  400. 2 char start & end seps for every element, and
  401. 2 char TypeCode for every element & for record *)
  402. OldEntry := RecordExists AND (NewTotData <= OldTotalBytes);
  403. (* whether record exists and old file spot is big enough *)
  404. IF OldEntry THEN
  405. (* rewrite in old spot if not too big *)
  406. IF NOT ChangeNdxEntry( RecName, RecName, offset,
  407. NewTotData, NdxFile) THEN
  408. RETURN FALSE;
  409. END;
  410. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, offset );
  411. NewFilePtr := offset;
  412. (*I'm not sure this assignment is necessary, but it
  413. prevents confusion.*)
  414. ELSE
  415. (* new entry is too big; so delete old index entry and
  416. write at end *)
  417. IF RecordExists THEN
  418. (* change old entry to garbage *)
  419. IF NOT ChangeNdxEntry( RecName, '', offset,
  420. OldTotalBytes, NdxFile) THEN
  421. RETURN FALSE;
  422. END;
  423. INC( offset, 8 );
  424. (*We skip past the record's first NdxBones.StartSep and
  425. its ListCode, plus the NdxBones.StartSep for the
  426. RecordName and its StrCode. Using a numeric literal
  427. here is dangerous.*)
  428. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, offset);
  429. StringIO.WriteStr( NdxFile^.handle, NdxBones.IsGarbageByte);
  430. (* write garbage byte in old record *)
  431. END;
  432. NewFilePtr := NdxFile^.NdxFilePtr;
  433. (*NdxFile^.NdxFilePtr always points at the end of the
  434. NdxFile's data area--at the NdxMarker, in other words.*)
  435. OldTotalBytes := NewTotData;
  436. (* initialize two variables that InsertNdxEntry will
  437. update if it finds old garbage space to re-use *)
  438. IF NOT InsertNdxEntry( RecName, NewFilePtr, NewTotData,
  439. OldTotalBytes, NdxFile) THEN
  440. (* make new entry for this record, or re-use garbage
  441. space *)
  442. RETURN FALSE;
  443. END;
  444. (* make new index entry *)
  445. HandleIO.SetFilePtr( NdxFile^.handle, HandleIO.FromStart, NewFilePtr);
  446. (* put file pointer at start of this new record *)
  447. END;
  448. SavedMessage := ListUtils.ListToFileHandle( NdxFile^.ListBuf,
  449. NdxFile^.handle, NdxBones.StartSep, NdxBones.EndSep, 0,
  450. BytesWritten );
  451. IF BytesWritten # Numbers.Lc(NewTotData) THEN
  452. (*we've miscalculated NewTotData*)
  453. (*
  454. Diagnostics.diagL( "Unexpected value for BytesWritten", BytesWritten );
  455. Diagnostics.diagC( "Should be", NewTotData );
  456. *)
  457. END;
  458. IF NewTotData < OldTotalBytes THEN
  459. (* garbage space at end of record to fill *)
  460. DEC( OldTotalBytes, NewTotData);
  461. IF HandleIO.FillFile( NdxFile^.handle, OldTotalBytes, 0C ) #
  462. StringIO.NoError THEN
  463. (* fill end of record with nulls *)
  464. RETURN FALSE;
  465. END;
  466. END;
  467. IF (NOT OldEntry) OR (NewTotData # OldUsedBytes) THEN
  468. (* if not using old index entry *)
  469. IF NewFilePtr = NdxFile^.NdxFilePtr THEN
  470. NdxFile^.NdxFilePtr := NdxFile^.NdxFilePtr + Numbers.Lc( NewTotData );
  471. StringIO.WriteStr( NdxFile^.handle, NdxBones.NdxMarker);
  472. (* correct ndxfileptr and write ndxmarker if adding
  473. to end of file *)
  474. END;
  475. ChangedIndex( NdxFile);
  476. (* write changed index to file, or set UpdateNeeded *)
  477. END;
  478. GenLists.DisposeList( NdxFile^.ListBuf );
  479. (*Might as well dispose of the list buffer since it's no good once
  480. we've encoded it.*)
  481. StrEdit.SetLength( NdxFile^.BufRecName, 0);
  482. (*Set BufRecName to null again because ChangeNdxEntry may
  483. have put the name back in.*)
  484. RETURN TRUE;
  485. END WriteRecord;
  486. PROCEDURE ResetBuf( VAR TheBuf: GenLists.GenList );
  487. VAR
  488. ElmntBytes, ElmntType, theleng, cnt: CARDINAL;
  489. TmpAddr: SYSTEM.ADDRESS;
  490. sublst: GenLists.GenList;
  491. BEGIN
  492. theleng := GenLists.ListLength( TheBuf);
  493. IF theleng # 0 THEN
  494. FOR cnt := 1 TO theleng DO
  495. GenLists.GetElmtAdr( TheBuf, cnt, TmpAddr, ElmntBytes, ElmntType);
  496. IF ElmntType = GenLists.ListCode THEN
  497. GenLists.GetChildList( TheBuf, cnt, sublst);
  498. ResetBuf( sublst);
  499. ELSIF ElmntType = GenLists.StrCode THEN
  500. LowLevel.Fill( TmpAddr, 1, 0C);
  501. ELSE
  502. LowLevel.Fill( TmpAddr, ElmntBytes, 0C);
  503. END;
  504. END;
  505. END;
  506. END ResetBuf;
  507. PROCEDURE FindField( StruList: GenLists.GenList; FieldName: ARRAY OF CHAR;
  508. VAR DataList: GenLists.GenList; VAR spot: CARDINAL): BOOLEAN;
  509. (* flip thru structure to find field & return the sublist
  510. it is in & its position in that list;
  511. if can't find, return FALSE.
  512. Start counting with spot.*)
  513. VAR
  514. NameSize, NameType, PeriodSpot, indx, cnt,
  515. FieldLeng, ElmntBytes, ElmntType: CARDINAL;
  516. TmpPtr, NamePtr: LowLevel.Address8086;
  517. SubName: ARRAY [0..255] OF CHAR;
  518. NotFound, StillMatches: BOOLEAN;
  519. SubStruList, SubDataList: GenLists.GenList;
  520. TmpAddr: SYSTEM.ADDRESS;
  521. BEGIN
  522. (*FindField*)
  523. StrEdit.CAPstr(FieldName);
  524. IF PosUtils.Equal( FieldName, 'RECORD') THEN
  525. spot := 0;
  526. RETURN TRUE;
  527. END;
  528. cnt := 1;
  529. NotFound := TRUE;
  530. PeriodSpot := PosUtils.Pos( '.', FieldName);
  531. StrEdit.SetLength( SubName, 0);
  532. IF PeriodSpot <= HIGH( FieldName) THEN
  533. (* period found -> subfields specified *)
  534. IF PeriodSpot = M2Strings.Length(FieldName) - 1 THEN
  535. StrEdit.SetLength( FieldName, M2Strings.Length( FieldName) - 1);
  536. (* delete period if alone at end of field name *)
  537. ELSE
  538. M2Strings.Copy( FieldName, PeriodSpot + 1,
  539. M2Strings.Length(FieldName) -PeriodSpot - 1,
  540. SubName);
  541. (* SubName is the name of the subfields *)
  542. StrEdit.SetLength( FieldName, PeriodSpot);
  543. (* make field name the name at the first level *)
  544. END;
  545. END;
  546. FieldLeng := M2Strings.Length( FieldName);
  547. (* length of name sought *)
  548. WHILE (cnt <= GenLists.ListLength( StruList)) AND NotFound DO
  549. (* flip thru structure to find field *)
  550. GenLists.GetElmtAdr( StruList, cnt, NamePtr.a, NameSize, NameType);
  551. (* read next field *)
  552. INC( cnt);
  553. IF (NameType # GenLists.ListCode) THEN
  554. (* if not a list, see if it is the sought name *)
  555. INC( spot);
  556. (* inc the field counter *)
  557. IF NameSize = (1 + FieldLeng) THEN
  558. (* compare this field name to name sought *)
  559. indx := 0;
  560. TmpPtr := NamePtr;
  561. StillMatches := TRUE;
  562. WHILE StillMatches AND (indx < FieldLeng) DO
  563. StillMatches := FieldName[ indx] = TmpPtr.b^;
  564. IF StillMatches THEN
  565. INC( indx);
  566. LowLevel.IncAddr( TmpPtr.a, 1 );
  567. END;
  568. END;
  569. NotFound := NOT StillMatches;
  570. END;
  571. END;
  572. END;
  573. IF NotFound THEN
  574. RETURN FALSE ;
  575. END;
  576. IF M2Strings.Length( SubName) # 0 THEN
  577. GenLists.GetElmtAdr( StruList, cnt, TmpAddr, ElmntBytes, ElmntType);
  578. IF ElmntType = GenLists.ListCode THEN
  579. (* if this field has a sub list *)
  580. GenLists.GetChildList( StruList, cnt, SubStruList);
  581. GenLists.GetChildList( DataList, spot, SubDataList);
  582. DataList := SubDataList;
  583. spot := 0;
  584. IF NOT FindField( SubStruList, SubName, DataList, spot)
  585. THEN
  586. RETURN FALSE;
  587. END;
  588. ELSE
  589. RETURN FALSE;
  590. END;
  591. END;
  592. RETURN TRUE;
  593. END FindField;
  594. PROCEDURE AddRecord( NdxFile: NdxTypes.NdxFileType; RecName:
  595. ARRAY OF CHAR);
  596. (* Adds new record to file by:
  597. putting record name in BufRecName
  598. (don't add to index; WriteRec will do it)
  599. and creating empty list buffer *)
  600. BEGIN
  601. StrEdit.AssignStr(RecName, NdxFile^.BufRecName);
  602. ResetBuf( NdxFile^.ListBuf );
  603. (* initialize empty ListBuf *)
  604. END AddRecord;
  605. PROCEDURE PutField( VAR NdxFile: NdxTypes.NdxFileType;
  606. RecName, FieldName: ARRAY OF CHAR; TheType: CARDINAL;
  607. TheField: ARRAY OF SYSTEM.BYTE ): BOOLEAN;
  608. BEGIN
  609. RETURN PutFieldAdr( NdxFile, RecName, FieldName, TheType,
  610. SYSTEM.ADR(TheField), HIGH(TheField) + 1 );
  611. END PutField;
  612. PROCEDURE GetField( VAR NdxFile: NdxTypes.NdxFileType;
  613. RecName, FieldName: ARRAY OF CHAR; VAR TheType: CARDINAL;
  614. VAR TheField: ARRAY OF SYSTEM.BYTE ): BOOLEAN;
  615. VAR
  616. TmpAdr: SYSTEM.ADDRESS;
  617. TmpSize: CARDINAL;
  618. found: BOOLEAN;
  619. BEGIN
  620. found := GetFieldAdr( NdxFile, RecName, FieldName, TheType,
  621. TmpAdr, TmpSize );
  622. IF found THEN
  623. LowLevel.Move( TmpAdr, SYSTEM.ADR(TheField),
  624. Numbers.Min(TmpSize, HIGH(TheField) + 1) );
  625. IF TheType = GenLists.StrCode THEN
  626. IF (HIGH(TheField) + 2) < TmpSize THEN
  627. (*Ignore the fact that we couldn't store the null
  628. terminator.*)
  629. found := FALSE;
  630. END;
  631. ELSIF (HIGH(TheField) + 1) < TmpSize THEN
  632. (*We do this to warn user that there's been an
  633. overflow.*)
  634. found := FALSE;
  635. END;
  636. END;
  637. RETURN found;
  638. END GetField;
  639. PROCEDURE PutFieldAdr( VAR NdxFile: NdxTypes.NdxFileType; RecName,
  640. FieldName: ARRAY OF CHAR; TheType: CARDINAL; TheFieldAdr:
  641. SYSTEM.ADDRESS; TheFieldSize: CARDINAL ): BOOLEAN;
  642. (*Returns FALSE if FieldName is not in the structure list
  643. associated with NdxFile, or if not of TheType. It
  644. calls InitBuffer to: do a Retrieve if current contents of
  645. RecName are not in the read buffer, and then it transfers
  646. from the read buffer into the list buffer (actually it
  647. allocates a list element for every field in the read
  648. buffer). If the RecName does not exist, it is created.
  649. Then it looks for FieldName in that list (the list
  650. buffer), encodes the incoming string and puts it over the
  651. current value. Doesn't actually write anything to the
  652. file; you have to use WriteRecord before doing a Put with
  653. any different record, else the stuff you've stored in the
  654. list buffer will be lost.*)
  655. VAR
  656. len1, len2, spot: CARDINAL;
  657. TmpList, DataList: GenLists.GenList;
  658. BEGIN
  659. spot := 0;
  660. StrEdit.CrunchBlanks( RecName );
  661. len1 := M2Strings.Length(RecName);
  662. IF len1 > NdxTypes.RecNameLength THEN
  663. StrEdit.SetLength( RecName, NdxTypes.RecNameLength );
  664. END;
  665. IF len1 = 0 THEN
  666. RETURN FALSE;
  667. ELSIF NOT NdxBones.InitBuffer( NdxFile, RecName) THEN
  668. (*Loads file data if exists, or else creates new record.*)
  669. AddRecord( NdxFile, RecName);
  670. END;
  671. DataList := NdxFile^.ListBuf;
  672. IF NOT FindField( NdxFile^.StructLst, FieldName, DataList, spot) THEN
  673. (* locates field; returns list and position *)
  674. RETURN FALSE;
  675. END;
  676. IF (spot = 0) THEN
  677. (* replacing the entire record *)
  678. IF (TheType # GenLists.ListCode) THEN
  679. (*This used to be illegal. Now we anticipate what
  680. they're trying to do.*)
  681. GenLists.NewList( TmpList );
  682. GenLists.ListInsertAdr( TheFieldAdr, TheFieldSize,
  683. TheType, TmpList, 1 );
  684. ELSIF NOT GenLists.AdrToList( TheFieldAdr, TheFieldSize, TmpList ) THEN
  685. HALT();
  686. END;
  687. len1 := GenLists.ListLength(TmpList);
  688. len2 := GenLists.ListLength(DataList);
  689. IF ( 1 + len1 ) >= len2 THEN
  690. (* only allow if list as big as structure *)
  691. IF SYSTEM.ADDRESS(NdxFile^.ListBuf) # SYSTEM.ADDRESS(TmpList) THEN
  692. (*We do this test because it's likely that ListBuf and
  693. TmpList will be the same--GetField gives you the real
  694. ListBuf, not a copy of it, so people may be modifying
  695. the ListBuf directly and then passing it back to
  696. PutField. The PutField in that case isn't necessary,
  697. since PutField's only purpose is to modify the
  698. ListBuf.*)
  699. GenLists.DisposeList( NdxFile^.ListBuf);
  700. NdxFile^.ListBuf := TmpList;
  701. (* dispose of old buffer and use new data as buffer *)
  702. END;
  703. ELSE
  704. RETURN FALSE;
  705. END;
  706. ELSE
  707. GenLists.ListReplaceAdr( TheFieldAdr, TheFieldSize, TheType,
  708. DataList, spot );
  709. (* puts new data in list buffer in proper spot *)
  710. END;
  711. RETURN TRUE;
  712. END PutFieldAdr;
  713. PROCEDURE GetFieldAdr( VAR NdxFile: NdxTypes.NdxFileType; RecName,
  714. FieldName: ARRAY OF CHAR; VAR TheType: CARDINAL; VAR
  715. TheFieldAdr: SYSTEM.ADDRESS; VAR TheFieldSize: CARDINAL ):
  716. BOOLEAN;
  717. (*GetFieldAdr first calls InitBuffer to do retrieve if
  718. needed & finds field in index list if it is there. If
  719. problem with either, return FALSE. Then get the element
  720. out of the ListBuffer *)
  721. VAR
  722. spot: CARDINAL;
  723. DataList: GenLists.GenList;
  724. offset: LONGINT; (*Not used.*)
  725. RecSize, ListSpot: CARDINAL; (*Not used.*)
  726. BEGIN
  727. spot := 0;
  728. StrEdit.CrunchBlanks( RecName );
  729. IF (M2Strings.Length(RecName)=0) OR (NOT NdxBones.FindRecord(
  730. NdxFile, RecName, offset, RecSize, ListSpot )) THEN
  731. RETURN FALSE;
  732. END;
  733. IF NOT NdxBones.InitBuffer( NdxFile, RecName) THEN
  734. RETURN FALSE;
  735. END;
  736. DataList := NdxFile^.ListBuf;
  737. IF NOT FindField( NdxFile^.StructLst, FieldName,
  738. DataList, spot) THEN
  739. RETURN FALSE;
  740. END;
  741. IF spot = 0 THEN
  742. (* entire record requested *)
  743. TheFieldSize := (*SYSTEM.TSIZE(GenLists.GenList)*) 4;
  744. TheFieldAdr := GenLists.AdrOfList( NdxFile^.ListBuf );
  745. TheType := GenLists.ListCode;
  746. RETURN TRUE;
  747. ELSE
  748. GenLists.GetElmtAdr( DataList, spot, TheFieldAdr,
  749. TheFieldSize, TheType);
  750. (* try to retrieve the requested element *)
  751. END;
  752. RETURN TRUE;
  753. END GetFieldAdr;
  754. PROCEDURE FileStructure( NdxFile: NdxTypes.NdxFileType;
  755. VAR Structure: ARRAY OF CHAR );
  756. (*Returns a string containing the names of all fields
  757. defined for the NdxFile, in the form used by the
  758. Structure parameter of the CreateNdxFile procedure.*)
  759. PROCEDURE AddTheList( TheList: GenLists.GenList);
  760. VAR
  761. leng, cnt, TheType, TmpSize: CARDINAL;
  762. tmpbuf: ARRAY [0..NdxTypes.RecNameLength] OF CHAR;
  763. TmpAddr: SYSTEM.ADDRESS;
  764. SubList: GenLists.GenList;
  765. BEGIN
  766. leng := GenLists.ListLength( TheList);
  767. FOR cnt := 1 TO leng DO
  768. GenLists.GetElmtAdr( TheList, cnt, TmpAddr, TmpSize, TheType);
  769. IF TheType # GenLists.ListCode THEN
  770. IF cnt # 1 THEN
  771. StrEdit.Append( Structure, ',');
  772. END;
  773. IF TmpSize <= (NdxTypes.RecNameLength + 1) THEN
  774. LowLevel.Move( TmpAddr, SYSTEM.ADR(tmpbuf), TmpSize);
  775. ELSE
  776. LowLevel.Move( TmpAddr, SYSTEM.ADR(tmpbuf),
  777. (NdxTypes.RecNameLength + 1));
  778. END;
  779. StrEdit.Append( Structure, tmpbuf);
  780. ELSE
  781. StrEdit.Append( Structure, '{');
  782. GenLists.GetChildList( TheList, cnt, SubList);
  783. AddTheList( SubList);
  784. StrEdit.Append( Structure, '}');
  785. END;
  786. END;
  787. END AddTheList;
  788. BEGIN
  789. NdxTypes.CheckInit( NdxFile );
  790. StrEdit.SetLength( Structure, 0);
  791. AddTheList( NdxFile^.StructLst);
  792. END FileStructure;
  793. PROCEDURE RecordExists( NdxFile: NdxTypes.NdxFileType; VAR
  794. RecName: ARRAY OF CHAR ): BOOLEAN;
  795. VAR
  796. offset: LONGINT; (*Not used.*)
  797. RecSize, ListSpot: CARDINAL; (*Not used.*)
  798. BEGIN
  799. NdxTypes.CheckInit( NdxFile );
  800. StrEdit.CrunchBlanks( RecName );
  801. RETURN (M2Strings.Length(RecName) # 0) AND
  802. (NdxBones.FindRecord( NdxFile, RecName, offset, RecSize, ListSpot ));
  803. END RecordExists;
  804. PROCEDURE SafetyOn( VAR NdxFile: NdxTypes.NdxFileType );
  805. (*After SafetyOn is called, every time WriteRecord adds a
  806. record to the end of an NdxFile and thereby overwrites the
  807. ndx, it writes out a new copy of the ndx at the end of the
  808. file. NdxFiles are initialized with Safety off.*)
  809. BEGIN
  810. NdxTypes.CheckInit( NdxFile );
  811. NdxFile^.SafetyOn := TRUE;
  812. END SafetyOn;
  813. PROCEDURE SafetyOff( VAR NdxFile: NdxTypes.NdxFileType );
  814. (*After SafetyOff is called, the ndx at the end of an NdxFile
  815. can be overwritten, and will be restored only when
  816. CloseNdxFile is called.*)
  817. BEGIN
  818. NdxTypes.CheckInit( NdxFile );
  819. NdxFile^.SafetyOn := FALSE;
  820. END SafetyOff;
  821. PROCEDURE FindBlankSpace( VAR Ndx: GenLists.GenList; VAR NewElmt:
  822. NdxTypes.NdxElement; VAR OldElmt: CARDINAL): BOOLEAN;
  823. (* if can find space for NewElmt in deleted records at end of
  824. index, change NewElmt to point to the empty spot, return
  825. the cardinal position of the re-used garbage element of
  826. the index, and return TRUE *)
  827. VAR
  828. TheType: CARDINAL;
  829. TmpElmt: NdxTypes.NdxElement;
  830. BEGIN
  831. IF (M2Strings.Length( NewElmt.RecName) = 0) OR
  832. (NewElmt.UsedChars = 0) OR
  833. (GenLists.ListLength(Ndx) = 0) THEN
  834. (* don't try this for garbage entries or empty index *)
  835. RETURN FALSE;
  836. ELSE
  837. GenLists.GetElmt( Ndx, GenLists.ListLength(Ndx), TmpElmt, TheType);
  838. END;
  839. WHILE M2Strings.Length(TmpElmt.RecName) = 0 DO
  840. (* search through all entries in index with no name
  841. (garbage entries) *)
  842. IF TmpElmt.Allocated >= NewElmt.Allocated THEN
  843. (* found an entry to re-use *)
  844. NewElmt.Allocated := TmpElmt.Allocated;
  845. NewElmt.FilePos := TmpElmt.FilePos;
  846. OldElmt := GenLists.ElmtNow( Ndx);
  847. RETURN TRUE;
  848. END;
  849. IF GenLists.ElmtNow( Ndx ) = 1 THEN
  850. (* if can't back up any more, return FALSE *)
  851. RETURN FALSE;
  852. END;
  853. GenLists.NextElmt( Ndx, -1, TmpElmt, TheType);
  854. END;
  855. RETURN FALSE;
  856. END FindBlankSpace;
  857. (*$O-*)
  858. (*We turn off optimization in this procedure to avoid a bug in
  859. the beta copy of Logitech's v3.0 compiler.*)
  860. PROCEDURE InsertNdxEntry( RecName: ARRAY OF CHAR;
  861. VAR FilePos: LONGINT; UsedChars: CARDINAL;
  862. VAR AllocatedChars: CARDINAL; VAR NdxFile: NdxTypes.NdxFileType ):
  863. BOOLEAN;
  864. VAR
  865. dummylong: LONGINT;
  866. TheElmt, dummycard, OldElmt, NameLength: CARDINAL;
  867. TmpElmt: NdxTypes.NdxElement;
  868. BEGIN
  869. NameLength := M2Strings.Length(RecName);
  870. IF NameLength < (HIGH(RecName) + 1) THEN
  871. LowLevel.Fill( LowLevel.AddAddr(SYSTEM.ADR(RecName), NameLength ),
  872. 1 + HIGH(RecName) - NameLength, 0C );
  873. (*We do this to initialize end space in the Ndx; makes it
  874. easier to read when debugging.*)
  875. END;
  876. LowLevel.Fill( SYSTEM.ADR(TmpElmt.RecName),
  877. M2Strings.Length(TmpElmt.RecName), 0C );
  878. StrEdit.AssignStr( RecName, TmpElmt.RecName );
  879. TmpElmt.FilePos := FilePos;
  880. TmpElmt.UsedChars := UsedChars;
  881. TmpElmt.Allocated := AllocatedChars;
  882. IF NOT NdxBones.FindRecord(NdxFile, RecName, dummylong,
  883. dummycard, TheElmt) THEN
  884. (*The FindRecord returns the alphabetically correct
  885. insertion point, TheElmt.*)
  886. IF FindBlankSpace( NdxFile^.Ndx, TmpElmt, OldElmt) THEN
  887. (* if can find space for record in existing garbage, use it
  888. and delete the garbage index entry *)
  889. FilePos := TmpElmt.FilePos;
  890. AllocatedChars := TmpElmt.Allocated;
  891. GenLists.ListDelete( NdxFile^.Ndx, OldElmt, 1);
  892. END;
  893. GenLists.ListInsert( TmpElmt, NdxTypes.NdxTypeCode,
  894. NdxFile^.Ndx, TheElmt);
  895. RETURN TRUE;
  896. ELSE
  897. RETURN FALSE;
  898. END;
  899. END InsertNdxEntry;
  900. (*$O=*)
  901. PROCEDURE ChangeNdxEntry( OldRecName, NewRecName: ARRAY OF CHAR;
  902. FilePos: LONGINT; NumUsed: CARDINAL; VAR NdxFile: NdxTypes.NdxFileType):
  903. BOOLEAN;
  904. VAR
  905. TmpElmt: NdxTypes.NdxElement;
  906. dummylong: LONGINT;
  907. dummycard, NewElmt, OldElmt: CARDINAL;
  908. ToGarbage: BOOLEAN;
  909. BEGIN
  910. LowLevel.Fill( SYSTEM.ADR(TmpElmt.RecName),
  911. M2Strings.Length(TmpElmt.RecName), 0C );
  912. StrEdit.AssignStr( NewRecName, TmpElmt.RecName );
  913. ToGarbage := M2Strings.Length( NewRecName)=0;
  914. IF ToGarbage THEN
  915. TmpElmt.UsedChars := 0;
  916. (* Marks the entry as garbage if you change name to '' *)
  917. ELSE
  918. TmpElmt.UsedChars := NumUsed;
  919. END;
  920. TmpElmt.FilePos := FilePos;
  921. TmpElmt.Allocated := NumUsed;
  922. IF NdxBones.FindRecord(NdxFile, OldRecName, dummylong,
  923. dummycard, dummycard) THEN
  924. IF NdxBones.CompareProc( OldRecName, NewRecName) # 0 THEN
  925. (* to change record names, find and save old position,
  926. if new name does not exist then delete old and insert
  927. new *)
  928. OldElmt := GenLists.ElmtNow(NdxFile^.Ndx);
  929. IF ToGarbage OR (NOT NdxBones.FindRecord(NdxFile, NewRecName,
  930. dummylong, dummycard, dummycard)) THEN
  931. GenLists.ListDelete( NdxFile^.Ndx, OldElmt, 1);
  932. (*If new name does not exist (or represents garbage)
  933. and old entry can be deleted, return success of
  934. trying to insert new name *)
  935. ToGarbage := NdxBones.FindRecord(NdxFile, NewRecName, dummylong,
  936. dummycard, NewElmt);
  937. (*We do not need this result. We need NewElmt. *)
  938. IF ToGarbage THEN
  939. (* if found new value in file already, it is a
  940. garbage entry; insert at that point *)
  941. NewElmt := GenLists.ElmtNow( NdxFile^.Ndx);
  942. END;
  943. GenLists.ListInsert( TmpElmt, NdxTypes.NdxTypeCode,
  944. NdxFile^.Ndx, NewElmt);
  945. RETURN TRUE;
  946. ELSE
  947. RETURN FALSE;
  948. END;
  949. (* if changed name, delete old and add new *)
  950. END;
  951. GenLists.ListReplace( TmpElmt, NdxTypes.NdxTypeCode, NdxFile^.Ndx,
  952. GenLists.ElmtNow(NdxFile^.Ndx));
  953. RETURN TRUE;
  954. ELSE
  955. RETURN FALSE;
  956. END;
  957. END ChangeNdxEntry;
  958. PROCEDURE Init();
  959. BEGIN
  960. IF Initialized THEN
  961. RETURN;
  962. ELSE
  963. Initialized := TRUE;
  964. END;
  965. (*EntryDiag:
  966. Diagnostics.Init();
  967. :EntryDiag*)
  968. Drectory.Init();
  969. ErrorManager.Init();
  970. ErrorNames.Init();
  971. HandleIO.Init();
  972. GenLists.Init();
  973. ListUtils.Init();
  974. LowLevel.Init();
  975. M2Strings.Init();
  976. NdxBones.Init();
  977. NdxTypes.Init();
  978. Numbers.Init();
  979. NumTypes.Init();
  980. PosUtils.Init();
  981. StrEdit.Init();
  982. StringIO.Init();
  983. VStorage.Init();
  984. (*EntryDiag:
  985. Diagnostics.diagS( 'Entering NdxFiles', '' );
  986. :EntryDiag*)
  987. VStorage.NilHandle( NulHandle );
  988. (*EntryDiag:
  989. Diagnostics.diagS( 'Exiting NdxFiles', '' );
  990. :EntryDiag*)
  991. END Init;
  992. BEGIN
  993. Initialized := FALSE;
  994. Init();
  995. END NdxFiles.