Code

new file
[inkscape.git] / src / deptool.cpp
1 /**
2  * DepTool dependency tool
3  *
4  * This is a simple dependency generator coded in C++
5  *
6  * Authors:
7  *   Bob Jamison
8  *
9  * Copyright (C) 2006 Bob Jamison
10  *
11  *  This library is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU Lesser General Public
13  *  License as published by the Free Software Foundation; either
14  *  version 2.1 of the License, or (at your option) any later version.
15  *
16  *  This library is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  Lesser General Public License for more details.
20  *
21  *  You should have received a copy of the GNU Lesser General Public
22  *  License along with this library; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  */
26 /*
27  INSTRUCTIONS
29  1.  First you optionally create a file named 'make.exclude.'  This
30  lists the file names relative to the current directory.  Lines starting
31  with a '#' are ignored.  Here is an example:
32  
33 ========= SNIP ======== 
34 ######################################################################
35 # File: make.exclude
36 #
37 # This is a list of files to exclude from building, using DepTool
38 #
39 ######################################################################
42 ast
43 bonobo
45 dialogs/filedialog-win32.cpp
46 display/testnr.cpp
47 display/bezier-utils-test.cpp
48 dom/work
49 #next line is ignored
50 #dom/odf/SvgOdg.cpp
51 extension/api.cpp
52 ========= SNIP ======== 
54 2.  Run deptool.  This will take a few seconds to scan all of your files
55 and make its dependency lists.  Three files are created:
56 make.files: lists all of the files that were considered
57 make.dep: contains the output INCLUDE and OBJECT declarations
58     for you to include and use in your makefile.  It also contains
59     the dependency listings.
60 make.ref: contains a reverse-dependency listing.  This takes each file
61     and recursively determines which other files include it, and how
62     far the nesting is.
64 3.  Include deptool.mk in your makefile.
66 */
69 #include <stdio.h>
70 #include <stdarg.h>
71 #include <time.h>
72 #include <sys/time.h>
74 #include <dirent.h>
75 #include <sys/stat.h>
77 #include <string>
78 #include <set>
79 #include <map>
80 #include <vector>
83 //# This will allow us to redefine the string in the future
84 typedef std::string DTString;
86 /**
87  *  Class which holds information for each file.
88  */
89 class FileRec
90 {
91 public:
93     typedef enum
94         {
95         UNKNOWN,
96         CFILE,
97         HFILE,
98         OFILE
99         } FileType;
101     /**
102      *  Constructor
103      */
104     FileRec()
105         {type = UNKNOWN;}
107     /**
108      *  Copy constructor
109      */
110     FileRec(const FileRec &other)
111         {assign(other);}
112     /**
113      *  Constructor
114      */
115     FileRec(int typeVal)
116         {init(); type = typeVal;}
117     /**
118      *  Assignment operator
119      */
120     FileRec &operator=(const FileRec &other)
121         {assign(other); return *this;}
124     /**
125      *  Destructor
126      */
127     ~FileRec()
128         {}
130     /**
131      *  Directory part of the file name
132      */
133     DTString path;
135     /**
136      *  Base name, sans directory and suffix
137      */
138     DTString baseName;
140     /**
141      *  File extension, such as cpp or h
142      */
143     DTString suffix;
145     /**
146      *  Type of file: CFILE, HFILE, OFILE
147      */
148     int type;
150     /**
151      *  'Distance' of inclusion from a file that depends on this one.
152      */
153     int distance;
155     /**
156      * Used to list files ref'd by this one, in the case of allFiles,
157      * or other files which reference this one, such as refFiles;
158      */
159     std::map<DTString, FileRec *> files;
162 private:
164     void init()
165         {
166         }
168     void assign(const FileRec &other)
169         {
170         type     = other.type;
171         distance = other.distance;
172         baseName = other.baseName;
173         suffix   = other.suffix;
174         files    = other.files;
175         }
177 };
181 /**
182  *  Main class which does the work.
183  */
184 class DepTool
186 public:
188     /**
189      *  Constructor
190      */
191     DepTool();
193     /**
194      *  Destructor
195      */
196     virtual ~DepTool();
198     /**
199      * Creates the list of all file names which will be
200      * candidates for further processing.  Reads make.exclude
201      * to see which files for directories to leave out.
202      */
203     virtual bool createFileList();
206     /**
207      *  Generates the forward and reverse dependency lists
208      */
209     virtual bool generateDependencies();
211     /**
212      *  Calls the other two methods, then generates the files.
213      */
214     virtual bool run();
217 private:
219     /**
220      *
221      */
222     void reset();
224     /**
225      *
226      */
227     void error(char *fmt, ...);
229     /**
230      *
231      */
232     void trace(char *fmt, ...);
234     /**
235      *  Removes whitespace from beginning and end of a string
236      */
237     DTString trim(const DTString &val);
239     /**
240      *
241      */
242     DTString getSuffix(const DTString &fname);
244     /**
245      *
246      */
247     void parseName(const DTString &fullname,
248                    DTString &path,
249                    DTString &basename,
250                    DTString &suffix);
252     /**
253      *
254      */
255     int get(int pos);
257     /**
258      *
259      */
260     int skipwhite(int pos);
262     /**
263      *
264      */
265     int getword(int pos, DTString &ret);
267     /**
268      *
269      */
270     bool sequ(int pos, char *key);
272     /**
273      *
274      */
275     bool listFilesInDirectory(const DTString &dirname, int depth);
277     /**
278      *
279      */
280     bool saveFileList();
282     /**
283      *
284      */
285     bool saveDepFile();
287     /**
288      *
289      */
290     bool saveRefFile();
292     /**
293      *
294      */
295     bool addIncludeFile(FileRec *frec, const DTString &fname);
297     /**
298      *
299      */
300     bool scanFile(const DTString &fname, FileRec *frec);
302     /**
303      *
304      */
305     bool processDependency(FileRec *ofile,
306                            FileRec *include,
307                            int depth);
309     /**
310      *
311      */
312     bool processReference(FileRec *ofile,
313                           DTString &fname,
314                           int depth);
316     /**
317      *
318      */
319     std::set<DTString> excludes;
321     /**
322      *
323      */
324     std::set<DTString> excludesUsed;
326     /**
327      *
328      */
329     std::set<DTString> excludesUnused;
331     /**
332      *
333      */
334     std::vector<DTString> directories;
336     /**
337      * A list of all files which will be processed for
338      * dependencies.
339      */
340     std::map<DTString, FileRec *> allFiles;
342     /**
343      * A list of .h files, with a list for each one
344      * of which other files include them.
345      */
346     std::map<DTString, FileRec *> refFiles;
348     /**
349      * The list of .o files, and the
350      * dependencies upon them.
351      */
352     std::map<DTString, FileRec *> depFiles;
354     char *fileBuf;
355     int   fileSize;
358 };
361 //########################################################################
362 //# M A I N
363 //########################################################################
365 /**
366  * Constructor
367  */
368 DepTool::DepTool()
373 /**
374  *  Destructor
375  */
376 DepTool::~DepTool()
378     reset();
381 /**
382  *  Clean up after processing.  Called by the destructor, but should
383  *  also be called before the object is reused.
384  */
385 void DepTool::reset()
387     std::map<DTString, FileRec *>::iterator iter;
388     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
389         {
390         FileRec *frec = iter->second;
391         delete frec;
392         }
393     allFiles.clear();
394     for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
395         {
396         FileRec *frec = iter->second;
397         delete frec;
398         }
399     refFiles.clear();
400     for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
401         {
402         FileRec *frec = iter->second;
403         delete frec;
404         }
405     depFiles.clear();
407     excludes.clear();
408     excludesUsed.clear();
409     excludesUnused.clear();
413 /**
414  *  Format an error message in printf() style
415  */
416 void DepTool::error(char *fmt, ...)
418     va_list ap;
419     va_start(ap, fmt);
420     fprintf(stderr, "DepTool error: ");
421     vfprintf(stderr, fmt, ap);
422     fprintf(stderr, "\n");
423     va_end(ap);
427 /**
428  *  Format an trace message in printf() style
429  */
430 void DepTool::trace(char *fmt, ...)
432     va_list ap;
433     va_start(ap, fmt);
434     fprintf(stdout, "DepTool: ");
435     vfprintf(stdout, fmt, ap);
436     fprintf(stdout, "\n");
437     va_end(ap);
442 //########################################################################
443 //# U T I L I T Y
444 //########################################################################
446 /**
447  *  Removes whitespace from beginning and end of a string
448  */
449 DTString DepTool::trim(const DTString &s)
451     if (s.size() < 1)
452         return s;
453     
454     //Find first non-ws char
455     unsigned int begin = 0;
456     for ( ; begin < s.size() ; begin++)
457         {
458         if (!isspace(s[begin]))
459             break;
460         }
462     //Find first non-ws char, going in reverse
463     unsigned int end = s.size() - 1;
464     for ( ; end > begin ; end--)
465         {
466         if (!isspace(s[end]))
467             break;
468         }
469     //trace("begin:%d  end:%d", begin, end);
471     DTString res = s.substr(begin, end-begin+1);
472     return res;
476 /**
477  *  Parse a full path name into path, base name, and suffix
478  */
479 void DepTool::parseName(const DTString &fullname,
480                         DTString &path,
481                         DTString &basename,
482                         DTString &suffix)
484     if (fullname.size() < 2)
485         return;
487     unsigned int pos = fullname.find_last_of('/');
488     if (pos != fullname.npos && pos<fullname.size()-1)
489         {
490         path = fullname.substr(0, pos);
491         pos++;
492         basename = fullname.substr(pos, fullname.size()-pos);
493         }
494     else
495         {
496         path = "";
497         basename = fullname;
498         }
500     pos = basename.find_last_of('.');
501     if (pos != basename.npos && pos<basename.size()-1)
502         {
503         suffix   = basename.substr(pos+1, basename.size()-pos-1);
504         basename = basename.substr(0, pos);
505         }
507     //trace("parsename:%s %s %s", path.c_str(),
508     //        basename.c_str(), suffix.c_str()); 
512 /**
513  *  Return the suffix, if any, of a file name
514  */
515 DTString DepTool::getSuffix(const DTString &fname)
517     if (fname.size() < 2)
518         return "";
519     unsigned int pos = fname.find_last_of('.');
520     if (pos == fname.npos)
521         return "";
522     pos++;
523     DTString res = fname.substr(pos, fname.size()-pos);
524     //trace("suffix:%s", res.c_str()); 
525     return res;
530 //########################################################################
531 //# P R O C E S S I N G
532 //########################################################################
534 /**
535  *  Recursively list all files and directories under 'dirname', except
536  *  those in the exclude list.
537  */
538 bool DepTool::listFilesInDirectory(const DTString &dirname, int depth)
540     //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
542     int cFiles = 0;
543     int hFiles = 0;
545     std::vector<DTString> subdirs;
546     DIR *dir = opendir(dirname.c_str());
547     while (true)
548         {
549         struct dirent *de = readdir(dir);
550         if (!de)
551             break;
552         DTString s = de->d_name;
553         struct stat finfo;
554         DTString fname;
555         if (s.size() == 0 || s[0] == '.')
556             continue;
558         if (dirname.size()>0 && dirname != ".")
559             {
560             fname.append(dirname);
561             fname.append("/");
562             }
563         fname.append(s);
564         if (stat(fname.c_str(), &finfo)<0)
565             {
566             error("cannot stat file:%s", s.c_str());
567             }
568         else if (excludes.find(fname) != excludes.end())
569             {
570             //trace("excluded file/dir: %s", fname.c_str());
571             excludesUsed.insert(fname);
572             }
573         else if (S_ISDIR(finfo.st_mode))
574             {
575             //trace("directory: %s", fname.c_str());
576             subdirs.push_back(fname);
577             }
578         else if (!S_ISREG(finfo.st_mode))
579             {
580             trace("not regular: %s", fname.c_str());
581             }
582         else
583             {
584             DTString path;
585             DTString basename;
586             DTString sfx;
587             parseName(fname, path, basename, sfx);
588             if (sfx == "cpp" || sfx == "c" || sfx == "cxx"   || sfx == "cc")
589                 {
590                 cFiles++;
591                 FileRec *fe  = new FileRec(FileRec::CFILE);
592                 fe->path     = path;
593                 fe->baseName = basename;
594                 fe->suffix   = sfx;
595                 allFiles[fname] = fe;
596                 }
597             else if (sfx == "h"   ||  sfx == "hh"  ||
598                      sfx == "hpp" ||  sfx == "hxx")
599                 {
600                 hFiles++;
601                 FileRec *fe = new FileRec(FileRec::HFILE);
602                 fe->path     = path;
603                 fe->baseName = basename;
604                 fe->suffix   = sfx;
605                 allFiles[fname] = fe;
606                 }
607             }
608         }
609     closedir(dir);
611     if (hFiles > 0)
612         directories.push_back(dirname);
614     for (unsigned int i=0 ; i<subdirs.size() ; i++)
615         {
616         listFilesInDirectory(subdirs[i], depth+1);
617         }
619     return true;
624 /**
625  *
626  */
627 bool DepTool::createFileList()
629     excludes.insert("deptool.cpp");
630     FILE *f = fopen("make.exclude", "r");
631     if (!f)
632         {
633         trace("'make.exclude not found");
634         }
635     else
636         {
637         char readBuf[256];
638         while (!feof(f))
639             {
640             if (!fgets(readBuf, 255, f))
641                 break;
642             DTString s = readBuf;
643             s = trim(s);
644             //trace("s: %d '%s' ", s.size(), s.c_str());
645             if (s.size() > 0 && s[0]!='#')
646                 excludes.insert(s);
647             }
648         fclose(f);
649         }
651     listFilesInDirectory(".", 0);
653     // Note which files in the exclude list were not used.
654     std::set<DTString>::iterator iter;
655     for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
656         {
657         DTString fname = *iter;
658         std::set<DTString>::iterator citer = excludesUsed.find(fname);
659         if (citer == excludesUsed.end())
660             excludesUnused.insert(fname);
661         }
663     saveFileList();
665     return true;
669 /**
670  * Get a character from the buffer at pos.  If out of range,
671  * return -1 for safety
672  */
673 int DepTool::get(int pos)
675     if (pos>fileSize)
676         return -1;
677     return fileBuf[pos];
682 /**
683  *  Skip over all whitespace characters beginning at pos.  Return
684  *  the position of the first non-whitespace character.
685  */
686 int DepTool::skipwhite(int pos)
688     while (pos < fileSize)
689         {
690         int ch = get(pos);
691         if (ch < 0)
692             break;
693         if (!isspace(ch))
694             break;
695         pos++;
696         }
697     return pos;
701 /**
702  *  Parse the buffer beginning at pos, for a word.  Fill
703  *  'ret' with the result.  Return the position after the
704  *  word.
705  */
706 int DepTool::getword(int pos, DTString &ret)
708     while (pos < fileSize)
709         {
710         int ch = get(pos);
711         if (ch < 0)
712             break;
713         if (isspace(ch))
714             break;
715         ret.push_back((char)ch);
716         pos++;
717         }
718     return pos;
721 /**
722  * Return whether the sequence of characters in the buffer
723  * beginning at pos match the key,  for the length of the key
724  */
725 bool DepTool::sequ(int pos, char *key)
727     while (*key)
728         {
729         if (*key != get(pos))
730             return false;
731         key++; pos++;
732         }
733     return true;
738 /**
739  *  Add an include file name to a file record.  If the name
740  *  is not found in allFiles explicitly, try prepending include
741  *  directory names to it and try again.
742  */
743 bool DepTool::addIncludeFile(FileRec *frec, const DTString &iname)
746     std::map<DTString, FileRec *>::iterator iter =
747            allFiles.find(iname);
748     if (iter != allFiles.end())
749         {
750          //h file in same dir
751         FileRec *other = iter->second;
752         //trace("local: '%s'", iname.c_str());
753         frec->files[iname] = other;
754         return true;
755         }
756     else 
757         {
758         //look in other dirs
759         std::vector<DTString>::iterator diter;
760         for (diter=directories.begin() ;
761              diter!=directories.end() ; diter++)
762             {
763             DTString dfname = *diter;
764             dfname.append("/");
765             dfname.append(iname);
766             iter = allFiles.find(dfname);
767             if (iter != allFiles.end())
768                 {
769                 FileRec *other = iter->second;
770                 //trace("other: '%s'", iname.c_str());
771                 frec->files[dfname] = other;
772                 return true;
773                 }
774             }
775         }
776     return true;
781 /**
782  *  Lightly parse a file to find the #include directives.  Do
783  *  a bit of state machine stuff to make sure that the directive
784  *  is valid.  (Like not in a comment).
785  */
786 bool DepTool::scanFile(const DTString &fname, FileRec *frec)
788     FILE *f = fopen(fname.c_str(), "r");
789     if (!f)
790         {
791         error("Could not open '%s' for reading", fname.c_str());
792         return false;
793         }
794     DTString buf;
795     while (true)
796         {
797         int ch = fgetc(f);
798         if (ch < 0)
799             break;
800         buf.push_back((char)ch);
801         }
802     fclose(f);
804     fileSize = buf.size();
805     fileBuf  = (char *)buf.c_str();
806     int pos = 0;
809     while (pos < fileSize)
810         {
811         //trace("p:%c", get(pos));
813         //# Block comment
814         if (get(pos) == '/' && get(pos+1) == '*')
815             {
816             pos += 2;
817             while (pos < fileSize)
818                 {
819                 if (get(pos) == '*' && get(pos+1) == '/')
820                     {
821                     pos += 2;
822                     break;
823                     }
824                 else
825                     pos++;
826                 }
827             }
828         //# Line comment
829         else if (get(pos) == '/' && get(pos+1) == '/')
830             {
831             pos += 2;
832             while (pos < fileSize)
833                 {
834                 if (get(pos) == '\n')
835                     {
836                     pos++;
837                     break;
838                     }
839                 else
840                     pos++;
841                 }
842             }
843         //# #include! yaay
844         else if (sequ(pos, "#include"))
845             {
846             pos += 8;
847             pos = skipwhite(pos);
848             DTString iname;
849             pos = getword(pos, iname);
850             if (iname.size()>2)
851                 {
852                 iname = iname.substr(1, iname.size()-2);
853                 addIncludeFile(frec, iname);
854                 }
855             }
856         else
857             {
858             pos++;
859             }
860         }
862     return true;
867 /**
868  *  Recursively check include lists to find all files in allFiles to which
869  *  a given file is dependent.
870  */
871 bool DepTool::processDependency(FileRec *ofile,
872                                 FileRec *include,
873                                 int depth)
875     std::map<DTString, FileRec *>::iterator iter;
876     for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
877         {
878         DTString fname  = iter->first;
879         if (ofile->files.find(fname) != ofile->files.end())
880             {
881             //trace("file '%s' already seen", fname.c_str());
882             continue;
883             }
884         FileRec *child  = iter->second;
885         ofile->files[fname] = child;
886       
887         processDependency(ofile, child, depth+1);
888         }
891     return true;
896 /**
897  *  Recursively check include lists to find all files in allFiles which
898  *  will eventually have a dependency on this file.  This is basically
899  *  the inverse of processDependency().
900  */
901 bool DepTool::processReference(FileRec *hfile,
902                                DTString &fname,
903                                int depth)
905     std::map<DTString, FileRec *>::iterator iter;
906     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
907         {
908         FileRec *frec = iter->second;
909         std::map<DTString, FileRec *>::iterator fiter =
910                   frec->files.find(fname);
911         if (fiter != frec->files.end())
912             {
913             DTString cfname  = iter->first;
914             if (hfile->files.find(cfname) != hfile->files.end())
915                 {
916                 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
917                 continue;
918                 }
919             FileRec *child  = iter->second;
920             child->distance = depth;
921             hfile->files[cfname] = child;      
922             processReference(hfile, cfname, depth+1);
923             }
924         }
926     return true;
931 /**
932  *  Generate the file dependency and reference lists.
933  */
934 bool DepTool::generateDependencies()
936     std::map<DTString, FileRec *>::iterator iter;
937     //# First pass.  Scan for all includes
938     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
939         {
940         FileRec *frec = iter->second;
941         if (!scanFile(iter->first, frec))
942             {
943             //quit?
944             }
945         }
947     //# Second pass.  Scan for all includes
948     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
949         {
950         FileRec *include = iter->second;
951         if (include->type == FileRec::CFILE)
952             {
953             DTString cFileName = iter->first;
954             FileRec *ofile     = new FileRec(FileRec::OFILE);
955             ofile->path        = include->path;
956             ofile->baseName    = include->baseName;
957             ofile->suffix      = include->suffix;
958             DTString fname     = include->path;
959             if (fname.size()>0)
960                 fname.append("/");
961             fname.append(include->baseName);
962             fname.append(".o");
963             depFiles[fname]    = ofile;
964             //add the .c file first, of course
965             ofile->files[cFileName] = include;
966             //trace("ofile:%s", fname.c_str());
968             processDependency(ofile, include, 0);
969             }
970         else if (include->type == FileRec::HFILE)
971             {
972             DTString fname     = iter->first;
973             FileRec *hfile     = new FileRec(FileRec::HFILE);
974             hfile->path        = include->path;
975             hfile->baseName    = include->baseName;
976             hfile->suffix      = include->suffix;
977             refFiles[fname]    = hfile;
978             //trace("hfile:%s", fname.c_str());
980             processReference(hfile, fname, 0);
981             }
982         }
984       
985     return true;
989 /**
990  *  High-level call to do what DepTool does.
991  */
992 bool DepTool::run()
994     reset();
995     if (!createFileList())
996         return false;
997     if (!generateDependencies())
998         return false;
999     saveDepFile();
1000     saveRefFile();
1001     return true;
1005 //########################################################################
1006 //# O U T P U T S
1007 //########################################################################
1011 /**
1012  *  Save the allFiles list.  This is basically all files in a directory
1013  *  except those denied in the exclude list.
1014  */
1015 bool DepTool::saveFileList()
1017     time_t tim;
1018     time(&tim);
1020     FILE *f = fopen("make.files", "w");
1021     if (!f)
1022         {
1023         trace("cannot open 'make.files' for writing");
1024         }
1025     fprintf(f, "########################################################\n");
1026     fprintf(f, "## File: make.files\n");
1027     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1028     fprintf(f, "########################################################\n");
1030     fprintf(f, "\n\n\n");
1031     fprintf(f, "########################################################\n");
1032     fprintf(f, "## F I L E S\n");
1033     fprintf(f, "########################################################\n");
1035     std::map<DTString, FileRec *>::iterator iter;
1036     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1037         {
1038         fprintf(f, "%s\n", iter->first.c_str());
1039         }
1041     fprintf(f, "\n\n\n");
1042     fprintf(f, "########################################################\n");
1043     fprintf(f, "## E X C L U D E D\n");
1044     fprintf(f, "########################################################\n");
1046     std::set<DTString>::iterator uiter;
1047     for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1048         {
1049         DTString fname = *uiter;
1050         fprintf(f, "%s\n", fname.c_str());
1051         }
1053     fprintf(f, "\n\n\n");
1054     fprintf(f, "########################################################\n");
1055     fprintf(f, "## E X C L U D E  entries unused\n");
1056     fprintf(f, "########################################################\n");
1058     for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1059         {
1060         DTString fname = *uiter;
1061         fprintf(f, "%s\n", fname.c_str());
1062         }
1064     fprintf(f, "\n\n\n");
1065     fprintf(f, "########################################################\n");
1066     fprintf(f, "## E N D\n");
1067     fprintf(f, "########################################################\n");
1069     fclose(f);
1071     return true;
1075 /**
1076  *   This is the main product.  This file lists the Include directives,
1077  *   the Object list, and the dependency list.
1078  */
1079 bool DepTool::saveDepFile()
1081     time_t tim;
1082     time(&tim);
1084     FILE *f = fopen("make.dep", "w");
1085     if (!f)
1086         {
1087         trace("cannot open 'make.dep' for writing");
1088         }
1089     fprintf(f, "########################################################\n");
1090     fprintf(f, "## File: make.dep\n");
1091     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1092     fprintf(f, "########################################################\n");
1094     fprintf(f, "\n\n");
1095     
1096     fprintf(f, "########################################################\n");
1097     fprintf(f, "## I N C L U D E\n");
1098     fprintf(f, "########################################################\n");
1099     fprintf(f, "DEPTOOL_INCLUDE =");
1100     
1101     std::vector<DTString>::iterator inciter;
1102     for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1103         {
1104         fprintf(f, " \\\n");
1105         DTString dirname = *inciter;
1106         fprintf(f, "-I%s", dirname.c_str());
1107         }
1109     fprintf(f, "\n\n\n");
1110     fprintf(f, "########################################################\n");
1111     fprintf(f, "## O B J E C T S\n");
1112     fprintf(f, "########################################################\n");
1113     fprintf(f, "DEPTOOL_OBJECTS =");
1114     
1115     std::map<DTString, FileRec *>::iterator oiter;
1116     for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1117         {
1118         FileRec *frec = oiter->second;
1119         if (frec->type == FileRec::CFILE)
1120             {
1121             fprintf(f, " \\\n");
1122             DTString fname = frec->path;
1123             if (fname.size()>0)
1124                 fname.append("/");
1125             fname.append(frec->baseName);
1126             fname.append(".o");
1127             fprintf(f, "%s", fname.c_str());
1128             }
1129         }
1132     fprintf(f, "\n\n\n");
1133     fprintf(f, "########################################################\n");
1134     fprintf(f, "## D E P E N D E N C I E S\n");
1135     fprintf(f, "########################################################\n");
1136     std::map<DTString, FileRec *>::iterator iter;
1137     for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1138         {
1139         FileRec *frec = iter->second;
1140         if (frec->type == FileRec::OFILE)
1141             {
1142             DTString fname = iter->first;
1143             fprintf(f, "%s:", fname.c_str());
1144             std::map<DTString, FileRec *>::iterator citer;
1145             for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1146                 {
1147                 DTString cfname = citer->first;
1148                 fprintf(f, " \\\n");
1149                 fprintf(f, "\t%s", cfname.c_str());
1150                 }
1151             fprintf(f, "\n\n\n");
1152             }
1153         }
1155     fprintf(f, "\n\n\n");
1156     fprintf(f, "########################################################\n");
1157     fprintf(f, "## E N D\n");
1158     fprintf(f, "########################################################\n");
1160     fclose(f);
1162     return true;
1166 /**
1167  *  Save the "reference" file, which lists each include file, and any files
1168  *  that are judged to be dependent upon it.
1169  */
1170 bool DepTool::saveRefFile()
1172     time_t tim;
1173     time(&tim);
1175     FILE *f = fopen("make.ref", "w");
1176     if (!f)
1177         {
1178         trace("cannot open 'make.ref' for writing");
1179         }
1180     fprintf(f, "########################################################\n");
1181     fprintf(f, "## File: make.ref\n");
1182     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1183     fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1184     fprintf(f, "##    the given file.\n");
1185     fprintf(f, "########################################################\n");
1187     fprintf(f, "\n\n");
1188     
1189     std::map<DTString, FileRec *>::iterator iter;
1190     for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1191         {
1192         FileRec *frec = iter->second;
1193         if (frec->type == FileRec::HFILE)
1194             {
1195             DTString fname = iter->first;
1196             fprintf(f, "### %s\n", fname.c_str());
1197             std::map<DTString, FileRec *>::iterator citer;
1198             for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1199                 {
1200                 DTString cfname = citer->first;
1201                 fprintf(f, "%3d %s\n", citer->second->distance,
1202                                cfname.c_str());
1203                 }
1204             fprintf(f, "\n");
1205             }
1206         }
1208     fprintf(f, "\n\n\n");
1209     fprintf(f, "########################################################\n");
1210     fprintf(f, "## E N D\n");
1211     fprintf(f, "########################################################\n");
1213     fclose(f);
1215     return true;
1223 //########################################################################
1224 //# M A I N
1225 //########################################################################
1228 /**
1229  *  Run the DepTool's main functions
1230  */
1231 static bool runTool()
1233     DepTool depTool;
1235     if (!depTool.run())
1236         return false;
1238     return true;
1242 /**
1243  * Console main()
1244  */
1245 int main(int argc, char **argv)
1247     if (!runTool())
1248         return 1;
1250     return 0;
1254 //########################################################################
1255 //# E N D    O F    F I L E
1256 //########################################################################