Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

GraphVizVisitor.cxx

00001 /* -*-c-file-style: "hopper";-*- */
00002 
00003 /*
00004  * Copyright 2000 by Eric M. Hopper <hopper@omnifarious.mn.org>
00005  * 
00006  *     This program is free software; you can redistribute it and/or modify it
00007  *     under the terms of the GNU Lesser General Public License as published
00008  *     by the Free Software Foundation; either version 2 of the License, or
00009  *     (at your option) any later version.
00010  * 
00011  *     This program is distributed in the hope that it will be useful, but
00012  *     WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *     Lesser General Public License for more details.
00015  * 
00016  *     You should have received a copy of the GNU Lesser General Public
00017  *     License along with this program; if not, write to the Free Software
00018  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 /* $Header: /home/hopper/src/cvs/C++/StrMod/GraphVizVisitor.cxx,v 1.9 2002/02/05 22:50:06 hopper Exp $ */
00022 
00023 // For a log, see ChangeLog
00024 
00025 #ifdef __GNUG__
00026 #  pragma implementation "GraphVizVisitor.h"
00027 #endif
00028 
00029 #include "StrMod/GraphVizVisitor.h"
00030 #include "StrMod/DynamicBuffer.h"
00031 #include <iostream>
00032 #include <iomanip>
00033 #include <cstddef>
00034 #include <cctype>
00035 #include <cstring>
00036 
00037 namespace strmod {
00038 namespace strmod {
00039 
00040 const STR_ClassIdent GraphVizVisitor::identifier(48UL);
00041 
00042 /*!
00043  * @param root The root of the StrChunk DAG to be printed.
00044  *
00045  * @param out The ostream to print the GraphViz parseable tree on.
00046  *
00047  * @return A pointer to a StrChunk containing the data in the DAG flattened
00048  * into a single buffer.
00049  */
00050 const StrChunkPtr GraphVizVisitor::visit(const StrChunkPtr &root, std::ostream &out)
00051 {
00052    StrChunkPtr retval;
00053    static char name = 'A';
00054    if (root)
00055    {
00056       data_ = new DynamicBuffer;
00057       data_->resize(root->Length());
00058       rootpos_ = 0;
00059       edges_.clear();
00060       out_ = &out;
00061       try {
00062           out << "digraph " << (name++) << " {\n";
00063           startVisit(root);
00064           {
00065               const void *dataptr = data_->getVoidP();
00066               out << "n_" << root.GetPtr() << " -> d_" << dataptr << ";\n";
00067               printData(data_->getVoidP(), data_->Length());
00068               out.flush();
00069               assert(data_->Length() == rootpos_);
00070           }
00071           out << "}\n";
00072       }
00073       catch (...) {
00074           // Clean ourselves up if an exception happens.
00075           out_ = NULL;
00076           rootpos_ = 0;
00077           delete data_;
00078           data_ = 0;
00079           edges_.clear();
00080           throw;
00081       }
00082       out_ = NULL;
00083       rootpos_ = 0;
00084       retval = data_;
00085       data_ = 0;
00086       edges_.clear();
00087    }
00088    return(retval);
00089 }
00090 
00091 void GraphVizVisitor::use_visitStrChunk(const StrChunkPtr &chunk,
00092                                         const LinearExtent &used)
00093    throw(halt_visitation)
00094 {
00095    const void *parent = getParent().GetPtr();
00096    if (parent)
00097    {
00098       const void *me = chunk.GetPtr();
00099       const edge_t edge(me, parent);
00100       if (edges_.find(edge) == edges_.end())
00101       {
00102          edges_.insert(edge);
00103          (*out_) << "n_" << parent << " -> n_" << me << ";\n";
00104       }
00105    }
00106 }
00107 
00108 void GraphVizVisitor::use_visitDataBlock(const void *start, size_t len,
00109                                          const void *realstart, size_t reallen)
00110    throw(halt_visitation)
00111 {
00112    const void *parent = getParent().GetPtr();
00113    const void *me = realstart;
00114    const edge_t edge(me, parent);
00115    if (edges_.find(edge) == edges_.end())
00116    {
00117       edges_.insert(edge);
00118       (*out_) << "n_" << parent << " -> d_" << me << ";\n";
00119       printData(realstart, reallen);
00120    }
00121    assert((rootpos_ + len) <= data_->Length());
00122    memcpy(data_->getCharP() + rootpos_, start, len);
00123    rootpos_ += len;
00124 }
00125 
00126 /*!
00127  * Prints out a chunk of data that may contain non-printable characters.  It
00128  * prints out the octal escape sequence for a non-printable character, or a
00129  * '"' character.  It captures '"' characters because those are used to
00130  * delimit strings in GraphViz.
00131  */
00132 void GraphVizVisitor::printData(const void *data, size_t len)
00133 {
00134    (*out_) << "d_" << data << "[shape=box,label=\"";
00135    const unsigned char *tmp = static_cast<const unsigned char *>(data);
00136    for (size_t i = 0; i < len; ++i)
00137    {
00138       if (tmp[i] == '"')
00139       {
00140          (*out_) << "\\042";
00141       }
00142       else if (isprint(tmp[i]))
00143       {
00144          (*out_) << tmp[i];
00145       }
00146       else
00147       {
00148          unsigned int val = tmp[i];
00149          (*out_) << '\\' << std::oct << val;
00150       }
00151    }
00152    (*out_) << "\"];\n";
00153 }
00154 
00155 };  // End namespace strmod
00156 };  // End namespace strmod

Generated on Wed Jan 29 00:32:43 2003 for libNet by doxygen1.3-rc1