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.

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