home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / mkfiles32 / makedep.cpp next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  25.4 KB  |  852 lines

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