GENLISTS.LST 70 KB

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