Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

708 lines
19 KiB

  1. /************************************************************/
  2. /* Windows Write, Copyright 1985-1992 Microsoft Corporation */
  3. /************************************************************/
  4. /* cache.c -- Paragraph attribute fetching and caching for WRITE */
  5. #define NOCLIPBOARD
  6. #define NOGDICAPMASKS
  7. #define NOCTLMGR
  8. #define NOVIRTUALKEYCODES
  9. #define NOWINMESSAGES
  10. #define NOWINSTYLES
  11. #define NOSYSMETRICS
  12. #define NOMENUS
  13. #define NOICON
  14. #define NOKEYSTATE
  15. #define NORASTEROPS
  16. #define NOSHOWWINDOW
  17. #define NOSYSCOMMANDS
  18. #define NOCREATESTRUCT
  19. #define NOATOM
  20. #define NOMETAFILE
  21. #define NOGDI
  22. #define NOFONT
  23. #define NOBRUSH
  24. #define NOPEN
  25. #define NOBITMAP
  26. #define NOCOLOR
  27. #define NODRAWTEXT
  28. #define NOWNDCLASS
  29. #define NOSOUND
  30. #define NOCOMM
  31. #define NOMB
  32. #define NOMSG
  33. #define NOOPENFILE
  34. #define NORESOURCE
  35. #define NOPOINT
  36. #define NORECT
  37. #define NOREGION
  38. #define NOSCROLL
  39. #define NOTEXTMETRIC
  40. #define NOWH
  41. #define NOWINOFFSETS
  42. #include <windows.h>
  43. #include "mw.h"
  44. #include "docdefs.h"
  45. #include "editdefs.h"
  46. #include "cmddefs.h"
  47. #include "propdefs.h"
  48. #include "filedefs.h"
  49. #include "fkpdefs.h"
  50. #include "fmtdefs.h"
  51. #define NOKCCODES
  52. #include "ch.h"
  53. #include "prmdefs.h"
  54. #include "debug.h"
  55. extern int vfDiskError;
  56. extern typeCP vcpFirstParaCache;
  57. extern typeCP vcpLimParaCache;
  58. extern typeFC fcMacPapIns;
  59. extern struct FCB (**hpfnfcb)[];
  60. extern struct FKPD vfkpdParaIns;
  61. extern int ichInsert;
  62. extern CHAR rgchInsert[];
  63. extern int vdocExpFetch;
  64. extern int vdocSectCache;
  65. extern typeCP vcpFirstSectCache;
  66. extern typeCP vcpLimSectCache;
  67. extern int vdocPageCache;
  68. extern typeCP vcpMinPageCache;
  69. extern typeCP vcpMacPageCache;
  70. extern typeCP cpMinCur;
  71. extern struct PAP vpapAbs;
  72. extern struct PAP *vppapNormal;
  73. extern struct DOD (**hpdocdod)[];
  74. extern struct FLI vfli;
  75. extern int vdxaPaper;
  76. extern int vdyaPaper;
  77. extern typePN PnFkpFromFcScr();
  78. extern int vdocParaCache;
  79. extern int visedCache;
  80. extern int vdocPageCache;
  81. extern struct SEP vsepAbs;
  82. extern struct SEP vsepPage;
  83. extern struct SEP vsepNormal;
  84. extern int ctrCache;
  85. extern int itrFirstCache;
  86. extern int itrLimCache;
  87. extern typeCP cpCacheHint;
  88. CHAR *PchFromFc();
  89. CHAR *PchGetPn();
  90. CachePara(doc, cp)
  91. int doc;
  92. typeCP cp;
  93. { /* Make the para containing <doc, cp> the currently cached para */
  94. struct PCD *ppcd, *ppcdBase;
  95. typeCP cpMac, cpGuess;
  96. struct DOD *pdod;
  97. int dty;
  98. struct PCTB *ppctb;
  99. if (vdocParaCache == doc && vcpFirstParaCache <= cp &&
  100. cp < vcpLimParaCache)
  101. return; /* That's what the cache is for */
  102. Assert(cp >= cp0);
  103. pdod = &(**hpdocdod)[doc];
  104. dty = pdod->dty;
  105. if (cp >= pdod->cpMac)
  106. { /* Use normal para for end mark and beyond */
  107. #ifdef ENABLE /* Occasionally this is not true (but it should be) */
  108. Assert( cp == pdod->cpMac );
  109. #endif
  110. if (cp > cpMinCur)
  111. { /* this piece of code treats the case when the whole document
  112. is a non-empty semi-paragraph (chars but no EOL's) */
  113. CachePara( doc, cp - 1 ); /* Recursion will not happen */
  114. if ( vcpLimParaCache > cp )
  115. {
  116. vcpLimParaCache = pdod->cpMac + ccpEol;
  117. return;
  118. }
  119. }
  120. vdocParaCache = doc;
  121. vcpLimParaCache = (vcpFirstParaCache = pdod->cpMac) + ccpEol;
  122. DefaultPaps( doc );
  123. return;
  124. }
  125. FreezeHp();
  126. ppctb = *pdod->hpctb;
  127. ppcdBase = &ppctb->rgpcd [ IpcdFromCp( ppctb, cpGuess = cp ) ];
  128. if (vdocParaCache == doc && cp == vcpLimParaCache)
  129. vcpFirstParaCache = cp;
  130. else
  131. { /* Search backward to find para start */
  132. for (ppcd = ppcdBase; ; --ppcd)
  133. { /* Beware heap movement! */
  134. typeCP cpMin = ppcd->cpMin;
  135. int fn = ppcd->fn;
  136. if (! ppcd->fNoParaLast)
  137. { /* Don't check if we know there's no para end */
  138. typeFC fcMin = ppcd->fc;
  139. typeFC fc;
  140. if ((fc = FcParaFirst(fn,
  141. fcMin + cpGuess - cpMin, fcMin)) != fcNil)
  142. { /* Found para begin */
  143. vcpFirstParaCache = cpMin + (fc - fcMin);
  144. break;
  145. }
  146. }
  147. /* Now we know there's no para end from cpMin to cpGuess. */
  148. /* If original piece, may be one after cp */
  149. #ifdef BOGUSBL
  150. /* vfInsertMode protects against a critical section in insert */
  151. /* when the CR is already inserted but the supporting PAP structure */
  152. /* is not in place yet */
  153. if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
  154. #else /* Insert CR works differently now, above test slows us down
  155. by forcing many calls to FcParaLim */
  156. if (cp != cpGuess)
  157. #endif
  158. ppcd->fNoParaLast = true; /* Save some work next time */
  159. if (cpMin == cp0)
  160. { /* Beginning of doc is beginning of para */
  161. vcpFirstParaCache = cpMinCur;
  162. break;
  163. }
  164. /** Some low memory error conditions may cause ppctb to be
  165. messed up **/
  166. if (ppcd == ppctb->rgpcd)
  167. {
  168. Assert(0);
  169. vcpFirstParaCache = cp0; // hope for divine grace
  170. break;
  171. }
  172. cpGuess = cpMin;
  173. }
  174. }
  175. vdocParaCache = doc;
  176. /* Now go forward to find the cpLimPara */
  177. cpMac = pdod->cpMac;
  178. cpGuess = cp;
  179. for (ppcd = ppcdBase; ; ++ppcd)
  180. {
  181. typeCP cpMin = ppcd->cpMin;
  182. typeCP cpLim = (ppcd + 1)->cpMin;
  183. typeFC fc;
  184. int fn = ppcd->fn;
  185. if (! ppcd->fNoParaLast)
  186. { /* Don't check if we know there's no para end */
  187. typeFC fcMin = ppcd->fc;
  188. if ((fc = FcParaLim(fn, fcMin + cpGuess - cpMin,
  189. fcMin + (cpLim - cpMin), &vpapAbs)) != fcNil)
  190. { /* Found para end */
  191. vcpLimParaCache = cpMin + (fc - fcMin);
  192. /* Under Write, FcParaLim can't set the correct rgtbd */
  193. /* That's because tabs are a DOCUMENT property */
  194. /* We set it here instead */
  195. GetTabsForDoc( doc );
  196. break;
  197. }
  198. }
  199. /* Now we know there's no para end. */
  200. #ifdef BOGUSBL
  201. /* The check for vfInsertMode is necessary because of a critical */
  202. /* section in insertion between the insertion of a CR and the call */
  203. /* to AddRunScratch */
  204. if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
  205. #else /* Insert CR has changed, we no longer try to pretend that
  206. the CR is not in the scratch file piece before the run is
  207. added. This new approach gains us speed, especially during backspace */
  208. if (cp != cpGuess)
  209. #endif
  210. ppcd->fNoParaLast = true; /* Save some work next time */
  211. if (cpLim == cpMac)
  212. { /* No EOL at end of doc */
  213. vcpLimParaCache = cpMac + ccpEol;
  214. MeltHp();
  215. DefaultPaps( doc );
  216. return;
  217. }
  218. /** Some low memory error conditions may cause ppctb to be
  219. messed up **/
  220. else if ((cpLim > cpMac) || (ppcd == (ppctb->rgpcd + ppctb->ipcdMac - 1)))
  221. {
  222. Assert(0);
  223. vcpLimParaCache = cpMac + ccpEol; // hope for divine grace
  224. MeltHp();
  225. DefaultPaps( doc );
  226. return;
  227. }
  228. cpGuess = cpLim;
  229. }
  230. /* Don't bother with properties for buffers */
  231. #ifdef ENABLE /* No buffers or styles in MEMO */
  232. if (dty != dtyBuffer || pdod->docSsht != docNil)
  233. #endif
  234. {
  235. struct PRM prm = ppcd->prm;
  236. if (!bPRMNIL(prm))
  237. DoPrm((struct CHP *) 0, &vpapAbs, prm);
  238. #ifdef STYLES
  239. blt(vpapCache.fStyled ? PpropXlate(doc, &vpapCache, &vpapCache) :
  240. &vpapCache, &vpapAbs, cwPAP);
  241. #endif /* STYLES */
  242. }
  243. /* This little piece of code is necessary to provide compatibility between Word
  244. and Memo documents. It compresses the entire range of line spacing into single
  245. spacing, one and one-half spacing, and double spacing. */
  246. if (vpapAbs.dyaLine <= czaLine)
  247. {
  248. vpapAbs.dyaLine = czaLine;
  249. }
  250. else if (vpapAbs.dyaLine >= 2 * czaLine)
  251. {
  252. vpapAbs.dyaLine = 2 * czaLine;
  253. }
  254. else
  255. {
  256. vpapAbs.dyaLine = (vpapAbs.dyaLine + czaLine / 4) / (czaLine / 2) *
  257. (czaLine / 2);
  258. }
  259. MeltHp();
  260. }
  261. DefaultPaps( doc )
  262. int doc;
  263. {
  264. typeCP cpFirstSave, cpLimSave;
  265. struct TBD (**hgtbd)[];
  266. if (vcpFirstParaCache > cpMinCur)
  267. { /* Get pap from previous paragraph */
  268. cpFirstSave = vcpFirstParaCache;
  269. cpLimSave = vcpLimParaCache;
  270. CachePara(doc, cpFirstSave - 1); /* Recursion should not happen */
  271. vpapAbs.fGraphics = false; /* Don't make last para a picture */
  272. vpapAbs.rhc = 0; /* Don't make last para a running head */
  273. vcpLimParaCache = cpLimSave;
  274. vcpFirstParaCache = cpFirstSave;
  275. return;
  276. }
  277. #ifdef CASHMERE
  278. blt(vppapNormal, &vpapAbs, cwPAPBase+cwTBD);
  279. #else /* For MEMO, the default PAPS have the document's tab table */
  280. blt(vppapNormal, &vpapAbs, cwPAPBase);
  281. GetTabsForDoc( doc );
  282. #endif
  283. #ifdef STYLES
  284. blt(&vpapNormal, &vpapCache, cwPAP);
  285. blt(PpropXlate(doc, &vpapNormal, &vpapStd), &vpapAbs, cwPAP);
  286. #endif
  287. }
  288. GetTabsForDoc( doc )
  289. int doc;
  290. { /* Get tab table for passed document into vpapAbs.rgtbd */
  291. struct TBD (**hgtbd)[];
  292. hgtbd = (**hpdocdod)[doc].hgtbd;
  293. if (hgtbd==0)
  294. bltc( vpapAbs.rgtbd, 0, cwTBD * itbdMax );
  295. else
  296. blt( *hgtbd, vpapAbs.rgtbd, cwTBD * itbdMax );
  297. }
  298. #ifdef CASHMERE
  299. CacheSect(doc, cp)
  300. int doc;
  301. typeCP cp;
  302. {
  303. struct SETB **hsetb, *psetb;
  304. struct SED *psed;
  305. CHAR *pchFprop;
  306. int cchT;
  307. struct DOD *pdod;
  308. if (doc == vdocSectCache && cp >= vcpFirstSectCache && cp < vcpLimSectCache)
  309. return;
  310. if ( vdocSectCache != doc && cp != cp0 )
  311. CacheSect( doc, cp0 ); /* Changing docs, assure vsepPage is accurate */
  312. vdocSectCache = doc;
  313. visedCache = iNil;
  314. blt(&vsepNormal, &vsepAbs, cwSEP);
  315. if ((hsetb = HsetbGet(doc)) == 0)
  316. {
  317. vcpFirstSectCache = cp0;
  318. vcpLimSectCache = (pdod = &(**hpdocdod)[doc])->cpMac + 1;
  319. blt(&vsepAbs, &vsepPage, cwSEP); /* set up page info */
  320. return;
  321. }
  322. psetb = *hsetb;
  323. psed = psetb->rgsed;
  324. FreezeHp();
  325. psed += (visedCache = IcpSearch(cp + 1, psed, cchSED, bcpSED, psetb->csed));
  326. Assert( (visedCache >= 0) && (visedCache < psetb->csed) );
  327. vcpFirstSectCache = (visedCache == 0) ? cp0 : (psed - 1)->cp;
  328. vcpLimSectCache = psed->cp;
  329. if (psed->fc != fcNil)
  330. {
  331. pchFprop = PchFromFc(psed->fn, psed->fc, &cchT);
  332. if (*pchFprop != 0)
  333. bltbyte(pchFprop + 1, &vsepAbs, *pchFprop);
  334. }
  335. if (vcpFirstSectCache == cp0)
  336. blt(&vsepAbs, &vsepPage, cwSEP);
  337. else
  338. RecalcSepText(); /* Since this is not the first section of a document,
  339. the margins could be wrong and must be recalculated */
  340. MeltHp();
  341. }
  342. #endif /* CASHMERE */
  343. CacheSect(doc, cp)
  344. int doc;
  345. typeCP cp;
  346. { /* Get current section properties into vsepAbs; section
  347. limits into vcpFirstSectCache, vcpLimSectCache
  348. MEMO VERSION: one section per document */
  349. struct DOD *pdod;
  350. if (doc == vdocSectCache)
  351. return;
  352. vdocSectCache = doc;
  353. pdod = &(**hpdocdod)[doc];
  354. if ( pdod->hsep )
  355. blt( *pdod->hsep, &vsepAbs, cwSEP );
  356. else
  357. blt( &vsepNormal, &vsepAbs, cwSEP );
  358. vcpFirstSectCache = cp0;
  359. vcpLimSectCache = pdod->cpMac;
  360. blt(&vsepAbs, &vsepPage, cwSEP);
  361. }
  362. RecalcSepText()
  363. {
  364. /* calculate value to be changed because of change in page dimensions */
  365. int xaRight, dxaText, cColumns;
  366. int yaBottom, dyaText;
  367. xaRight = vsepPage.xaMac - vsepPage.cColumns * vsepPage.dxaText -
  368. vsepPage.xaLeft - vsepPage.dxaGutter -
  369. (vsepPage.cColumns - 1) * vsepPage.dxaColumns;
  370. dxaText = vdxaPaper - xaRight - vsepPage.xaLeft;
  371. cColumns = vsepAbs.cColumns;
  372. vsepAbs.dxaText = max(dxaMinUseful,
  373. ((dxaText-vsepPage.dxaGutter-(cColumns-1)*vsepAbs.dxaColumns)/cColumns));
  374. vsepAbs.xaMac = vdxaPaper;
  375. /* Calculate bottom margin, correct */
  376. yaBottom = vsepPage.yaMac - vsepPage.yaTop - vsepPage.dyaText;
  377. vsepAbs.dyaText = max(dyaMinUseful, vdyaPaper - vsepPage.yaTop - yaBottom);
  378. vsepAbs.yaMac = vdyaPaper;
  379. }
  380. InvalidateCaches(doc)
  381. int doc;
  382. {
  383. if (doc == vfli.doc) /* Invalidate current formatted line */
  384. vfli.doc = docNil;
  385. if (doc == vdocExpFetch)
  386. vdocExpFetch = docNil;
  387. if (doc == vdocParaCache)
  388. vdocParaCache = docNil;
  389. if (doc == vdocSectCache)
  390. vdocSectCache = docNil;
  391. /* When the current doc is equal to the cached doc, it is unnecessary */
  392. /* to invalidate the page cache when the vcpMinPageCache is 0 and the */
  393. /* vcpMacPageCache is cpMax, since this indicates that all characters in */
  394. /* the document are on page 1. */
  395. if ((doc == vdocPageCache) &&
  396. (!(vcpMinPageCache == cp0 && vcpMacPageCache == cpMax)))
  397. vdocPageCache = docNil;
  398. }
  399. TrashCache()
  400. { /* Invalidate scrolling cache */
  401. ctrCache = 0;
  402. cpCacheHint = cp0;
  403. itrFirstCache = itrLimCache = 0;
  404. }
  405. typeFC FcParaFirst(fn, fc, fcMin)
  406. int fn;
  407. typeFC fc, fcMin;
  408. { /* Return the fc after the latest para end before fc.
  409. if there is no para end in [fcMin, fc), return fcNil. */
  410. struct FCB *pfcb;
  411. if ((fn == fnInsert) || (fc == fcMin))
  412. return fcNil;
  413. if (fn == fnScratch && fc >= fcMacPapIns)
  414. return (fcMin <= fcMacPapIns) ? fcMacPapIns : fcNil;
  415. pfcb = &(**hpfnfcb)[fn];
  416. if (!pfcb->fFormatted)
  417. { /* Unformatted file; scan for an EOL */
  418. typePN pn;
  419. typeFC fcFirstPage;
  420. #ifdef p2bSector
  421. fcFirstPage = (fc - 1) & ~(cfcPage - 1);
  422. pn = fcFirstPage / cfcPage;
  423. #else
  424. pn = (fc - 1) / cfcPage;
  425. fcFirstPage = pn * cfcPage;
  426. #endif
  427. while (fc > fcMin)
  428. {
  429. CHAR *pch;
  430. int cchT;
  431. pch = PchGetPn( fn, pn--, &cchT, false ) + (fc - fcFirstPage);
  432. if (fcMin > fcFirstPage)
  433. fcFirstPage = fcMin;
  434. while (fc > fcFirstPage)
  435. {
  436. if (*(--pch) == chEol)
  437. {
  438. return fc;
  439. }
  440. fc--;
  441. }
  442. fcFirstPage -= cfcPage;
  443. }
  444. return fcNil;
  445. }
  446. else
  447. { /* Formatted file; get info from para run */
  448. struct FKP *pfkp;
  449. typeFC fcFirst, fcLim;
  450. int cchT;
  451. pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
  452. PnFkpFromFcScr(&vfkpdParaIns, fc) :
  453. pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
  454. if (vfDiskError)
  455. return fcNil;
  456. BFromFc(pfkp, fc, &fcFirst, &fcLim);
  457. return (fcMin < fcFirst) ? fcFirst : fcNil;
  458. }
  459. }
  460. typeFC FcParaLim(fn, fc, fcMac, ppap)
  461. int fn;
  462. typeFC fc, fcMac;
  463. struct PAP *ppap;
  464. { /* Return the fc after the first para end after or at fc.
  465. if there is no para end in [fc, fcMac), return fcNil. */
  466. /* Also return paragraph properties in ppap */
  467. struct FCB *pfcb;
  468. /* Start out by feeding caller the normal pap */
  469. #ifdef CASHMERE
  470. blt(vppapNormal, ppap, cwPAPBase + cwTBD);
  471. #else
  472. blt(vppapNormal, ppap, cwPAPBase);
  473. #endif
  474. if ( (fn == fnInsert) || ((fn == fnScratch) && (fc >= fcMacPapIns)) )
  475. return fcNil;
  476. if (!(pfcb = &(**hpfnfcb) [fn])->fFormatted)
  477. { /* Unformatted file; scan for EOL */
  478. typePN pn;
  479. typeFC fcFirstPage;
  480. #ifdef p2bSector
  481. fcFirstPage = fc & ~(cfcPage - 1);
  482. pn = fcFirstPage / cfcPage;
  483. #else
  484. pn = fc / cfcPage;
  485. fcFirstPage = pn * cfcPage;
  486. #endif
  487. while (fc < fcMac)
  488. {
  489. CHAR *pch;
  490. int cchT;
  491. pch = PchGetPn( fn, pn++, &cchT, false ) + (fc - fcFirstPage);
  492. if ((fcFirstPage += cfcPage) > fcMac)
  493. fcFirstPage = fcMac;
  494. while (fc < fcFirstPage)
  495. {
  496. fc++;
  497. if (*pch++ == chEol)
  498. return fc;
  499. }
  500. }
  501. return fcNil;
  502. }
  503. else
  504. { /* Formatted file; get info from para run */
  505. struct FKP *pfkp;
  506. struct FPAP *pfpap;
  507. int bfpap;
  508. typeFC fcLim;
  509. int cchT;
  510. pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
  511. PnFkpFromFcScr(&vfkpdParaIns, fc) :
  512. pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
  513. if (vfDiskError)
  514. { /* Recover from severe disk error reading formatting info */
  515. blt(vppapNormal, ppap, cwPAP);
  516. return (fcMac == pfcb->fcMac) ? fcMac : fcNil;
  517. }
  518. { /* In-line, fast substitute for BFromFc */
  519. register struct RUN *prun = (struct RUN *) pfkp->rgb;
  520. while (prun->fcLim <= fc)
  521. prun++;
  522. fcLim = prun->fcLim;
  523. bfpap = prun->b;
  524. }
  525. if (fcLim <= fcMac)
  526. {
  527. if (bfpap != bNil)
  528. { /* Non-standard para */
  529. pfpap = (struct FPAP *) &pfkp->rgb[bfpap];
  530. bltbyte(pfpap->rgchPap, ppap, pfpap->cch);
  531. }
  532. return fcLim;
  533. }
  534. return fcNil;
  535. }
  536. }
  537. /* B F R O M FC */
  538. int BFromFc( pfkp, fc, pfcFirst, pfcLim )
  539. struct FKP *pfkp;
  540. typeFC fc;
  541. typeFC *pfcFirst, *pfcLim;
  542. { /* Return the base offset & bounds for the first run with fcLim > fc. */
  543. /* Short table, linear search */
  544. register struct RUN *prun = (struct RUN *) pfkp->rgb;
  545. while (prun->fcLim <= fc)
  546. prun++;
  547. *pfcFirst = ((prun == (struct RUN *)pfkp->rgb) ?
  548. pfkp->fcFirst : (prun - 1)->fcLim);
  549. *pfcLim = prun->fcLim;
  550. return prun->b;
  551. }
  552. /* I F R O M F C */
  553. int IFromFc(pfcLim, fc)
  554. register typeFC *pfcLim;
  555. typeFC fc;
  556. { /* Return the index of the first fcLim > fc. */
  557. int ifc = 0;
  558. /* Probably a small table, so linear search? */
  559. while (*pfcLim++ <= fc)
  560. ++ifc;
  561. return ifc;
  562. }
  563. #ifdef BOGUSBL
  564. /* B F R O M F C */
  565. int BFromFc(pfkp, fc, pfcFirst, pfcLim)
  566. struct FKP *pfkp;
  567. typeFC fc;
  568. typeFC *pfcFirst, *pfcLim;
  569. { /* Return the base offset & bounds for the first run with fcLim > fc. */
  570. struct RUN *prun, *rgrun;
  571. int ifcMin, ifcLim;
  572. ifcMin = 0;
  573. ifcLim = pfkp->crun;
  574. rgrun = (struct RUN *)pfkp->rgb;
  575. #ifdef INEFFICIENT
  576. ifc = IcpSearch(fc + 1, pfkp->rgb, cchRUN, bfcRUN, pfkp->crun);
  577. #endif
  578. while (ifcMin + 1 < ifcLim)
  579. {
  580. int ifcGuess = (ifcMin + ifcLim - 1) >> 1;
  581. if (rgrun[ifcGuess].fcLim <= fc)
  582. ifcMin = ifcGuess + 1;
  583. else
  584. ifcLim = ifcGuess + 1;
  585. }
  586. prun = &rgrun[ifcMin];
  587. *pfcLim = prun->fcLim;
  588. *pfcFirst = (ifcMin == 0 ? pfkp->fcFirst : (prun - 1)->fcLim);
  589. return prun->b;
  590. }
  591. #endif /* BOGUSBL */
  592.