Code

improve streaming
[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 String;
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     String path;
135     /**
136      *  Base name, sans directory and suffix
137      */
138     String baseName;
140     /**
141      *  File extension, such as cpp or h
142      */
143     String 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<String, FileRec *> files;
162     bool checked;
164 private:
166     void init()
167         {
168         type    = UNKNOWN;
169         checked = false;
170         }
172     void assign(const FileRec &other)
173         {
174         type     = other.type;
175         distance = other.distance;
176         baseName = other.baseName;
177         suffix   = other.suffix;
178         files    = other.files;
179         checked  = other.checked;
180         }
182 };
186 /**
187  *  Main class which does the work.
188  */
189 class DepTool
191 public:
193     /**
194      *  Constructor
195      */
196     DepTool();
198     /**
199      *  Destructor
200      */
201     virtual ~DepTool();
203     /**
204      * Creates the list of all file names which will be
205      * candidates for further processing.  Reads make.exclude
206      * to see which files for directories to leave out.
207      */
208     virtual bool createFileList();
211     /**
212      *  Generates the forward and reverse dependency lists
213      */
214     virtual bool generateDependencies();
216     /**
217      *  Calls the other two methods, then generates the files.
218      */
219     virtual bool run();
222 private:
224     /**
225      *
226      */
227     void reset();
229     /**
230      *
231      */
232     void error(char *fmt, ...);
234     /**
235      *
236      */
237     void trace(char *fmt, ...);
239     /**
240      *  Removes whitespace from beginning and end of a string
241      */
242     String trim(const String &val);
244     /**
245      *
246      */
247     String getSuffix(const String &fname);
249     /**
250      *
251      */
252     void parseName(const String &fullname,
253                    String &path,
254                    String &basename,
255                    String &suffix);
257     /**
258      *
259      */
260     int get(int pos);
262     /**
263      *
264      */
265     int skipwhite(int pos);
267     /**
268      *
269      */
270     int getword(int pos, String &ret);
272     /**
273      *
274      */
275     bool sequ(int pos, char *key);
277     /**
278      *
279      */
280     bool listFilesInDirectory(const String &dirname, int depth);
282     /**
283      *
284      */
285     bool saveFileList();
287     /**
288      *
289      */
290     bool saveDepFile(bool doXml);
292     /**
293      *
294      */
295     bool saveRefFile(bool doXml);
297     /**
298      *
299      */
300     bool addIncludeFile(FileRec *frec, const String &fname);
302     /**
303      *
304      */
305     bool scanFile(const String &fname, FileRec *frec);
307     /**
308      *
309      */
310     bool processDependency(FileRec *ofile,
311                            FileRec *include,
312                            int depth);
314     /**
315      *
316      */
317     bool processReference(FileRec *ofile,
318                           String &fname,
319                           int depth);
321     /**
322      *
323      */
324     std::set<String> excludes;
326     /**
327      *
328      */
329     std::set<String> excludesUsed;
331     /**
332      *
333      */
334     std::set<String> excludesUnused;
336     /**
337      *
338      */
339     std::vector<String> directories;
341     /**
342      * A list of all files which will be processed for
343      * dependencies.
344      */
345     std::map<String, FileRec *> allFiles;
347     /**
348      * A list of .h files, with a list for each one
349      * of which other files include them.
350      */
351     std::map<String, FileRec *> refFiles;
353     /**
354      * The list of .o files, and the
355      * dependencies upon them.
356      */
357     std::map<String, FileRec *> depFiles;
359     char *fileBuf;
360     int   fileSize;
361     
362     static const int readBufLen = 8192;
363     char readBuf[8193];
366 };
369 //########################################################################
370 //# M A I N
371 //########################################################################
373 /**
374  * Constructor
375  */
376 DepTool::DepTool()
381 /**
382  *  Destructor
383  */
384 DepTool::~DepTool()
386     reset();
389 /**
390  *  Clean up after processing.  Called by the destructor, but should
391  *  also be called before the object is reused.
392  */
393 void DepTool::reset()
395     std::map<String, FileRec *>::iterator iter;
396     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
397         {
398         FileRec *frec = iter->second;
399         delete frec;
400         }
401     allFiles.clear();
402     for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
403         {
404         FileRec *frec = iter->second;
405         delete frec;
406         }
407     refFiles.clear();
408     for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
409         {
410         FileRec *frec = iter->second;
411         delete frec;
412         }
413     depFiles.clear();
415     excludes.clear();
416     excludesUsed.clear();
417     excludesUnused.clear();
421 /**
422  *  Format an error message in printf() style
423  */
424 void DepTool::error(char *fmt, ...)
426     va_list ap;
427     va_start(ap, fmt);
428     fprintf(stderr, "DepTool error: ");
429     vfprintf(stderr, fmt, ap);
430     fprintf(stderr, "\n");
431     va_end(ap);
435 /**
436  *  Format an trace message in printf() style
437  */
438 void DepTool::trace(char *fmt, ...)
440     va_list ap;
441     va_start(ap, fmt);
442     fprintf(stdout, "DepTool: ");
443     vfprintf(stdout, fmt, ap);
444     fprintf(stdout, "\n");
445     va_end(ap);
450 //########################################################################
451 //# U T I L I T Y
452 //########################################################################
454 /**
455  *  Removes whitespace from beginning and end of a string
456  */
457 String DepTool::trim(const String &s)
459     if (s.size() < 1)
460         return s;
461     
462     //Find first non-ws char
463     unsigned int begin = 0;
464     for ( ; begin < s.size() ; begin++)
465         {
466         if (!isspace(s[begin]))
467             break;
468         }
470     //Find first non-ws char, going in reverse
471     unsigned int end = s.size() - 1;
472     for ( ; end > begin ; end--)
473         {
474         if (!isspace(s[end]))
475             break;
476         }
477     //trace("begin:%d  end:%d", begin, end);
479     String res = s.substr(begin, end-begin+1);
480     return res;
484 /**
485  *  Parse a full path name into path, base name, and suffix
486  */
487 void DepTool::parseName(const String &fullname,
488                         String &path,
489                         String &basename,
490                         String &suffix)
492     if (fullname.size() < 2)
493         return;
495     unsigned int pos = fullname.find_last_of('/');
496     if (pos != fullname.npos && pos<fullname.size()-1)
497         {
498         path = fullname.substr(0, pos);
499         pos++;
500         basename = fullname.substr(pos, fullname.size()-pos);
501         }
502     else
503         {
504         path = "";
505         basename = fullname;
506         }
508     pos = basename.find_last_of('.');
509     if (pos != basename.npos && pos<basename.size()-1)
510         {
511         suffix   = basename.substr(pos+1, basename.size()-pos-1);
512         basename = basename.substr(0, pos);
513         }
515     //trace("parsename:%s %s %s", path.c_str(),
516     //        basename.c_str(), suffix.c_str()); 
520 /**
521  *  Return the suffix, if any, of a file name
522  */
523 String DepTool::getSuffix(const String &fname)
525     if (fname.size() < 2)
526         return "";
527     unsigned int pos = fname.find_last_of('.');
528     if (pos == fname.npos)
529         return "";
530     pos++;
531     String res = fname.substr(pos, fname.size()-pos);
532     //trace("suffix:%s", res.c_str()); 
533     return res;
538 //########################################################################
539 //# P R O C E S S I N G
540 //########################################################################
542 /**
543  *  Recursively list all files and directories under 'dirname', except
544  *  those in the exclude list.
545  */
546 bool DepTool::listFilesInDirectory(const String &dirname, int depth)
548     //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
550     int cFiles = 0;
551     int hFiles = 0;
553     std::vector<String> subdirs;
554     DIR *dir = opendir(dirname.c_str());
555     while (true)
556         {
557         struct dirent *de = readdir(dir);
558         if (!de)
559             break;
560         String s = de->d_name;
561         struct stat finfo;
562         String fname;
563         if (s.size() == 0 || s[0] == '.')
564             continue;
566         if (dirname.size()>0 && dirname != ".")
567             {
568             fname.append(dirname);
569             fname.append("/");
570             }
571         fname.append(s);
572         if (stat(fname.c_str(), &finfo)<0)
573             {
574             error("cannot stat file:%s", s.c_str());
575             }
576         else if (excludes.find(fname) != excludes.end())
577             {
578             //trace("excluded file/dir: %s", fname.c_str());
579             excludesUsed.insert(fname);
580             }
581         else if (S_ISDIR(finfo.st_mode))
582             {
583             //trace("directory: %s", fname.c_str());
584             subdirs.push_back(fname);
585             }
586         else if (!S_ISREG(finfo.st_mode))
587             {
588             trace("not regular: %s", fname.c_str());
589             }
590         else
591             {
592             String path;
593             String basename;
594             String sfx;
595             parseName(fname, path, basename, sfx);
596             if (sfx == "cpp" || sfx == "c" || sfx == "cxx"   || sfx == "cc")
597                 {
598                 cFiles++;
599                 FileRec *fe  = new FileRec(FileRec::CFILE);
600                 fe->path     = path;
601                 fe->baseName = basename;
602                 fe->suffix   = sfx;
603                 allFiles[fname] = fe;
604                 }
605             else if (sfx == "h"   ||  sfx == "hh"  ||
606                      sfx == "hpp" ||  sfx == "hxx")
607                 {
608                 hFiles++;
609                 FileRec *fe = new FileRec(FileRec::HFILE);
610                 fe->path     = path;
611                 fe->baseName = basename;
612                 fe->suffix   = sfx;
613                 allFiles[fname] = fe;
614                 }
615             }
616         }
617     closedir(dir);
619     if (hFiles > 0)
620         directories.push_back(dirname);
622     for (unsigned int i=0 ; i<subdirs.size() ; i++)
623         {
624         listFilesInDirectory(subdirs[i], depth+1);
625         }
627     return true;
632 /**
633  *
634  */
635 bool DepTool::createFileList()
637     excludes.insert("deptool.cpp");
638     FILE *f = fopen("make.exclude", "r");
639     if (!f)
640         {
641         trace("'make.exclude not found");
642         }
643     else
644         {
645         char readBuf[256];
646         while (!feof(f))
647             {
648             if (!fgets(readBuf, 255, f))
649                 break;
650             String s = readBuf;
651             s = trim(s);
652             //trace("s: %d '%s' ", s.size(), s.c_str());
653             if (s.size() > 0 && s[0]!='#')
654                 excludes.insert(s);
655             }
656         fclose(f);
657         }
659     listFilesInDirectory(".", 0);
661     // Note which files in the exclude list were not used.
662     std::set<String>::iterator iter;
663     for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
664         {
665         String fname = *iter;
666         std::set<String>::iterator citer = excludesUsed.find(fname);
667         if (citer == excludesUsed.end())
668             excludesUnused.insert(fname);
669         }
671     saveFileList();
673     return true;
677 /**
678  * Get a character from the buffer at pos.  If out of range,
679  * return -1 for safety
680  */
681 int DepTool::get(int pos)
683     if (pos>fileSize)
684         return -1;
685     return fileBuf[pos];
690 /**
691  *  Skip over all whitespace characters beginning at pos.  Return
692  *  the position of the first non-whitespace character.
693  */
694 int DepTool::skipwhite(int pos)
696     while (pos < fileSize)
697         {
698         int ch = get(pos);
699         if (ch < 0)
700             break;
701         if (!isspace(ch))
702             break;
703         pos++;
704         }
705     return pos;
709 /**
710  *  Parse the buffer beginning at pos, for a word.  Fill
711  *  'ret' with the result.  Return the position after the
712  *  word.
713  */
714 int DepTool::getword(int pos, String &ret)
716     while (pos < fileSize)
717         {
718         int ch = get(pos);
719         if (ch < 0)
720             break;
721         if (isspace(ch))
722             break;
723         ret.push_back((char)ch);
724         pos++;
725         }
726     return pos;
729 /**
730  * Return whether the sequence of characters in the buffer
731  * beginning at pos match the key,  for the length of the key
732  */
733 bool DepTool::sequ(int pos, char *key)
735     while (*key)
736         {
737         if (*key != get(pos))
738             return false;
739         key++; pos++;
740         }
741     return true;
746 /**
747  *  Add an include file name to a file record.  If the name
748  *  is not found in allFiles explicitly, try prepending include
749  *  directory names to it and try again.
750  */
751 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
754     std::map<String, FileRec *>::iterator iter =
755            allFiles.find(iname);
756     if (iter != allFiles.end())
757         {
758          //h file in same dir
759         FileRec *other = iter->second;
760         //trace("local: '%s'", iname.c_str());
761         frec->files[iname] = other;
762         return true;
763         }
764     else 
765         {
766         //look in other dirs
767         std::vector<String>::iterator diter;
768         for (diter=directories.begin() ;
769              diter!=directories.end() ; diter++)
770             {
771             String dfname = *diter;
772             dfname.append("/");
773             dfname.append(iname);
774             iter = allFiles.find(dfname);
775             if (iter != allFiles.end())
776                 {
777                 FileRec *other = iter->second;
778                 //trace("other: '%s'", iname.c_str());
779                 frec->files[dfname] = other;
780                 return true;
781                 }
782             }
783         }
784     return true;
789 /**
790  *  Lightly parse a file to find the #include directives.  Do
791  *  a bit of state machine stuff to make sure that the directive
792  *  is valid.  (Like not in a comment).
793  */
794 bool DepTool::scanFile(const String &fname, FileRec *frec)
796     FILE *f = fopen(fname.c_str(), "r");
797     if (!f)
798         {
799         error("Could not open '%s' for reading", fname.c_str());
800         return false;
801         }
802     String buf;
803     while (!feof(f))
804         {
805         int len = fread(readBuf, 1, readBufLen, f);
806         readBuf[len] = '\0';
807         buf.append(readBuf);
808         }
809     fclose(f);
811     fileSize = buf.size();
812     fileBuf  = (char *)buf.c_str();
813     int pos = 0;
816     while (pos < fileSize)
817         {
818         //trace("p:%c", get(pos));
820         //# Block comment
821         if (get(pos) == '/' && get(pos+1) == '*')
822             {
823             pos += 2;
824             while (pos < fileSize)
825                 {
826                 if (get(pos) == '*' && get(pos+1) == '/')
827                     {
828                     pos += 2;
829                     break;
830                     }
831                 else
832                     pos++;
833                 }
834             }
835         //# Line comment
836         else if (get(pos) == '/' && get(pos+1) == '/')
837             {
838             pos += 2;
839             while (pos < fileSize)
840                 {
841                 if (get(pos) == '\n')
842                     {
843                     pos++;
844                     break;
845                     }
846                 else
847                     pos++;
848                 }
849             }
850         //# #include! yaay
851         else if (sequ(pos, "#include"))
852             {
853             pos += 8;
854             pos = skipwhite(pos);
855             String iname;
856             pos = getword(pos, iname);
857             if (iname.size()>2)
858                 {
859                 iname = iname.substr(1, iname.size()-2);
860                 addIncludeFile(frec, iname);
861                 }
862             }
863         else
864             {
865             pos++;
866             }
867         }
869     return true;
874 /**
875  *  Recursively check include lists to find all files in allFiles to which
876  *  a given file is dependent.
877  */
878 bool DepTool::processDependency(FileRec *ofile,
879                                 FileRec *include,
880                                 int depth)
882     std::map<String, FileRec *>::iterator iter;
883     for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
884         {
885         String fname  = iter->first;
886         if (ofile->files.find(fname) != ofile->files.end())
887             {
888             //trace("file '%s' already seen", fname.c_str());
889             continue;
890             }
891         FileRec *child  = iter->second;
892         ofile->files[fname] = child;
893       
894         processDependency(ofile, child, depth+1);
895         }
898     return true;
903 /**
904  *  Recursively check include lists to find all files in allFiles which
905  *  will eventually have a dependency on this file.  This is basically
906  *  the inverse of processDependency().
907  */
908 bool DepTool::processReference(FileRec *hfile,
909                                String &fname,
910                                int depth)
912     std::map<String, FileRec *>::iterator iter;
913     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
914         {
915         FileRec *frec = iter->second;
916         std::map<String, FileRec *>::iterator fiter =
917                   frec->files.find(fname);
918         if (fiter != frec->files.end())
919             {
920             String cfname  = iter->first;
921             if (hfile->files.find(cfname) != hfile->files.end())
922                 {
923                 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
924                 continue;
925                 }
926             FileRec *child  = iter->second;
927             child->distance = depth;
928             hfile->files[cfname] = child;      
929             processReference(hfile, cfname, depth+1);
930             }
931         }
933     return true;
938 /**
939  *  Generate the file dependency and reference lists.
940  */
941 bool DepTool::generateDependencies()
943     std::map<String, FileRec *>::iterator iter;
944     //# First pass.  Scan for all includes
945     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
946         {
947         FileRec *frec = iter->second;
948         if (!scanFile(iter->first, frec))
949             {
950             //quit?
951             }
952         }
954     //# Second pass.  Scan for all includes
955     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
956         {
957         FileRec *include = iter->second;
958         if (include->type == FileRec::CFILE)
959             {
960             String cFileName = iter->first;
961             FileRec *ofile     = new FileRec(FileRec::OFILE);
962             ofile->path        = include->path;
963             ofile->baseName    = include->baseName;
964             ofile->suffix      = include->suffix;
965             String fname     = include->path;
966             if (fname.size()>0)
967                 fname.append("/");
968             fname.append(include->baseName);
969             fname.append(".o");
970             depFiles[fname]    = ofile;
971             //add the .c file first, of course
972             ofile->files[cFileName] = include;
973             //trace("ofile:%s", fname.c_str());
975             processDependency(ofile, include, 0);
976             }
977         /*
978         else if (include->type == FileRec::HFILE)
979             {
980             String fname     = iter->first;
981             FileRec *hfile     = new FileRec(FileRec::HFILE);
982             hfile->path        = include->path;
983             hfile->baseName    = include->baseName;
984             hfile->suffix      = include->suffix;
985             refFiles[fname]    = hfile;
986             //trace("hfile:%s", fname.c_str());
988             processReference(hfile, fname, 0);
989             }
990         */
991         }
993       
994     return true;
998 /**
999  *  High-level call to do what DepTool does.
1000  */
1001 bool DepTool::run()
1003     reset();
1004     if (!createFileList())
1005         return false;
1006     if (!generateDependencies())
1007         return false;
1008     saveDepFile(false);
1009     //saveRefFile(true);
1010     return true;
1014 //########################################################################
1015 //# O U T P U T S
1016 //########################################################################
1020 /**
1021  *  Save the allFiles list.  This is basically all files in a directory
1022  *  except those denied in the exclude list.
1023  */
1024 bool DepTool::saveFileList()
1026     time_t tim;
1027     time(&tim);
1029     FILE *f = fopen("make.files", "w");
1030     if (!f)
1031         {
1032         trace("cannot open 'make.files' for writing");
1033         }
1034     fprintf(f, "########################################################\n");
1035     fprintf(f, "## File: make.files\n");
1036     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1037     fprintf(f, "########################################################\n");
1039     fprintf(f, "\n\n\n");
1040     fprintf(f, "########################################################\n");
1041     fprintf(f, "## F I L E S\n");
1042     fprintf(f, "########################################################\n");
1044     std::map<String, FileRec *>::iterator iter;
1045     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1046         {
1047         fprintf(f, "%s\n", iter->first.c_str());
1048         }
1050     fprintf(f, "\n\n\n");
1051     fprintf(f, "########################################################\n");
1052     fprintf(f, "## E X C L U D E D\n");
1053     fprintf(f, "########################################################\n");
1055     std::set<String>::iterator uiter;
1056     for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1057         {
1058         String fname = *uiter;
1059         fprintf(f, "%s\n", fname.c_str());
1060         }
1062     fprintf(f, "\n\n\n");
1063     fprintf(f, "########################################################\n");
1064     fprintf(f, "## E X C L U D E  entries unused\n");
1065     fprintf(f, "########################################################\n");
1067     for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1068         {
1069         String fname = *uiter;
1070         fprintf(f, "%s\n", fname.c_str());
1071         }
1073     fprintf(f, "\n\n\n");
1074     fprintf(f, "########################################################\n");
1075     fprintf(f, "## E N D\n");
1076     fprintf(f, "########################################################\n");
1078     fclose(f);
1080     return true;
1084 /**
1085  *   This is the main product.  This file lists the Include directives,
1086  *   the Object list, and the dependency list.
1087  */
1088 bool DepTool::saveDepFile(bool doXml)
1090     time_t tim;
1091     time(&tim);
1093     FILE *f = fopen("make.dep", "w");
1094     if (!f)
1095         {
1096         trace("cannot open 'make.dep' for writing");
1097         }
1098     if (doXml)
1099         {
1100         fprintf(f, "<?xml version='1.0'?>\n");
1101         fprintf(f, "<deptool>\n");
1102         fprintf(f, "\n");
1103         fprintf(f, "<!--\n");
1104         fprintf(f, "########################################################\n");
1105         fprintf(f, "## File: make.dep\n");
1106         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1107         fprintf(f, "########################################################\n");
1108         fprintf(f, "-->\n");
1110         fprintf(f, "\n\n");
1111     
1112         fprintf(f, "\n");
1113         fprintf(f, "<!--\n");
1114         fprintf(f, "########################################################\n");
1115         fprintf(f, "## I N C L U D E\n");
1116         fprintf(f, "########################################################\n");
1117         fprintf(f, "-->\n");
1118         fprintf(f, "<includes>\n");
1119     
1120         std::vector<String>::iterator inciter;
1121         for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1122             {
1123             String dirname = *inciter;
1124             fprintf(f, "    <inc name='%s'/>\n", dirname.c_str());
1125             }
1127         fprintf(f, "</includes>\n");
1128         fprintf(f, "\n\n\n");
1129         fprintf(f, "<!--\n");
1130         fprintf(f, "########################################################\n");
1131         fprintf(f, "## O B J E C T S\n");
1132         fprintf(f, "########################################################\n");
1133         fprintf(f, "-->\n");
1134         fprintf(f, "<objects>\n");
1135     
1136         std::map<String, FileRec *>::iterator oiter;
1137         for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1138             {
1139             FileRec *frec = oiter->second;
1140             if (frec->type == FileRec::CFILE)
1141                 {
1142                 String fname = frec->path;
1143                 if (fname.size()>0)
1144                     fname.append("/");
1145                 fname.append(frec->baseName);
1146                 fname.append(".o");
1147                 fprintf(f, "   <obj name='%s'/>\n", fname.c_str());
1148                 }
1149             }
1152         fprintf(f, "</objects>\n");
1153         fprintf(f, "\n\n\n");
1154         fprintf(f, "<!--\n");
1155         fprintf(f, "########################################################\n");
1156         fprintf(f, "## D E P E N D E N C I E S\n");
1157         fprintf(f, "########################################################\n");
1158         fprintf(f, "-->\n");
1159         fprintf(f, "<dependencies>\n\n");
1160         std::map<String, FileRec *>::iterator iter;
1161         for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1162             {
1163             FileRec *frec = iter->second;
1164             if (frec->type == FileRec::OFILE)
1165                 {
1166                 String fname = iter->first;
1167                 fprintf(f, "<file name='%s'>\n", fname.c_str());
1168                 std::map<String, FileRec *>::iterator citer;
1169                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1170                     {
1171                     String cfname = citer->first;
1172                     fprintf(f, "    <dep name='%s'/>\n", cfname.c_str());
1173                     }
1174                 fprintf(f, "</file>\n\n");
1175                 }
1176             }
1178         fprintf(f, "</dependencies>\n");
1179         fprintf(f, "\n\n\n");
1180         fprintf(f, "</deptool>\n");
1181         fprintf(f, "<!--\n");
1182         fprintf(f, "########################################################\n");
1183         fprintf(f, "## E N D\n");
1184         fprintf(f, "########################################################\n");
1185         fprintf(f, "-->\n");
1186         }
1187     else // ######### !XML
1188         {
1189         fprintf(f, "########################################################\n");
1190         fprintf(f, "## File: make.dep\n");
1191         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1192         fprintf(f, "########################################################\n");
1194         fprintf(f, "\n\n");
1195     
1196         fprintf(f, "########################################################\n");
1197         fprintf(f, "## I N C L U D E\n");
1198         fprintf(f, "########################################################\n");
1199         fprintf(f, "DEPTOOL_INCLUDE =");
1200     
1201         std::vector<String>::iterator inciter;
1202         for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1203             {
1204             fprintf(f, " \\\n");
1205             String dirname = *inciter;
1206             fprintf(f, "-I%s", dirname.c_str());
1207             }
1209         fprintf(f, "\n\n\n");
1210         fprintf(f, "########################################################\n");
1211         fprintf(f, "## O B J E C T S\n");
1212         fprintf(f, "########################################################\n");
1213         fprintf(f, "DEPTOOL_OBJECTS =");
1214     
1215         std::map<String, FileRec *>::iterator oiter;
1216         for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1217             {
1218             FileRec *frec = oiter->second;
1219             if (frec->type == FileRec::CFILE)
1220                 {
1221                 fprintf(f, " \\\n");
1222                 String fname = frec->path;
1223                 if (fname.size()>0)
1224                     fname.append("/");
1225                 fname.append(frec->baseName);
1226                 fname.append(".o");
1227                 fprintf(f, "%s", fname.c_str());
1228                 }
1229             }
1232         fprintf(f, "\n\n\n");
1233         fprintf(f, "########################################################\n");
1234         fprintf(f, "## D E P E N D E N C I E S\n");
1235         fprintf(f, "########################################################\n");
1236         std::map<String, FileRec *>::iterator iter;
1237         for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1238             {
1239             FileRec *frec = iter->second;
1240             if (frec->type == FileRec::OFILE)
1241                 {
1242                 String fname = iter->first;
1243                 fprintf(f, "%s:", fname.c_str());
1244                 std::map<String, FileRec *>::iterator citer;
1245                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1246                     {
1247                     String cfname = citer->first;
1248                     fprintf(f, " \\\n");
1249                     fprintf(f, "\t%s", cfname.c_str());
1250                     }
1251                 fprintf(f, "\n\n\n");
1252                 }
1253             }
1255         fprintf(f, "\n\n\n");
1256         fprintf(f, "########################################################\n");
1257         fprintf(f, "## E N D\n");
1258         fprintf(f, "########################################################\n");
1259         }
1261     fclose(f);
1263     return true;
1267 /**
1268  *  Save the "reference" file, which lists each include file, and any files
1269  *  that are judged to be dependent upon it.
1270  */
1271 bool DepTool::saveRefFile(bool doXml)
1273     time_t tim;
1274     time(&tim);
1276     FILE *f = fopen("make.ref", "w");
1277     if (!f)
1278         {
1279         trace("cannot open 'make.ref' for writing");
1280         }
1281     if (doXml)
1282         {
1283         fprintf(f, "<?xml version='1.0'?>\n");
1284         fprintf(f, "<deptool>\n\n");
1285         fprintf(f, "<!--\n");
1286         fprintf(f, "########################################################\n");
1287         fprintf(f, "## File: make.ref\n");
1288         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1289         fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1290         fprintf(f, "##    the given file.\n");
1291         fprintf(f, "########################################################\n");
1292         fprintf(f, "-->\n");
1293         fprintf(f, "\n\n");
1294     
1296         std::map<String, FileRec *>::iterator iter;
1297         for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1298             {
1299             FileRec *frec = iter->second;
1300             if (frec->type == FileRec::HFILE)
1301                 {
1302                 String fname = iter->first;
1303                 fprintf(f, "<file name='%s'>\n", fname.c_str());
1304                 std::map<String, FileRec *>::iterator citer;
1305                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1306                     {
1307                     String cfname = citer->first;
1308                     fprintf(f, "    <ref d='%d' name='%s'/>\n", 
1309                                citer->second->distance, cfname.c_str());
1310                     }
1311                 fprintf(f, "</file>\n\n");
1312                 }
1313             }
1314         fprintf(f, "\n\n\n");
1315         fprintf(f, "</deptool>\n");
1316         fprintf(f, "<!--\n");
1317         fprintf(f, "########################################################\n");
1318         fprintf(f, "## E N D\n");
1319         fprintf(f, "########################################################\n");
1320         fprintf(f, "-->\n");
1321         }
1323     else //######### not xml
1324         {
1325         fprintf(f, "########################################################\n");
1326         fprintf(f, "## File: make.ref\n");
1327         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1328         fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1329         fprintf(f, "##    the given file.\n");
1330         fprintf(f, "########################################################\n");
1331         fprintf(f, "\n\n");
1332     
1334         std::map<String, FileRec *>::iterator iter;
1335         for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1336             {
1337             FileRec *frec = iter->second;
1338             if (frec->type == FileRec::HFILE)
1339                 {
1340                 String fname = iter->first;
1341                 fprintf(f, "### %s\n", fname.c_str());
1342                 std::map<String, FileRec *>::iterator citer;
1343                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1344                     {
1345                     String cfname = citer->first;
1346                     fprintf(f, "%3d %s\n", citer->second->distance,
1347                                    cfname.c_str());
1348                     }
1349                 fprintf(f, "\n");
1350                 }
1351             }
1353         fprintf(f, "\n\n\n");
1354         fprintf(f, "########################################################\n");
1355         fprintf(f, "## E N D\n");
1356         fprintf(f, "########################################################\n");
1357         }
1359     fclose(f);
1361     return true;
1369 //########################################################################
1370 //# M A I N
1371 //########################################################################
1374 /**
1375  *  Run the DepTool's main functions
1376  */
1377 static bool runTool()
1379     DepTool depTool;
1381     if (!depTool.run())
1382         return false;
1384     return true;
1388 /**
1389  * Console main()
1390  */
1391 int main(int argc, char **argv)
1393     if (!runTool())
1394         return 1;
1396     return 0;
1400 //########################################################################
1401 //# E N D    O F    F I L E
1402 //########################################################################