Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / config / makedep.cpp
blobec5ff762dcdb0f9f92db2cc786f62577ed9cd69d
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 FILE *pAltFile = stdout;
54 CStringArray includeDirectories;
56 // turn a file, relative path or other into an absolute path
57 // This function copied from MFC 1.52
58 BOOL PASCAL _AfxFullPath(LPSTR lpszPathOut, LPCSTR lpszFileIn)
59 // lpszPathOut = buffer of _MAX_PATH
60 // lpszFileIn = file, relative path or absolute path
61 // (both in ANSI character set)
63 OFSTRUCT of;
64 if (OpenFile(lpszFileIn, &of, OF_PARSE) != HFILE_ERROR)
66 // of.szPathName is in the OEM character set
67 OemToAnsi(of.szPathName, lpszPathOut);
68 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
69 return TRUE;
71 else
73 TRACE1("Warning: could not parse the path %Fs\n", lpszFileIn);
74 lstrcpy(lpszPathOut, lpszFileIn); // take it literally
75 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
76 return FALSE;
80 void AddIncludeDirectory( char *pString ){
81 CString s = pString;
82 int len = s.GetLength();
83 if(len > 0 && s[len - 1] != '\\' ){
84 s += "\\";
86 includeDirectories.Add(s);
89 BOOL FileExists( const char *pString ){
90 struct _stat buf;
91 int result;
93 result = _stat( pString, &buf );
94 return (result == 0);
97 void FixPathName(CString& str) {
98 str.MakeUpper(); // all upper case
100 // now switch all forward slashes to back slashes
101 int index;
102 while ((index = str.Find('/')) != -1) {
103 str.SetAt(index, '\\');
107 void FATName(CString& csLONGName)
109 // Only relevant for 16 bits.
110 if(b16) {
111 // Convert filename to FAT (8.3) equivalent.
112 char aBuffer[2048];
114 if(GetShortPathName(csLONGName, aBuffer, 2048)) {
115 csLONGName = aBuffer;
121 class CFileRecord {
122 public:
123 CString m_shortName;
124 CString m_pathName;
125 CPtrArray m_includes; // pointers to CFileRecords in fileMap
126 BOOL m_bVisited;
127 BOOL m_bSystem;
128 BOOL m_bSource;
129 static CMapStringToPtr fileMap; // contains all allocated CFileRecords
130 static CStringArray orderedFileNames;
131 static CMapStringToPtr includeMap; // pointer to CFileRecords in fileMap
132 static CMapStringToPtr noDependMap;
134 CFileRecord( const char *shortName, const char* pFullName, BOOL bSystem, BOOL bSource):
135 m_shortName( shortName ),
136 m_pathName(),
137 m_includes(),
138 m_bVisited(FALSE),
139 m_bSource( bSource ),
140 m_bSystem(bSystem){
142 m_pathName = pFullName;
143 FixPathName(m_pathName); // all upper case for consistency
144 ASSERT(FindFileRecord(m_pathName) == NULL); // make sure it's not already in the map
145 fileMap[m_pathName] = this; // add this to the filemap, using the appropriate name as the key
146 if (bSource) {
147 orderedFileNames.Add(m_pathName); // remember the order we saw source files in
152 // open the file and grab all the includes.
154 void ProcessFile(){
155 FILE *f;
156 CString fullName;
157 BOOL bSystem;
158 DWORD lineCntr = 0;
159 char *a = new char[2048];
160 memset(a, 0, 2048);
161 char srcPath[_MAX_PATH];
163 // construct the full path
164 if (!_AfxFullPath(srcPath, m_pathName)) {
165 strcpy(srcPath, m_pathName);
168 // strip off the source filename to end up with just the path
169 LPSTR pTemp = strrchr(srcPath, '\\');
170 if (pTemp) {
171 *(pTemp + 1) = 0;
174 f = fopen(m_pathName, "r");
175 if(f != NULL && f != (FILE *)-1) {
176 setvbuf(f, NULL, _IOFBF, 32768); // use a large file buffer
177 while(fgets(a, 2047, f)) {
178 // if the string "//{{NO_DEPENDENCIES}}" is at the start of one of the
179 // first 10 lines of a file, don't build dependencies on it or any
180 // of the files it includes
181 if (lineCntr < 10) {
182 static char* pDependStr = "//{{NO_DEPENDENCIES}}";
183 if (strncmp(a, pDependStr, strlen(pDependStr)) == 0) {
184 noDependMap[m_pathName] = 0; // add it to the noDependMap
185 break; // no need for further processing of this file
188 ++lineCntr;
189 // have to handle a variety of legal syntaxes that we find in our source files:
190 // #include
191 // # include
192 // #include
193 // if the first non-whitespace char is a '#', consider this line
194 pTemp = a;
195 pTemp += strspn(pTemp, " \t"); // skip whitespace
196 if (*pTemp == '#') {
197 ++pTemp; // skip the '#'
198 pTemp += strspn(pTemp, " \t"); // skip more whitespace
199 if( !strncmp(pTemp, "include", 7) ){
200 pTemp += 7; // skip the "include"
201 pTemp += strspn(pTemp, " \t"); // skip more whitespace
202 bSystem = (*pTemp == '<'); // mark if it's a system include or not
203 // forget system files -- we just have to search all the paths
204 // every time and never find them! This change alone speeds a full
205 // depend run on my system from 5 minutes to 3:15
206 // if (bSystem || (*pTemp == '"')) {
207 if (*pTemp == '"') {
208 LPSTR pStart = pTemp + 1; // mark the start of the string
209 pTemp = pStart + strcspn(pStart, ">\" "); // find the end of the string
210 *pTemp = 0; // terminate the string
212 // construct the full pathname from the path part of the
213 // source file and the name listed here
214 fullName = srcPath;
215 fullName += pStart;
216 CFileRecord *pAddMe = AddFile( pStart, fullName, bSystem );
217 if (pAddMe) {
218 m_includes.Add(pAddMe);
224 fclose(f);
226 delete [] a;
229 void PrintIncludes(){
230 int i = 0;
231 while( i < m_includes.GetSize() ){
232 CFileRecord *pRec = (CFileRecord*) m_includes[i];
234 // Don't write out files that don't exist or are not in the namespace
235 // of the programs using it (netscape_AppletMozillaContext.h doesn't
236 // mix well with 16 bits).
237 // Also don't write out files that are in the noDependMap
238 void* lookupJunk;
239 if( !pRec->m_bVisited && pRec->m_pathName.GetLength() != 0 && !noDependMap.Lookup(pRec->m_pathName, lookupJunk)) {
241 // not supposed to have a file in the list that doesn't exist
242 ASSERT(FileExists(pRec->m_pathName));
244 CString csOutput;
245 csOutput = pRec->m_pathName;
246 FATName(csOutput);
248 fprintf(pAltFile, "\\\n %s ", (const char *) csOutput );
250 // mark this one as done so we don't do it more than once
251 pRec->m_bVisited = TRUE;
253 pRec->PrintIncludes();
255 i++;
259 void PrintDepend(){
260 CFileRecord *pRec;
261 BOOL bFound;
262 POSITION next;
263 CString name;
265 // clear all the m_bVisisted flags so we can use it to keep track
266 // of whether we've already output this file as a dependency
267 next = fileMap.GetStartPosition();
268 while( next ){
269 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
270 pRec->m_bVisited = FALSE;
273 char fname[_MAX_FNAME];
275 if (pRec->m_pathName.GetLength() != 0) {
276 if( bSimple ){
277 fprintf(pAltFile, "\n\n\n%s:\t", m_pathName );
279 else {
280 CString csOutput;
281 csOutput = m_pathName;
282 FATName(csOutput);
284 _splitpath( csOutput, NULL, NULL, fname, NULL );
286 fprintf(pAltFile, "\n\n\n$(OUTDIR)\\%s.obj: %s ", fname, (const char*) csOutput );
288 m_bVisited = TRUE; // mark it as done so we won't do it again
289 PrintIncludes();
294 static CString NormalizeFileName( const char* pName ){
295 return CString(pName);
298 static CFileRecord* FindFileRecord( const char *pName ){
299 CFileRecord* pRec = NULL;
300 CString name(pName);
301 FixPathName(name);
302 fileMap.Lookup(name, (void*&)pRec);
303 return(pRec);
305 public:
306 static CFileRecord* AddFile( const char* pShortName, const char* pFullName, BOOL bSystem = FALSE,
307 BOOL bSource = FALSE ){
309 char fullName[_MAX_PATH];
310 BOOL bFound = FALSE;
311 CString foundName;
312 CString fixedShortName;
313 CString s;
315 // normalize the name
316 fixedShortName = pShortName;
317 FixPathName(fixedShortName);
318 pShortName = fixedShortName;
320 // if it is source, we might be getting an obj file. If we do,
321 // convert it to a c or c++ file.
322 if( bSource && (strcmp(GetExt(pShortName),".obj") == 0) ){
323 char path_buffer[_MAX_PATH];
324 char fname[_MAX_FNAME] = "";
325 CString s;
327 _splitpath( pShortName, NULL, NULL, fname, NULL );
328 if( FileExists( s = CString(fname) + ".cpp") ){
329 pShortName = s;
330 pFullName = s;
332 else if( FileExists( s = CString(fname) + ".c" ) ){
333 pShortName = s;
334 pFullName = s;
336 else {
337 return 0;
341 // if pFullName was not constructed, construct it here based on the current directory
342 if (!pFullName) {
343 _AfxFullPath(fullName, pShortName);
344 pFullName = fullName;
347 // first check to see if we already have this exact file
348 CFileRecord *pRec = FindFileRecord(pFullName);
350 // if not found and not a source file check the header list --
351 // all files we've found in include directories are in the includeMap.
352 // we can save gobs of time by getting it from there
353 if (!pRec && !bSource)
354 includeMap.Lookup(fixedShortName, (void*&)pRec);
356 if (!pRec) {
357 // not in one of our lists, start scrounging on disk
359 // check the fullname first
360 if (FileExists(pFullName)) {
361 foundName = pFullName;
362 bFound = TRUE;
364 else {
365 // if still not found, search the include paths
366 int i = 0;
367 while( i < includeDirectories.GetSize() ){
368 if( FileExists( includeDirectories[i] + pShortName ) ){
369 foundName = includeDirectories[i] + pShortName;
370 bFound = TRUE;
371 break;
373 i++;
377 else {
378 // we found it
379 bFound = TRUE;
382 // source files are not allowed to be missing
383 if (bSource && !pRec && !bFound) {
384 fprintf(stderr, "Source file: %s doesn't exist\n", pFullName);
385 mainReturn = -1; // exit with an error, don't write out the results
388 #ifdef _DEBUG
389 if (!pRec && !bFound && !bSystem) {
390 fprintf(stderr, "Header not found: %s (%s)\n", pShortName, pFullName);
392 #endif
394 // if none of the above logic found it already in the list,
395 // must be a new file, add it to the list
396 if (bFound && (pRec == NULL)) {
397 pRec = new CFileRecord( pShortName, foundName, bSystem, bSource);
399 // if this one isn't a source file add it to the includeMap
400 // for performance reasons (so we can find it there next time rather
401 // than having to search the file system again)
402 if (!bSource) {
403 includeMap[pShortName] = pRec;
406 return pRec;
410 static void PrintDependancies(){
411 CFileRecord *pRec;
412 BOOL bFound;
413 POSITION next;
414 CString name;
416 // use orderedFileNames to preserve order
417 for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
418 pRec = FindFileRecord(orderedFileNames[pos]);
419 if(pRec && pRec->m_bSource ){
420 pRec->PrintDepend();
426 void PrintDepend2(){
427 CFileRecord *pRec;
428 int i;
430 if( m_includes.GetSize() != 0 ){
431 fprintf(pAltFile, "\n\n\n%s: \\\n",m_pathName );
432 i = 0;
433 while( i < m_includes.GetSize() ){
434 pRec = (CFileRecord*) m_includes[i];
435 fprintf(pAltFile, "\t\t\t%s\t\\\n",pRec->m_pathName );
436 i++;
441 static void PrintDependancies2(){
442 CFileRecord *pRec;
443 BOOL bFound;
444 POSITION next;
445 CString name;
447 next = fileMap.GetStartPosition();
448 while( next ){
449 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
450 pRec->PrintDepend2();
455 static void PrintTargets(const char *pMacroName, const char *pDelimiter){
456 CFileRecord *pRec;
457 BOOL bFound;
458 POSITION next;
459 CString name;
461 BOOL bNeedDelimiter = FALSE;
462 fprintf(pAltFile, "%s = ", pMacroName);
464 // use orderedFileNames to preserve target order
465 for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
466 pRec = FindFileRecord(orderedFileNames[pos]);
467 ASSERT(pRec);
469 if( pRec && pRec->m_bSource && pRec->m_pathName.GetLength() != 0){
470 char fname[_MAX_FNAME];
472 CString csOutput;
473 csOutput = pRec->m_pathName;
474 FATName(csOutput);
476 _splitpath( csOutput, NULL, NULL, fname, NULL );
478 if(bNeedDelimiter) {
479 fprintf(pAltFile, "%s\n", pDelimiter);
480 bNeedDelimiter = FALSE;
483 fprintf(pAltFile, " $(OUTDIR)\\%s.obj ", fname );
484 bNeedDelimiter = TRUE;
487 fprintf(pAltFile, "\n\n\n");
490 static CString DirDefine( const char *pPath ){
491 char path_buffer[_MAX_PATH];
492 char dir[_MAX_DIR] = "";
493 char dir2[_MAX_DIR] = "";
494 char fname[_MAX_FNAME] = "";
495 char ext[_MAX_EXT] = "";
496 CString s;
498 _splitpath( pPath, 0, dir, 0, ext );
500 BOOL bDone = FALSE;
502 while( dir && !bDone){
503 // remove the trailing slash
504 dir[ strlen(dir)-1] = 0;
505 _splitpath( dir, 0, dir2, fname, 0 );
506 if( strcmp( fname, "SRC" ) == 0 ){
507 strcpy( dir, dir2 );
509 else {
510 bDone = TRUE;
513 s = CString(fname) + "_" + (ext+1);
514 return s;
518 static void PrintSources(){
519 int i;
520 CString dirName, newDirName;
522 for( i=0; i< orderedFileNames.GetSize(); i++ ){
523 newDirName= DirDefine( orderedFileNames[i] );
524 if( newDirName != dirName ){
525 fprintf( pAltFile, "\n\n\nFILES_%s= $(FILES_%s) \\",
526 (const char*)newDirName, (const char*)newDirName );
527 dirName = newDirName;
529 fprintf( pAltFile, "\n\t%s^", (const char*)orderedFileNames[i] );
533 static CString SourceDirName( const char *pPath, BOOL bFileName){
534 char path_buffer[_MAX_PATH];
535 char drive[_MAX_DRIVE] = "";
536 char dir[_MAX_DIR] = "";
537 char fname[_MAX_FNAME] = "";
538 char ext[_MAX_EXT] = "";
539 CString s;
541 _splitpath( pPath, drive, dir, fname, ext );
543 s = CString(drive) + dir;
544 if( bFileName ){
545 s += CString("FNAME") + ext;
547 else {
548 // remove the trailing slash
549 s = s.Left( s.GetLength() - 1 );
551 return s;
555 static CString GetExt( const char *pPath){
556 char ext[_MAX_EXT] = "";
558 _splitpath( pPath, 0,0,0, ext );
560 CString s = CString(ext);
561 s.MakeLower();
562 return s;
565 static void PrintBuildRules(){
566 int i;
567 CString dirName;
569 CMapStringToPtr dirList;
571 for( i=0; i< orderedFileNames.GetSize(); i++ ){
572 dirList[ SourceDirName(orderedFileNames[i], TRUE) ]= 0;
575 POSITION next;
576 CString name;
577 void *pVal;
579 next = dirList.GetStartPosition();
580 while( next ){
581 dirList.GetNextAssoc( next, name, pVal);
582 CString dirDefine = DirDefine( name );
583 CString ext = GetExt( name );
584 name = SourceDirName( name, FALSE );
585 CString response = dirDefine.Left(8);
587 fprintf( pAltFile,
588 "\n\n\n{%s}%s{$(OUTDIR)}.obj:\n"
589 "\t@rem <<$(OUTDIR)\\%s.cl\n"
590 "\t$(CFILEFLAGS)\n"
591 "\t$(CFLAGS_%s)\n"
592 "<<KEEP\n"
593 "\t$(CPP) @$(OUTDIR)\\%s.cl %%s\n",
594 (const char*)name,
595 (const char*)ext,
596 (const char*)response,
597 (const char*)dirDefine,
598 (const char*)response
601 fprintf( pAltFile,
602 "\n\n\nBATCH_%s:\n"
603 "\t@rem <<$(OUTDIR)\\%s.cl\n"
604 "\t$(CFILEFLAGS)\n"
605 "\t$(CFLAGS_%s)\n"
606 "\t$(FILES_%s)\n"
607 "<<KEEP\n"
608 "\t$(TIMESTART)\n"
609 "\t$(CPP) @$(OUTDIR)\\%s.cl\n"
610 "\t$(TIMESTOP)\n",
611 (const char*)dirDefine,
612 (const char*)response,
613 (const char*)dirDefine,
614 (const char*)dirDefine,
615 (const char*)response
620 // Loop through one more time and build the final batch build
621 // rule
623 fprintf( pAltFile,
624 "\n\n\nBATCH_BUILD_OBJECTS:\t\t\\\n");
626 next = dirList.GetStartPosition();
627 while( next ){
628 dirList.GetNextAssoc( next, name, pVal);
629 CString dirDefine = DirDefine( name );
631 fprintf( pAltFile,
632 "\tBATCH_%s\t\t\\\n", dirDefine );
635 fprintf( pAltFile,
636 "\n\n");
640 static void ProcessFiles(){
641 CFileRecord *pRec;
642 BOOL bFound;
643 POSITION next;
644 CString name;
646 // search all the files for headers, adding each one to the list when found
647 // rather than do it recursively, it simple marks each one it's done
648 // and starts over, stopping only when all are marked as done
650 next = fileMap.GetStartPosition();
651 while( next ){
652 fileMap.GetNextAssoc( next, name, *(void**)&pRec );
653 if( pRec->m_bVisited == FALSE && pRec->m_bSystem == FALSE ){
654 // mark this file as already done so we don't read it again
655 // to find its headers
656 pRec->m_bVisited = TRUE;
657 pRec->ProcessFile();
658 // Start searching from the beginning again
659 // because ProcessFile may have added new files
660 // and changed the GetNextAssoc order
661 next = fileMap.GetStartPosition();
670 CMapStringToPtr CFileRecord::fileMap; // contains all allocated CFileRecords
671 CStringArray CFileRecord::orderedFileNames;
672 CMapStringToPtr CFileRecord::includeMap; // pointers to CFileRecords in fileMap
673 CMapStringToPtr CFileRecord::noDependMap; // no data, just an index
675 int main( int argc, char** argv ){
676 int i = 1;
677 char *pStr;
678 static int iRecursion = 0; // Track levels of recursion.
679 static CString outputFileName;
681 // Entering.
682 iRecursion++;
684 while( i < argc ){
685 if( argv[i][0] == '-' || argv[i][0] == '/' ){
686 switch( argv[i][1] ){
688 case 'i':
689 case 'I':
690 if( argv[i][2] != 0 ){
691 pStr = &(argv[i][2]);
693 else {
694 i++;
695 pStr = argv[i];
697 if( pStr == 0 || *pStr == '-' || *pStr == '/' ){
698 goto usage;
700 else {
701 AddIncludeDirectory( pStr );
703 break;
705 case 'f':
706 case 'F':
707 if( argv[i][2] != 0 ){
708 pStr = &(argv[i][2]);
710 else {
711 i++;
712 pStr = argv[i];
714 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
715 goto usage;
717 else {
718 CStdioFile f;
719 CString s;
720 if( f.Open( pStr, CFile::modeRead ) ){
721 while(f.ReadString(s)){
722 s.TrimLeft();
723 s.TrimRight();
724 if( s.GetLength() ){
725 CFileRecord::AddFile( s, NULL, FALSE, TRUE );
728 f.Close();
730 else {
731 fprintf(stderr,"makedep: file not found: %s", pStr );
732 exit(-1);
735 break;
737 case 'o':
738 case 'O':
739 if( argv[i][2] != 0 ){
740 pStr = &(argv[i][2]);
742 else {
743 i++;
744 pStr = argv[i];
746 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
747 goto usage;
749 else {
750 CStdioFile f;
751 CString s;
752 outputFileName = pStr;
753 if(!(pAltFile = fopen(pStr, "w+"))) {
754 fprintf(stderr, "makedep: file not found: %s", pStr );
755 exit(-1);
758 break;
760 case '1':
761 if( argv[i][2] == '6') {
762 b16 = TRUE;
764 break;
766 case 's':
767 case 'S':
768 bSimple = TRUE;
769 break;
773 case 'h':
774 case 'H':
775 case '?':
776 usage:
777 fprintf(stderr, "usage: makedep -I <dirname> -F <filelist> <filename>\n"
778 " -I <dirname> Directory name, can be repeated\n"
779 " -F <filelist> List of files to scan, one per line\n"
780 " -O <outputFile> File to write output, default stdout\n");
781 exit(-1);
784 else if( argv[i][0] == '@' ){
785 // file contains our commands.
786 CStdioFile f;
787 CString s;
788 int iNewArgc = 0;
789 char **apNewArgv = new char*[5000];
790 memset(apNewArgv, 0, sizeof(apNewArgv));
792 // First one is always the name of the exe.
793 apNewArgv[0] = argv[0];
794 iNewArgc++;
796 const char *pTraverse;
797 const char *pBeginArg;
798 if( f.Open( &argv[i][1], CFile::modeRead ) ){
799 while( iNewArgc < 5000 && f.ReadString(s) ) {
800 // Scan the string for args, and do the right thing.
801 pTraverse = (const char *)s;
802 while(iNewArgc < 5000 && *pTraverse) {
803 if(isspace(*pTraverse)) {
804 pTraverse++;
805 continue;
808 // Extract to next space.
809 pBeginArg = pTraverse;
810 do {
811 pTraverse++;
813 while(*pTraverse && !isspace(*pTraverse));
814 apNewArgv[iNewArgc] = new char[pTraverse - pBeginArg + 1];
815 memset(apNewArgv[iNewArgc], 0, pTraverse - pBeginArg + 1);
816 strncpy(apNewArgv[iNewArgc], pBeginArg, pTraverse - pBeginArg);
817 iNewArgc++;
820 f.Close();
823 // Recurse if needed.
824 if(iNewArgc > 1) {
825 main(iNewArgc, apNewArgv);
828 // Free off the argvs (but not the very first one which we didn't allocate).
829 while(iNewArgc > 1) {
830 iNewArgc--;
831 delete [] apNewArgv[iNewArgc];
833 delete [] apNewArgv;
835 else {
836 CFileRecord::AddFile( argv[i], NULL, FALSE, TRUE );
838 i++;
841 // Only of the very bottom level of recursion do we do this.
842 if(iRecursion == 1) {
844 // only write the results out if no errors encountered
845 if (mainReturn == 0) {
846 CFileRecord::ProcessFiles();
847 if( !bSimple ){
848 CFileRecord::PrintTargets("OBJ_FILES", "\\");
849 if(b16) {
850 CFileRecord::PrintTargets("LINK_OBJS", "+\\");
852 else {
853 CFileRecord::PrintTargets("LINK_OBJS", "^");
855 CFileRecord::PrintSources();
856 CFileRecord::PrintBuildRules();
858 CFileRecord::PrintDependancies();
861 if(pAltFile != stdout) {
862 fclose(pAltFile);
863 if (mainReturn != 0) {
864 remove(outputFileName); // kill output file if returning an error
868 iRecursion--;
870 if (iRecursion == 0 )
872 // last time through -- clean up allocated CFileRecords!
873 CFileRecord *pFRec;
874 CString name;
875 POSITION next;
877 next = CFileRecord::fileMap.GetStartPosition();
878 while( next ){
879 CFileRecord::fileMap.GetNextAssoc( next, name, *(void**)&pFRec );
880 delete pFRec;
884 return mainReturn;