Workaround for intermittent js_GetClassObject failures (bug 457069, r=brendan).
[mozilla-central.git] / config / makedep.cpp
blob62a1907f0d459e6df921e236b60a2511d6751416
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
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.
36 * ***** END LICENSE BLOCK ***** */
38 // Dependency building hack
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/stat.h>
44 #include <ctype.h>
45 #include <afxcoll.h>
46 #include <afxtempl.h>
48 int mainReturn = 0;
49 BOOL b16 = FALSE;
50 BOOL bSimple = FALSE;
52 // freopen won't work on stdout in win16
53 FILE *pAltFile = stdout;
55 CStringArray includeDirectories;
57 // turn a file, relative path or other into an absolute path
58 // This function copied from MFC 1.52
59 BOOL PASCAL _AfxFullPath(LPSTR lpszPathOut, LPCSTR lpszFileIn)
60 // lpszPathOut = buffer of _MAX_PATH
61 // lpszFileIn = file, relative path or absolute path
62 // (both in ANSI character set)
64 OFSTRUCT of;
65 if (OpenFile(lpszFileIn, &of, OF_PARSE) != HFILE_ERROR)
67 // of.szPathName is in the OEM character set
68 OemToAnsi(of.szPathName, lpszPathOut);
69 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
70 return TRUE;
72 else
74 TRACE1("Warning: could not parse the path %Fs\n", lpszFileIn);
75 lstrcpy(lpszPathOut, lpszFileIn); // take it literally
76 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
77 return FALSE;
81 void AddIncludeDirectory( char *pString ){
82 CString s = pString;
83 int len = s.GetLength();
84 if(len > 0 && s[len - 1] != '\\' ){
85 s += "\\";
87 includeDirectories.Add(s);
90 BOOL FileExists( const char *pString ){
91 struct _stat buf;
92 int result;
94 result = _stat( pString, &buf );
95 return (result == 0);
98 void FixPathName(CString& str) {
99 str.MakeUpper(); // all upper case
101 // now switch all forward slashes to back slashes
102 int index;
103 while ((index = str.Find('/')) != -1) {
104 str.SetAt(index, '\\');
108 void FATName(CString& csLONGName)
110 // Only relevant for 16 bits.
111 if(b16) {
112 // Convert filename to FAT (8.3) equivalent.
113 char aBuffer[2048];
115 if(GetShortPathName(csLONGName, aBuffer, 2048)) {
116 csLONGName = aBuffer;
122 class CFileRecord {
123 public:
124 CString m_shortName;
125 CString m_pathName;
126 CPtrArray m_includes; // pointers to CFileRecords in fileMap
127 BOOL m_bVisited;
128 BOOL m_bSystem;
129 BOOL m_bSource;
130 static CMapStringToPtr fileMap; // contains all allocated CFileRecords
131 static CStringArray orderedFileNames;
132 static CMapStringToPtr includeMap; // pointer to CFileRecords in fileMap
133 static CMapStringToPtr noDependMap;
135 CFileRecord( const char *shortName, const char* pFullName, BOOL bSystem, BOOL bSource):
136 m_shortName( shortName ),
137 m_pathName(),
138 m_includes(),
139 m_bVisited(FALSE),
140 m_bSource( bSource ),
141 m_bSystem(bSystem){
143 m_pathName = pFullName;
144 FixPathName(m_pathName); // all upper case for consistency
145 ASSERT(FindFileRecord(m_pathName) == NULL); // make sure it's not already in the map
146 fileMap[m_pathName] = this; // add this to the filemap, using the appropriate name as the key
147 if (bSource) {
148 orderedFileNames.Add(m_pathName); // remember the order we saw source files in
153 // open the file and grab all the includes.
155 void ProcessFile(){
156 FILE *f;
157 CString fullName;
158 BOOL bSystem;
159 DWORD lineCntr = 0;
160 char *a = new char[2048];
161 memset(a, 0, 2048);
162 char srcPath[_MAX_PATH];
164 // construct the full path
165 if (!_AfxFullPath(srcPath, m_pathName)) {
166 strcpy(srcPath, m_pathName);
169 // strip off the source filename to end up with just the path
170 LPSTR pTemp = strrchr(srcPath, '\\');
171 if (pTemp) {
172 *(pTemp + 1) = 0;
175 f = fopen(m_pathName, "r");
176 if(f != NULL && f != (FILE *)-1) {
177 setvbuf(f, NULL, _IOFBF, 32768); // use a large file buffer
178 while(fgets(a, 2047, f)) {
179 // if the string "//{{NO_DEPENDENCIES}}" is at the start of one of the
180 // first 10 lines of a file, don't build dependencies on it or any
181 // of the files it includes
182 if (lineCntr < 10) {
183 static char* pDependStr = "//{{NO_DEPENDENCIES}}";
184 if (strncmp(a, pDependStr, strlen(pDependStr)) == 0) {
185 noDependMap[m_pathName] = 0; // add it to the noDependMap
186 break; // no need for further processing of this file
189 ++lineCntr;
190 // have to handle a variety of legal syntaxes that we find in our source files:
191 // #include
192 // # include
193 // #include
194 // if the first non-whitespace char is a '#', consider this line
195 pTemp = a;
196 pTemp += strspn(pTemp, " \t"); // skip whitespace
197 if (*pTemp == '#') {
198 ++pTemp; // skip the '#'
199 pTemp += strspn(pTemp, " \t"); // skip more whitespace
200 if( !strncmp(pTemp, "include", 7) ){
201 pTemp += 7; // skip the "include"
202 pTemp += strspn(pTemp, " \t"); // skip more whitespace
203 bSystem = (*pTemp == '<'); // mark if it's a system include or not
204 // forget system files -- we just have to search all the paths
205 // every time and never find them! This change alone speeds a full
206 // depend run on my system from 5 minutes to 3:15
207 // if (bSystem || (*pTemp == '"')) {
208 if (*pTemp == '"') {
209 LPSTR pStart = pTemp + 1; // mark the start of the string
210 pTemp = pStart + strcspn(pStart, ">\" "); // find the end of the string
211 *pTemp = 0; // terminate the string
213 // construct the full pathname from the path part of the
214 // source file and the name listed here
215 fullName = srcPath;
216 fullName += pStart;
217 CFileRecord *pAddMe = AddFile( pStart, fullName, bSystem );
218 if (pAddMe) {
219 m_includes.Add(pAddMe);
225 fclose(f);
227 delete [] a;
230 void PrintIncludes(){
231 int i = 0;
232 while( i < m_includes.GetSize() ){
233 CFileRecord *pRec = (CFileRecord*) m_includes[i];
235 // Don't write out files that don't exist or are not in the namespace
236 // of the programs using it (netscape_AppletMozillaContext.h doesn't
237 // mix well with 16 bits).
238 // Also don't write out files that are in the noDependMap
239 void* lookupJunk;
240 if( !pRec->m_bVisited && pRec->m_pathName.GetLength() != 0 && !noDependMap.Lookup(pRec->m_pathName, lookupJunk)) {
242 // not supposed to have a file in the list that doesn't exist
243 ASSERT(FileExists(pRec->m_pathName));
245 CString csOutput;
246 csOutput = pRec->m_pathName;
247 FATName(csOutput);
249 fprintf(pAltFile, "\\\n %s ", (const char *) csOutput );
251 // mark this one as done so we don't do it more than once
252 pRec->m_bVisited = TRUE;
254 pRec->PrintIncludes();
256 i++;
260 void PrintDepend(){
261 CFileRecord *pRec;
262 BOOL bFound;
263 POSITION next;
264 CString name;
266 // clear all the m_bVisisted flags so we can use it to keep track
267 // of whether we've already output this file as a dependency
268 next = fileMap.GetStartPosition();
269 while( next ){
270 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
271 pRec->m_bVisited = FALSE;
274 char fname[_MAX_FNAME];
276 if (pRec->m_pathName.GetLength() != 0) {
277 if( bSimple ){
278 fprintf(pAltFile, "\n\n\n%s:\t", m_pathName );
280 else {
281 CString csOutput;
282 csOutput = m_pathName;
283 FATName(csOutput);
285 _splitpath( csOutput, NULL, NULL, fname, NULL );
287 fprintf(pAltFile, "\n\n\n$(OUTDIR)\\%s.obj: %s ", fname, (const char*) csOutput );
289 m_bVisited = TRUE; // mark it as done so we won't do it again
290 PrintIncludes();
295 static CString NormalizeFileName( const char* pName ){
296 return CString(pName);
299 static CFileRecord* FindFileRecord( const char *pName ){
300 CFileRecord* pRec = NULL;
301 CString name(pName);
302 FixPathName(name);
303 fileMap.Lookup(name, (void*&)pRec);
304 return(pRec);
306 public:
307 static CFileRecord* AddFile( const char* pShortName, const char* pFullName, BOOL bSystem = FALSE,
308 BOOL bSource = FALSE ){
310 char fullName[_MAX_PATH];
311 BOOL bFound = FALSE;
312 CString foundName;
313 CString fixedShortName;
314 CString s;
316 // normalize the name
317 fixedShortName = pShortName;
318 FixPathName(fixedShortName);
319 pShortName = fixedShortName;
321 // if it is source, we might be getting an obj file. If we do,
322 // convert it to a c or c++ file.
323 if( bSource && (strcmp(GetExt(pShortName),".obj") == 0) ){
324 char path_buffer[_MAX_PATH];
325 char fname[_MAX_FNAME] = "";
326 CString s;
328 _splitpath( pShortName, NULL, NULL, fname, NULL );
329 if( FileExists( s = CString(fname) + ".cpp") ){
330 pShortName = s;
331 pFullName = s;
333 else if( FileExists( s = CString(fname) + ".c" ) ){
334 pShortName = s;
335 pFullName = s;
337 else {
338 return 0;
342 // if pFullName was not constructed, construct it here based on the current directory
343 if (!pFullName) {
344 _AfxFullPath(fullName, pShortName);
345 pFullName = fullName;
348 // first check to see if we already have this exact file
349 CFileRecord *pRec = FindFileRecord(pFullName);
351 // if not found and not a source file check the header list --
352 // all files we've found in include directories are in the includeMap.
353 // we can save gobs of time by getting it from there
354 if (!pRec && !bSource)
355 includeMap.Lookup(fixedShortName, (void*&)pRec);
357 if (!pRec) {
358 // not in one of our lists, start scrounging on disk
360 // check the fullname first
361 if (FileExists(pFullName)) {
362 foundName = pFullName;
363 bFound = TRUE;
365 else {
366 // if still not found, search the include paths
367 int i = 0;
368 while( i < includeDirectories.GetSize() ){
369 if( FileExists( includeDirectories[i] + pShortName ) ){
370 foundName = includeDirectories[i] + pShortName;
371 bFound = TRUE;
372 break;
374 i++;
378 else {
379 // we found it
380 bFound = TRUE;
383 // source files are not allowed to be missing
384 if (bSource && !pRec && !bFound) {
385 fprintf(stderr, "Source file: %s doesn't exist\n", pFullName);
386 mainReturn = -1; // exit with an error, don't write out the results
389 #ifdef _DEBUG
390 if (!pRec && !bFound && !bSystem) {
391 fprintf(stderr, "Header not found: %s (%s)\n", pShortName, pFullName);
393 #endif
395 // if none of the above logic found it already in the list,
396 // must be a new file, add it to the list
397 if (bFound && (pRec == NULL)) {
398 pRec = new CFileRecord( pShortName, foundName, bSystem, bSource);
400 // if this one isn't a source file add it to the includeMap
401 // for performance reasons (so we can find it there next time rather
402 // than having to search the file system again)
403 if (!bSource) {
404 includeMap[pShortName] = pRec;
407 return pRec;
411 static void PrintDependancies(){
412 CFileRecord *pRec;
413 BOOL bFound;
414 POSITION next;
415 CString name;
417 // use orderedFileNames to preserve order
418 for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
419 pRec = FindFileRecord(orderedFileNames[pos]);
420 if(pRec && pRec->m_bSource ){
421 pRec->PrintDepend();
427 void PrintDepend2(){
428 CFileRecord *pRec;
429 int i;
431 if( m_includes.GetSize() != 0 ){
432 fprintf(pAltFile, "\n\n\n%s: \\\n",m_pathName );
433 i = 0;
434 while( i < m_includes.GetSize() ){
435 pRec = (CFileRecord*) m_includes[i];
436 fprintf(pAltFile, "\t\t\t%s\t\\\n",pRec->m_pathName );
437 i++;
442 static void PrintDependancies2(){
443 CFileRecord *pRec;
444 BOOL bFound;
445 POSITION next;
446 CString name;
448 next = fileMap.GetStartPosition();
449 while( next ){
450 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
451 pRec->PrintDepend2();
456 static void PrintTargets(const char *pMacroName, const char *pDelimiter){
457 CFileRecord *pRec;
458 BOOL bFound;
459 POSITION next;
460 CString name;
462 BOOL bNeedDelimiter = FALSE;
463 fprintf(pAltFile, "%s = ", pMacroName);
465 // use orderedFileNames to preserve target order
466 for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
467 pRec = FindFileRecord(orderedFileNames[pos]);
468 ASSERT(pRec);
470 if( pRec && pRec->m_bSource && pRec->m_pathName.GetLength() != 0){
471 char fname[_MAX_FNAME];
473 CString csOutput;
474 csOutput = pRec->m_pathName;
475 FATName(csOutput);
477 _splitpath( csOutput, NULL, NULL, fname, NULL );
479 if(bNeedDelimiter) {
480 fprintf(pAltFile, "%s\n", pDelimiter);
481 bNeedDelimiter = FALSE;
484 fprintf(pAltFile, " $(OUTDIR)\\%s.obj ", fname );
485 bNeedDelimiter = TRUE;
488 fprintf(pAltFile, "\n\n\n");
491 static CString DirDefine( const char *pPath ){
492 char path_buffer[_MAX_PATH];
493 char dir[_MAX_DIR] = "";
494 char dir2[_MAX_DIR] = "";
495 char fname[_MAX_FNAME] = "";
496 char ext[_MAX_EXT] = "";
497 CString s;
499 _splitpath( pPath, 0, dir, 0, ext );
501 BOOL bDone = FALSE;
503 while( dir && !bDone){
504 // remove the trailing slash
505 dir[ strlen(dir)-1] = 0;
506 _splitpath( dir, 0, dir2, fname, 0 );
507 if( strcmp( fname, "SRC" ) == 0 ){
508 strcpy( dir, dir2 );
510 else {
511 bDone = TRUE;
514 s = CString(fname) + "_" + (ext+1);
515 return s;
519 static void PrintSources(){
520 int i;
521 CString dirName, newDirName;
523 for( i=0; i< orderedFileNames.GetSize(); i++ ){
524 newDirName= DirDefine( orderedFileNames[i] );
525 if( newDirName != dirName ){
526 fprintf( pAltFile, "\n\n\nFILES_%s= $(FILES_%s) \\",
527 (const char*)newDirName, (const char*)newDirName );
528 dirName = newDirName;
530 fprintf( pAltFile, "\n\t%s^", (const char*)orderedFileNames[i] );
534 static CString SourceDirName( const char *pPath, BOOL bFileName){
535 char path_buffer[_MAX_PATH];
536 char drive[_MAX_DRIVE] = "";
537 char dir[_MAX_DIR] = "";
538 char fname[_MAX_FNAME] = "";
539 char ext[_MAX_EXT] = "";
540 CString s;
542 _splitpath( pPath, drive, dir, fname, ext );
544 s = CString(drive) + dir;
545 if( bFileName ){
546 s += CString("FNAME") + ext;
548 else {
549 // remove the trailing slash
550 s = s.Left( s.GetLength() - 1 );
552 return s;
556 static CString GetExt( const char *pPath){
557 char ext[_MAX_EXT] = "";
559 _splitpath( pPath, 0,0,0, ext );
561 CString s = CString(ext);
562 s.MakeLower();
563 return s;
566 static void PrintBuildRules(){
567 int i;
568 CString dirName;
570 CMapStringToPtr dirList;
572 for( i=0; i< orderedFileNames.GetSize(); i++ ){
573 dirList[ SourceDirName(orderedFileNames[i], TRUE) ]= 0;
576 POSITION next;
577 CString name;
578 void *pVal;
580 next = dirList.GetStartPosition();
581 while( next ){
582 dirList.GetNextAssoc( next, name, pVal);
583 CString dirDefine = DirDefine( name );
584 CString ext = GetExt( name );
585 name = SourceDirName( name, FALSE );
586 CString response = dirDefine.Left(8);
588 fprintf( pAltFile,
589 "\n\n\n{%s}%s{$(OUTDIR)}.obj:\n"
590 "\t@rem <<$(OUTDIR)\\%s.cl\n"
591 "\t$(CFILEFLAGS)\n"
592 "\t$(CFLAGS_%s)\n"
593 "<<KEEP\n"
594 "\t$(CPP) @$(OUTDIR)\\%s.cl %%s\n",
595 (const char*)name,
596 (const char*)ext,
597 (const char*)response,
598 (const char*)dirDefine,
599 (const char*)response
602 fprintf( pAltFile,
603 "\n\n\nBATCH_%s:\n"
604 "\t@rem <<$(OUTDIR)\\%s.cl\n"
605 "\t$(CFILEFLAGS)\n"
606 "\t$(CFLAGS_%s)\n"
607 "\t$(FILES_%s)\n"
608 "<<KEEP\n"
609 "\t$(TIMESTART)\n"
610 "\t$(CPP) @$(OUTDIR)\\%s.cl\n"
611 "\t$(TIMESTOP)\n",
612 (const char*)dirDefine,
613 (const char*)response,
614 (const char*)dirDefine,
615 (const char*)dirDefine,
616 (const char*)response
621 // Loop through one more time and build the final batch build
622 // rule
624 fprintf( pAltFile,
625 "\n\n\nBATCH_BUILD_OBJECTS:\t\t\\\n");
627 next = dirList.GetStartPosition();
628 while( next ){
629 dirList.GetNextAssoc( next, name, pVal);
630 CString dirDefine = DirDefine( name );
632 fprintf( pAltFile,
633 "\tBATCH_%s\t\t\\\n", dirDefine );
636 fprintf( pAltFile,
637 "\n\n");
641 static void ProcessFiles(){
642 CFileRecord *pRec;
643 BOOL bFound;
644 POSITION next;
645 CString name;
647 // search all the files for headers, adding each one to the list when found
648 // rather than do it recursively, it simple marks each one it's done
649 // and starts over, stopping only when all are marked as done
651 next = fileMap.GetStartPosition();
652 while( next ){
653 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
654 if( pRec->m_bVisited == FALSE && pRec->m_bSystem == FALSE ){
655 // mark this file as already done so we don't read it again
656 // to find its headers
657 pRec->m_bVisited = TRUE;
658 pRec->ProcessFile();
659 // Start searching from the beginning again
660 // because ProcessFile may have added new files
661 // and changed the GetNextAssoc order
662 next = fileMap.GetStartPosition();
671 CMapStringToPtr CFileRecord::fileMap; // contains all allocated CFileRecords
672 CStringArray CFileRecord::orderedFileNames;
673 CMapStringToPtr CFileRecord::includeMap; // pointers to CFileRecords in fileMap
674 CMapStringToPtr CFileRecord::noDependMap; // no data, just an index
676 int main( int argc, char** argv ){
677 int i = 1;
678 char *pStr;
679 static int iRecursion = 0; // Track levels of recursion.
680 static CString outputFileName;
682 // Entering.
683 iRecursion++;
685 while( i < argc ){
686 if( argv[i][0] == '-' || argv[i][0] == '/' ){
687 switch( argv[i][1] ){
689 case 'i':
690 case 'I':
691 if( argv[i][2] != 0 ){
692 pStr = &(argv[i][2]);
694 else {
695 i++;
696 pStr = argv[i];
698 if( pStr == 0 || *pStr == '-' || *pStr == '/' ){
699 goto usage;
701 else {
702 AddIncludeDirectory( pStr );
704 break;
706 case 'f':
707 case 'F':
708 if( argv[i][2] != 0 ){
709 pStr = &(argv[i][2]);
711 else {
712 i++;
713 pStr = argv[i];
715 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
716 goto usage;
718 else {
719 CStdioFile f;
720 CString s;
721 if( f.Open( pStr, CFile::modeRead ) ){
722 while(f.ReadString(s)){
723 s.TrimLeft();
724 s.TrimRight();
725 if( s.GetLength() ){
726 CFileRecord::AddFile( s, NULL, FALSE, TRUE );
729 f.Close();
731 else {
732 fprintf(stderr,"makedep: file not found: %s", pStr );
733 exit(-1);
736 break;
738 case 'o':
739 case 'O':
740 if( argv[i][2] != 0 ){
741 pStr = &(argv[i][2]);
743 else {
744 i++;
745 pStr = argv[i];
747 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
748 goto usage;
750 else {
751 CStdioFile f;
752 CString s;
753 outputFileName = pStr;
754 if(!(pAltFile = fopen(pStr, "w+"))) {
755 fprintf(stderr, "makedep: file not found: %s", pStr );
756 exit(-1);
759 break;
761 case '1':
762 if( argv[i][2] == '6') {
763 b16 = TRUE;
765 break;
767 case 's':
768 case 'S':
769 bSimple = TRUE;
770 break;
774 case 'h':
775 case 'H':
776 case '?':
777 usage:
778 fprintf(stderr, "usage: makedep -I <dirname> -F <filelist> <filename>\n"
779 " -I <dirname> Directory name, can be repeated\n"
780 " -F <filelist> List of files to scan, one per line\n"
781 " -O <outputFile> File to write output, default stdout\n");
782 exit(-1);
785 else if( argv[i][0] == '@' ){
786 // file contains our commands.
787 CStdioFile f;
788 CString s;
789 int iNewArgc = 0;
790 char **apNewArgv = new char*[5000];
791 memset(apNewArgv, 0, sizeof(apNewArgv));
793 // First one is always the name of the exe.
794 apNewArgv[0] = argv[0];
795 iNewArgc++;
797 const char *pTraverse;
798 const char *pBeginArg;
799 if( f.Open( &argv[i][1], CFile::modeRead ) ){
800 while( iNewArgc < 5000 && f.ReadString(s) ) {
801 // Scan the string for args, and do the right thing.
802 pTraverse = (const char *)s;
803 while(iNewArgc < 5000 && *pTraverse) {
804 if(isspace(*pTraverse)) {
805 pTraverse++;
806 continue;
809 // Extract to next space.
810 pBeginArg = pTraverse;
811 do {
812 pTraverse++;
814 while(*pTraverse && !isspace(*pTraverse));
815 apNewArgv[iNewArgc] = new char[pTraverse - pBeginArg + 1];
816 memset(apNewArgv[iNewArgc], 0, pTraverse - pBeginArg + 1);
817 strncpy(apNewArgv[iNewArgc], pBeginArg, pTraverse - pBeginArg);
818 iNewArgc++;
821 f.Close();
824 // Recurse if needed.
825 if(iNewArgc > 1) {
826 main(iNewArgc, apNewArgv);
829 // Free off the argvs (but not the very first one which we didn't allocate).
830 while(iNewArgc > 1) {
831 iNewArgc--;
832 delete [] apNewArgv[iNewArgc];
834 delete [] apNewArgv;
836 else {
837 CFileRecord::AddFile( argv[i], NULL, FALSE, TRUE );
839 i++;
842 // Only of the very bottom level of recursion do we do this.
843 if(iRecursion == 1) {
845 // only write the results out if no errors encountered
846 if (mainReturn == 0) {
847 CFileRecord::ProcessFiles();
848 if( !bSimple ){
849 CFileRecord::PrintTargets("OBJ_FILES", "\\");
850 if(b16) {
851 CFileRecord::PrintTargets("LINK_OBJS", "+\\");
853 else {
854 CFileRecord::PrintTargets("LINK_OBJS", "^");
856 CFileRecord::PrintSources();
857 CFileRecord::PrintBuildRules();
859 CFileRecord::PrintDependancies();
862 if(pAltFile != stdout) {
863 fclose(pAltFile);
864 if (mainReturn != 0) {
865 remove(outputFileName); // kill output file if returning an error
869 iRecursion--;
871 if (iRecursion == 0 )
873 // last time through -- clean up allocated CFileRecords!
874 CFileRecord *pFRec;
875 CString name;
876 POSITION next;
878 next = CFileRecord::fileMap.GetStartPosition();
879 while( next ){
880 CFileRecord::fileMap.GetNextAssoc( next, name, *(void**)&pFRec );
881 delete pFRec;
885 return mainReturn;