GENLISTS.MOD 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769
  1. IMPLEMENTATION MODULE GenLists;
  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/genlists.mov 1.6 30 Dec 1990 17:41:34 coleb $
  12. *
  13. *)
  14. (*EntryDiag:
  15. IMPORT Diagnostics;
  16. :EntryDiag*)
  17. IMPORT ErrorManager;
  18. IMPORT LowLevel;
  19. IMPORT M2Strings;
  20. IMPORT Numbers;
  21. IMPORT NumTypes;
  22. IMPORT PosUtils;
  23. IMPORT StrEdit;
  24. IMPORT StrConv;
  25. IMPORT SYSTEM;
  26. IMPORT VStorage;
  27. VAR
  28. ModInitialized : BOOLEAN;
  29. PROCEDURE Init();
  30. BEGIN
  31. IF ModInitialized THEN
  32. RETURN;
  33. ELSE
  34. ModInitialized := TRUE;
  35. END;
  36. (*EntryDiag:
  37. Diagnostics.Init();
  38. :EntryDiag*)
  39. ErrorManager.Init();
  40. LowLevel.Init();
  41. M2Strings.Init();
  42. Numbers.Init();
  43. NumTypes.Init();
  44. PosUtils.Init();
  45. StrEdit.Init();
  46. StrConv.Init();
  47. VStorage.Init();
  48. (*EntryDiag:
  49. Diagnostics.diagS( 'Entering GenLists', '' );
  50. :EntryDiag*)
  51. ErrorFlag := NoListError;
  52. DiagMode := FALSE;
  53. (*EntryDiag:
  54. Diagnostics.diagS( 'Exiting GenLists', '' );
  55. :EntryDiag*)
  56. END Init;
  57. CONST
  58. InitKey = 53304;
  59. NoMemErStr = "Lack Memory";
  60. RangeErStr = "GenList ref. out of range";
  61. Circularity = "Can't insert a list into itself";
  62. TYPE
  63. GenList = POINTER TO GenListRec;
  64. ElmtPtr = POINTER TO GenElmt;
  65. GenElmt =
  66. RECORD
  67. FromBlock : BOOLEAN;
  68. (*We have to track this because the BlockToList procedure
  69. could assign addresses and sizes to a data area that it
  70. did not get from the Storage module.*)
  71. size : CARDINAL;
  72. prv, nxt : ElmtPtr;
  73. type : CARDINAL;
  74. CASE : CARDINAL OF
  75. (* Changed from tagged to untagged variant 14 Nov 87
  76. because Stony Brook actually enforces matched
  77. references. Making type a tag never did anything for
  78. us anyway. *)
  79. 0 :
  80. elem : SYSTEM.ADDRESS;
  81. | ListCode :
  82. Lelem : POINTER TO GenList;
  83. | StrCode :
  84. Selem : POINTER TO ARRAY [0..255] OF CHAR;
  85. (*Using extremely large strings here seem to blow the
  86. RTD's workspace, for some reason.*)
  87. | 65530 :
  88. handle : VStorage.MemHandle;
  89. | 65529 :
  90. Ielem : POINTER TO INTEGER;
  91. | 65528 :
  92. Celem : POINTER TO CARDINAL;
  93. | 65527 :
  94. Belem : POINTER TO BOOLEAN;
  95. | 65526 :
  96. Chelem : POINTER TO CHAR;
  97. END;
  98. END;
  99. BlockDescriptor =
  100. RECORD
  101. ElmtRecsAddr : SYSTEM.ADDRESS;
  102. ElmtRecsSize : CARDINAL;
  103. DataAddr : VStorage.MemHandle;
  104. DataSize : CARDINAL;
  105. END;
  106. GenListRec =
  107. RECORD
  108. ParentList : GenList;
  109. (*This has to be the first field in the record.*)
  110. InitCheck : CARDINAL;
  111. BlockList : GenList;
  112. (*A list of BlockDescriptors. Used only when the list is
  113. allocated with BlockToList.*)
  114. current, lngth : CARDINAL;
  115. first, now, last : ElmtPtr;
  116. END;
  117. PROCEDURE AdrOfList(VAR TheList : GenList) : SYSTEM.ADDRESS;
  118. BEGIN
  119. RETURN SYSTEM.ADR(TheList);
  120. END AdrOfList;
  121. PROCEDURE AdrToList(TheAddr : SYSTEM.ADDRESS; TheSize : CARDINAL; VAR
  122. TheList : GenList) : BOOLEAN;
  123. BEGIN
  124. IF TheSize # SYSTEM.TSIZE(GenList) THEN
  125. RETURN FALSE;
  126. ELSE
  127. LowLevel.Move(TheAddr, SYSTEM.ADR(TheList), TheSize);
  128. RETURN TRUE;
  129. END;
  130. END AdrToList;
  131. PROCEDURE ListMove(TheList : GenList; spot : CARDINAL) : BOOLEAN;
  132. VAR
  133. dist1, dist2, dist3, SmallestDist : INTEGER;
  134. BEGIN
  135. IF spot=0 THEN
  136. (*diag*)
  137. ErrorFlag := RefToZero;
  138. RETURN FALSE;
  139. END;
  140. WITH TheList^ DO
  141. IF spot>lngth THEN
  142. current := lngth;
  143. now := last;
  144. ErrorFlag := RefPastEnd;
  145. RETURN FALSE;
  146. ELSE
  147. dist1 := INTEGER(spot)-1;
  148. dist2 := INTEGER(spot)-INTEGER(lngth);
  149. dist3 := INTEGER(spot)-INTEGER(current);
  150. (*Now we need to know which of these is smallest.*)
  151. IF ABS(dist1)>ABS(dist2) THEN
  152. IF ABS(dist2)>ABS(dist3) THEN
  153. SmallestDist := dist3;
  154. ELSE
  155. now := last;
  156. current := lngth;
  157. SmallestDist := dist2;
  158. END;
  159. ELSE
  160. IF ABS(dist1)>ABS(dist3) THEN
  161. SmallestDist := dist3;
  162. ELSE
  163. now := first;
  164. current := 1;
  165. SmallestDist := dist1;
  166. END;
  167. END;
  168. IF SmallestDist>0 THEN
  169. WHILE (current<spot) AND (now#NIL) DO
  170. now := now^.nxt;
  171. INC(current);
  172. END;
  173. ELSE
  174. WHILE (current>spot) AND (now#NIL) DO
  175. now := now^.prv;
  176. DEC(current);
  177. END;
  178. END;
  179. END;
  180. END;
  181. ErrorFlag := NoListError;
  182. RETURN TRUE;
  183. END ListMove;
  184. PROCEDURE MoveToSpot(TheList : GenList; spot : CARDINAL);
  185. VAR
  186. TmpStr: ARRAY [0..47] OF CHAR;
  187. BEGIN
  188. IF NOT ListMove(TheList,spot) THEN
  189. StrConv.CardinalToStr( spot, 0, TmpStr );
  190. M2Strings.Insert( "Can't move to list spot ", TmpStr, 0 );
  191. ErrorManager.WARN(TmpStr);
  192. END;
  193. END MoveToSpot;
  194. PROCEDURE GetChildList(TheList : GenList; spot : CARDINAL; VAR
  195. Child : GenList);
  196. BEGIN
  197. MoveToSpot( TheList, spot );
  198. IF (TheList^.now^.type#ListCode) OR (TheList^.now^.size# SYSTEM.TSIZE(
  199. GenList)) THEN
  200. ErrorFlag := NoSuchList;
  201. ErrorManager.WARN('Non-list passed to GetChildList');
  202. RETURN;
  203. END;
  204. VStorage.ReadMem(TheList^.now^.handle, 0,
  205. SYSTEM.ADR(Child), SYSTEM.TSIZE(GenList));
  206. ErrorFlag := NoListError;
  207. END GetChildList;
  208. PROCEDURE CircularLinkage( ElmtAdr: SYSTEM.ADDRESS; ElmtSize:
  209. CARDINAL; BigList : GenList; GoingUp: BOOLEAN ): BOOLEAN;
  210. (*Here we are trying to detect attempts to insert a list into
  211. itself, or into one of its own sublists, or into a list
  212. into which it has already been inserted.*)
  213. VAR
  214. tmpsize, cnt, TypeCode, ListEnd : CARDINAL;
  215. tmpadr : SYSTEM.ADDRESS;
  216. SubList, SmallList: GenList;
  217. BEGIN
  218. IF (NOT DiagMode) OR (BigList = NIL) THEN
  219. RETURN FALSE;
  220. END;
  221. IF NOT AdrToList( ElmtAdr, ElmtSize, SmallList ) THEN
  222. RETURN FALSE;
  223. END;
  224. IF SmallList = NIL THEN
  225. (*Note that it's okay to have more than one NIL list
  226. in a list.*)
  227. RETURN FALSE;
  228. END;
  229. IF (SmallList = BigList) THEN
  230. ErrorFlag := corruption;
  231. RETURN TRUE;
  232. END;
  233. IF GoingUp AND (BigList^.ParentList # NIL) THEN
  234. IF CircularLinkage( ElmtAdr, ElmtSize, BigList^.ParentList, TRUE ) THEN
  235. RETURN TRUE;
  236. END;
  237. END;
  238. ListEnd := ListLength( BigList );
  239. FOR cnt := 1 TO ListEnd DO
  240. GetElmtAdr( BigList, cnt, tmpadr, tmpsize, TypeCode );
  241. IF TypeCode = ListCode THEN
  242. GetChildList( BigList, cnt, SubList );
  243. IF (SmallList = SubList) THEN
  244. ErrorFlag := corruption;
  245. RETURN TRUE;
  246. ELSE
  247. IF CircularLinkage( ElmtAdr, ElmtSize, SubList, FALSE ) THEN
  248. RETURN TRUE;
  249. END;
  250. END;
  251. END;
  252. END;
  253. RETURN FALSE;
  254. END CircularLinkage;
  255. PROCEDURE InitResponse(msg : ARRAY OF CHAR);
  256. (*All calls to InitResponse are diagnostic. Remove them from
  257. finished programs.*)
  258. VAR
  259. TmpStr : ARRAY [0..79] OF CHAR;
  260. BEGIN
  261. StrEdit.AssignStr('Uninit. list passed to ', TmpStr);
  262. StrEdit.Append(TmpStr, msg);
  263. ErrorManager.WARN(TmpStr);
  264. END InitResponse;
  265. (* ===========================
  266. Exported procedures.
  267. =========================== *)
  268. PROCEDURE NewList(VAR TheList : GenList);
  269. VAR
  270. size : CARDINAL;
  271. BEGIN
  272. IF (NOT ModInitialized) THEN Init() END;
  273. size := SYSTEM.TSIZE(GenListRec);
  274. VStorage.DosAlloc(TheList, SYSTEM.TSIZE(GenListRec));
  275. TheList^.InitCheck := InitKey;
  276. TheList^.ParentList := NIL;
  277. TheList^.BlockList := NIL;
  278. TheList^.current := 0;
  279. TheList^.lngth := 0;
  280. TheList^.first := NIL;
  281. TheList^.now := NIL;
  282. TheList^.last := NIL;
  283. ErrorFlag := NoListError;
  284. END NewList;
  285. PROCEDURE BlockToList(TheAddr: SYSTEM.ADDRESS; BlockSize: CARDINAL;
  286. delimiter1, delimiter2: ARRAY OF CHAR; RecSize, TypeCode:
  287. CARDINAL; VAR TheList: GenList);
  288. (*We're doing a lot of stuff to avoid problems with disposing
  289. of lists created this way. The problems tend to arise
  290. because the Storage module doesn't know that any of this stuff
  291. has been allocated except the big contiguous areas for the
  292. data and the list.*)
  293. VAR
  294. cnt, spot1, spot2, Delim1Len, Delim2Len, elements: CARDINAL;
  295. TmpBlockDescr: BlockDescriptor;
  296. TmpList: GenList;
  297. TwoDelimiters, FixedLengthRecs: BOOLEAN;
  298. BlockAdr: SYSTEM.ADDRESS;
  299. PROCEDURE MakeOneList(TheList: GenList);
  300. VAR
  301. Tmptr, OldPtr: ElmtPtr;
  302. CheckStr: ARRAY [0..15] OF CHAR;
  303. SubList: GenList;
  304. EndFound : BOOLEAN;
  305. tmpadr: SYSTEM.ADDRESS;
  306. BEGIN
  307. IF (NOT FixedLengthRecs) AND TwoDelimiters THEN
  308. spot2 := spot1;
  309. IF TypeCode < 65000 THEN
  310. (* getting type from file, so make room for it *)
  311. INC(spot2, 2);
  312. END;
  313. IF 0 = PosUtils.PosAdr(delimiter2, LowLevel.AddAddr(BlockAdr, spot2),
  314. BlockSize - spot2) THEN
  315. (* If an ending delimiter starts this list, it is a null
  316. list, so exit without putting any elements in it *)
  317. spot1 := spot2;
  318. RETURN;
  319. END;
  320. END;
  321. OldPtr := NIL;
  322. EndFound := FALSE;
  323. WHILE (cnt <= (elements - 1)) AND (NOT EndFound) DO
  324. Tmptr := ElmtPtr( LowLevel.AddAddr(TmpBlockDescr.ElmtRecsAddr,
  325. (cnt * SYSTEM.TSIZE(GenElmt))));
  326. (*Tmptr gets the address of the next unused area of the
  327. list block.*)
  328. INC(cnt);
  329. IF TwoDelimiters AND (Delim1Len > 0) THEN
  330. spot1 := PosUtils.PosAdr(delimiter1,
  331. LowLevel.AddAddr(BlockAdr, spot1), BlockSize -
  332. spot1) + Delim1Len + spot1;
  333. IF spot1 > BlockSize THEN
  334. spot1 := BlockSize;
  335. END;
  336. (*We've found the next delimiter1*)
  337. END;
  338. IF TypeCode < 65000 THEN
  339. (*Any type code above 65000 REPERTOIRE considers one of
  340. its own. Because it doesn't know what this type code
  341. is, we leave room to get it from the block.*)
  342. tmpadr := LowLevel.AddAddr(BlockAdr, spot1);
  343. LowLevel.Move( tmpadr, SYSTEM.ADR(Tmptr^.type), 2);
  344. IF Tmptr^.type = ListCode THEN
  345. (*Now we call ourselves recursively.*)
  346. NewList(SubList);
  347. LowLevel.Move(SYSTEM.ADR(SubList), LowLevel.AddAddr(BlockAdr,
  348. spot1 - 2), SYSTEM.TSIZE(GenList));
  349. (*We're using an unused part of the data block for
  350. the data area of SubList.*)
  351. Tmptr^.elem := LowLevel.AddAddr(BlockAdr, spot1 - 2);
  352. SubList^.ParentList := TheList;
  353. MakeOneList(SubList);
  354. INC(spot1, Delim2Len);
  355. ELSE
  356. Tmptr^.elem := LowLevel.AddAddr(BlockAdr, spot1 + 2);
  357. END;
  358. ELSE
  359. (*We do know what the type code is--we assume it's not in
  360. the block.*)
  361. Tmptr^.elem := LowLevel.AddAddr(BlockAdr, spot1);
  362. (*Tmptr^.elem gets the address of some area of the data
  363. block.*)
  364. Tmptr^.type := TypeCode;
  365. END;
  366. IF NOT FixedLengthRecs THEN
  367. IF Tmptr^.type = ListCode THEN
  368. RecSize := 4;
  369. ELSE
  370. spot2 := PosUtils.PosAdr(delimiter2,
  371. LowLevel.AddAddr(BlockAdr, spot1), BlockSize -
  372. spot1) + spot1;
  373. IF TypeCode < 65000 THEN
  374. (*We don't know what the type code is--we want to get
  375. it from the block--so we assume the first two bytes
  376. contain it.*)
  377. IF (spot1 + 2) > spot2 THEN
  378. (*Something is horribly wrong; try to slip out
  379. without being noticed.*)
  380. RETURN;
  381. END;
  382. RecSize := (spot2 - spot1) - 2;
  383. ELSE
  384. (*We know what the type code is, so we assume it's not
  385. in the block.*)
  386. RecSize := spot2 - spot1;
  387. END;
  388. spot1 := spot2 + Delim2Len;
  389. (*spot1 should now be pointing at the byte
  390. immediately following the delimiter2 that we just found.*)
  391. END;
  392. LowLevel.Fill(SYSTEM.ADR(CheckStr), HIGH(CheckStr) + 1, 0C);
  393. (*
  394. IF cnt >= 171 THEN
  395. Diagnostics.diagA( 'BlockAdr', BlockAdr );
  396. Diagnostics.diagC( 'spot1', spot1 );
  397. Diagnostics.diagC( 'BlockSize', BlockSize );
  398. Diagnostics.diagS( 'CheckStr', CheckStr );
  399. END;
  400. *)
  401. IF (spot1+Delim2Len) >= BlockSize THEN
  402. (* Corrects an OS/2 segmentation fault. *)
  403. EndFound := TRUE;
  404. ELSE
  405. tmpadr := LowLevel.AddAddr(BlockAdr, spot1);
  406. LowLevel.Move( tmpadr, SYSTEM.ADR(CheckStr), Delim2Len);
  407. IF TwoDelimiters AND (M2Strings.CompareStr(CheckStr, delimiter2) = 0) THEN
  408. (*We've found two delimiter2's in a row, so this list
  409. is ended.*)
  410. EndFound := TRUE;
  411. END;
  412. END;
  413. ELSE
  414. spot1 := cnt * RecSize;
  415. END;
  416. Tmptr^.FromBlock := TRUE;
  417. Tmptr^.size := RecSize;
  418. Tmptr^.prv := OldPtr;
  419. IF OldPtr = NIL THEN
  420. TheList^.current := 1;
  421. TheList^.first := Tmptr;
  422. TheList^.now := Tmptr;
  423. ELSE
  424. OldPtr^.nxt := Tmptr;
  425. END;
  426. OldPtr := Tmptr;
  427. INC(TheList^.lngth);
  428. END;
  429. Tmptr^.nxt := NIL;
  430. TheList^.last := Tmptr;
  431. END MakeOneList;
  432. BEGIN
  433. IF (NOT ModInitialized) THEN Init() END;
  434. (*BlockToList*)
  435. IF NOT Initialized(TheList) THEN
  436. (*diag*)
  437. InitResponse('BlockToList');
  438. RETURN;
  439. END;
  440. Delim1Len := M2Strings.Length(delimiter1);
  441. Delim2Len := M2Strings.Length(delimiter2);
  442. TwoDelimiters := FALSE;
  443. IF VStorage.InEms( VStorage.MemHandle(TheAddr) ) THEN
  444. BlockAdr := VStorage.LockMem( VStorage.MemHandle(TheAddr) );
  445. VStorage.UnLockMem( VStorage.MemHandle(TheAddr) );
  446. ELSE
  447. BlockAdr := TheAddr;
  448. END;
  449. IF ((Delim1Len>0) OR (Delim2Len>0)) AND (RecSize>0) THEN
  450. (*diag*)
  451. ErrorManager.WARN("Delim-RecSize conflict");
  452. RETURN;
  453. END;
  454. (*Next determine how many elements are in the block.*)
  455. FixedLengthRecs := RecSize > 0;
  456. IF FixedLengthRecs THEN
  457. elements := BlockSize DIV RecSize;
  458. ELSE
  459. (*The records are going to be of variable length.*)
  460. IF M2Strings.CompareStr(delimiter1, delimiter2) # 0 THEN
  461. TwoDelimiters := TRUE;
  462. END;
  463. cnt := 0;
  464. elements := 0;
  465. REPEAT
  466. (*We count the delimiter2s in the block to determine how
  467. many list elements there will be.*)
  468. spot1 := PosUtils.PosAdr(delimiter2, LowLevel.AddAddr(BlockAdr, cnt),
  469. BlockSize - cnt);
  470. IF spot1 < (BlockSize - cnt) THEN
  471. INC(elements);
  472. END;
  473. INC(cnt, spot1 + Delim2Len);
  474. UNTIL cnt >= BlockSize;
  475. END;
  476. (*
  477. Diagnostics.diagC( 'elements', elements );
  478. *)
  479. IF (VAL(LONGINT, elements) * VAL(LONGINT,
  480. SYSTEM.TSIZE(GenElmt))) > NumTypes.L65535 THEN
  481. ErrorManager.WARN('RecSize too small');
  482. (*User has probably reduced RecNameLength to the point
  483. that the list's controlling records will take up more
  484. space than its data. If so, user needs to reduce size of
  485. ThisChunk in NdxBones.ReadNdx.*)
  486. RETURN;
  487. END;
  488. NewList(TmpList);
  489. TheList^.BlockList := TmpList;
  490. WITH TmpBlockDescr DO
  491. DataAddr := VStorage.MemHandle(TheAddr);
  492. DataSize := BlockSize;
  493. ElmtRecsSize := elements * SYSTEM.TSIZE(GenElmt);
  494. VStorage.DosAlloc(ElmtRecsAddr, ElmtRecsSize);
  495. (*Allocates a contiguous area of memory for the GenList.
  496. Note that we can't just append a list element for every
  497. RecSize'd area of the block using ListInsert because
  498. that would allocate an unnecessary, fragmented copy of
  499. the block.*)
  500. END;
  501. ListInsert(TmpBlockDescr, 0, TheList^.BlockList, 65535);
  502. (*Insert the BlockDescriptor into the BlockList, using 0 as
  503. the type code.*)
  504. IF elements = 0 THEN
  505. RETURN;
  506. END;
  507. (*From here down we're actually building TheList.*)
  508. spot1 := 0;
  509. (*spot1 tracks the position of the last delimiter1 we've
  510. found.*)
  511. spot2 := 0;
  512. (*spot2 tracks the position of the last delimiter2 we've
  513. found.*)
  514. cnt := 0;
  515. (*cnt tracks the number of elements we've processed.*)
  516. MakeOneList(TheList);
  517. (*MakeOneList processes elements until all elements have
  518. been processed or until two delimiter2's are found in a row.*)
  519. IF FixedLengthRecs AND ((BlockSize MOD RecSize) # 0) THEN
  520. (*Note that we may already have allocated lots of memory
  521. for the list. If you're sure it's invalid, you have to
  522. DisposeList(TheList) when BlockToList returns FALSE.*)
  523. ErrorFlag := underflow;
  524. ErrorManager.WARN('Bad Recsize');
  525. RETURN;
  526. END;
  527. ErrorFlag := NoListError;
  528. END BlockToList;
  529. PROCEDURE ChangeTypeCode(VAR TheList : GenList; spot, NewTypeCode :
  530. CARDINAL);
  531. BEGIN
  532. MoveToSpot( TheList, spot );
  533. TheList^.now^.type := NewTypeCode;
  534. END ChangeTypeCode;
  535. PROCEDURE CopyList(InList : GenList; VAR OutList : GenList);
  536. VAR
  537. spot, OldSize, OldType, lngth : CARDINAL;
  538. OldAdr : SYSTEM.ADDRESS;
  539. OldChild, NewChild : GenList;
  540. BEGIN
  541. IF (NOT ModInitialized) THEN Init() END;
  542. ErrorFlag := NoListError;
  543. IF NOT Initialized(InList) THEN
  544. (*diag*)
  545. InitResponse('Copy');
  546. RETURN;
  547. END;
  548. NewList(OutList);
  549. lngth := ListLength(InList);
  550. FOR spot := 1 TO lngth DO
  551. GetElmtAdr(InList, spot, OldAdr, OldSize, OldType);
  552. IF OldType=ListCode THEN
  553. VStorage.ReadMem(InList^.now^.handle, 0,
  554. SYSTEM.ADR(OldChild), SYSTEM.TSIZE(GenList));
  555. IF OldChild = NIL THEN
  556. NewChild := NIL;
  557. ELSE
  558. CopyList(OldChild, NewChild);
  559. (*recursive call*)
  560. END;
  561. OldAdr := SYSTEM.ADR(NewChild);
  562. OldSize := SYSTEM.TSIZE(GenList);
  563. END;
  564. ListInsertAdr(OldAdr, OldSize, OldType, OutList, spot);
  565. END;
  566. IF NOT ListMove( OutList, 1 ) THEN
  567. (*Do nothing; point is just to reset current to 1 for
  568. convenience of screen system.*)
  569. END;
  570. END CopyList;
  571. PROCEDURE DisconnectLists( VAR sublist, mainlist: GenList );
  572. VAR
  573. ListEnd, cnt, TypeCode, tmpsize: CARDINAL;
  574. tmpadr: SYSTEM.ADDRESS;
  575. tmplist: GenList;
  576. BEGIN
  577. ListEnd := ListLength( mainlist );
  578. FOR cnt := 1 TO ListEnd DO
  579. GetElmtAdr( mainlist, cnt, tmpadr, tmpsize, TypeCode );
  580. IF (TypeCode = ListCode) AND AdrToList( tmpadr, tmpsize, tmplist ) THEN
  581. IF (sublist = tmplist) THEN
  582. mainlist^.now^.type := 0;
  583. sublist^.ParentList := NIL;
  584. ELSE
  585. IF Initialized( tmplist ) THEN
  586. DisconnectLists( sublist, tmplist );
  587. END;
  588. END;
  589. END;
  590. END;
  591. END DisconnectLists;
  592. PROCEDURE DisposeList(VAR TheList : GenList);
  593. VAR
  594. TmpBlockDescr : BlockDescriptor;
  595. TypeCode : CARDINAL;
  596. BEGIN
  597. IF NOT Initialized(TheList) THEN
  598. (*diag*)
  599. (*
  600. InitResponse('DisposeList');
  601. If you want to guarantee that your code is free of needless
  602. calls to DisposeList, you may want to reinsert this.
  603. Reinsertion may also help you avoid subtle design problems.
  604. For people just learning to use REPERTOIRE, though, this causes
  605. needless irritations, so we commented it out.
  606. *)
  607. RETURN;
  608. END;
  609. IF TheList^.ParentList # NIL THEN
  610. ErrorManager.WARN("Disposal of sublist before parent");
  611. END;
  612. ListDelete(TheList, 1, TheList^.lngth);
  613. WITH TheList^ DO
  614. InitCheck := 0;
  615. (*This zeroes the InitCheck in what will become phantom
  616. memory. It's not strictly necessary, but it helps
  617. detect cases where two GenLists point at the same
  618. thing.*)
  619. IF BlockList#NIL THEN
  620. WHILE ListLength(BlockList)>0 DO
  621. GetElmt(BlockList, 1, TmpBlockDescr, TypeCode);
  622. WITH TmpBlockDescr DO
  623. VStorage.DosDealloc(ElmtRecsAddr, ElmtRecsSize);
  624. VStorage.DeallocMem( VStorage.MemHandle(DataAddr), DataSize );
  625. END;
  626. ListDelete(BlockList, 1, 1);
  627. END;
  628. VStorage.DosDealloc(BlockList, SYSTEM.TSIZE(GenListRec));
  629. END;
  630. END;
  631. VStorage.DosDealloc(TheList, SYSTEM.TSIZE(GenListRec));
  632. TheList := NIL;
  633. ErrorFlag := NoListError;
  634. END DisposeList;
  635. PROCEDURE ElmtNow(TheList : GenList) : CARDINAL;
  636. BEGIN
  637. IF NOT Initialized(TheList) THEN
  638. (*diag*)
  639. RETURN 0;
  640. END;
  641. RETURN TheList^.current;
  642. END ElmtNow;
  643. PROCEDURE GetElmt(TheList : GenList; spot : CARDINAL; VAR TheElmt :
  644. ARRAY OF SYSTEM.BYTE; VAR TypeCode : CARDINAL);
  645. VAR
  646. DestSize : CARDINAL;
  647. BEGIN
  648. IF NOT Initialized(TheList) THEN
  649. (*diag*)
  650. InitResponse('Get');
  651. RETURN;
  652. END;
  653. MoveToSpot( TheList, spot );
  654. TypeCode := TheList^.now^.type;
  655. DestSize := HIGH(TheElmt)+1;
  656. WITH TheList^.now^ DO
  657. IF size<=DestSize THEN
  658. (*We test for this first because we're not going to
  659. allow overflows.*)
  660. VStorage.ReadMem(handle, 0, SYSTEM.ADR(TheElmt), size);
  661. IF size<DestSize THEN
  662. ErrorFlag := underflow;
  663. IF TypeCode=StrCode THEN
  664. LowLevel.PokeByte(0C,
  665. LowLevel.seg(SYSTEM.ADR(TheElmt)),
  666. LowLevel.ofs(SYSTEM.ADR(TheElmt))+size);
  667. (*We do this to make sure we have a null
  668. terminator at the end of our string.*)
  669. (*
  670. ELSE
  671. WARN('Underflow in GetElmt.');
  672. You may want to reinsert this message
  673. if you encounter problems with confused
  674. data types in your lists, but it is
  675. cumbersome in most situations.
  676. *)
  677. END;
  678. RETURN;
  679. END;
  680. ELSE
  681. VStorage.ReadMem(handle, 0, SYSTEM.ADR(TheElmt), DestSize);
  682. IF (TypeCode = StrCode) AND (size> (DestSize + 1)) THEN
  683. IF INTEGER(DestSize) > LowLevel.ScanEQ( DestSize, 0C,
  684. SYSTEM.ADR(TheElmt) ) THEN
  685. (* We found a null somewhere in TheElmt; no need to worry. *)
  686. ErrorFlag := NoListError;
  687. RETURN;
  688. END;
  689. END;
  690. IF (TypeCode#StrCode) OR (size> (DestSize + 1)) THEN
  691. (*If it's a string, we're not going to signal an
  692. overflow if size exceeds DestSize by only one,
  693. because the difference is just the null terminator
  694. that we probably appended in the ListInsert.*)
  695. ErrorFlag := overflow;
  696. ErrorManager.WARN('GetElmt Overflow');
  697. RETURN;
  698. END;
  699. END;
  700. END;
  701. ErrorFlag := NoListError;
  702. END GetElmt;
  703. PROCEDURE GetElmtAdr(TheList : GenList; spot : CARDINAL; VAR
  704. ReadAddr : SYSTEM.ADDRESS; VAR TheSize : CARDINAL; VAR TypeCode :
  705. CARDINAL);
  706. BEGIN
  707. IF NOT Initialized(TheList) THEN
  708. (*diag*)
  709. InitResponse('Get');
  710. RETURN;
  711. END;
  712. MoveToSpot( TheList, spot );
  713. WITH TheList^.now^ DO
  714. ReadAddr := VStorage.LockMem(handle);
  715. VStorage.UnLockMem(handle);
  716. (* since we unlock here, the returned address is not
  717. guaranteed to be good after the calling program does
  718. anything that affects VStorage memory allocation *)
  719. TypeCode := type;
  720. TheSize := size;
  721. END;
  722. ErrorFlag := NoListError;
  723. END GetElmtAdr;
  724. PROCEDURE GetParentList(TheList : GenList; VAR Parent : GenList);
  725. BEGIN
  726. IF TheList^.ParentList=NIL THEN
  727. ErrorFlag := NoSuchList;
  728. ErrorManager.WARN("No parent");
  729. RETURN;
  730. END;
  731. Parent := TheList^.ParentList;
  732. ErrorFlag := NoListError;
  733. END GetParentList;
  734. PROCEDURE Initialized(TheList : GenList) : BOOLEAN;
  735. BEGIN
  736. IF (NOT ModInitialized) THEN Init() END;
  737. IF TheList=NIL THEN
  738. ErrorFlag := NoInit;
  739. RETURN FALSE;
  740. ELSIF TheList^.InitCheck=InitKey THEN
  741. ErrorFlag := NoListError;
  742. RETURN TRUE;
  743. ELSE
  744. ErrorFlag := NoInit;
  745. RETURN FALSE;
  746. END;
  747. END Initialized;
  748. PROCEDURE JoinLists(VAR MergedList, SurvivingList : GenList; spot :
  749. CARDINAL);
  750. VAR
  751. TmpList1, TmpList2 : GenList;
  752. len1, len2 : LONGINT;
  753. BEGIN
  754. IF (NOT Initialized(MergedList)) OR (NOT Initialized(
  755. SurvivingList)) THEN
  756. (*diag*)
  757. InitResponse('Join');
  758. END;
  759. len1 := Numbers.Lc(ListLength(MergedList));
  760. len2 := Numbers.Lc(ListLength(SurvivingList));
  761. IF (len1+len2)> NumTypes.L65535 THEN
  762. (*diag*)
  763. ErrorManager.WARN("Join too long");
  764. RETURN;
  765. END;
  766. IF len1> NumTypes.L0 THEN
  767. IF len2=NumTypes.L0 THEN
  768. SurvivingList^ := MergedList^;
  769. SurvivingList^.lngth := 0;
  770. (*Because it's going to by INCed by MergedList^.lngth
  771. below.*)
  772. SurvivingList^.BlockList := NIL;
  773. (*Because MergedList^.BlockList is going to be joined
  774. to it below.*)
  775. ELSIF spot>SurvivingList^.lngth THEN
  776. SurvivingList^.last^.nxt := MergedList^.first;
  777. MergedList^.first^.prv := SurvivingList^.last;
  778. SurvivingList^.last := MergedList^.last;
  779. ELSIF spot<=1 THEN
  780. MergedList^.last^.nxt := SurvivingList^.first;
  781. SurvivingList^.first^.prv := MergedList^.last;
  782. SurvivingList^.first := MergedList^.first;
  783. ELSE
  784. IF ListMove(SurvivingList,spot) THEN
  785. END;
  786. WITH SurvivingList^ DO
  787. now^.prv^.nxt := MergedList^.first;
  788. MergedList^.first^.prv := now^.prv;
  789. MergedList^.last^.nxt := now;
  790. now^.prv := MergedList^.last;
  791. END;
  792. END;
  793. INC(SurvivingList^.lngth, MergedList^.lngth);
  794. SurvivingList^.now := SurvivingList^.first;
  795. SurvivingList^.current := 1;
  796. END;
  797. IF (MergedList^.BlockList#NIL)
  798. AND (ListLength(MergedList^.BlockList)>0) THEN
  799. IF SurvivingList^.BlockList=NIL THEN
  800. NewList(TmpList1);
  801. SurvivingList^.BlockList := TmpList1;
  802. ELSE
  803. TmpList1 := SurvivingList^.BlockList;
  804. END;
  805. TmpList2 := MergedList^.BlockList;
  806. JoinLists(TmpList2, TmpList1, 65535);
  807. (*recursive call*)
  808. END;
  809. VStorage.DosDealloc(MergedList, SYSTEM.TSIZE(GenListRec));
  810. MergedList := NIL;
  811. END JoinLists;
  812. PROCEDURE ListDelete(TheList : GenList; spot, HowMany : CARDINAL);
  813. VAR
  814. ElementsDeleted : CARDINAL;
  815. NewPrv, NewNxt : ElmtPtr;
  816. SubList : GenList;
  817. BEGIN
  818. IF NOT Initialized(TheList) THEN
  819. (*diag*)
  820. InitResponse('Delete');
  821. RETURN;
  822. END;
  823. IF HowMany=0 THEN
  824. ErrorFlag := NoListError;
  825. RETURN;
  826. ELSIF spot>TheList^.lngth THEN
  827. ErrorFlag := RefPastEnd;
  828. ErrorManager.WARN(RangeErStr);
  829. RETURN;
  830. END;
  831. MoveToSpot( TheList, spot );
  832. ElementsDeleted := 0;
  833. NewPrv := TheList^.now^.prv;
  834. LOOP
  835. WITH TheList^.now^ DO
  836. IF type=ListCode THEN
  837. VStorage.ReadMem(handle, 0, SYSTEM.ADR(SubList),
  838. SYSTEM.TSIZE(GenList));
  839. (*We can't use GetChildList for this operation
  840. because the list is corrupt between deletion of
  841. the first and last elements.*)
  842. IF Initialized(SubList) THEN
  843. SubList^.ParentList := NIL;
  844. (*DisposeList normally checks for a non-NIL
  845. ParentList to detect disposals of sublists before
  846. parents. This disables the check.*)
  847. DisposeList(SubList);
  848. END;
  849. END;
  850. (* 8 Jul 88: took following statement out of ELSIF clause
  851. so as to deallocate the 4-byte pointer to the GenListRec. We
  852. were previously leaking memory 4 bytes per sublist. *)
  853. IF NOT FromBlock THEN
  854. (*We can't deallocate the data area if it was
  855. allocated as part of a big block. Instead, we'll
  856. deallocate it in DisposeList.*)
  857. VStorage.DeallocMem(handle, size);
  858. END;
  859. INC(ElementsDeleted);
  860. NewNxt := nxt;
  861. END;
  862. IF (ElementsDeleted<HowMany) AND (NewNxt#NIL) THEN
  863. TheList^.now := NewNxt;
  864. IF (NewNxt^.prv#NIL) AND (NOT NewNxt^.prv^.FromBlock) THEN
  865. VStorage.DosDealloc(NewNxt^.prv, SYSTEM.TSIZE(GenElmt));
  866. END;
  867. ELSE
  868. WITH TheList^ DO
  869. DEC(lngth, ElementsDeleted);
  870. IF NOT now^.FromBlock THEN
  871. VStorage.DosDealloc(now, SYSTEM.TSIZE(GenElmt));
  872. END;
  873. IF NewPrv#NIL THEN
  874. (*Establish the forward link.*)
  875. NewPrv^.nxt := NewNxt;
  876. ELSE
  877. (*We've deleted the first element of TheList.*)
  878. first := NewNxt;
  879. END;
  880. IF NewNxt#NIL THEN
  881. (*Establish the backward link.*)
  882. NewNxt^.prv := NewPrv;
  883. now := NewNxt;
  884. ELSE
  885. (*We've deleted the last element of TheList.*)
  886. now := NewPrv;
  887. last := NewPrv;
  888. DEC(current);
  889. (*Note that current will go to zero here if we delete
  890. the only remaining element of TheList. That should
  891. be correct, since it's initialized to zero.*)
  892. END;
  893. EXIT;
  894. END;
  895. END;
  896. END;
  897. ErrorFlag := NoListError;
  898. END ListDelete;
  899. PROCEDURE ListInsert(Element : ARRAY OF SYSTEM.BYTE; TypeCode : CARDINAL;
  900. TheList : GenList; spot : CARDINAL);
  901. BEGIN
  902. ListInsertAdr(SYSTEM.ADR(Element), HIGH(Element)+1, TypeCode, TheList,
  903. spot);
  904. END ListInsert;
  905. PROCEDURE ListInsertAdr(ReadAddr : SYSTEM.ADDRESS; TheSize : CARDINAL;
  906. TypeCode : CARDINAL; TheList : GenList; spot : CARDINAL);
  907. (* inserts a unit TheSize long starting at ReadAddr *)
  908. VAR
  909. tmp : ElmtPtr;
  910. TmpElmt : GenElmt;
  911. TmpAdr : SYSTEM.ADDRESS;
  912. Indirector : POINTER TO GenList;
  913. DiagSize : CARDINAL;
  914. BEGIN
  915. IF (TypeCode = ListCode) AND DiagMode THEN
  916. IF CircularLinkage( ReadAddr, TheSize, TheList, TRUE ) THEN
  917. ErrorManager.WARN( Circularity );
  918. END;
  919. END;
  920. ErrorFlag := NoListError;
  921. IF NOT Initialized(TheList) THEN
  922. (*diag*)
  923. InitResponse('Insert');
  924. RETURN;
  925. END;
  926. IF TypeCode=StrCode THEN
  927. TmpElmt.size := 1+ LowLevel.ScanEQ(TheSize,0C,ReadAddr);
  928. (*This makes sure the null terminator gets included with
  929. the string, if there is one. If the string completely
  930. fills its array, there won't be a null terminator, so
  931. we have to put one in when we copy out of the list in
  932. GetElmt and NextElmt.*)
  933. ELSE
  934. TmpElmt.size := TheSize;
  935. (*Store the size of the data area to be allocated.*)
  936. END;
  937. IF NOT VStorage.AllocMem(TmpElmt.handle,TmpElmt.size) THEN
  938. (*Allocate the data area.*)
  939. ErrorFlag := InsuffMem;
  940. ErrorManager.WARN(NoMemErStr);
  941. RETURN;
  942. END;
  943. TmpAdr := VStorage.LockMem(TmpElmt.handle);
  944. (* locks the allocated area into memory (allows us to use
  945. expanded memory) *)
  946. LowLevel.Move(ReadAddr, TmpAdr, TmpElmt.size);
  947. (*Copy the element into the data area.*)
  948. IF TypeCode=StrCode THEN
  949. LowLevel.Fill( LowLevel.AddAddr(TmpAdr, TmpElmt.size-1), 1, 0C);
  950. (* if string, store null terminator *)
  951. END;
  952. VStorage.UnLockMem(TmpElmt.handle);
  953. WITH TheList^ DO
  954. IF (NOT ListMove(TheList,spot)) AND (ErrorFlag=RefToZero) THEN
  955. (*diag*)
  956. ErrorManager.WARN(RangeErStr);
  957. RETURN;
  958. END;
  959. DiagSize := SYSTEM.TSIZE(GenElmt);
  960. VStorage.DosAlloc(tmp, DiagSize);
  961. tmp^.type := TypeCode;
  962. IF TypeCode=ListCode THEN
  963. Indirector := ReadAddr;
  964. IF Initialized(Indirector^) THEN
  965. (* 23 Dec 88: added this check for NIL to fix bug discovered
  966. by the people at LaserMaster Corp. *)
  967. Indirector^^.ParentList := TheList;
  968. END;
  969. END;
  970. IF now=NIL THEN
  971. (*This only happens when we have a null list. Otherwise
  972. ListMove will have stopped before going past the last
  973. element in the list.*)
  974. tmp^.nxt := NIL;
  975. tmp^.prv := NIL;
  976. last := tmp;
  977. first := tmp;
  978. current := 1;
  979. ELSE
  980. IF (spot>lngth) THEN
  981. tmp^.prv := now;
  982. tmp^.nxt := NIL;
  983. now^.nxt := tmp;
  984. INC(current);
  985. last := tmp;
  986. ELSE
  987. tmp^.prv := now^.prv;
  988. now^.prv := tmp;
  989. tmp^.nxt := now;
  990. IF tmp^.prv#NIL THEN
  991. (*We know we're not on the first element of the list.*)
  992. tmp^.prv^.nxt := tmp;
  993. ELSE
  994. (*tmp is the new first element of the list.*)
  995. first := tmp;
  996. END;
  997. END;
  998. END;
  999. tmp^.elem := TmpElmt.elem;
  1000. tmp^.size := TmpElmt.size;
  1001. tmp^.FromBlock := FALSE;
  1002. now := tmp;
  1003. INC(lngth);
  1004. END;
  1005. IF ErrorFlag = RefPastEnd THEN
  1006. ErrorFlag := NoListError;
  1007. END;
  1008. END ListInsertAdr;
  1009. PROCEDURE ListLength(TheList : GenList) : CARDINAL;
  1010. (*Number of elements at this node of the list.*)
  1011. BEGIN
  1012. IF NOT Initialized(TheList) THEN
  1013. (*diag*)
  1014. InitResponse('ListLength');
  1015. RETURN 0;
  1016. END;
  1017. ErrorFlag := NoListError;
  1018. (*added 30 Oct 86*)
  1019. RETURN TheList^.lngth;
  1020. END ListLength;
  1021. PROCEDURE ListReplace(Element : ARRAY OF SYSTEM.BYTE; TypeCode : CARDINAL;
  1022. TheList : GenList; spot : CARDINAL);
  1023. BEGIN
  1024. ListReplaceAdr(SYSTEM.ADR(Element), HIGH(Element)+1, TypeCode, TheList,
  1025. spot);
  1026. END ListReplace;
  1027. PROCEDURE ListReplaceAdr(ReadAddr : SYSTEM.ADDRESS; TheSize, TypeCode :
  1028. CARDINAL; TheList : GenList; spot : CARDINAL);
  1029. VAR
  1030. StrLen, DestSize : CARDINAL;
  1031. ChildList, CheckList : GenList;
  1032. tmp : ElmtPtr;
  1033. Indirector : POINTER TO GenList;
  1034. TmpAdr : SYSTEM.ADDRESS;
  1035. BEGIN
  1036. ErrorFlag := NoListError;
  1037. IF NOT Initialized(TheList) THEN
  1038. (*diag*)
  1039. InitResponse('Replace');
  1040. RETURN;
  1041. END;
  1042. MoveToSpot( TheList, spot );
  1043. WITH TheList^.now^ DO
  1044. IF (type = ListCode) THEN
  1045. (*Now we have to dispose of the old list UNLESS it's
  1046. identical to what replaces it.*)
  1047. GetChildList(TheList, spot, ChildList);
  1048. IF (TypeCode # ListCode) OR (NOT AdrToList( ReadAddr,
  1049. TheSize, CheckList )) THEN
  1050. CheckList := NIL;
  1051. END;
  1052. IF (CheckList # ChildList) AND (ChildList # NIL) THEN
  1053. ChildList^.ParentList := NIL;
  1054. (*We do this to prevent DisposeList from warning us
  1055. about premature disposal of children.*)
  1056. IF (CheckList # NIL) AND DiagMode THEN
  1057. IF CircularLinkage( ReadAddr, TheSize, TheList, TRUE ) THEN
  1058. ErrorManager.WARN( Circularity );
  1059. END;
  1060. IF NOT ListMove(TheList,spot) THEN
  1061. (*Have to make sure we're still in the same spot.*)
  1062. RETURN;
  1063. END;
  1064. END;
  1065. (*Check for circularity first so you won't find
  1066. the disposed sublist.*)
  1067. DisposeList(ChildList);
  1068. (*DisposeList won't mind if ChildList is NIL.*)
  1069. END;
  1070. END;
  1071. IF (TypeCode=StrCode) THEN
  1072. (*We know here that we're dealing with strings, so an
  1073. underflow won't matter. If the new string is shorter
  1074. than the size of the old element's data area, we can
  1075. copy over it without ALLOCATING and DEALLOCATING.*)
  1076. StrLen := 1 + LowLevel.ScanEQ(TheSize,0C,ReadAddr);
  1077. (*This makes sure the null terminator gets included with
  1078. the string.*)
  1079. IF StrLen<=size THEN
  1080. TmpAdr := VStorage.LockMem(handle);
  1081. LowLevel.Move(ReadAddr, TmpAdr, StrLen);
  1082. LowLevel.PokeByte(0C, LowLevel.seg(TmpAdr),
  1083. LowLevel.ofs(TmpAdr)+StrLen-1);
  1084. (*We do this to guarantee that constant strings
  1085. passed to open arrays will be stored with null
  1086. terminators.*)
  1087. VStorage.UnLockMem(handle);
  1088. IF StrLen<size THEN
  1089. (*We do this to let the user determine whether a
  1090. longer string has been replaced with a shorter one,
  1091. although it's not clear why any user would want to
  1092. know that.*)
  1093. ErrorFlag := underflow;
  1094. END;
  1095. type := TypeCode;
  1096. RETURN;
  1097. ELSE
  1098. TheSize := StrLen;
  1099. END;
  1100. END;
  1101. DestSize := size;
  1102. END;
  1103. (* We have to end the WITH here because we may change the
  1104. TheList^.now pointer in the next few lines.*)
  1105. IF DestSize#TheSize THEN
  1106. IF TheList^.now^.FromBlock THEN
  1107. VStorage.DosAlloc(tmp, SYSTEM.TSIZE(GenElmt));
  1108. tmp^ := TheList^.now^;
  1109. TheList^.now := tmp;
  1110. TheList^.now^.FromBlock := FALSE;
  1111. (*We do this because we know at this point that FromBlock
  1112. has to be FALSE--the new data won't fit in the old
  1113. area--and since FromBlock tells ListDelete whether it
  1114. can dispose of memory allocated both to the data area
  1115. and the controlling record, we can't let them get out
  1116. of sync.*)
  1117. (* Next, correct nxt, prv, first, and last pointers
  1118. if affected *)
  1119. IF spot=1 THEN
  1120. TheList^.first := tmp;
  1121. ELSE
  1122. TheList^.now^.prv^.nxt := tmp;
  1123. END;
  1124. IF spot>=TheList^.lngth THEN
  1125. TheList^.last := tmp;
  1126. ELSE
  1127. TheList^.now^.nxt^.prv := tmp;
  1128. END;
  1129. ELSE
  1130. VStorage.DeallocMem(TheList^.now^.handle, TheList^.now^.size);
  1131. END;
  1132. TheList^.now^.size := TheSize;
  1133. IF NOT VStorage.AllocMem( TheList^.now^.handle,
  1134. TheList^.now^.size ) THEN
  1135. ErrorFlag := InsuffMem;
  1136. ErrorManager.WARN(NoMemErStr);
  1137. RETURN;
  1138. END;
  1139. END;
  1140. WITH TheList^.now^ DO
  1141. TmpAdr := VStorage.LockMem(handle);
  1142. LowLevel.Move(ReadAddr, TmpAdr, TheSize);
  1143. type := TypeCode;
  1144. IF TypeCode=ListCode THEN
  1145. Indirector := ReadAddr;
  1146. IF Initialized(Indirector^) THEN
  1147. (* 23 Dec 88: added this check for NIL to fix bug discovered
  1148. by the people at LaserMaster Corp. *)
  1149. Indirector^^.ParentList := TheList;
  1150. END;
  1151. ELSIF TypeCode=StrCode THEN
  1152. LowLevel.PokeByte(0C, LowLevel.seg(TmpAdr),
  1153. LowLevel.ofs(TmpAdr) + TheSize - 1 );
  1154. END;
  1155. VStorage.UnLockMem(handle);
  1156. END;
  1157. END ListReplaceAdr;
  1158. PROCEDURE ListSize(TheList : GenList; VAR TotalElements : LONGINT;
  1159. VAR TotalSubLists : CARDINAL; VAR TotalListSize : LONGINT) : LONGINT;
  1160. VAR
  1161. SubList : GenList;
  1162. SubListTotal : CARDINAL;
  1163. SubElements, DataSize, SubSize : LONGINT;
  1164. firstime : BOOLEAN;
  1165. BEGIN
  1166. TotalElements := NumTypes.L0;
  1167. TotalSubLists := 0;
  1168. DataSize := NumTypes.L0;
  1169. TotalListSize := NumTypes.L0;
  1170. IF NOT Initialized(TheList) THEN
  1171. (*diag*)
  1172. RETURN DataSize;
  1173. END;
  1174. IF NOT ListMove(TheList,1) THEN
  1175. RETURN DataSize;
  1176. END;
  1177. firstime := TRUE;
  1178. REPEAT
  1179. IF firstime THEN
  1180. firstime := FALSE;
  1181. ELSE
  1182. IF NOT ListMove(TheList,TheList^.current+1) THEN
  1183. END;
  1184. END;
  1185. IF TheList^.now^.type=ListCode THEN
  1186. GetChildList(TheList, TheList^.current, SubList);
  1187. DataSize := DataSize+ListSize(SubList,SubElements,
  1188. SubListTotal,SubSize);
  1189. INC(TotalElements);
  1190. (*We increment our TotalElements one for the sublist.*)
  1191. TotalElements := TotalElements+SubElements;
  1192. (*And again for the sublist's elements.*)
  1193. INC(TotalSubLists);
  1194. (*We increment it one for the sublist itself.*)
  1195. INC(TotalSubLists, SubListTotal);
  1196. (*And again for all the sublist's sublists.*)
  1197. TotalListSize := TotalListSize+SubSize;
  1198. ELSE
  1199. INC(TotalElements);
  1200. DataSize := DataSize + Numbers.Lc(TheList^.now^.size);
  1201. TotalListSize := TotalListSize + Numbers.Lc( TheList^.now^.size );
  1202. INC(TotalListSize, SYSTEM.TSIZE(GenListRec));
  1203. END;
  1204. UNTIL TheList^.current=TheList^.lngth;
  1205. ErrorFlag := NoListError;
  1206. RETURN DataSize;
  1207. END ListSize;
  1208. PROCEDURE ListToAdr(TheList : GenList; TheAddr : SYSTEM.ADDRESS; TheSize :
  1209. CARDINAL) : BOOLEAN;
  1210. BEGIN
  1211. IF TheSize # SYSTEM.TSIZE(GenList) THEN
  1212. RETURN FALSE;
  1213. ELSE
  1214. LowLevel.Move(SYSTEM.ADR(TheList), TheAddr, TheSize);
  1215. RETURN TRUE;
  1216. END;
  1217. END ListToAdr;
  1218. PROCEDURE ListToBlock(TheList : GenList; delimiter1, delimiter2 :
  1219. ARRAY OF CHAR; VAR TheAddr : SYSTEM.ADDRESS; VAR BlockSize, RecSize :
  1220. CARDINAL);
  1221. (*Note that the calling program is responsible for
  1222. deallocating the memory allocated by ListToBlock.*)
  1223. VAR
  1224. DelimSpace, BlockPtr, SubLists : CARDINAL;
  1225. tmpl, elements, TotalData, TotalListSize : LONGINT;
  1226. TwoDelimiters : BOOLEAN;
  1227. PROCEDURE CopyOut(TheList : GenList);
  1228. (*This procedure has to be split out from the rest of
  1229. ListToBlock because it needs to call itself recursively
  1230. when it encounters a SubList. Note that it operates on the
  1231. BlockPtr variable, which is global to the ListToBlock
  1232. procedure. The purpose of that is to prevent the recursive
  1233. calls from writing back over the start of the block.*)
  1234. VAR
  1235. SubList : GenList;
  1236. NilList: BOOLEAN;
  1237. BEGIN
  1238. IF NOT Initialized( TheList ) THEN
  1239. NewList( TheList );
  1240. NilList := TRUE;
  1241. ELSE
  1242. NilList := FALSE;
  1243. END;
  1244. IF NOT ListMove(TheList,1) THEN
  1245. ErrorFlag := RefPastEnd;
  1246. RETURN;
  1247. END;
  1248. WHILE ErrorFlag#RefPastEnd DO
  1249. WITH TheList^.now^ DO
  1250. IF TwoDelimiters THEN
  1251. LowLevel.Move(SYSTEM.ADR(delimiter1),
  1252. LowLevel.AddAddr(TheAddr, BlockPtr),
  1253. M2Strings.Length(delimiter1));
  1254. INC(BlockPtr, M2Strings.Length(delimiter1));
  1255. (*These next two statements make the kind of block
  1256. produced by ListToBlock match the structure of an
  1257. NdxFile. You may want to delete them if you use
  1258. ListToBlock for other purposes.*)
  1259. LowLevel.Move(SYSTEM.ADR(type),
  1260. LowLevel.AddAddr(TheAddr, BlockPtr), 2);
  1261. INC(BlockPtr, 2);
  1262. END;
  1263. IF type=ListCode THEN
  1264. GetChildList(TheList, TheList^.current, SubList);
  1265. CopyOut(SubList);
  1266. ELSE
  1267. VStorage.ReadMem(handle, 0,
  1268. LowLevel.AddAddr(TheAddr, BlockPtr), size);
  1269. INC(BlockPtr, size);
  1270. END;
  1271. END;
  1272. LowLevel.Move(SYSTEM.ADR(delimiter2),
  1273. LowLevel.AddAddr(TheAddr, BlockPtr),
  1274. M2Strings.Length(delimiter2));
  1275. INC(BlockPtr, M2Strings.Length(delimiter2));
  1276. IF ListMove(TheList,TheList^.current+1) THEN
  1277. END;
  1278. END;
  1279. IF NilList THEN
  1280. DisposeList( TheList );
  1281. END;
  1282. END CopyOut;
  1283. BEGIN
  1284. IF (NOT ModInitialized) THEN Init() END;
  1285. (*ListToBlock*)
  1286. TotalData := ListSize(TheList,elements,SubLists,TotalListSize);
  1287. IF (TotalData> NumTypes.L65535) THEN
  1288. (*We've got too much data in the list to store in a
  1289. contiguous area of memory.*)
  1290. ErrorFlag := InsuffMem;
  1291. RETURN;
  1292. END;
  1293. TwoDelimiters := FALSE;
  1294. IF (M2Strings.Length(delimiter1)>0) OR
  1295. (M2Strings.Length(delimiter2)>0) THEN
  1296. IF elements> NumTypes.L65535 THEN
  1297. ErrorFlag := InsuffMem;
  1298. RETURN;
  1299. END;
  1300. DelimSpace := Numbers.C(elements *
  1301. Numbers.Lc(M2Strings.Length(delimiter1)));
  1302. IF NOT PosUtils.Equal(delimiter1,delimiter2) THEN
  1303. (*We're supposed to use a separate delimiter to mark the
  1304. start and end of each element.*)
  1305. DelimSpace := DelimSpace + Numbers.C(elements *
  1306. Numbers.Lc(M2Strings.Length(delimiter2)+2));
  1307. (*It's +2 to allow room for record types. See the
  1308. comment above.*)
  1309. TwoDelimiters := TRUE;
  1310. END;
  1311. ELSE
  1312. DelimSpace := 0;
  1313. END;
  1314. BlockSize := Numbers.C(TotalData)+DelimSpace;
  1315. (* size of block created *)
  1316. VStorage.DosAlloc(TheAddr, BlockSize);
  1317. tmpl := elements-Numbers.Lc(SubLists);
  1318. (*We use tmpl to avoid a bug in Logitech's v3.0 LongInts.*)
  1319. IF (elements > Numbers.Lc(SubLists)) AND
  1320. ((Numbers.Lc(BlockSize) MOD (tmpl))=NumTypes.L0) THEN
  1321. RecSize := BlockSize DIV Numbers.C(tmpl);
  1322. (* size of each record if they're fixed-length *)
  1323. ELSE
  1324. RecSize := 0;
  1325. END;
  1326. BlockPtr := 0;
  1327. CopyOut(TheList);
  1328. ErrorFlag := NoListError;
  1329. END ListToBlock;
  1330. PROCEDURE NextElmt(TheList : GenList; HowFar : INTEGER; VAR
  1331. TheElmt : ARRAY OF SYSTEM.BYTE; VAR TypeCode : CARDINAL);
  1332. VAR
  1333. DestSize, cnt : CARDINAL;
  1334. BEGIN
  1335. IF NOT Initialized(TheList) THEN
  1336. (*diag*)
  1337. InitResponse('Next');
  1338. RETURN;
  1339. END;
  1340. WITH TheList^ DO
  1341. cnt := ABS(HowFar);
  1342. IF (TheList^.now#NIL) AND (HowFar<0) THEN
  1343. WHILE (cnt>0) AND (TheList^.now^.prv#NIL) DO
  1344. TheList^.now := TheList^.now^.prv;
  1345. DEC(cnt);
  1346. DEC(TheList^.current);
  1347. END;
  1348. ELSE
  1349. WHILE (cnt>0) AND (TheList^.now^.nxt#NIL) DO
  1350. TheList^.now := TheList^.now^.nxt;
  1351. DEC(cnt);
  1352. INC(TheList^.current);
  1353. END;
  1354. END;
  1355. END;
  1356. TypeCode := TheList^.now^.type;
  1357. DestSize := HIGH(TheElmt)+1;
  1358. WITH TheList^.now^ DO
  1359. IF size<=DestSize THEN
  1360. (*We test for this first because we're not going to
  1361. allow overflows.*)
  1362. VStorage.ReadMem(handle, 0, SYSTEM.ADR(TheElmt), size);
  1363. IF size<DestSize THEN
  1364. ErrorFlag := underflow;
  1365. IF TypeCode=StrCode THEN
  1366. LowLevel.PokeByte(0C,
  1367. LowLevel.seg(SYSTEM.ADR(TheElmt)),
  1368. LowLevel.ofs(SYSTEM.ADR(TheElmt))+size);
  1369. (*We do this to make sure we have a null
  1370. terminator at the end of our string.*)
  1371. RETURN;
  1372. ELSE
  1373. (*
  1374. WARN('Underflow in NextElmt');
  1375. Commented out, 30 Oct 86
  1376. *)
  1377. RETURN;
  1378. END;
  1379. ELSE
  1380. ErrorFlag := NoListError;
  1381. RETURN;
  1382. END;
  1383. ELSE
  1384. VStorage.ReadMem(handle, 0, SYSTEM.ADR(TheElmt), DestSize);
  1385. ErrorFlag := overflow;
  1386. ErrorManager.WARN('Overflow in NextElmt');
  1387. RETURN;
  1388. END;
  1389. END;
  1390. ErrorFlag := NoListError;
  1391. END NextElmt;
  1392. PROCEDURE NilList(VAR TheList : GenList);
  1393. BEGIN
  1394. TheList := NIL;
  1395. END NilList;
  1396. PROCEDURE SameList( list1, list2: GenList ): BOOLEAN;
  1397. VAR
  1398. tmpadr: SYSTEM.ADDRESS;
  1399. tmpsize: CARDINAL;
  1400. BEGIN
  1401. IF (NOT ModInitialized) THEN Init() END;
  1402. IF (list1 = list2) THEN
  1403. RETURN TRUE;
  1404. END;
  1405. tmpsize := 4;
  1406. IF NOT ListToAdr( list1, SYSTEM.ADR(tmpadr), tmpsize ) THEN
  1407. RETURN FALSE;
  1408. END;
  1409. RETURN CircularLinkage( SYSTEM.ADR(tmpadr), tmpsize, list2, TRUE );
  1410. END SameList;
  1411. PROCEDURE ScanList(TheStr : ARRAY OF CHAR; TheList : GenList;
  1412. StartingAt, EndingAt : CARDINAL; VAR FoundSpot : CARDINAL) :
  1413. CARDINAL;
  1414. VAR
  1415. spot : CARDINAL;
  1416. TmpAdr : SYSTEM.ADDRESS;
  1417. BEGIN
  1418. (*ScanList*)
  1419. IF NOT Initialized(TheList) THEN
  1420. (*diag*)
  1421. RETURN 0;
  1422. END;
  1423. IF NOT ListMove(TheList,StartingAt) THEN
  1424. RETURN 0;
  1425. END;
  1426. IF TheList^.now=NIL THEN
  1427. ErrorFlag := NoListError;
  1428. RETURN (0);
  1429. END;
  1430. WITH TheList^ DO
  1431. IF (EndingAt>StartingAt) THEN
  1432. WHILE (StartingAt<=EndingAt) AND (now#NIL) DO
  1433. TmpAdr := VStorage.LockMem(now^.handle);
  1434. spot := PosUtils.PosAdr(TheStr,TmpAdr,now^.size);
  1435. (* We could use a ScanMem function here if it existed*)
  1436. VStorage.UnLockMem(now^.handle);
  1437. IF (spot<now^.size) THEN
  1438. FoundSpot := spot;
  1439. ErrorFlag := NoListError;
  1440. RETURN (current);
  1441. END;
  1442. INC(StartingAt);
  1443. INC(current);
  1444. now := now^.nxt;
  1445. END;
  1446. IF now=NIL THEN
  1447. now := last;
  1448. END;
  1449. ELSE
  1450. WHILE (StartingAt>=EndingAt) AND (now#NIL) DO
  1451. TmpAdr := VStorage.LockMem(now^.handle);
  1452. spot := PosUtils.PosAdr(TheStr,TmpAdr,now^.size);
  1453. VStorage.UnLockMem(now^.handle);
  1454. IF (spot<now^.size) THEN
  1455. FoundSpot := spot;
  1456. RETURN (current);
  1457. END;
  1458. DEC(StartingAt);
  1459. DEC(TheList^.current);
  1460. TheList^.now := TheList^.now^.prv;
  1461. END;
  1462. IF now=NIL THEN
  1463. now := first;
  1464. END;
  1465. END;
  1466. END;
  1467. RETURN (0);
  1468. (*TheStr not found between StartingAt and EndingAt.*)
  1469. END ScanList;
  1470. PROCEDURE Swap2Elmts(elmt1, elmt2 : ElmtPtr);
  1471. (* Former version swapped by exchanging list elements. It's
  1472. easier to swap by exchanging the pointers to the data
  1473. elements. (Makes the sort algorithm easier, too.) This
  1474. routine is a good place to start optimizing, or even put
  1475. it inline.
  1476. *)
  1477. VAR
  1478. AuxElmt : GenElmt;
  1479. AuxPtr1, AuxPtr2 : ElmtPtr;
  1480. BEGIN
  1481. IF elmt1=elmt2 THEN
  1482. RETURN;
  1483. END;
  1484. (* first swap everything, both ptrs and data *)
  1485. AuxElmt := elmt1^;
  1486. elmt1^ := elmt2^;
  1487. elmt2^ := AuxElmt;
  1488. (* then put ptrs back in their original place *)
  1489. WITH elmt1^ DO
  1490. AuxPtr1 := prv;
  1491. prv := elmt2^.prv;
  1492. AuxPtr2 := nxt;
  1493. nxt := elmt2^.nxt;
  1494. END;
  1495. WITH elmt2^ DO
  1496. prv := AuxPtr1;
  1497. nxt := AuxPtr2;
  1498. END;
  1499. END Swap2Elmts;
  1500. PROCEDURE ShellSortList(TheList: GenList; CompResult: Comparator) ;
  1501. (*
  1502. Tri de liste suivant le tri SHELL plus rapide que le
  1503. QuickSort dans le cas o— l'on a des listes presque tri‚es.
  1504. *)
  1505. VAR
  1506. Data1Adr, Data2Adr : SYSTEM.ADDRESS;
  1507. Ptr1, Ptr2 : ElmtPtr;
  1508. Elem1, Elem2 : CARDINAL;
  1509. NbElements, saut, borneSup : CARDINAL;
  1510. BEGIN
  1511. NbElements := ListLength(TheList);
  1512. saut := NbElements;
  1513. LOOP
  1514. saut := saut DIV 2;
  1515. IF saut # 0 THEN
  1516. borneSup := NbElements - saut;
  1517. Elem1 := 1;
  1518. Ptr1 := TheList^.first;
  1519. Elem2 := saut + 1;
  1520. IF ListMove(TheList, Elem2) THEN END;
  1521. Ptr2 := TheList^.now;
  1522. WHILE Elem1 <= borneSup DO
  1523. Data1Adr := VStorage.LockMem( Ptr1^.handle );
  1524. VStorage.UnLockMem( Ptr1^.handle );
  1525. Data2Adr := VStorage.LockMem( Ptr2^.handle );
  1526. VStorage.UnLockMem( Ptr2^.handle );
  1527. IF CompResult(Data1Adr, Ptr1^.size, Data2Adr,
  1528. Ptr2^.size) > 0 THEN
  1529. Swap2Elmts(Ptr1, Ptr2);
  1530. IF Elem1 > saut THEN
  1531. Ptr2 := Ptr1;
  1532. Elem2 := Elem1;
  1533. DEC(Elem1, saut);
  1534. IF ListMove(TheList, Elem1) THEN END;
  1535. Ptr1 := TheList^.now;
  1536. ELSE
  1537. INC(Elem1);
  1538. Ptr1 := Ptr1^.nxt;
  1539. INC(Elem2);
  1540. Ptr2 := Ptr2^.nxt;
  1541. END;
  1542. ELSE
  1543. INC(Elem1);
  1544. Ptr1 := Ptr1^.nxt;
  1545. INC(Elem2);
  1546. Ptr2 := Ptr2^.nxt;
  1547. END (* if *);
  1548. END (* while *);
  1549. ELSE
  1550. EXIT;
  1551. END (* if *);
  1552. END (* loop *);
  1553. END ShellSortList;
  1554. PROCEDURE SortList(TheList : GenList; CompResult : Comparator);
  1555. (*28 July 87: replaced old SortList, which used a bubble
  1556. sort, with Torbjorn Sund's version, which uses a quicksort.
  1557. Performance: With a list size of N, bubble sort runs as
  1558. b*N*N, QuickSort as q*N*log2(N). On a Kaypro AT at 8 MHz,
  1559. b = 0.5 msec, q = 3.5 msec.
  1560. *)
  1561. PROCEDURE QSortList(lwr, upr : ElmtPtr);
  1562. VAR
  1563. Pivot, Curnt : SYSTEM.ADDRESS;
  1564. PivotSize, CurntSize : CARDINAL;
  1565. i, m : ElmtPtr;
  1566. LwrCount, UprCount : CARDINAL;
  1567. BEGIN
  1568. LOOP
  1569. (* there goes the tail recursion *)
  1570. IF lwr=upr THEN
  1571. EXIT;
  1572. END;
  1573. WITH lwr^ DO
  1574. (* could be any, preferrably a random element *)
  1575. Pivot := VStorage.LockMem(handle);
  1576. (* 6 Jan 88: inserted this lock to correct
  1577. oversight pointed out by Dr. Michael Anderson;
  1578. SortList wasn't working when EMS was installed. *)
  1579. VStorage.UnLockMem(handle);
  1580. (* We go ahead and unlock here because we know we
  1581. will be finished with this address before
  1582. something else gets swapped into its place. *)
  1583. PivotSize := size;
  1584. END;
  1585. m := lwr;
  1586. i := lwr;
  1587. LwrCount := 0;
  1588. UprCount := 0;
  1589. WHILE i#upr DO
  1590. i := i^.nxt;
  1591. (* no need to worry about NIL here *)
  1592. WITH i^ DO
  1593. Curnt := VStorage.LockMem(handle);
  1594. (* 6 Jan 88: Lock/UnLock inserted. See above. *)
  1595. VStorage.UnLockMem(handle);
  1596. CurntSize := size;
  1597. END;
  1598. IF CompResult(Pivot,PivotSize,Curnt,CurntSize)>0 THEN
  1599. INC(LwrCount);
  1600. m := m^.nxt;
  1601. Swap2Elmts(m, i);
  1602. ELSE
  1603. INC(UprCount);
  1604. END;
  1605. END;
  1606. Swap2Elmts(lwr, m);
  1607. (* sort shortest interval first; this minimizes recursion depth *)
  1608. IF LwrCount<UprCount THEN
  1609. (* the IF is strictly necessary only with "fat" partitioning *)
  1610. IF LwrCount>0 THEN
  1611. QSortList(lwr, m^.prv);
  1612. END;
  1613. (* Instead of QSortList( m^.nxt, upr); *)
  1614. lwr := m^.nxt;
  1615. ELSE
  1616. IF UprCount>0 THEN
  1617. QSortList(m^.nxt, upr);
  1618. END;
  1619. (* instead of QSortList( lwr, m^.prv); *)
  1620. upr := m^.prv;
  1621. END;
  1622. END;
  1623. END QSortList;
  1624. BEGIN
  1625. WITH TheList^ DO
  1626. QSortList(first, last);
  1627. END;
  1628. END SortList;
  1629. PROCEDURE SplitList(InList : GenList; where : CARDINAL; VAR
  1630. OutList : GenList);
  1631. VAR
  1632. InLength : CARDINAL;
  1633. BEGIN
  1634. IF NOT Initialized(InList) THEN
  1635. (*diag*)
  1636. InitResponse('Split');
  1637. END;
  1638. NewList(OutList);
  1639. InLength := ListLength(InList);
  1640. IF (where>InLength) OR (InLength=0) OR (where=0) THEN
  1641. RETURN;
  1642. END;
  1643. IF ListMove(InList,where) THEN
  1644. END;
  1645. WITH InList^ DO
  1646. OutList^.first := now;
  1647. OutList^.current := 1;
  1648. OutList^.now := now;
  1649. OutList^.last := last;
  1650. OutList^.lngth := (lngth-where)+1;
  1651. OutList^.ParentList := ParentList;
  1652. now := now^.prv;
  1653. last := now;
  1654. lngth := where-1;
  1655. current := where-1;(* added -1 per ukah 9/15/91 *)
  1656. IF lngth=0 THEN
  1657. first := NIL;
  1658. ELSE (* added else clause per ukah 9/15/91 *)
  1659. last^.nxt :=NIL;
  1660. END;
  1661. OutList^.first^.prv:=NIL; (* ukah *)
  1662. END;
  1663. (*Note that we're leaving InList in charge of the
  1664. BlockList. OutList may have a lot of FromBlock elements
  1665. but nothing in its BlockList.*)
  1666. END SplitList;
  1667. BEGIN
  1668. ModInitialized := FALSE;
  1669. END GenLists.