Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
DaVinci.h
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */
00037 /* ====================================================================
00038  *
00039  *
00040  * Description:
00041  *      Interface to daVinci.  The DaVinci class, along with its
00042  *      subordinate classes and types, provides a high level model
00043  *      for interactive examination of graph-based data structures.
00044  *      Sufficient sanity checking is done to detect most daVinci
00045  *      usage errors before issuing commands to daVinci.
00046  *      
00047  *      Key concepts and interface functions are described below:
00048  *
00049  *   daVinci  X-Window visualization tool from University of Bremen, Germany.
00050  *            runs as a separate process. Commands are sent to daVinci via
00051  *            a UNIX pipe, replies (ack, events) are returned though another
00052  *            pipe.
00053  *            see  http://www.informatik.uni-bremen.de/~davinci/
00054  *
00055  *   DA_ACK    return type indicating a reply from daVinci.
00056  *             NULL => ok; otherwise an error message (const char *).
00057  *             Assume message is statically allocated and may be overwritten
00058  *             by any subsequence DaVinci member function.
00059  *
00060  *   DaVinci(FILE *trace_fp = NULL)
00061  *      create DaVinci object.  if trace_fp != NULL then all traffic
00062  *      to/from daVinci is logged in indicated file.
00063  *
00064  *   bool Davinci::enabled(bool msg)
00065  *      use environment variable DAVINCIHOME as indication daVinci
00066  *      availability.  return true iff set; if not set and msg is true
00067  *      then issue (at most one) warning.
00068  *
00069  *   void DaVinci::Event_Loop(DaVinci_Callback *cb_hook)
00070  *   void DaVinci::Exit_Event_Loop()
00071  *      respond to actions from daVinci window until exit action taken.
00072  *         daVinci file menu - exit daVinci
00073  *         daVinci edit menu - exit_event_loop
00074  *         in callback function, call exit_event_loop.
00075  *      The first closes the daVinci window while the later two allow
00076  *      the caller to resume w/o closing the DaVinci window.  If the
00077  *      DaVinci object is not destroyed, and the daVinci is not exited,
00078  *      subsequence calls to event_loop() will resume response to actions.
00079  *      see notes on DaVinci_Callback below.
00080  *
00081  *   DA_ACK DaVinci::Title(const char *title)
00082  *   DA_ACK DaVinci::Show_Status(const char *status)
00083  *   DA_ACK DaVinci::Show_Message(const char *msg)
00084  *      Display strings at top, lower left, lower right resp. of window.
00085  *      The daVinci doc. suggests using "message" for transient events
00086  *      such as "file saved" and "status" for ongoing state.  "title"
00087  *      seems like a good place to identify the origin of the DaVinci
00088  *      client.
00089  *
00090  *   struct MENU_INFO
00091  *      for defining submenu under "edit".  suggest that this be done
00092  *      using static initialization.  A menu item may identify a submenu
00093  *      or be itself a leave item.  The initially_active field indicates
00094  *      if the item is accessable on immediately after menu_create().
00095  *               
00096  *   DA_ACK DaVinci::Menu_Create(INT n_items, const MENU_INFO *items)
00097  *      create new menu hierarchy under the daVinci "edit" menu.
00098  *      see MENU_INFO structure.
00099  *
00100  *   DA_ACK DaVinci::Menu_Activate(INT n_ids, const char *ids[])
00101  *   DA_ACK DaVinci::Menu_Deactivate(INT n_ids, const char *ids[])
00102  *      enable/disable sets of menu items.
00103  *   
00104  *   void   DaVinci::Graph_Begin()
00105  *   void   DaVinci::Node_Begin( id, label, node_type )
00106  *   void   DaVinci::Out_Edge( edge_id, edge_type, dest_id )
00107  *   void   DaVinci::Node_End()
00108  *   DA_ACK DaVinci::Graph_End()
00109  *      The above define a graph.  Each node as a unique NODE_ID;
00110  *      each edge a uniq EDGE_ID.
00111  *      Usage:  graph_begin [ node_begin out_edge* node_end ]* graph_end
00112  *      see also: NODE_ID, EDGE_ID, NODE_TYPE, EDGE_TYPE
00113  *
00114  *   DA_ACK DaVinci::Change_Attr( node_id, node_type, new_label = NULL )
00115  *   DA_ACK DaVinci::Change_Attr( edge_id, edge_type )
00116  *      change attributes (color, shape, line-type, etc.) of node/edge.
00117  *
00118  *   void   DaVinci::Update_Begin()
00119  *   void   DaVinci::New_Node( node_id, label, node_type )
00120  *   void   DaVinci::New_Edge( edge_id, edge_type, src, dst )
00121  *   DA_ACK DaVinci::Update_End()
00122  *      add new nodes/edges.  must list all new nodes before any
00123  *      new edges in an update group.  i.e., usage symopsis is:
00124  *         Update_Begin New_Node* New_Edge* Update_End
00125  *
00126  * class DaVinci_Callback
00127  *    virtual void DaVinci_Callback::node_select( n_ids, id_array )
00128  *    virtual void DaVinci_Callback::edge_select( edge_id )
00129  *    virtual void DaVinci_Callback::menu_select( menu_id )
00130  *
00131  *    Response to daVinci events is managented by Callback functions.
00132  *    The DaVinci class client creates a subclass of DaVinci_Callback
00133  *    and redefines the virtual member for events of interest.
00134  *    The Callback subclass object is passed to event_loop().
00135  *   
00136  * ====================================================================
00137  */
00138 
00139 //more: open use MEM_POOL * or keep 'generic' for use outside Mongoose?
00140 
00141 #ifndef DaVinci_INCLUDED
00142 #define DaVinci_INCLUDED
00143 
00144 // Avoid compile errors for STL files
00145 //
00146 #if defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
00147 #undef short
00148 #undef int
00149 #undef long
00150 #endif // defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
00151 
00152 #include <stdio.h>
00153 #include <assert.h>
00154 #include <sys/types.h> 
00155 
00156 
00157 // Solaris CC workaround
00158 #include <stack>
00159 #include <queue>
00160 #include <set>
00161 
00162 #ifndef _USE_STL_EXT
00163 #include <map>
00164 #else
00165 #include <hash_map>
00166 #endif
00167 
00168 using namespace std;
00169 
00170 #include "defs.h"
00171 #include "errors.h"
00172 #include "cxx_memory.h"
00173 
00174 typedef void *NODE_ID;
00175 
00176 struct EDGE_ID {   // if multiple edges add occurence id.
00177   NODE_ID src;
00178   NODE_ID dst;
00179 
00180   EDGE_ID(NODE_ID s, NODE_ID d) : src(s), dst(d) {}
00181 };
00182 
00183 // WARNING: Do _NOT_ delete strings/arrays passed back by Callback
00184 //          functions.  These are allocated/deleted by the DaVinci
00185 //          class in accordance with its lifetime.
00186 
00187 class DaVinci_Callback {
00188 public:
00189   virtual void Node_Select(const INT n_ids, const NODE_ID id_array[]);
00190   virtual void Edge_Select(const EDGE_ID& edge_id);
00191   virtual void Menu_Select(const char *menu_id);
00192 };
00193 
00194 class DaVinci;
00195 
00196 typedef enum {
00197   NS_UNSET,     // default is BOX.
00198   NS_BOX,
00199   NS_CIRCLE,
00200   NS_ELLIPSE,
00201   NS_RHOMBUS,
00202   NS_TEXT
00203   //more NS_ICON
00204 } NODE_SHAPE;
00205 
00206 typedef enum {
00207   NB_UNSET,     // default is SINGLE.
00208   NB_SINGLE,
00209   NB_DOUBLE
00210 } NODE_BORDER;
00211 
00212 typedef enum {
00213   NH_UNSET,      // default is SHOW.
00214   NH_HIDE,
00215   NH_SHOW
00216 } NODE_HIDE;
00217 
00218 class NODE_TYPE {
00219 private:
00220   char         _type_name[20];  // node type name.   "" if unset.
00221   char         _node_color[30]; // attribute: COLOR  "" if unset.
00222   NODE_SHAPE   _node_shape;     // attribute: _GO
00223   NODE_BORDER  _border;         // attribute: BORDER
00224   NODE_HIDE    _hide;           // attribute: HIDDEN
00225   // more: fontfamily,fontstyle,iconfile.
00226 
00227   friend class DaVinci;
00228 public:
00229   NODE_TYPE() {
00230     _type_name[0]  = '\0';
00231     _node_color[0] = '\0';
00232     _node_shape    = NS_UNSET;
00233     _border        = NB_UNSET;
00234     _hide          = NH_UNSET;
00235   }
00236   NODE_TYPE& Name(const char *typ_name);
00237   NODE_TYPE& Color(const char *rgb);
00238   NODE_TYPE& Shape(NODE_SHAPE ns) {
00239     _node_shape = ns; return *this;
00240   }
00241   NODE_TYPE& Boarder(NODE_BORDER nb) {
00242     _border = nb; return *this;
00243   }
00244   NODE_TYPE& Hidden(NODE_HIDE nh) {
00245     _hide = nh; return *this;
00246   }
00247 };
00248 
00249 typedef enum {
00250   EP_UNSET,   // default is SOLID.
00251   EP_SOLID,
00252   EP_DOTTED,
00253   EP_DASHED,
00254   EP_THICK,   // beware: same as a selected edge.
00255   EP_DOUBLE
00256 } EDGE_PATTERN;
00257 
00258 typedef enum {
00259   ED_UNSET,   // default is NORMAL (->).
00260   ED_NORMAL,
00261   ED_INVERSE,
00262   ED_BOTH,
00263   ED_NONE
00264 } EDGE_DIR;
00265 
00266 class EDGE_TYPE {
00267 private:
00268   char         _type_name[20];    // edge type name.         "" if unset.
00269   char         _edge_color[30];   // attribute: EDGECOLOR    "" if unset.
00270   EDGE_PATTERN _edge_pattern;     // attribute: EDGEPATTERN
00271   EDGE_DIR     _edge_dir;         // attribute: _DIR
00272 
00273   friend class DaVinci;
00274 public:
00275   EDGE_TYPE() {
00276     _type_name[0]  = '\0';
00277     _edge_color[0] = '\0';
00278     _edge_pattern  = EP_UNSET;
00279     _edge_dir      = ED_UNSET;
00280   }
00281   EDGE_TYPE& Name(const char *typ_name);
00282   EDGE_TYPE& Color(const char *rgb);
00283   EDGE_TYPE& Pattern(EDGE_PATTERN pat) { _edge_pattern = pat; return *this; }
00284   EDGE_TYPE& Direction(EDGE_DIR dir)   { _edge_dir     = dir; return *this; }
00285 };
00286 
00287 struct MENU_INFO {
00288   char      *id;                // id from/to DaVinci.
00289   char      *label;             // displayed by DaVinci.
00290   bool       initially_active;  // active on startup ?
00291   INT        n_subitems;        // 0 => this is a leaf item.
00292   MENU_INFO *subitems;          // NULL => this is leaf item.
00293 };
00294 
00295 typedef enum {
00296   EK_COM_ERROR,
00297   EK_OK,
00298   EK_SEL_EDGE,
00299   EK_SEL_MENU,
00300   EK_SEL_NODES,
00301   EK_QUIT           // DaVinci exiting.
00302      // more: many more event kinds ..
00303 } EVENT_KIND;
00304 
00305 
00306 struct EVENT_T {       //more? full OO-style - queue ptrs, use class heir ..
00307   EVENT_KIND  kind;
00308   union {
00309     struct {
00310       const char *msg;   // ptr into static buffer.
00311     } com_error;
00312 
00313     struct {
00314       NODE_ID edge_src;
00315       NODE_ID edge_dst;
00316     } sel_edge;
00317 
00318     struct {
00319       const char *label;  // always a heap object.
00320     } sel_menu;
00321 
00322     struct {
00323       INT      n_nodes;
00324       NODE_ID *node_ids;
00325     } sel_nodes;
00326   } u;
00327 };
00328 
00329 struct Equal_obj {
00330   bool operator()(const char* s1, const char* s2) const {
00331     return strcmp(s1, s2) == 0;
00332   }
00333 };
00334 
00335 typedef enum {
00336   DM_ACTIVE,    // want menu item turned on.
00337   DM_INACTIVE,  // want menu item turned on.
00338   DM_UNKNOWN    // entry from menu select (using map domain as string pool).
00339 } Item_status;
00340 
00341 
00342 // Solaris CC workaround
00343 // replace hash_map with map
00344 #ifndef _USE_STL_EXT
00345 struct char_ss_compare {
00346     bool operator() (const char* s1, const char* s2) const
00347     {
00348         return strcmp(s1, s2) < 0;
00349     }
00350 };
00351 typedef map < const char *, Item_status, char_ss_compare > Item_info;
00352 
00353 #else
00354 typedef hash_map< const char *, Item_status,
00355                   hash<const char *>, Equal_obj > Item_info;
00356 #endif
00357 
00358 class Menu_info {
00359 private:
00360   MEM_POOL *_m;
00361 public:
00362   Item_info items;
00363 
00364   Menu_info(MEM_POOL *m) :  _m(m) {}  // alloc to pool; free with pool.
00365   ~Menu_info() {}
00366   void operator=(Menu_info&); // don't define.
00367   Menu_info(Menu_info&);      // don't define.
00368 
00369   const char *Add(const char *cp); // use items maps domain as string pool.
00370   void        Set(const char *cp, Item_status status);
00371 };
00372 
00373 typedef const char *DA_ACK;  // NULL => ok, otherwise error string.
00374 
00375 class DaVinci {
00376 private:
00377   class IO {
00378   private:
00379     FILE  *_to_fp;
00380     FILE  *_from_fp;
00381     FILE  *_trace_fp;
00382     bool   _trace_tagged;
00383   public:
00384     IO() {
00385       _to_fp = _from_fp = _trace_fp = NULL;
00386       _trace_tagged = false;
00387     }
00388     void Trace(FILE *tfp) { _trace_fp = tfp; }
00389     ~IO();
00390 
00391     void Init(FILE *to, FILE *from) {
00392       _to_fp   = to;
00393       _from_fp = from;
00394     }
00395     void  Close();
00396     void  Out_Fmt(const char *fmt, ...);
00397     char *In_Line();               // sync read; NULL => EOF.
00398   };
00399   typedef UINT32 FTAG;
00400   typedef FTAG   FTAGS;
00401 
00402   IO              _io;
00403   MEM_POOL       *_m;
00404 
00405   queue<EVENT_T>  _event_q;
00406 
00407   set<NODE_ID>    _node_def_set;  // used iff _usage_check == true.
00408   set<NODE_ID>    _node_ref_set;  // used iff _usage_check == true.
00409   Menu_info       _menu_state;
00410   bool            _basic_menu_added;
00411   bool            _in_event_loop;
00412   bool            _display_ok;
00413   bool            _usage_check;
00414   FTAG            _ftag_last;
00415   INT             _node_cnt;
00416   INT             _edge_cnt;
00417   pid_t           _pid;
00418 
00419   const char *Ft_Str(const FTAG ftag);
00420   void        Usage_Error(FTAG curr, FTAGS prereq);
00421 
00422   bool Usage_Ok(FTAG curr, FTAGS prereq) {
00423     if ( _display_ok && (prereq == 0 || (_ftag_last & prereq)) ) {
00424       _ftag_last = curr;
00425       return true;
00426     }
00427     Usage_Error(curr, prereq);
00428     return false;
00429   }
00430   DA_ACK Wait_For_Ack();
00431 
00432   DA_ACK Emit_Ack(const char *line) {
00433     assert( strchr( line, '\n' ) == NULL );
00434     _io.Out_Fmt( line );
00435     _io.Out_Fmt( "\n" );
00436     return Wait_For_Ack();
00437   }
00438   void Emit_Do(const char *line) {
00439     DA_ACK msg = Emit_Ack( line );
00440     if ( msg ) {
00441       fprintf(stderr, "Unexpected DaVinci error: %s\n", msg);
00442     }
00443   }
00444   const char *Parse_Menu_Label(const char *epfx);
00445   bool        Parse_Event(const char *line, EVENT_T *event);
00446   bool        Parse_Node_Ids(const char *epfx,
00447                              INT *n_nodes, NODE_ID **node_ids);
00448 
00449   void Emit_Menu(INT n_items, const MENU_INFO *items);
00450   void Emit_Attr(const NODE_TYPE& nt, char **comma);
00451   void Emit_Attr(const EDGE_TYPE& et);
00452 
00453   void   Menu_Basic_Do( const char *label );
00454   DA_ACK Menu_Set_Active();
00455 
00456   void Kill_Davinci();
00457 public:
00458   static bool enabled(bool msg) {
00459     bool is_enabled = ( getenv("DAVINCIHOME") != NULL );
00460     if ( ! is_enabled ) {
00461       static bool msg_given = false;
00462       if ( ! msg_given ) {
00463         DevWarn("daVinci not enabled; %s\n",
00464                 "must set DAVINCIHOME and put daVinci on path.");
00465         msg_given = true;
00466       }
00467     }
00468     return is_enabled;
00469   }
00470 
00471   DaVinci(MEM_POOL *m, FILE *trace_fp = NULL, bool usage_check = false);
00472   ~DaVinci();
00473 
00474   bool is_ok() const { return _display_ok; }
00475 
00476   DaVinci(const DaVinci&);        // don't allow/define.
00477   void operator=(const DaVinci&); // don't allow/define.
00478 
00479   void Event_Loop(DaVinci_Callback *cb_hook);
00480   void Exit_Event_Loop();
00481 
00482   DA_ACK Title(const char *title);        // on top.
00483   DA_ACK Show_Status(const char *status); // lower right.
00484   DA_ACK Show_Message(const char *msg);   // lower left (for transient msg).
00485 
00486   DA_ACK Menu_Create(INT n_items, const MENU_INFO *items);
00487   DA_ACK Menu_Activate(INT n_ids, const char *ids[]);
00488   DA_ACK Menu_Deactivate(INT n_ids, const char *ids[]);
00489 
00490   void   Graph_Begin();
00491   void   Node_Begin(NODE_ID id, const char *label, const NODE_TYPE& node_type);
00492   void   Out_Edge(const EDGE_ID&   edge_id,
00493                   const EDGE_TYPE& edge_type,
00494                   const NODE_ID    dest_id);
00495   void   Node_End();
00496   DA_ACK Graph_End();
00497 
00498   DA_ACK Change_Attr(const NODE_ID     node_id,
00499                      const NODE_TYPE&  nt,
00500                      const char       *new_label = NULL);
00501 
00502   DA_ACK Change_Attr(const EDGE_ID& edge_id, const EDGE_TYPE& et);
00503 
00504   void Update_Begin();  // all new_node() must preceed first new_edge().
00505   void New_Node(NODE_ID id, const char *label, const NODE_TYPE& nt );
00506   void New_Edge(const EDGE_ID& id, const EDGE_TYPE& et,
00507                 NODE_ID src, NODE_ID dst);
00508   DA_ACK Update_End();
00509 };
00510 
00511 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines