Back to index

lightning-sunbird  0.9+nobinonly
makedep.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // Dependency building hack
00039 //
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <sys/stat.h>
00044 #include <ctype.h>
00045 #include <afxcoll.h>
00046 #include <afxtempl.h>
00047 
00048 int mainReturn = 0;
00049 BOOL b16 = FALSE;
00050 BOOL bSimple = FALSE;
00051 
00052 //     freopen won't work on stdout in win16
00053 FILE *pAltFile = stdout;
00054 
00055 CStringArray includeDirectories;
00056 
00057 // turn a file, relative path or other into an absolute path
00058 // This function copied from MFC 1.52
00059 BOOL PASCAL _AfxFullPath(LPSTR lpszPathOut, LPCSTR lpszFileIn)
00060         // lpszPathOut = buffer of _MAX_PATH
00061         // lpszFileIn = file, relative path or absolute path
00062         // (both in ANSI character set)
00063 {
00064         OFSTRUCT of;
00065         if (OpenFile(lpszFileIn, &of, OF_PARSE) != HFILE_ERROR)
00066         {
00067                 // of.szPathName is in the OEM character set
00068                 OemToAnsi(of.szPathName, lpszPathOut);
00069                 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
00070                 return TRUE;
00071         }
00072         else
00073         {
00074                 TRACE1("Warning: could not parse the path %Fs\n", lpszFileIn);
00075                 lstrcpy(lpszPathOut, lpszFileIn);  // take it literally
00076                 AnsiUpper(lpszPathOut); // paths in upper case just to be sure
00077                 return FALSE;
00078         }
00079 }
00080 
00081 void AddIncludeDirectory( char *pString ){
00082     CString s = pString;
00083        int len = s.GetLength();
00084     if(len > 0 && s[len - 1] != '\\' ){
00085         s += "\\";
00086     }
00087     includeDirectories.Add(s);
00088 }
00089 
00090 BOOL FileExists( const char *pString ){
00091     struct _stat buf;
00092     int result;
00093 
00094     result = _stat( pString, &buf );
00095     return (result == 0);
00096 }
00097 
00098 void FixPathName(CString& str) {
00099        str.MakeUpper();            // all upper case
00100 
00101        // now switch all forward slashes to back slashes
00102        int index;
00103        while ((index = str.Find('/')) != -1) {
00104               str.SetAt(index, '\\');
00105        }
00106 }
00107 
00108 void FATName(CString& csLONGName)
00109 {
00110     //  Only relevant for 16 bits.
00111     if(b16) {
00112         //  Convert filename to FAT (8.3) equivalent.
00113         char aBuffer[2048];
00114 
00115         if(GetShortPathName(csLONGName, aBuffer, 2048)) {
00116             csLONGName = aBuffer;
00117         }
00118     }
00119 }
00120 
00121 
00122 class CFileRecord {
00123 public:
00124     CString m_shortName;
00125     CString m_pathName;
00126     CPtrArray m_includes;  // pointers to CFileRecords in fileMap
00127     BOOL m_bVisited;
00128     BOOL m_bSystem;
00129     BOOL m_bSource;
00130     static CMapStringToPtr fileMap;      // contains all allocated CFileRecords
00131     static CStringArray orderedFileNames;
00132     static CMapStringToPtr includeMap;   // pointer to CFileRecords in fileMap
00133     static CMapStringToPtr noDependMap;
00134 
00135     CFileRecord( const char *shortName, const char* pFullName, BOOL bSystem, BOOL bSource):
00136                 m_shortName( shortName ),
00137                 m_pathName(),
00138                 m_includes(),
00139                 m_bVisited(FALSE),
00140                 m_bSource( bSource ),
00141                 m_bSystem(bSystem){
00142 
00143               m_pathName = pFullName;
00144               FixPathName(m_pathName);                         // all upper case for consistency
00145               ASSERT(FindFileRecord(m_pathName) == NULL);      // make sure it's not already in the map
00146         fileMap[m_pathName] = this;                     // add this to the filemap, using the appropriate name as the key
00147               if (bSource) {
00148                      orderedFileNames.Add(m_pathName);  // remember the order we saw source files in
00149               }
00150     }
00151 
00152     // 
00153     // open the file and grab all the includes.
00154     //
00155     void ProcessFile(){
00156         FILE *f;
00157               CString fullName;
00158         BOOL bSystem;
00159               DWORD lineCntr = 0;
00160               char *a = new char[2048];
00161         memset(a, 0, 2048);
00162               char srcPath[_MAX_PATH];
00163 
00164               // construct the full path
00165               if (!_AfxFullPath(srcPath, m_pathName)) {
00166                      strcpy(srcPath, m_pathName);
00167               }
00168 
00169               // strip off the source filename to end up with just the path
00170               LPSTR pTemp = strrchr(srcPath, '\\');
00171               if (pTemp) {
00172                      *(pTemp + 1) = 0;
00173               }
00174 
00175         f = fopen(m_pathName, "r");
00176         if(f != NULL && f != (FILE *)-1)  {
00177                      setvbuf(f, NULL, _IOFBF, 32768);          // use a large file buffer
00178             while(fgets(a, 2047, f)) {
00179                             // if the string "//{{NO_DEPENDENCIES}}" is at the start of one of the 
00180                             // first 10 lines of a file, don't build dependencies on it or any
00181                             // of the files it includes
00182                             if (lineCntr < 10) {
00183                                    static char* pDependStr = "//{{NO_DEPENDENCIES}}";
00184                                    if (strncmp(a, pDependStr, strlen(pDependStr)) == 0) {
00185                                           noDependMap[m_pathName] = 0;       // add it to the noDependMap
00186                                           break;                                           // no need for further processing of this file
00187                                    }
00188                             }
00189                             ++lineCntr;
00190                             // have to handle a variety of legal syntaxes that we find in our source files:
00191                             //    #include
00192                             // #   include
00193                 // #include
00194                             // if the first non-whitespace char is a '#', consider this line
00195                             pTemp = a;
00196                             pTemp += strspn(pTemp, " \t");                   // skip whitespace
00197                             if (*pTemp == '#') {
00198                                    ++pTemp;                                                // skip the '#'
00199                                    pTemp += strspn(pTemp, " \t");            // skip more whitespace
00200                                    if( !strncmp(pTemp, "include", 7) ){
00201                                           pTemp += 7;                                      // skip the "include"
00202                                           pTemp += strspn(pTemp, " \t");     // skip more whitespace
00203                                           bSystem = (*pTemp == '<');         // mark if it's a system include or not
00204                         // forget system files -- we just have to search all the paths
00205                         // every time and never find them! This change alone speeds a full
00206                         // depend run on my system from 5 minutes to 3:15
00207                                           // if (bSystem || (*pTemp == '"')) {
00208                         if (*pTemp == '"') {
00209                                                  LPSTR pStart = pTemp + 1;   // mark the start of the string
00210                                                  pTemp = pStart + strcspn(pStart, ">\" "); // find the end of the string
00211                                                  *pTemp = 0;                               // terminate the string
00212 
00213                                                  // construct the full pathname from the path part of the 
00214                                                  // source file and the name listed here
00215                                                  fullName = srcPath;
00216                                                  fullName += pStart;
00217                                                  CFileRecord *pAddMe = AddFile( pStart, fullName, bSystem );
00218                                                  if (pAddMe) {
00219                                                         m_includes.Add(pAddMe);
00220                                                  }
00221                                           }
00222                                    }
00223                             }
00224             }
00225             fclose(f);
00226         }
00227         delete [] a;
00228     }
00229 
00230     void PrintIncludes(){
00231         int i = 0;
00232         while( i < m_includes.GetSize() ){
00233             CFileRecord *pRec = (CFileRecord*) m_includes[i];
00234 
00235             //  Don't write out files that don't exist or are not in the namespace
00236             //      of the programs using it (netscape_AppletMozillaContext.h doesn't
00237             //      mix well with 16 bits).
00238                      // Also don't write out files that are in the noDependMap
00239                      void*  lookupJunk;
00240             if( !pRec->m_bVisited && pRec->m_pathName.GetLength() != 0 && !noDependMap.Lookup(pRec->m_pathName, lookupJunk)) {
00241 
00242                             // not supposed to have a file in the list that doesn't exist
00243                             ASSERT(FileExists(pRec->m_pathName));
00244 
00245                 CString csOutput;
00246                 csOutput = pRec->m_pathName;
00247                 FATName(csOutput);
00248 
00249                             fprintf(pAltFile, "\\\n    %s ", (const char *) csOutput );
00250 
00251                             // mark this one as done so we don't do it more than once
00252                 pRec->m_bVisited = TRUE;
00253 
00254                 pRec->PrintIncludes();
00255             }
00256             i++;
00257         }
00258     }
00259 
00260     void PrintDepend(){
00261         CFileRecord *pRec;
00262         BOOL bFound;
00263         POSITION next;
00264         CString name;
00265 
00266               // clear all the m_bVisisted flags so we can use it to keep track
00267               // of whether we've already output this file as a dependency
00268         next = fileMap.GetStartPosition();
00269         while( next ){
00270             fileMap.GetNextAssoc( next, name, *(void**)&pRec );
00271             pRec->m_bVisited = FALSE;
00272         }
00273 
00274         char fname[_MAX_FNAME];
00275 
00276               if (pRec->m_pathName.GetLength() != 0) {
00277             if( bSimple ){
00278                      fprintf(pAltFile, "\n\n\n%s:\t", m_pathName );
00279             }
00280             else {
00281                 CString csOutput;
00282                 csOutput = m_pathName;
00283                 FATName(csOutput);
00284 
00285                      _splitpath( csOutput, NULL, NULL, fname, NULL );
00286 
00287                      fprintf(pAltFile, "\n\n\n$(OUTDIR)\\%s.obj: %s ", fname, (const char*) csOutput );
00288             }
00289                m_bVisited = TRUE;         // mark it as done so we won't do it again
00290                PrintIncludes();
00291               }
00292     }
00293 
00294 
00295     static CString NormalizeFileName( const char* pName ){
00296         return CString(pName);
00297     }
00298 
00299     static CFileRecord* FindFileRecord( const char *pName ){
00300               CFileRecord* pRec = NULL;
00301               CString name(pName);
00302               FixPathName(name);
00303               fileMap.Lookup(name, (void*&)pRec);
00304               return(pRec);
00305     }
00306 public:
00307     static CFileRecord* AddFile( const char* pShortName, const char* pFullName, BOOL bSystem = FALSE, 
00308                 BOOL bSource = FALSE ){
00309 
00310               char fullName[_MAX_PATH];
00311               BOOL bFound = FALSE;
00312               CString foundName;
00313               CString fixedShortName;
00314         CString s;
00315 
00316         // normalize the name
00317         fixedShortName = pShortName;
00318         FixPathName(fixedShortName);
00319         pShortName = fixedShortName;
00320 
00321         // if it is source, we might be getting an obj file.  If we do,
00322         //  convert it to a c or c++ file.
00323         if( bSource && (strcmp(GetExt(pShortName),".obj") == 0) ){
00324             char path_buffer[_MAX_PATH];
00325             char fname[_MAX_FNAME] = "";
00326             CString s;
00327 
00328             _splitpath( pShortName, NULL, NULL, fname, NULL );
00329             if( FileExists( s = CString(fname) + ".cpp") ){
00330                 pShortName = s;
00331                 pFullName = s;
00332             }
00333             else if( FileExists( s = CString(fname) + ".c" ) ){
00334                 pShortName = s;
00335                 pFullName = s;
00336             }
00337             else {
00338                 return 0;
00339             }
00340         }
00341 
00342               // if pFullName was not constructed, construct it here based on the current directory
00343               if (!pFullName) {
00344                      _AfxFullPath(fullName, pShortName);
00345                      pFullName = fullName;
00346               }
00347               
00348               // first check to see if we already have this exact file
00349               CFileRecord *pRec = FindFileRecord(pFullName);
00350 
00351         // if not found and not a source file check the header list --
00352         // all files we've found in include directories are in the includeMap.
00353         // we can save gobs of time by getting it from there
00354         if (!pRec && !bSource)
00355             includeMap.Lookup(fixedShortName, (void*&)pRec);
00356 
00357         if (!pRec) {
00358             // not in one of our lists, start scrounging on disk
00359 
00360             // check the fullname first
00361             if (FileExists(pFullName)) {
00362                 foundName = pFullName;
00363                 bFound = TRUE;
00364             }
00365             else {
00366                 // if still not found, search the include paths
00367                 int i = 0;
00368                 while( i < includeDirectories.GetSize() ){
00369                     if( FileExists( includeDirectories[i] + pShortName ) ){
00370                         foundName = includeDirectories[i] + pShortName;
00371                         bFound = TRUE;
00372                         break;
00373                     }
00374                     i++;
00375                 }
00376             }
00377         }
00378         else {
00379             // we found it
00380             bFound = TRUE;
00381         }
00382 
00383               // source files are not allowed to be missing
00384               if (bSource && !pRec && !bFound) {
00385                      fprintf(stderr, "Source file: %s doesn't exist\n", pFullName);
00386                      mainReturn = -1;            // exit with an error, don't write out the results
00387               }
00388 
00389 #ifdef _DEBUG
00390               if (!pRec && !bFound && !bSystem) {
00391                      fprintf(stderr, "Header not found: %s (%s)\n", pShortName, pFullName);
00392               }
00393 #endif
00394 
00395               // if none of the above logic found it already in the list, 
00396         // must be a new file, add it to the list
00397         if (bFound && (pRec == NULL)) {
00398             pRec = new CFileRecord( pShortName, foundName, bSystem, bSource);
00399 
00400                      // if this one isn't a source file add it to the includeMap
00401                      // for performance reasons (so we can find it there next time rather
00402                      // than having to search the file system again)
00403                      if (!bSource) {
00404                             includeMap[pShortName] = pRec;
00405                      }
00406         }
00407         return pRec;
00408     }
00409 
00410 
00411     static void PrintDependancies(){
00412         CFileRecord *pRec;
00413         BOOL bFound;
00414         POSITION next;
00415         CString name;
00416 
00417               // use orderedFileNames to preserve order
00418               for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
00419                      pRec = FindFileRecord(orderedFileNames[pos]);
00420             if(pRec && pRec->m_bSource ){
00421                 pRec->PrintDepend();
00422                      }
00423               }
00424     }
00425 
00426 
00427     void PrintDepend2(){
00428         CFileRecord *pRec;
00429         int i;
00430 
00431         if( m_includes.GetSize() != 0 ){
00432                      fprintf(pAltFile, "\n\n\n%s: \\\n",m_pathName );
00433             i = 0;
00434             while( i < m_includes.GetSize() ){
00435                 pRec = (CFileRecord*) m_includes[i];
00436                      fprintf(pAltFile, "\t\t\t%s\t\\\n",pRec->m_pathName );
00437                 i++;
00438             }
00439         }
00440     }
00441 
00442     static void PrintDependancies2(){
00443         CFileRecord *pRec;
00444         BOOL bFound;
00445         POSITION next;
00446         CString name;
00447 
00448         next = fileMap.GetStartPosition();
00449         while( next ){
00450             fileMap.GetNextAssoc( next, name, *(void**)&pRec );
00451             pRec->PrintDepend2();
00452         }
00453     }
00454 
00455 
00456     static void PrintTargets(const char *pMacroName, const char *pDelimiter){
00457         CFileRecord *pRec;
00458         BOOL bFound;
00459         POSITION next;
00460         CString name;
00461 
00462         BOOL bNeedDelimiter = FALSE;
00463               fprintf(pAltFile, "%s = ", pMacroName);        
00464 
00465               // use orderedFileNames to preserve target order
00466               for (int pos = 0; pos < orderedFileNames.GetSize(); pos++) {
00467                      pRec = FindFileRecord(orderedFileNames[pos]);
00468                      ASSERT(pRec);
00469 
00470             if( pRec && pRec->m_bSource && pRec->m_pathName.GetLength() != 0){
00471                 char fname[_MAX_FNAME];
00472 
00473                 CString csOutput;
00474                 csOutput = pRec->m_pathName;
00475                 FATName(csOutput);
00476 
00477                 _splitpath( csOutput, NULL, NULL, fname, NULL );
00478 
00479                 if(bNeedDelimiter)  {
00480                     fprintf(pAltFile, "%s\n", pDelimiter);
00481                     bNeedDelimiter = FALSE;
00482                 }
00483 
00484                             fprintf(pAltFile, "     $(OUTDIR)\\%s.obj   ", fname );
00485                 bNeedDelimiter = TRUE;
00486             }
00487         }
00488               fprintf(pAltFile, "\n\n\n");        
00489     }
00490 
00491     static CString DirDefine( const char *pPath ){
00492         char path_buffer[_MAX_PATH];
00493         char dir[_MAX_DIR] = "";
00494         char dir2[_MAX_DIR] = "";
00495         char fname[_MAX_FNAME] = "";
00496         char ext[_MAX_EXT] = "";
00497         CString s;
00498 
00499         _splitpath( pPath, 0, dir, 0, ext );
00500 
00501         BOOL bDone = FALSE;
00502 
00503         while( dir && !bDone){
00504             // remove the trailing slash
00505             dir[ strlen(dir)-1] = 0;
00506             _splitpath( dir, 0, dir2, fname, 0 );
00507             if( strcmp( fname, "SRC" ) == 0 ){
00508                 strcpy( dir, dir2 );
00509             }
00510             else {
00511                 bDone = TRUE;
00512             }
00513         }
00514         s = CString(fname) + "_" + (ext+1);
00515         return s;
00516     }
00517 
00518 
00519     static void PrintSources(){
00520         int i;
00521         CString dirName, newDirName;
00522 
00523         for( i=0; i< orderedFileNames.GetSize(); i++ ){
00524             newDirName= DirDefine( orderedFileNames[i] );
00525             if( newDirName != dirName ){
00526                 fprintf( pAltFile, "\n\n\nFILES_%s= $(FILES_%s) \\", 
00527                         (const char*)newDirName, (const char*)newDirName );
00528                 dirName = newDirName;
00529             }
00530             fprintf( pAltFile, "\n\t%s^", (const char*)orderedFileNames[i] );
00531         }
00532     }
00533 
00534     static CString SourceDirName( const char *pPath, BOOL bFileName){
00535         char path_buffer[_MAX_PATH];
00536         char drive[_MAX_DRIVE] = "";
00537         char dir[_MAX_DIR] = "";
00538         char fname[_MAX_FNAME] = "";
00539         char ext[_MAX_EXT] = "";
00540         CString s;
00541 
00542         _splitpath( pPath, drive, dir, fname, ext );
00543 
00544         s = CString(drive) + dir;
00545         if( bFileName ){
00546             s += CString("FNAME") + ext;
00547         }
00548         else {
00549             // remove the trailing slash
00550             s = s.Left( s.GetLength() - 1 );
00551         }
00552         return s;
00553     }
00554 
00555 
00556     static CString GetExt( const char *pPath){
00557         char ext[_MAX_EXT] = "";
00558 
00559         _splitpath( pPath, 0,0,0, ext );
00560 
00561         CString s = CString(ext);
00562         s.MakeLower();
00563         return s;
00564     }
00565 
00566     static void PrintBuildRules(){
00567         int i;
00568         CString dirName;
00569         
00570         CMapStringToPtr dirList;
00571 
00572         for( i=0; i< orderedFileNames.GetSize(); i++ ){
00573             dirList[ SourceDirName(orderedFileNames[i], TRUE) ]= 0;
00574         }
00575 
00576         POSITION next;
00577         CString name;
00578         void *pVal;
00579 
00580         next = dirList.GetStartPosition();
00581         while( next ){
00582             dirList.GetNextAssoc( next, name, pVal);
00583             CString dirDefine = DirDefine( name );
00584             CString ext = GetExt( name );
00585             name = SourceDirName( name, FALSE );
00586             CString response = dirDefine.Left(8);
00587 
00588             fprintf( pAltFile, 
00589                 "\n\n\n{%s}%s{$(OUTDIR)}.obj:\n"
00590                 "\t@rem <<$(OUTDIR)\\%s.cl\n"
00591                 "\t$(CFILEFLAGS)\n"
00592                 "\t$(CFLAGS_%s)\n"
00593                 "<<KEEP\n"
00594                 "\t$(CPP) @$(OUTDIR)\\%s.cl %%s\n",
00595                 (const char*)name,
00596                 (const char*)ext,
00597                 (const char*)response,
00598                 (const char*)dirDefine,
00599                 (const char*)response
00600             );
00601 
00602             fprintf( pAltFile, 
00603                 "\n\n\nBATCH_%s:\n"
00604                 "\t@rem <<$(OUTDIR)\\%s.cl\n"
00605                 "\t$(CFILEFLAGS)\n"
00606                 "\t$(CFLAGS_%s)\n"
00607                 "\t$(FILES_%s)\n"
00608                 "<<KEEP\n"
00609                 "\t$(TIMESTART)\n"
00610                 "\t$(CPP) @$(OUTDIR)\\%s.cl\n"
00611                 "\t$(TIMESTOP)\n",
00612                 (const char*)dirDefine,
00613                 (const char*)response,
00614                 (const char*)dirDefine,
00615                 (const char*)dirDefine,
00616                 (const char*)response
00617             );
00618         }
00619 
00620         //
00621         // Loop through one more time and build the final batch build
00622         //  rule
00623         //
00624         fprintf( pAltFile, 
00625             "\n\n\nBATCH_BUILD_OBJECTS:\t\t\\\n");
00626 
00627         next = dirList.GetStartPosition();
00628         while( next ){
00629             dirList.GetNextAssoc( next, name, pVal);
00630             CString dirDefine = DirDefine( name );
00631 
00632             fprintf( pAltFile, 
00633                 "\tBATCH_%s\t\t\\\n", dirDefine );
00634         }
00635 
00636         fprintf( pAltFile, 
00637             "\n\n");
00638     }
00639         
00640 
00641     static void ProcessFiles(){
00642         CFileRecord *pRec;
00643         BOOL bFound;
00644         POSITION next;
00645         CString name;
00646 
00647               // search all the files for headers, adding each one to the list when found
00648               // rather than do it recursively, it simple marks each one it's done
00649               // and starts over, stopping only when all are marked as done
00650 
00651         next = fileMap.GetStartPosition();
00652         while( next ){
00653             fileMap.GetNextAssoc( next, name, *(void**)&pRec );
00654             if( pRec->m_bVisited == FALSE && pRec->m_bSystem == FALSE ){
00655                             // mark this file as already done so we don't read it again
00656                             // to find its headers
00657                 pRec->m_bVisited = TRUE;
00658                 pRec->ProcessFile();
00659                 // Start searching from the beginning again
00660                             // because ProcessFile may have added new files 
00661                             // and changed the GetNextAssoc order
00662                 next = fileMap.GetStartPosition();       
00663 
00664             }
00665         }
00666     }
00667 
00668 
00669 };
00670 
00671 CMapStringToPtr CFileRecord::fileMap;           // contains all allocated CFileRecords
00672 CStringArray CFileRecord::orderedFileNames;
00673 CMapStringToPtr CFileRecord::includeMap;        // pointers to CFileRecords in fileMap
00674 CMapStringToPtr CFileRecord::noDependMap;       // no data, just an index
00675 
00676 int main( int argc, char** argv ){
00677     int i = 1;
00678     char *pStr;
00679     static int iRecursion = 0;     //     Track levels of recursion.
00680        static CString outputFileName;
00681     
00682     // Entering.
00683     iRecursion++;
00684 
00685     while( i < argc ){
00686         if( argv[i][0] == '-' || argv[i][0] == '/' ){
00687             switch( argv[i][1] ){
00688 
00689             case 'i':
00690             case 'I':
00691                 if( argv[i][2] != 0 ){
00692                     pStr = &(argv[i][2]);
00693                 }
00694                 else {
00695                     i++;
00696                     pStr = argv[i];
00697                 }
00698                 if( pStr == 0 || *pStr == '-' || *pStr == '/' ){
00699                     goto usage;
00700                 }
00701                 else {
00702                     AddIncludeDirectory( pStr );
00703                 }
00704                 break;
00705 
00706             case 'f':
00707             case 'F':
00708                 if( argv[i][2] != 0 ){
00709                     pStr = &(argv[i][2]);
00710                 }
00711                 else {
00712                     i++;
00713                     pStr = argv[i];
00714                 }
00715                 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
00716                     goto usage;
00717                 }
00718                 else {
00719                     CStdioFile f;
00720                     CString s;
00721                     if( f.Open( pStr, CFile::modeRead ) ){
00722                         while(f.ReadString(s)){
00723                             s.TrimLeft();
00724                             s.TrimRight();
00725                             if( s.GetLength() ){
00726                                 CFileRecord::AddFile( s, NULL, FALSE, TRUE );
00727                             }
00728                         } 
00729                         f.Close();
00730                     }
00731                     else {
00732                         fprintf(stderr,"makedep: file not found: %s", pStr );
00733                         exit(-1);
00734                     }
00735                 }
00736                 break;
00737 
00738             case 'o':
00739             case 'O':
00740                 if( argv[i][2] != 0 ){
00741                     pStr = &(argv[i][2]);
00742                 }
00743                 else {
00744                     i++;
00745                     pStr = argv[i];
00746                 }
00747                 if( pStr == 0 || *pStr == '-' || *pStr == '/'){
00748                     goto usage;
00749                 }
00750                 else {
00751                     CStdioFile f;
00752                     CString s;
00753                                    outputFileName = pStr;
00754                                    if(!(pAltFile = fopen(pStr, "w+")))       {
00755                         fprintf(stderr, "makedep: file not found: %s", pStr );
00756                         exit(-1);
00757                     }
00758                 }
00759                 break;
00760 
00761             case '1':
00762                 if( argv[i][2] == '6')  {
00763                     b16 = TRUE;
00764                 }
00765                 break;
00766 
00767             case 's':
00768             case 'S':
00769                 bSimple = TRUE;
00770                 break;
00771 
00772 
00773 
00774             case 'h':
00775             case 'H':
00776             case '?':
00777             usage:
00778                 fprintf(stderr, "usage: makedep -I <dirname> -F <filelist> <filename>\n"
00779                        "  -I <dirname>    Directory name, can be repeated\n"
00780                        "  -F <filelist>   List of files to scan, one per line\n"
00781                        "  -O <outputFile> File to write output, default stdout\n");
00782                 exit(-1);
00783             }
00784         }
00785         else if( argv[i][0] == '@' ){
00786               //     file contains our commands.
00787                CStdioFile f;
00788            CString s;
00789            int iNewArgc = 0;
00790            char **apNewArgv = new char*[5000];
00791                      memset(apNewArgv, 0, sizeof(apNewArgv));
00792 
00793                      //     First one is always the name of the exe.
00794                      apNewArgv[0] = argv[0];
00795                      iNewArgc++;
00796 
00797                      const char *pTraverse;
00798                      const char *pBeginArg;
00799                if( f.Open( &argv[i][1], CFile::modeRead ) ){
00800                while( iNewArgc < 5000 && f.ReadString(s) )     {
00801                                    //     Scan the string for args, and do the right thing.
00802                                    pTraverse = (const char *)s;
00803                                    while(iNewArgc < 5000 && *pTraverse)      {
00804                                           if(isspace(*pTraverse))     {
00805                                                         pTraverse++;
00806                                                         continue;
00807                                           }
00808 
00809                                           //     Extract to next space.
00810                                           pBeginArg = pTraverse;
00811                                           do     {
00812                                                  pTraverse++;
00813                                           }
00814                                           while(*pTraverse && !isspace(*pTraverse));
00815                                           apNewArgv[iNewArgc] = new char[pTraverse - pBeginArg + 1];
00816                                           memset(apNewArgv[iNewArgc], 0, pTraverse - pBeginArg + 1);
00817                                           strncpy(apNewArgv[iNewArgc], pBeginArg, pTraverse - pBeginArg);
00818                                           iNewArgc++;
00819                                    }
00820                    } 
00821                f.Close();
00822               }
00823               
00824               //     Recurse if needed.
00825               if(iNewArgc > 1)     {
00826                      main(iNewArgc, apNewArgv);
00827               }
00828               
00829               //     Free off the argvs (but not the very first one which we didn't allocate).
00830               while(iNewArgc > 1)  {
00831                      iNewArgc--;
00832                      delete [] apNewArgv[iNewArgc];
00833               }
00834               delete [] apNewArgv;
00835         }
00836         else {
00837             CFileRecord::AddFile( argv[i], NULL, FALSE, TRUE );
00838         }
00839         i++;
00840     }
00841     
00842     // Only of the very bottom level of recursion do we do this.
00843     if(iRecursion == 1)     {
00844 
00845               // only write the results out if no errors encountered
00846               if (mainReturn == 0) {
00847                      CFileRecord::ProcessFiles();
00848             if( !bSimple ){
00849                      CFileRecord::PrintTargets("OBJ_FILES", "\\");
00850                 if(b16) {
00851                          CFileRecord::PrintTargets("LINK_OBJS", "+\\");
00852                 }
00853                 else    {
00854                          CFileRecord::PrintTargets("LINK_OBJS", "^");
00855                 }
00856                 CFileRecord::PrintSources();
00857                 CFileRecord::PrintBuildRules();
00858             }
00859               CFileRecord::PrintDependancies();
00860               }
00861            
00862               if(pAltFile != stdout)      {
00863                      fclose(pAltFile);
00864                      if (mainReturn != 0) {
00865                             remove(outputFileName);     // kill output file if returning an error
00866                      }
00867               }
00868        }
00869        iRecursion--;
00870 
00871     if (iRecursion == 0 )
00872     {
00873         // last time through -- clean up allocated CFileRecords!
00874         CFileRecord *pFRec;
00875         CString     name;
00876         POSITION    next;
00877 
00878         next = CFileRecord::fileMap.GetStartPosition();
00879         while( next ){
00880             CFileRecord::fileMap.GetNextAssoc( next, name, *(void**)&pFRec );
00881             delete pFRec;
00882         }
00883     }
00884 
00885     return mainReturn;
00886 }