Code

new file
authorishmal <ishmal@users.sourceforge.net>
Mon, 19 Jun 2006 18:24:50 +0000 (18:24 +0000)
committerishmal <ishmal@users.sourceforge.net>
Mon, 19 Jun 2006 18:24:50 +0000 (18:24 +0000)
src/deptool.cpp [new file with mode: 0644]

diff --git a/src/deptool.cpp b/src/deptool.cpp
new file mode 100644 (file)
index 0000000..c35a63e
--- /dev/null
@@ -0,0 +1,1256 @@
+/**
+ * DepTool dependency tool
+ *
+ * This is a simple dependency generator coded in C++
+ *
+ * Authors:
+ *   Bob Jamison
+ *
+ * Copyright (C) 2006 Bob Jamison
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ INSTRUCTIONS
+
+ 1.  First you optionally create a file named 'make.exclude.'  This
+ lists the file names relative to the current directory.  Lines starting
+ with a '#' are ignored.  Here is an example:
+========= SNIP ======== 
+######################################################################
+# File: make.exclude
+#
+# This is a list of files to exclude from building, using DepTool
+#
+######################################################################
+
+
+ast
+bonobo
+
+dialogs/filedialog-win32.cpp
+display/testnr.cpp
+display/bezier-utils-test.cpp
+dom/work
+#next line is ignored
+#dom/odf/SvgOdg.cpp
+extension/api.cpp
+========= SNIP ======== 
+
+2.  Run deptool.  This will take a few seconds to scan all of your files
+and make its dependency lists.  Three files are created:
+make.files: lists all of the files that were considered
+make.dep: contains the output INCLUDE and OBJECT declarations
+    for you to include and use in your makefile.  It also contains
+    the dependency listings.
+make.ref: contains a reverse-dependency listing.  This takes each file
+    and recursively determines which other files include it, and how
+    far the nesting is.
+
+3.  Include deptool.mk in your makefile.
+
+*/
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+
+
+//# This will allow us to redefine the string in the future
+typedef std::string DTString;
+
+/**
+ *  Class which holds information for each file.
+ */
+class FileRec
+{
+public:
+
+    typedef enum
+        {
+        UNKNOWN,
+        CFILE,
+        HFILE,
+        OFILE
+        } FileType;
+
+    /**
+     *  Constructor
+     */
+    FileRec()
+        {type = UNKNOWN;}
+
+    /**
+     *  Copy constructor
+     */
+    FileRec(const FileRec &other)
+        {assign(other);}
+    /**
+     *  Constructor
+     */
+    FileRec(int typeVal)
+        {init(); type = typeVal;}
+    /**
+     *  Assignment operator
+     */
+    FileRec &operator=(const FileRec &other)
+        {assign(other); return *this;}
+
+
+    /**
+     *  Destructor
+     */
+    ~FileRec()
+        {}
+
+    /**
+     *  Directory part of the file name
+     */
+    DTString path;
+
+    /**
+     *  Base name, sans directory and suffix
+     */
+    DTString baseName;
+
+    /**
+     *  File extension, such as cpp or h
+     */
+    DTString suffix;
+
+    /**
+     *  Type of file: CFILE, HFILE, OFILE
+     */
+    int type;
+
+    /**
+     *  'Distance' of inclusion from a file that depends on this one.
+     */
+    int distance;
+
+    /**
+     * Used to list files ref'd by this one, in the case of allFiles,
+     * or other files which reference this one, such as refFiles;
+     */
+    std::map<DTString, FileRec *> files;
+
+
+private:
+
+    void init()
+        {
+        }
+
+    void assign(const FileRec &other)
+        {
+        type     = other.type;
+        distance = other.distance;
+        baseName = other.baseName;
+        suffix   = other.suffix;
+        files    = other.files;
+        }
+
+};
+
+
+
+/**
+ *  Main class which does the work.
+ */
+class DepTool
+{
+public:
+
+    /**
+     *  Constructor
+     */
+    DepTool();
+
+    /**
+     *  Destructor
+     */
+    virtual ~DepTool();
+
+    /**
+     * Creates the list of all file names which will be
+     * candidates for further processing.  Reads make.exclude
+     * to see which files for directories to leave out.
+     */
+    virtual bool createFileList();
+
+
+    /**
+     *  Generates the forward and reverse dependency lists
+     */
+    virtual bool generateDependencies();
+
+    /**
+     *  Calls the other two methods, then generates the files.
+     */
+    virtual bool run();
+
+
+private:
+
+    /**
+     *
+     */
+    void reset();
+
+    /**
+     *
+     */
+    void error(char *fmt, ...);
+
+    /**
+     *
+     */
+    void trace(char *fmt, ...);
+
+    /**
+     *  Removes whitespace from beginning and end of a string
+     */
+    DTString trim(const DTString &val);
+
+    /**
+     *
+     */
+    DTString getSuffix(const DTString &fname);
+
+    /**
+     *
+     */
+    void parseName(const DTString &fullname,
+                   DTString &path,
+                   DTString &basename,
+                   DTString &suffix);
+
+    /**
+     *
+     */
+    int get(int pos);
+
+    /**
+     *
+     */
+    int skipwhite(int pos);
+
+    /**
+     *
+     */
+    int getword(int pos, DTString &ret);
+
+    /**
+     *
+     */
+    bool sequ(int pos, char *key);
+
+    /**
+     *
+     */
+    bool listFilesInDirectory(const DTString &dirname, int depth);
+
+    /**
+     *
+     */
+    bool saveFileList();
+
+    /**
+     *
+     */
+    bool saveDepFile();
+
+    /**
+     *
+     */
+    bool saveRefFile();
+
+    /**
+     *
+     */
+    bool addIncludeFile(FileRec *frec, const DTString &fname);
+
+    /**
+     *
+     */
+    bool scanFile(const DTString &fname, FileRec *frec);
+
+    /**
+     *
+     */
+    bool processDependency(FileRec *ofile,
+                           FileRec *include,
+                           int depth);
+
+    /**
+     *
+     */
+    bool processReference(FileRec *ofile,
+                          DTString &fname,
+                          int depth);
+
+    /**
+     *
+     */
+    std::set<DTString> excludes;
+
+    /**
+     *
+     */
+    std::set<DTString> excludesUsed;
+
+    /**
+     *
+     */
+    std::set<DTString> excludesUnused;
+
+    /**
+     *
+     */
+    std::vector<DTString> directories;
+
+    /**
+     * A list of all files which will be processed for
+     * dependencies.
+     */
+    std::map<DTString, FileRec *> allFiles;
+
+    /**
+     * A list of .h files, with a list for each one
+     * of which other files include them.
+     */
+    std::map<DTString, FileRec *> refFiles;
+
+    /**
+     * The list of .o files, and the
+     * dependencies upon them.
+     */
+    std::map<DTString, FileRec *> depFiles;
+
+    char *fileBuf;
+    int   fileSize;
+
+
+};
+
+
+//########################################################################
+//# M A I N
+//########################################################################
+
+/**
+ * Constructor
+ */
+DepTool::DepTool()
+{
+}
+
+
+/**
+ *  Destructor
+ */
+DepTool::~DepTool()
+{
+    reset();
+}
+
+/**
+ *  Clean up after processing.  Called by the destructor, but should
+ *  also be called before the object is reused.
+ */
+void DepTool::reset()
+{
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        delete frec;
+        }
+    allFiles.clear();
+    for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        delete frec;
+        }
+    refFiles.clear();
+    for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        delete frec;
+        }
+    depFiles.clear();
+
+    excludes.clear();
+    excludesUsed.clear();
+    excludesUnused.clear();
+}
+
+
+/**
+ *  Format an error message in printf() style
+ */
+void DepTool::error(char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr, "DepTool error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+}
+
+
+/**
+ *  Format an trace message in printf() style
+ */
+void DepTool::trace(char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stdout, "DepTool: ");
+    vfprintf(stdout, fmt, ap);
+    fprintf(stdout, "\n");
+    va_end(ap);
+}
+
+
+
+//########################################################################
+//# U T I L I T Y
+//########################################################################
+
+/**
+ *  Removes whitespace from beginning and end of a string
+ */
+DTString DepTool::trim(const DTString &s)
+{
+    if (s.size() < 1)
+        return s;
+    
+    //Find first non-ws char
+    unsigned int begin = 0;
+    for ( ; begin < s.size() ; begin++)
+        {
+        if (!isspace(s[begin]))
+            break;
+        }
+
+    //Find first non-ws char, going in reverse
+    unsigned int end = s.size() - 1;
+    for ( ; end > begin ; end--)
+        {
+        if (!isspace(s[end]))
+            break;
+        }
+    //trace("begin:%d  end:%d", begin, end);
+
+    DTString res = s.substr(begin, end-begin+1);
+    return res;
+}
+
+
+/**
+ *  Parse a full path name into path, base name, and suffix
+ */
+void DepTool::parseName(const DTString &fullname,
+                        DTString &path,
+                        DTString &basename,
+                        DTString &suffix)
+{
+    if (fullname.size() < 2)
+        return;
+
+    unsigned int pos = fullname.find_last_of('/');
+    if (pos != fullname.npos && pos<fullname.size()-1)
+        {
+        path = fullname.substr(0, pos);
+        pos++;
+        basename = fullname.substr(pos, fullname.size()-pos);
+        }
+    else
+        {
+        path = "";
+        basename = fullname;
+        }
+
+    pos = basename.find_last_of('.');
+    if (pos != basename.npos && pos<basename.size()-1)
+        {
+        suffix   = basename.substr(pos+1, basename.size()-pos-1);
+        basename = basename.substr(0, pos);
+        }
+
+    //trace("parsename:%s %s %s", path.c_str(),
+    //        basename.c_str(), suffix.c_str()); 
+}
+
+
+/**
+ *  Return the suffix, if any, of a file name
+ */
+DTString DepTool::getSuffix(const DTString &fname)
+{
+    if (fname.size() < 2)
+        return "";
+    unsigned int pos = fname.find_last_of('.');
+    if (pos == fname.npos)
+        return "";
+    pos++;
+    DTString res = fname.substr(pos, fname.size()-pos);
+    //trace("suffix:%s", res.c_str()); 
+    return res;
+}
+
+
+
+//########################################################################
+//# P R O C E S S I N G
+//########################################################################
+
+/**
+ *  Recursively list all files and directories under 'dirname', except
+ *  those in the exclude list.
+ */
+bool DepTool::listFilesInDirectory(const DTString &dirname, int depth)
+{
+    //trace("### listFilesInDirectory(%s, %d)", dirname.c_str(), depth);
+
+    int cFiles = 0;
+    int hFiles = 0;
+
+    std::vector<DTString> subdirs;
+    DIR *dir = opendir(dirname.c_str());
+    while (true)
+        {
+        struct dirent *de = readdir(dir);
+        if (!de)
+            break;
+        DTString s = de->d_name;
+        struct stat finfo;
+        DTString fname;
+        if (s.size() == 0 || s[0] == '.')
+            continue;
+
+        if (dirname.size()>0 && dirname != ".")
+            {
+            fname.append(dirname);
+            fname.append("/");
+            }
+        fname.append(s);
+        if (stat(fname.c_str(), &finfo)<0)
+            {
+            error("cannot stat file:%s", s.c_str());
+            }
+        else if (excludes.find(fname) != excludes.end())
+            {
+            //trace("excluded file/dir: %s", fname.c_str());
+            excludesUsed.insert(fname);
+            }
+        else if (S_ISDIR(finfo.st_mode))
+            {
+            //trace("directory: %s", fname.c_str());
+            subdirs.push_back(fname);
+            }
+        else if (!S_ISREG(finfo.st_mode))
+            {
+            trace("not regular: %s", fname.c_str());
+            }
+        else
+            {
+            DTString path;
+            DTString basename;
+            DTString sfx;
+            parseName(fname, path, basename, sfx);
+            if (sfx == "cpp" || sfx == "c" || sfx == "cxx"   || sfx == "cc")
+                {
+                cFiles++;
+                FileRec *fe  = new FileRec(FileRec::CFILE);
+                fe->path     = path;
+                fe->baseName = basename;
+                fe->suffix   = sfx;
+                allFiles[fname] = fe;
+                }
+            else if (sfx == "h"   ||  sfx == "hh"  ||
+                     sfx == "hpp" ||  sfx == "hxx")
+                {
+                hFiles++;
+                FileRec *fe = new FileRec(FileRec::HFILE);
+                fe->path     = path;
+                fe->baseName = basename;
+                fe->suffix   = sfx;
+                allFiles[fname] = fe;
+                }
+            }
+        }
+    closedir(dir);
+
+    if (hFiles > 0)
+        directories.push_back(dirname);
+
+    for (unsigned int i=0 ; i<subdirs.size() ; i++)
+        {
+        listFilesInDirectory(subdirs[i], depth+1);
+        }
+
+    return true;
+}
+
+
+
+/**
+ *
+ */
+bool DepTool::createFileList()
+{
+    excludes.insert("deptool.cpp");
+    FILE *f = fopen("make.exclude", "r");
+    if (!f)
+        {
+        trace("'make.exclude not found");
+        }
+    else
+        {
+        char readBuf[256];
+        while (!feof(f))
+            {
+            if (!fgets(readBuf, 255, f))
+                break;
+            DTString s = readBuf;
+            s = trim(s);
+            //trace("s: %d '%s' ", s.size(), s.c_str());
+            if (s.size() > 0 && s[0]!='#')
+                excludes.insert(s);
+            }
+        fclose(f);
+        }
+
+    listFilesInDirectory(".", 0);
+
+    // Note which files in the exclude list were not used.
+    std::set<DTString>::iterator iter;
+    for (iter=excludes.begin() ; iter!=excludes.end() ; iter++)
+        {
+        DTString fname = *iter;
+        std::set<DTString>::iterator citer = excludesUsed.find(fname);
+        if (citer == excludesUsed.end())
+            excludesUnused.insert(fname);
+        }
+
+    saveFileList();
+
+    return true;
+}
+
+
+/**
+ * Get a character from the buffer at pos.  If out of range,
+ * return -1 for safety
+ */
+int DepTool::get(int pos)
+{
+    if (pos>fileSize)
+        return -1;
+    return fileBuf[pos];
+}
+
+
+
+/**
+ *  Skip over all whitespace characters beginning at pos.  Return
+ *  the position of the first non-whitespace character.
+ */
+int DepTool::skipwhite(int pos)
+{
+    while (pos < fileSize)
+        {
+        int ch = get(pos);
+        if (ch < 0)
+            break;
+        if (!isspace(ch))
+            break;
+        pos++;
+        }
+    return pos;
+}
+
+
+/**
+ *  Parse the buffer beginning at pos, for a word.  Fill
+ *  'ret' with the result.  Return the position after the
+ *  word.
+ */
+int DepTool::getword(int pos, DTString &ret)
+{
+    while (pos < fileSize)
+        {
+        int ch = get(pos);
+        if (ch < 0)
+            break;
+        if (isspace(ch))
+            break;
+        ret.push_back((char)ch);
+        pos++;
+        }
+    return pos;
+}
+
+/**
+ * Return whether the sequence of characters in the buffer
+ * beginning at pos match the key,  for the length of the key
+ */
+bool DepTool::sequ(int pos, char *key)
+{
+    while (*key)
+        {
+        if (*key != get(pos))
+            return false;
+        key++; pos++;
+        }
+    return true;
+}
+
+
+
+/**
+ *  Add an include file name to a file record.  If the name
+ *  is not found in allFiles explicitly, try prepending include
+ *  directory names to it and try again.
+ */
+bool DepTool::addIncludeFile(FileRec *frec, const DTString &iname)
+{
+
+    std::map<DTString, FileRec *>::iterator iter =
+           allFiles.find(iname);
+    if (iter != allFiles.end())
+        {
+         //h file in same dir
+        FileRec *other = iter->second;
+        //trace("local: '%s'", iname.c_str());
+        frec->files[iname] = other;
+        return true;
+        }
+    else 
+        {
+        //look in other dirs
+        std::vector<DTString>::iterator diter;
+        for (diter=directories.begin() ;
+             diter!=directories.end() ; diter++)
+            {
+            DTString dfname = *diter;
+            dfname.append("/");
+            dfname.append(iname);
+            iter = allFiles.find(dfname);
+            if (iter != allFiles.end())
+                {
+                FileRec *other = iter->second;
+                //trace("other: '%s'", iname.c_str());
+                frec->files[dfname] = other;
+                return true;
+                }
+            }
+        }
+    return true;
+}
+
+
+
+/**
+ *  Lightly parse a file to find the #include directives.  Do
+ *  a bit of state machine stuff to make sure that the directive
+ *  is valid.  (Like not in a comment).
+ */
+bool DepTool::scanFile(const DTString &fname, FileRec *frec)
+{
+    FILE *f = fopen(fname.c_str(), "r");
+    if (!f)
+        {
+        error("Could not open '%s' for reading", fname.c_str());
+        return false;
+        }
+    DTString buf;
+    while (true)
+        {
+        int ch = fgetc(f);
+        if (ch < 0)
+            break;
+        buf.push_back((char)ch);
+        }
+    fclose(f);
+
+    fileSize = buf.size();
+    fileBuf  = (char *)buf.c_str();
+    int pos = 0;
+
+
+    while (pos < fileSize)
+        {
+        //trace("p:%c", get(pos));
+
+        //# Block comment
+        if (get(pos) == '/' && get(pos+1) == '*')
+            {
+            pos += 2;
+            while (pos < fileSize)
+                {
+                if (get(pos) == '*' && get(pos+1) == '/')
+                    {
+                    pos += 2;
+                    break;
+                    }
+                else
+                    pos++;
+                }
+            }
+        //# Line comment
+        else if (get(pos) == '/' && get(pos+1) == '/')
+            {
+            pos += 2;
+            while (pos < fileSize)
+                {
+                if (get(pos) == '\n')
+                    {
+                    pos++;
+                    break;
+                    }
+                else
+                    pos++;
+                }
+            }
+        //# #include! yaay
+        else if (sequ(pos, "#include"))
+            {
+            pos += 8;
+            pos = skipwhite(pos);
+            DTString iname;
+            pos = getword(pos, iname);
+            if (iname.size()>2)
+                {
+                iname = iname.substr(1, iname.size()-2);
+                addIncludeFile(frec, iname);
+                }
+            }
+        else
+            {
+            pos++;
+            }
+        }
+
+    return true;
+}
+
+
+
+/**
+ *  Recursively check include lists to find all files in allFiles to which
+ *  a given file is dependent.
+ */
+bool DepTool::processDependency(FileRec *ofile,
+                                FileRec *include,
+                                int depth)
+{
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=include->files.begin() ; iter!=include->files.end() ; iter++)
+        {
+        DTString fname  = iter->first;
+        if (ofile->files.find(fname) != ofile->files.end())
+            {
+            //trace("file '%s' already seen", fname.c_str());
+            continue;
+            }
+        FileRec *child  = iter->second;
+        ofile->files[fname] = child;
+      
+        processDependency(ofile, child, depth+1);
+        }
+
+
+    return true;
+}
+
+
+
+/**
+ *  Recursively check include lists to find all files in allFiles which
+ *  will eventually have a dependency on this file.  This is basically
+ *  the inverse of processDependency().
+ */
+bool DepTool::processReference(FileRec *hfile,
+                               DTString &fname,
+                               int depth)
+{
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        std::map<DTString, FileRec *>::iterator fiter =
+                  frec->files.find(fname);
+        if (fiter != frec->files.end())
+            {
+            DTString cfname  = iter->first;
+            if (hfile->files.find(cfname) != hfile->files.end())
+                {
+                //trace("%d reffile '%s' already seen", depth, cfname.c_str());
+                continue;
+                }
+            FileRec *child  = iter->second;
+            child->distance = depth;
+            hfile->files[cfname] = child;      
+            processReference(hfile, cfname, depth+1);
+            }
+        }
+
+    return true;
+}
+
+
+
+/**
+ *  Generate the file dependency and reference lists.
+ */
+bool DepTool::generateDependencies()
+{
+    std::map<DTString, FileRec *>::iterator iter;
+    //# First pass.  Scan for all includes
+    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        if (!scanFile(iter->first, frec))
+            {
+            //quit?
+            }
+        }
+
+    //# Second pass.  Scan for all includes
+    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
+        {
+        FileRec *include = iter->second;
+        if (include->type == FileRec::CFILE)
+            {
+            DTString cFileName = iter->first;
+            FileRec *ofile     = new FileRec(FileRec::OFILE);
+            ofile->path        = include->path;
+            ofile->baseName    = include->baseName;
+            ofile->suffix      = include->suffix;
+            DTString fname     = include->path;
+            if (fname.size()>0)
+                fname.append("/");
+            fname.append(include->baseName);
+            fname.append(".o");
+            depFiles[fname]    = ofile;
+            //add the .c file first, of course
+            ofile->files[cFileName] = include;
+            //trace("ofile:%s", fname.c_str());
+
+            processDependency(ofile, include, 0);
+            }
+        else if (include->type == FileRec::HFILE)
+            {
+            DTString fname     = iter->first;
+            FileRec *hfile     = new FileRec(FileRec::HFILE);
+            hfile->path        = include->path;
+            hfile->baseName    = include->baseName;
+            hfile->suffix      = include->suffix;
+            refFiles[fname]    = hfile;
+            //trace("hfile:%s", fname.c_str());
+
+            processReference(hfile, fname, 0);
+            }
+        }
+
+      
+    return true;
+}
+
+
+/**
+ *  High-level call to do what DepTool does.
+ */
+bool DepTool::run()
+{
+    reset();
+    if (!createFileList())
+        return false;
+    if (!generateDependencies())
+        return false;
+    saveDepFile();
+    saveRefFile();
+    return true;
+}
+
+
+//########################################################################
+//# O U T P U T S
+//########################################################################
+
+
+
+/**
+ *  Save the allFiles list.  This is basically all files in a directory
+ *  except those denied in the exclude list.
+ */
+bool DepTool::saveFileList()
+{
+    time_t tim;
+    time(&tim);
+
+    FILE *f = fopen("make.files", "w");
+    if (!f)
+        {
+        trace("cannot open 'make.files' for writing");
+        }
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## File: make.files\n");
+    fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
+    fprintf(f, "########################################################\n");
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## F I L E S\n");
+    fprintf(f, "########################################################\n");
+
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=allFiles.begin() ; iter!=allFiles.end() ; iter++)
+        {
+        fprintf(f, "%s\n", iter->first.c_str());
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## E X C L U D E D\n");
+    fprintf(f, "########################################################\n");
+
+    std::set<DTString>::iterator uiter;
+    for (uiter=excludesUsed.begin() ; uiter!=excludesUsed.end() ; uiter++)
+        {
+        DTString fname = *uiter;
+        fprintf(f, "%s\n", fname.c_str());
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## E X C L U D E  entries unused\n");
+    fprintf(f, "########################################################\n");
+
+    for (uiter=excludesUnused.begin() ; uiter!=excludesUnused.end() ; uiter++)
+        {
+        DTString fname = *uiter;
+        fprintf(f, "%s\n", fname.c_str());
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## E N D\n");
+    fprintf(f, "########################################################\n");
+
+    fclose(f);
+
+    return true;
+}
+
+
+/**
+ *   This is the main product.  This file lists the Include directives,
+ *   the Object list, and the dependency list.
+ */
+bool DepTool::saveDepFile()
+{
+    time_t tim;
+    time(&tim);
+
+    FILE *f = fopen("make.dep", "w");
+    if (!f)
+        {
+        trace("cannot open 'make.dep' for writing");
+        }
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## File: make.dep\n");
+    fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
+    fprintf(f, "########################################################\n");
+
+    fprintf(f, "\n\n");
+    
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## I N C L U D E\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "DEPTOOL_INCLUDE =");
+    
+    std::vector<DTString>::iterator inciter;
+    for (inciter=directories.begin() ; inciter!=directories.end() ; inciter++)
+        {
+        fprintf(f, " \\\n");
+        DTString dirname = *inciter;
+        fprintf(f, "-I%s", dirname.c_str());
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## O B J E C T S\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "DEPTOOL_OBJECTS =");
+    
+    std::map<DTString, FileRec *>::iterator oiter;
+    for (oiter=allFiles.begin() ; oiter!=allFiles.end() ; oiter++)
+        {
+        FileRec *frec = oiter->second;
+        if (frec->type == FileRec::CFILE)
+            {
+            fprintf(f, " \\\n");
+            DTString fname = frec->path;
+            if (fname.size()>0)
+                fname.append("/");
+            fname.append(frec->baseName);
+            fname.append(".o");
+            fprintf(f, "%s", fname.c_str());
+            }
+        }
+
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## D E P E N D E N C I E S\n");
+    fprintf(f, "########################################################\n");
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=depFiles.begin() ; iter!=depFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        if (frec->type == FileRec::OFILE)
+            {
+            DTString fname = iter->first;
+            fprintf(f, "%s:", fname.c_str());
+            std::map<DTString, FileRec *>::iterator citer;
+            for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
+                {
+                DTString cfname = citer->first;
+                fprintf(f, " \\\n");
+                fprintf(f, "\t%s", cfname.c_str());
+                }
+            fprintf(f, "\n\n\n");
+            }
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## E N D\n");
+    fprintf(f, "########################################################\n");
+
+    fclose(f);
+
+    return true;
+}
+
+
+/**
+ *  Save the "reference" file, which lists each include file, and any files
+ *  that are judged to be dependent upon it.
+ */
+bool DepTool::saveRefFile()
+{
+    time_t tim;
+    time(&tim);
+
+    FILE *f = fopen("make.ref", "w");
+    if (!f)
+        {
+        trace("cannot open 'make.ref' for writing");
+        }
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## File: make.ref\n");
+    fprintf(f, "## Generated by DepTool at :%s", ctime(&tim));
+    fprintf(f, "## Note: The metric is the 'distance' of inclusion from\n");
+    fprintf(f, "##    the given file.\n");
+    fprintf(f, "########################################################\n");
+
+    fprintf(f, "\n\n");
+    
+    std::map<DTString, FileRec *>::iterator iter;
+    for (iter=refFiles.begin() ; iter!=refFiles.end() ; iter++)
+        {
+        FileRec *frec = iter->second;
+        if (frec->type == FileRec::HFILE)
+            {
+            DTString fname = iter->first;
+            fprintf(f, "### %s\n", fname.c_str());
+            std::map<DTString, FileRec *>::iterator citer;
+            for (citer=frec->files.begin() ; citer!=frec->files.end() ; citer++)
+                {
+                DTString cfname = citer->first;
+                fprintf(f, "%3d %s\n", citer->second->distance,
+                               cfname.c_str());
+                }
+            fprintf(f, "\n");
+            }
+        }
+
+    fprintf(f, "\n\n\n");
+    fprintf(f, "########################################################\n");
+    fprintf(f, "## E N D\n");
+    fprintf(f, "########################################################\n");
+
+    fclose(f);
+
+    return true;
+}
+
+
+
+
+
+
+//########################################################################
+//# M A I N
+//########################################################################
+
+
+/**
+ *  Run the DepTool's main functions
+ */
+static bool runTool()
+{
+    DepTool depTool;
+
+    if (!depTool.run())
+        return false;
+
+    return true;
+}
+
+
+/**
+ * Console main()
+ */
+int main(int argc, char **argv)
+{
+    if (!runTool())
+        return 1;
+
+    return 0;
+}
+
+
+//########################################################################
+//# E N D    O F    F I L E
+//########################################################################