00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 #include <sys/socket.h>
00059 #include <arpa/inet.h>
00060 #include <stdio.h>
00061
00062 #include <sys/types.h>
00063 #include <unistd.h>
00064 #include <signal.h>
00065 #ifndef __MINGW32__
00066 #if defined(BUILD_OS_DARWIN) || defined(__CYGWIN__) || defined(__APPLE__)
00067 #include <sys/wait.h>
00068 #else
00069 #include <wait.h>
00070 #endif
00071 #endif
00072 #include <stdarg.h>
00073 #include <time.h>
00074 #include <string.h>
00075 #include <errno.h>
00076
00077 #include "DaVinci.h"
00078
00079 #define MAX_MENU_LABEL_LEN 100
00080
00081 #define CALLBACK_DEBUG
00082
00083 std::queue<EVENT_T> DaVinci::_event_q_socket[MAX_VIEW_NUM];
00084 INT DaVinci::_tcp_socket = 0;
00085 INT DaVinci::_davinci_count =0;
00086 INT DaVinci::_contex_count = 0;
00087 CONTEX_TYPE DaVinci::_contex_use_array[MAX_VIEW_NUM];
00088 INT DaVinci::_current_contex = -1;
00089 bool DaVinci::_use_socket = false;
00090
00091
00092
00093
00094
00095
00096 void
00097 DaVinci_Callback::Node_Select(const INT n_ids, const NODE_ID id_array[])
00098 {
00099 #ifdef CALLBACK_DEBUG
00100 fprintf(stderr, "Node_Select([");
00101 const char *sep = " ";
00102 for (INT i = 0; i < n_ids; ++i) {
00103 fprintf(stderr, "%s%p", sep, id_array[i]);
00104 sep = ", ";
00105 }
00106 fprintf(stderr, " ])\n");
00107 #endif
00108 }
00109
00110 void
00111 DaVinci_Callback::Edge_Select(const EDGE_ID& id)
00112 {
00113 #ifdef CALLBACK_DEBUG
00114 fprintf(stderr, "Edge_Select(%p,%p)\n", id.src, id.dst);
00115 #endif
00116 }
00117
00118 void
00119 DaVinci_Callback::Menu_Select(const char *menu_id)
00120 {
00121 #ifdef CALLBACK_DEBUG
00122 fprintf(stderr, "Menu_Select(%s)\n", menu_id);
00123 #endif
00124 }
00125
00126
00127
00128
00129
00130 NODE_TYPE&
00131 NODE_TYPE::Name(const char *typ_name)
00132 {
00133 if ( typ_name ) {
00134 strncpy(_type_name, typ_name, sizeof(_type_name) - 1);
00135 }
00136
00137
00138 return *this;
00139 }
00140
00141 NODE_TYPE&
00142 NODE_TYPE::Color(const char *rgb)
00143 {
00144 strncpy(_node_color, rgb, sizeof(_node_color) - 1);
00145
00146 return *this;
00147 }
00148
00149 EDGE_TYPE&
00150 EDGE_TYPE::Name(const char *typ_name)
00151 {
00152 if ( typ_name ) {
00153 strncpy(_type_name, typ_name, sizeof(_type_name) - 1);
00154 }
00155
00156
00157 return *this;
00158 }
00159
00160
00161 EDGE_TYPE&
00162 EDGE_TYPE::Color(const char *rgb)
00163 {
00164 strncpy(_edge_color, rgb, sizeof(_edge_color) - 1);
00165
00166 return *this;
00167 }
00168
00169
00170
00171
00172
00173
00174 const char *
00175 Menu_info::Add(const char *cp)
00176 {
00177 Item_info::iterator it = items.find( cp );
00178
00179 if ( cp == NULL ) return NULL;
00180
00181 if ( it != items.end() ) {
00182 return (*it).first;
00183 } else {
00184 char *buf = CXX_NEW_ARRAY(char, strlen(cp)+1, _m);
00185 const char *cpy = strcpy( buf, cp );
00186 items[ cpy ] = DM_UNKNOWN;
00187 return cpy;
00188 }
00189 }
00190
00191 void
00192 Menu_info::Set(const char *cp, Item_status status)
00193 {
00194 if ( cp ) {
00195 if ( items.find( cp ) == items.end() ) {
00196 char *buf = CXX_NEW_ARRAY(char, strlen(cp)+1, _m);
00197 cp = strcpy( buf, cp );
00198 }
00199 items[ cp ] = status;
00200 }
00201 }
00202
00203
00204
00205
00206
00207 DaVinci::IO::~IO()
00208 {
00209 if(!_use_socket || _davinci_count==0) Close ();
00210 }
00211
00212 void
00213 DaVinci::IO::Close()
00214 {
00215 if ( _to_fp ) (void)fclose( _to_fp );
00216 if ( _from_fp ) (void)fclose( _from_fp );
00217 }
00218
00219 void
00220 DaVinci::IO::Out_Fmt(const char *fmt, ...)
00221 {
00222 if ( _to_fp == NULL ) {
00223 fprintf(stderr, "DaVinci::IO::Out_Fmt _to_fp not set!\n");
00224 return;
00225 }
00226 va_list ap;
00227 va_start(ap, fmt);
00228
00229 vfprintf(_to_fp, fmt, ap);
00230
00231 if ( _trace_fp ) {
00232 if ( ! _trace_tagged ) {
00233 fprintf(_trace_fp, "TO-DAVINCI: ");
00234 _trace_tagged = true;
00235 }
00236 vfprintf(_trace_fp, fmt, ap);
00237
00238 if ( strchr( fmt, '\n' ) ) {
00239 _trace_tagged = false;
00240 }
00241 fflush(_trace_fp);
00242 }
00243
00244 va_end(ap);
00245 }
00246
00247 char *
00248 DaVinci::IO::In_Line()
00249 {
00250 static char buf[10000];
00251
00252 if ( _from_fp == NULL ) {
00253 fprintf(stderr, "DaVinci::IO::Out_Fmt _from_fp not set!\n");
00254 return NULL;
00255 }
00256 char *rp = fgets( buf, sizeof(buf), _from_fp );
00257
00258 if ( rp ) {
00259 char *np = strchr( rp, '\n' );
00260 if ( np ) {
00261 *np = '\0';
00262 } else {
00263 fprintf(stderr, "in_line truncation! (%.50s ..)\n", buf);
00264 }
00265 if(_use_socket){
00266 np = strchr( rp, '\r' );
00267 if ( np ) {
00268 *np = '\0';
00269 }
00270 }
00271
00272 if (strlen(rp) >= sizeof(buf) ) {
00273 fprintf(stderr, "INTERNAL ERROR! DaVinci::IO:in_line buf overflow\n");
00274 abort();
00275 }
00276 }
00277 if ( _trace_fp && rp ) {
00278 fprintf(_trace_fp, "FROM-DAVINCI: %s\n", buf);
00279 fflush(_trace_fp);
00280
00281 _trace_tagged = false;
00282 }
00283 return rp;
00284 }
00285
00286
00287
00288
00289
00290 #define FT_DAVINCI FTAG(1 << 0)
00291 #define FT_TITLE FTAG(1 << 1)
00292 #define FT_SHOW_STATUS FTAG(1 << 2)
00293 #define FT_SHOW_MESSAGE FTAG(1 << 3)
00294 #define FT_MENU_CREATE FTAG(1 << 4)
00295 #define FT_MENU_ACTIVATE FTAG(1 << 5)
00296 #define FT_MENU_DEACTIVATE FTAG(1 << 6)
00297 #define FT_GRAPH_BEGIN FTAG(1 << 7)
00298 #define FT_NODE_BEGIN FTAG(1 << 8)
00299 #define FT_OUT_EDGE FTAG(1 << 9)
00300 #define FT_NODE_END FTAG(1 << 10)
00301 #define FT_GRAPH_END FTAG(1 << 11)
00302 #define FT_CHANGE_ATTR FTAG(1 << 12)
00303 #define FT_UPDATE_BEGIN FTAG(1 << 13)
00304 #define FT_NEW_NODE FTAG(1 << 14)
00305 #define FT_NEW_EDGE FTAG(1 << 15)
00306 #define FT_DELETE_EDGE FTAG(1 << 16)
00307 #define FT_UPDATE_END FTAG(1 << 17)
00308
00309 #define BASE_SET ( \
00310 FT_DAVINCI | FT_TITLE | FT_SHOW_STATUS | FT_SHOW_MESSAGE \
00311 | FT_MENU_CREATE | FT_MENU_ACTIVATE | FT_MENU_DEACTIVATE \
00312 | FT_GRAPH_END | FT_CHANGE_ATTR | FT_UPDATE_END \
00313 )
00314
00315 const char *
00316 DaVinci::Ft_Str(const FTAG ftag)
00317 {
00318 const char *s = "<<ft_str: unknown tag>>";
00319
00320 switch ( ftag ) {
00321 case FT_DAVINCI: s = "DaVinci"; break;
00322 case FT_TITLE: s = "title"; break;
00323 case FT_SHOW_STATUS: s = "show_status"; break;
00324 case FT_SHOW_MESSAGE: s = "show_message"; break;
00325 case FT_MENU_CREATE: s = "menu_create"; break;
00326 case FT_MENU_ACTIVATE: s = "menu_activate"; break;
00327 case FT_MENU_DEACTIVATE: s = "menu_deactivate"; break;
00328 case FT_GRAPH_BEGIN: s = "graph_begin"; break;
00329 case FT_NODE_BEGIN: s = "node_begin"; break;
00330 case FT_OUT_EDGE: s = "out_edge"; break;
00331 case FT_NODE_END: s = "node_end"; break;
00332 case FT_GRAPH_END: s = "graph_end"; break;
00333 case FT_CHANGE_ATTR: s = "change_attr"; break;
00334 case FT_UPDATE_BEGIN: s = "update_begin"; break;
00335 case FT_NEW_NODE: s = "new_node"; break;
00336 case FT_NEW_EDGE: s = "new_edge"; break;
00337 case FT_UPDATE_END: s = "update_end"; break;
00338 default:
00339 ;
00340 }
00341 return s;
00342 }
00343
00344 void
00345 DaVinci::Usage_Error(FTAG curr, FTAGS prereq)
00346 {
00347 fprintf(stderr, "Error while Calling DaVinci::%s - ", Ft_Str(curr));
00348
00349 if ( ! _display_ok ) {
00350 fprintf(stderr, "DaVinci display not ok\n");
00351 } else {
00352 fprintf(stderr, "preceeding %s expected member of {", Ft_Str(_ftag_last));
00353 FTAGS fts = prereq;
00354 const char *comma = "";
00355 for (FTAGS ft = FT_DAVINCI; fts != 0; ft <<= 1) {
00356 if ( ft & fts ) {
00357 fprintf(stderr, "%s %s", comma, Ft_Str(ft));
00358 comma = ",";
00359 fts ^= ft;
00360 }
00361 }
00362 fprintf(stderr, " }\n");
00363 }
00364 }
00365
00366 DA_ACK
00367 DaVinci::Wait_For_Ack()
00368 {
00369 EVENT_T event;
00370 char *line;
00371
00372
00373
00374
00375
00376
00377
00378
00379 while ( (line = _io.In_Line()) != NULL ) {
00380 if(_use_socket){
00381 if(line[0] == 'c' && line[1] == 'o' && line[2] == 'n' && line[3] == 't'
00382 && line[4] == 'e' && line[5] == 'x' && line[6] == 't'){
00383 if(line[9] >='0' && line[9] <= '9'){
00384 sscanf(line, "context(\"%d\")", &_current_contex);
00385 }
00386 continue;
00387 }
00388 }
00389 if ( Parse_Event( line, &event ) ) {
00390 switch ( event.kind ) {
00391 case EK_OK:
00392 return NULL;
00393 case EK_COM_ERROR:
00394 return event.u.com_error.msg;
00395 default:
00396 if(_use_socket){
00397 _event_q_socket[_current_contex].push( event );
00398 }else{
00399 _event_q.push( event );
00400 }
00401 }
00402 }
00403 }
00404 _display_ok = false;
00405
00406 return "Unexpected EOF from DaVinci";
00407 }
00408
00409 bool
00410 DaVinci::Parse_Node_Ids(const char *epfx, INT *n_nodes, NODE_ID **node_ids)
00411 {
00412 INT n_alloc = 5;
00413 NODE_ID *ids = CXX_NEW_ARRAY(NODE_ID, n_alloc, _m);
00414 INT cnt = 0;
00415 const char *cp = epfx;
00416 const char *sp;
00417 NODE_ID id;
00418
00419
00420
00421
00422
00423
00424 if ( cp[0] != '(' || cp[1] != '[' ) {
00425 fprintf(stderr, "BAD NODE_ID list (lp): %s\n", epfx);
00426 return false;
00427 }
00428 cp += 2;
00429
00430 while ( *cp != ']' ) {
00431 sp = strchr( cp, ',' );
00432 if ( sp == NULL ) {
00433 sp = strchr( cp, ']' );
00434 if ( sp == NULL ) {
00435 fprintf(stderr, "BAD NODE_ID list (sep): %s\n", epfx);
00436 return false;
00437 }
00438 }
00439 if ( sscanf( cp, "\"%p\"", &id ) != 1 ) {
00440 fprintf(stderr, "BAD NODE_ID (id): .. %s\n", cp);
00441 return false;
00442 }
00443 if ( cnt >= n_alloc ) {
00444 n_alloc = cnt + 10;
00445 NODE_ID *nids = CXX_NEW_ARRAY(NODE_ID, n_alloc, _m);
00446 for (INT i = 0; i < cnt; ++i) {
00447 nids[i] = ids[i];
00448 }
00449 ids = nids;
00450 }
00451 ids[ cnt++ ] = id;
00452
00453 cp = ( *sp == ',' ? sp + 1 : sp );
00454 }
00455 *n_nodes = cnt;
00456 *node_ids = ids;
00457
00458 return true;
00459 }
00460
00461 bool
00462 Parse_Edge_Id( const char *epfx, EVENT_T *event )
00463 {
00464 if ( sscanf(epfx, "(\"%p:%p\")",
00465 &event->u.sel_edge.edge_src,
00466 &event->u.sel_edge.edge_dst) != 2 ) {
00467 fprintf(stderr, "Malformed EDGE_ID %s\n", epfx);
00468 return false;
00469 }
00470 return true;
00471 }
00472
00473 const char *
00474 DaVinci::Parse_Menu_Label( const char *epfx )
00475 {
00476 char label[MAX_MENU_LABEL_LEN];
00477 INT len = strlen( epfx );
00478
00479 if ( epfx[0] != '('
00480 || epfx[1] != '"'
00481 || epfx[len - 2] != '"'
00482 || epfx[len - 1] != ')' ) {
00483 fprintf(stderr, "parse_menu_label: not wrapped as expected\n");
00484 return NULL;
00485 }
00486 strncpy( label, epfx + 2, len - 4 );
00487 label[ len - 4 ] = '\0';
00488
00489
00490
00491
00492 return _menu_state.Add( label );
00493 }
00494
00495 static struct {
00496 const char *name;
00497 EVENT_KIND kind;
00498 } Event_Tbl[] = {
00499 { "close", EK_CLOSE },
00500 { "communication_error", EK_COM_ERROR },
00501 { "disconnect", EK_DISCONNECT},
00502 { "edge_selection_label", EK_SEL_EDGE },
00503 { "menu_selection", EK_SEL_MENU },
00504 { "node_selections_labels", EK_SEL_NODES },
00505 { "ok", EK_OK },
00506 { "quit", EK_QUIT }
00507 };
00508 #define N_EVENT ( sizeof(Event_Tbl) / sizeof(Event_Tbl[0]) )
00509
00510 bool
00511 DaVinci::Parse_Event(const char *line, EVENT_T *event)
00512 {
00513 char *epfx;
00514
00515 epfx = strchr( line, '(' );
00516 if ( epfx == NULL ) {
00517 epfx = strchr( line, '\0' );
00518 }
00519 INT nchr = epfx - line;
00520 INT lo = 0;
00521 INT hi = N_EVENT - 1;
00522 INT mid;
00523 INT cmp;
00524
00525 while ( lo <= hi ) {
00526 mid = ( lo + hi ) / 2;
00527 cmp = strncmp( Event_Tbl[ mid ].name, line, nchr );
00528 if ( cmp == 0 ) break;
00529 if ( cmp < 0 ) {
00530 lo = mid + 1;
00531 } else {
00532 hi = mid - 1;
00533 }
00534 }
00535 if ( cmp != 0 ) {
00536 #ifndef REPORT_FONT_WARNINGS
00537 if ( strncmp(line, "Font ", 5) == 0 ) {
00538 return false;
00539 }
00540 #endif
00541 fprintf(stderr, "DaVinci::Parse_Event UNKNOWN: %s\n", line);
00542 return false;
00543 }
00544 event->kind = Event_Tbl[ mid ].kind;
00545
00546 switch ( event->kind ) {
00547 case EK_COM_ERROR:
00548 event->u.com_error.msg = line;
00549 break;
00550 case EK_QUIT:
00551 case EK_OK:
00552 case EK_CLOSE:
00553 case EK_DISCONNECT:
00554
00555 break;
00556 case EK_SEL_EDGE:
00557 if ( ! Parse_Edge_Id( epfx, event ) ) {
00558 return false;
00559 }
00560 break;
00561 case EK_SEL_MENU:
00562 {
00563 const char *ss = Parse_Menu_Label( epfx );
00564 if ( ss == NULL ) return false;
00565 event->u.sel_menu.label = ss;
00566 }
00567 break;
00568 case EK_SEL_NODES:
00569 if ( ! Parse_Node_Ids( epfx, &event->u.sel_nodes.n_nodes,
00570 &event->u.sel_nodes.node_ids ) ) {
00571 return false;
00572 }
00573 break;
00574 default:
00575 fprintf(stderr, "INTERNAL ERROR: missing event case %d\n", event->kind);
00576 return false;
00577 }
00578 return true;
00579 }
00580
00581 void
00582 DaVinci::Emit_Menu(INT n_items, const MENU_INFO *items)
00583 {
00584 for (INT i = 0; i < n_items; ++i) {
00585 if ( items[i].subitems && items[i].n_subitems > 0 ) {
00586 _io.Out_Fmt( "submenu_entry(\"%s\", \"%s\",[",
00587 items[i].id, items[i].label);
00588 Emit_Menu( items[i].n_subitems, items[i].subitems );
00589 _io.Out_Fmt( "])" );
00590 } else {
00591 _io.Out_Fmt( "menu_entry(\"%s\", \"%s\")",
00592 items[i].id, items[i].label);
00593 }
00594 if ( i < n_items - 1 ) _io.Out_Fmt( "," );
00595
00596 _menu_state.Set( items[i].id,
00597 (items[i].initially_active ? DM_ACTIVE : DM_INACTIVE));
00598 }
00599 }
00600
00601 void
00602 DaVinci::Emit_Attr(const NODE_TYPE& nt, const char **comma)
00603 {
00604 const char *val = NULL;
00605
00606 if ( nt._node_color[0] != '\0' ) {
00607 _io.Out_Fmt( ",a(\"COLOR\",\"%s\")", nt._node_color);
00608 }
00609
00610 switch ( nt._node_shape ) {
00611 case NS_UNSET: val = NULL; break;
00612 case NS_BOX: val = "box"; break;
00613 case NS_CIRCLE: val = "circle"; break;
00614 case NS_ELLIPSE: val = "ellipse"; break;
00615 case NS_RHOMBUS: val = "rhombus"; break;
00616 case NS_TEXT: val = "text"; break;
00617 default:
00618 fprintf(stderr, "DaVinci::emit_attr/node unexpected shape %d\n",
00619 nt._node_shape);
00620 }
00621 if ( val) {
00622 _io.Out_Fmt( "%sa(\"_GO\",\"%s\")", *comma, val);
00623 *comma = ",";
00624 }
00625
00626 switch ( nt._border ) {
00627 case NB_UNSET: val = NULL; break;
00628 case NB_SINGLE: val = "single"; break;
00629 case NB_DOUBLE: val = "double"; break;
00630 default:
00631 fprintf(stderr, "DaVinci:emit_attr/node unexpected border type %d\n",
00632 nt._border);
00633 }
00634 if ( val ) {
00635 _io.Out_Fmt( "%sa(\"BORDER\",\"%s\")", *comma, val);
00636 *comma = ",";
00637 }
00638
00639 switch ( nt._hide ) {
00640 case NH_UNSET: val = NULL; break;
00641 case NH_HIDE: val = "true"; break;
00642 case NH_SHOW: val = "false"; break;
00643 default:
00644 fprintf(stderr, "DaVinci:emit_attr/node unexpected hide/show value %d\n",
00645 nt._hide);
00646 }
00647 if ( val ) {
00648 _io.Out_Fmt( "%sa(\"HIDDEN\",\"%s\")", *comma, val);
00649 *comma = ",";
00650 }
00651 }
00652
00653 void
00654 DaVinci::Emit_Attr(const EDGE_TYPE& et)
00655 {
00656
00657 const char *val = NULL;
00658 const char *comma = "";
00659
00660 if ( et._edge_color[0] != '\0' ) {
00661 _io.Out_Fmt( "a(\"EDGECOLOR\",\"%s\")", et._edge_color );
00662 comma = ",";
00663 }
00664
00665 switch ( et._edge_pattern ) {
00666 case EP_UNSET: val = NULL; break;
00667 case EP_SOLID: val = "solid"; break;
00668 case EP_DOTTED: val = "dotted"; break;
00669 case EP_DASHED: val = "dashed"; break;
00670 case EP_THICK: val = "thick"; break;
00671 case EP_DOUBLE: val = "double"; break;
00672 default:
00673 fprintf(stderr, "DaVinci::emit_attr/edge unexpected edge pattern %d\n",
00674 et._edge_pattern);
00675 }
00676 if ( val ) {
00677 _io.Out_Fmt( "%sa(\"EDGEPATTERN\",\"%s\")", comma, val );
00678 comma = ",";
00679 }
00680
00681 switch ( et._edge_dir ) {
00682 case ED_UNSET: val = NULL; break;
00683 case ED_NORMAL: val = "normal"; break;
00684 case ED_INVERSE: val = "inverse"; break;
00685 case ED_BOTH: val = "both"; break;
00686 case ED_NONE: val = "none"; break;
00687 }
00688 if ( val ) {
00689 _io.Out_Fmt( "%sa(\"_DIR\",\"%s\")", comma, val );
00690 comma = ",";
00691 }
00692 }
00693
00694 void
00695 DaVinci::Menu_Basic_Do( const char *label )
00696 {
00697 if ( strcmp( label, "exit_event_loop" ) == 0 ) {
00698 if(_use_socket){
00699 char s[100];
00700 sprintf(s, "multi(set_context(\"%d\"))", _contex);
00701 Emit_Do(s);
00702 _io.Out_Fmt( "menu(file(close))");
00703 _io.Out_Fmt( "\n" );
00704 }else{
00705 Exit_Event_Loop();
00706 }
00707 }
00708 }
00709
00710 DA_ACK
00711 DaVinci::Menu_Set_Active()
00712 {
00713 bool first = true;
00714
00715 _io.Out_Fmt( "app_menu(activate_menus([" );
00716 for (Item_info::iterator m_iter = _menu_state.items.begin();
00717 m_iter != _menu_state.items.end(); ++m_iter) {
00718 if ( (*m_iter).second == DM_ACTIVE) {
00719 const char *menu_id = (*m_iter).first;
00720 _io.Out_Fmt( "%s\"%s\"", (first ? "" : ","), menu_id );
00721 first = false;
00722 }
00723 }
00724 _io.Out_Fmt( "]))\n" );
00725
00726 return Wait_For_Ack();
00727 }
00728
00729 void
00730 DaVinci::Kill_Davinci()
00731 {
00732 INT stat;
00733
00734 _display_ok = false;
00735 #ifndef __MINGW32__
00736 kill (_pid, SIGINT);
00737 waitpid (_pid, &stat, WNOHANG);
00738
00739 #endif
00740 _io.Close();
00741 }
00742
00743
00744
00745
00746 DaVinci::DaVinci(MEM_POOL *m, FILE *_trace_fp, bool usage_check) :
00747 _menu_state(m)
00748 {
00749 #ifndef __MINGW32__
00750 _m = m;
00751 _basic_menu_added = false;
00752 _in_event_loop = false;
00753 _display_ok = false;
00754 _usage_check = usage_check;
00755 _ftag_last = FT_DAVINCI;
00756 _node_cnt = 0;
00757 _edge_cnt = 0;
00758 FILE *from_display;
00759 FILE *to_display;
00760
00761 if(_use_socket){
00762 _davinci_count++;
00763
00764 if(_davinci_count == 1){
00765 for(int i =0; i < MAX_VIEW_NUM; i++) {
00766 _contex_use_array[i] = CONTEX_UNUSE;
00767 }
00768 struct sockaddr_in addr_server;
00769
00770 _tcp_socket = socket(PF_INET, SOCK_STREAM, 0);
00771 if (_tcp_socket < 0) {
00772 perror( "DaVinci" );
00773 return;
00774 }
00775
00776
00777 addr_server.sin_family = AF_INET;
00778
00779
00780
00781 addr_server.sin_port = htons(2542);
00782
00783
00784
00785 FILE *ip_fp;
00786 char ip_address[100];
00787 if(!(ip_fp = fopen(getenv("UDRAWIP"), "r"))){
00788 fprintf(stderr, "Can't get the ip address of DaVinci server!\n");
00789 perror( "DaVinci" );
00790 return;
00791 }
00792 fscanf(ip_fp, "%s", ip_address);
00793 addr_server.sin_addr.s_addr = inet_addr(ip_address);
00794 bzero(&(addr_server.sin_zero),8);
00795
00796 if (connect(_tcp_socket, (struct sockaddr *)&addr_server, sizeof(addr_server)) < 0)
00797 {
00798 fprintf(stderr, "Can't connect to %s:2542, please start using this commandline:\n"
00799 "uDrawGraph -server\n", ip_address);
00800 perror( "DaVinci" );
00801 return;
00802 }
00803
00804 }
00805 from_display = fdopen(_tcp_socket, "r");
00806 to_display = fdopen(_tcp_socket, "w");
00807 char *tracefile = getenv("UDRAW_TRACEFILE");
00808
00809 setbuf(from_display, NULL);
00810 setbuf(to_display, NULL);
00811 _io.Init( to_display, from_display );
00812 if(_trace_fp == NULL && tracefile){
00813 _trace_fp = fopen(tracefile, "a");
00814 }
00815 _io.Trace( _trace_fp );
00816 if(_davinci_count == 1){
00817 DA_ACK msg = Wait_For_Ack();
00818 if ( msg ) {
00819 fprintf(stderr, "DaVinci connection failed: %s\n", msg);
00820 return;
00821 }
00822 }
00823
00824 _display_ok = true;
00825
00826 INT i;
00827 for( i = 0; i < MAX_VIEW_NUM; i++){
00828 if(_contex_use_array[i] == CONTEX_UNUSE){
00829 char s[100];
00830 sprintf(s, "multi(open_context(\"%d\"))", i);
00831 Emit_Do( s);
00832 _contex_use_array[i] = CONTEX_ACTIVE;
00833 _contex_count++;
00834 _contex = i;
00835 break;
00836 }
00837 }
00838 if(i == MAX_VIEW_NUM) {
00839 fprintf(stderr, "DaVinci:reach the max view size");
00840 }
00841 }else{
00842 INT read_pipe[2];
00843 INT write_pipe[2];
00844
00845 if ( pipe( read_pipe ) == -1 || pipe(write_pipe) == -1 ) {
00846 perror( "DaVinci" );
00847 return;
00848 }
00849 from_display = fdopen(read_pipe[0], "r");
00850 to_display = fdopen(write_pipe[1], "w");
00851 char *logfile = getenv("DAVINCI_LOGFILE");
00852
00853 setbuf(from_display, NULL);
00854 setbuf(to_display, NULL);
00855
00856 switch ( _pid = fork() ) {
00857 case -1:
00858 fprintf(stderr, "Unable to fork (for daVinci)\n");
00859 close (read_pipe[0]);
00860 close (read_pipe[1]);
00861 close (write_pipe[0]);
00862 close (write_pipe[1]);
00863 return;
00864 case 0:
00865 dup2 (write_pipe[0], 0);
00866 dup2 (read_pipe[1], 1);
00867 dup2 (read_pipe[1], 2);
00868
00869 close (write_pipe[0]);
00870 close (read_pipe[1]);
00871
00872 if ( logfile ) {
00873 char fname[1000];
00874
00875
00876
00877 sprintf(fname, "%s.%ld", logfile, time(NULL));
00878 execlp ("daVinci", "daVinci", "-pipe", "-log", fname, NULL);
00879 } else {
00880 execlp ("daVinci", "daVinci", "-pipe", NULL);
00881 }
00882
00883
00884
00885 printf("communication_error(\"execlp of daVinci: %s %s\")\n",
00886 strerror(errno), "(define $DAVINCIHOME; need daVinci on $PATH)");
00887 exit (1);
00888
00889 default:
00890 close (read_pipe[1]);
00891 close (write_pipe[0]);
00892 }
00893 _io.Init( to_display, from_display );
00894 _io.Trace( _trace_fp );
00895
00896 DA_ACK msg = Wait_For_Ack();
00897 if ( msg ) {
00898 fprintf(stderr, "DaVinci connection failed: %s\n", msg);
00899 return;
00900 }
00901 _display_ok = true;
00902 }
00903
00904 #ifdef TARG_IA64
00905 Emit_Do( "set(font_size(12))" );
00906 Emit_Do( "set(gap_height(10))" );
00907 Emit_Do( "set(gap_width(10))" );
00908 #else
00909 Emit_Do( "set(font_size(6))" );
00910 Emit_Do( "set(gap_height(40))" );
00911 Emit_Do( "set(gap_width(20))" );
00912 #endif
00913 #endif
00914 }
00915
00916 DaVinci::~DaVinci()
00917 {
00918 if(_use_socket){
00919 _davinci_count--;
00920 if(_davinci_count ==0) close(_tcp_socket);
00921 }
00922
00923 }
00924
00925
00926
00927
00928 static MENU_INFO Menu_basic[] = {
00929 { "exit_event_loop", "exit_event_loop", true, 0, NULL }
00930 };
00931 #define N_MENU_BASIC ( sizeof(Menu_basic) / sizeof(Menu_basic[0]) )
00932
00933 void
00934 DaVinci::Event_Loop(DaVinci_Callback *cb_hook)
00935 {
00936 static DaVinci_Callback dflt_cb_hook;
00937
00938 EVENT_T event;
00939 INT i;
00940
00941 if ( _in_event_loop || ! _display_ok ) return;
00942
00943 if ( cb_hook == NULL ) {
00944 cb_hook = &dflt_cb_hook;
00945 }
00946
00947 if ( ! _basic_menu_added ) {
00948 DA_ACK msg = Menu_Create( N_MENU_BASIC, Menu_basic );
00949 if ( msg ) {
00950 fprintf(stderr, "Unable to add Basic Menu -- %s.\n",
00951 "best to not start event_loop");
00952 return;
00953 }
00954 _basic_menu_added = true;
00955 }
00956 _in_event_loop = true;
00957
00958 while ( _display_ok ) {
00959 while ( (_use_socket && !_event_q_socket[_contex].empty()) ||
00960 (!_use_socket && !_event_q.empty())) {
00961 if(_use_socket){
00962 event = _event_q_socket[_contex].front();
00963 _event_q_socket[_contex].pop();
00964 }else{
00965 event = _event_q.front();
00966 _event_q.pop();
00967 }
00968 switch ( event.kind ) {
00969 case EK_COM_ERROR:
00970 fprintf(stderr, "event_loop: Unexpected: %s\n", event.u.com_error.msg);
00971 break;
00972 case EK_OK:
00973 fprintf(stderr, "event_loop: Unexpected: OK\n");
00974 break;
00975 case EK_SEL_EDGE:
00976 {
00977 EDGE_ID edge_id(event.u.sel_edge.edge_src,
00978 event.u.sel_edge.edge_dst);
00979 cb_hook->Edge_Select( edge_id );
00980 }
00981 break;
00982 case EK_SEL_MENU:
00983 for (i = 0; i < N_MENU_BASIC; ++i) {
00984 if ( strcmp( event.u.sel_menu.label, Menu_basic[i].id ) == 0 ) {
00985 Menu_Basic_Do( event.u.sel_menu.label );
00986 break;
00987 }
00988 }
00989 if ( i >= N_MENU_BASIC ) {
00990 cb_hook->Menu_Select( event.u.sel_menu.label );
00991 }
00992 break;
00993 case EK_SEL_NODES:
00994 cb_hook->Node_Select( event.u.sel_nodes.n_nodes,
00995 event.u.sel_nodes.node_ids );
00996 break;
00997 case EK_QUIT:
00998 case EK_CLOSE:
00999 if(_use_socket){
01000 _contex_use_array[_contex] = CONTEX_UNUSE;
01001 _contex_count--;
01002 if(_contex_count == 0){
01003 close(_tcp_socket);
01004 }
01005 _display_ok = false;
01006 _in_event_loop = false;
01007 }else{
01008 _display_ok = false;
01009 _in_event_loop = false;
01010 }
01011 break;
01012 case EK_DISCONNECT:
01013 fprintf(stderr, "EVENT: EK_DISCONNET\n");
01014 break;
01015 default:
01016 fprintf(stderr, "ERROR: event_loop missing event case %d\n",
01017 event.kind);
01018 }
01019 if ( ! _in_event_loop ) {
01020 return;
01021 }
01022 }
01023
01024
01025 char *line = _io.In_Line();
01026
01027 if ( line == NULL ) {
01028 _display_ok = false;
01029 break;
01030 }
01031
01032 if(_use_socket && line[0] == 'c' && line[1] == 'o' && line[2] == 'n'
01033 && line[3] == 't' && line[4] == 'e' && line[5] == 'x' && line[6] == 't'){
01034 if(line[9] >='0' && line[9] <= '9'){
01035 sscanf(line, "context(\"%d\")", &_current_contex);
01036 }
01037 continue;
01038 }
01039 if ( Parse_Event( line, &event ) ) {
01040 if(_use_socket){
01041 if(event.kind == EK_QUIT || event.kind ==EK_CLOSE){
01042 while ( ! _event_q_socket[_current_contex].empty() ) {
01043 _event_q_socket[_current_contex].pop();
01044 }
01045 }
01046 _event_q_socket[_current_contex].push( event );
01047 }else{
01048 _event_q.push( event );
01049 }
01050 }
01051 }
01052
01053 }
01054
01055 void
01056 DaVinci::Exit_Event_Loop()
01057 {
01058 _in_event_loop = false;
01059 }
01060
01061 DA_ACK
01062 DaVinci::Title(const char *title)
01063 {
01064 if ( ! Usage_Ok( FT_TITLE, BASE_SET ) ) return "Usage-error";
01065
01066 _io.Out_Fmt( "window(title(\"%s\"))\n", title );
01067 return Wait_For_Ack();
01068 }
01069
01070 DA_ACK
01071 DaVinci::Show_Status(const char *status)
01072 {
01073 if ( ! Usage_Ok( FT_SHOW_STATUS, BASE_SET ) ) return "Usage-error";
01074
01075 _io.Out_Fmt( "window(show_status(\"%s\"))\n", status );
01076 return Wait_For_Ack();
01077 }
01078
01079 DA_ACK
01080 DaVinci::Show_Message(const char *msg)
01081 {
01082 if ( ! Usage_Ok( FT_SHOW_MESSAGE, BASE_SET ) ) return "Usage-error";
01083
01084 _io.Out_Fmt( "window(show_message(\"%s\"))\n", msg );
01085 return Wait_For_Ack();
01086 }
01087
01088 DA_ACK
01089 DaVinci::Menu_Create(INT n_items, const MENU_INFO *items)
01090 {
01091 if ( ! Usage_Ok( FT_MENU_CREATE, BASE_SET ) ) return "Usage-error";
01092
01093 if ( n_items == 0 ) return NULL;
01094
01095 _io.Out_Fmt( "app_menu(create_menus([" );
01096 Emit_Menu( n_items, items );
01097 _io.Out_Fmt( "]))\n" );
01098
01099 DA_ACK msg = Wait_For_Ack();
01100 if ( msg ) return msg;
01101
01102 return Menu_Set_Active();
01103 }
01104
01105 DA_ACK
01106 DaVinci::Menu_Activate(INT n_ids, const char *id[])
01107 {
01108 if ( ! Usage_Ok( FT_MENU_ACTIVATE, BASE_SET ) ) return "Usage-error";
01109
01110 for (INT i = 0; i < n_ids; ++i) {
01111 _menu_state.Set( id[i], DM_ACTIVE );
01112 }
01113 return Menu_Set_Active();
01114 }
01115
01116 DA_ACK
01117 DaVinci::Menu_Deactivate(INT n_ids, const char *id[])
01118 {
01119 if ( ! Usage_Ok( FT_MENU_DEACTIVATE, BASE_SET ) ) return "Usage-error";
01120
01121 for (INT i = 0; i < n_ids; ++i) {
01122 _menu_state.Set( id[i], DM_INACTIVE );
01123 }
01124 return Menu_Set_Active();
01125 }
01126
01127 void
01128 DaVinci::Graph_Begin()
01129 {
01130 if ( ! Usage_Ok( FT_GRAPH_BEGIN, BASE_SET ) ) return;
01131
01132 _io.Out_Fmt( "graph(new_placed([" );
01133 _node_cnt = 0;
01134 }
01135
01136 void
01137 DaVinci::Node_Begin(NODE_ID id, const char *label, const NODE_TYPE& node_type)
01138 {
01139 if ( ! Usage_Ok( FT_NODE_BEGIN, (FT_GRAPH_BEGIN|FT_NODE_END) ) ) return;
01140
01141 if ( _usage_check ) {
01142 if ( _node_def_set.count(id) > 0 ) {
01143 fprintf(stderr, "DaVinci::Node_Begin USAGE-ERROR, %s 0x%p\n",
01144 "duplicate def for node", id);
01145 } else {
01146 _node_def_set.insert(id);
01147 }
01148 }
01149 _io.Out_Fmt( "%sl(\"%p\",n(\"%s\",[a(\"OBJECT\",\"%s\")",
01150 ( _node_cnt > 0 ? "," : "" ),
01151 id, node_type._type_name, label);
01152 _node_cnt += 1;
01153 _edge_cnt = 0;
01154 const char *comma = ",";
01155 Emit_Attr( node_type, &comma );
01156 _io.Out_Fmt( "],[" );
01157
01158 }
01159
01160 void
01161 DaVinci::Out_Edge(const EDGE_ID& edge_id,
01162 const EDGE_TYPE& edge_type,
01163 const NODE_ID dest_id)
01164 {
01165 if ( ! Usage_Ok( FT_OUT_EDGE, (FT_NODE_BEGIN|FT_OUT_EDGE) ) ) return;
01166
01167 if ( _usage_check ) {
01168 _node_ref_set.insert(edge_id.dst);
01169 }
01170 _io.Out_Fmt( "%sl(\"%p:%p\",e(\"%s\",[",
01171 ( _edge_cnt > 0 ? "," : "" ),
01172 edge_id.src, edge_id.dst, edge_type._type_name);
01173 _edge_cnt += 1;
01174
01175 Emit_Attr( edge_type );
01176 _io.Out_Fmt( "],r(\"%p\")))", dest_id);
01177 }
01178
01179 void
01180 DaVinci::Node_End()
01181 {
01182 if ( ! Usage_Ok( FT_NODE_END, (FT_NODE_BEGIN|FT_OUT_EDGE) ) ) return;
01183
01184 _io.Out_Fmt( "]))" );
01185 }
01186
01187 DA_ACK
01188 DaVinci::Graph_End()
01189 {
01190 if ( _usage_check ) {
01191 for (std::set<NODE_ID>::iterator it_ref = _node_ref_set.begin();
01192 it_ref != _node_ref_set.end(); ++it_ref) {
01193 NODE_ID ref_id = *it_ref;
01194
01195 if ( _node_def_set.count(ref_id) == 0 ) {
01196 fprintf(stderr, "ERROR DaVinci node 0x%p referenced, %s\n",
01197 ref_id, "but not defined.");
01198 }
01199 }
01200 }
01201 if ( ! Usage_Ok( FT_GRAPH_END, (FT_NODE_END|FT_GRAPH_BEGIN) ) ) {
01202 return "Usage-error";
01203 }
01204 _io.Out_Fmt( "]))\n" );
01205
01206 return Wait_For_Ack();
01207 }
01208
01209 DA_ACK
01210 DaVinci::Change_Attr(const NODE_ID id,
01211 const NODE_TYPE& nt,
01212 const char *new_label)
01213 {
01214 if ( ! Usage_Ok( FT_CHANGE_ATTR, BASE_SET ) ) return "Usage-error";
01215
01216 const char *comma = "";
01217
01218 _io.Out_Fmt( "graph(change_attr([node(\"%p\",[", id);
01219
01220 if ( new_label ) {
01221 _io.Out_Fmt( "a(\"OBJECT\",\"%s\")", new_label );
01222 comma = ",";
01223 }
01224 Emit_Attr( nt, &comma );
01225
01226 _io.Out_Fmt( "])]))\n");
01227
01228 return Wait_For_Ack();
01229 }
01230
01231 DA_ACK
01232 DaVinci::Change_Attr(const EDGE_ID& edge_id, const EDGE_TYPE& et)
01233 {
01234 if ( ! Usage_Ok( FT_CHANGE_ATTR, BASE_SET ) ) return "Usage-error";
01235
01236 _io.Out_Fmt( "graph(change_attr([edge(\"%p:%p\",[",
01237 edge_id.src, edge_id.dst );
01238 Emit_Attr( et );
01239 _io.Out_Fmt( "])]))\n");
01240
01241 return Wait_For_Ack();
01242 }
01243
01244 void
01245 DaVinci::Update_Begin()
01246 {
01247 if ( ! Usage_Ok( FT_UPDATE_BEGIN, BASE_SET ) ) return;
01248
01249 _io.Out_Fmt( "graph(update([" );
01250 _node_cnt = 0;
01251 _edge_cnt = 0;
01252 }
01253
01254 void
01255 DaVinci::New_Node(NODE_ID id, const char *label, const NODE_TYPE& nt )
01256 {
01257 if ( ! Usage_Ok( FT_NEW_NODE, (FT_UPDATE_BEGIN|FT_NEW_NODE) ) ) return;
01258
01259 if ( _edge_cnt > 0 ) {
01260 fprintf(stderr, "Must list ALL new_nodes before first new_edge\n");
01261 fprintf(stderr, "Skipping this node to avoid DaVinci error.\n");
01262 return;
01263 }
01264 _io.Out_Fmt( "%snew_node(\"%p\",[a(\"OBJECT\",\"%s\")",
01265 (_node_cnt > 0 ? "," : ""), id, label );
01266 const char *comma = ",";
01267 Emit_Attr( nt, &comma );
01268 _node_cnt += 1;
01269 }
01270
01271 void
01272 DaVinci::New_Edge(const EDGE_ID& id,
01273 const EDGE_TYPE& et,
01274 NODE_ID src,
01275 NODE_ID dst)
01276 {
01277 if ( ! Usage_Ok( FT_NEW_EDGE, (FT_UPDATE_BEGIN|FT_NEW_NODE|FT_NEW_EDGE) ) ) {
01278 return;
01279 }
01280 if ( _edge_cnt == 0 ) {
01281 _io.Out_Fmt( "],[" );
01282 }
01283 _io.Out_Fmt( "%snew_edge(\"%p:%p\",\"\",[", (_edge_cnt > 0 ? "," : ""),
01284 id.src, id.dst );
01285 Emit_Attr( et );
01286 _io.Out_Fmt( "],\"%p\",\"%p\")", src, dst);
01287 _edge_cnt += 1;
01288 }
01289
01290 void
01291 DaVinci::Delete_Edge(const EDGE_ID& id)
01292 {
01293 if ( ! Usage_Ok( FT_DELETE_EDGE,
01294 (FT_UPDATE_BEGIN|FT_NEW_NODE|FT_NEW_EDGE|FT_DELETE_EDGE) ) ) {
01295 return;
01296 }
01297 if ( _edge_cnt == 0 ) {
01298 _io.Out_Fmt( "],[" );
01299 }
01300 _io.Out_Fmt( "%sdelete_edge(\"%p:%p\")", (_edge_cnt > 0 ? "," : ""),
01301 id.src, id.dst );
01302 _edge_cnt += 1;
01303 }
01304
01305 DA_ACK
01306 DaVinci::Update_End()
01307 {
01308 if ( ! Usage_Ok( FT_UPDATE_END,
01309 (FT_UPDATE_BEGIN|FT_NEW_NODE|FT_NEW_EDGE) ) ) {
01310 return "Usage-error";
01311 }
01312 if ( _edge_cnt == 0 ) {
01313 _io.Out_Fmt( "],[" );
01314 }
01315 _io.Out_Fmt( "]))\n");
01316
01317 return Wait_For_Ack();
01318 }