Leaked source code of windows server 2003
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.

1358 lines
48 KiB

  1. /* SCCSID = %W% %E% */
  2. /*
  3. * Copyright Microsoft Corporation, 1983-1987
  4. *
  5. * This Module contains Proprietary Information of Microsoft
  6. * Corporation and should be treated as Confidential.
  7. */
  8. /****************************************************************
  9. * *
  10. * LIBRARY PROCESSING ROUTINES *
  11. * *
  12. ****************************************************************/
  13. #include <minlit.h> /* Types and constants */
  14. #include <bndtrn.h> /* Types and constants */
  15. #include <bndrel.h> /* Types and constants */
  16. #include <lnkio.h> /* Linker I/O definitions */
  17. #include <lnkmsg.h> /* Error messages */
  18. #include <extern.h> /* External declarations */
  19. #include <stdlib.h>
  20. #if OSMSDOS
  21. #include <dos.h> /* DOS interface definitions */
  22. #if CPU286
  23. #define INCL_BASE
  24. #include <os2.h> /* OS/2 interface definitions */
  25. #if defined(M_I86LM)
  26. #undef NEAR
  27. #define NEAR
  28. #endif
  29. #endif
  30. #endif
  31. #define DICHDR 0xF1 /* Dictionary header type (F1H) */
  32. #if OSXENIX
  33. #define ShrOpenRd(f) fopen(f,RDBIN)
  34. #endif
  35. #if NEWIO
  36. #include <errno.h> /* System error codes */
  37. #endif
  38. #define PNSORTMAX 512 /* Maximum # modules can be sorted */
  39. typedef struct _edmt /* Extended Dictionary Module Table */
  40. {
  41. WORD page;
  42. WORD list;
  43. }
  44. edmt;
  45. LOCAL FTYPE fUndefHit; /* found this undef in the library */
  46. LOCAL FTYPE fFileExtracted; /* Took file from library flag */
  47. LOCAL FTYPE fUndefsSeen; /* True if externals seen in library */
  48. LOCAL WORD ipnMac; /* Count of page numbers in sort table */
  49. LOCAL WORD *pnSort; /* Sort table for library page numbers */
  50. /* f(ifh) = pointer to dictionary */
  51. LOCAL WORD mpifhcpnHash[IFHLIBMAX];
  52. /* f(ifh) = # pages in hash table */
  53. LOCAL BYTE mpifhAlign[IFHLIBMAX];
  54. /* f(ifh) = lib alignment factor */
  55. LOCAL RBTYPE vrpNewList; /* List of unprocessed files */
  56. LOCAL FTYPE vfLibOpen; /* Library open flag */
  57. #if M_BYTESWAP OR defined( _WIN32 )
  58. #define getfarword getword /* This assumes no far data */
  59. #else
  60. #define getfarword(x) (((WORD FAR *)(x))[0])
  61. #endif
  62. /*
  63. * INTERFACE WITH ASSEMBLY LANGUAGE FUNCTION
  64. */
  65. WORD libAlign; /* Library alignment factor */
  66. WORD libcpnHash; /* Length of hash table in pages */
  67. BYTE FAR *mpifhDict[IFHLIBMAX];
  68. /*
  69. * FUNCTION PROTOTYPES
  70. */
  71. LOCAL unsigned char NEAR OpenLibrary(unsigned char *sbLib);
  72. LOCAL void NEAR FreeDictionary(void);
  73. #if CPU8086 OR CPU286
  74. LOCAL WORD NEAR readfar(int fh, char FAR *buf,int n);
  75. #endif
  76. LOCAL void NEAR GetDictionary(void);
  77. LOCAL WORD NEAR GetLib(void);
  78. LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef,
  79. RBTYPE rhte,
  80. RBTYPE rprop,
  81. WORD fNewHte);
  82. LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2);
  83. LOCAL void NEAR LookMod(edmt *modtab,unsigned short iMod);
  84. LOCAL void NEAR LookPage(edmt *modtab,unsigned short cMod,unsigned short page);
  85. LOCAL void NEAR ProcExtDic(char *pExtDic);
  86. LOCAL char * NEAR GetExtDic(void);
  87. #if NEW_LIB_SEARCH
  88. /// undef lookaside list
  89. typedef struct tag_UND
  90. {
  91. struct tag_UND * pNext;
  92. APROPNAMEPTR papropUndef;
  93. DWORD dwLibMask;
  94. RBTYPE rhte;
  95. } UND;
  96. #define C_UNDS_POOL 128
  97. typedef struct tag_UNDPOOL
  98. {
  99. struct tag_UNDPOOL *pNext;
  100. UND und[C_UNDS_POOL];
  101. } UNDPOOL;
  102. // pool storage management variables
  103. UNDPOOL *pundpoolCur;
  104. UNDPOOL *pundpoolHead;
  105. int iundPool = C_UNDS_POOL;
  106. UND * pundFree;
  107. UND * pundListHead;
  108. #define FUndefsLeft() (pundListHead != NULL)
  109. void StoreUndef(APROPNAMEPTR, RBTYPE, RBTYPE, WORD);
  110. #else
  111. #define FUndefsLeft() (fUndefsSeen)
  112. #endif
  113. FTYPE fStoreUndefsInLookaside = FALSE;
  114. /////
  115. #if NOASM
  116. LOCAL WORD NEAR rolw(WORD x, WORD n) /* Rotate word left */
  117. {
  118. return(LO16BITS((x << n) | ((x >> (WORDLN - n)) & ~(~0 << n))));
  119. }
  120. LOCAL WORD NEAR rorw(WORD x, WORD n) /* Rotate word right */
  121. {
  122. return(LO16BITS((x << (WORDLN - n)) | ((x >> n) & ~(~0 << (WORDLN - n)))));
  123. }
  124. #endif
  125. #if OSMSDOS
  126. BSTYPE NEAR ShrOpenRd(pname)
  127. char *pname; /* Name of file (null-terminated) */
  128. {
  129. int fh; /* File handle */
  130. #if NEWIO
  131. if(mpifhfh[ifhLibCur])
  132. {
  133. fh = mpifhfh[ifhLibCur];
  134. /* If dictionary not allocated, seek to beginning since we're
  135. * somewhere else now.
  136. */
  137. if(!mpifhDict[ifhLibCur])
  138. if (_lseek(fh,0L,0) == -1) {
  139. return NULL;
  140. }
  141. }
  142. else
  143. fh = SmartOpen(pname,ifhLibCur);
  144. if(fh > 0)
  145. {
  146. fflush(bsInput);
  147. bsInput->_file = (char) fh;
  148. return(bsInput);
  149. }
  150. else
  151. return(NULL);
  152. #else
  153. if((fh = _sopen(pname,O_RDONLY | O_BINARY,SH_DENYWR)) < 0)
  154. return(NULL);
  155. return(fdopen(fh,RDBIN));
  156. #endif
  157. }
  158. #endif /* OSMSDOS */
  159. #pragma check_stack(on)
  160. /****************************************************************
  161. * *
  162. * OpenLibrary: *
  163. * *
  164. * This function takes as its arguments a pointer to the text *
  165. * of the name of the library to open, a count of the bytes in *
  166. * that name, an index into a global table in which to place *
  167. * the file handle for the opened library. It returns TRUE if *
  168. * it succeeds, FALSE if it fails to open the file; and it *
  169. * dies gracefully if the file is not a valid library. *
  170. * *
  171. ****************************************************************/
  172. LOCAL FTYPE NEAR OpenLibrary(sbLib)
  173. BYTE *sbLib; /* Library name */
  174. {
  175. SBTYPE libnam; /* Library name */
  176. WORD reclen; /* Library header record length */
  177. BSTYPE bsLib; /* File stream pointer for library */
  178. memcpy(libnam,&sbLib[1],min(sizeof(libnam), B2W(sbLib[0])));
  179. /* Copy library name */
  180. libnam[B2W(sbLib[0])] = '\0'; /* Null-terminate name */
  181. /* WARNING: do not assign bsInput to NULL if open fails, it
  182. * screws up NEWIO.
  183. */
  184. if((bsLib = ShrOpenRd(libnam)) != NULL)
  185. { /* If open successful */
  186. bsInput = bsLib;
  187. /* If dictionary already allocated, no need to do anything */
  188. if(mpifhDict[ifhLibCur])
  189. return((FTYPE) TRUE);
  190. #if OSMSDOS
  191. /* Reduce buffer size. We can avoid calling setvbuf() because
  192. * everything is set up properly at this point.
  193. */
  194. #if OWNSTDIO
  195. bsInput->_bsize = 512;
  196. #else
  197. setvbuf(bsInput, bsInput->_base, _IOFBF, 512);
  198. #endif
  199. #endif
  200. if(getc(bsInput) == LIBHDR) /* If we have a library */
  201. {
  202. reclen = (WORD) (3 + WSGets());
  203. /* Get record length */
  204. for(libAlign = 15; libAlign &&
  205. !(reclen & (1 << libAlign)); --libAlign);
  206. /* Calculate alignment factor */
  207. mpifhAlign[ifhLibCur] = (BYTE) libAlign;
  208. if(libAlign >= 4 && reclen == (WORD) (1 << libAlign))
  209. { /* Check legality of alignment */
  210. libHTAddr = (long) WSGets();
  211. libHTAddr += (long) WSGets() << WORDLN;
  212. /* Get the offset of the hash table */
  213. if (libHTAddr <= 0L)
  214. Fatal(ER_badlib,libnam);
  215. if ((mpifhcpnHash[ifhLibCur] = WSGets()) <= 0)
  216. /* Get size of hash table in pages */
  217. Fatal(ER_badlib,libnam);
  218. #if OSMSDOS
  219. /* Restore big buffer size. Avoid calling setvbuf(). */
  220. #if OWNSTDIO
  221. bsInput->_bsize = LBUFSIZ;
  222. #else
  223. setvbuf(bsInput, bsInput->_base, _IOFBF, LBUFSIZ);
  224. #endif
  225. #endif
  226. return((FTYPE) TRUE); /* Success */
  227. }
  228. }
  229. Fatal(ER_badlib,libnam);
  230. }
  231. return(FALSE); /* Failure */
  232. }
  233. #pragma check_stack(off)
  234. /*
  235. * LookupLibSym: look up a symbol in library dictionary
  236. *
  237. * The minimum page size is 16, so we can return paragraph offsets.
  238. * This is a win because offsets are stored as paragraphs in the
  239. * sorting table anyway. Also, the majority of libraries have page
  240. * size of 16.
  241. *
  242. * Parameters:
  243. * char *psb - pointer to length-prefixed string
  244. * Returns:
  245. * Long paragraph offset to location of module which defines
  246. * the symbol, or 0L if not found.
  247. */
  248. #if NOASM
  249. LOCAL WORD NEAR LookupLibSym(psb)
  250. BYTE *psb; /* Symbol to look up */
  251. {
  252. WORD i1; /* First hash value */
  253. WORD d1; /* First hash delta */
  254. WORD i2; /* Second hash value */
  255. WORD d2; /* Second hash delta */
  256. WORD pn; /* Page number */
  257. WORD dpn; /* Page number delta */
  258. WORD pslot; /* Page slot */
  259. WORD dpslot; /* Page slot delta */
  260. WORD ipn; /* Initial page number */
  261. BYTE FAR *hpg;
  262. #if NOASM
  263. WORD ch1; /* Character */
  264. WORD ch2; /* Character */
  265. char *pc1; /* Character pointer */
  266. char *pc2; /* Character pointer */
  267. WORD length; /* Symbol length */
  268. #endif
  269. #if LIBDEBUG
  270. OutSb(stderr,psb);
  271. fprintf(stderr," is wanted; dictionary is %d pages\r\n",libcpnHash);
  272. #endif
  273. #if NOASM
  274. length = B2W(psb[0]); /* Get symbol length */
  275. pc1 = (char *) psb; /* Initialize */
  276. pc2 = (char *) &psb[B2W(psb[0])]; /* Initialize */
  277. i1 = 0; /* Initialize */
  278. d1 = 0; /* Initialize */
  279. i2 = 0; /* Initialize */
  280. d2 = 0; /* Initialize */
  281. while(length--) /* Hashing loop */
  282. {
  283. ch1 = (WORD) (B2W(*pc1++) | 040);/* Force to lower case */
  284. ch2 = (WORD) (B2W(*pc2--) | 040);/* Force to lower case */
  285. i1 = (WORD) (rolw(i1,2) ^ ch1); /* Hash */
  286. d1 = (WORD) (rolw(d1,2) ^ ch2); /* Hash */
  287. i2 = (WORD) (rorw(i2,2) ^ ch2); /* Hash */
  288. d2 = (WORD) (rorw(d2,2) ^ ch1); /* Hash */
  289. }
  290. #else
  291. i1 = libhash(psb,&d1,&i2,&d2); /* Hash */
  292. #endif
  293. pn = (WORD) (i1 % libcpnHash); /* Calculate page number index */
  294. if(!(dpn = (WORD) (d1 % libcpnHash))) dpn = 1;
  295. /* Calculate page number delta */
  296. pslot = (WORD) (i2 % CSLOTMAX); /* Calculate page slot index */
  297. if(!(dpslot = (WORD) (d2 % CSLOTMAX))) dpslot = 1;
  298. /* Calculate page slot delta */
  299. #if LIBDEBUG
  300. fprintf(stderr,"page index %d, delta %d, bucket index %d, delta %d\r\n",
  301. pn,dpn,pslot,dpslot);
  302. #endif
  303. ipn = pn; /* Remember initial page number */
  304. for(;;) /* Search loop */
  305. {
  306. #if LIBDEBUG
  307. fprintf(stderr,"Page %d:\r\n",pn);
  308. #endif
  309. // Get pointer to the dictionary page
  310. hpg = mpifhDict[ifhLibCur] + (pn << LG2PAG);
  311. for(i2 = 0; i2 < CSLOTMAX; ++i2)/* Loop to check slots */
  312. {
  313. #if LIBDEBUG
  314. fprintf(stderr,"Bucket %d %sempty, page %sfull\r\n",
  315. pslot,hpg[pslot]? "not ": "",
  316. B2W(hpg[CSLOTMAX]) == 0xFF? "": "not ");
  317. #endif
  318. if(!(i1 = (WORD) (B2W(hpg[pslot]) << 1)))
  319. { /* If slot is empty */
  320. if(B2W(hpg[CSLOTMAX]) == 0xFF) break;
  321. /* If page is full, break */
  322. return(0); /* Search failed */
  323. }
  324. #if LIBDEBUG
  325. fprintf(stderr," Comparing ");
  326. OutSb(stderr,psb);
  327. fprintf(stderr," to ");
  328. OutSb(stderr,&hpg[i1]);
  329. fprintf(stderr," %signoring case\r\n",fIgnoreCase? "": "not ");
  330. #endif
  331. if(psb[0] == hpg[i1] && SbNewComp(psb,&hpg[i1],fIgnoreCase))
  332. { /* If symbols match */
  333. #if LIBDEBUG
  334. fprintf(stderr,"Match found in slot %d\r\n",i2 >> 1);
  335. #endif
  336. i1 += (WORD) (B2W(hpg[i1]) + 1); /* Skip over name */
  337. i1 = getfarword(&hpg[i1]);
  338. /* Get page number of module */
  339. return(i1); /* Return page number of module */
  340. }
  341. if((pslot += dpslot) >= CSLOTMAX) pslot -= CSLOTMAX;
  342. /* Try next slot */
  343. }
  344. if((pn += dpn) >= libcpnHash) pn -= libcpnHash;
  345. /* Try next page */
  346. if (ipn == pn) return(0); /* Once around without finding it */
  347. }
  348. }
  349. #endif /*NOASM*/
  350. /*
  351. * FreeDictionary : free space allocated for dictionaries
  352. */
  353. LOCAL void NEAR FreeDictionary ()
  354. {
  355. WORD i;
  356. for (i = 0; i < ifhLibMac; ++i)
  357. if (mpifhDict[i])
  358. FFREE(mpifhDict[i]);
  359. }
  360. #if CPU8086 OR CPU286
  361. /*
  362. * readfar : read() with a far buffer
  363. *
  364. * Emulate read() except use a far buffer. Call the system
  365. * directly.
  366. *
  367. * Returns:
  368. * 0 if error, else number of bytes read.
  369. */
  370. LOCAL WORD NEAR readfar (fh, buf, n)
  371. int fh; /* File handle */
  372. char FAR *buf; /* Buffer to store bytes in */
  373. int n; /* # bytes to read */
  374. {
  375. #if OSMSDOS
  376. unsigned bytesread; /* Number of bytes read */
  377. #if CPU8086
  378. if (_dos_read(fh, buf, n, &bytesread))
  379. return(0);
  380. return(bytesread);
  381. #else
  382. if(DosRead(fh,buf,n,(unsigned FAR *) &bytesread))
  383. return(0);
  384. return(bytesread);
  385. #endif
  386. #endif /* OSMSDOS */
  387. #if OSXENIX
  388. char mybuf[PAGLEN];
  389. int cppage;
  390. char *p;
  391. while(n > 0)
  392. {
  393. cppage = n > PAGLEN ? PAGLEN : n;
  394. if(read(fh,mybuf,cppage) != cppage)
  395. return(0);
  396. n -= cppage;
  397. for(p = mybuf; p < mybuf[cppage]; *buf++ = *p++);
  398. }
  399. #endif
  400. }
  401. #endif
  402. LOCAL void NEAR GetDictionary ()
  403. {
  404. unsigned cb;
  405. #if CPU8086 OR CPU286
  406. // If there is more than 128 pages in dictionary return,
  407. // because the dictionary is bigger than 64k
  408. if (libcpnHash >= 128)
  409. return;
  410. #endif
  411. cb = libcpnHash << LG2PAG;
  412. mpifhDict[ifhLibCur] = GetMem(cb);
  413. // Go to the dictionary and read it in a single call
  414. #if defined(M_I386) || defined( _WIN32 )
  415. if (fseek(bsInput, libHTAddr, 0))
  416. Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
  417. if (fread(mpifhDict[ifhLibCur], 1, cb, bsInput) != (int) cb)
  418. Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
  419. #else
  420. _lseek(fileno(bsInput), libHTAddr, 0);
  421. if (readfar(fileno(bsInput), mpifhDict[ifhLibCur], cb) != cb)
  422. Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
  423. #endif
  424. }
  425. #pragma check_stack(on)
  426. LOCAL WORD NEAR GetLib(void) /* Open the next library in list */
  427. {
  428. AHTEPTR pahteLib; /* Pointer to library name */
  429. #if OSMSDOS
  430. SBTYPE sbLib; /* Library name */
  431. SBTYPE sbNew; /* New parts to library name */
  432. #endif
  433. if(mpifhrhte[ifhLibCur] == RHTENIL) /* If this library is to be skipped */
  434. {
  435. return(FALSE); /* No library opened */
  436. }
  437. for(;;) /* Loop to open library */
  438. {
  439. pahteLib = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
  440. /* Get name from hash table */
  441. if(OpenLibrary(GetFarSb(pahteLib->cch))) break;
  442. /* Break if lib opened okay */
  443. if(fNoprompt)
  444. Fatal(ER_libopn,1 + GetFarSb(pahteLib->cch));
  445. else
  446. {
  447. sbLib[0] = '\0'; /* No string yet */
  448. UpdateFileParts(sbLib,GetFarSb(pahteLib->cch));
  449. (*pfPrompt)(sbNew,ER_libopn, /* Prompt for new filespec */
  450. (int) (__int64) (1 + GetFarSb(pahteLib->cch)),
  451. P_EnterNewFileSpec, 0);
  452. }
  453. if(fNoprompt || !sbNew[0])
  454. {
  455. mpifhrhte[ifhLibCur] = RHTENIL;
  456. /* Do not bother next time */
  457. return(FALSE); /* Unsuccessful */
  458. }
  459. #if OSMSDOS
  460. UpdateFileParts(sbLib,sbNew); /* Update file name with new parts */
  461. PropSymLookup(sbLib,ATTRFIL,TRUE);
  462. /* Add library to symbol table */
  463. mpifhrhte[ifhLibCur] = vrhte; /* Save virtual address */
  464. AddLibPath(ifhLibCur); /* Add default path spec, maybe */
  465. #endif
  466. }
  467. vfLibOpen = (FTYPE) TRUE; /* A library is open */
  468. libcpnHash = mpifhcpnHash[ifhLibCur];
  469. libAlign = mpifhAlign[ifhLibCur];
  470. if (mpifhDict[ifhLibCur] == NULL) /* If dictionary not allocated, do it */
  471. GetDictionary();
  472. return(TRUE); /* Success */
  473. }
  474. #pragma check_stack(off)
  475. /****************************************************************
  476. * *
  477. * ProcessAnUndef: *
  478. * *
  479. * This function takes as its arguments two pointers, two *
  480. * RBTYPEs, and a flag. It does not return a meaningful *
  481. * value. Most of the parameters to this function are *
  482. * dummies; this function's address is passed as a parameter, *
  483. * and its parameter list must match those of all the *
  484. * functions whose addresses can be passed as a parameter to *
  485. * the same function to which ProcessAnUndef's address is *
  486. * passed. Called by EnSyms. *
  487. * *
  488. ****************************************************************/
  489. LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef,
  490. RBTYPE rhte,
  491. RBTYPE rprop__NotUsed__,
  492. WORD fNewHte__NotUsed__)
  493. {
  494. AHTEPTR pahte; /* Pointer to hash table entry */
  495. WORD pn; /* Library page number */
  496. APROPUNDEFPTR pUndef;
  497. ATTRTYPE attr;
  498. #if NOT NEWSYM
  499. SBTYPE sb; /* Undefined symbol */
  500. #endif
  501. fUndefHit = FALSE;
  502. pUndef = (APROPUNDEFPTR ) papropUndef;
  503. attr = pUndef->au_flags;
  504. // don't pull out any "weak" externs or unused aliased externals
  505. if (((attr & WEAKEXT) && !(attr & UNDECIDED)) ||
  506. ((attr & SUBSTITUTE) && !(attr & SEARCH_LIB)))
  507. {
  508. fUndefHit = TRUE; // this item is effectively resolved...
  509. return;
  510. }
  511. fUndefsSeen = (FTYPE) TRUE; /* Set flag */
  512. if(!mpifhDict[ifhLibCur] && !vfLibOpen)
  513. return; /* Return if unable to get library */
  514. pahte = (AHTEPTR ) FetchSym(rhte,FALSE);
  515. /* Fetch name from symbol table */
  516. #if NOT NEWSYM
  517. memcpy(sb,pahte->cch,B2W(pahte->cch[0]) + 1);
  518. /* Copy name */
  519. #endif
  520. #if LIBDEBUG
  521. fprintf(stdout,"Looking for '%s' - ", 1+GetFarSb(pahte->cch));
  522. fflush(stdout);
  523. #endif
  524. #if NEWSYM
  525. if(pn = LookupLibSym(GetFarSb(pahte->cch)))
  526. #else
  527. if(pn = LookupLibSym(sb)) /* If symbol defined in this library */
  528. #endif
  529. {
  530. fUndefHit = TRUE;
  531. #if LIBDEBUG
  532. fprintf(stdout,"Symbol found at page %xH\r\n", pn);
  533. fflush(stdout);
  534. #endif
  535. /* We now try to stuff the page number (pn) into a table that will
  536. * be sorted later.
  537. */
  538. if (ipnMac < PNSORTMAX)
  539. {
  540. pnSort[ipnMac++] = pn;
  541. return;
  542. }
  543. /*
  544. * No room to save the file offset so save file directly.
  545. */
  546. pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
  547. /*
  548. * If SaveInput returns 0, then module was seen before. Means
  549. * that dictionary says symbol is defined in this module but
  550. * for some reason, such as IMPDEF, the definition wasn't
  551. * accepted. In this case, we return.
  552. */
  553. if(!SaveInput(GetFarSb(pahte->cch), (long)pn << libAlign, ifhLibCur, 0))
  554. return;
  555. /*
  556. * If first module extracted, save start of file list.
  557. */
  558. if(!fFileExtracted)
  559. {
  560. vrpNewList = vrpropTailFile;
  561. fFileExtracted = (FTYPE) TRUE;
  562. }
  563. }
  564. #if LIBDEBUG
  565. else
  566. {
  567. fprintf(stdout, "Symbol NOT found\r\n"); /* Debug message */
  568. fflush(stdout);
  569. }
  570. #endif
  571. }
  572. #if NEW_LIB_SEARCH
  573. void StoreUndef(APROPNAMEPTR papropUndef, RBTYPE rhte,
  574. RBTYPE rprop, WORD fNewHte)
  575. {
  576. UND * pund;
  577. APROPUNDEFPTR pUndef;
  578. ATTRTYPE attr;
  579. pUndef = (APROPUNDEFPTR ) papropUndef;
  580. attr = pUndef->au_flags;
  581. // don't pull out any "weak" externs or unused aliased externals
  582. if (((attr & WEAKEXT) && !(attr & UNDECIDED)) ||
  583. ((attr & SUBSTITUTE) && !(attr & SEARCH_LIB)))
  584. return;
  585. #ifdef LIBDEBUG
  586. {
  587. AHTEPTR pahte;
  588. pahte = (AHTEPTR) FetchSym(rhte,FALSE);
  589. fprintf(stdout,"Adding '%s'\r\n", 1+GetFarSb(pahte->cch));
  590. fflush(stdout);
  591. }
  592. #endif
  593. if (pundFree) // check free list
  594. {
  595. pund = pundFree;
  596. pundFree = pundFree->pNext;
  597. }
  598. else if (iundPool < C_UNDS_POOL) // check pool
  599. {
  600. pund = &pundpoolCur->und[iundPool];
  601. iundPool++;
  602. }
  603. else
  604. {
  605. // allocate new pool...
  606. pundpoolCur = (UNDPOOL *)GetMem(sizeof(UNDPOOL));
  607. pundpoolCur->pNext = pundpoolHead;
  608. pundpoolHead = pundpoolCur;
  609. pund = &pundpoolCur->und[0];
  610. iundPool = 1; // entry zero is already used up
  611. }
  612. pund->dwLibMask = 0;
  613. pund->pNext = pundListHead;
  614. pund->papropUndef = papropUndef;
  615. pund->rhte = rhte;
  616. pundListHead = pund;
  617. }
  618. #endif
  619. /*
  620. * Greater-than comparator to be used by Sort routine.
  621. */
  622. LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2)
  623. {
  624. if (*pn1 < *pn2)
  625. return(-1);
  626. if (*pn1 > *pn2)
  627. return(1);
  628. return(0);
  629. }
  630. /************************************************************************
  631. * Extended Dictionary
  632. *
  633. * The extended dictionary occurs at the end of the regular dictionary
  634. * and contains a first-level dependency tree for all the modules
  635. * in the library.
  636. ************************************************************************/
  637. #define LIBEXD 0xf2 /* Library EXtended Dictionary */
  638. /****************************************************************
  639. * *
  640. * Extended Dictionary Format: *
  641. * *
  642. * *
  643. * BYTE =0xF2 Extended Dictionary header *
  644. * WORD length of extended dictionary in bytes *
  645. * excluding 1st 3 bytes *
  646. * *
  647. * Start of ext. dictionary: *
  648. * *
  649. * WORD number of modules in library = N *
  650. * *
  651. * Module table, indexed by module number, with N + 1 fixed- *
  652. * length entries: *
  653. * *
  654. * WORD module page number *
  655. * WORD offset from start of ext. dictionary to list *
  656. * of required modules *
  657. * *
  658. * Last entry is null. *
  659. * *
  660. * Module dependency lists, N variable-length lists: *
  661. * *
  662. * WORD list length (number of required modules) *
  663. * WORD module index, 0-based; this is index to module *
  664. * . . . table at the begin of ext. dictionary. *
  665. * . . . *
  666. * *
  667. * *
  668. ****************************************************************/
  669. /*
  670. * LookMod : look up a module by index in the extended dictionary
  671. *
  672. * Get the list of modules required by the given module. If not
  673. * already marked, save index in sorting table (which will be
  674. * converted to page number later) and mark the entry in the
  675. * module table as seen by setting the low bit of the list offset.
  676. *
  677. * Parameters:
  678. * modtab: Pointer to module table
  679. * iMod: Index into table, 0-based
  680. */
  681. LOCAL void NEAR LookMod (edmt *modtab, WORD iMod)
  682. {
  683. WORD *pw; /* Pointer to list of indexes */
  684. WORD n; /* List counter */
  685. /*
  686. * Get the pointer to the list. Mask off low bit since it is used
  687. * as a marker.
  688. */
  689. pw = (WORD *) ((char *) modtab + (modtab[iMod].list & ~1));
  690. /*
  691. * For every entry in the list, if the corresponding entry in the
  692. * module table is not marked, save the index in pnSort and mark
  693. * the entry in the module table.
  694. */
  695. for(n = *pw++; n--; pw++)
  696. {
  697. if(!(modtab[*pw].list & 1))
  698. {
  699. /*
  700. * Check for table overflow.
  701. */
  702. if(ipnMac == PNSORTMAX)
  703. return;
  704. pnSort[ipnMac++] = *pw;
  705. modtab[*pw].list |= 1;
  706. }
  707. }
  708. }
  709. /*
  710. * LookPage : Look up a module in the module table by page number
  711. *
  712. * Use binary search. If page is found, call LookMod() on the
  713. * matching entry.
  714. *
  715. * Parameters:
  716. * modtab: Pointer to module table
  717. * cMod: Number of entries in table
  718. * page: Page number
  719. * ASSUMES:
  720. * The highest entry in the table has a page number of 0xffff.
  721. */
  722. LOCAL void NEAR LookPage (edmt *modtab, WORD cMod, WORD page)
  723. {
  724. WORD mid; /* Current mid point */
  725. WORD lo, hi; /* Current low and high points */
  726. lo = 0; /* Table is 0-based. */
  727. hi = (WORD) (cMod - 1);
  728. while(lo <= hi)
  729. {
  730. if(modtab[mid = (WORD) ((lo + hi) >> 1)].page == page)
  731. {
  732. modtab[mid].list |= 1;
  733. LookMod(modtab,mid);
  734. return;
  735. }
  736. else if(modtab[mid].page < page)
  737. lo = (WORD) (mid + 1);
  738. else
  739. hi = (WORD) (mid - 1);
  740. }
  741. }
  742. /*
  743. * ProcExtDic : Process Extended Dictionary
  744. *
  745. * Store in pnSort all the secondary modules required by
  746. * the modules obtained from the regular dictionary lookup.
  747. *
  748. * Parameters:
  749. * pExtDic: Pointer to extended dictionary
  750. */
  751. LOCAL void NEAR ProcExtDic (pExtDic)
  752. char *pExtDic;
  753. {
  754. WORD *p;
  755. WORD *pEnd;
  756. WORD cMod;
  757. edmt *modtab;
  758. cMod = getword(pExtDic);
  759. modtab = (edmt *) (pExtDic + 2);
  760. /* For the binary search algorithm, we make an artifical last entry
  761. * with a page # at least as high as anything else.
  762. */
  763. modtab[cMod].page = 0xffff;
  764. /* Process by page numbers */
  765. for(p = pnSort, pEnd = &pnSort[ipnMac]; p < pEnd; ++p)
  766. LookPage(modtab, cMod, *p);
  767. /* Now pnSort from pEnd to lfaSort[ipnMac] contains module
  768. * index numbers. Process by index number and convert to page.
  769. */
  770. for( ; p < &pnSort[ipnMac]; ++p)
  771. {
  772. LookMod(modtab,*p);
  773. *p = modtab[*p].page;
  774. }
  775. }
  776. /*
  777. * GetExtDic - Get Extended Dictionary
  778. */
  779. LOCAL char * NEAR GetExtDic ()
  780. {
  781. char *p;
  782. int length;
  783. if(!vfLibOpen)
  784. if(!GetLib())
  785. return(NULL);
  786. /* WARNING: we must just have read dictionary for this to work,
  787. * otherwise an fseek() is required here.
  788. */
  789. if (!mpifhDict[ifhLibCur])
  790. {
  791. fflush(bsInput);
  792. if (fseek(bsInput, libHTAddr + (libcpnHash << LG2PAG), 0))
  793. Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
  794. }
  795. if(getc(bsInput) != LIBEXD)
  796. return(NULL);
  797. if((p = GetMem(length = WSGets())) != NULL)
  798. if(fread(p,1,length,bsInput) != length)
  799. {
  800. FreeMem(p);
  801. p = NULL;
  802. }
  803. return(p);
  804. }
  805. char *pExtDic = NULL; /* Pointer to extended dictionary */
  806. /****************************************************************
  807. * *
  808. * LibrarySearch: *
  809. * *
  810. * This function takes no arguments. It searches all open *
  811. * libraries to resolve undefined externals. It does not *
  812. * return a meaningful value. *
  813. * *
  814. ****************************************************************/
  815. void NEAR LibrarySearch(void)
  816. {
  817. RBTYPE vrpTmpFileFirst;
  818. WORD ifhLibMacInit; /* Initial number of libs to search */
  819. FTYPE searchMore; /* Search continue flag */
  820. WORD bufpnSort[PNSORTMAX];
  821. /* Actual space for pnSort */
  822. SBTYPE sbLibname; /* Name of current library */
  823. AHTEPTR pahte; /* Pointer to hash table entry */
  824. REGISTER WORD i;
  825. FTYPE fLibPass1 = (FTYPE) TRUE;
  826. /* True if on 1st pass thru libs */
  827. FTYPE *fUsedInPass1; /* True if lib used in 1st pass thru libs */
  828. FTYPE fFirstTime; /* True if lib seen for the first time */
  829. extern FTYPE fNoExtDic; /* True if /NOEXTDICTIONARY */
  830. #if NEW_LIB_SEARCH
  831. UND *pund; /* pointer in undef lookaside list */
  832. UND *pundPrev; /* pointer to previous undef entry */
  833. UND *pundNext; /* pointer to next undef entry */
  834. #endif
  835. fUndefsSeen = (FTYPE) TRUE; /* There are undefined externals */
  836. vfLibOpen = FALSE; /* No libraries open yet */
  837. pnSort = bufpnSort; /* Initialize sort table pointer */
  838. ifhLibMacInit = ifhLibMac;
  839. fUsedInPass1 = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE));
  840. if (fUsedInPass1 != NULL)
  841. memset(fUsedInPass1, TRUE, ifhLibMac);
  842. #if NEW_LIB_SEARCH
  843. // build up the the lookaside list
  844. EnSyms(StoreUndef,ATTRUND);
  845. fStoreUndefsInLookaside = TRUE;
  846. #endif
  847. do /* Loop to search libraries */
  848. {
  849. searchMore = FALSE; /* Assume on final pass */
  850. for(ifhLibCur = 0; ifhLibCur < ifhLibMac && FUndefsLeft(); ++ifhLibCur)
  851. { /* While undefs and libraries */
  852. #if NEW_LIB_SEARCH
  853. DWORD libMask = (1<<ifhLibCur);
  854. if (pundListHead->dwLibMask & libMask)
  855. continue; // no need to search this library
  856. // the first item in the list has already
  857. // been searched...
  858. #endif
  859. if(!GetLib())
  860. continue;
  861. /*
  862. * If this is first pass through the libraries and /NOEXT was
  863. * not given, try to get the extended dictionary. We assume that
  864. * if there is one then only one library pass is needed.
  865. */
  866. if(fLibPass1 && !fNoExtDic)
  867. pExtDic = GetExtDic();
  868. else
  869. pExtDic = NULL;
  870. /* If no extended dictionary, reduce buffer size because more
  871. * seeking will be done. This will affect remaining libraries
  872. * in search; we don't care about mixed extended and non-
  873. * extended libraries.
  874. */
  875. if(!pExtDic)
  876. setvbuf(bsInput,bsInput->_base,_IOFBF,1024);
  877. pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
  878. /* Get library name */
  879. memcpy(sbLibname,GetFarSb(pahte->cch),B2W(pahte->cch[0])+1);
  880. #if WIN_3 OR C8_IDE
  881. sbLibname[B2W(*sbLibname)+1] = '\0';
  882. #endif
  883. #if WIN_3
  884. StatMsgWin( "%s\r\n", sbLibname+1);
  885. #endif
  886. #if C8_IDE
  887. if(fC8IDE)
  888. {
  889. sprintf(msgBuf, "@I4%s\r\n", sbLibname+1);
  890. _write(fileno(stderr), msgBuf, strlen(msgBuf));
  891. }
  892. #endif
  893. fFirstTime = (FTYPE) TRUE;
  894. while(FUndefsLeft()) /* While there are undefs seen */
  895. {
  896. fFileExtracted = FALSE; /* Assume we won't take anything */
  897. fUndefsSeen = FALSE; /* Assume no more undefs */
  898. ipnMac = 0; /* Initialize sort table count */
  899. #if NOT NEW_LIB_SEARCH
  900. EnSyms(ProcessAnUndef,ATTRUND);
  901. #else
  902. pund = pundListHead;
  903. pundPrev = NULL;
  904. while (pund)
  905. {
  906. if (pund->dwLibMask & libMask)
  907. {
  908. break; // since items are added to the head,
  909. // as soon as we find one item that has
  910. // already been searched, the rest have
  911. // also already been searched...
  912. // pundPrev = pund;
  913. // pund = pund->pNext;
  914. // continue;
  915. }
  916. pundNext = pund->pNext;
  917. if (pund->papropUndef->an_attr == ATTRUND)
  918. ProcessAnUndef(pund->papropUndef, pund->rhte, 0, 0);
  919. else
  920. fUndefHit = TRUE; // no longer undefined -- remove
  921. if (fUndefHit)
  922. {
  923. // remove this item from the undef list...
  924. if (pundPrev)
  925. pundPrev->pNext = pundNext;
  926. else
  927. pundListHead = pundNext;
  928. pund->pNext = pundFree;
  929. pundFree = pund;
  930. }
  931. else
  932. {
  933. pund->dwLibMask |= libMask;
  934. pundPrev = pund;
  935. }
  936. pund = pundNext;
  937. }
  938. #endif
  939. /* Try to resolve references */
  940. /* If no modules obtained, exit loop. */
  941. if(!ipnMac)
  942. {
  943. #if NEWIO
  944. if (fLibPass1)
  945. {
  946. /*
  947. * If this library is seen for the first time in
  948. * the first pass thru libraries and we don't
  949. * pull out any modules from it, then close this
  950. * library, because there are big chances this
  951. * library is not needed.
  952. */
  953. if (fFirstTime)
  954. {
  955. _close(mpifhfh[ifhLibCur]);
  956. mpifhfh[ifhLibCur] = 0;
  957. /*
  958. * Mark it also as not used in pass 1
  959. * so, we can closed it also in the
  960. * next passes thru libs.
  961. */
  962. if (fUsedInPass1)
  963. fUsedInPass1[ifhLibCur] = FALSE;
  964. }
  965. }
  966. else if (fUsedInPass1 && !fUsedInPass1[ifhLibCur])
  967. {
  968. /*
  969. * In pass "n" thru libs close libraries
  970. * not used in pass 1.
  971. */
  972. _close(mpifhfh[ifhLibCur]);
  973. mpifhfh[ifhLibCur] = 0;
  974. }
  975. #endif
  976. break;
  977. }
  978. fFirstTime = FALSE; /* No longer first time seen */
  979. /* If extended dictionary present, process it. */
  980. if(pExtDic)
  981. ProcExtDic(pExtDic);
  982. /* Sort modules by page offset. */
  983. qsort(pnSort, ipnMac, sizeof(WORD),
  984. (int (__cdecl *)(const void *, const void *)) FGtNum);
  985. /*
  986. * Save each module represented in the table.
  987. */
  988. for (i = 0; i < ipnMac; i++)
  989. {
  990. /*
  991. * If SaveInput returns 0, the module was already seen. See
  992. * above comment in ProcessAnUndef().
  993. */
  994. if(!SaveInput(sbLibname, (long)pnSort[i] << libAlign, ifhLibCur, 0))
  995. continue;
  996. if(!fFileExtracted) /* If no files extracted yet */
  997. {
  998. vrpNewList = vrpropTailFile;
  999. /* Save start of file list */
  1000. fFileExtracted = (FTYPE) TRUE;
  1001. /* We have extracted a file */
  1002. }
  1003. }
  1004. if(!fFileExtracted)
  1005. break; /* If we didn't take anything, break */
  1006. /* Library might not be open because we may have searched
  1007. * an already-loaded dictionary. If necessary, re-open
  1008. * library.
  1009. */
  1010. if(!vfLibOpen)
  1011. GetLib();
  1012. searchMore = (FTYPE) TRUE; /* Otherwise it's worth another pass */
  1013. vrpTmpFileFirst = rprop1stFile;
  1014. /* Save head of module list */
  1015. rprop1stFile = vrpNewList;
  1016. /* Put new modules at head of list */
  1017. fLibPass = (FTYPE) TRUE; /* Processing object from library */
  1018. DrivePass(ProcP1); /* Do pass 1 on object from library */
  1019. fLibPass = FALSE; /* No longer processing lib. object */
  1020. rprop1stFile = vrpTmpFileFirst;
  1021. /* Restore original head of list */
  1022. if (fUsedInPass1 && ifhLibMacInit < ifhLibMac)
  1023. {
  1024. /* DrivePass added more libraries to search */
  1025. /* Reallocate fUsedInPass1 */
  1026. FTYPE *p; /* Temporary pointer */
  1027. p = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE));
  1028. if (p == NULL)
  1029. {
  1030. FFREE(fUsedInPass1);
  1031. fUsedInPass1 = NULL;
  1032. }
  1033. else
  1034. {
  1035. memset(p, TRUE, ifhLibMac);
  1036. memcpy(p, fUsedInPass1, ifhLibMacInit);
  1037. FFREE(fUsedInPass1);
  1038. fUsedInPass1 = p;
  1039. }
  1040. ifhLibMacInit = ifhLibMac;
  1041. }
  1042. }
  1043. /* Free space for extended dictionary if present */
  1044. if(pExtDic)
  1045. FFREE(pExtDic);
  1046. if(vfLibOpen)
  1047. {
  1048. #if NOT NEWIO
  1049. fclose(bsInput); /* Close the library */
  1050. #endif
  1051. vfLibOpen = FALSE; /* No library open */
  1052. }
  1053. }
  1054. /* No longer on 1st pass thru libraries. */
  1055. fLibPass1 = FALSE;
  1056. }
  1057. while(searchMore && FUndefsLeft()); /* Do until search done */
  1058. FreeMem(fUsedInPass1);
  1059. FreeDictionary(); /* Free dictionary space */
  1060. /*
  1061. * Restore large buffer size in case it was reduced.
  1062. */
  1063. setvbuf(bsInput,bsInput->_base,_IOFBF,LBUFSIZ);
  1064. #if NEW_LIB_SEARCH
  1065. fStoreUndefsInLookaside = FALSE;
  1066. while (pundpoolHead)
  1067. {
  1068. pundpoolCur = pundpoolHead->pNext;
  1069. FFREE(pundpoolHead);
  1070. pundpoolHead = pundpoolCur;
  1071. }
  1072. #endif
  1073. }
  1074. #if CMDMSDOS
  1075. /*
  1076. * GetLibAll:
  1077. *
  1078. * Process all the modules in a given library in Pass 1.
  1079. * Create property cells for them and insert into the file list.
  1080. */
  1081. void NEAR GetLibAll(sbLib)
  1082. BYTE *sbLib;
  1083. {
  1084. WORD ifh; /* (fake) library index */
  1085. long lfa; /* Current file offset */
  1086. IOVTYPE iov; /* Overlay number */
  1087. RBTYPE rbFileNext; /* Pointer to next file property */
  1088. RBTYPE rbFileNew; /* Pointer to new file property */
  1089. APROPFILEPTR apropFile, apropFilePrev;
  1090. BYTE *sbInput; /* Asciiz filename */
  1091. int fh; /* File handle */
  1092. fDrivePass = FALSE;
  1093. sbInput = sbLib + 1;
  1094. /* Get the ifh, iov, and pointer to the next file from the current
  1095. * file pointer.
  1096. */
  1097. apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE);
  1098. ifh = apropFile->af_ifh;
  1099. iov = apropFile->af_iov;
  1100. rbFileNext = apropFile->af_FNxt;
  1101. #if NEWIO
  1102. fh = SmartOpen(sbInput,ifh);
  1103. if (fh <= 0 && lpszLIB != NULL)
  1104. fh = SearchPathLink(lpszLIB, sbInput, ifh, TRUE);
  1105. if (fh > 0)
  1106. {
  1107. fflush(bsInput);
  1108. bsInput->_file = (char) fh;
  1109. }
  1110. else
  1111. Fatal(ER_fileopn,sbInput);
  1112. #else
  1113. if((bsInput = fopen(sbInput,RDBIN)) == NULL)
  1114. Fatal(ER_fileopn,sbInput);
  1115. #endif
  1116. if(getc(bsInput) != LIBHDR) /* Check for valid record type */
  1117. Fatal(ER_badlib,sbInput);
  1118. cbRec = (WORD) (3 + WSGets()); /* Get record length */
  1119. for(libAlign = 15; libAlign && !(cbRec & (1 << libAlign)); --libAlign);
  1120. /* Calculate alignment factor */
  1121. fDrivePass = (FTYPE) TRUE;
  1122. /* Reset current file's lfa from 0 to offset of 1st module */
  1123. apropFile->af_lfa = lfa = 1L << libAlign;
  1124. /* Go to the first module */
  1125. if (fseek(bsInput,lfa,0))
  1126. Fatal(ER_badlib,sbInput);
  1127. /* Process the library as follows: Process the current module.
  1128. * Go to the next module; if it starts with DICHDR then we're
  1129. * done. Else, create a new file property cell for the next
  1130. * module, insert it in the file list, and go to start of loop.
  1131. */
  1132. rect = (WORD) getc(bsInput);
  1133. while (rect != DICHDR)
  1134. {
  1135. ungetc(rect, bsInput);
  1136. lfaLast = apropFile->af_lfa = ftell(bsInput);
  1137. ProcP1();
  1138. while (TYPEOF(rect) != MODEND)
  1139. {
  1140. rect = (WORD) getc(bsInput);
  1141. if (fseek(bsInput, (cbRec = WSGets()), 1))
  1142. Fatal(ER_badlib,sbInput);
  1143. }
  1144. do
  1145. {
  1146. rect = (WORD) getc(bsInput);
  1147. }
  1148. while (rect != THEADR && rect != DICHDR && rect != EOF);
  1149. if (rect == DICHDR)
  1150. {
  1151. if (rbFileNext == RHTENIL)
  1152. vrpropTailFile = vrpropFile;
  1153. #if NOT NEWIO
  1154. fclose(bsInput);
  1155. #else
  1156. rbFilePrev = vrpropFile;
  1157. #endif
  1158. return;
  1159. }
  1160. if (rect == EOF)
  1161. Fatal(ER_libeof);
  1162. // Make a new file property cell
  1163. apropFile = (APROPFILEPTR ) PropAdd(vrhteFile, ATTRFIL);
  1164. rbFileNew = vrprop;
  1165. #if ILINK
  1166. apropFile->af_imod = ++imodCur; // allocate a module number
  1167. apropFile->af_cont = 0;
  1168. apropFile->af_ientOnt = 0;
  1169. #endif
  1170. apropFile->af_rMod = 0;
  1171. apropFile->af_ifh = (char) ifh;
  1172. apropFile->af_iov = (IOVTYPE) iov;
  1173. apropFile->af_FNxt = rbFileNext;
  1174. #if SYMDEB
  1175. apropFile->af_publics = NULL;
  1176. apropFile->af_Src = NULL;
  1177. apropFile->af_SrcLast = NULL;
  1178. apropFile->af_cvInfo = NULL;
  1179. #endif
  1180. apropFile->af_ComDat = 0L;
  1181. apropFile->af_ComDatLast = 0L;
  1182. MARKVP();
  1183. // Get the just-processed property file cell
  1184. apropFilePrev = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE);
  1185. apropFilePrev->af_FNxt = rbFileNew;
  1186. vrpropFile = rbFileNew;
  1187. };
  1188. // Remove an empty Lib from the chain of files
  1189. if (vrpropFile == rprop1stFile)
  1190. {
  1191. // If the empty lib is first on list
  1192. rprop1stFile = rbFileNext;
  1193. }
  1194. else
  1195. {
  1196. #if NEWIO
  1197. apropFilePrev = (APROPFILEPTR)FetchSym(rbFilePrev, TRUE);
  1198. apropFilePrev->af_FNxt = apropFile->af_FNxt;
  1199. #endif
  1200. }
  1201. #if NEWIO
  1202. if (rbFileNext == RHTENIL)
  1203. vrpropTailFile = rbFilePrev; // In case we removed the last file
  1204. _close(fileno(bsInput));
  1205. rbFilePrev = vrpropFile;
  1206. #endif
  1207. }
  1208. #endif /*CMDMSDOS*/