BTREE.MOD 98 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631
  1. (*# call(o_a_size=>off) *)
  2. (*# call(o_a_copy=>off) *)
  3. (*# call(near_call=>on) *)
  4. IMPLEMENTATION MODULE Btree;
  5. (*
  6. Copyright (C) 1988..1991 Jensen & Partners International
  7. *)
  8. IMPORT CoreMem, FIOx, Lib, Str;
  9. FROM SYSTEM IMPORT Seg, Ofs, ADR;
  10. (*%T _mthread *)
  11. IMPORT Process;
  12. (*%E *)
  13. CONST
  14. (* ----------------------------------------------------------- *)
  15. (* For v3.0, the embedded version number has NOT been changed. *)
  16. (* See BTREE.DOC for details on compatability issues. *)
  17. (* ----------------------------------------------------------- *)
  18. ThisVersion = 200; (* See Open() procedure for testing *)
  19. Nil = MAX(LONGCARD);
  20. SectorSize = 512;
  21. PageSize = SectorSize*2;
  22. GuardV1 = 123456789;
  23. GuardV2 = 987654321;
  24. FileDataWrSize = 32;
  25. IndexDataWrSize = 32;
  26. TYPE
  27. LockType = (Implicit,Explicit,AllImplicit,AllLocks);
  28. LockRec = RECORD
  29. Position : LONGCARD;
  30. ICnt,ECnt : SHORTCARD;
  31. In : IHandle;
  32. END;
  33. LocksArray = ARRAY [0..LockQSize-1] OF LockRec;
  34. FileType = (IndexSlot,DataSlot,FreeSlot);
  35. KeyType = ARRAY [1..MaxKeySize] OF BYTE;
  36. PageRefRec = RECORD
  37. Page : LONGCARD;
  38. Rec : CARDINAL;
  39. Cnt : CARDINAL;
  40. END;
  41. PageRef = RECORD
  42. Height : CARDINAL;
  43. Refs : ARRAY [1..8191] OF PageRefRec; (* last *)
  44. END;
  45. PageRefPtr = POINTER TO PageRef;
  46. (* *************************************************************************
  47. In the following two records (IndexData and IndexFile), special
  48. considerations are required for some of the fields...
  49. (*I*) Denotes fields which must be checked against the contents of
  50. the file when the file is opened.
  51. (*V*) Denotes fields that reflect the current status of the file,
  52. and thus must be read after the file is locked and written
  53. before the file is unlocked.
  54. (*F*) Denotes fields which, if changed by a process other than the
  55. current one, require that the current process flush its
  56. buffers.
  57. ************************************************************************* *)
  58. IndexDataWr = RECORD
  59. CASE : BOOLEAN OF
  60. FALSE : RecordCnt : LONGCARD; (*V*)
  61. CASE Ft : FileType OF (*I*)
  62. DataSlot : RecordSize : CARDINAL; (*I*)
  63. | IndexSlot : WriteCnt, (*F*)
  64. TopPage : LONGCARD; (*V*)
  65. Depth, (*V*)
  66. KeySize, (*I*)
  67. N2, (*I*)
  68. N22 : CARDINAL; (*I*)
  69. DupKey : BOOLEAN; (*I*)
  70. END;
  71. | TRUE : FILL : ARRAY[1..IndexDataWrSize] OF BYTE;
  72. END;
  73. END;
  74. IndexFileWr = RECORD
  75. CASE : BOOLEAN OF
  76. FALSE : HeaderSize : CARDINAL; (*1*)(*I*)
  77. FileSize : LONGCARD; (*2*)(*V*)
  78. Version : CARDINAL; (*I*)
  79. FreeList : LONGCARD; (*V*)
  80. IndexCount : CARDINAL; (*I*)
  81. Mode : AccessMode; (*I*)
  82. PageSz, (*I*)
  83. MaxKeySz : CARDINAL; (*I*)
  84. | TRUE : FILL : ARRAY[1..FileDataWrSize] OF BYTE;
  85. END;
  86. END;
  87. IndexData = RECORD
  88. LastDataRef: LONGCARD;
  89. NextIndx : IHandle;
  90. LastErr : Errors;
  91. ErrorNest : CARDINAL;
  92. ihLock : LockRec;
  93. CASE Ft : FileType OF
  94. | DataSlot : Sync : BOOLEAN;
  95. bufSize : CARDINAL;
  96. bufPtr : ADDRESS;
  97. | IndexSlot : OldWriteCnt : LONGCARD;
  98. DataPtr : IHandle;
  99. PageRefs : PageRefPtr;
  100. PageLevel : CARDINAL;
  101. CompFct : CompareFunction;
  102. KeyFct : KeyFunction;
  103. LastKeyOK : BOOLEAN;
  104. LastKey : KeyType;
  105. LastKeyRef : LONGCARD;
  106. END;
  107. iwr : POINTER TO IndexDataWr;
  108. END;
  109. IndexFile = RECORD
  110. G1 : LONGCARD;
  111. ReadOnly,
  112. Buffered,
  113. WriteThru : BOOLEAN; (* not fully implemented *)
  114. Locks : LocksArray;
  115. fhLock : LockRec;
  116. FHandle : CARDINAL;
  117. fwr : POINTER TO IndexFileWr;
  118. G2 : LONGCARD; (* 2nd to last *)
  119. Id : ARRAY[0..346] OF IndexData; (* last *)
  120. END;
  121. IndexItem = RECORD
  122. IP : LONGCARD;
  123. DP : LONGCARD;
  124. Key : KeyType;
  125. END;
  126. TPage = RECORD
  127. CASE : BOOLEAN OF
  128. FALSE : ICount : CARDINAL;
  129. IItem : IndexItem;
  130. | TRUE : FILL : ARRAY [1..PageSize] OF BYTE;
  131. END;
  132. END;
  133. (*# save *)
  134. (*# data(near_ptr=>off) *)
  135. TPagePointer = POINTER TO TPage;
  136. (*# restore *)
  137. xTPage = RECORD
  138. CASE : BOOLEAN OF
  139. FALSE : ICount : CARDINAL;
  140. IItem : IndexItem;
  141. | TRUE : FILL : ARRAY [1..PageSize] OF BYTE;
  142. END;
  143. extra : IndexItem;
  144. END;
  145. BufferPages = RECORD
  146. iH : IHandle;
  147. Wr : BOOLEAN;
  148. Page : LONGCARD;
  149. Buf : TPagePointer;
  150. END;
  151. FindMode = (Fnd,Ins,Src,Idx,Rec);
  152. (* Fnd = first exact key match
  153. Ins = place to insert into
  154. Src = first exact key match or greater
  155. Idx = exact entry (i.e. DataPos also)
  156. Rec = exact entry (i.e. DataPos also) or greater *)
  157. WalkMode = (Forward,Backward);
  158. ErrorStrs = ARRAY Errors,[0..31] OF CHAR;
  159. CONST
  160. IndexDataSize = SIZE(IndexData);
  161. IndexFileSize = VSIZE(IndexFile.G2)+IndexDataSize;
  162. ErrorStr = ErrorStrs('No Error',
  163. '#: Bad Open',
  164. 'Bad # Slot',
  165. 'Not a FHandle',
  166. 'Not an IHandle',
  167. 'Not a Data File',
  168. 'Not an Index File',
  169. '#: Bad Index',
  170. '#: Wrong Record Size',
  171. 'Key Too Large',
  172. 'Duplicated Key',
  173. '#: Access Mode Not Supported',
  174. 'Error During Read',
  175. 'Error During Write',
  176. "Couldn't Acquire Lock",
  177. 'Item Must Already Be Locked',
  178. 'File I/O Error',
  179. 'Lock Table Overflow',
  180. 'Unknown Error');
  181. FileDataCheck = FileDataWrSize=SIZE(IndexFileWr);
  182. IndexDataCheck = IndexDataWrSize=SIZE(IndexDataWr);
  183. (*%F FileDataCheck *)
  184. WARNING - FileDataWrSize must be equal to SIZE(FileDataWr);
  185. (*%E *)
  186. (*%F IndexDataCheck *)
  187. WARNING - IndexDataWrSize must be equal to SIZE(IndexDataWr);
  188. (*%E *)
  189. MODULE inline;
  190. EXPORT MemMove, MemFastMove, AddAddr, IncAddr, DecAddr;
  191. TYPE
  192. A2 = ARRAY[0..1] OF SHORTCARD;
  193. A3 = ARRAY[0..2] OF SHORTCARD;
  194. A6 = ARRAY[0..5] OF SHORTCARD;
  195. A8 = ARRAY[0..7] OF SHORTCARD;
  196. A19 = ARRAY[0..18] OF SHORTCARD;
  197. A21 = ARRAY[0..20] OF SHORTCARD;
  198. (*%T _fptr *)
  199. (*# save *)
  200. (*# call(inline=>on) *)
  201. (*# call(reg_param=>(si,ax,di,es,cx),reg_saved=>(ax,bx,dx,ds,es,st1,st2,st3,st4,st5,st6)) *)
  202. PROCEDURE MemMove(s,r: ADDRESS; c: CARDINAL)=A21(0E3H,013H,(* jcxz $1 *)
  203. 09CH, (* pushf *)
  204. 01EH, (* push ds *)
  205. 08EH,0D8H,(* mov ds,ax *)
  206. 03BH,0FEH,(* cmp di,si *)
  207. 072H,007H,(* jb $0 *)
  208. 003H,0F1H,(* add si,cx *)
  209. 003H,0F9H,(* add di,cx *)
  210. 04EH, (* dec si *)
  211. 04FH, (* dec di *)
  212. 0FDH, (* std *)
  213. (* $0: *)
  214. 0F3H,0A4H,(* rep ;movsb *)
  215. 01FH, (* pop ds *)
  216. 09DH); (* popf *)
  217. (* $1: *)
  218. (*# restore *)
  219. (*# save *)
  220. (*# call(inline=>on) *)
  221. (*# call(reg_param=>(si,ax,di,es,cx),reg_saved=>(ax,bx,dx,ds,es,st1,st2,st3,st4,st5,st6)) *)
  222. PROCEDURE MemFastMove(s,r: ADDRESS; c: CARDINAL)=A8(0E3H,006H,(* jcxz $0 *)
  223. 01EH, (* push ds *)
  224. 08EH,0D8H,(* mov ds,ax *)
  225. 0F3H,0A4H,(* rep ;movsb *)
  226. 01FH); (* pop ds *)
  227. (* $0: *)
  228. (*# restore *)
  229. (*# save *)
  230. (*# call(inline=>on) *)
  231. (*# call(reg_param=>(ax,dx,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  232. PROCEDURE AddAddr(A: ADDRESS; I: CARDINAL): ADDRESS=A2(003H,0C1H);(*add ax,cx*)
  233. (*# restore *)
  234. (*# save *)
  235. (*# call(inline=>on) *)
  236. (*# call(reg_param=>(bx,es,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  237. PROCEDURE IncAddr(VAR a: ADDRESS; i: CARDINAL)=A3(026H,001H,007H); (* add es:[bx],cx *)
  238. (*# restore *)
  239. (*# save *)
  240. (*# call(inline=>on) *)
  241. (*# call(reg_param=>(bx,es,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  242. PROCEDURE DecAddr(VAR a: ADDRESS; i: CARDINAL)=A3(026H,029H,007H); (* sub es:[bx],cx *)
  243. (*# restore *)
  244. (*%E *)
  245. (*%F _fptr *)
  246. (*# save *)
  247. (*# call(inline=>on) *)
  248. (*# call(reg_param=>(si,di,cx),reg_saved=>(ax,bx,dx,ds,st1,st2,st3,st4,st5,st6)) *)
  249. PROCEDURE MemMove(s,r: ADDRESS; c: CARDINAL)=A19(0E3H,011H,(* jcxz $1 *)
  250. 09CH, (* pushf *)
  251. 01EH, (* push ds *)
  252. 007H, (* pop es *)
  253. 03BH,0FEH,(* cmp di,si *)
  254. 072H,007H,(* jb $0 *)
  255. 003H,0F1H,(* add si,cx *)
  256. 003H,0F9H,(* add di,cx *)
  257. 04EH, (* dec si *)
  258. 04FH, (* dec di *)
  259. 0FDH, (* std *)
  260. (* $0: *)
  261. 0F3H,0A4H,(* rep; movsb*)
  262. 09DH); (* popf *)
  263. (* $1: *)
  264. (*# restore *)
  265. (*# save *)
  266. (*# call(inline=>on) *)
  267. (*# call(reg_param=>(si,di,cx),reg_saved=>(ax,bx,dx,ds,st1,st2,st3,st4,st5,st6)) *)
  268. PROCEDURE MemFastMove(s,r: ADDRESS; c: CARDINAL)=A6(0E3H,004H, (* jcxz $0 *)
  269. 01EH, (* push ds *)
  270. 007H, (* pop es *)
  271. 0F3H,0A4H); (* rep; movsb*)
  272. (* $0: *)
  273. (*# restore *)
  274. (*# save *)
  275. (*# call(inline=>on) *)
  276. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  277. PROCEDURE AddAddr(A: ADDRESS; I: CARDINAL): ADDRESS=A2(003H,0C1H);(*add ax,cx*)
  278. (*# restore *)
  279. (*# save *)
  280. (*# call(inline=>on) *)
  281. (*# call(reg_param=>(bx,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  282. PROCEDURE IncAddr(VAR a: ADDRESS; i: CARDINAL)=A2(001H,007H); (* add [bx],cx *)
  283. (*# restore *)
  284. (*# save *)
  285. (*# call(inline=>on) *)
  286. (*# call(reg_param=>(bx,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  287. PROCEDURE DecAddr(VAR a: ADDRESS; i: CARDINAL)=A2(029H,007H); (* sub [bx],cx *)
  288. (*# restore *)
  289. (*%E *)
  290. END inline;
  291. CONST
  292. OutOfMemory = 80;
  293. ioError = 81;
  294. DiskFull = 82;
  295. (*# save *)
  296. (*# call(reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  297. PROCEDURE Die(error: BOOLEAN; code: CARDINAL);
  298. VAR s : ARRAY [0..79] OF CHAR;
  299. b : BOOLEAN;
  300. BEGIN
  301. IF error THEN
  302. Str.CardToStr(LONGCARD(code),s,10,b);
  303. Str.Prepend(s,CHR(13)+CHR(10)+'BTREE: Fatal error, code = ');
  304. Lib.FatalError(s);
  305. END;
  306. END Die;
  307. (*# restore *)
  308. PROCEDURE AllocMem(VAR a: ADDRESS; s: CARDINAL);
  309. BEGIN
  310. a := CoreMem.calloc(1,s);
  311. END AllocMem;
  312. PROCEDURE FreeMem(VAR a: ADDRESS);
  313. BEGIN
  314. IF a#NIL THEN
  315. CoreMem.free(a);
  316. a := NIL;
  317. END;
  318. END FreeMem;
  319. PROCEDURE AdjustBuffer(D: IHandle; rs: CARDINAL);
  320. VAR
  321. sz : CARDINAL;
  322. BEGIN
  323. WITH D.ID^ DO
  324. WITH Id[D.In] DO
  325. IF iwr^.RecordSize=0 THEN
  326. sz := AdjustBlock(rs);
  327. IF bufSize<sz THEN
  328. FreeMem(bufPtr);
  329. AllocMem(bufPtr,sz);
  330. Die(bufPtr=NIL,OutOfMemory);
  331. bufSize := sz;
  332. END;
  333. END;
  334. END;
  335. END;
  336. END AdjustBuffer;
  337. PROCEDURE IsFHandle(fH: FHandle): BOOLEAN;
  338. BEGIN
  339. RETURN (fH#NIL) AND
  340. (fH^.G1=GuardV1) AND
  341. (fH^.G2=GuardV2);
  342. END IsFHandle;
  343. PROCEDURE IsIHandle(iH: IHandle): BOOLEAN;
  344. BEGIN
  345. RETURN IsFHandle(iH.ID) AND (iH.In<=iH.ID^.fwr^.IndexCount) AND
  346. (iH.ID^.Id[iH.In].Ft#FreeSlot) AND
  347. (iH.ID^.Id[iH.In].iwr^.Ft#FreeSlot);
  348. END IsIHandle;
  349. PROCEDURE IsData(iH: IHandle): BOOLEAN;
  350. BEGIN
  351. RETURN IsIHandle(iH) AND
  352. (iH.ID^.Id[iH.In].Ft=DataSlot) AND
  353. (iH.ID^.Id[iH.In].iwr^.Ft=DataSlot);
  354. END IsData;
  355. PROCEDURE IsIndex(iH: IHandle): BOOLEAN;
  356. BEGIN
  357. RETURN IsIHandle(iH) AND
  358. (iH.ID^.Id[iH.In].Ft=IndexSlot) AND
  359. (iH.ID^.Id[iH.In].iwr^.Ft=IndexSlot);
  360. END IsIndex;
  361. (*# save *)
  362. (*# call(o_a_size=>on) *)
  363. PROCEDURE Error(err: Errors; str: ARRAY OF CHAR);
  364. VAR
  365. st : ARRAY [0..100] OF CHAR;
  366. i : CARDINAL;
  367. BEGIN
  368. IF err#OK THEN
  369. st := CHR(13)+CHR(10);
  370. Str.Append(st,ErrorStr[err]);
  371. i := Str.Pos(st,'#');
  372. IF i#MAX(CARDINAL) THEN
  373. Str.Delete(st,i,1);
  374. Str.Insert(st,str,i);
  375. ELSIF Str.Length(str)#0 THEN
  376. Str.Append(st,' (');
  377. Str.Append(st,str);
  378. Str.Append(st,')');
  379. END;
  380. ErrorHandler(err,st);
  381. END;
  382. END Error;
  383. (*# restore *)
  384. PROCEDURE ClearErr(iH: IHandle);
  385. BEGIN
  386. IF IsIHandle(iH) THEN
  387. iH.ID^.Id[iH.In].LastErr := OK;
  388. END;
  389. END ClearErr;
  390. PROCEDURE ClearFErr(fH: FHandle);
  391. VAR
  392. iH : IHandle;
  393. BEGIN
  394. iH.ID := fH;
  395. iH.In := 0;
  396. ClearErr(iH);
  397. END ClearFErr;
  398. PROCEDURE SetErr(iH: IHandle; err: Errors);
  399. BEGIN
  400. IF IsIHandle(iH) AND (iH.ID^.Id[iH.In].LastErr=OK) THEN
  401. iH.ID^.Id[iH.In].LastErr := err;
  402. END;
  403. END SetErr;
  404. (*# save *)
  405. (*# call(o_a_size=>on) *)
  406. PROCEDURE CallErr(iH: IHandle; err: Errors; str: ARRAY OF CHAR);
  407. BEGIN
  408. SetErr(iH,err);
  409. Error(err,str);
  410. END CallErr;
  411. (*# restore *)
  412. PROCEDURE SetFErr(fH: FHandle; err: Errors);
  413. VAR
  414. iH : IHandle;
  415. BEGIN
  416. iH.ID := fH;
  417. iH.In := 0;
  418. SetErr(iH,err);
  419. END SetFErr;
  420. (*# save *)
  421. (*# call(o_a_size=>on) *)
  422. PROCEDURE CallFErr(fH: FHandle; err: Errors; str: ARRAY OF CHAR);
  423. VAR
  424. iH : IHandle;
  425. BEGIN
  426. iH.ID := fH;
  427. iH.In := 0;
  428. CallErr(iH,err,str);
  429. END CallFErr;
  430. (*# restore *)
  431. (*# save *)
  432. (*# call(o_a_size=>on) *)
  433. PROCEDURE IOerr(iH: IHandle; str: ARRAY OF CHAR): BOOLEAN;
  434. VAR
  435. i : CARDINAL;
  436. tmp : ARRAY[0..80] OF CHAR;
  437. ok : BOOLEAN;
  438. BEGIN
  439. i := FIOx.Error();
  440. IF i#0 THEN
  441. Str.CardToStr(VAL(LONGCARD,i),tmp,10,ok);
  442. Str.Insert(tmp,'#',0);
  443. IF Str.Length(str) # 0 THEN
  444. Str.Append(tmp,' ');
  445. Str.Append(tmp,str);
  446. END;
  447. CallErr(IHandle(iH),FileError,tmp);
  448. RETURN TRUE;
  449. ELSE
  450. RETURN FALSE;
  451. END;
  452. END IOerr;
  453. (*# restore *)
  454. (*# save *)
  455. (*# call(o_a_size=>on) *)
  456. PROCEDURE IOFerr(fH: FHandle; str: ARRAY OF CHAR): BOOLEAN;
  457. VAR
  458. iH: IHandle;
  459. BEGIN
  460. iH.ID := fH;
  461. iH.In := 0;
  462. RETURN IOerr(iH,str);
  463. END IOFerr;
  464. (*# restore *)
  465. (*# save *)
  466. (*# call(o_a_size=>on) *)
  467. PROCEDURE IOabort(str: ARRAY OF CHAR);
  468. BEGIN
  469. Die(IOerr(Null,str),ioError);
  470. END IOabort;
  471. (*# restore *)
  472. PROCEDURE ReadRec(D: IHandle; p: LONGCARD; VAR d: ARRAY OF BYTE);
  473. VAR
  474. l : CARDINAL;
  475. BEGIN
  476. WITH D.ID^ DO
  477. WITH Id[D.In] DO
  478. IF iwr^.RecordSize=0 THEN
  479. FIOx.Seek(FHandle,p-2);
  480. IOabort('ReadRec');
  481. FIOx.Read(FHandle,l,SIZE(l));
  482. IOabort('ReadRec');
  483. IF fwr^.Mode=Compress THEN
  484. AdjustBuffer(D,l);
  485. FIOx.Read(FHandle,bufPtr^,l);
  486. IOabort('ReadRec');
  487. Unpacker(l,bufPtr,ADR(d));
  488. ELSE
  489. FIOx.Read(FHandle,d,l);
  490. IOabort('ReadRec');
  491. END;
  492. ELSE
  493. FIOx.Seek(FHandle,p);
  494. IOabort('ReadRec');
  495. FIOx.Read(FHandle,d,iwr^.RecordSize);
  496. END;
  497. END;
  498. END;
  499. END ReadRec;
  500. PROCEDURE LoadRec(D: IHandle; p: LONGCARD; VAR bp: LONGCARD; VAR bs: CARDINAL);
  501. VAR
  502. a : ADDRESS;
  503. BEGIN
  504. WITH D.ID^ DO
  505. WITH Id[D.In] DO
  506. IF iwr^.RecordSize=0 THEN
  507. bp := p-SIZE(CARDINAL);
  508. FIOx.Seek(FHandle,bp);
  509. IOabort('LoadRec');
  510. FIOx.Read(FHandle,bs,SIZE(bs));
  511. IOabort('LoadRec');
  512. IF fwr^.Mode=Compress THEN
  513. AllocMem(a,bs);
  514. Die(a=NIL,OutOfMemory);
  515. FIOx.Read(FHandle,a^,bs);
  516. IOabort('LoadRec');
  517. AdjustBuffer(D,UnpackedSize(bs,a));
  518. Unpacker(bs,a,bufPtr);
  519. FreeMem(a);
  520. ELSE
  521. AdjustBuffer(D,bs);
  522. FIOx.Read(FHandle,bufPtr^,bs);
  523. IOabort('LoadRec');
  524. END;
  525. ELSE
  526. bp := p;
  527. bs := iwr^.RecordSize;
  528. FIOx.Seek(FHandle,p);
  529. IOabort('LoadRec');
  530. FIOx.Read(FHandle,bufPtr^,bs);
  531. END;
  532. END;
  533. END;
  534. END LoadRec;
  535. MODULE LRU;
  536. (* This local module encapsulates the LRU buffer. *)
  537. IMPORT Nil, IHandle, BufferPages, TPage, CallErr, Null, UnknownError,
  538. AllocMem, MemMove, IOabort, Die, OutOfMemory, DiskFull, FIOx, CoreMem;
  539. (*%T _mthread *)
  540. IMPORT Process;
  541. (*%E *)
  542. EXPORT ReadPage, WritePage, ClearPage, ClearBuffers, SaveBuffers;
  543. CONST
  544. LRUCount = 32;
  545. VAR
  546. LruPages : ARRAY [1..LRUCount] OF BufferPages;
  547. (*%F _fptr *)
  548. _Buf : TPage;
  549. (*%E *)
  550. PROCEDURE MovePage(i: CARDINAL; discard: BOOLEAN);
  551. VAR
  552. j : CARDINAL;
  553. t : BufferPages;
  554. src,
  555. dest : ADDRESS;
  556. len : CARDINAL;
  557. BEGIN
  558. IF discard THEN
  559. src := ADR(LruPages[1]);
  560. dest := ADR(LruPages[2]);
  561. len := i-1;
  562. j := 1;
  563. ELSIF i=LRUCount THEN
  564. len := 0;
  565. ELSE
  566. src := ADR(LruPages[i+1]);
  567. dest := ADR(LruPages[i]);
  568. len := LRUCount-i;
  569. j := LRUCount;
  570. END;
  571. IF len # 0 THEN
  572. t := LruPages[i];
  573. MemMove(src,dest,len*SIZE(BufferPages));
  574. LruPages[j] := t;
  575. END;
  576. END MovePage;
  577. (*# save *)
  578. (*# check(overflow=>off) *)
  579. PROCEDURE FlushPage(i: CARDINAL);
  580. BEGIN
  581. WITH LruPages[i] DO
  582. IF Wr THEN
  583. FIOx.Seek(iH.ID^.FHandle,Page);
  584. IOabort('FlushPage');
  585. (*%F _fptr *)
  586. _Buf := Buf^;
  587. FIOx.Write(iH.ID^.FHandle,_Buf,SIZE(TPage));
  588. (*%E *)
  589. (*%T _fptr *)
  590. FIOx.Write(iH.ID^.FHandle,Buf^,SIZE(TPage));
  591. (*%E *)
  592. IOabort('FlushPage');
  593. IF iH.ID^.Id[iH.In].OldWriteCnt=iH.ID^.Id[iH.In].iwr^.WriteCnt THEN
  594. INC(iH.ID^.Id[iH.In].iwr^.WriteCnt);
  595. END;
  596. Wr := FALSE;
  597. IF iH.ID^.WriteThru THEN
  598. FIOx.Flush(iH.ID^.FHandle);
  599. END;
  600. END;
  601. END;
  602. END FlushPage;
  603. (*# restore *)
  604. PROCEDURE FindPage(ih: IHandle; page: LONGCARD): BOOLEAN;
  605. VAR
  606. i : CARDINAL;
  607. f : BOOLEAN;
  608. BEGIN
  609. i := LRUCount;
  610. LOOP
  611. WITH LruPages[i] DO
  612. f := (ih=iH) AND (Page=page);
  613. END;
  614. IF f OR (i=1) THEN
  615. EXIT;
  616. END;
  617. DEC(i);
  618. END;
  619. MovePage(i,FALSE);
  620. IF NOT f THEN
  621. FlushPage(LRUCount);
  622. WITH LruPages[LRUCount] DO
  623. iH := ih;
  624. Page := page;
  625. END;
  626. END;
  627. RETURN f;
  628. END FindPage;
  629. PROCEDURE ReadPage(ih: IHandle; page: LONGCARD; VAR TP: TPage);
  630. BEGIN
  631. (*%T _mthread *) Process.Lock(); (*%E *)
  632. WITH LruPages[LRUCount] DO
  633. IF NOT FindPage(ih,page) THEN
  634. FIOx.Seek(ih.ID^.FHandle,page);
  635. IOabort('ReadPage');
  636. (*%F _fptr *)
  637. FIOx.Read(ih.ID^.FHandle,_Buf,SIZE(TPage));
  638. Buf^ := _Buf;
  639. (*%E *)
  640. (*%T _fptr *)
  641. FIOx.Read(ih.ID^.FHandle,Buf^,SIZE(TPage));
  642. (*%E *)
  643. IOabort('ReadPage');
  644. END;
  645. TP := Buf^;
  646. END;
  647. (*%T _mthread *) Process.Unlock(); (*%E *)
  648. END ReadPage;
  649. PROCEDURE WritePage(ih: IHandle; page: LONGCARD; VAR TP: TPage);
  650. VAR
  651. r : CARDINAL;
  652. BEGIN
  653. IF page=Nil THEN
  654. CallErr(Null,UnknownError,'WritePage');
  655. Die(TRUE,DiskFull);
  656. END;
  657. (*%T _mthread *) Process.Lock(); (*%E *)
  658. IF NOT FindPage(ih,page) THEN
  659. (* nothing *)
  660. END;
  661. WITH LruPages[LRUCount] DO
  662. Buf^ := TP;
  663. Wr := TRUE;
  664. IF iH.ID^.WriteThru THEN
  665. FlushPage(LRUCount);
  666. END;
  667. END;
  668. (*%T _mthread *) Process.Unlock(); (*%E *)
  669. END WritePage;
  670. PROCEDURE UnUse(ih: IHandle; page: LONGCARD; wr: BOOLEAN);
  671. VAR
  672. i : CARDINAL;
  673. BEGIN
  674. (*%T _mthread *) Process.Lock(); (*%E *)
  675. i := 1;
  676. WHILE i<=LRUCount DO
  677. WITH LruPages[i] DO
  678. IF (((ih.In=MAX(CARDINAL)) AND (ih.ID=iH.ID)) OR (ih=iH)) AND
  679. ((page=Page) OR (page=Nil)) THEN
  680. IF wr THEN
  681. FlushPage(i);
  682. ELSE
  683. MovePage(i,TRUE);
  684. LruPages[1].Wr := FALSE;
  685. LruPages[1].iH := Null;
  686. LruPages[1].Page := 0;
  687. END;
  688. END;
  689. END;
  690. INC(i);
  691. END;
  692. (*%T _mthread *) Process.Unlock(); (*%E *)
  693. END UnUse;
  694. PROCEDURE ClearPage(ih: IHandle; page: LONGCARD);
  695. BEGIN
  696. UnUse(ih,page,FALSE);
  697. END ClearPage;
  698. PROCEDURE ClearBuffers(ih: IHandle);
  699. BEGIN
  700. UnUse(ih,Nil,FALSE);
  701. END ClearBuffers;
  702. PROCEDURE SaveBuffers(ih: IHandle);
  703. BEGIN
  704. UnUse(ih,Nil,TRUE);
  705. END SaveBuffers;
  706. PROCEDURE Init;
  707. VAR
  708. i : CARDINAL;
  709. BEGIN
  710. FOR i := 1 TO LRUCount DO
  711. LruPages[i] := BufferPages(Null,FALSE,0,FarNIL);
  712. LruPages[i].Buf := CoreMem._fcalloc(1,SIZE(TPage));
  713. Die(LruPages[i].Buf=FarNIL,OutOfMemory);
  714. END;
  715. END Init;
  716. BEGIN
  717. Init;
  718. END LRU;
  719. PROCEDURE ccOneLock(lock: LockRec; type: LockType): BOOLEAN;
  720. BEGIN
  721. WITH lock DO
  722. RETURN ((type=Implicit) AND (ICnt=1) AND (ECnt=0)) OR
  723. ((type=Explicit) AND (ECnt=1) AND (ICnt=0));
  724. END;
  725. END ccOneLock;
  726. PROCEDURE ccLock(dH: IHandle; VAR lock: LockRec; type: LockType): BOOLEAN;
  727. VAR
  728. lck : FIOx.LockRec;
  729. BEGIN
  730. IF dH.ID^.Buffered THEN
  731. RETURN TRUE;
  732. END;
  733. WITH lock DO
  734. IF (type=Implicit) AND (ICnt#MAX(SHORTCARD)) THEN
  735. INC(ICnt);
  736. ELSIF (type=Explicit) AND (ECnt#MAX(SHORTCARD)) THEN
  737. INC(ECnt);
  738. ELSE
  739. CallErr(dH,LockOverflow,'ccLock');
  740. RETURN FALSE;
  741. END;
  742. IF (type=Implicit) AND (In=Null) THEN
  743. In := dH;
  744. END;
  745. lck.pos := lock.Position;
  746. lck.len := 1;
  747. IF ccOneLock(lock,type) AND NOT FIOx.Lock(dH.ID^.FHandle,lck) THEN
  748. IF type=Implicit THEN
  749. DEC(ICnt);
  750. ELSE
  751. DEC(ECnt);
  752. END;
  753. SetErr(dH,Locked);
  754. RETURN FALSE;
  755. ELSE
  756. RETURN TRUE;
  757. END;
  758. END;
  759. END ccLock;
  760. PROCEDURE cLock(dH: IHandle; dLoc: LONGCARD; type: LockType): BOOLEAN;
  761. VAR
  762. idx,
  763. tmp : CARDINAL;
  764. BEGIN
  765. IF dH.ID^.Buffered THEN
  766. RETURN TRUE;
  767. END;
  768. idx := MAX(CARDINAL);
  769. LOOP
  770. FOR tmp := 0 TO LockQSize-1 DO
  771. WITH dH.ID^.Locks[tmp] DO
  772. IF Position=dLoc THEN
  773. idx := tmp;
  774. EXIT;
  775. ELSIF (idx=MAX(CARDINAL)) AND (Position=Nil) THEN
  776. idx := tmp;
  777. END;
  778. END;
  779. END;
  780. IF idx#MAX(CARDINAL) THEN
  781. WITH dH.ID^.Locks[idx] DO
  782. Position := dLoc;
  783. ICnt := 0;
  784. ECnt := 0;
  785. IF type=Implicit THEN
  786. In := dH;
  787. ELSE
  788. In := Null;
  789. END;
  790. END;
  791. END;
  792. EXIT;
  793. END;
  794. IF idx#MAX(CARDINAL) THEN
  795. IF NOT ccLock(dH,dH.ID^.Locks[idx],type) THEN
  796. dH.ID^.Locks[idx].Position := Nil;
  797. RETURN FALSE;
  798. ELSE
  799. RETURN TRUE;
  800. END;
  801. ELSE
  802. CallErr(dH,LockOverflow,'cLock');
  803. RETURN FALSE;
  804. END;
  805. END cLock;
  806. PROCEDURE Lock(F: FHandle; DataLoc: LONGCARD): BOOLEAN;
  807. VAR
  808. dH : IHandle;
  809. BEGIN
  810. dH.ID := F;
  811. dH.In := 0;
  812. ClearErr(dH);
  813. IF NOT IsIHandle(dH) THEN
  814. CallFErr(dH.ID,NotIHandle,'Lock');
  815. RETURN FALSE;
  816. END;
  817. RETURN cLock(dH,DataLoc,Explicit);
  818. END Lock;
  819. PROCEDURE LockDat(iH: IHandle; dLoc: LONGCARD): BOOLEAN;
  820. VAR
  821. idx,
  822. tmp : CARDINAL;
  823. BEGIN
  824. IF iH.ID^.Buffered THEN
  825. RETURN TRUE;
  826. END;
  827. idx := MAX(CARDINAL);
  828. LOOP
  829. FOR tmp := 0 TO LockQSize-1 DO
  830. WITH iH.ID^.Id[iH.In].DataPtr.ID^.Locks[tmp] DO
  831. IF Position=dLoc THEN
  832. idx := tmp;
  833. EXIT;
  834. ELSIF (idx=MAX(CARDINAL)) AND (Position=Nil) THEN
  835. idx := tmp;
  836. END;
  837. END;
  838. END;
  839. IF idx#MAX(CARDINAL) THEN
  840. WITH iH.ID^.Id[iH.In].DataPtr.ID^.Locks[idx] DO
  841. Position := dLoc;
  842. ICnt := 0;
  843. ECnt := 0;
  844. In := iH;
  845. END;
  846. END;
  847. EXIT;
  848. END;
  849. IF idx#MAX(CARDINAL) THEN
  850. RETURN ccLock(iH,iH.ID^.Id[iH.In].DataPtr.ID^.Locks[idx],Implicit);
  851. ELSE
  852. CallErr(iH,LockOverflow,'LockDat');
  853. RETURN FALSE;
  854. END;
  855. END LockDat;
  856. PROCEDURE ccUnLock(dH: IHandle; VAR lock: LockRec; type: LockType);
  857. VAR
  858. lck : FIOx.LockRec;
  859. BEGIN
  860. IF dH.ID^.Buffered THEN
  861. RETURN;
  862. END;
  863. WITH lock DO
  864. IF type=Implicit THEN
  865. IF ICnt#0 THEN
  866. DEC(ICnt);
  867. END;
  868. ELSIF type=AllImplicit THEN
  869. ICnt := 0;
  870. ELSIF type=AllLocks THEN
  871. ICnt := 0;
  872. ECnt := 0;
  873. ELSIF type=Explicit THEN
  874. IF ECnt#0 THEN
  875. DEC(ECnt);
  876. ELSE
  877. CallErr(dH,NotLocked,'ccUnLock');
  878. RETURN;
  879. END;
  880. END;
  881. IF ICnt=0 THEN
  882. IF ECnt#0 THEN
  883. In := Null;
  884. ELSE
  885. lck.pos := Position;
  886. lck.len := 1;
  887. FIOx.UnLock(dH.ID^.FHandle,lck);
  888. END;
  889. END;
  890. END;
  891. END ccUnLock;
  892. PROCEDURE cUnLock(dH: IHandle; dLoc: LONGCARD; type: LockType);
  893. VAR
  894. idx : CARDINAL;
  895. BEGIN
  896. IF dH.ID^.Buffered THEN
  897. RETURN;
  898. END;
  899. FOR idx := 0 TO LockQSize-1 DO
  900. IF dH.ID^.Locks[idx].Position=dLoc THEN
  901. ccUnLock(dH,dH.ID^.Locks[idx],type);
  902. dH.ID^.Locks[idx].Position := Nil;
  903. RETURN;
  904. END;
  905. END;
  906. IF type=Explicit THEN
  907. CallErr(dH,NotLocked,'cUnLock');
  908. END;
  909. END cUnLock;
  910. PROCEDURE UnLock(F: FHandle; DataLoc: LONGCARD);
  911. VAR
  912. dH : IHandle;
  913. BEGIN
  914. dH.ID := F;
  915. dH.In := 0;
  916. ClearErr(dH);
  917. IF NOT IsIHandle(dH) THEN
  918. CallFErr(dH.ID,NotIHandle,'UnLock');
  919. RETURN;
  920. END;
  921. cUnLock(dH,DataLoc,Explicit);
  922. END UnLock;
  923. PROCEDURE UnLockDat(iH: IHandle; dLoc: LONGCARD);
  924. VAR
  925. idx : CARDINAL;
  926. BEGIN
  927. IF iH.ID^.Buffered THEN
  928. RETURN;
  929. END;
  930. FOR idx := 0 TO LockQSize-1 DO
  931. WITH iH.ID^.Id[iH.In].DataPtr.ID^ DO
  932. IF Locks[idx].Position=dLoc THEN
  933. ccUnLock(iH,Locks[idx],Implicit);
  934. Locks[idx].Position := Nil;
  935. RETURN;
  936. END;
  937. END;
  938. END;
  939. END UnLockDat;
  940. PROCEDURE FollowNextIndx(VAR H : IHandle);
  941. BEGIN
  942. WITH H.ID^.Id[H.In] DO H := NextIndx; END;
  943. END FollowNextIndx;
  944. PROCEDURE Release(H: IHandle);
  945. VAR
  946. idx : CARDINAL;
  947. BEGIN
  948. ClearErr(H);
  949. IF NOT IsIHandle(H) THEN
  950. CallFErr(H.ID,NotIHandle,'Release');
  951. RETURN;
  952. END;
  953. IF H.ID^.Id[H.In].Ft=DataSlot THEN
  954. FollowNextIndx(H);
  955. WHILE H#Null DO
  956. Release(H);
  957. FollowNextIndx(H);
  958. END;
  959. ELSE
  960. IF IsData(H.ID^.Id[H.In].DataPtr) THEN
  961. WITH H.ID^.Id[H.In].DataPtr.ID^ DO
  962. IF NOT Buffered THEN
  963. FOR idx := 0 TO LockQSize-1 DO
  964. WITH Locks[idx] DO
  965. IF (Position#Nil) AND (In=H) THEN
  966. ccUnLock(H,Locks[idx],AllImplicit);
  967. Position := Nil;
  968. END;
  969. END;
  970. END;
  971. END;
  972. END;
  973. END;
  974. END;
  975. END Release;
  976. PROCEDURE cOneLock(dH: IHandle; dLoc: LONGCARD; type: LockType): BOOLEAN;
  977. VAR
  978. idx : CARDINAL;
  979. BEGIN
  980. WITH dH.ID^ DO
  981. IF NOT Buffered THEN
  982. FOR idx := 0 TO LockQSize-1 DO
  983. IF Locks[idx].Position=dLoc THEN
  984. RETURN ccOneLock(Locks[idx],type);
  985. END;
  986. END;
  987. END;
  988. END;
  989. RETURN FALSE;
  990. END cOneLock;
  991. PROCEDURE cLocked(dH: IHandle; dLoc: LONGCARD): BOOLEAN;
  992. VAR
  993. idx : CARDINAL;
  994. BEGIN
  995. WITH dH.ID^ DO
  996. IF NOT Buffered THEN
  997. FOR idx := 0 TO LockQSize-1 DO
  998. IF Locks[idx].Position=dLoc THEN
  999. RETURN TRUE;
  1000. END;
  1001. END;
  1002. RETURN FALSE;
  1003. ELSE
  1004. RETURN TRUE;
  1005. END;
  1006. END;
  1007. END cLocked;
  1008. PROCEDURE LockFile(fH: FHandle): BOOLEAN;
  1009. VAR
  1010. iH : IHandle;
  1011. BEGIN
  1012. IF NOT IsFHandle(fH) THEN
  1013. CallFErr(fH,NotFHandle,'LockFile');
  1014. RETURN FALSE;
  1015. END;
  1016. WITH fH^ DO
  1017. IF NOT Buffered THEN
  1018. iH.ID := fH;
  1019. iH.In := 0;
  1020. IF NOT ccLock(iH,fhLock,Implicit) THEN
  1021. RETURN FALSE;
  1022. END;
  1023. IF ccOneLock(fhLock,Implicit) THEN
  1024. FIOx.Seek(FHandle,fhLock.Position);
  1025. IOabort('LockFile');
  1026. FIOx.Read(FHandle,fwr^,FileDataWrSize);
  1027. IOabort('LockFile');
  1028. END;
  1029. END;
  1030. END;
  1031. RETURN TRUE;
  1032. END LockFile;
  1033. PROCEDURE FlushFHandle(fH: FHandle);
  1034. BEGIN
  1035. WITH fH^ DO
  1036. IF NOT ReadOnly THEN
  1037. FIOx.Seek(FHandle,fhLock.Position);
  1038. IOabort('FlushFHandle');
  1039. FIOx.Write(FHandle,fwr^,FileDataWrSize);
  1040. IOabort('FlushFHandle');
  1041. END;
  1042. END;
  1043. END FlushFHandle;
  1044. PROCEDURE UnLockFile(fH: FHandle);
  1045. VAR
  1046. iH : IHandle;
  1047. BEGIN
  1048. IF NOT IsFHandle(fH) THEN
  1049. CallFErr(fH,NotFHandle,'UnLockFile');
  1050. RETURN;
  1051. END;
  1052. WITH fH^ DO
  1053. IF NOT Buffered THEN
  1054. IF ccOneLock(fhLock,Implicit) THEN
  1055. FlushFHandle(fH);
  1056. END;
  1057. iH.ID := fH;
  1058. iH.In := 0;
  1059. ccUnLock(iH,fhLock,Implicit);
  1060. END;
  1061. END;
  1062. END UnLockFile;
  1063. PROCEDURE cLockIHandle(iH: IHandle; type: LockType): BOOLEAN;
  1064. BEGIN
  1065. WITH iH.ID^ DO
  1066. IF NOT Buffered THEN
  1067. WITH Id[iH.In] DO
  1068. IF ccLock(iH,ihLock,type) THEN
  1069. IF ccOneLock(ihLock,type) THEN
  1070. FIOx.Seek(FHandle,ihLock.Position);
  1071. IOabort('cLockIHandle');
  1072. FIOx.Read(FHandle,iwr^,IndexDataWrSize);
  1073. IOabort('cLockIHandle');
  1074. IF (Ft=IndexSlot) AND (OldWriteCnt#iwr^.WriteCnt) THEN
  1075. ClearBuffers(iH);
  1076. OldWriteCnt := iwr^.WriteCnt;
  1077. PageLevel := 0;
  1078. IF PageRefs^.Height<iwr^.Depth THEN
  1079. FreeMem(PageRefs);
  1080. AllocMem(PageRefs,VSIZE(PageRef.Height)+(iwr^.Depth+1)*SIZE(PageRefRec));
  1081. Die(PageRefs=NIL,OutOfMemory);
  1082. PageRefs^.Height := iwr^.Depth+1;
  1083. END;
  1084. END;
  1085. END;
  1086. ELSE
  1087. RETURN FALSE;
  1088. END;
  1089. END;
  1090. END;
  1091. END;
  1092. RETURN TRUE;
  1093. END cLockIHandle;
  1094. PROCEDURE LockIHandle(H: IHandle): BOOLEAN;
  1095. BEGIN
  1096. ClearErr(H);
  1097. IF NOT IsIHandle(H) THEN
  1098. CallFErr(H.ID,NotIHandle,'LockIHandle');
  1099. RETURN FALSE;
  1100. END;
  1101. RETURN cLockIHandle(H,Explicit);
  1102. END LockIHandle;
  1103. PROCEDURE FlushIHandle(iH: IHandle);
  1104. BEGIN
  1105. WITH iH.ID^ DO
  1106. IF NOT ReadOnly THEN
  1107. WITH Id[iH.In] DO
  1108. IF Ft=IndexSlot THEN
  1109. SaveBuffers(iH);
  1110. OldWriteCnt := iwr^.WriteCnt;
  1111. END;
  1112. FIOx.Seek(FHandle,ihLock.Position);
  1113. IOabort('FlushIHandle');
  1114. FIOx.Write(FHandle,iwr^,IndexDataWrSize);
  1115. IOabort('FlushIHandle');
  1116. END;
  1117. END;
  1118. END;
  1119. END FlushIHandle;
  1120. PROCEDURE SetLastKey(iH: IHandle);
  1121. VAR
  1122. TP : TPage;
  1123. TYPE
  1124. IPtr = POINTER Seg(TP) TO IndexItem;
  1125. A2 = ARRAY[0..1] OF SHORTCARD;
  1126. (*# save *)
  1127. (*# call(inline=>on) *)
  1128. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1129. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  1130. (*# restore *)
  1131. VAR
  1132. IP : IPtr;
  1133. BEGIN
  1134. WITH iH.ID^ DO
  1135. WITH Id[iH.In] DO
  1136. LastKeyOK := TRUE;
  1137. ReadPage(iH,PageRefs^.Refs[PageLevel].Page,TP);
  1138. IP := AddIPtr(IPtr(Ofs((TP.IItem))),PageRefs^.Refs[PageLevel].Rec*(2*SIZE(LONGCARD)+iwr^.KeySize));
  1139. LastKey := IP^.Key;
  1140. LastKeyRef := IP^.DP;
  1141. END;
  1142. END;
  1143. END SetLastKey;
  1144. PROCEDURE cUnLockIHandle(iH: IHandle; type: LockType);
  1145. BEGIN
  1146. WITH iH.ID^ DO
  1147. IF NOT Buffered THEN
  1148. WITH Id[iH.In] DO
  1149. IF ccOneLock(ihLock,type) THEN
  1150. IF Ft=IndexSlot THEN
  1151. IF PageLevel#0 THEN
  1152. SetLastKey(iH);
  1153. END;
  1154. FlushIHandle(iH);
  1155. END;
  1156. END;
  1157. ccUnLock(iH,ihLock,type);
  1158. END;
  1159. END;
  1160. END;
  1161. END cUnLockIHandle;
  1162. PROCEDURE UnLockIHandle(H: IHandle);
  1163. BEGIN
  1164. ClearErr(H);
  1165. IF NOT IsIHandle(H) THEN
  1166. CallFErr(H.ID,NotIHandle,'UnLockIHandle');
  1167. RETURN;
  1168. END;
  1169. cUnLockIHandle(H,Explicit);
  1170. END UnLockIHandle;
  1171. PROCEDURE N2Eval(KeySize: CARDINAL): CARDINAL;
  1172. VAR
  1173. t : CARDINAL;
  1174. BEGIN
  1175. t := (PageSize-6) DIV (8+KeySize);
  1176. IF ODD(t) THEN
  1177. DEC(t);
  1178. END;
  1179. IF (t=0) THEN
  1180. CallErr(Null,KeyTooBig,'N2Eval');
  1181. RETURN MAX(CARDINAL);
  1182. END;
  1183. RETURN t;
  1184. END N2Eval;
  1185. PROCEDURE WalkIx(iH: IHandle; mode: WalkMode);
  1186. VAR
  1187. TP : TPage;
  1188. TYPE
  1189. IPtr = POINTER Seg(TP) TO IndexItem;
  1190. A2 = ARRAY[0..1] OF SHORTCARD;
  1191. A3 = ARRAY[0..2] OF SHORTCARD;
  1192. (*# save *)
  1193. (*# call(inline=>on) *)
  1194. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1195. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  1196. (*# restore *)
  1197. (*%T _fptr *)
  1198. (*# save *)
  1199. (*# call(inline=>on) *)
  1200. (*# call(reg_param=>(bx,es,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1201. PROCEDURE IncIPtr(VAR a: IPtr; i: CARDINAL)=A3(026H,001H,007H); (* add es:[bx],cx *)
  1202. (*# restore *)
  1203. (*# save *)
  1204. (*# call(inline=>on) *)
  1205. (*# call(reg_param=>(bx,es,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1206. PROCEDURE DecIPtr(VAR a: IPtr; i: CARDINAL)=A3(026H,029H,007H); (* sub es:[bx],cx *)
  1207. (*# restore *)
  1208. (*%E *)
  1209. (*%F _fptr *)
  1210. (*# save *)
  1211. (*# call(inline=>on) *)
  1212. (*# call(reg_param=>(bx,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1213. PROCEDURE IncIPtr(VAR a: IPtr; i: CARDINAL)=A2(001H,007H); (* add [bx],cx *)
  1214. (*# restore *)
  1215. (*# save *)
  1216. (*# call(inline=>on) *)
  1217. (*# call(reg_param=>(bx,ax),reg_saved=>(ax,bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1218. PROCEDURE DecIPtr(VAR a: IPtr; i: CARDINAL)=A2(029H,007H); (* sub [bx],cx *)
  1219. (*# restore *)
  1220. (*%E *)
  1221. VAR
  1222. IP,
  1223. BP : IPtr;
  1224. LeafPage : BOOLEAN;
  1225. ItemSize : CARDINAL;
  1226. Index : CARDINAL;
  1227. PROCEDURE GetP(P: LONGCARD);
  1228. BEGIN
  1229. ReadPage(iH,P,TP);
  1230. IP := BP;
  1231. WITH iH.ID^.Id[iH.In] DO
  1232. LeafPage := PageLevel=iwr^.Depth;
  1233. WITH PageRefs^.Refs[PageLevel] DO
  1234. Page := P;
  1235. IF TP.ICount=iwr^.N2 THEN
  1236. IF P=iwr^.TopPage THEN
  1237. Cnt := 2;
  1238. ELSE
  1239. Cnt := PageRefs^.Refs[PageLevel-1].Cnt+1;
  1240. END;
  1241. ELSE
  1242. Cnt := 0;
  1243. END;
  1244. END;
  1245. END;
  1246. Index := 0;
  1247. END GetP;
  1248. BEGIN
  1249. WITH iH.ID^.Id[iH.In] DO
  1250. ItemSize := 8+iwr^.KeySize;
  1251. BP := IPtr(Ofs((TP.IItem)));
  1252. LastDataRef := Nil;
  1253. IF PageLevel=0 THEN
  1254. PageLevel := 1;
  1255. GetP(iwr^.TopPage);
  1256. IF TP.ICount=0 THEN
  1257. PageLevel := 0;
  1258. RETURN;
  1259. ELSE
  1260. Index := 0;
  1261. LOOP
  1262. IF mode=Backward THEN
  1263. Index := TP.ICount;
  1264. END;
  1265. PageRefs^.Refs[PageLevel].Rec := Index;
  1266. IncIPtr(IP,Index*ItemSize);
  1267. IF LeafPage THEN
  1268. IF mode=Backward THEN
  1269. DecIPtr(IP,ItemSize);
  1270. DEC(PageRefs^.Refs[PageLevel].Rec);
  1271. END;
  1272. EXIT;
  1273. END;
  1274. INC(PageLevel);
  1275. GetP(IP^.IP);
  1276. END;
  1277. END;
  1278. ELSE
  1279. GetP(PageRefs^.Refs[PageLevel].Page);
  1280. Index := PageRefs^.Refs[PageLevel].Rec;
  1281. IF mode=Forward THEN
  1282. IF (Index+1<TP.ICount) OR
  1283. ((Index<TP.ICount) AND NOT LeafPage) THEN
  1284. INC(Index);
  1285. WHILE NOT LeafPage DO
  1286. PageRefs^.Refs[PageLevel].Rec := Index;
  1287. IncIPtr(IP,Index*ItemSize);
  1288. INC(PageLevel);
  1289. GetP(IP^.IP);
  1290. END;
  1291. ELSE
  1292. REPEAT
  1293. DEC(PageLevel);
  1294. IF PageLevel=0 THEN
  1295. RETURN;
  1296. END;
  1297. GetP(PageRefs^.Refs[PageLevel].Page);
  1298. Index := PageRefs^.Refs[PageLevel].Rec;
  1299. UNTIL Index<TP.ICount;
  1300. END;
  1301. ELSE
  1302. IF LeafPage THEN
  1303. IF Index=0 THEN
  1304. REPEAT
  1305. DEC(PageLevel);
  1306. IF PageLevel=0 THEN
  1307. RETURN;
  1308. END;
  1309. GetP(PageRefs^.Refs[PageLevel].Page);
  1310. Index := PageRefs^.Refs[PageLevel].Rec;
  1311. UNTIL Index>0;
  1312. END;
  1313. ELSE
  1314. REPEAT
  1315. PageRefs^.Refs[PageLevel].Rec := Index;
  1316. IncIPtr(IP,Index*ItemSize);
  1317. INC(PageLevel);
  1318. GetP(IP^.IP);
  1319. Index := TP.ICount;
  1320. UNTIL LeafPage;
  1321. END;
  1322. DEC(Index);
  1323. END;
  1324. PageRefs^.Refs[PageLevel].Rec := Index;
  1325. IncIPtr(IP,Index*ItemSize);
  1326. END;
  1327. LastDataRef := IP^.DP;
  1328. END;
  1329. END WalkIx;
  1330. PROCEDURE FindIx(iH: IHandle; Key: ARRAY OF BYTE; DataPos: LONGCARD;
  1331. Mode: FindMode): BOOLEAN;
  1332. VAR
  1333. TP : TPage;
  1334. TYPE
  1335. IPtr = POINTER Seg(TP) TO IndexItem;
  1336. A2 = ARRAY[0..1] OF SHORTCARD;
  1337. (*# save *)
  1338. (*# call(inline=>on) *)
  1339. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  1340. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  1341. (*# restore *)
  1342. VAR
  1343. IP,
  1344. BP : IPtr;
  1345. LeafPage : BOOLEAN;
  1346. ItemSize : CARDINAL;
  1347. Index : CARDINAL;
  1348. C : CmpRes;
  1349. First,
  1350. Last : CARDINAL;
  1351. LABEL
  1352. _Greater,
  1353. _Less;
  1354. PROCEDURE GetPage(P: LONGCARD);
  1355. BEGIN
  1356. ReadPage(iH,P,TP);
  1357. WITH iH.ID^.Id[iH.In] DO
  1358. LeafPage := PageLevel=iwr^.Depth;
  1359. WITH PageRefs^.Refs[PageLevel] DO
  1360. Page := P;
  1361. IF TP.ICount=iwr^.N2 THEN
  1362. IF P=iwr^.TopPage THEN
  1363. Cnt := 2;
  1364. ELSE
  1365. Cnt := PageRefs^.Refs[PageLevel-1].Cnt+1;
  1366. END;
  1367. ELSE
  1368. Cnt := 0;
  1369. END;
  1370. END;
  1371. END;
  1372. First := 0;
  1373. Last := TP.ICount;
  1374. Index := (First + Last) DIV 2;
  1375. IP := AddIPtr(BP,Index*ItemSize);
  1376. END GetPage;
  1377. PROCEDURE Walk(m : WalkMode);
  1378. BEGIN
  1379. WITH iH.ID^.Id[iH.In] DO
  1380. WalkIx(iH,m);
  1381. IF PageLevel#0 THEN
  1382. GetPage(PageRefs^.Refs[PageLevel].Page);
  1383. IP := AddIPtr(BP,PageRefs^.Refs[PageLevel].Rec*ItemSize);
  1384. C := CompFct(ADR(IP^.Key),ADR(Key));
  1385. LastDataRef := IP^.DP;
  1386. ELSE
  1387. LastDataRef := Nil;
  1388. END;
  1389. END;
  1390. END Walk;
  1391. BEGIN
  1392. BP := IPtr(ADR(TP.IItem));
  1393. WITH iH.ID^.Id[iH.In] DO
  1394. ItemSize := 2*SIZE(LONGCARD)+iwr^.KeySize;
  1395. PageLevel := 1;
  1396. GetPage(iwr^.TopPage);
  1397. LOOP (* Opt1 *)
  1398. IF Index<TP.ICount THEN
  1399. C := CompFct(ADR(IP^.Key),ADR(Key));
  1400. LastDataRef := IP^.DP;
  1401. ELSE
  1402. C := Greater;
  1403. LastDataRef := Nil;
  1404. END;
  1405. IF First >= Last THEN
  1406. PageRefs^.Refs[PageLevel].Rec := Index;
  1407. IF LeafPage THEN
  1408. CASE Mode OF
  1409. | Ins : RETURN FALSE;
  1410. | Idx : RETURN FALSE;
  1411. | Rec : IF Index=TP.ICount THEN
  1412. Walk(Forward);
  1413. END;
  1414. RETURN FALSE;
  1415. | Fnd,
  1416. Src : WHILE (PageLevel#0) AND (C#Less) DO
  1417. Walk(Backward);
  1418. END;
  1419. Walk(Forward);
  1420. RETURN (PageLevel#0) AND ((C=Eq) OR (Mode=Src));
  1421. END;
  1422. ELSE
  1423. INC(PageLevel);
  1424. GetPage(IP^.IP);
  1425. END;
  1426. ELSE
  1427. CASE C OF
  1428. | Greater :
  1429. _Greater: (* This key is >= the one we want *)
  1430. Last := Index;
  1431. | Eq : CASE Mode OF
  1432. | Ins : IF NOT iwr^.DupKey THEN
  1433. CallErr(iH,ErrDupKey,'FindIx');
  1434. PageRefs^.Refs[PageLevel].Rec := Index;
  1435. RETURN FALSE;
  1436. ELSIF IP^.DP<DataPos THEN
  1437. GOTO _Less;
  1438. ELSE
  1439. GOTO _Greater;
  1440. END;
  1441. | Idx,
  1442. Rec : IF IP^.DP<DataPos THEN
  1443. GOTO _Less;
  1444. ELSIF IP^.DP=DataPos THEN
  1445. PageRefs^.Refs[PageLevel].Rec := Index;
  1446. RETURN TRUE;
  1447. ELSE
  1448. GOTO _Greater;
  1449. END;
  1450. | Fnd,
  1451. Src : GOTO _Greater;
  1452. END;
  1453. | Less :
  1454. _Less: (* This key is < the one we want *)
  1455. First := Index+1;
  1456. END;
  1457. Index := (First + Last) DIV 2;
  1458. IP := AddIPtr(BP,Index*ItemSize);
  1459. END;
  1460. END;
  1461. END;
  1462. END FindIx;
  1463. PROCEDURE FreeFreeBlock(fH: FHandle; Loc: LONGCARD);
  1464. BEGIN
  1465. FIOx.Seek(fH^.FHandle,Loc);
  1466. IOabort('FreeFreeBlock');
  1467. FIOx.Write(fH^.FHandle,fH^.fwr^.FreeList,4);
  1468. IOabort('FreeFreeBlock');
  1469. fH^.fwr^.FreeList := Loc;
  1470. END FreeFreeBlock;
  1471. PROCEDURE AllocateFreeBlock(fH: FHandle): LONGCARD;
  1472. VAR
  1473. Loc : LONGCARD;
  1474. r : CARDINAL;
  1475. BEGIN
  1476. IF fH^.fwr^.FreeList#Nil THEN
  1477. Loc := fH^.fwr^.FreeList;
  1478. FIOx.Seek(fH^.FHandle,Loc);
  1479. IOabort('AllocateFreeBlock');
  1480. FIOx.Read(fH^.FHandle,fH^.fwr^.FreeList,4);
  1481. IOabort('AllocateFreeBlock');
  1482. RETURN Loc;
  1483. ELSE
  1484. FIOx.Seek(fH^.FHandle,fH^.fwr^.FileSize+PageSize-1);
  1485. IOabort('AllocateFreeBlock');
  1486. FIOx.Write(fH^.FHandle,0,1);
  1487. IF FIOx.Error()=FIOx.DISK_FULL THEN
  1488. FIOx.Truncate(fH^.FHandle,fH^.fwr^.FileSize);
  1489. IOabort('AllocateFreeBlock');
  1490. RETURN Nil;
  1491. END;
  1492. IOabort('AllocateFreeBlock');
  1493. Loc := fH^.fwr^.FileSize;
  1494. INC(fH^.fwr^.FileSize,PageSize);
  1495. RETURN Loc;
  1496. END;
  1497. END AllocateFreeBlock;
  1498. (*# save *)
  1499. (*# check(overflow=>off) *)
  1500. PROCEDURE FreeBlock(fH: FHandle; Len,Loc: LONGCARD);
  1501. VAR
  1502. iH : IHandle;
  1503. r,
  1504. PLen,
  1505. NLen : CARDINAL;
  1506. PLoc,
  1507. PLen4 : LONGCARD;
  1508. BEGIN
  1509. iH.ID := fH;
  1510. iH.In := 0;
  1511. LOOP
  1512. WITH fH^ DO
  1513. CASE fwr^.Mode OF
  1514. FixSize : AddIndex(iH,Len,Loc);
  1515. EXIT;
  1516. | Size16,
  1517. Compress : IF Len<SIZE(CARDINAL)*2 THEN
  1518. Len := SIZE(CARDINAL)*2;
  1519. END;
  1520. FIOx.Seek(FHandle,Loc-SIZE(CARDINAL));
  1521. IOabort('FreeBlock');
  1522. FIOx.Read(FHandle,PLen,SIZE(CARDINAL));
  1523. IF FIOx.Error()#FIOx.NO_ERROR THEN
  1524. PLen := MAX(CARDINAL);
  1525. END;
  1526. PLoc := Loc-LONGCARD(PLen);
  1527. IF ((Loc-SIZE(CARDINAL))>LONGCARD(fwr^.HeaderSize)) AND (PLen<MAX(CARDINAL)-SIZE(LONGCARD)*2) AND FindIx(iH,PLen,PLoc,Idx) THEN
  1528. DeleteIndex(iH,PLen,PLoc);
  1529. IF LONGCARD(PLen)+Len<MAX(CARDINAL)-SIZE(LONGCARD)*2 THEN
  1530. NLen := PLen+CARDINAL(Len);
  1531. Loc := Loc+Len;
  1532. Len := 0;
  1533. ELSE
  1534. NLen := MAX(CARDINAL)-SIZE(LONGCARD)*2;
  1535. Len := Len-LONGCARD((MAX(CARDINAL)-SIZE(LONGCARD)*2-PLen));
  1536. Loc := Loc+LONGCARD((MAX(CARDINAL)-SIZE(LONGCARD)*2-PLen))
  1537. END;
  1538. IF (Len>0) AND (Len<SIZE(LONGCARD)) THEN
  1539. NLen := NLen-(SIZE(LONGCARD)-CARDINAL(Len));
  1540. Loc := Loc-(SIZE(LONGCARD)-Len);
  1541. Len := SIZE(LONGCARD);
  1542. END;
  1543. FIOx.Seek(FHandle,PLoc);
  1544. IOabort('FreeBlock');
  1545. FIOx.Write(FHandle,NLen,SIZE(CARDINAL));
  1546. IOabort('FreeBlock');
  1547. FIOx.Seek(FHandle,PLoc+LONGCARD(NLen)-SIZE(CARDINAL));
  1548. IOabort('FreeBlock');
  1549. FIOx.Write(FHandle,NLen,SIZE(CARDINAL));
  1550. IOabort('FreeBlock');
  1551. AddIndex(iH,NLen,PLoc);
  1552. END;
  1553. IF Len>0 THEN
  1554. FIOx.Seek(FHandle,Loc);
  1555. IOabort('FreeBlock');
  1556. FIOx.Write(FHandle,Len,SIZE(CARDINAL));
  1557. IOabort('FreeBlock');
  1558. FIOx.Seek(FHandle,Loc+Len-SIZE(CARDINAL));
  1559. IOabort('FreeBlock');
  1560. FIOx.Write(FHandle,Len,SIZE(CARDINAL));
  1561. IOabort('FreeBlock');
  1562. AddIndex(iH,Len,Loc);
  1563. PLoc := Loc+Len;
  1564. ELSE
  1565. Len := LONGCARD(NLen);
  1566. PLoc := PLoc+Len;
  1567. END;
  1568. (* Opt2 *)
  1569. FIOx.Seek(FHandle,PLoc);
  1570. IOabort('FreeBlock');
  1571. FIOx.Read(FHandle,PLen,SIZE(CARDINAL));
  1572. IF FIOx.Error()#FIOx.NO_ERROR THEN
  1573. PLen := MAX(CARDINAL);
  1574. END;
  1575. IF (Len<MAX(CARDINAL)-SIZE(LONGCARD)*2) AND (PLen<MAX(CARDINAL)-SIZE(LONGCARD)*2) AND FindIx(iH,PLen,PLoc,Idx) THEN
  1576. DeleteIndex(iH,PLen,PLoc);
  1577. Len := LONGCARD(PLen);
  1578. Loc := PLoc;
  1579. ELSE
  1580. EXIT;
  1581. END;
  1582. | Size32 : IF Len<SIZE(LONGCARD)*2 THEN
  1583. Len := SIZE(LONGCARD)*2;
  1584. END;
  1585. FIOx.Seek(FHandle,Loc-SIZE(LONGCARD));
  1586. IOabort('FreeBlock');
  1587. FIOx.Read(FHandle,PLen4,SIZE(LONGCARD));
  1588. IF FIOx.Error()#FIOx.NO_ERROR THEN
  1589. PLen4 := MAX(LONGCARD);
  1590. END;
  1591. PLoc := Loc-PLen4;
  1592. IF ((Loc-SIZE(LONGCARD))>LONGCARD(fwr^.HeaderSize)) AND (PLen4<MAX(LONGCARD)-SIZE(LONGCARD)*2) AND FindIx(iH,PLen4,PLoc,Idx) THEN
  1593. DeleteIndex(iH,PLen4,PLoc);
  1594. Len := PLen4+Len;
  1595. FIOx.Seek(FHandle,PLoc);
  1596. IOabort('FreeBlock');
  1597. FIOx.Write(FHandle,Len,SIZE(LONGCARD));
  1598. IOabort('FreeBlock');
  1599. FIOx.Seek(FHandle,PLoc+Len-SIZE(LONGCARD));
  1600. IOabort('FreeBlock');
  1601. FIOx.Write(FHandle,Len,SIZE(LONGCARD));
  1602. IOabort('FreeBlock');
  1603. AddIndex(iH,Len,PLoc);
  1604. PLoc := PLoc+Len;
  1605. ELSE
  1606. FIOx.Seek(FHandle,Loc);
  1607. IOabort('FreeBlock');
  1608. FIOx.Write(FHandle,Len,SIZE(LONGCARD));
  1609. IOabort('FreeBlock');
  1610. FIOx.Seek(FHandle,Loc+Len-SIZE(LONGCARD));
  1611. IOabort('FreeBlock');
  1612. FIOx.Write(FHandle,Len,SIZE(LONGCARD));
  1613. IOabort('FreeBlock');
  1614. AddIndex(iH,Len,Loc);
  1615. PLoc := Loc+Len;
  1616. END;
  1617. (* Opt2 *)
  1618. FIOx.Seek(FHandle,PLoc);
  1619. IOabort('FreeBlock');
  1620. FIOx.Read(FHandle,PLen4,SIZE(LONGCARD));
  1621. IF FIOx.Error()#FIOx.NO_ERROR THEN
  1622. PLen4 := MAX(LONGCARD);
  1623. END;
  1624. IF (Len<MAX(LONGCARD)-SIZE(LONGCARD)*2) AND (PLen4<MAX(LONGCARD)-SIZE(LONGCARD)*2) AND FindIx(iH,PLen4,PLoc,Idx) THEN
  1625. DeleteIndex(iH,PLen4,PLoc);
  1626. Len := PLen4;
  1627. Loc := PLoc;
  1628. ELSE
  1629. EXIT;
  1630. END;
  1631. | NoDealoc : CallFErr(fH,BadFree,'NoDealloc');
  1632. RETURN;
  1633. ELSE
  1634. CallFErr(fH,UnknownError,'FreeBlock');
  1635. RETURN;
  1636. END;
  1637. END;
  1638. END;
  1639. END FreeBlock;
  1640. (*# restore *)
  1641. PROCEDURE AllocateBlock(fH: FHandle; Len: LONGCARD): LONGCARD;
  1642. VAR
  1643. Loc : LONGCARD;
  1644. PROCEDURE Extend;
  1645. BEGIN
  1646. FIOx.Seek(fH^.FHandle,fH^.fwr^.FileSize+Len-1);
  1647. IOabort('AllocateBlock.Extend');
  1648. FIOx.Write(fH^.FHandle,0,1);
  1649. IF FIOx.Error()=FIOx.DISK_FULL THEN
  1650. FIOx.Truncate(fH^.FHandle,fH^.fwr^.FileSize);
  1651. IOabort('AllocateBlock.Extend');
  1652. Loc := Nil;
  1653. RETURN;
  1654. END;
  1655. IOabort('AllocateBlock.Extend');
  1656. Loc := fH^.fwr^.FileSize;
  1657. INC(fH^.fwr^.FileSize,Len);
  1658. END Extend;
  1659. VAR
  1660. iH : IHandle;
  1661. ActLen4,
  1662. tl : LONGCARD;
  1663. ActLen2,
  1664. r : CARDINAL;
  1665. Safe : BOOLEAN;
  1666. BEGIN
  1667. iH.ID := fH;
  1668. iH.In := 0;
  1669. WITH fH^ DO
  1670. CASE fwr^.Mode OF
  1671. FixSize : IF Len >= MAX(CARDINAL)-8 THEN
  1672. CallFErr(fH,BadSize,'Allocate');
  1673. RETURN Nil;
  1674. END;
  1675. IF FindIndex(iH,Len,Loc) THEN
  1676. DeleteIndex(iH,Len,Loc);
  1677. ELSE
  1678. Extend;
  1679. END;
  1680. | Size16,
  1681. Compress : IF Len<4 THEN
  1682. Len := 4;
  1683. END;
  1684. IF Len >= MAX(CARDINAL)-8 THEN
  1685. CallFErr(fH,BadSize,'Allocate');
  1686. RETURN Nil;
  1687. END;
  1688. IF FindIndex(iH,Len,Loc) THEN
  1689. DeleteIndex(iH,Len,Loc);
  1690. ELSIF SearchIndex(iH,Len+4,Loc) THEN
  1691. FIOx.Seek(FHandle,Loc);
  1692. IOabort('AllocateBlock');
  1693. FIOx.Read(FHandle,ActLen2,SIZE(CARDINAL));
  1694. IOabort('AllocateBlock');
  1695. DeleteIndex(iH,ActLen2,Loc);
  1696. FreeBlock(fH,LONGCARD(ActLen2)-Len,Loc+Len);
  1697. ELSE
  1698. Extend;
  1699. END;
  1700. | Size32 : IF Len<8 THEN
  1701. Len := 8;
  1702. END;
  1703. IF FindIndex(iH,Len,Loc) THEN
  1704. DeleteIndex(iH,Len,Loc);
  1705. ELSIF SearchIndex(iH,Len+8,Loc) THEN
  1706. FIOx.Seek(FHandle,Loc);
  1707. IOabort('AllocateBlock');
  1708. FIOx.Read(FHandle,ActLen4,SIZE(LONGCARD));
  1709. IOabort('AllocateBlock');
  1710. DeleteIndex(iH,ActLen4,Loc);
  1711. FreeBlock(fH,ActLen4-Len,Loc+Len);
  1712. ELSE
  1713. Extend;
  1714. END;
  1715. | NoDealoc : Extend;
  1716. ELSE
  1717. CallFErr(fH,UnknownError,'Allocate Block');
  1718. RETURN Nil;
  1719. END;
  1720. END;
  1721. RETURN Loc;
  1722. END AllocateBlock;
  1723. PROCEDURE LockIx(dH: IHandle): BOOLEAN;
  1724. PROCEDURE cLockIx(iH: IHandle): BOOLEAN;
  1725. BEGIN
  1726. IF iH#Null THEN
  1727. IF NOT cLockIHandle(iH,Implicit) THEN
  1728. RETURN FALSE;
  1729. ELSIF NOT cLockIx(iH.ID^.Id[iH.In].NextIndx) THEN
  1730. cUnLockIHandle(iH,Implicit);
  1731. RETURN FALSE;
  1732. END;
  1733. END;
  1734. RETURN TRUE;
  1735. END cLockIx;
  1736. BEGIN
  1737. IF NOT cLockIx(dH.ID^.Id[dH.In].NextIndx) THEN
  1738. SetErr(dH,Locked);
  1739. RETURN FALSE;
  1740. ELSE
  1741. RETURN TRUE;
  1742. END;
  1743. END LockIx;
  1744. PROCEDURE UnLockIx(dH: IHandle);
  1745. BEGIN
  1746. FollowNextIndx(dH);
  1747. WHILE dH#Null DO
  1748. cUnLockIHandle(dH,Implicit);
  1749. FollowNextIndx(dH);
  1750. END;
  1751. END UnLockIx;
  1752. PROCEDURE Delete(D: IHandle);
  1753. VAR
  1754. r,
  1755. Size,
  1756. BSize : CARDINAL;
  1757. t,
  1758. BPos : LONGCARD;
  1759. iH,
  1760. tH : IHandle;
  1761. Key : KeyType;
  1762. BEGIN
  1763. ClearErr(D);
  1764. IF NOT IsData(D) THEN
  1765. CallErr(D,NotData,'Delete');
  1766. RETURN;
  1767. END;
  1768. IF D.ID^.ReadOnly THEN
  1769. CallErr(D,BadWrite,'Delete with ReadOnly');
  1770. RETURN;
  1771. END;
  1772. IF NOT cLocked(D,D.ID^.Id[D.In].LastDataRef) THEN
  1773. CallErr(D,NotLocked,'Delete');
  1774. RETURN;
  1775. END;
  1776. WITH D.ID^.Id[D.In] DO
  1777. IF LastDataRef#Nil THEN
  1778. IF LockFile(D.ID) THEN
  1779. IF LockIx(D) THEN
  1780. LoadRec(D,LastDataRef,BPos,BSize);
  1781. iH := NextIndx;
  1782. LOOP
  1783. WHILE iH.ID#NIL DO
  1784. iH.ID^.Id[iH.In].KeyFct(ADR(Key),bufPtr);
  1785. DeleteIndex(iH,Key,LastDataRef);
  1786. IF LastError(iH)#OK THEN
  1787. SetErr(D,LastError(iH));
  1788. tH := NextIndx;
  1789. WHILE tH#iH DO
  1790. tH.ID^.Id[tH.In].KeyFct(ADR(Key),bufPtr);
  1791. AddIndex(tH,Key,LastDataRef);
  1792. IF LastError(tH)#OK THEN
  1793. ClearErr(D);
  1794. SetErr(D,LastError(tH));
  1795. EXIT;
  1796. END;
  1797. FollowNextIndx(tH);
  1798. END;
  1799. EXIT;
  1800. END;
  1801. FollowNextIndx(iH);
  1802. END;
  1803. FreeBlock(D.ID,LONGCARD(BSize),BPos);
  1804. EXIT;
  1805. END;
  1806. cUnLock(D,LastDataRef,AllLocks);
  1807. LastDataRef := Nil;
  1808. IF LastError(D)=OK THEN
  1809. DEC(iwr^.RecordCnt);
  1810. END;
  1811. UnLockIx(D);
  1812. END;
  1813. UnLockFile(D.ID);
  1814. ELSE
  1815. SetErr(D,Locked);
  1816. END;
  1817. END;
  1818. END;
  1819. END Delete;
  1820. PROCEDURE Add(D: IHandle; Data: ARRAY OF BYTE; Length: CARDINAL);
  1821. VAR
  1822. Size : CARDINAL;
  1823. Buf : ADDRESS;
  1824. iH,
  1825. tH : IHandle;
  1826. Key : KeyType;
  1827. BEGIN
  1828. ClearErr(D);
  1829. IF NOT IsData(D) THEN
  1830. CallErr(D,NotData,'Add');
  1831. RETURN;
  1832. END;
  1833. IF D.ID^.ReadOnly THEN
  1834. CallErr(D,BadWrite,'Add with ReadOnly');
  1835. RETURN;
  1836. END;
  1837. WITH D.ID^.Id[D.In] DO
  1838. IF LockFile(D.ID) THEN
  1839. IF LockIx(D) THEN
  1840. IF iwr^.RecordSize=0 THEN
  1841. IF D.ID^.fwr^.Mode=Compress THEN
  1842. AdjustBuffer(D,Length);
  1843. Size := Packer(Length,ADR(Data),bufPtr);
  1844. Buf := bufPtr;
  1845. ELSE
  1846. Size := Length;
  1847. Buf := ADR(Data);
  1848. END;
  1849. LastDataRef := AllocateBlock(D.ID,LONGCARD(Size+SIZE(Size)))+SIZE(Size);
  1850. IF LastDataRef#Nil THEN
  1851. FIOx.Seek(D.ID^.FHandle,LastDataRef-SIZE(Size));
  1852. IOabort('Add');
  1853. FIOx.Write(D.ID^.FHandle,Size,SIZE(Size));
  1854. IOabort('Add');
  1855. END;
  1856. ELSE
  1857. Size := iwr^.RecordSize;
  1858. Buf := ADR(Data);
  1859. LastDataRef := AllocateBlock(D.ID,LONGCARD(Size));
  1860. IF LastDataRef#Nil THEN
  1861. FIOx.Seek(D.ID^.FHandle,LastDataRef);
  1862. IOabort('Add');
  1863. END;
  1864. END;
  1865. IF LastDataRef=Nil THEN
  1866. UnLockIx(D);
  1867. UnLockFile(D.ID);
  1868. CallErr(D,FileError,'Add');
  1869. RETURN;
  1870. END;
  1871. FIOx.Write(D.ID^.FHandle,Buf^,Size);
  1872. IOabort('Add');
  1873. iH := NextIndx;
  1874. LOOP
  1875. WHILE iH.ID#NIL DO
  1876. iH.ID^.Id[iH.In].KeyFct(ADR(Key),ADR(Data));
  1877. AddIndex(iH,Key,LastDataRef);
  1878. IF LastError(iH)#OK THEN
  1879. SetErr(D,LastError(iH));
  1880. LOOP
  1881. tH := NextIndx;
  1882. WHILE tH#iH DO
  1883. tH.ID^.Id[tH.In].KeyFct(ADR(Key),ADR(Data));
  1884. DeleteIndex(tH,Key,LastDataRef);
  1885. IF LastError(tH)#OK THEN
  1886. ClearErr(D);
  1887. SetErr(D,LastError(tH));
  1888. EXIT;
  1889. END;
  1890. FollowNextIndx(tH);
  1891. END;
  1892. EXIT;
  1893. END;
  1894. IF iwr^.RecordSize=0 THEN
  1895. FreeBlock(D.ID,LONGCARD(Size+SIZE(Size)),LastDataRef-SIZE(Size));
  1896. ELSE
  1897. FreeBlock(D.ID,LONGCARD(Size),LastDataRef);
  1898. END;
  1899. EXIT;
  1900. END;
  1901. FollowNextIndx(iH);
  1902. END;
  1903. EXIT;
  1904. END;
  1905. IF LastError(D)=OK THEN
  1906. INC(iwr^.RecordCnt);
  1907. END;
  1908. UnLockIx(D);
  1909. END;
  1910. UnLockFile(D.ID);
  1911. ELSE
  1912. SetErr(D,Locked);
  1913. END;
  1914. END;
  1915. END Add;
  1916. PROCEDURE Change(D: IHandle; Data: ARRAY OF BYTE; Length: CARDINAL);
  1917. VAR
  1918. BPos : LONGCARD;
  1919. size : CARDINAL;
  1920. t : CARDINAL;
  1921. iH : IHandle;
  1922. err : Errors;
  1923. OldKey,
  1924. NewKey : KeyType;
  1925. BEGIN
  1926. ClearErr(D);
  1927. IF NOT IsData(D) THEN
  1928. CallErr(D,NotData,'Change');
  1929. RETURN;
  1930. END;
  1931. IF D.ID^.ReadOnly THEN
  1932. CallErr(D,BadWrite,'Change with ReadOnly');
  1933. RETURN;
  1934. END;
  1935. IF (D.ID^.Id[D.In].iwr^.RecordSize=0) AND (D.ID^.fwr^.Mode=Compress) THEN
  1936. CallErr(D,BadSize,'Change');
  1937. RETURN;
  1938. END;
  1939. IF D.ID^.Id[D.In].LastDataRef=Nil THEN
  1940. CallErr(D,BadIndex,'Change');
  1941. RETURN;
  1942. END;
  1943. IF NOT cLocked(D,D.ID^.Id[D.In].LastDataRef) THEN
  1944. CallErr(D,NotLocked,'Change');
  1945. RETURN;
  1946. END;
  1947. LoadRec(D,D.ID^.Id[D.In].LastDataRef,BPos,size);
  1948. IF size#Length THEN
  1949. CallErr(D,BadSize,'Change');
  1950. RETURN;
  1951. END;
  1952. err := OK;
  1953. iH := D.ID^.Id[D.In].NextIndx;
  1954. LOOP
  1955. IF iH=Null THEN
  1956. EXIT;
  1957. END;
  1958. WITH iH.ID^.Id[iH.In] DO
  1959. KeyFct(ADR(OldKey),D.ID^.Id[D.In].bufPtr);
  1960. KeyFct(ADR(NewKey),ADR(Data));
  1961. IF CompFct(ADR(OldKey),ADR(NewKey))#Eq THEN
  1962. err := BadIndex;
  1963. EXIT;
  1964. END;
  1965. iH := NextIndx;
  1966. END;
  1967. END;
  1968. CallErr(D,err,'Change');
  1969. IF err=OK THEN
  1970. FIOx.Seek(D.ID^.FHandle,D.ID^.Id[D.In].LastDataRef);
  1971. IOabort('Change');
  1972. FIOx.Write(D.ID^.FHandle,Data,size);
  1973. IOabort('Change');
  1974. END;
  1975. END Change;
  1976. PROCEDURE SyncIx(iH: IHandle; rec: ARRAY OF BYTE);
  1977. VAR
  1978. tH : IHandle;
  1979. BEGIN
  1980. tH := iH.ID^.Id[iH.In].DataPtr;
  1981. IF tH.ID^.Id[tH.In].Sync THEN
  1982. LOOP
  1983. FollowNextIndx(tH);
  1984. IF tH=Null THEN
  1985. EXIT;
  1986. END;
  1987. IF tH#iH THEN
  1988. WITH tH.ID^.Id[tH.In] DO
  1989. LastKeyRef := iH.ID^.Id[iH.In].LastDataRef;
  1990. KeyFct(ADR(LastKey),ADR(rec));
  1991. LastKeyOK := TRUE;
  1992. PageLevel := 0;
  1993. END;
  1994. END;
  1995. END;
  1996. END;
  1997. END SyncIx;
  1998. PROCEDURE Search(I: IHandle; Key: ARRAY OF BYTE;
  1999. VAR Data: ARRAY OF BYTE): BOOLEAN;
  2000. VAR
  2001. r : BOOLEAN;
  2002. t : CARDINAL;
  2003. BEGIN
  2004. ClearErr(I);
  2005. IF NOT IsIndex(I) THEN
  2006. CallErr(I,NotIndex,'Search');
  2007. RETURN FALSE;
  2008. END;
  2009. Release(I);
  2010. IF cLockIHandle(I,Implicit) THEN
  2011. r := SearchIndex(I,Key,I.ID^.Id[I.In].LastDataRef);
  2012. WITH I.ID^.Id[I.In] DO
  2013. IF NOT r THEN
  2014. DataPtr.ID^.Id[DataPtr.In].LastDataRef := Nil;
  2015. ELSE
  2016. IF LockDat(I,LastDataRef) THEN
  2017. DataPtr.ID^.Id[DataPtr.In].LastDataRef := LastDataRef;
  2018. ReadRec(DataPtr,LastDataRef,Data);
  2019. (*
  2020. l := DataPtr.ID^.Id[DataPtr.In].iwr^.RecordSize;
  2021. IF l=0 THEN
  2022. FIOx.Seek(DataPtr.ID^.FHandle,LastDataRef-2);
  2023. IOabort('Search');
  2024. FIOx.Read(DataPtr.ID^.FHandle,l,2);
  2025. IOabort('Search');
  2026. ELSE
  2027. FIOx.Seek(DataPtr.ID^.FHandle,LastDataRef);
  2028. IOabort('Search');
  2029. END;
  2030. FIOx.Read(DataPtr.ID^.FHandle,Data,l);
  2031. IOabort('Search');
  2032. *)
  2033. SyncIx(I,Data);
  2034. ELSE
  2035. r := FALSE;
  2036. END;
  2037. END;
  2038. END;
  2039. cUnLockIHandle(I,Implicit);
  2040. RETURN r;
  2041. ELSE
  2042. RETURN FALSE;
  2043. END;
  2044. END Search;
  2045. PROCEDURE Find(I: IHandle; Key: ARRAY OF BYTE;
  2046. VAR Data: ARRAY OF BYTE): BOOLEAN;
  2047. VAR
  2048. r : BOOLEAN;
  2049. t : CARDINAL;
  2050. BEGIN
  2051. ClearErr(I);
  2052. IF NOT IsIndex(I) THEN
  2053. CallErr(I,NotIndex,'Find');
  2054. RETURN FALSE;
  2055. END;
  2056. Release(I);
  2057. IF cLockIHandle(I,Implicit) THEN
  2058. r := FindIndex(I,Key,I.ID^.Id[I.In].LastDataRef);
  2059. WITH I.ID^.Id[I.In] DO
  2060. IF r THEN
  2061. IF LockDat(I,LastDataRef) THEN
  2062. DataPtr.ID^.Id[DataPtr.In].LastDataRef := LastDataRef;
  2063. ReadRec(DataPtr,LastDataRef,Data);
  2064. (*
  2065. l := DataPtr.ID^.Id[DataPtr.In].iwr^.RecordSize;
  2066. IF l=0 THEN
  2067. FIOx.Seek(DataPtr.ID^.FHandle,LastDataRef-2);
  2068. IOabort('Find');
  2069. FIOx.Read(DataPtr.ID^.FHandle,l,2);
  2070. IOabort('Find');
  2071. ELSE
  2072. FIOx.Seek(DataPtr.ID^.FHandle,LastDataRef);
  2073. IOabort('Find');
  2074. END;
  2075. FIOx.Read(DataPtr.ID^.FHandle,Data,l);
  2076. IOabort('Find');
  2077. *)
  2078. SyncIx(I,Data);
  2079. ELSE
  2080. r := FALSE;
  2081. END;
  2082. ELSE
  2083. DataPtr.ID^.Id[DataPtr.In].LastDataRef := Nil;
  2084. END;
  2085. END;
  2086. cUnLockIHandle(I,Implicit);
  2087. RETURN r;
  2088. ELSE
  2089. RETURN FALSE;
  2090. END;
  2091. END Find;
  2092. PROCEDURE Next(I: IHandle; VAR Data: ARRAY OF BYTE): BOOLEAN;
  2093. VAR
  2094. SerKey : IndexItem;
  2095. Loc : LONGCARD;
  2096. r : CARDINAL;
  2097. ok : BOOLEAN;
  2098. BEGIN
  2099. ClearErr(I);
  2100. IF NOT IsIndex(I) THEN
  2101. CallErr(I,NotIndex,'Next');
  2102. RETURN FALSE;
  2103. END;
  2104. IF cLockIHandle(I,Implicit) THEN
  2105. WITH I.ID^.Id[I.In] DO
  2106. IF NextIndex(I,Loc) THEN
  2107. IF LockDat(I,Loc) THEN
  2108. DataPtr.ID^.Id[DataPtr.In].LastDataRef := Loc;
  2109. ReadRec(DataPtr,Loc,Data);
  2110. (*
  2111. l := DataPtr.ID^.Id[DataPtr.In].iwr^.RecordSize;
  2112. IF l=0 THEN
  2113. FIOx.Seek(DataPtr.ID^.FHandle,Loc-2);
  2114. IOabort('Next');
  2115. FIOx.Read(DataPtr.ID^.FHandle,l,2);
  2116. IOabort('Next');
  2117. ELSE
  2118. FIOx.Seek(DataPtr.ID^.FHandle,Loc);
  2119. IOabort('Next');
  2120. END;
  2121. FIOx.Read(DataPtr.ID^.FHandle,Data,l);
  2122. IOabort('Next');
  2123. *)
  2124. SyncIx(I,Data);
  2125. LastKeyOK := FALSE;
  2126. ok := TRUE;
  2127. ELSE
  2128. PageLevel := 0;
  2129. ok := FALSE;
  2130. END;
  2131. ELSE
  2132. ok := FALSE;
  2133. END;
  2134. END;
  2135. cUnLockIHandle(I,Implicit);
  2136. RETURN ok;
  2137. ELSE
  2138. RETURN FALSE;
  2139. END;
  2140. END Next;
  2141. PROCEDURE Prev(I: IHandle; VAR Data: ARRAY OF BYTE): BOOLEAN;
  2142. VAR
  2143. SerKey : IndexItem;
  2144. Loc : LONGCARD;
  2145. r : CARDINAL;
  2146. ok : BOOLEAN;
  2147. BEGIN
  2148. ClearErr(I);
  2149. IF NOT IsIndex(I) THEN
  2150. CallErr(I,NotIndex,'Prev');
  2151. RETURN FALSE;
  2152. END;
  2153. IF cLockIHandle(I,Implicit) THEN
  2154. WITH I.ID^.Id[I.In] DO
  2155. IF PrevIndex(I,Loc) THEN
  2156. IF LockDat(I,Loc) THEN
  2157. DataPtr.ID^.Id[DataPtr.In].LastDataRef := Loc;
  2158. ReadRec(DataPtr,Loc,Data);
  2159. (*
  2160. l := DataPtr.ID^.Id[DataPtr.In].iwr^.RecordSize;
  2161. IF l=0 THEN
  2162. FIOx.Seek(DataPtr.ID^.FHandle,Loc-2);
  2163. IOabort('Prev');
  2164. FIOx.Read(DataPtr.ID^.FHandle,l,2);
  2165. IOabort('Prev');
  2166. ELSE
  2167. FIOx.Seek(DataPtr.ID^.FHandle,Loc);
  2168. IOabort('Prev');
  2169. END;
  2170. FIOx.Read(DataPtr.ID^.FHandle,Data,l);
  2171. IOabort('Prev');
  2172. *)
  2173. SyncIx(I,Data);
  2174. LastKeyOK := FALSE;
  2175. ok := TRUE;
  2176. ELSE
  2177. PageLevel := 0;
  2178. ok := FALSE;
  2179. END;
  2180. ELSE
  2181. ok := FALSE;
  2182. END;
  2183. END;
  2184. cUnLockIHandle(I,Implicit);
  2185. RETURN ok;
  2186. ELSE
  2187. RETURN FALSE;
  2188. END;
  2189. END Prev;
  2190. PROCEDURE Reset(H: IHandle);
  2191. VAR
  2192. iH : IHandle;
  2193. BEGIN
  2194. ClearErr(H);
  2195. IF NOT IsIHandle(H) THEN
  2196. CallFErr(H.ID,NotIHandle,'Reset');
  2197. RETURN;
  2198. END;
  2199. IF IsData(H) THEN
  2200. iH := H.ID^.Id[H.In].NextIndx;
  2201. WHILE iH.ID#NIL DO
  2202. Reset(iH);
  2203. FollowNextIndx(iH);
  2204. END;
  2205. ELSE
  2206. H.ID^.Id[H.In].PageLevel := 0;
  2207. H.ID^.Id[H.In].LastKeyOK := FALSE;
  2208. Release(H);
  2209. END;
  2210. H.ID^.Id[H.In].LastDataRef := Nil;
  2211. END Reset;
  2212. PROCEDURE UpdateSlot(iH: IHandle);
  2213. BEGIN
  2214. FIOx.Seek(iH.ID^.FHandle,iH.ID^.Id[iH.In].ihLock.Position);
  2215. IOabort('UpdateSlot');
  2216. FIOx.Write(iH.ID^.FHandle,iH.ID^.Id[iH.In].iwr^,IndexDataWrSize);
  2217. IOabort('UpdateSlot');
  2218. END UpdateSlot;
  2219. PROCEDURE OpenIx(VAR iH: IHandle; CmpFct: CompareFunction; KeSize: CARDINAL;
  2220. DpKey: BOOLEAN; Create: BOOLEAN);
  2221. VAR
  2222. t : TPage;
  2223. i,
  2224. r : CARDINAL;
  2225. BEGIN
  2226. WITH iH.ID^.Id[iH.In] DO
  2227. LastDataRef := Nil;
  2228. NextIndx := Null;
  2229. LastErr := OK;
  2230. ErrorNest := 0;
  2231. DataPtr := Null;
  2232. PageLevel := 0;
  2233. CompFct := CmpFct;
  2234. KeyFct := NULLPROC;
  2235. LastKeyOK := FALSE;
  2236. IF Create THEN
  2237. OldWriteCnt := 0;
  2238. AllocMem(PageRefs,VSIZE(PageRef.Height)+10*SIZE(PageRefRec));
  2239. Die(PageRefs=NIL,OutOfMemory);
  2240. PageRefs^.Height := 10;
  2241. iwr^.RecordCnt := 0;
  2242. iwr^.WriteCnt := 0;
  2243. IF iH.In=0 THEN
  2244. iwr^.TopPage := iH.ID^.fwr^.FileSize;
  2245. INC(iH.ID^.fwr^.FileSize,PageSize);
  2246. ELSE
  2247. iwr^.TopPage := AllocateBlock(iH.ID,PageSize);
  2248. END;
  2249. iwr^.Depth := 1;
  2250. iwr^.KeySize := KeSize;
  2251. iwr^.N2 := N2Eval(KeSize);
  2252. IF iwr^.N2=MAX(CARDINAL) THEN
  2253. SetFErr(iH.ID,KeyTooBig);
  2254. RETURN;
  2255. END;
  2256. iwr^.N22 := iwr^.N2 DIV 2;
  2257. iwr^.DupKey := DpKey;
  2258. (* create empty Root Page *)
  2259. t.ICount := 0;
  2260. t.IItem.IP := Nil;
  2261. iwr^.Ft := IndexSlot;
  2262. FIOx.Seek(iH.ID^.FHandle,iwr^.TopPage);
  2263. IOabort('OpenIx');
  2264. FIOx.Write(iH.ID^.FHandle,t,SIZE(t));
  2265. IOabort('OpenIx');
  2266. UpdateSlot(iH);
  2267. ELSE
  2268. IF (iwr^.Ft#IndexSlot) OR (iwr^.KeySize#KeSize) OR (iwr^.DupKey#DpKey) THEN
  2269. CallFErr(iH.ID,BadIndex,'OpenIx');
  2270. RETURN;
  2271. END;
  2272. OldWriteCnt := iwr^.WriteCnt;
  2273. i := 10;
  2274. IF i+2 < iwr^.Depth THEN
  2275. i := (iwr^.Depth-i)*2+i;
  2276. END;
  2277. AllocMem(PageRefs,VSIZE(PageRef.Height)+i*SIZE(PageRefRec));
  2278. Die(PageRefs=NIL,OutOfMemory);
  2279. PageRefs^.Height := i;
  2280. END;
  2281. Ft := IndexSlot;
  2282. END;
  2283. END OpenIx;
  2284. (*# save *)
  2285. (*%T _fcall *) (*# call(near_call=>off) *) (*%E *)
  2286. PROCEDURE SizeCmp4(VAR a,b: LONGCARD): CmpRes;
  2287. BEGIN
  2288. IF a < b THEN
  2289. RETURN Less;
  2290. ELSIF a = b THEN
  2291. RETURN Eq;
  2292. ELSE
  2293. RETURN Greater;
  2294. END;
  2295. END SizeCmp4;
  2296. (*# restore *)
  2297. (*# save *)
  2298. (*%T _fcall *) (*# call(near_call=>off) *) (*%E *)
  2299. PROCEDURE SizeCmp2(VAR a,b: CARDINAL): CmpRes;
  2300. BEGIN
  2301. IF a < b THEN
  2302. RETURN Less;
  2303. ELSIF a = b THEN
  2304. RETURN Eq;
  2305. ELSE
  2306. RETURN Greater;
  2307. END;
  2308. END SizeCmp2;
  2309. (*# restore *)
  2310. PROCEDURE Open(Name: ARRAY OF CHAR; MaxIHandle: CARDINAL; AMode : AccessMode;
  2311. readOnly, shared, Create: BOOLEAN): FHandle;
  2312. VAR
  2313. iH : IHandle;
  2314. h,
  2315. r,
  2316. i : CARDINAL;
  2317. lck : FIOx.LockRec;
  2318. (*# save *)
  2319. (*# call(o_a_size=>on) *)
  2320. PROCEDURE Abort(str : ARRAY OF CHAR);
  2321. BEGIN
  2322. IF iH.ID # NIL THEN
  2323. IF iH.ID^.FHandle#MAX(CARDINAL) THEN
  2324. FIOx.Close(iH.ID^.FHandle);
  2325. IOabort('Open.Abort');
  2326. END;
  2327. FreeMem(iH.ID);
  2328. END;
  2329. CallErr(Null,BadOpen,str);
  2330. END Abort;
  2331. (*# restore *)
  2332. BEGIN
  2333. IF (AMode=Compress) AND NOT Packing() THEN
  2334. CallErr(Null,BadOpen,'Compress w/o PACK');
  2335. RETURN NIL;
  2336. END;
  2337. IF readOnly AND Create THEN
  2338. CallErr(Null,BadOpen,'ReadOnly with Create');
  2339. RETURN NIL;
  2340. END;
  2341. IF shared AND Create THEN
  2342. CallErr(Null,BadOpen,'Shared with Create');
  2343. END;
  2344. r := FIOx.Open(Name,shared,readOnly,Create);
  2345. IF r=MAX(CARDINAL) THEN
  2346. CallErr(Null,FileError,'Create');
  2347. RETURN NIL;
  2348. END;
  2349. h := SIZE(IndexDataWr)*MaxIHandle+SIZE(IndexFileWr);
  2350. IF h MOD SectorSize#0 THEN
  2351. h := h+SectorSize-(h MOD SectorSize);
  2352. END;
  2353. i := IndexDataSize*MaxIHandle+IndexFileSize+h;
  2354. AllocMem(iH.ID,i);
  2355. Die(iH.ID=NIL,OutOfMemory);
  2356. iH.In := 0;
  2357. WITH iH.ID^ DO
  2358. ReadOnly := readOnly;
  2359. Buffered := NOT shared OR readOnly OR NOT FIOx.MultiFile(r);
  2360. WriteThru := FALSE;
  2361. FOR i := 0 TO LockQSize-1 DO
  2362. Locks[i] := LockRec(Nil,0,0,Null);
  2363. END;
  2364. fhLock := LockRec(0,0,0,Null);
  2365. FHandle := r;
  2366. fwr := AddAddr(iH.ID,IndexFileSize+IndexDataSize*MaxIHandle);
  2367. FOR i := 0 TO MaxIHandle DO
  2368. WITH Id[i] DO
  2369. ihLock := LockRec(0,0,0,Null);
  2370. ihLock.Position := SIZE(IndexFileWr)+SIZE(IndexDataWr)*VAL(LONGCARD,i);
  2371. Ft := FreeSlot;
  2372. iwr := AddAddr(fwr,VAL(CARDINAL,ihLock.Position));
  2373. END;
  2374. END;
  2375. IF Create THEN
  2376. fwr^.HeaderSize := h;
  2377. fwr^.FileSize := VAL(LONGCARD,h);
  2378. fwr^.Version := ThisVersion;
  2379. fwr^.FreeList := Nil;
  2380. fwr^.IndexCount :=MaxIHandle;
  2381. fwr^.Mode := AMode;
  2382. fwr^.PageSz := PageSize;
  2383. fwr^.MaxKeySz := MaxKeySize;
  2384. FOR i := 0 TO MaxIHandle DO
  2385. Id[i].iwr^.Ft := FreeSlot;
  2386. END;
  2387. FIOx.Write(FHandle,fwr^,fwr^.HeaderSize);
  2388. IOabort('Open');
  2389. ELSE
  2390. lck.pos := 0;
  2391. lck.len := SIZE(fwr^.HeaderSize);
  2392. IF NOT Buffered AND NOT FIOx.Lock(FHandle,lck) THEN
  2393. Abort('Lock failure');
  2394. RETURN NIL;
  2395. END;
  2396. FIOx.Read(FHandle,fwr^.HeaderSize,SIZE(fwr^.HeaderSize));
  2397. IF NOT Buffered THEN
  2398. FIOx.UnLock(FHandle,lck);
  2399. END;
  2400. IF FIOx.Error()#FIOx.PAST_EOF THEN
  2401. IOabort('Open');
  2402. END;
  2403. IF (FIOx.Error()=FIOx.PAST_EOF) OR (h#fwr^.HeaderSize) THEN
  2404. Abort('HeaderSize');
  2405. RETURN NIL;
  2406. END;
  2407. lck.pos := 0;
  2408. lck.len := VAL(LONGCARD,fwr^.HeaderSize);
  2409. IF NOT Buffered AND NOT FIOx.Lock(FHandle,lck) THEN
  2410. Abort('Lock failure(2)');
  2411. END;
  2412. FIOx.Read(FHandle,fwr^.FileSize,fwr^.HeaderSize-SIZE(fwr^.HeaderSize));
  2413. IF NOT Buffered THEN
  2414. FIOx.UnLock(FHandle,lck);
  2415. END;
  2416. IF FIOx.Error()#FIOx.PAST_EOF THEN
  2417. IOabort('Open');
  2418. END;
  2419. IF FIOx.Error()=FIOx.PAST_EOF THEN
  2420. Abort('I/O Error');
  2421. RETURN NIL;
  2422. ELSIF (fwr^.Version DIV 10) # (ThisVersion DIV 10) THEN
  2423. Abort('Version'); (* The version number's ones digit isn't tested! *)
  2424. RETURN NIL;
  2425. ELSIF fwr^.Mode#AMode THEN
  2426. Abort('Accessmode');
  2427. RETURN NIL;
  2428. ELSIF fwr^.IndexCount#MaxIHandle THEN
  2429. Abort('MaxIHandle');
  2430. RETURN NIL;
  2431. ELSIF fwr^.PageSz#PageSize THEN
  2432. Abort('PageSize');
  2433. RETURN NIL;
  2434. ELSIF fwr^.MaxKeySz#MaxKeySize THEN
  2435. Abort('MaxKeySize');
  2436. RETURN NIL;
  2437. END;
  2438. END;
  2439. IF AMode=Size32 THEN
  2440. OpenIx(iH,CompareFunction(SizeCmp4),4,TRUE,Create);
  2441. ELSE
  2442. OpenIx(iH,CompareFunction(SizeCmp2),2,TRUE,Create);
  2443. END;
  2444. IF iH=Null THEN
  2445. Abort('Unknown error');
  2446. RETURN NIL;
  2447. END;
  2448. END;
  2449. iH.ID^.G1 := GuardV1;
  2450. iH.ID^.G2 := GuardV2;
  2451. ClearFErr(iH.ID);
  2452. RETURN iH.ID;
  2453. END Open;
  2454. PROCEDURE OpenIndex(F: FHandle; D: IHandle; I: CARDINAL;
  2455. CmpFct: CompareFunction; KeFct: KeyFunction;
  2456. KeSize: CARDINAL; DpKey,New: BOOLEAN): IHandle;
  2457. VAR
  2458. iH : IHandle;
  2459. idx : CARDINAL;
  2460. BEGIN
  2461. ClearFErr(F);
  2462. IF NOT IsFHandle(F) THEN
  2463. CallFErr(F,NotFHandle,'OpenIndex');
  2464. RETURN Null;
  2465. END;
  2466. IF (D#Null) AND NOT IsData(D) THEN
  2467. CallFErr(F,NotData,'OpenIndex');
  2468. RETURN Null;
  2469. END;
  2470. IF New AND NOT F^.Buffered THEN
  2471. CallFErr(F,BadOpen,'New with Sharing');
  2472. RETURN Null;
  2473. END;
  2474. IF (F^.fwr^.IndexCount<I) OR ((F^.Id[I].iwr^.Ft#FreeSlot)=New) THEN
  2475. CallFErr(F,NoSlot,'Index');
  2476. RETURN Null;
  2477. END;
  2478. IF New AND F^.ReadOnly THEN
  2479. CallFErr(F,BadOpen,'New with ReadOnly');
  2480. RETURN Null;
  2481. END;
  2482. iH.ID := F;
  2483. iH.In := I;
  2484. OpenIx(iH,CmpFct,KeSize,DpKey,New);
  2485. IF iH#Null THEN
  2486. WITH iH.ID^.Id[I] DO
  2487. IF (KeFct#NULLPROC) AND (D#Null) THEN
  2488. KeyFct := KeFct;
  2489. NextIndx := D.ID^.Id[D.In].NextIndx;
  2490. D.ID^.Id[D.In].NextIndx := iH;
  2491. DataPtr := D;
  2492. END;
  2493. END;
  2494. END;
  2495. RETURN iH;
  2496. END OpenIndex;
  2497. PROCEDURE OpenData(F: FHandle; I,RSize: CARDINAL; New: BOOLEAN): IHandle;
  2498. VAR
  2499. dH : IHandle;
  2500. BEGIN
  2501. ClearFErr(F);
  2502. IF NOT IsFHandle(F) THEN
  2503. CallFErr(F,NotFHandle,'OpenData');
  2504. RETURN Null;
  2505. END;
  2506. IF New AND NOT F^.Buffered THEN
  2507. CallFErr(F,BadOpen,'New with Sharing');
  2508. RETURN Null;
  2509. END;
  2510. IF (F^.fwr^.IndexCount<I) OR ((F^.Id[I].iwr^.Ft#FreeSlot)=New) THEN
  2511. CallFErr(F,NoSlot,'Data');
  2512. RETURN Null;
  2513. END;
  2514. IF (RSize=0) AND (F^.fwr^.Mode=FixSize) THEN
  2515. CallFErr(F,BadOpen,'OpenData');
  2516. RETURN Null;
  2517. END;
  2518. IF New AND F^.ReadOnly THEN
  2519. CallFErr(F,BadOpen,'New with ReadOnly');
  2520. END;
  2521. dH.ID := F;
  2522. dH.In := I;
  2523. WITH dH.ID^.Id[dH.In] DO
  2524. LastDataRef := Nil;
  2525. NextIndx := Null;
  2526. LastErr := OK;
  2527. ErrorNest := 0;
  2528. Sync := FALSE;
  2529. bufSize := RSize;
  2530. IF RSize=0 THEN
  2531. bufPtr := NIL;
  2532. ELSE
  2533. AllocMem(bufPtr,RSize);
  2534. Die(bufPtr=NIL,OutOfMemory);
  2535. END;
  2536. IF New THEN
  2537. iwr^.Ft := DataSlot;
  2538. iwr^.RecordSize := RSize;
  2539. iwr^.RecordCnt := 0;
  2540. UpdateSlot(dH);
  2541. ELSE
  2542. IF iwr^.Ft # DataSlot THEN
  2543. CallFErr(F,NotData,'OpenData');
  2544. RETURN Null;
  2545. ELSIF iwr^.RecordSize # RSize THEN
  2546. CallFErr(F,BadSize,'OpenData');
  2547. RETURN Null;
  2548. END;
  2549. END;
  2550. Ft := DataSlot;
  2551. END;
  2552. RETURN dH;
  2553. END OpenData;
  2554. PROCEDURE FreeIHandle(VAR H: IHandle);
  2555. VAR
  2556. dH : IHandle;
  2557. iH : IHandle;
  2558. BEGIN
  2559. ClearErr(H);
  2560. ClearFErr(H.ID);
  2561. IF NOT IsIHandle(H) THEN
  2562. CallFErr(H.ID,NotIHandle,'FreeIHandle');
  2563. RETURN;
  2564. END;
  2565. IF NOT H.ID^.Buffered AND IsIndex(H) AND (H.ID^.Id[H.In].DataPtr#Null) THEN
  2566. CallErr(H,BadFree,'FreeIHandle');
  2567. RETURN;
  2568. END;
  2569. IF IsData(H) THEN
  2570. dH := H.ID^.Id[H.In].NextIndx;
  2571. WHILE dH # Null DO
  2572. iH := dH;
  2573. FollowNextIndx(dH);
  2574. iH.ID^.Id[iH.In].NextIndx := Null;
  2575. iH.ID^.Id[iH.In].DataPtr := Null;
  2576. FreeIHandle(iH);
  2577. END;
  2578. ELSE
  2579. dH := H.ID^.Id[H.In].DataPtr;
  2580. LOOP
  2581. IF dH.ID=NIL THEN
  2582. EXIT;
  2583. END;
  2584. iH := dH.ID^.Id[dH.In].NextIndx;
  2585. IF iH=H THEN
  2586. dH.ID^.Id[dH.In].NextIndx := iH.ID^.Id[iH.In].NextIndx;
  2587. EXIT;
  2588. END;
  2589. FollowNextIndx(dH);
  2590. END;
  2591. END;
  2592. WITH H.ID^.Id[H.In] DO
  2593. CASE Ft OF
  2594. IndexSlot : FreeMem(PageRefs);
  2595. SaveBuffers(H);
  2596. ClearBuffers(H);
  2597. | DataSlot : FreeMem(bufPtr);
  2598. ELSE
  2599. (* ignore *)
  2600. END;
  2601. Ft := FreeSlot;
  2602. DataPtr := Null;
  2603. END;
  2604. H := Null;
  2605. END FreeIHandle;
  2606. PROCEDURE ClearIndex(VAR I: IHandle);
  2607. VAR
  2608. TP : TPage;
  2609. TYPE
  2610. IPtr = POINTER Seg(TP) TO IndexItem;
  2611. A2 = ARRAY[0..1] OF SHORTCARD;
  2612. (*# save *)
  2613. (*# call(inline=>on) *)
  2614. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  2615. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  2616. (*# restore *)
  2617. PROCEDURE Free(Page: LONGCARD; Level: CARDINAL);
  2618. VAR
  2619. i : CARDINAL;
  2620. IP : IPtr;
  2621. BEGIN
  2622. WITH I.ID^.Id[I.In] DO
  2623. IF Level=iwr^.Depth THEN
  2624. ClearPage(I,Page);
  2625. FreeBlock(I.ID,PageSize,Page);
  2626. ELSE
  2627. i := 0;
  2628. IP := IPtr(Ofs((TP.IItem)));
  2629. LOOP
  2630. ReadPage(I,Page,TP);
  2631. IF i>TP.ICount THEN
  2632. EXIT;
  2633. END;
  2634. Free(IP^.IP,Level+1);
  2635. INC(i);
  2636. IncAddr(IP,8+iwr^.KeySize);
  2637. END;
  2638. ClearPage(I,Page);
  2639. FreeBlock(I.ID,PageSize,Page);
  2640. END;
  2641. END;
  2642. END Free;
  2643. BEGIN
  2644. ClearErr(I);
  2645. ClearFErr(I.ID);
  2646. IF NOT IsIndex(I) THEN
  2647. CallErr(I,NotIndex,'ClearIndex');
  2648. RETURN;
  2649. END;
  2650. IF NOT I.ID^.Buffered THEN
  2651. CallErr(I,BadFree,'ClearIndex');
  2652. RETURN;
  2653. END;
  2654. IF I.ID^.ReadOnly THEN
  2655. CallErr(I,BadWrite,'ClearIndex with ReadOnly');
  2656. END;
  2657. Free(I.ID^.Id[I.In].iwr^.TopPage,1);
  2658. FreeIHandle(I);
  2659. END ClearIndex;
  2660. PROCEDURE Close(VAR F: FHandle);
  2661. VAR
  2662. idx : CARDINAL;
  2663. iH : IHandle;
  2664. BEGIN
  2665. ClearFErr(F);
  2666. IF NOT IsFHandle(F) THEN
  2667. CallFErr(F,NotFHandle,'Close');
  2668. RETURN;
  2669. END;
  2670. iH.ID := F;
  2671. iH.In := MAX(CARDINAL);
  2672. SaveBuffers(iH);
  2673. ClearBuffers(iH);
  2674. Flush(F);
  2675. iH.In := 0;
  2676. WITH F^ DO
  2677. IF NOT Buffered THEN
  2678. FOR idx := 0 TO LockQSize-1 DO
  2679. IF Locks[idx].Position#Nil THEN
  2680. ccUnLock(iH,Locks[idx],AllLocks);
  2681. END;
  2682. END;
  2683. END;
  2684. FOR idx := 0 TO F^.fwr^.IndexCount DO
  2685. WITH Id[idx] DO
  2686. IF NOT Buffered AND ((ihLock.ICnt#0) OR (ihLock.ECnt#0)) THEN
  2687. ccUnLock(iH,ihLock,AllLocks);
  2688. END;
  2689. CASE Ft OF
  2690. IndexSlot : FreeMem(PageRefs);
  2691. | DataSlot : FreeMem(bufPtr);
  2692. ELSE
  2693. (* ignore *)
  2694. END;
  2695. END;
  2696. END;
  2697. IF NOT Buffered AND ((fhLock.ICnt#0) OR (fhLock.ECnt#0)) THEN
  2698. ccUnLock(iH,fhLock,AllLocks);
  2699. END;
  2700. FIOx.Close(FHandle);
  2701. END;
  2702. F^.G1 := 0;
  2703. F^.G2 := 0;
  2704. FreeMem(F);
  2705. END Close;
  2706. PROCEDURE Allocate(F: FHandle; Length: LONGCARD): LONGCARD;
  2707. VAR
  2708. Pos : LONGCARD;
  2709. iH : IHandle;
  2710. ok : BOOLEAN;
  2711. BEGIN
  2712. ClearFErr(F);
  2713. IF NOT IsFHandle(F) THEN
  2714. CallFErr(F,NotFHandle,'Allocate');
  2715. RETURN MAX(LONGCARD);
  2716. END;
  2717. IF F^.ReadOnly THEN
  2718. CallFErr(F,BadWrite,'Allocate with ReadOnly');
  2719. RETURN MAX(LONGCARD);
  2720. END;
  2721. IF LockFile(F) THEN
  2722. Pos := AllocateBlock(F,Length+4);
  2723. IF Pos=Nil THEN
  2724. CallFErr(F,FileError,'Allocate');
  2725. RETURN Nil;
  2726. END;
  2727. FIOx.Seek(F^.FHandle,Pos);
  2728. IOabort('Allocate');
  2729. FIOx.Write(F^.FHandle,Length+4,4);
  2730. IOabort('Allocate');
  2731. iH.ID := F;
  2732. iH.In := 0;
  2733. ok := cLock(iH,Pos+4,Explicit);
  2734. UnLockFile(F);
  2735. RETURN Pos+4;
  2736. ELSE
  2737. RETURN MAX(LONGCARD);
  2738. END;
  2739. END Allocate;
  2740. PROCEDURE DeAllocate(F: FHandle; Position: LONGCARD);
  2741. VAR
  2742. Len : LONGCARD;
  2743. r : CARDINAL;
  2744. iH : IHandle;
  2745. BEGIN
  2746. ClearFErr(F);
  2747. IF NOT IsFHandle(F) THEN
  2748. CallFErr(F,NotFHandle,'DeAllocate');
  2749. RETURN;
  2750. END;
  2751. IF F^.ReadOnly THEN
  2752. CallFErr(F,BadWrite,'DeAllocate with ReadOnly');
  2753. RETURN;
  2754. END;
  2755. iH.ID := F;
  2756. iH.In := 0;
  2757. IF NOT cLocked(iH,Position) THEN
  2758. CallFErr(F,NotLocked,'Write');
  2759. END;
  2760. SetFErr(F,OK);
  2761. IF LockFile(F) THEN
  2762. FIOx.Seek(F^.FHandle,Position-4);
  2763. IOabort('DeAllocate');
  2764. FIOx.Read(F^.FHandle,Len,4);
  2765. IOabort('DeAllocate');
  2766. FreeBlock(F,Len,Position-4);
  2767. cUnLock(iH,Position,AllLocks);
  2768. UnLockFile(F);
  2769. END;
  2770. END DeAllocate;
  2771. PROCEDURE Read(F: FHandle; Position: LONGCARD; Length: CARDINAL;
  2772. VAR Data: ARRAY OF BYTE);
  2773. VAR
  2774. iH : IHandle;
  2775. BEGIN
  2776. ClearFErr(F);
  2777. IF NOT IsFHandle(F) THEN
  2778. CallFErr(F,NotFHandle,'Read');
  2779. RETURN;
  2780. END;
  2781. iH.ID := F;
  2782. iH.In := 0;
  2783. IF NOT cLocked(iH,Position) THEN
  2784. CallFErr(F,NotLocked,'Read');
  2785. END;
  2786. SetFErr(F,OK);
  2787. FIOx.Seek(F^.FHandle,Position);
  2788. IOabort('Read');
  2789. FIOx.Read(F^.FHandle,Data,Length);
  2790. IOabort('Read');
  2791. END Read;
  2792. PROCEDURE Write(F: FHandle; Position: LONGCARD; Length: CARDINAL;
  2793. Data: ARRAY OF BYTE);
  2794. VAR
  2795. iH : IHandle;
  2796. BEGIN
  2797. ClearFErr(F);
  2798. IF NOT IsFHandle(F) THEN
  2799. CallFErr(F,NotFHandle,'Write');
  2800. RETURN;
  2801. END;
  2802. IF F^.ReadOnly THEN
  2803. CallFErr(F,BadWrite,'Write with ReadOnly');
  2804. RETURN;
  2805. END;
  2806. iH.ID := F;
  2807. iH.In := 0;
  2808. IF NOT cLocked(iH,Position) THEN
  2809. CallFErr(F,NotLocked,'Write');
  2810. END;
  2811. FIOx.Seek(F^.FHandle,Position);
  2812. IOabort('Write');
  2813. FIOx.Write(F^.FHandle,Data,Length);
  2814. IOabort('Write');
  2815. END Write;
  2816. PROCEDURE Flush(F: FHandle);
  2817. VAR
  2818. idx : CARDINAL;
  2819. iH : IHandle;
  2820. BEGIN
  2821. ClearFErr(F);
  2822. IF NOT IsFHandle(F) THEN
  2823. CallFErr(F,NotFHandle,'Flush');
  2824. RETURN;
  2825. END;
  2826. iH.ID := F;
  2827. IF F^.Buffered THEN
  2828. FOR idx := 0 TO F^.fwr^.IndexCount DO
  2829. iH.In := idx;
  2830. FlushIHandle(iH);
  2831. END;
  2832. FlushFHandle(F);
  2833. ELSE
  2834. FOR idx := 0 TO F^.fwr^.IndexCount DO
  2835. WITH F^.Id[idx] DO
  2836. IF (Ft#FreeSlot) AND ((ihLock.ECnt#0) OR (ihLock.ICnt#0)) THEN
  2837. iH.In := idx;
  2838. FlushIHandle(iH);
  2839. END;
  2840. END;
  2841. END;
  2842. IF (F^.fhLock.ECnt#0) OR (F^.fhLock.ICnt#0) THEN
  2843. FlushFHandle(F);
  2844. END;
  2845. END;
  2846. FIOx.Flush(F^.FHandle);
  2847. END Flush;
  2848. PROCEDURE AddIndex(I: IHandle; Key: ARRAY OF BYTE; DataLoc: LONGCARD);
  2849. VAR
  2850. TP : xTPage;
  2851. TYPE
  2852. IPtr = POINTER Seg(TP) TO IndexItem;
  2853. A2 = ARRAY[0..1] OF SHORTCARD;
  2854. (*# save *)
  2855. (*# call(inline=>on) *)
  2856. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  2857. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  2858. (*# restore *)
  2859. VAR
  2860. InsKey : IndexItem;
  2861. C : CmpRes;
  2862. r,
  2863. Level : CARDINAL;
  2864. b : BOOLEAN;
  2865. ItemSize : CARDINAL;
  2866. Index : CARDINAL;
  2867. Page,
  2868. PageTmp : LONGCARD;
  2869. IP,
  2870. NP,
  2871. XP : IPtr;
  2872. BEGIN
  2873. ClearErr(I);
  2874. IF NOT IsIndex(I) THEN
  2875. CallErr(I,NotIndex,'AddIndex');
  2876. RETURN;
  2877. END;
  2878. IF I.ID^.ReadOnly THEN
  2879. CallErr(I,BadWrite,'AddIndex with ReadOnly');
  2880. RETURN;
  2881. END;
  2882. IF LockFile(I.ID) THEN
  2883. IF cLockIHandle(I,Implicit) THEN
  2884. WITH I.ID^.Id[I.In] DO
  2885. ItemSize := 8+iwr^.KeySize;
  2886. InsKey.IP := Nil;
  2887. InsKey.DP := DataLoc;
  2888. MemFastMove(ADR(Key),ADR(InsKey.Key),iwr^.KeySize);
  2889. b := FindIx(I,InsKey.Key,DataLoc,Ins);
  2890. IF LastError(I)=OK THEN
  2891. Level := PageLevel;
  2892. Index := PageRefs^.Refs[Level].Rec;
  2893. Page := PageRefs^.Refs[Level].Page;
  2894. ReadPage(I,Page,TPage(TP));
  2895. IF TP.ICount=iwr^.N2 THEN
  2896. FIOx.Truncate(I.ID^.FHandle,I.ID^.fwr^.FileSize+VAL(LONGCARD,PageRefs^.Refs[PageLevel].Cnt)*PageSize);
  2897. IF FIOx.Error()#FIOx.NO_ERROR THEN
  2898. FIOx.Truncate(I.ID^.FHandle,I.ID^.fwr^.FileSize);
  2899. IOabort('AddIndex');
  2900. cUnLockIHandle(I,Implicit);
  2901. UnLockFile(I.ID);
  2902. CallErr(I,FileError,'AddIndex');
  2903. RETURN;
  2904. END;
  2905. IOabort('AddIndex');
  2906. END;
  2907. LOOP
  2908. IP := AddIPtr(IPtr(Ofs((TP.IItem))),Index*ItemSize);
  2909. XP := AddIPtr(IP,ItemSize);
  2910. INC(TP.ICount);
  2911. MemMove(ADR(IP^),ADR(XP^),ItemSize*(TP.ICount-(Index+1))+4);
  2912. MemFastMove(ADR(InsKey),ADR(IP^),ItemSize);
  2913. IF TP.ICount<=iwr^.N2 THEN
  2914. EXIT;
  2915. ELSE
  2916. NP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize*iwr^.N22);
  2917. MemFastMove(ADR(NP^),ADR(InsKey),ItemSize);
  2918. TP.ICount := iwr^.N22;
  2919. IncAddr(NP,ItemSize);
  2920. IF I.In=0 THEN
  2921. InsKey.IP := AllocateFreeBlock(I.ID);
  2922. ELSE
  2923. InsKey.IP := AllocateBlock(I.ID,PageSize);
  2924. END;
  2925. WritePage(I,InsKey.IP,TPage(TP));
  2926. MemFastMove(ADR(NP^),ADR(TP.IItem),ItemSize*iwr^.N22+4);
  2927. WritePage(I,Page,TPage(TP));
  2928. DEC(Level);
  2929. IF Level=0 THEN
  2930. TP.ICount := 1;
  2931. MemFastMove(ADR(InsKey),ADR(TP.IItem),ItemSize);
  2932. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize);
  2933. IP^.IP := iwr^.TopPage;
  2934. IF I.In=0 THEN
  2935. iwr^.TopPage := AllocateFreeBlock(I.ID);
  2936. ELSE
  2937. iwr^.TopPage := AllocateBlock(I.ID,PageSize);
  2938. END;
  2939. Page := iwr^.TopPage;
  2940. INC(iwr^.Depth);
  2941. IF iwr^.Depth>PageRefs^.Height THEN
  2942. FreeMem(PageRefs);
  2943. r := iwr^.Depth+1;
  2944. AllocMem(PageRefs,VSIZE(PageRef.Height)+r*SIZE(PageRefRec));
  2945. Die(PageRefs=NIL,OutOfMemory);
  2946. PageRefs^.Height := r;
  2947. END;
  2948. EXIT;
  2949. END;
  2950. END;
  2951. Index := PageRefs^.Refs[Level].Rec;
  2952. Page := PageRefs^.Refs[Level].Page;
  2953. ReadPage(I,Page,TPage(TP));
  2954. END;
  2955. WritePage(I,Page,TPage(TP));
  2956. PageLevel := 0;
  2957. END;
  2958. IF LastError(I)=OK THEN
  2959. INC(iwr^.RecordCnt);
  2960. END;
  2961. END;
  2962. cUnLockIHandle(I,Implicit);
  2963. END;
  2964. FIOx.Truncate(I.ID^.FHandle,I.ID^.fwr^.FileSize);
  2965. UnLockFile(I.ID);
  2966. ELSE
  2967. SetErr(I,Locked);
  2968. END;
  2969. END AddIndex;
  2970. PROCEDURE DeleteIndex(I: IHandle; Key: ARRAY OF BYTE; DataLoc: LONGCARD);
  2971. VAR
  2972. TP : TPage;
  2973. TYPE
  2974. IPtr = POINTER Seg(TP) TO IndexItem;
  2975. A2 = ARRAY[0..1] OF SHORTCARD;
  2976. (*# save *)
  2977. (*# call(inline=>on) *)
  2978. (*# call(reg_param=>(ax,cx),reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2,st3,st4,st5,st6)) *)
  2979. PROCEDURE AddIPtr(A: IPtr; I: CARDINAL): IPtr=A2(003H,0C1H);(*add ax,cx*)
  2980. (*# restore *)
  2981. VAR
  2982. QP,
  2983. RP : TPage;
  2984. DelKey : IndexItem;
  2985. Level : CARDINAL;
  2986. ItemSize : CARDINAL;
  2987. Page,
  2988. RPage : LONGCARD;
  2989. IP,
  2990. JP,
  2991. NP : IPtr;
  2992. (* 07/23/90 DWD - This procedure has not yet been optimized
  2993. by using MemFastMove() *)
  2994. BEGIN
  2995. ClearErr(I);
  2996. IF NOT IsIndex(I) THEN
  2997. CallErr(I,NotIndex,'DeleteIndex');
  2998. RETURN;
  2999. END;
  3000. IF I.ID^.ReadOnly THEN
  3001. CallErr(I,BadWrite,'DeleteIndex with ReadOnly');
  3002. RETURN;
  3003. END;
  3004. IF LockFile(I.ID) THEN
  3005. IF cLockIHandle(I,Implicit) THEN
  3006. WITH I.ID^.Id[I.In] DO
  3007. LOOP
  3008. ItemSize := 8+iwr^.KeySize;
  3009. DelKey.DP := DataLoc;
  3010. MemFastMove(ADR(Key),ADR(DelKey.Key),iwr^.KeySize);
  3011. IF NOT FindIx(I,DelKey.Key,DataLoc,Idx) THEN
  3012. CallErr(I,BadIndex,'DelIndex');
  3013. EXIT;
  3014. END;
  3015. Level := PageLevel;
  3016. Page := PageRefs^.Refs[PageLevel].Page;
  3017. ReadPage(I,Page,TP);
  3018. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize*PageRefs^.Refs[PageLevel].Rec);
  3019. IF PageLevel#iwr^.Depth THEN
  3020. INC(Level);
  3021. NP := IP;
  3022. IncAddr(NP,ItemSize);
  3023. INC(PageRefs^.Refs[PageLevel].Rec);
  3024. Page := NP^.IP;
  3025. LOOP
  3026. ReadPage(I,Page,QP);
  3027. PageRefs^.Refs[Level].Rec := 0;
  3028. PageRefs^.Refs[Level].Page := Page;
  3029. IF Level=iwr^.Depth THEN
  3030. EXIT;
  3031. END;
  3032. Page := QP.IItem.IP;
  3033. INC(Level);
  3034. END;
  3035. MemFastMove(ADR(QP.IItem.DP),ADR(IP^.DP),iwr^.KeySize+4);
  3036. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3037. TP:=QP;
  3038. PageLevel := iwr^.Depth;
  3039. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize*PageRefs^.Refs[PageLevel].Rec)
  3040. END;
  3041. NP := IP;
  3042. IncAddr(NP,ItemSize);
  3043. DEC(TP.ICount);
  3044. MemFastMove(ADR(NP^),ADR(IP^),ItemSize*(TP.ICount-PageRefs^.Refs[PageLevel].Rec));
  3045. WHILE (TP.ICount<iwr^.N22) AND (PageLevel#1) DO
  3046. IF PageRefs^.Refs[PageLevel-1].Rec=0 THEN
  3047. (* Has got a right sibling *)
  3048. ReadPage(I,PageRefs^.Refs[PageLevel-1].Page,QP);
  3049. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize*TP.ICount);
  3050. JP := AddIPtr(IPtr(Ofs((QP.IItem))),ItemSize*(PageRefs^.Refs[PageLevel-1].Rec+1));
  3051. RPage := JP^.IP;
  3052. DecAddr(JP,ItemSize);
  3053. ReadPage(I,RPage,RP);
  3054. MemFastMove(ADR(JP^.DP),ADR(IP^.DP),iwr^.KeySize+4);
  3055. INC(TP.ICount);
  3056. IF RP.ICount>iwr^.N22 THEN
  3057. IncAddr(IP,ItemSize);
  3058. IP^.IP := RP.IItem.IP;
  3059. MemFastMove(ADR(RP.IItem.DP),ADR(JP^.DP),iwr^.KeySize+4);
  3060. DEC(RP.ICount);
  3061. IP := AddIPtr(IPtr(Ofs((RP.IItem))),ItemSize);
  3062. MemFastMove(ADR(IP^),ADR(RP.IItem),ItemSize*RP.ICount+4);
  3063. WritePage(I,RPage,RP);
  3064. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3065. WritePage(I,PageRefs^.Refs[PageLevel-1].Page,QP);
  3066. PageLevel :=0;
  3067. EXIT;
  3068. END;
  3069. IncAddr(IP,ItemSize);
  3070. MemFastMove(ADR(RP.IItem),ADR(IP^),ItemSize*iwr^.N22+4);
  3071. TP.ICount := iwr^.N2;
  3072. IP := JP;
  3073. IncAddr(IP,ItemSize);
  3074. DEC(QP.ICount);
  3075. MemFastMove(ADR(IP^.DP),ADR(JP^.DP),ItemSize*(QP.ICount-PageRefs^.Refs[PageLevel-1].Rec));
  3076. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3077. ClearPage(I,RPage);
  3078. IF I.In=0 THEN
  3079. FreeFreeBlock(I.ID,RPage);
  3080. ELSE
  3081. FreeBlock(I.ID,PageSize,RPage);
  3082. END;
  3083. DEC(PageLevel);
  3084. TP := QP;
  3085. ELSE
  3086. (* Has got a left sibling *)
  3087. ReadPage(I,PageRefs^.Refs[PageLevel-1].Page,QP);
  3088. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize);
  3089. MemMove(ADR(TP.IItem),ADR(IP^),ItemSize*TP.ICount+4);
  3090. JP := AddIPtr(IPtr(Ofs((QP.IItem))),ItemSize*(PageRefs^.Refs[PageLevel-1].Rec-1));
  3091. RPage := JP^.IP;
  3092. ReadPage(I,RPage,RP);
  3093. MemFastMove(ADR(JP^.DP),ADR(TP.IItem.DP),iwr^.KeySize+4);
  3094. INC(TP.ICount);
  3095. IF RP.ICount>iwr^.N22 THEN
  3096. NP := AddIPtr(IPtr(Ofs((RP.IItem))),ItemSize*RP.ICount);
  3097. TP.IItem.IP:= NP^.IP;
  3098. DecAddr(NP,ItemSize);
  3099. MemFastMove(ADR(NP^.DP),ADR(JP^.DP),iwr^.KeySize+4);
  3100. DEC(RP.ICount);
  3101. WritePage(I,RPage,RP);
  3102. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3103. WritePage(I,PageRefs^.Refs[PageLevel-1].Page,QP);
  3104. PageLevel := 0;
  3105. EXIT;
  3106. END;
  3107. IP := AddIPtr(IPtr(Ofs((TP.IItem))),ItemSize*iwr^.N22);
  3108. MemFastMove(ADR(TP.IItem.DP),ADR(IP^.DP),ItemSize*iwr^.N22);
  3109. MemFastMove(ADR(RP.IItem),ADR(TP.IItem),ItemSize*iwr^.N22+4);
  3110. TP.ICount := iwr^.N2;
  3111. IP := JP;
  3112. IncAddr(IP,ItemSize);
  3113. MemFastMove(ADR(IP^),ADR(JP^),ItemSize*(QP.ICount-PageRefs^.Refs[PageLevel-1].Rec)+4);
  3114. DEC(QP.ICount);
  3115. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3116. ClearPage(I,RPage);
  3117. IF I.In=0 THEN
  3118. FreeFreeBlock(I.ID,RPage);
  3119. ELSE
  3120. FreeBlock(I.ID,PageSize,RPage);
  3121. END;
  3122. DEC(PageLevel);
  3123. TP := QP;
  3124. END;
  3125. END;
  3126. IF (TP.ICount=0) AND (iwr^.Depth>1) THEN
  3127. DEC(iwr^.Depth);
  3128. iwr^.TopPage := TP.IItem.IP;
  3129. ELSE
  3130. WritePage(I,PageRefs^.Refs[PageLevel].Page,TP);
  3131. END;
  3132. PageLevel :=0;
  3133. EXIT;
  3134. END;
  3135. IF LastError(I)=OK THEN
  3136. DEC(iwr^.RecordCnt);
  3137. END;
  3138. END;
  3139. cUnLockIHandle(I,Implicit);
  3140. END;
  3141. UnLockFile(I.ID);
  3142. ELSE
  3143. SetErr(I,Locked);
  3144. END;
  3145. END DeleteIndex;
  3146. PROCEDURE FindIndex(I: IHandle; Key: ARRAY OF BYTE;
  3147. VAR DataLoc: LONGCARD): BOOLEAN;
  3148. VAR
  3149. res : BOOLEAN;
  3150. BEGIN
  3151. ClearErr(I);
  3152. IF NOT IsIndex(I) THEN
  3153. CallErr(I,NotIndex,'FindIndex');
  3154. RETURN FALSE;
  3155. END;
  3156. Release(I);
  3157. IF cLockIHandle(I,Implicit) THEN
  3158. IF FindIx(I,Key,Nil,Fnd) THEN
  3159. DataLoc := I.ID^.Id[I.In].LastDataRef;
  3160. res := TRUE;
  3161. ELSE
  3162. res := FALSE;
  3163. END;
  3164. I.ID^.Id[I.In].LastKeyOK := FALSE;
  3165. cUnLockIHandle(I,Implicit);
  3166. RETURN res;
  3167. ELSE
  3168. RETURN FALSE;
  3169. END;
  3170. END FindIndex;
  3171. PROCEDURE SearchIndex(I: IHandle; Key: ARRAY OF BYTE;
  3172. VAR DataLoc: LONGCARD): BOOLEAN;
  3173. VAR
  3174. res : BOOLEAN;
  3175. BEGIN
  3176. ClearErr(I);
  3177. IF NOT IsIndex(I) THEN
  3178. CallErr(I,NotIndex,'SearchIndex');
  3179. RETURN FALSE;
  3180. END;
  3181. Release(I);
  3182. IF cLockIHandle(I,Implicit) THEN
  3183. IF FindIx(I,Key,Nil,Src) THEN
  3184. DataLoc := I.ID^.Id[I.In].LastDataRef;
  3185. res := TRUE;
  3186. ELSE
  3187. res := FALSE;
  3188. END;
  3189. I.ID^.Id[I.In].LastKeyOK := FALSE;
  3190. cUnLockIHandle(I,Implicit);
  3191. RETURN res;
  3192. ELSE
  3193. RETURN FALSE;
  3194. END;
  3195. END SearchIndex;
  3196. PROCEDURE Recover(iH: IHandle) : BOOLEAN;
  3197. BEGIN
  3198. WITH iH.ID^ DO
  3199. WITH Id[iH.In] DO
  3200. IF (PageLevel=0) AND LastKeyOK THEN
  3201. RETURN FindIx(iH,LastKey,LastKeyRef,Rec);
  3202. ELSIF PageLevel#0 THEN
  3203. SetLastKey(iH);
  3204. END;
  3205. END;
  3206. END;
  3207. RETURN TRUE;
  3208. END Recover;
  3209. PROCEDURE NextIndex(I: IHandle; VAR DataLoc: LONGCARD): BOOLEAN;
  3210. VAR
  3211. res : BOOLEAN;
  3212. BEGIN
  3213. ClearErr(I);
  3214. IF NOT IsIndex(I) THEN
  3215. CallErr(I,NotIndex,'NextIndex');
  3216. RETURN FALSE;
  3217. END;
  3218. Release(I);
  3219. IF cLockIHandle(I,Implicit) THEN
  3220. WITH I.ID^.Id[I.In] DO
  3221. IF Recover(I) THEN
  3222. WalkIx(I,Forward);
  3223. END;
  3224. res := PageLevel#0;
  3225. cUnLockIHandle(I,Implicit);
  3226. IF res THEN
  3227. DataLoc := LastDataRef;
  3228. END;
  3229. RETURN res;
  3230. END;
  3231. ELSE
  3232. RETURN FALSE;
  3233. END;
  3234. END NextIndex;
  3235. PROCEDURE PrevIndex(I: IHandle; VAR DataLoc: LONGCARD): BOOLEAN;
  3236. VAR
  3237. res : BOOLEAN;
  3238. BEGIN
  3239. ClearErr(I);
  3240. IF NOT IsIndex(I) THEN
  3241. CallErr(I,NotIndex,'PrevIndex');
  3242. RETURN FALSE;
  3243. END;
  3244. Release(I);
  3245. IF cLockIHandle(I,Implicit) THEN
  3246. res := Recover(I);
  3247. WITH I.ID^.Id[I.In] DO
  3248. WalkIx(I,Backward);
  3249. res := PageLevel#0;
  3250. cUnLockIHandle(I,Implicit);
  3251. IF res THEN
  3252. DataLoc := LastDataRef;
  3253. END;
  3254. RETURN res;
  3255. END;
  3256. ELSE
  3257. RETURN FALSE;
  3258. END;
  3259. END PrevIndex;
  3260. PROCEDURE SetSyncMode(D: IHandle; On: BOOLEAN);
  3261. BEGIN
  3262. ClearErr(D);
  3263. IF NOT IsData(D) THEN
  3264. CallErr(D,NotData,'SetSyncMode');
  3265. RETURN;
  3266. END;
  3267. D.ID^.Id[D.In].Sync := On;
  3268. Reset(D);
  3269. END SetSyncMode;
  3270. PROCEDURE LastError(H: IHandle): Errors;
  3271. BEGIN
  3272. IF NOT IsFHandle(H.ID) THEN
  3273. RETURN NotFHandle;
  3274. ELSIF NOT IsIHandle(H) THEN
  3275. RETURN NotIHandle;
  3276. ELSE
  3277. RETURN H.ID^.Id[H.In].LastErr;
  3278. END;
  3279. END LastError;
  3280. PROCEDURE LastFError(F: FHandle): Errors;
  3281. VAR
  3282. iH : IHandle;
  3283. BEGIN
  3284. iH.ID := F;
  3285. iH.In := 0;
  3286. RETURN LastError(iH);
  3287. END LastFError;
  3288. PROCEDURE LastRef(I : IHandle) : LONGCARD;
  3289. BEGIN
  3290. IF NOT IsIHandle(I) THEN
  3291. CallErr(I,NotIHandle,'LastRef');
  3292. RETURN Nil;
  3293. END;
  3294. RETURN I.ID^.Id[I.In].LastDataRef;
  3295. END LastRef;
  3296. PROCEDURE RecordCount(I: IHandle): LONGCARD;
  3297. BEGIN
  3298. ClearErr(I);
  3299. IF NOT IsIHandle(I) THEN
  3300. CallErr(I,NotIHandle,'RecordCount');
  3301. RETURN Nil;
  3302. END;
  3303. WITH I.ID^.Id[I.In] DO
  3304. IF NOT I.ID^.Buffered AND (ihLock.ICnt=0) AND (ihLock.ECnt=0) THEN
  3305. CallErr(I,NotLocked,'RecordCount');
  3306. RETURN Nil;
  3307. END;
  3308. RETURN iwr^.RecordCnt;
  3309. END;
  3310. END RecordCount;
  3311. (*# save *)
  3312. (*%T _fcall *) (*# call(near_call=>off) *) (*%E *)
  3313. (*# call(o_a_size=>on) *)
  3314. PROCEDURE Err(err: Errors; str: ARRAY OF CHAR);
  3315. VAR s : ARRAY[0..79] OF CHAR;
  3316. BEGIN
  3317. Str.Concat(s,CHR(13)+CHR(10),str);
  3318. Lib.FatalError(s);
  3319. END Err;
  3320. (*# restore *)
  3321. MODULE NoPack;
  3322. IMPORT MemFastMove;
  3323. EXPORT QUALIFIED Packer, Unpacker, UnpackedSize, Packing, AdjustBlock;
  3324. PROCEDURE Packer(n: CARDINAL; in: ADDRESS; out: ADDRESS): CARDINAL;
  3325. BEGIN
  3326. MemFastMove(in,out,n);
  3327. RETURN n;
  3328. END Packer;
  3329. PROCEDURE Unpacker(n: CARDINAL; in: ADDRESS; out: ADDRESS);
  3330. BEGIN
  3331. MemFastMove(in,out,n);
  3332. END Unpacker;
  3333. PROCEDURE UnpackedSize(n: CARDINAL; in: ADDRESS): CARDINAL;
  3334. BEGIN
  3335. RETURN n;
  3336. END UnpackedSize;
  3337. PROCEDURE Packing(): BOOLEAN;
  3338. BEGIN
  3339. RETURN FALSE;
  3340. END Packing;
  3341. PROCEDURE AdjustBlock(rs: CARDINAL): CARDINAL;
  3342. BEGIN
  3343. RETURN rs;
  3344. END AdjustBlock;
  3345. END NoPack;
  3346. BEGIN
  3347. ErrorHandler := Err;
  3348. Packer := NoPack.Packer;
  3349. Unpacker := NoPack.Unpacker;
  3350. UnpackedSize := NoPack.UnpackedSize;
  3351. Packing := NoPack.Packing;
  3352. AdjustBlock := NoPack.AdjustBlock;
  3353. END Btree.
  3354.