Code

Unify stat type for older glib.
[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 saveCmakeFile();
297     /**
298      *
299      */
300     bool saveRefFile(bool doXml);
302     /**
303      *
304      */
305     bool addIncludeFile(FileRec *frec, const String &fname);
307     /**
308      *
309      */
310     bool scanFile(const String &fname, FileRec *frec);
312     /**
313      *
314      */
315     bool processDependency(FileRec *ofile,
316                            FileRec *include,
317                            int depth);
319     /**
320      *
321      */
322     bool processReference(FileRec *ofile,
323                           String &fname,
324                           int depth);
326     /**
327      *
328      */
329     std::set<String> excludes;
331     /**
332      *
333      */
334     std::set<String> excludesUsed;
336     /**
337      *
338      */
339     std::set<String> excludesUnused;
341     /**
342      *
343      */
344     std::vector<String> directories;
346     /**
347      * A list of all files which will be processed for
348      * dependencies.
349      */
350     std::map<String, FileRec *> allFiles;
352     /**
353      * A list of .h files, with a list for each one
354      * of which other files include them.
355      */
356     std::map<String, FileRec *> refFiles;
358     /**
359      * The list of .o files, and the
360      * dependencies upon them.
361      */
362     std::map<String, FileRec *> depFiles;
364     char *fileBuf;
365     int   fileSize;
366     
367     static const int readBufLen = 8192;
368     char readBuf[8193];
371 };
374 //########################################################################
375 //# M A I N
376 //########################################################################
378 /**
379  * Constructor
380  */
381 DepTool::DepTool()
386 /**
387  *  Destructor
388  */
389 DepTool::~DepTool()
391     reset();
394 /**
395  *  Clean up after processing.  Called by the destructor, but should
396  *  also be called before the object is reused.
397  */
398 void DepTool::reset()
400     std::map<String, FileRec *>::iterator iter;
401     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
402         {
403         FileRec *frec = iter->second;
404         delete frec;
405         }
406     allFiles.clear();
407     for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
408         {
409         FileRec *frec = iter->second;
410         delete frec;
411         }
412     refFiles.clear();
413     for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
414         {
415         FileRec *frec = iter->second;
416         delete frec;
417         }
418     depFiles.clear();
420     excludes.clear();
421     excludesUsed.clear();
422     excludesUnused.clear();
426 /**
427  *  Format an error message in printf() style
428  */
429 void DepTool::error(char *fmt, ...)
431     va_list ap;
432     va_start(ap, fmt);
433     fprintf(stderr, "DepTool error: ");
434     vfprintf(stderr, fmt, ap);
435     fprintf(stderr, "\n");
436     va_end(ap);
440 /**
441  *  Format an trace message in printf() style
442  */
443 void DepTool::trace(char *fmt, ...)
445     va_list ap;
446     va_start(ap, fmt);
447     fprintf(stdout, "DepTool: ");
448     vfprintf(stdout, fmt, ap);
449     fprintf(stdout, "\n");
450     va_end(ap);
455 //########################################################################
456 //# U T I L I T Y
457 //########################################################################
459 /**
460  *  Removes whitespace from beginning and end of a string
461  */
462 String DepTool::trim(const String &s)
464     if (s.size() < 1)
465         return s;
466     
467     //Find first non-ws char
468     unsigned int begin = 0;
469     for ( ; begin < s.size() ; begin++)
470         {
471         if (!isspace(s[begin]))
472             break;
473         }
475     //Find first non-ws char, going in reverse
476     unsigned int end = s.size() - 1;
477     for ( ; end > begin ; end--)
478         {
479         if (!isspace(s[end]))
480             break;
481         }
482     //trace("begin:%d  end:%d", begin, end);
484     String res = s.substr(begin, end-begin+1);
485     return res;
489 /**
490  *  Parse a full path name into path, base name, and suffix
491  */
492 void DepTool::parseName(const String &fullname,
493                         String &path,
494                         String &basename,
495                         String &suffix)
497     if (fullname.size() < 2)
498         return;
500     String::size_type pos = fullname.find_last_of('/');
501     if (pos != fullname.npos && pos<fullname.size()-1)
502         {
503         path = fullname.substr(0, pos);
504         pos++;
505         basename = fullname.substr(pos, fullname.size()-pos);
506         }
507     else
508         {
509         path = "";
510         basename = fullname;
511         }
513     pos = basename.find_last_of('.');
514     if (pos != basename.npos && pos<basename.size()-1)
515         {
516         suffix   = basename.substr(pos+1, basename.size()-pos-1);
517         basename = basename.substr(0, pos);
518         }
520     //trace("parsename:%s %s %s", path.c_str(),
521     //        basename.c_str(), suffix.c_str()); 
525 /**
526  *  Return the suffix, if any, of a file name
527  */
528 String DepTool::getSuffix(const String &fname)
530     if (fname.size() < 2)
531         return "";
532     String::size_type pos = fname.find_last_of('.');
533     if (pos == fname.npos)
534         return "";
535     pos++;
536     String res = fname.substr(pos, fname.size()-pos);
537     //trace("suffix:%s", res.c_str()); 
538     return res;
543 //########################################################################
544 //# P R O C E S S I N G
545 //########################################################################
547 /**
548  *  Recursively list all files and directories under 'dirname', except
549  *  those in the exclude list.
550  */
551 bool DepTool::listFilesInDirectory(const String &dirname, int depth)
553     //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
555     int cFiles = 0;
556     int hFiles = 0;
558     std::vector<String> subdirs;
559     DIR *dir = opendir(dirname.c_str());
560     while (true)
561         {
562         struct dirent *de = readdir(dir);
563         if (!de)
564             break;
565         String s = de->d_name;
566         struct stat finfo;
567         String fname;
568         if (s.size() == 0 || s[0] == '.')
569             continue;
571         if (dirname.size()>0 && dirname != ".")
572             {
573             fname.append(dirname);
574             fname.append("/");
575             }
576         fname.append(s);
577         if (stat(fname.c_str(), &finfo)<0)
578             {
579             error("cannot stat file:%s", s.c_str());
580             }
581         else if (excludes.find(fname) != excludes.end())
582             {
583             //trace("excluded file/dir: %s", fname.c_str());
584             excludesUsed.insert(fname);
585             }
586         else if (S_ISDIR(finfo.st_mode))
587             {
588             //trace("directory: %s", fname.c_str());
589             subdirs.push_back(fname);
590             }
591         else if (!S_ISREG(finfo.st_mode))
592             {
593             trace("not regular: %s", fname.c_str());
594             }
595         else
596             {
597             String path;
598             String basename;
599             String sfx;
600             parseName(fname, path, basename, sfx);
601             if (sfx == "cpp" || sfx == "c" || sfx == "cxx"   || sfx == "cc")
602                 {
603                 cFiles++;
604                 FileRec *fe  = new FileRec(FileRec::CFILE);
605                 fe->path     = path;
606                 fe->baseName = basename;
607                 fe->suffix   = sfx;
608                 allFiles[fname] = fe;
609                 }
610             else if (sfx == "h"   ||  sfx == "hh"  ||
611                      sfx == "hpp" ||  sfx == "hxx")
612                 {
613                 hFiles++;
614                 FileRec *fe = new FileRec(FileRec::HFILE);
615                 fe->path     = path;
616                 fe->baseName = basename;
617                 fe->suffix   = sfx;
618                 allFiles[fname] = fe;
619                 }
620             }
621         }
622     closedir(dir);
624     if (hFiles > 0)
625         directories.push_back(dirname);
627     for (unsigned int i=0 ; i<subdirs.size() ; i++)
628         {
629         listFilesInDirectory(subdirs[i], depth+1);
630         }
632     return true;
637 /**
638  *
639  */
640 bool DepTool::createFileList()
642     excludes.insert("deptool.cpp");
643     FILE *f = fopen("make.exclude", "r");
644     if (!f)
645         {
646         trace("'make.exclude not found");
647         }
648     else
649         {
650         char readBuf[256];
651         while (!feof(f))
652             {
653             if (!fgets(readBuf, 255, f))
654                 break;
655             String s = readBuf;
656             s = trim(s);
657             //trace("s: %d '%s' ", s.size(), s.c_str());
658             if (s.size() > 0 && s[0]!='#')
659                 excludes.insert(s);
660             }
661         fclose(f);
662         }
664     listFilesInDirectory(".", 0);
666     // Note which files in the exclude list were not used.
667     std::set<String>::iterator iter;
668     for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
669         {
670         String fname = *iter;
671         std::set<String>::iterator citer = excludesUsed.find(fname);
672         if (citer == excludesUsed.end())
673             excludesUnused.insert(fname);
674         }
676     saveFileList();
678     return true;
682 /**
683  * Get a character from the buffer at pos.  If out of range,
684  * return -1 for safety
685  */
686 int DepTool::get(int pos)
688     if (pos>fileSize)
689         return -1;
690     return fileBuf[pos];
695 /**
696  *  Skip over all whitespace characters beginning at pos.  Return
697  *  the position of the first non-whitespace character.
698  */
699 int DepTool::skipwhite(int pos)
701     while (pos < fileSize)
702         {
703         int ch = get(pos);
704         if (ch < 0)
705             break;
706         if (!isspace(ch))
707             break;
708         pos++;
709         }
710     return pos;
714 /**
715  *  Parse the buffer beginning at pos, for a word.  Fill
716  *  'ret' with the result.  Return the position after the
717  *  word.
718  */
719 int DepTool::getword(int pos, String &ret)
721     while (pos < fileSize)
722         {
723         int ch = get(pos);
724         if (ch < 0)
725             break;
726         if (isspace(ch))
727             break;
728         ret.push_back((char)ch);
729         pos++;
730         }
731     return pos;
734 /**
735  * Return whether the sequence of characters in the buffer
736  * beginning at pos match the key,  for the length of the key
737  */
738 bool DepTool::sequ(int pos, char *key)
740     while (*key)
741         {
742         if (*key != get(pos))
743             return false;
744         key++; pos++;
745         }
746     return true;
751 /**
752  *  Add an include file name to a file record.  If the name
753  *  is not found in allFiles explicitly, try prepending include
754  *  directory names to it and try again.
755  */
756 bool DepTool::addIncludeFile(FileRec *frec, const String &iname)
759     std::map<String, FileRec *>::iterator iter =
760            allFiles.find(iname);
761     if (iter != allFiles.end())
762         {
763          //h file in same dir
764         FileRec *other = iter->second;
765         //trace("local: '%s'", iname.c_str());
766         frec->files[iname] = other;
767         return true;
768         }
769     else 
770         {
771         //look in other dirs
772         std::vector<String>::iterator diter;
773         for (diter=directories.begin() ;
774              diter!=directories.end() ; diter++)
775             {
776             String dfname = *diter;
777             dfname.append("/");
778             dfname.append(iname);
779             iter = allFiles.find(dfname);
780             if (iter != allFiles.end())
781                 {
782                 FileRec *other = iter->second;
783                 //trace("other: '%s'", iname.c_str());
784                 frec->files[dfname] = other;
785                 return true;
786                 }
787             }
788         }
789     return true;
794 /**
795  *  Lightly parse a file to find the #include directives.  Do
796  *  a bit of state machine stuff to make sure that the directive
797  *  is valid.  (Like not in a comment).
798  */
799 bool DepTool::scanFile(const String &fname, FileRec *frec)
801     FILE *f = fopen(fname.c_str(), "r");
802     if (!f)
803         {
804         error("Could not open '%s' for reading", fname.c_str());
805         return false;
806         }
807     String buf;
808     while (!feof(f))
809         {
810         int len = fread(readBuf, 1, readBufLen, f);
811         readBuf[len] = '\0';
812         buf.append(readBuf);
813         }
814     fclose(f);
816     fileSize = buf.size();
817     fileBuf  = (char *)buf.c_str();
818     int pos = 0;
821     while (pos < fileSize)
822         {
823         //trace("p:%c", get(pos));
825         //# Block comment
826         if (get(pos) == '/' && get(pos+1) == '*')
827             {
828             pos += 2;
829             while (pos < fileSize)
830                 {
831                 if (get(pos) == '*' && get(pos+1) == '/')
832                     {
833                     pos += 2;
834                     break;
835                     }
836                 else
837                     pos++;
838                 }
839             }
840         //# Line comment
841         else if (get(pos) == '/' && get(pos+1) == '/')
842             {
843             pos += 2;
844             while (pos < fileSize)
845                 {
846                 if (get(pos) == '\n')
847                     {
848                     pos++;
849                     break;
850                     }
851                 else
852                     pos++;
853                 }
854             }
855         //# #include! yaay
856         else if (sequ(pos, "#include"))
857             {
858             pos += 8;
859             pos = skipwhite(pos);
860             String iname;
861             pos = getword(pos, iname);
862             if (iname.size()>2)
863                 {
864                 iname = iname.substr(1, iname.size()-2);
865                 addIncludeFile(frec, iname);
866                 }
867             }
868         else
869             {
870             pos++;
871             }
872         }
874     return true;
879 /**
880  *  Recursively check include lists to find all files in allFiles to which
881  *  a given file is dependent.
882  */
883 bool DepTool::processDependency(FileRec *ofile,
884                                 FileRec *include,
885                                 int depth)
887     std::map<String, FileRec *>::iterator iter;
888     for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
889         {
890         String fname  = iter->first;
891         if (ofile->files.find(fname) != ofile->files.end())
892             {
893             //trace("file '%s' already seen", fname.c_str());
894             continue;
895             }
896         FileRec *child  = iter->second;
897         ofile->files[fname] = child;
898       
899         processDependency(ofile, child, depth+1);
900         }
903     return true;
908 /**
909  *  Recursively check include lists to find all files in allFiles which
910  *  will eventually have a dependency on this file.  This is basically
911  *  the inverse of processDependency().
912  */
913 bool DepTool::processReference(FileRec *hfile,
914                                String &fname,
915                                int depth)
917     std::map<String, FileRec *>::iterator iter;
918     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
919         {
920         FileRec *frec = iter->second;
921         std::map<String, FileRec *>::iterator fiter =
922                   frec->files.find(fname);
923         if (fiter != frec->files.end())
924             {
925             String cfname  = iter->first;
926             if (hfile->files.find(cfname) != hfile->files.end())
927                 {
928                 //trace("%d reffile '%s' already seen", depth, cfname.c_str());
929                 continue;
930                 }
931             FileRec *child  = iter->second;
932             child->distance = depth;
933             hfile->files[cfname] = child;      
934             processReference(hfile, cfname, depth+1);
935             }
936         }
938     return true;
943 /**
944  *  Generate the file dependency and reference lists.
945  */
946 bool DepTool::generateDependencies()
948     std::map<String, FileRec *>::iterator iter;
949     //# First pass.  Scan for all includes
950     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
951         {
952         FileRec *frec = iter->second;
953         if (!scanFile(iter->first, frec))
954             {
955             //quit?
956             }
957         }
959     //# Second pass.  Scan for all includes
960     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
961         {
962         FileRec *include = iter->second;
963         if (include->type == FileRec::CFILE)
964             {
965             String cFileName = iter->first;
966             FileRec *ofile     = new FileRec(FileRec::OFILE);
967             ofile->path        = include->path;
968             ofile->baseName    = include->baseName;
969             ofile->suffix      = include->suffix;
970             String fname     = include->path;
971             if (fname.size()>0)
972                 fname.append("/");
973             fname.append(include->baseName);
974             fname.append(".o");
975             depFiles[fname]    = ofile;
976             //add the .c file first, of course
977             ofile->files[cFileName] = include;
978             //trace("ofile:%s", fname.c_str());
980             processDependency(ofile, include, 0);
981             }
982         /*
983         else if (include->type == FileRec::HFILE)
984             {
985             String fname     = iter->first;
986             FileRec *hfile     = new FileRec(FileRec::HFILE);
987             hfile->path        = include->path;
988             hfile->baseName    = include->baseName;
989             hfile->suffix      = include->suffix;
990             refFiles[fname]    = hfile;
991             //trace("hfile:%s", fname.c_str());
993             processReference(hfile, fname, 0);
994             }
995         */
996         }
998       
999     return true;
1003 /**
1004  *  High-level call to do what DepTool does.
1005  */
1006 bool DepTool::run()
1008     reset();
1009     if (!createFileList())
1010         return false;
1011     if (!generateDependencies())
1012         return false;
1013     saveDepFile(false);
1014     saveCmakeFile();
1015     //saveRefFile(true);
1016     return true;
1020 //########################################################################
1021 //# O U T P U T S
1022 //########################################################################
1026 /**
1027  *  Save the allFiles list.  This is basically all files in a directory
1028  *  except those denied in the exclude list.
1029  */
1030 bool DepTool::saveFileList()
1032     time_t tim;
1033     time(&tim);
1035     FILE *f = fopen("make.files", "w");
1036     if (!f)
1037         {
1038         trace("cannot open 'make.files' for writing");
1039         }
1040     fprintf(f, "########################################################\n");
1041     fprintf(f, "## File: make.files\n");
1042     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1043     fprintf(f, "########################################################\n");
1045     fprintf(f, "\n\n\n");
1046     fprintf(f, "########################################################\n");
1047     fprintf(f, "## F I L E S\n");
1048     fprintf(f, "########################################################\n");
1050     std::map<String, FileRec *>::iterator iter;
1051     for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
1052         {
1053         fprintf(f, "%s\n", iter->first.c_str());
1054         }
1056     fprintf(f, "\n\n\n");
1057     fprintf(f, "########################################################\n");
1058     fprintf(f, "## E X C L U D E D\n");
1059     fprintf(f, "########################################################\n");
1061     std::set<String>::iterator uiter;
1062     for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
1063         {
1064         String fname = *uiter;
1065         fprintf(f, "%s\n", fname.c_str());
1066         }
1068     fprintf(f, "\n\n\n");
1069     fprintf(f, "########################################################\n");
1070     fprintf(f, "## E X C L U D E  entries unused\n");
1071     fprintf(f, "########################################################\n");
1073     for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
1074         {
1075         String fname = *uiter;
1076         fprintf(f, "%s\n", fname.c_str());
1077         }
1079     fprintf(f, "\n\n\n");
1080     fprintf(f, "########################################################\n");
1081     fprintf(f, "## E N D\n");
1082     fprintf(f, "########################################################\n");
1084     fclose(f);
1086     return true;
1090 /**
1091  *   This is the main product.  This file lists the Include directives,
1092  *   the Object list, and the dependency list.
1093  */
1094 bool DepTool::saveDepFile(bool doXml)
1096     time_t tim;
1097     time(&tim);
1099     FILE *f = fopen("make.dep", "w");
1100     if (!f)
1101         {
1102         trace("cannot open 'make.dep' for writing");
1103         }
1104     if (doXml)
1105         {
1106         fprintf(f, "<?xml version='1.0'?>\n");
1107         fprintf(f, "<deptool>\n");
1108         fprintf(f, "\n");
1109         fprintf(f, "<!--\n");
1110         fprintf(f, "########################################################\n");
1111         fprintf(f, "## File: make.dep\n");
1112         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1113         fprintf(f, "########################################################\n");
1114         fprintf(f, "-->\n");
1116         fprintf(f, "\n\n");
1117     
1118         fprintf(f, "\n");
1119         fprintf(f, "<!--\n");
1120         fprintf(f, "########################################################\n");
1121         fprintf(f, "## I N C L U D E\n");
1122         fprintf(f, "########################################################\n");
1123         fprintf(f, "-->\n");
1124         fprintf(f, "<includes>\n");
1125     
1126         std::vector<String>::iterator inciter;
1127         for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1128             {
1129             String dirname = *inciter;
1130             fprintf(f, "    <inc name='%s'/>\n", dirname.c_str());
1131             }
1133         fprintf(f, "</includes>\n");
1134         fprintf(f, "\n\n\n");
1135         fprintf(f, "<!--\n");
1136         fprintf(f, "########################################################\n");
1137         fprintf(f, "## O B J E C T S\n");
1138         fprintf(f, "########################################################\n");
1139         fprintf(f, "-->\n");
1140         fprintf(f, "<objects>\n");
1141     
1142         std::map<String, FileRec *>::iterator oiter;
1143         for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1144             {
1145             FileRec *frec = oiter->second;
1146             if (frec->type == FileRec::CFILE)
1147                 {
1148                 String fname = frec->path;
1149                 if (fname.size()>0)
1150                     fname.append("/");
1151                 fname.append(frec->baseName);
1152                 fname.append(".o");
1153                 fprintf(f, "   <obj name='%s'/>\n", fname.c_str());
1154                 }
1155             }
1158         fprintf(f, "</objects>\n");
1159         fprintf(f, "\n\n\n");
1160         fprintf(f, "<!--\n");
1161         fprintf(f, "########################################################\n");
1162         fprintf(f, "## D E P E N D E N C I E S\n");
1163         fprintf(f, "########################################################\n");
1164         fprintf(f, "-->\n");
1165         fprintf(f, "<dependencies>\n\n");
1166         std::map<String, FileRec *>::iterator iter;
1167         for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1168             {
1169             FileRec *frec = iter->second;
1170             if (frec->type == FileRec::OFILE)
1171                 {
1172                 String fname = iter->first;
1173                 fprintf(f, "<file name='%s'>\n", fname.c_str());
1174                 std::map<String, FileRec *>::iterator citer;
1175                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1176                     {
1177                     String cfname = citer->first;
1178                     fprintf(f, "    <dep name='%s'/>\n", cfname.c_str());
1179                     }
1180                 fprintf(f, "</file>\n\n");
1181                 }
1182             }
1184         fprintf(f, "</dependencies>\n");
1185         fprintf(f, "\n\n\n");
1186         fprintf(f, "</deptool>\n");
1187         fprintf(f, "<!--\n");
1188         fprintf(f, "########################################################\n");
1189         fprintf(f, "## E N D\n");
1190         fprintf(f, "########################################################\n");
1191         fprintf(f, "-->\n");
1192         }
1193     else // ######### !XML
1194         {
1195         fprintf(f, "########################################################\n");
1196         fprintf(f, "## File: make.dep\n");
1197         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1198         fprintf(f, "########################################################\n");
1200         fprintf(f, "\n\n");
1201     
1202         fprintf(f, "########################################################\n");
1203         fprintf(f, "## I N C L U D E\n");
1204         fprintf(f, "########################################################\n");
1205         fprintf(f, "DEPTOOL_INCLUDE =");
1206     
1207         std::vector<String>::iterator inciter;
1208         for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
1209             {
1210             fprintf(f, " \\\n");
1211             String dirname = *inciter;
1212             fprintf(f, "-I%s", dirname.c_str());
1213             }
1215         fprintf(f, "\n\n\n");
1216         fprintf(f, "########################################################\n");
1217         fprintf(f, "## O B J E C T S\n");
1218         fprintf(f, "########################################################\n");
1219         fprintf(f, "DEPTOOL_OBJECTS =");
1220     
1221         std::map<String, FileRec *>::iterator oiter;
1222         for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1223             {
1224             FileRec *frec = oiter->second;
1225             if (frec->type == FileRec::CFILE)
1226                 {
1227                 fprintf(f, " \\\n");
1228                 String fname = frec->path;
1229                 if (fname.size()>0)
1230                     fname.append("/");
1231                 fname.append(frec->baseName);
1232                 fname.append(".o");
1233                 fprintf(f, "%s", fname.c_str());
1234                 }
1235             }
1238         fprintf(f, "\n\n\n");
1239         fprintf(f, "########################################################\n");
1240         fprintf(f, "## D E P E N D E N C I E S\n");
1241         fprintf(f, "########################################################\n");
1242         std::map<String, FileRec *>::iterator iter;
1243         for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
1244             {
1245             FileRec *frec = iter->second;
1246             if (frec->type == FileRec::OFILE)
1247                 {
1248                 String fname = iter->first;
1249                 fprintf(f, "%s:", fname.c_str());
1250                 std::map<String, FileRec *>::iterator citer;
1251                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1252                     {
1253                     String cfname = citer->first;
1254                     fprintf(f, " \\\n");
1255                     fprintf(f, "\t%s", cfname.c_str());
1256                     }
1257                 fprintf(f, "\n\n\n");
1258                 }
1259             }
1261         fprintf(f, "\n\n\n");
1262         fprintf(f, "########################################################\n");
1263         fprintf(f, "## E N D\n");
1264         fprintf(f, "########################################################\n");
1265         }
1267     fclose(f);
1269     return true;
1273 /**
1274  *  Save the "reference" file, which lists each include file, and any files
1275  *  that are judged to be dependent upon it.
1276  */
1277 bool DepTool::saveRefFile(bool doXml)
1279     time_t tim;
1280     time(&tim);
1282     FILE *f = fopen("make.ref", "w");
1283     if (!f)
1284         {
1285         trace("cannot open 'make.ref' for writing");
1286         }
1287     if (doXml)
1288         {
1289         fprintf(f, "<?xml version='1.0'?>\n");
1290         fprintf(f, "<deptool>\n\n");
1291         fprintf(f, "<!--\n");
1292         fprintf(f, "########################################################\n");
1293         fprintf(f, "## File: make.ref\n");
1294         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1295         fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1296         fprintf(f, "##    the given file.\n");
1297         fprintf(f, "########################################################\n");
1298         fprintf(f, "-->\n");
1299         fprintf(f, "\n\n");
1300     
1302         std::map<String, FileRec *>::iterator iter;
1303         for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1304             {
1305             FileRec *frec = iter->second;
1306             if (frec->type == FileRec::HFILE)
1307                 {
1308                 String fname = iter->first;
1309                 fprintf(f, "<file name='%s'>\n", fname.c_str());
1310                 std::map<String, FileRec *>::iterator citer;
1311                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1312                     {
1313                     String cfname = citer->first;
1314                     fprintf(f, "    <ref d='%d' name='%s'/>\n", 
1315                                citer->second->distance, cfname.c_str());
1316                     }
1317                 fprintf(f, "</file>\n\n");
1318                 }
1319             }
1320         fprintf(f, "\n\n\n");
1321         fprintf(f, "</deptool>\n");
1322         fprintf(f, "<!--\n");
1323         fprintf(f, "########################################################\n");
1324         fprintf(f, "## E N D\n");
1325         fprintf(f, "########################################################\n");
1326         fprintf(f, "-->\n");
1327         }
1329     else //######### not xml
1330         {
1331         fprintf(f, "########################################################\n");
1332         fprintf(f, "## File: make.ref\n");
1333         fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1334         fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
1335         fprintf(f, "##    the given file.\n");
1336         fprintf(f, "########################################################\n");
1337         fprintf(f, "\n\n");
1338     
1340         std::map<String, FileRec *>::iterator iter;
1341         for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
1342             {
1343             FileRec *frec = iter->second;
1344             if (frec->type == FileRec::HFILE)
1345                 {
1346                 String fname = iter->first;
1347                 fprintf(f, "### %s\n", fname.c_str());
1348                 std::map<String, FileRec *>::iterator citer;
1349                 for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
1350                     {
1351                     String cfname = citer->first;
1352                     fprintf(f, "%3d %s\n", citer->second->distance,
1353                                    cfname.c_str());
1354                     }
1355                 fprintf(f, "\n");
1356                 }
1357             }
1359         fprintf(f, "\n\n\n");
1360         fprintf(f, "########################################################\n");
1361         fprintf(f, "## E N D\n");
1362         fprintf(f, "########################################################\n");
1363         }
1365     fclose(f);
1367     return true;
1371 /**
1372  *   This is a new thing.  It creates a cmake file that should be able to
1373  *   build the entire thing. 
1374  */
1375 bool DepTool::saveCmakeFile()
1377     time_t tim;
1378     time(&tim);
1380     FILE *f = fopen("CMakeLists.txt", "w");
1381     if (!f)
1382         {
1383         trace("cannot open 'CMakeLists.txt' for writing");
1384         }
1385     fprintf(f, "########################################################\n");
1386     fprintf(f, "## File: CMakeLists.txt\n");
1387     fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
1388     fprintf(f, "########################################################\n");
1390     fprintf(f, "\n\n");
1391     
1392     fprintf(f, "\n\n\n");
1393     fprintf(f, "########################################################\n");
1394     fprintf(f, "## P R O J E C T\n");
1395     fprintf(f, "########################################################\n");
1396     fprintf(f, "project (INKSCAPE)\n");
1397     fprintf(f, "\n\n\n");
1398     fprintf(f, "########################################################\n");
1399     fprintf(f, "## O B J E C T S\n");
1400     fprintf(f, "########################################################\n");
1401     fprintf(f, "set (INKSCAPE_SRCS\n");
1402     
1403     std::map<String, FileRec *>::iterator oiter;
1404     for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
1405         {
1406         FileRec *frec = oiter->second;
1407         if (frec->type == FileRec::CFILE)
1408             {
1409             //fprintf(f, " \\\n");
1410             String fname = frec->path;
1411             if (fname.size()>0)
1412                 fname.append("/");
1413             fname.append(frec->baseName);
1414             fname.append(".");
1415             fname.append(frec->suffix);
1416             fprintf(f, "%s\n", fname.c_str());
1417             }
1418         }
1419     fprintf(f, ")\n\n");
1421     fprintf(f, "add_executable (inkscape ${INKSCAPE_SRCS})\n");
1423     fprintf(f, "\n\n\n");
1424     fprintf(f, "########################################################\n");
1425     fprintf(f, "## E N D\n");
1426     fprintf(f, "########################################################\n");
1428     fclose(f);
1430     return true;
1438 //########################################################################
1439 //# M A I N
1440 //########################################################################
1443 /**
1444  *  Run the DepTool's main functions
1445  */
1446 static bool runTool()
1448     DepTool depTool;
1450     if (!depTool.run())
1451         return false;
1453     return true;
1457 /**
1458  * Console main()
1459  */
1460 int main(int argc, char **argv)
1462     if (!runTool())
1463         return 1;
1465     return 0;
1469 //########################################################################
1470 //# E N D    O F    F I L E
1471 //########################################################################