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.

1511 lines
35 KiB

  1. /*****************************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1987-1999 **/
  4. /*****************************************************************************/
  5. /*****************************************************************************
  6. File : filehndl.cxx
  7. Title : file i/o handler for the MIDL compiler. Handles nested
  8. : file accessing, preprocessed file handling etc
  9. Description : Used by the compiler for handling import files, pre-
  10. processing of files etc
  11. History :
  12. 25-Aug-1990 VibhasC Create
  13. 26-Aug-1990 VibhasC Add functionality
  14. *****************************************************************************/
  15. #pragma warning ( disable : 4514 )
  16. /****************************************************************************
  17. *** local defines
  18. ***************************************************************************/
  19. #define MAX_LINE_LENGTH (256)
  20. #define INTERMEDIATE_EXT ("._i")
  21. #define SMART_INCLUDE_STRING ("smart_include")
  22. /****************************************************************************
  23. *** include files
  24. ***************************************************************************/
  25. #include "nulldefs.h"
  26. extern "C"
  27. {
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <process.h>
  32. #include <ctype.h>
  33. #include <errno.h>
  34. #include <malloc.h>
  35. #include <fcntl.h>
  36. #include <sys\types.h>
  37. #include <sys\stat.h>
  38. #include <io.h>
  39. #include <share.h>
  40. }
  41. #include "common.hxx"
  42. #include "errors.hxx"
  43. #include "filehndl.hxx"
  44. #include "cmdana.hxx"
  45. #include "control.hxx"
  46. #include "linenum.hxx"
  47. #include "midlvers.h"
  48. /****************************************************************************
  49. *** public data
  50. ***************************************************************************/
  51. short DebugLine = 0;
  52. char * pDebugFile;
  53. int StdoutSave = -1;
  54. int StderrSave = -1;
  55. FILE * pNullFile = NULL;
  56. /****************************************************************************
  57. *** extern procs
  58. ***************************************************************************/
  59. extern void StripSlashes( char * );
  60. extern void ChangeToForwardSlash( char *, char * );
  61. extern STATUS_T CreateFullPathAndFName( char *, char **, char ** );
  62. extern "C" long __stdcall GetTempPathA( long, char * );
  63. extern "C" long __stdcall GetTempFileNameA( const char*, const char*, unsigned int, char * );
  64. /****************************************************************************
  65. *** extern data
  66. ***************************************************************************/
  67. extern CCONTROL * pCompiler;
  68. extern CMD_ARG * pCommand;
  69. extern short curr_line_G;
  70. extern FILE * hFile_G;
  71. extern BOOL fRedundantImport;
  72. /*** _nfa_info *************************************************************
  73. * Purpose : constructor for the _nfa_info class
  74. * Input : nothing
  75. * Output :
  76. * Notes : Initialize
  77. ***************************************************************************/
  78. _nfa_info::_nfa_info( void )
  79. {
  80. BOOL fMinusIDefined = pCommand->IsSwitchDefined(SWITCH_I);
  81. BOOL fNoDefIDirDefined = pCommand->IsSwitchDefined(SWITCH_NO_DEF_IDIR);
  82. char * pDefault = ".";
  83. char * pEnv = (char *)0;
  84. char * pIPaths = (char *)0;
  85. char * p1 = (char *)0;
  86. char * p2 = (char *)0;
  87. char * p3 = (char *)0;
  88. /***
  89. *** init
  90. ***/
  91. pFileList = 0;
  92. pPathList = (PATH_LIST *)NULL;
  93. pStack = pStackFirst= (IN_STACK_ELEMENT *)NULL;
  94. iCurLexLevel = 0;
  95. Flags.fPreProcess = 0;
  96. Flags.fFileSet = 0;
  97. Flags.fEOI = 0;
  98. Flags.fBaseFileName= 0;
  99. Flags.fInInclude = 0;
  100. // macro expansion handling
  101. pTextDict = new ISTACK( 10 );
  102. // init the search paths. If the -no_def-idir switch is defined, then
  103. // dont set the default paths. But if the -no_def_idir switch IS defined,
  104. // then if the -I switch is not found, set the current path to .
  105. if ( fMinusIDefined )
  106. pIPaths = pCommand->GetMinusISpecification();
  107. if ( ( pEnv = getenv( "INCLUDE" ) ) == 0 )
  108. pEnv = getenv( "include" );
  109. //
  110. // make a copy of this because we will be doing strtoks on this.
  111. //
  112. if( pEnv )
  113. {
  114. // use p1 as temp;
  115. p1 = new char [ strlen( pEnv ) + 1 ];
  116. strcpy( p1, pEnv );
  117. pEnv = p1;
  118. }
  119. p1 = pDefault;
  120. p2 = pIPaths;
  121. p3 = pEnv;
  122. if( fNoDefIDirDefined && fMinusIDefined )
  123. {
  124. p1 = p3 = (char *)0;
  125. }
  126. else if( fNoDefIDirDefined && !fMinusIDefined )
  127. {
  128. p2 = p3 = (char *)0;
  129. }
  130. else if( !fNoDefIDirDefined && !fMinusIDefined )
  131. {
  132. p1 = pDefault;
  133. p2 = (char *)0;
  134. p3 = pEnv;
  135. }
  136. SetSearchPathsInOrder( p1, p2, p3 );
  137. if( pIPaths ) delete pIPaths;
  138. //
  139. // we have made a copy of the env variable, so we can delete this copy
  140. // now.
  141. //
  142. if( pEnv ) delete pEnv;
  143. }
  144. void
  145. _nfa_info::Init()
  146. {
  147. CMD_ARG * pCommandProcessor = pCompiler->GetCommandProcessor();
  148. // set preprocessing on or off depending upon the need
  149. if( !pCommandProcessor->IsSwitchDefined( SWITCH_NO_CPP ) )
  150. SetPreProcessingOn();
  151. }
  152. void
  153. _nfa_info::SetSearchPathsInOrder(
  154. char * p1,
  155. char * p2,
  156. char * p3 )
  157. {
  158. if( p1 )
  159. RegisterIt( p1 );
  160. if( p2 )
  161. RegisterIt( p2 );
  162. if( p3 )
  163. RegisterIt( p3 );
  164. }
  165. void
  166. _nfa_info::RegisterIt(
  167. char * pPath
  168. )
  169. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  170. Routine Description:
  171. register command paths.
  172. Arguments:
  173. pPath - pointer to path bein registered.
  174. Return Value:
  175. None.
  176. Notes:
  177. We expect the path components to be separated by a ';'. register those
  178. with the import controller. This function must become part of the import
  179. controller class.
  180. ----------------------------------------------------------------------------*/
  181. {
  182. #define TOKEN_STRING (";")
  183. char * pToken = strtok( pPath, TOKEN_STRING );
  184. if( pToken )
  185. {
  186. SetPath( pToken );
  187. while ( ( pToken = strtok( 0, TOKEN_STRING ) ) != 0 )
  188. {
  189. SetPath( pToken );
  190. }
  191. }
  192. }
  193. void
  194. _nfa_info::RegisterTextSubsObject( TEXT_BUFFER* )
  195. {
  196. MIDL_ASSERT(0);
  197. }
  198. _nfa_info::~_nfa_info()
  199. {
  200. EndOperations();
  201. }
  202. /*** GetLexLevel **********************************************************
  203. * Purpose : to return the current lexical level of the nfa
  204. * Input : nothing
  205. * Output : current lexical level
  206. * Notes :
  207. **************************************************************************/
  208. short
  209. NFA_INFO::GetLexLevel( void )
  210. {
  211. return iCurLexLevel;
  212. }
  213. /*** PushLexLevel **********************************************************
  214. * Purpose : push lexical level in preparation of a new input file
  215. * Input : nothing
  216. * Output : 0 if all is well, error otherwise.
  217. * Notes :
  218. **************************************************************************/
  219. short
  220. NFA_INFO::PushLexLevel ( void )
  221. {
  222. // if an attempt to push the lexical level without opening any file
  223. // at that level was made, assert
  224. MIDL_ASSERT( Flags.fFileSet == 1 );
  225. // if we are in a deep imports heirarchy,
  226. // close the current file, record its position so that we can start
  227. // reading at the same place when we come back to it on a poplexlevel
  228. if ( iCurLexLevel > 12 )
  229. {
  230. pStack->ulPos = ftell( pStack->hFile );
  231. fclose(pStack->hFile);
  232. pStack->fOpen = 0;
  233. }
  234. Flags.fFileSet = 0;
  235. iCurLexLevel++;
  236. return 0;
  237. }
  238. /*** PopLexLevel **********************************************************
  239. * Purpose : pop the lexical level
  240. * Input : nothing
  241. * Output : returns STATUS_OK if all is well.Error otherwise
  242. * Notes : pop involves, re-opening the input file, if it was closed
  243. * : retsoring the input file handle back, deleting the stack
  244. * : element for that lexical level.
  245. *************************************************************************/
  246. STATUS_T
  247. NFA_INFO::PopLexLevel( void )
  248. {
  249. IN_STACK_ELEMENT * pCurStack;
  250. char * pName;
  251. MIDL_ASSERT( iCurLexLevel > 0 );
  252. //
  253. // remove the current stack level, by closing the file at that
  254. // level and deleting the stack element. reduce the current lexical
  255. // level by one
  256. //
  257. iCurLexLevel--;
  258. if( ! pStack->fRedundantImport )
  259. {
  260. EndOneOperation( pStack );
  261. }
  262. else // close the nul file
  263. {
  264. // if ( pStack->hFile && pStack->fOpen && )
  265. // fclose( pStack->hFile );
  266. }
  267. pCurStack = pStack = pStack->pPrev;
  268. delete pStack->pNext;
  269. pStack->pNext = (IN_STACK_ELEMENT *)NULL;
  270. //
  271. // if the file at this lexical level is closed, open it
  272. //
  273. pName = pStack->pName;
  274. if( !pStack->fOpen )
  275. {
  276. if( (pStack->hFile = fopen( pStack->pIFileName, "rb" )) == (FILE *)NULL)
  277. {
  278. RpcError((char *)NULL, 0, INPUT_OPEN, pName);
  279. return INPUT_OPEN;
  280. }
  281. if ( !pStack->pBuffer )
  282. pStack->pBuffer = new char [MIDL_RD_BUFSIZE];
  283. setvbuf( pStack->hFile, pStack->pBuffer,_IOFBF, MIDL_RD_BUFSIZE );
  284. // restore the system-wide file handle
  285. pStack->fOpen = 1;
  286. // the input file is open now, position it to where it was before
  287. // we changed current lexical level
  288. if( fseek( pStack->hFile, pStack->ulPos, SEEK_SET) )
  289. {
  290. RpcError((char *)NULL, 0, INPUT_READ, pName);
  291. return INPUT_READ;
  292. }
  293. }
  294. // update the line number information, and set current file
  295. curr_line_G = pStack->uLine;
  296. hFile_G = pStack->hFile;
  297. AddFileToDB( pName );
  298. // everything is fine , lets go
  299. return STATUS_OK;
  300. }
  301. STATUS_T
  302. NFA_INFO::EndOperations()
  303. {
  304. IN_STACK_ELEMENT * pS = pStackFirst;
  305. while( pStackFirst = pS )
  306. {
  307. EndOneOperation( pS );
  308. pS = pS->pNext;
  309. delete pStackFirst;
  310. }
  311. pStackFirst = pStack = (IN_STACK_ELEMENT *)0;
  312. Flags.fFileSet = 0;
  313. return STATUS_OK;
  314. }
  315. STATUS_T
  316. NFA_INFO::EndOneOperation( IN_STACK_ELEMENT * pSElement)
  317. {
  318. BOOL fSavePP = pCommand->IsSwitchDefined( SWITCH_SAVEPP );
  319. if( pSElement && pSElement->hFile )
  320. {
  321. fclose( pSElement->hFile );
  322. if( Flags.fPreProcess && !fSavePP )
  323. {
  324. MIDL_UNLINK( pSElement->pIFileName );
  325. delete pSElement->pIFileName;
  326. }
  327. if( pSElement->pMIFileName && !fSavePP )
  328. {
  329. MIDL_UNLINK( pSElement->pMIFileName );
  330. delete pSElement->pMIFileName;
  331. }
  332. }
  333. return STATUS_OK;
  334. }
  335. /*** SetNewInputFile *******************************************************
  336. * Purpose : to set the input file to a new one
  337. * Input : pointer to the new input file name
  338. * Output : STATUS_OK if all is ok, error otherwise.
  339. * Notes :
  340. **************************************************************************/
  341. #define _MAX_FILE_NAME (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
  342. STATUS_T
  343. NFA_INFO::SetNewInputFile(
  344. char *pFullInputName)
  345. {
  346. FILE *hFile = (FILE *)NULL;
  347. STATUS_T uError;
  348. IN_STACK_ELEMENT *pStackCur = pStack;
  349. char agNameBuf[ _MAX_FILE_NAME + 1];
  350. char agDrive[_MAX_DRIVE];
  351. char agPath[_MAX_DIR];
  352. char agName[_MAX_FNAME];
  353. char agExt[_MAX_EXT];
  354. char *pPath;
  355. char *pIFileName = (char *)NULL,
  356. *pMIFileName = (char *) NULL;
  357. char *pFullName = new char[ strlen( pFullInputName ) + 1];
  358. // make sure everything opened in binary mode
  359. _fmode = _O_BINARY;
  360. //
  361. // if the filename has any forward slashes, change them to back-slashes.
  362. //
  363. ChangeToForwardSlash( pFullInputName, pFullName );
  364. // if we have seen this file before, do not process it again, just return
  365. // an error
  366. if( IsDuplicateInput( pFullName ) )
  367. {
  368. pStack = new IN_STACK_ELEMENT;
  369. if(pStackCur)
  370. {
  371. pStackCur->pNext = pStack;
  372. pStack->pPrev = pStackCur;
  373. pStackCur->uLine = curr_line_G;
  374. }
  375. else
  376. {
  377. pStack->pPrev = (IN_STACK_ELEMENT *)NULL;
  378. pStackFirst = pStack;
  379. }
  380. pStack->pNext = (IN_STACK_ELEMENT *)NULL;
  381. pStack->fNewLine = 0;
  382. pStack->fRedundantImport = 1;
  383. fRedundantImport = 1;
  384. // make the next read get eof
  385. if ( !pNullFile )
  386. {
  387. pNullFile = fopen("nul", "rb");
  388. hFile = 0;
  389. }
  390. // fseek(hFile, 0, SEEK_END );
  391. pStack->fOpen = 1;
  392. pStack->fShadow = 0;
  393. pStack->ulPos =
  394. pStack->uShadowLine = 0;
  395. curr_line_G = 1;
  396. pStack->pShadowName =
  397. pStack->pName = pFullName;
  398. pStack->pIFileName = pIFileName;
  399. pStack->hFile = hFile;
  400. hFile_G = pNullFile;
  401. Flags.fFileSet = 1;
  402. return STATUS_OK;
  403. }
  404. // We need to find details of the file name. We need to see if the user
  405. // has already specified path, if so, override the current paths.
  406. // if the user has specified a file extension, get the extension. We
  407. // need to do that in order to have uniformity with the case where
  408. // a preprocessed file is input with a different extension
  409. _splitpath( pFullName, agDrive, agPath, agName, agExt );
  410. // fprintf( stdout, "Processing %s:\n", pFullName);
  411. // if file is specified with a path, the user knows fully the location
  412. // else search for the path of the file
  413. pPath = agPath;
  414. if( !*pPath && !agDrive[0] )
  415. {
  416. sprintf(agNameBuf, "%s%s", agName, agExt);
  417. if( (pPath = SearchForFile(agNameBuf)) == (char *)NULL)
  418. {
  419. RpcError((char *)NULL, 0, INPUT_OPEN, agNameBuf);
  420. return INPUT_OPEN;
  421. }
  422. strcpy(agPath, pPath);
  423. }
  424. else
  425. {
  426. // there is a path specification, which we must tag to this name
  427. // for all subsequent accesses to the file although it should not
  428. // be considered as part of the list of paths the user gave.
  429. // Remember, in our file list we store the paths too
  430. pPath = new char[ strlen(agPath) + 1];
  431. strcpy( pPath, agPath );
  432. }
  433. // do we need to preprocess the file ?
  434. if ( pCommand->Is64BitEnv() )
  435. fprintf( stdout, "64 bit " );
  436. fprintf( stdout, "Processing " );
  437. if( agDrive[0] )
  438. fprintf( stdout, "%s", agDrive );
  439. if( agPath[0] )
  440. fprintf( stdout, "%s", agPath );
  441. if( agName[0] )
  442. fprintf( stdout, "%s", agName );
  443. if( agExt[0] )
  444. fprintf( stdout, "%s", agExt );
  445. fprintf( stdout, "\n" );
  446. fflush( stdout );
  447. if (Flags.fPreProcess)
  448. {
  449. if ( ( uError = PreProcess( agDrive, agPath, agName, agExt, pIFileName) ) != 0 )
  450. return uError;
  451. }
  452. else // if no_cpp...
  453. {
  454. pIFileName = new char [ strlen( agDrive ) +
  455. strlen( agPath ) +
  456. strlen( agName ) +
  457. strlen( agExt ) + 2 ];
  458. strcpy( pIFileName, agDrive );
  459. strcat( pIFileName, agPath);
  460. if( agPath[0] && (agPath[ strlen(agPath)-1 ] != '\\'))
  461. strcat(pIFileName,"\\");
  462. strcat( pIFileName, agName );
  463. strcat( pIFileName, agExt );
  464. }
  465. if( (hFile = fopen(pIFileName, "rb")) == (FILE *)NULL)
  466. {
  467. // error obtained while reading file, return the error
  468. RpcError((char *)NULL, 0, INPUT_OPEN, pIFileName);
  469. return INPUT_OPEN;
  470. }
  471. // file was sucessfully opened, initialize its info
  472. // if a file has not been set at this nested level , a stack element
  473. // must be allocated for it. else the current file must be closed
  474. if( ! Flags.fFileSet )
  475. {
  476. pStack = new IN_STACK_ELEMENT;
  477. if(pStackCur)
  478. {
  479. pStackCur->pNext = pStack;
  480. pStack->pPrev = pStackCur;
  481. pStackCur->uLine = curr_line_G;
  482. }
  483. else
  484. {
  485. pStack->pPrev = (IN_STACK_ELEMENT *)NULL;
  486. pStackFirst = pStack;
  487. }
  488. pStack->pNext = (IN_STACK_ELEMENT *)NULL;
  489. pStack->fNewLine = 1;
  490. Flags.fFileSet = 1;
  491. }
  492. else
  493. {
  494. // file was set. That means input was coming from a file. Close
  495. // that file.
  496. fclose(pStack->hFile);
  497. }
  498. if ( !pStack->pBuffer )
  499. pStack->pBuffer = new char [MIDL_RD_BUFSIZE];
  500. setvbuf( hFile, pStack->pBuffer,_IOFBF, MIDL_RD_BUFSIZE );
  501. pStack->fOpen = 1;
  502. pStack->fRedundantImport = 0;
  503. fRedundantImport = 0;
  504. pStack->fShadow = 0;
  505. pStack->uShadowLine = 0;
  506. curr_line_G = 1;
  507. pStack->pShadowName =
  508. pStack->pName = pFullName;
  509. pStack->pIFileName = pIFileName;
  510. pStack->pMIFileName = pMIFileName;
  511. pStack->hFile = hFile;
  512. hFile_G = hFile;
  513. // update the line number information, and set current file
  514. AddFileToDB( pFullName );
  515. // add the file to the list of files that we have seen
  516. AddFileToFileList(pFullName, pPath);
  517. return STATUS_OK;
  518. }
  519. /*** SetLineFilename ******************************************************
  520. * Purpose : to add filename to the list of files we have input from
  521. * Input : filename to add to the list of files, file path
  522. * Output : STATUS_OK if all is well, error otherwise
  523. * Notes :
  524. ****************************************************************************/
  525. void
  526. NFA_INFO::SetLineFilename(
  527. char * pFName
  528. )
  529. {
  530. if(strcmp(pFName, pStack->pName) != 0)
  531. {
  532. pStack->pName = new char[strlen( pFName ) + 1 ];
  533. strcpy(pStack->pName, pFName);
  534. // update the line number information, and set current file
  535. AddFileToDB( pStack->pName );
  536. }
  537. }
  538. /*** AddFileToFileList ******************************************************
  539. * Purpose : to add filename to the list of files we have input from
  540. * Input : filename to add to the list of files, file path
  541. * Output : STATUS_OK if all is well, error otherwise
  542. * Notes :
  543. ****************************************************************************/
  544. STATUS_T
  545. NFA_INFO::AddFileToFileList(
  546. char *pName ,
  547. char *pPath )
  548. {
  549. FNAME_LIST *pList = pFileList;
  550. FNAME_LIST *pTemp;
  551. char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
  552. char * pN;
  553. char * pP;
  554. STATUS_T Status;
  555. char agDrive[_MAX_DRIVE];
  556. char agPath[_MAX_DIR];
  557. char agName[_MAX_FNAME];
  558. char agExt[_MAX_EXT];
  559. BOOL fNameHadNoPath = FALSE;
  560. #if 1
  561. _splitpath( pName, agDrive, agPath, agName, agExt );
  562. //
  563. // if the filename came with a path component choose that to add to the file
  564. // list else use the path parameter.
  565. //
  566. strcpy( agNameBuf, agDrive );
  567. strcat( agNameBuf, agPath );
  568. fNameHadNoPath = strlen( agNameBuf ) == 0;
  569. if ( fNameHadNoPath )
  570. strcpy( agNameBuf, pPath );
  571. if( pPath[ strlen(pPath) - 1] != '\\' )
  572. strcat( agNameBuf, "\\" );
  573. //
  574. // if the filename had a path component, then dont use that name, use the
  575. // name provided by splitpath.
  576. //
  577. if( fNameHadNoPath )
  578. strcat( agNameBuf, pName );
  579. else
  580. {
  581. strcat( agNameBuf, agName );
  582. strcat( agNameBuf, agExt );
  583. }
  584. if( (Status = CreateFullPathAndFName( agNameBuf, &pP, &pN )) != STATUS_OK )
  585. return OUT_OF_MEMORY;
  586. #endif // 1
  587. while(pList && pList->pNext) pList = pList->pNext;
  588. if ( (pTemp = new FNAME_LIST) == 0 )
  589. return OUT_OF_MEMORY;
  590. if(pList)
  591. pList->pNext = pTemp;
  592. else
  593. pFileList = pTemp;
  594. pList = pTemp;
  595. pList->pName = pN;
  596. pList->pPath = pP;
  597. pList->pNext = (FNAME_LIST *)NULL;
  598. return STATUS_OK;
  599. }
  600. STATUS_T
  601. CreateFullPathAndFName( char * pInput, char **ppPOut, char **ppNOut )
  602. {
  603. char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
  604. char agDrive[_MAX_DRIVE];
  605. char agPath[_MAX_DIR];
  606. char agName[_MAX_FNAME];
  607. char agExt[_MAX_EXT];
  608. _fullpath( agNameBuf, pInput,_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1);
  609. _splitpath( agNameBuf, agDrive, agPath, agName, agExt );
  610. strcpy( agNameBuf, agDrive );
  611. strcat( agNameBuf, agPath );
  612. *ppPOut = new char [strlen( agNameBuf ) + 1];
  613. strcpy( *ppPOut, agNameBuf );
  614. strcpy( agNameBuf, agName );
  615. strcat( agNameBuf, agExt );
  616. *ppNOut = new char [strlen( agNameBuf ) + 1];
  617. strcpy( *ppNOut, agNameBuf );
  618. return STATUS_OK;
  619. }
  620. BOOL
  621. NFA_INFO::IsDuplicateInput(
  622. char * pThisName)
  623. {
  624. FNAME_LIST *pList = pFileList;
  625. char * pN;
  626. char * pP;
  627. BOOL f = FALSE;
  628. char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
  629. char agDrive[_MAX_DRIVE];
  630. char agPath[_MAX_DIR];
  631. char agName[_MAX_FNAME];
  632. char agExt[_MAX_EXT];
  633. //
  634. // if the file did not come with a path component, then try the normal
  635. // search for file.
  636. //
  637. _splitpath( pThisName, agDrive, agPath, agName, agExt );
  638. strcpy( agNameBuf, agDrive );
  639. strcat( agNameBuf, agPath );
  640. if( strlen( agNameBuf ) == 0 )
  641. {
  642. if ( ( pP = SearchForFile( pThisName ) ) != 0 )
  643. {
  644. strcpy( agNameBuf, pP );
  645. strcat( agNameBuf, pThisName );
  646. }
  647. else
  648. {
  649. strcpy( agNameBuf, pThisName );
  650. }
  651. }
  652. else
  653. strcpy( agNameBuf, pThisName );
  654. CreateFullPathAndFName( agNameBuf, &pP, &pN );
  655. while( pList && pList->pName )
  656. {
  657. if( (_stricmp( pList->pName , pN ) == 0 ) &&
  658. (_stricmp( pList->pPath , pP ) == 0 )
  659. )
  660. {
  661. f = TRUE;
  662. break;
  663. }
  664. pList = pList->pNext;
  665. }
  666. delete pN;
  667. delete pP;
  668. return f;
  669. }
  670. /*** SetPath *****************************************************************
  671. * Purpose : to add a string to the list of possible paths
  672. * Input : path to add to the list of paths
  673. * Output : STATUS_OK if all is well, error otherwise
  674. * Notes :
  675. ****************************************************************************/
  676. STATUS_T
  677. NFA_INFO::SetPath(
  678. char *pPath )
  679. {
  680. PATH_LIST *pList = pPathList;
  681. PATH_LIST *pTemp;
  682. size_t Len;
  683. while(pList && pList->pNext) pList = pList->pNext;
  684. if ( (pTemp = new PATH_LIST) == 0 )
  685. return OUT_OF_MEMORY;
  686. if(pList)
  687. pList->pNext = pTemp;
  688. else
  689. pPathList = pTemp;
  690. #if 0
  691. // The user could specify a path using a leading space, for example, he can
  692. // specify the -I with a leading space. Even tho the -I should be presented
  693. // to the user with the leading space, we should not get confused. We omit
  694. // leading spaces.
  695. while( isspace( *pPath ) ) pPath++;
  696. #endif
  697. pList = pTemp;
  698. pList->pPath = new char[ (Len = strlen(pPath)) + 2];// one possible "\\"
  699. pList->pNext = (PATH_LIST *)NULL;
  700. strcpy( pList->pPath, pPath );
  701. if( Len && (pPath[ Len - 1 ] != '\\' ) )
  702. strcat( pList->pPath, "\\");
  703. return STATUS_OK;
  704. }
  705. /*** SetPreProcessingOn *****************************************************
  706. * Purpose : to set preprocessing on
  707. * Input : nothing
  708. * Output : STATUS_OK if all is well, error otherwise
  709. * Notes : Set the preprocessing flag on. This denotes that preprocessing
  710. * : will be on for all the files that are input to the compiler
  711. ****************************************************************************/
  712. STATUS_T
  713. NFA_INFO::SetPreProcessingOn(void)
  714. {
  715. Flags.fPreProcess = 1;
  716. return STATUS_OK;
  717. }
  718. /*** SearchForFile ********************************************************
  719. * Purpose : to search for a file in a previously registered set of paths
  720. * Input : file name
  721. * Output : (char *)NULL if the file was not found in the given set of paths
  722. * : else a pointer to the path where it was found
  723. * Notes :
  724. *************************************************************************/
  725. char *
  726. NFA_INFO::SearchForFile(
  727. char *pName)
  728. {
  729. PATH_LIST *pPathTemp = pPathList;
  730. char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
  731. // the name is guaranteed not to have path or drive info, just the
  732. // base name and extension. We must figure out the paths, from
  733. // the list of paths that we have registered so far
  734. while(pPathTemp)
  735. {
  736. sprintf(agNameBuf, "%s%s", pPathTemp->pPath, pName);
  737. // check for existence only. The read errors need to be checked
  738. // only at read time.
  739. if( _access( agNameBuf, 0 ) == 0 )
  740. return pPathTemp->pPath;
  741. pPathTemp = pPathTemp->pNext;
  742. }
  743. // we did not find the file, return an error
  744. return (char *)NULL;
  745. }
  746. /*** PreProcess ************************************************************
  747. * Purpose : to preprocess the given file into an intermediate file
  748. * Input : drive, path, name and current extension of the file
  749. * Output : STATUS_OK if all is well, error otherwise
  750. * Notes : The c compiler uses the /E switch to generate the
  751. * : the preprocessed output with line numbers to a file.
  752. * : Now the way to do the preprocessing is to spawn the
  753. * : c compiler with the /E switch. But we need to redirect the
  754. * : output to a file. To force the spawnee to redirect, we
  755. * : must also do the redirection in this process, so that the
  756. * : spawnee inherits our file handles.
  757. **************************************************************************/
  758. STATUS_T
  759. NFA_INFO::PreProcess(
  760. char *pDrive,
  761. char *pPath,
  762. char *pName,
  763. char *pExt,
  764. char *&pIFileName )
  765. {
  766. STATUS_T Status = STATUS_OK;
  767. char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
  768. char * pCppCmd = (pCompiler->GetCommandProcessor())->GetCPPCmd();
  769. char * pCppOptions;
  770. char * pCppBaseOptions;
  771. intptr_t SpawnError;
  772. int IFHandle;
  773. BOOL fStderrSaved = FALSE;
  774. FILE * hIFile;
  775. int XHandle;
  776. FILE * hXHandle = 0;
  777. BOOL fEraseFile = FALSE;
  778. char TempPathBuffer[1000];
  779. // build up the arguments
  780. strcpy( agNameBuf, "\"" );
  781. strcat( agNameBuf, pDrive );
  782. strcat(agNameBuf,pPath);
  783. if( *pPath && (pPath[ strlen(pPath)-1 ] != '\\'))
  784. strcat(agNameBuf,"\\");
  785. strcat( agNameBuf, pName );
  786. strcat( agNameBuf, pExt );
  787. strcat( agNameBuf, "\"" );
  788. pCppBaseOptions = pCommand->GetCPPOpt();
  789. pCppOptions = new char[ strlen( pCppBaseOptions ) + 40 ];
  790. int nVersion = ( rmj * 100 ) + ( rmm % 100 );
  791. if (pCommand->IsSwitchDefined(SWITCH_MKTYPLIB))
  792. {
  793. sprintf(pCppOptions, "-D__midl=%d -D__MKTYPLIB__=%d ", nVersion, nVersion );
  794. }
  795. else
  796. {
  797. sprintf(pCppOptions, "-D__midl=%d ", nVersion );
  798. }
  799. strcat( pCppOptions, pCppBaseOptions );
  800. // generate the name of the intermediate file into a buffer
  801. // pIFileName = _tempnam( NULL, "MIDL" );
  802. GetTempPathA( 1000, TempPathBuffer );
  803. pIFileName = new char[1000];
  804. if ( GetTempFileNameA( TempPathBuffer, "MIDL", 0, pIFileName ) == 0)
  805. {
  806. RpcError( (char *)NULL,
  807. 0,
  808. Status = INTERMEDIATE_FILE_CREATE,
  809. TempPathBuffer);
  810. return Status;
  811. }
  812. // printf("Intermediary files\n filename is %s\n agNameBuf is %s\n pCppOptions is %s\n", pIFileName, agNameBuf, pCppOptions );
  813. // open the intermediate file for writing.
  814. if( (hIFile = _fsopen( pIFileName, "w", SH_DENYWR )) == (FILE *)0 )
  815. {
  816. RpcError( (char *)NULL,
  817. 0,
  818. Status = INTERMEDIATE_FILE_CREATE,
  819. pIFileName);
  820. return Status;
  821. }
  822. IFHandle = MIDL_FILENO( hIFile );
  823. // save the current stdout handle
  824. if ( StdoutSave == -1 )
  825. {
  826. if( (StdoutSave = _dup(1)) == -1 )
  827. {
  828. RpcError( (char *)NULL,
  829. 0,
  830. Status = OUT_OF_SYSTEM_FILE_HANDLES,
  831. (char *)NULL);
  832. return Status;
  833. }
  834. }
  835. // now force the stdout to refer to the intermediate file handle,
  836. // thus establishing redirection.
  837. if( _dup2( IFHandle, 1 ) == -1 )
  838. {
  839. RpcError( (char *)NULL,
  840. 0,
  841. Status = OUT_OF_SYSTEM_FILE_HANDLES,
  842. (char *)NULL);
  843. return Status;
  844. }
  845. if( pCommand->IsSwitchDefined(SWITCH_X) )
  846. {
  847. fStderrSaved = TRUE;
  848. if( (hXHandle = fopen( "nul", "w" ) ) == (FILE *)0 )
  849. {
  850. RpcError( (char *)NULL,
  851. 0,
  852. Status = INTERMEDIATE_FILE_CREATE,
  853. "nul");
  854. return Status;
  855. }
  856. XHandle = MIDL_FILENO( hXHandle );
  857. // save the current stderr handle
  858. StderrSave = -1;
  859. if( (StderrSave = _dup(2)) == -1 )
  860. {
  861. RpcError( (char *)NULL,
  862. 0,
  863. Status = OUT_OF_SYSTEM_FILE_HANDLES,
  864. (char *)NULL);
  865. return Status;
  866. }
  867. // now force the stdout to refer to the intermediate file handle,
  868. // thus establishing redirection.
  869. if( _dup2( XHandle, 2 ) == -1 )
  870. {
  871. RpcError( (char *)NULL,
  872. 0,
  873. Status = OUT_OF_SYSTEM_FILE_HANDLES,
  874. (char *)NULL);
  875. return Status;
  876. }
  877. }
  878. // From now on, stdout is no longer stdout, till we restore it back.
  879. // thus if there are intermediate errors, stdout MUST be restored
  880. // before returning.
  881. // From now on, stderr is no longer stderr, till we restore it back.
  882. // stderr MUST be restored before returning.
  883. SpawnError = MIDL_SPAWNLP( P_WAIT
  884. ,pCppCmd
  885. ,pCppCmd
  886. ,pCppOptions
  887. ,agNameBuf
  888. ,(char *)NULL );
  889. delete pCppOptions;
  890. // before doing anything, close the intermediate file handle
  891. fclose( hIFile );
  892. // restore the stdout back
  893. _dup2( StdoutSave, 1 );
  894. if( fStderrSaved )
  895. {
  896. fclose( hXHandle );
  897. _dup2( StderrSave, 2 );
  898. }
  899. if( SpawnError == -1 )
  900. {
  901. switch( errno )
  902. {
  903. case ENOMEM:
  904. Status = OUT_OF_MEMORY;
  905. break;
  906. case ENOENT:
  907. Status = NO_PREPROCESSOR;
  908. break;
  909. case ENOEXEC:
  910. Status = PREPROCESSOR_INVALID;
  911. break;
  912. default:
  913. Status = PREPROCESSOR_EXEC;
  914. break;
  915. }
  916. RpcError((char *)NULL, 0, Status , pCppCmd);
  917. fEraseFile = TRUE;
  918. }
  919. else if( SpawnError )
  920. {
  921. char buf[10];
  922. sprintf(buf, "(%d)", SpawnError );
  923. RpcError((char *)NULL, 0, Status = PREPROCESSOR_ERROR, buf);
  924. fEraseFile = TRUE;
  925. }
  926. if( fEraseFile )
  927. {
  928. MIDL_UNLINK( pIFileName );
  929. }
  930. return Status;
  931. }
  932. /*** GetChar ****************************************************************
  933. * Purpose : get a character from the input stream
  934. * Input : nothing
  935. * Output : a character from the file
  936. * Notes : returns 0 if at end of file
  937. ****************************************************************************/
  938. short
  939. NFA_INFO::GetChar( void )
  940. {
  941. short ch;
  942. if( pStack->fRedundantImport )
  943. {
  944. fRedundantImport = TRUE;
  945. return 0x0;
  946. }
  947. if( !Flags.fFileSet || !pStack->fOpen) return 0;
  948. if( ( (ch=(short)getc(pStack->hFile)) == EOF ) && feof(pStack->hFile) )
  949. return 0;
  950. #if 0
  951. // if the line starts off with a '#', it may be a line number
  952. // indicator.
  953. if(pStack->fNewLine && (ch == '#'))
  954. {
  955. unsigned long SavePos = ftell(pStack->hFile);
  956. char buffer[_MAX_DRIVE + _MAX_PATH + _MAX_FNAME + _MAX_EXT ];
  957. short Count = 0;
  958. short fLinePresent = 0;
  959. // it coule be a # <space> number or #line <space> number
  960. while( (ch = getc( pStack->hFile ) ) == ' ' );
  961. if( isdigit( ch ) )
  962. {
  963. fLinePresent = 1;
  964. }
  965. else
  966. {
  967. buffer[ Count++ ] = (char)ch;
  968. // if it is #line, the first 5 characters will be #line
  969. while(Count < 4)
  970. buffer[Count++] = (char) getc(pStack->hFile);
  971. buffer[Count] = '\0';
  972. fLinePresent = (strcmp( buffer, "line" ) == 0 );
  973. if( fLinePresent )
  974. while( (ch = getc( pStack->hFile )) == ' ' );
  975. }
  976. if( fLinePresent )
  977. {
  978. Count = 0;
  979. do
  980. {
  981. buffer[Count++] = (char) ch;
  982. } while( (ch = getc(pStack->hFile)) != ' ');
  983. buffer[Count] = '\0';
  984. // line to be seen now is the line number indicated.
  985. // but the line number indicator is on a line
  986. // previous to that it indicates, so reflect that in
  987. // the line number
  988. pStack->uLine = atoi(buffer) - 1;
  989. while( (ch=getc(pStack->hFile)) == ' ');
  990. Count = 0;
  991. // buffer[Count++] = ch;
  992. // fgetc(pStack->hFile); // skip the quote
  993. if(ch == '\"')
  994. {
  995. while( (ch=getc(pStack->hFile)) != '\"')
  996. {
  997. buffer[Count++] = (char) ch;
  998. }
  999. buffer[Count] = 0;
  1000. // make the collected filename as the new name
  1001. StripSlashes( buffer );
  1002. if(strcmp(buffer, pStack->pName) != 0)
  1003. {
  1004. pStack->pName = new char[Count+1];
  1005. strcpy(pStack->pName, buffer);
  1006. // update the line number information, and set current file
  1007. AddFileToDB( pStack->pName );
  1008. }
  1009. }
  1010. while( (ch = getc( pStack->hFile )) != '\n');
  1011. goto newline;
  1012. }
  1013. else
  1014. {
  1015. fseek(pStack->hFile, SavePos, SEEK_SET);
  1016. ch = '#';
  1017. }
  1018. }
  1019. newline:
  1020. if(ch == '\n')
  1021. {
  1022. DebugLine = pStack->uLine++;
  1023. pDebugFile= pStack->pName;
  1024. pStack->fNewLine = 1;
  1025. }
  1026. else
  1027. {
  1028. // leave fNewLine set for leading white space
  1029. pStack->fNewLine = pStack->fNewLine && isspace( ch );
  1030. }
  1031. #endif // 0
  1032. return ch;
  1033. }
  1034. /*** UnGetChar **************************************************************
  1035. * Purpose : to unget the given character
  1036. * Input : the character to unget
  1037. * Output : the character which was unget-ed
  1038. * Notes :
  1039. ***************************************************************************/
  1040. short
  1041. NFA_INFO::UnGetChar(
  1042. short c)
  1043. {
  1044. if( !Flags.fFileSet || !pStack->fOpen) return 0;
  1045. ungetc( c, pStack->hFile );
  1046. #if 0
  1047. if(c == '\n')
  1048. {
  1049. pStack->uLine--;
  1050. // dont know what to do with column, really
  1051. }
  1052. #endif
  1053. return c;
  1054. }
  1055. /*** GetCurrentInputDetails *************************************************
  1056. * Purpose : to return details of the current input
  1057. * Input : pointer to name pointer, pointer to line no, pointer to col
  1058. * Output : STATUS_OK if all is well, error otherwise
  1059. * Notes :
  1060. ****************************************************************************/
  1061. STATUS_T
  1062. NFA_INFO::GetCurrentInputDetails(
  1063. char **ppName,
  1064. short *pLineNo,
  1065. short *pColNo )
  1066. {
  1067. if(!pStack)
  1068. {
  1069. (*ppName) = "";
  1070. (*pLineNo) = 0;
  1071. (*pColNo) = 0;
  1072. return NO_INPUT_FILE;
  1073. }
  1074. (*ppName) = pStack->pName;
  1075. (*pLineNo) = curr_line_G;
  1076. (*pColNo) = 0;
  1077. return STATUS_OK;
  1078. }
  1079. /*** GetInputDetails ********************************************************
  1080. * Purpose : to return details of the input
  1081. * Input : pointer to name pointer, pointer to line no, pointer to col
  1082. * Output : STATUS_OK if all is well, error otherwise
  1083. * Notes :
  1084. ****************************************************************************/
  1085. STATUS_T
  1086. NFA_INFO::GetInputDetails(
  1087. char **ppName,
  1088. short *pLineNo)
  1089. {
  1090. if(!pStack)
  1091. {
  1092. (*ppName) = "";
  1093. (*pLineNo) = 0;
  1094. return NO_INPUT_FILE;
  1095. }
  1096. (*ppName) = pStack->pShadowName;
  1097. (*pLineNo) = curr_line_G;
  1098. return STATUS_OK;
  1099. }
  1100. /*** GetInputDetails ********************************************************
  1101. * Purpose : to return details of the current input
  1102. * Input : pointer to name pointer
  1103. * Output : STATUS_OK if all is well, error otherwise
  1104. * Notes :
  1105. ****************************************************************************/
  1106. STATUS_T
  1107. NFA_INFO::GetInputDetails(
  1108. char **ppName)
  1109. {
  1110. if(!pStack) return NO_INPUT_FILE;
  1111. (*ppName) = pStack->pShadowName;
  1112. return STATUS_OK;
  1113. }
  1114. void
  1115. NFA_INFO::SetEOIFlag()
  1116. {
  1117. Flags.fEOI = 1;
  1118. }
  1119. short
  1120. NFA_INFO::GetEOIFlag()
  1121. {
  1122. return (short)Flags.fEOI;
  1123. }
  1124. BOOL
  1125. NFA_INFO::IsInInclude()
  1126. {
  1127. return Flags.fInInclude;
  1128. }
  1129. /****************************************************************************
  1130. **** temp functions to see if things are fine
  1131. ****************************************************************************/
  1132. void
  1133. NFA_INFO::Dump()
  1134. {
  1135. PATH_LIST *pPathTemp = pPathList;
  1136. FNAME_LIST *pNameTemp = pFileList;
  1137. printf("\nDump of file handler data structure:");
  1138. printf("\nPreprocessing :%d", Flags.fPreProcess);
  1139. printf("\nfFileSet :%d", Flags.fFileSet);
  1140. printf("\nCurrentLexLevel :%d", iCurLexLevel);
  1141. printf("\n");
  1142. if(pPathTemp)
  1143. {
  1144. printf("\nList of paths:");
  1145. while( pPathTemp )
  1146. {
  1147. printf("\nPATH: %s", pPathTemp->pPath);
  1148. pPathTemp = pPathTemp->pNext;
  1149. }
  1150. }
  1151. if(pNameTemp)
  1152. {
  1153. printf("\nList of input files so far:");
  1154. while(pNameTemp)
  1155. {
  1156. printf("\nFILE: %s", pNameTemp->pName);
  1157. pNameTemp = pNameTemp->pNext;
  1158. }
  1159. }
  1160. }
  1161. /******************************************************************************
  1162. * general utility routines
  1163. ******************************************************************************/
  1164. /*** SplitFileName ************************************************************
  1165. * Purpose : to analyse the filename and return individual components
  1166. * Input : pointers to individual components
  1167. * Output : nothing
  1168. * Notes :
  1169. *****************************************************************************/
  1170. void
  1171. SplitFileName(
  1172. char * pFullName,
  1173. char ** pagDrive,
  1174. char ** pagPath,
  1175. char ** pagName,
  1176. char ** pagExt )
  1177. {
  1178. char agDrive[ _MAX_DRIVE ];
  1179. char agPath[ _MAX_DIR ];
  1180. char agName[ _MAX_FNAME ];
  1181. char agExt[ _MAX_EXT ];
  1182. _splitpath( pFullName, agDrive, agPath, agName, agExt );
  1183. if( agDrive[0] )
  1184. {
  1185. (*pagDrive) = new char[ strlen(agDrive) + 1 ];
  1186. strcpy( (*pagDrive), agDrive );
  1187. }
  1188. else
  1189. {
  1190. (*pagDrive) = new char[ 1 ];
  1191. *(*pagDrive) = '\0';
  1192. }
  1193. if( agPath[0] )
  1194. {
  1195. (*pagPath) = new char[ strlen(agPath) + 1 ];
  1196. strcpy( (*pagPath), agPath );
  1197. }
  1198. else
  1199. {
  1200. (*pagPath) = new char[ 2 + 1 ];
  1201. strcpy( (*pagPath), ".\\");
  1202. }
  1203. if( agName[0] )
  1204. {
  1205. (*pagName) = new char[ strlen(agName) + 1 ];
  1206. strcpy( (*pagName), agName );
  1207. }
  1208. else
  1209. {
  1210. (*pagName) = new char[ 1 ];
  1211. *(*pagName) = '\0';
  1212. }
  1213. if( agExt[0] )
  1214. {
  1215. (*pagExt) = new char[ strlen(agExt) + 1 ];
  1216. strcpy( (*pagExt), agExt );
  1217. }
  1218. else
  1219. {
  1220. (*pagExt) = new char[ 1 ];
  1221. *(*pagExt) = '\0';
  1222. }
  1223. }
  1224. void
  1225. StripSlashes(
  1226. char * p )
  1227. {
  1228. char * pSave = p;
  1229. char * p1;
  1230. char * dest = new char [ 256 ],
  1231. * destSave = dest;
  1232. short n;
  1233. if( p )
  1234. {
  1235. dest[0] = 0;
  1236. while ( ( p1 = strstr( p, "\\\\" ) ) != 0 )
  1237. {
  1238. strncpy( dest, p, n = short(p1 - p) );
  1239. dest += n;
  1240. *dest++ = '\\';
  1241. *dest = 0;
  1242. p = p1 + 2;
  1243. while( *p == '\\') p++;
  1244. }
  1245. strcat( dest, p );
  1246. strcpy( pSave, destSave );
  1247. }
  1248. delete destSave;
  1249. }
  1250. void
  1251. ChangeToForwardSlash(
  1252. char * pFullInputName,
  1253. char * pFullName )
  1254. {
  1255. short ch;
  1256. while ( (ch = *pFullInputName++ ) != 0 )
  1257. {
  1258. if( ch == '/' )
  1259. ch = '\\';
  1260. *pFullName++ = (char) ch;
  1261. }
  1262. *pFullName = '\0';
  1263. }