PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/config/makedep.cpp

http://github.com/zpao/v8monkey
C++ | 885 lines | 752 code | 55 blank | 78 comment | 83 complexity | ef831a1f10aa60531907be8f738c0ed3 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is mozilla.org code.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Netscape Communications Corporation.
  19. * Portions created by the Initial Developer are Copyright (C) 1998
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s):
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either of the GNU General Public License Version 2 or later (the "GPL"),
  26. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. // Dependency building hack
  38. //
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <sys/stat.h>
  42. #include <ctype.h>
  43. #include <afxcoll.h>
  44. #include <afxtempl.h>
  45. int mainReturn = 0;
  46. BOOL b16 = FALSE;
  47. BOOL bSimple = FALSE;
  48. FILE *pAltFile = stdout;
  49. CStringArray includeDirectories;
  50. // turn a file, relative path or other into an absolute path
  51. // This function copied from MFC 1.52
  52. BOOL PASCAL _AfxFullPath(LPSTR lpszPathOut, LPCSTR lpszFileIn)
  53. // lpszPathOut = buffer of _MAX_PATH
  54. // lpszFileIn = file, relative path or absolute path
  55. // (both in ANSI character set)
  56. {
  57. OFSTRUCT of;
  58. if (OpenFile(lpszFileIn, &of, OF_PARSE) != HFILE_ERROR)
  59. {
  60. // of.szPathName is in the OEM character set
  61. OemToAnsi(of.szPathName, lpszPathOut);
  62. AnsiUpper(lpszPathOut); // paths in upper case just to be sure
  63. return TRUE;
  64. }
  65. else
  66. {
  67. TRACE1("Warning: could not parse the path %Fs\n", lpszFileIn);
  68. lstrcpy(lpszPathOut, lpszFileIn); // take it literally
  69. AnsiUpper(lpszPathOut); // paths in upper case just to be sure
  70. return FALSE;
  71. }
  72. }
  73. void AddIncludeDirectory( char *pString ){
  74. CString s = pString;
  75. int len = s.GetLength();
  76. if(len > 0 && s[len - 1] != '\\' ){
  77. s += "\\";
  78. }
  79. includeDirectories.Add(s);
  80. }
  81. BOOL FileExists( const char *pString ){
  82. struct _stat buf;
  83. int result;
  84. result = _stat( pString, &buf );
  85. return (result == 0);
  86. }
  87. void FixPathName(CString& str) {
  88. str.MakeUpper(); // all upper case
  89. // now switch all forward slashes to back slashes
  90. int index;
  91. while ((index = str.Find('/')) != -1) {
  92. str.SetAt(index, '\\');
  93. }
  94. }
  95. void FATName(CString& csLONGName)
  96. {
  97. // Only relevant for 16 bits.
  98. if(b16) {
  99. // Convert filename to FAT (8.3) equivalent.
  100. char aBuffer[2048];
  101. if(GetShortPathName(csLONGName, aBuffer, 2048)) {
  102. csLONGName = aBuffer;
  103. }
  104. }
  105. }
  106. class CFileRecord {
  107. public:
  108. CString m_shortName;
  109. CString m_pathName;
  110. CPtrArray m_includes; // pointers to CFileRecords in fileMap
  111. BOOL m_bVisited;
  112. BOOL m_bSystem;
  113. BOOL m_bSource;
  114. static CMapStringToPtr fileMap; // contains all allocated CFileRecords
  115. static CStringArray orderedFileNames;
  116. static CMapStringToPtr includeMap; // pointer to CFileRecords in fileMap
  117. static CMapStringToPtr noDependMap;
  118. CFileRecord( const char *shortName, const char* pFullName, BOOL bSystem, BOOL bSource):
  119. m_shortName( shortName ),
  120. m_pathName(),
  121. m_includes(),
  122. m_bVisited(FALSE),
  123. m_bSource( bSource ),
  124. m_bSystem(bSystem){
  125. m_pathName = pFullName;
  126. FixPathName(m_pathName); // all upper case for consistency
  127. ASSERT(FindFileRecord(m_pathName) == NULL); // make sure it's not already in the map
  128. fileMap[m_pathName] = this; // add this to the filemap, using the appropriate name as the key
  129. if (bSource) {
  130. orderedFileNames.Add(m_pathName); // remember the order we saw source files in
  131. }
  132. }
  133. //
  134. // open the file and grab all the includes.
  135. //
  136. void ProcessFile(){
  137. FILE *f;
  138. CString fullName;
  139. BOOL bSystem;
  140. DWORD lineCntr = 0;
  141. char *a = new char[2048];
  142. memset(a, 0, 2048);
  143. char srcPath[_MAX_PATH];
  144. // construct the full path
  145. if (!_AfxFullPath(srcPath, m_pathName)) {
  146. strcpy(srcPath, m_pathName);
  147. }
  148. // strip off the source filename to end up with just the path
  149. LPSTR pTemp = strrchr(srcPath, '\\');
  150. if (pTemp) {
  151. *(pTemp + 1) = 0;
  152. }
  153. f = fopen(m_pathName, "r");
  154. if(f != NULL && f != (FILE *)-1) {
  155. setvbuf(f, NULL, _IOFBF, 32768); // use a large file buffer
  156. while(fgets(a, 2047, f)) {
  157. // if the string "//{{NO_DEPENDENCIES}}" is at the start of one of the
  158. // first 10 lines of a file, don't build dependencies on it or any
  159. // of the files it includes
  160. if (lineCntr < 10) {
  161. static char* pDependStr = "//{{NO_DEPENDENCIES}}";
  162. if (strncmp(a, pDependStr, strlen(pDependStr)) == 0) {
  163. noDependMap[m_pathName] = 0; // add it to the noDependMap
  164. break; // no need for further processing of this file
  165. }
  166. }
  167. ++lineCntr;
  168. // have to handle a variety of legal syntaxes that we find in our source files:
  169. // #include
  170. // # include
  171. // #include
  172. // if the first non-whitespace char is a '#', consider this line
  173. pTemp = a;
  174. pTemp += strspn(pTemp, " \t"); // skip whitespace
  175. if (*pTemp == '#') {
  176. ++pTemp; // skip the '#'
  177. pTemp += strspn(pTemp, " \t"); // skip more whitespace
  178. if( !strncmp(pTemp, "include", 7) ){
  179. pTemp += 7; // skip the "include"
  180. pTemp += strspn(pTemp, " \t"); // skip more whitespace
  181. bSystem = (*pTemp == '<'); // mark if it's a system include or not
  182. // forget system files -- we just have to search all the paths
  183. // every time and never find them! This change alone speeds a full
  184. // depend run on my system from 5 minutes to 3:15
  185. // if (bSystem || (*pTemp == '"')) {
  186. if (*pTemp == '"') {
  187. LPSTR pStart = pTemp + 1; // mark the start of the string
  188. pTemp = pStart + strcspn(pStart, ">\" "); // find the end of the string
  189. *pTemp = 0; // terminate the string
  190. // construct the full pathname from the path part of the
  191. // source file and the name listed here
  192. fullName = srcPath;
  193. fullName += pStart;
  194. CFileRecord *pAddMe = AddFile( pStart, fullName, bSystem );
  195. if (pAddMe) {
  196. m_includes.Add(pAddMe);
  197. }
  198. }
  199. }
  200. }
  201. }
  202. fclose(f);
  203. }
  204. delete [] a;
  205. }
  206. void PrintIncludes(){
  207. int i = 0;
  208. while( i < m_includes.GetSize() ){
  209. CFileRecord *pRec = (CFileRecord*) m_includes[i];
  210. // Don't write out files that don't exist or are not in the namespace
  211. // of the programs using it (netscape_AppletMozillaContext.h doesn't
  212. // mix well with 16 bits).
  213. // Also don't write out files that are in the noDependMap
  214. void* lookupJunk;
  215. if( !pRec->m_bVisited && pRec->m_pathName.GetLength() != 0 && !noDependMap.Lookup(pRec->m_pathName, lookupJunk)) {
  216. // not supposed to have a file in the list that doesn't exist
  217. ASSERT(FileExists(pRec->m_pathName));
  218. CString csOutput;
  219. csOutput = pRec->m_pathName;
  220. FATName(csOutput);
  221. fprintf(pAltFile, "\\\n %s ", (const char *) csOutput );
  222. // mark this one as done so we don't do it more than once
  223. pRec->m_bVisited = TRUE;
  224. pRec->PrintIncludes();
  225. }
  226. i++;
  227. }
  228. }
  229. void PrintDepend(){
  230. CFileRecord *pRec;
  231. BOOL bFound;
  232. POSITION next;
  233. CString name;
  234. // clear all the m_bVisisted flags so we can use it to keep track
  235. // of whether we've already output this file as a dependency
  236. next = fileMap.GetStartPosition();
  237. while( next ){
  238. fileMap.GetNextAssoc( next, name, *(void**)&pRec );
  239. pRec->m_bVisited = FALSE;
  240. }
  241. char fname[_MAX_FNAME];
  242. if (pRec->m_pathName.GetLength() != 0) {
  243. if( bSimple ){
  244. fprintf(pAltFile, "\n\n\n%s:\t", m_pathName );
  245. }
  246. else {
  247. CString csOutput;
  248. csOutput = m_pathName;
  249. FATName(csOutput);
  250. _splitpath( csOutput, NULL, NULL, fname, NULL );
  251. fprintf(pAltFile, "\n\n\n$(OUTDIR)\\%s.obj: %s ", fname, (const char*) csOutput );
  252. }
  253. m_bVisited = TRUE; // mark it as done so we won't do it again
  254. PrintIncludes();
  255. }
  256. }
  257. static CString NormalizeFileName( const char* pName ){
  258. return CString(pName);
  259. }
  260. static CFileRecord* FindFileRecord( const char *pName ){
  261. CFileRecord* pRec = NULL;
  262. CString name(pName);
  263. FixPathName(name);
  264. fileMap.Lookup(name, (void*&)pRec);
  265. return(pRec);
  266. }
  267. public:
  268. static CFileRecord* AddFile( const char* pShortName, const char* pFullName, BOOL bSystem = FALSE,
  269. BOOL bSource = FALSE ){
  270. char fullName[_MAX_PATH];
  271. BOOL bFound = FALSE;
  272. CString foundName;
  273. CString fixedShortName;
  274. CString s;
  275. // normalize the name
  276. fixedShortName = pShortName;
  277. FixPathName(fixedShortName);
  278. pShortName = fixedShortName;
  279. // if it is source, we might be getting an obj file. If we do,
  280. // convert it to a c or c++ file.
  281. if( bSource && (strcmp(GetExt(pShortName),".obj") == 0) ){
  282. char path_buffer[_MAX_PATH];
  283. char fname[_MAX_FNAME] = "";
  284. CString s;
  285. _splitpath( pShortName, NULL, NULL, fname, NULL );
  286. if( FileExists( s = CString(fname) + ".cpp") ){
  287. pShortName = s;
  288. pFullName = s;
  289. }
  290. else if( FileExists( s = CString(fname) + ".c" ) ){
  291. pShortName = s;
  292. pFullName = s;
  293. }
  294. else {
  295. return 0;
  296. }
  297. }
  298. // if pFullName was not constructed, construct it here based on the current directory
  299. if (!pFullName) {
  300. _AfxFullPath(fullName, pShortName);
  301. pFullName = fullName;
  302. }
  303. // first check to see if we already have this exact file
  304. CFileRecord *pRec = FindFileRecord(pFullName);
  305. // if not found and not a source file check the header list --
  306. // all files we've found in include directories are in the includeMap.
  307. // we can save gobs of time by getting it from there
  308. if (!pRec && !bSource)
  309. includeMap.Lookup(fixedShortName, (void*&)pRec);
  310. if (!pRec) {
  311. // not in one of our lists, start scrounging on disk
  312. // check the fullname first
  313. if (FileExists(pFullName)) {
  314. foundName = pFullName;
  315. bFound = TRUE;
  316. }
  317. else {
  318. // if still not found, search the include paths
  319. int i = 0;
  320. while( i < includeDirectories.GetSize() ){
  321. if( FileExists( includeDirectories[i] + pShortName ) ){
  322. foundName = includeDirectories[i] + pShortName;
  323. bFound = TRUE;
  324. break;
  325. }
  326. i++;
  327. }
  328. }
  329. }
  330. else {
  331. // we found it
  332. bFound = TRUE;
  333. }
  334. // source files are not allowed to be missing
  335. if (bSource && !pRec && !bFound) {
  336. fprintf(stderr, "Source file: %s doesn't exist\n", pFullName);
  337. mainReturn = -1; // exit with an error, don't write out the results
  338. }
  339. #ifdef _DEBUG
  340. if (!pRec && !bFound && !bSystem) {
  341. fprintf(stderr, "Header not found: %s (%s)\n", pShortName, pFullName);
  342. }
  343. #endif
  344. // if none of the above logic found it already in the list,
  345. // must be a new file, add it to the list
  346. if (bFound && (pRec == NULL)) {
  347. pRec = new CFileRecord( pShortName, foundName, bSystem, bSource);
  348. // if this one isn't a source file add it to the includeMap
  349. // for performance reasons (so we can find it there next time rather
  350. // than having to search the file system again)
  351. if (!bSource) {
  352. includeMap[pShortName] = pRec;
  353. }
  354. }
  355. return pRec;
  356. }
  357. static void PrintDependancies(){
  358. CFileRecord *pRec;
  359. BOOL bFound;
  360. POSITION next;
  361. CString name;
  362. // use orderedFileNames to preserve order
  363. for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
  364. pRec = FindFileRecord(orderedFileNames[pos]);
  365. if(pRec && pRec->m_bSource ){
  366. pRec->PrintDepend();
  367. }
  368. }
  369. }
  370. void PrintDepend2(){
  371. CFileRecord *pRec;
  372. int i;
  373. if( m_includes.GetSize() != 0 ){
  374. fprintf(pAltFile, "\n\n\n%s: \\\n",m_pathName );
  375. i = 0;
  376. while( i < m_includes.GetSize() ){
  377. pRec = (CFileRecord*) m_includes[i];
  378. fprintf(pAltFile, "\t\t\t%s\t\\\n",pRec->m_pathName );
  379. i++;
  380. }
  381. }
  382. }
  383. static void PrintDependancies2(){
  384. CFileRecord *pRec;
  385. BOOL bFound;
  386. POSITION next;
  387. CString name;
  388. next = fileMap.GetStartPosition();
  389. while( next ){
  390. fileMap.GetNextAssoc( next, name, *(void**)&pRec );
  391. pRec->PrintDepend2();
  392. }
  393. }
  394. static void PrintTargets(const char *pMacroName, const char *pDelimiter){
  395. CFileRecord *pRec;
  396. BOOL bFound;
  397. POSITION next;
  398. CString name;
  399. BOOL bNeedDelimiter = FALSE;
  400. fprintf(pAltFile, "%s = ", pMacroName);
  401. // use orderedFileNames to preserve target order
  402. for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
  403. pRec = FindFileRecord(orderedFileNames[pos]);
  404. ASSERT(pRec);
  405. if( pRec && pRec->m_bSource && pRec->m_pathName.GetLength() != 0){
  406. char fname[_MAX_FNAME];
  407. CString csOutput;
  408. csOutput = pRec->m_pathName;
  409. FATName(csOutput);
  410. _splitpath( csOutput, NULL, NULL, fname, NULL );
  411. if(bNeedDelimiter) {
  412. fprintf(pAltFile, "%s\n", pDelimiter);
  413. bNeedDelimiter = FALSE;
  414. }
  415. fprintf(pAltFile, " $(OUTDIR)\\%s.obj ", fname );
  416. bNeedDelimiter = TRUE;
  417. }
  418. }
  419. fprintf(pAltFile, "\n\n\n");
  420. }
  421. static CString DirDefine( const char *pPath ){
  422. char path_buffer[_MAX_PATH];
  423. char dir[_MAX_DIR] = "";
  424. char dir2[_MAX_DIR] = "";
  425. char fname[_MAX_FNAME] = "";
  426. char ext[_MAX_EXT] = "";
  427. CString s;
  428. _splitpath( pPath, 0, dir, 0, ext );
  429. BOOL bDone = FALSE;
  430. while( dir && !bDone){
  431. // remove the trailing slash
  432. dir[ strlen(dir)-1] = 0;
  433. _splitpath( dir, 0, dir2, fname, 0 );
  434. if( strcmp( fname, "SRC" ) == 0 ){
  435. strcpy( dir, dir2 );
  436. }
  437. else {
  438. bDone = TRUE;
  439. }
  440. }
  441. s = CString(fname) + "_" + (ext+1);
  442. return s;
  443. }
  444. static void PrintSources(){
  445. int i;
  446. CString dirName, newDirName;
  447. for( i=0; i< orderedFileNames.GetSize(); i++ ){
  448. newDirName= DirDefine( orderedFileNames[i] );
  449. if( newDirName != dirName ){
  450. fprintf( pAltFile, "\n\n\nFILES_%s= $(FILES_%s) \\",
  451. (const char*)newDirName, (const char*)newDirName );
  452. dirName = newDirName;
  453. }
  454. fprintf( pAltFile, "\n\t%s^", (const char*)orderedFileNames[i] );
  455. }
  456. }
  457. static CString SourceDirName( const char *pPath, BOOL bFileName){
  458. char path_buffer[_MAX_PATH];
  459. char drive[_MAX_DRIVE] = "";
  460. char dir[_MAX_DIR] = "";
  461. char fname[_MAX_FNAME] = "";
  462. char ext[_MAX_EXT] = "";
  463. CString s;
  464. _splitpath( pPath, drive, dir, fname, ext );
  465. s = CString(drive) + dir;
  466. if( bFileName ){
  467. s += CString("FNAME") + ext;
  468. }
  469. else {
  470. // remove the trailing slash
  471. s = s.Left( s.GetLength() - 1 );
  472. }
  473. return s;
  474. }
  475. static CString GetExt( const char *pPath){
  476. char ext[_MAX_EXT] = "";
  477. _splitpath( pPath, 0,0,0, ext );
  478. CString s = CString(ext);
  479. s.MakeLower();
  480. return s;
  481. }
  482. static void PrintBuildRules(){
  483. int i;
  484. CString dirName;
  485. CMapStringToPtr dirList;
  486. for( i=0; i< orderedFileNames.GetSize(); i++ ){
  487. dirList[ SourceDirName(orderedFileNames[i], TRUE) ]= 0;
  488. }
  489. POSITION next;
  490. CString name;
  491. void *pVal;
  492. next = dirList.GetStartPosition();
  493. while( next ){
  494. dirList.GetNextAssoc( next, name, pVal);
  495. CString dirDefine = DirDefine( name );
  496. CString ext = GetExt( name );
  497. name = SourceDirName( name, FALSE );
  498. CString response = dirDefine.Left(8);
  499. fprintf( pAltFile,
  500. "\n\n\n{%s}%s{$(OUTDIR)}.obj:\n"
  501. "\t@rem <<$(OUTDIR)\\%s.cl\n"
  502. "\t$(CFILEFLAGS)\n"
  503. "\t$(CFLAGS_%s)\n"
  504. "<<KEEP\n"
  505. "\t$(CPP) @$(OUTDIR)\\%s.cl %%s\n",
  506. (const char*)name,
  507. (const char*)ext,
  508. (const char*)response,
  509. (const char*)dirDefine,
  510. (const char*)response
  511. );
  512. fprintf( pAltFile,
  513. "\n\n\nBATCH_%s:\n"
  514. "\t@rem <<$(OUTDIR)\\%s.cl\n"
  515. "\t$(CFILEFLAGS)\n"
  516. "\t$(CFLAGS_%s)\n"
  517. "\t$(FILES_%s)\n"
  518. "<<KEEP\n"
  519. "\t$(TIMESTART)\n"
  520. "\t$(CPP) @$(OUTDIR)\\%s.cl\n"
  521. "\t$(TIMESTOP)\n",
  522. (const char*)dirDefine,
  523. (const char*)response,
  524. (const char*)dirDefine,
  525. (const char*)dirDefine,
  526. (const char*)response
  527. );
  528. }
  529. //
  530. // Loop through one more time and build the final batch build
  531. // rule
  532. //
  533. fprintf( pAltFile,
  534. "\n\n\nBATCH_BUILD_OBJECTS:\t\t\\\n");
  535. next = dirList.GetStartPosition();
  536. while( next ){
  537. dirList.GetNextAssoc( next, name, pVal);
  538. CString dirDefine = DirDefine( name );
  539. fprintf( pAltFile,
  540. "\tBATCH_%s\t\t\\\n", dirDefine );
  541. }
  542. fprintf( pAltFile,
  543. "\n\n");
  544. }
  545. static void ProcessFiles(){
  546. CFileRecord *pRec;
  547. BOOL bFound;
  548. POSITION next;
  549. CString name;
  550. // search all the files for headers, adding each one to the list when found
  551. // rather than do it recursively, it simple marks each one it's done
  552. // and starts over, stopping only when all are marked as done
  553. next = fileMap.GetStartPosition();
  554. while( next ){
  555. fileMap.GetNextAssoc( next, name, *(void**)&pRec );
  556. if( pRec->m_bVisited == FALSE && pRec->m_bSystem == FALSE ){
  557. // mark this file as already done so we don't read it again
  558. // to find its headers
  559. pRec->m_bVisited = TRUE;
  560. pRec->ProcessFile();
  561. // Start searching from the beginning again
  562. // because ProcessFile may have added new files
  563. // and changed the GetNextAssoc order
  564. next = fileMap.GetStartPosition();
  565. }
  566. }
  567. }
  568. };
  569. CMapStringToPtr CFileRecord::fileMap; // contains all allocated CFileRecords
  570. CStringArray CFileRecord::orderedFileNames;
  571. CMapStringToPtr CFileRecord::includeMap; // pointers to CFileRecords in fileMap
  572. CMapStringToPtr CFileRecord::noDependMap; // no data, just an index
  573. int main( int argc, char** argv ){
  574. int i = 1;
  575. char *pStr;
  576. static int iRecursion = 0; // Track levels of recursion.
  577. static CString outputFileName;
  578. // Entering.
  579. iRecursion++;
  580. while( i < argc ){
  581. if( argv[i][0] == '-' || argv[i][0] == '/' ){
  582. switch( argv[i][1] ){
  583. case 'i':
  584. case 'I':
  585. if( argv[i][2] != 0 ){
  586. pStr = &(argv[i][2]);
  587. }
  588. else {
  589. i++;
  590. pStr = argv[i];
  591. }
  592. if( pStr == 0 || *pStr == '-' || *pStr == '/' ){
  593. goto usage;
  594. }
  595. else {
  596. AddIncludeDirectory( pStr );
  597. }
  598. break;
  599. case 'f':
  600. case 'F':
  601. if( argv[i][2] != 0 ){
  602. pStr = &(argv[i][2]);
  603. }
  604. else {
  605. i++;
  606. pStr = argv[i];
  607. }
  608. if( pStr == 0 || *pStr == '-' || *pStr == '/'){
  609. goto usage;
  610. }
  611. else {
  612. CStdioFile f;
  613. CString s;
  614. if( f.Open( pStr, CFile::modeRead ) ){
  615. while(f.ReadString(s)){
  616. s.TrimLeft();
  617. s.TrimRight();
  618. if( s.GetLength() ){
  619. CFileRecord::AddFile( s, NULL, FALSE, TRUE );
  620. }
  621. }
  622. f.Close();
  623. }
  624. else {
  625. fprintf(stderr,"makedep: file not found: %s", pStr );
  626. exit(-1);
  627. }
  628. }
  629. break;
  630. case 'o':
  631. case 'O':
  632. if( argv[i][2] != 0 ){
  633. pStr = &(argv[i][2]);
  634. }
  635. else {
  636. i++;
  637. pStr = argv[i];
  638. }
  639. if( pStr == 0 || *pStr == '-' || *pStr == '/'){
  640. goto usage;
  641. }
  642. else {
  643. CStdioFile f;
  644. CString s;
  645. outputFileName = pStr;
  646. if(!(pAltFile = fopen(pStr, "w+"))) {
  647. fprintf(stderr, "makedep: file not found: %s", pStr );
  648. exit(-1);
  649. }
  650. }
  651. break;
  652. case '1':
  653. if( argv[i][2] == '6') {
  654. b16 = TRUE;
  655. }
  656. break;
  657. case 's':
  658. case 'S':
  659. bSimple = TRUE;
  660. break;
  661. case 'h':
  662. case 'H':
  663. case '?':
  664. usage:
  665. fprintf(stderr, "usage: makedep -I <dirname> -F <filelist> <filename>\n"
  666. " -I <dirname> Directory name, can be repeated\n"
  667. " -F <filelist> List of files to scan, one per line\n"
  668. " -O <outputFile> File to write output, default stdout\n");
  669. exit(-1);
  670. }
  671. }
  672. else if( argv[i][0] == '@' ){
  673. // file contains our commands.
  674. CStdioFile f;
  675. CString s;
  676. int iNewArgc = 0;
  677. char **apNewArgv = new char*[5000];
  678. memset(apNewArgv, 0, sizeof(apNewArgv));
  679. // First one is always the name of the exe.
  680. apNewArgv[0] = argv[0];
  681. iNewArgc++;
  682. const char *pTraverse;
  683. const char *pBeginArg;
  684. if( f.Open( &argv[i][1], CFile::modeRead ) ){
  685. while( iNewArgc < 5000 && f.ReadString(s) ) {
  686. // Scan the string for args, and do the right thing.
  687. pTraverse = (const char *)s;
  688. while(iNewArgc < 5000 && *pTraverse) {
  689. if(isspace(*pTraverse)) {
  690. pTraverse++;
  691. continue;
  692. }
  693. // Extract to next space.
  694. pBeginArg = pTraverse;
  695. do {
  696. pTraverse++;
  697. }
  698. while(*pTraverse && !isspace(*pTraverse));
  699. apNewArgv[iNewArgc] = new char[pTraverse - pBeginArg + 1];
  700. memset(apNewArgv[iNewArgc], 0, pTraverse - pBeginArg + 1);
  701. strncpy(apNewArgv[iNewArgc], pBeginArg, pTraverse - pBeginArg);
  702. iNewArgc++;
  703. }
  704. }
  705. f.Close();
  706. }
  707. // Recurse if needed.
  708. if(iNewArgc > 1) {
  709. main(iNewArgc, apNewArgv);
  710. }
  711. // Free off the argvs (but not the very first one which we didn't allocate).
  712. while(iNewArgc > 1) {
  713. iNewArgc--;
  714. delete [] apNewArgv[iNewArgc];
  715. }
  716. delete [] apNewArgv;
  717. }
  718. else {
  719. CFileRecord::AddFile( argv[i], NULL, FALSE, TRUE );
  720. }
  721. i++;
  722. }
  723. // Only of the very bottom level of recursion do we do this.
  724. if(iRecursion == 1) {
  725. // only write the results out if no errors encountered
  726. if (mainReturn == 0) {
  727. CFileRecord::ProcessFiles();
  728. if( !bSimple ){
  729. CFileRecord::PrintTargets("OBJ_FILES", "\\");
  730. if(b16) {
  731. CFileRecord::PrintTargets("LINK_OBJS", "+\\");
  732. }
  733. else {
  734. CFileRecord::PrintTargets("LINK_OBJS", "^");
  735. }
  736. CFileRecord::PrintSources();
  737. CFileRecord::PrintBuildRules();
  738. }
  739. CFileRecord::PrintDependancies();
  740. }
  741. if(pAltFile != stdout) {
  742. fclose(pAltFile);
  743. if (mainReturn != 0) {
  744. remove(outputFileName); // kill output file if returning an error
  745. }
  746. }
  747. }
  748. iRecursion--;
  749. if (iRecursion == 0 )
  750. {
  751. // last time through -- clean up allocated CFileRecords!
  752. CFileRecord *pFRec;
  753. CString name;
  754. POSITION next;
  755. next = CFileRecord::fileMap.GetStartPosition();
  756. while( next ){
  757. CFileRecord::fileMap.GetNextAssoc( next, name, *(void**)&pFRec );
  758. delete pFRec;
  759. }
  760. }
  761. return mainReturn;
  762. }