Back to index

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