1 /*===========================================================================*/
2 /*                                                                           */
3 /* This file is part of the SYMPHONY MILP Solver Framework.                  */
4 /*                                                                           */
5 /* SYMPHONY was jointly developed by Ted Ralphs (ted@lehigh.edu) and         */
6 /* Laci Ladanyi (ladanyi@us.ibm.com).                                        */
7 /*                                                                           */
8 /* The Interactive Graph Drawing application was developed by Marta Eso.     */
9 /*                                                                           */
10 /* (c) Copyright 2000-2019 Ted Ralphs. All Rights Reserved.                  */
11 /*                                                                           */
12 /* This software is licensed under the Eclipse Public License. Please see    */
13 /* accompanying file for terms.                                              */
14 /*                                                                           */
15 /*===========================================================================*/
16 
17 #if defined(_MSC_VER) || defined (__MNO_CYGWIN)
18 #include <io.h>
19 #define execlp _execlp
20 #include <process.h>
21 #else
22 #include <unistd.h>
23 #endif
24 #include <memory.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 
31 #include "sym_constants.h"
32 #include "sym_macros.h"
33 #include "sym_proccomm.h"
34 #include "sym_messages.h"
35 #include "sym_dg.h"
36 #include "sym_dg_params.h"
37 
38 /*===========================================================================*/
39 
INTERMED_ERROR(char * window_name,int old_msgtag,int receiver,int msgtag)40 void INTERMED_ERROR(char *window_name, int old_msgtag,
41 		    int receiver, int msgtag)
42 {
43    int s_bufid;
44    s_bufid = init_send(DataInPlace);
45    send_char_array(window_name, MAX_NAME_LENGTH);
46    send_int_array(&old_msgtag, 1);
47    send_msg(receiver, msgtag);
48    freebuf(s_bufid);
49 }
50 
51 /*===========================================================================*/
52 
53 static int echo_commands;
spprint(FILE * write_to,const char * format,...)54 int spprint(FILE *write_to, const char *format, ...)
55 {
56    int i;
57    va_list ap;
58 
59    va_start(ap, format);
60    if (echo_commands) vprintf(format, ap);
61    va_end(ap);
62    va_start(ap, format);
63    i = vfprintf(write_to, format, ap);
64    va_end(ap);
65    return(i);
66 }
67 
68 /*===========================================================================*/
69 
70 /*===========================================================================*\
71  * Exec the named cmd as a child process, returning two pipes to
72  * communicate with the process, and the child's process ID.
73 \*===========================================================================*/
74 
start_child(char * cmd,FILE ** readpipe,FILE ** writepipe)75 int start_child(char *cmd, FILE **readpipe, FILE **writepipe)
76 {
77 
78    /* FIXME: Doesn't seem to work for Windows */
79 
80 #if !defined(_MSC_VER) && !defined (__MNO_CYGWIN)
81 
82    int childpid, pipe1[2], pipe2[2];
83 
84 #if !defined(_MSC_VER) && !defined (__MNO_CYGWIN)
85    if ((pipe(pipe1) < 0) || (pipe(pipe2) < 0)){
86       perror("pipe");
87       exit(-1);
88    }
89 #else
90    if ((_pipe(pipe1,256,O_BINARY) < 0) || (_pipe(pipe2,256,O_BINARY) < 0)){
91       perror("pipe");
92       exit(-1);
93    }
94 #endif
95 
96    if ((childpid = vfork()) < 0){
97       perror("fork");
98       exit(-1);
99    }else if (childpid > 0){    /* parent */
100       close(pipe1[0]);
101       close(pipe2[1]);
102       /* write to child is pipe1[1], read from child is pipe2[0] */
103       *readpipe = fdopen(pipe2[0], "r");
104       /* this sets the pipe to be a Non-Blocking IO one, so fgets won't wait
105        * until it receives a line. */
106       fcntl(pipe2[0], F_SETFL, O_NONBLOCK);
107       *writepipe = fdopen(pipe1[1], "w");
108       setlinebuf(*writepipe);
109       return(childpid);
110    }else{      /* child */
111       close(pipe1[1]);
112       close(pipe2[0]);
113       /* read from parent is pipe1[0], write to parent is pipe2[1] */
114       dup2(pipe1[0], 0);
115       dup2(pipe2[1], 1);
116       close(pipe1[0]);
117       close(pipe2[1]);
118       if (execlp(cmd, cmd, NULL) < 0)
119 	 perror("execlp");
120 
121       /* never returns */
122    }
123 
124 #endif
125 
126    return(0);
127 }
128 
129 /*===========================================================================*/
130 
main(void)131 int main(void)
132 {
133    dg_prob *dgp;
134    dg_params *par;
135    FILE *read_from, *write_to;
136    int childpid, sender;
137 
138    char tcl_msg[MAX_LINE_LENGTH +1];
139    char name[MAX_NAME_LENGTH +1], name2[MAX_NAME_LENGTH +1];
140    char source[MAX_NAME_LENGTH +1], target[MAX_NAME_LENGTH +1];
141    char title[MAX_TITLE_LENGTH +1], title2[MAX_TITLE_LENGTH +1];
142    char fname[MAX_FILE_NAME_LENGTH +1];
143    char old_weight[MAX_WEIGHT_LENGTH +1], new_weight[MAX_WEIGHT_LENGTH +1];
144    char new_label[MAX_LABEL_LENGTH +1];
145    char new_dash[MAX_DASH_PATTERN_LENGTH +1];
146    char *str;
147    int msgtag, keyword, key, r_bufid, s_bufid, bufid, bytes, len;
148 
149    int i, j, k, number, add_nodenum, change_nodenum, delete_nodenum;
150    int add_edgenum, change_edgenum, delete_edgenum;
151    int nodenum, new_nodenum, edgenum, new_edgenum, node_id, edge_id;
152    int new_radius, old_deleted_nodenum;
153    unsigned int id;
154    win_desc *desc;
155    dg_graph *g;
156    dg_node *nodes, *nod;
157    dg_edge *edges, *edg;
158    window *win, *new_win, *source_win, *target_win;
159 
160    register_process();
161    dgp = (dg_prob *) calloc(1, sizeof(dg_prob));
162 
163    /* receive parameters from the master */
164    r_bufid = receive_msg(ANYONE, DG_DATA);
165    bufinfo(r_bufid, &bytes, &msgtag, &dgp->master);
166    receive_char_array((char *)&dgp->par, sizeof(dg_params));
167    freebuf(r_bufid);
168    par = &(dgp->par);
169    echo_commands = par->echo_commands;
170 
171    /* fork the wish shell */
172    childpid = start_child((char *)"wish", &read_from, &write_to);
173 
174    /* Source the tcl scripts into wish and invoke startUp*/
175    spprint(write_to, "source %s/Init.tcl\n", par->source_path);
176    spprint(write_to, "source %s/Tools.tcl\n", par->source_path);
177    spprint(write_to, "source %s/NodeEdgeBasics.tcl\n", par->source_path);
178    spprint(write_to, "source %s/FileMenu.tcl\n", par->source_path);
179    spprint(write_to, "source %s/WindowMenu.tcl\n", par->source_path);
180    spprint(write_to, "source %s/NodeMenu.tcl\n", par->source_path);
181    spprint(write_to, "source %s/EdgeMenu.tcl\n", par->source_path);
182    spprint(write_to, "source %s/CAppl.tcl\n", par->source_path);
183 
184    spprint(write_to, "Igd_StartUp\n");
185 
186    /* set application defaults to those stored in par */
187    spprint(write_to,
188 	   "Igd_SetApplDefaults %i %i %i %i %i %i %i {%s} {%s} %i %i %i %f {%s} {%s} {%s}\n",
189 	   par->canvas_width, par->canvas_height, par->viewable_width,
190 	   par->viewable_height, par->disp_nodelabels,
191 	   par->disp_nodeweights, par->disp_edgeweights, par->node_dash,
192 	   par->edge_dash, par->node_radius, par->interactive_mode,
193 	   par->mouse_tracking, par->scale_factor, par->nodelabel_font,
194 	   par->nodeweight_font, par->edgeweight_font);
195 
196    /* invoke user initialization */
197 #ifdef USE_SYM_APPLICATION
198    CALL_USER_FUNCTION( user_initialize_dg(&dgp->user) );
199 #endif
200 
201    while(TRUE){
202 
203       msgtag = 0;
204 
205       if (dgp->waiting_to_die){
206 	 for ( i = 0; i < dgp->window_num; ){
207 	    if ( ! dgp->windows[i]->wait_for_click ){
208 	       spprint(write_to, "Igd_QuitWindow %u\n",dgp->windows[i]->id);
209 	       free_window(&dgp->window_num, dgp->windows, i);
210 	    }else{
211 	       i++;
212 	    }
213 	 }
214 	 if ( ! dgp->window_num )
215 	    wait_for_you_can_die(dgp, write_to);
216       }
217 
218       /* Interpret message coming from the tcl application. */
219       if (fgets(tcl_msg, 80, read_from) != NULL) {
220 	 sscanf(tcl_msg, "%i", &msgtag);
221 
222 	 switch(msgtag){
223 
224 	  case IGDTOI_CLICK_HAPPENED:
225 	    /* if wait_for_click is 2, send a message to the owner */
226 	    fgets(name2, MAX_NAME_LENGTH +1, read_from);
227 	    sscanf(name2, "%u", &id);
228 	    for (i = dgp->window_num - 1; i >= 0; i-- )
229 	       if ( dgp->windows[i]->id == id )
230 		  break;
231 	    if ( i < 0 ) {
232 	       /* this should never happen */
233 	       printf("Window of id %u is not found\n", id);
234 	       break;
235 	    }
236 	    if ( dgp->windows[i]->wait_for_click == 2 ) {
237 	       s_bufid = init_send(DataInPlace);
238 	       send_str(name);
239 	       send_msg(dgp->windows[i]->owner_tid, ITOC_CLICK_HAPPENED);
240 	       freebuf(s_bufid);
241 	    }
242 	    dgp->windows[i]->wait_for_click = 0;
243 	    break;
244 
245 	  case IGDTOI_QUIT_WINDOW:
246 	    /* delete data structure corresponding to this window */
247 	    fgets(name2, MAX_NAME_LENGTH +1, read_from);
248 	    sscanf(name2, "%u", &id);
249 	    for (i = dgp->window_num - 1; i >= 0; i-- )
250 	       if ( dgp->windows[i]->id == id )
251 		  break;
252 	    if ( i < 0 ) {
253 	       /* this should never happen */
254 	       printf("Window of id %u is not found\n", id);
255 	       break;
256 	    }
257 	    spprint(write_to, "Igd_QuitWindow %u\n", id);
258 	    free_window(&dgp->window_num, dgp->windows, i);
259 	    break;
260 
261 	  case IGDTOI_QUIT_APPLICATION:
262 	    /* delete all windows */
263 	    for ( i = 0; i < dgp->window_num; ){
264 	       if ( ! dgp->windows[i]->wait_for_click ){
265 		  spprint(write_to, "Igd_QuitWindow %u\n",dgp->windows[i]->id);
266 		  free_window(&dgp->window_num, dgp->windows, i);
267 	       }else{
268 		  i++;
269 	       }
270 	    }
271 	    dgp->waiting_to_die = TRUE;
272 	    break;
273 
274 	  case IGDTOI_TEXT_ENTERED:
275 	    fgets(name2, MAX_NAME_LENGTH +1, read_from);
276 	    sscanf(name2, "%u", &id);
277 	    for (i = dgp->window_num - 1; i >= 0; i-- )
278 	       if ( dgp->windows[i]->id == id )
279 		  break;
280 	    win = dgp->windows[i];
281 	    if ( i < 0 ) {
282 	       /* this should never happen */
283 	       printf("Window of id %u is not found\n", id);
284 	       break;
285 	    }
286 	    fgets(tcl_msg, MAX_LINE_LENGTH +1, read_from);
287 	    sscanf(tcl_msg, "%i", &win->text_length);
288 	    win->text = (char *) malloc( (win->text_length + 1) * CSIZE);
289 	    fread(win->text, CSIZE, win->text_length, read_from);
290 	    win->text[win->text_length] = 0;
291 
292 	    /* invoke function that interprets the message */
293 #ifdef USE_SYM_APPLICATION
294 	    CALL_USER_FUNCTION( user_interpret_text(dgp->user,
295 						    win->text_length,
296 						    win->text,
297 						    win->owner_tid) );
298 #endif
299 	    break;
300 
301 	  case IGDTOI_REQUEST_GRAPH:
302 	    fgets(name2, MAX_NAME_LENGTH +1, read_from);
303 	    sscanf(name2, "%u", &id);
304 	    for (i = dgp->window_num - 1; i >= 0; i-- )
305 	       if ( dgp->windows[i]->id == id )
306 		  break;
307 	    if ( i < 0 ) {
308 	       /* this should never happen */
309 	       printf("Window of id %u is not found\n", id);
310 	       break;
311 	    }
312 	    display_graph_on_canvas(dgp->windows[i], write_to);
313 	    break;
314 
315 	  default:
316 	    printf("Unknown message type from IGD to I (%i)\n", msgtag);
317 	    break;
318 
319 	 } /* end switch */
320       } /* end if */
321 
322       if (dgp->waiting_to_die)
323 	 continue;
324 
325 
326       /* Interpret the message coming from the C application.
327 
328 	 All the messages except INITIALIZE_WINDOW and COPY_GRAPH
329 	 and QUIT will be put on the pipe corresponding to the appropriate
330 	 window (messages are processed in FIFO order
331 
332 	 In case of INITIALIZE_WINDOW the data structure associated
333 	 with a winow is created (including the pipes.
334 
335 	 In case of COPY_GRAPH a message must be placed on both the
336 	 source and the target window's pipe.
337 
338 	 In case of QUIT all data structures are disassembled and then
339 	 the tcl application is killed.                                   */
340 
341       r_bufid = nreceive_msg(ANYONE, ANYTHING);
342       if (r_bufid > 0){
343 	 bufinfo(r_bufid, &bytes, &msgtag, &sender);
344 	 switch (msgtag){
345 
346 	  case CTOI_INITIALIZE_WINDOW:
347 
348 	    /* get the name of the new window */
349 	    receive_str(name);
350 	    receive_str(title);
351 
352 	    /* if a window with this name already exists: error */
353 	    i = find_window(dgp->window_num, dgp->windows, name);
354 	    if ( i >= 0 ) {
355 	       INTERMED_ERROR(name, msgtag, sender,ITOC_WINDOW_ALREADY_EXISTS);
356 	       freebuf(r_bufid);
357 	       break;
358 	    }
359 	    /* allocate space for the new window */
360 	    win = init_dgwin(dgp, sender, name, title);
361 
362 	    /* set up the window description */
363 	    receive_int_array(&number, 1);
364 	    copy_win_desc_from_par(win, &dgp->par);
365 	    for ( ; number > 0; number-- ) {
366 	       /* read out the key - value pairs */
367 	       receive_int_array(&key, 1);
368 	       set_window_desc_pvm(key, win);
369 	    }
370 
371 	    freebuf(r_bufid);
372 	    break;
373 
374 
375 	  case CTOI_COPY_GRAPH:
376 	    /* Copy source's graph into target's window.
377 	       Here a message is placed onto both target's and source's
378 	       pipe so that they can wait for each other before the
379 	       actual copying happens (shake hands) */
380 
381 	    receive_str(target);
382 	    receive_str(source);
383 
384 	    i = find_window(dgp->window_num, dgp->windows, target);
385 	    if (i < 0) { /* target doesn't exist, send error message */
386 	       INTERMED_ERROR(target, msgtag, sender,ITOC_WINDOW_DOESNT_EXIST);
387 	       freebuf(r_bufid);
388 	       break;
389 	    }
390 	    j = find_window(dgp->window_num, dgp->windows, source);
391 	    if (j < 0) { /* source doesn't exist, send error message */
392 	       INTERMED_ERROR(source, msgtag, sender,ITOC_WINDOW_DOESNT_EXIST);
393 	       freebuf(r_bufid);
394 	       break;
395 	    }
396 	    bufid = init_send(DataInPlace);
397 	    msgtag = WAITING_TO_GET_A_COPY;
398 	    send_int_array(&msgtag, 1);
399 	    send_str(source);
400 	    add_msg(dgp->windows[i], bufid);
401 	    setsbuf(0);
402 
403 	    bufid = init_send(DataInPlace);
404 	    msgtag = WAITING_TO_BE_COPIED;
405 	    send_int_array(&msgtag, 1);
406 	    send_str(target);
407 	    add_msg(dgp->windows[j], bufid);
408 	    setsbuf(0);
409 
410 	    freebuf(r_bufid);
411 	    break;
412 
413 
414 	  case CTOI_QUIT:
415 	    /* quit from all windows, disassemble data structures.
416 	     * (actually, this will happen on the top of the while loop...) */
417 	    if (! dgp->waiting_to_die)
418 	       dgp->waiting_to_die = TRUE;
419 	    freebuf(r_bufid);
420 	    break;
421 
422 	  case CTOI_YOU_CAN_DIE:
423 	    /* quit from all windows, disassemble data structures.
424 	     * (actually, this will happen on the top of the while loop...)
425 	     * and die */
426 	    dgp->waiting_to_die = 2 * TRUE;
427 	    freebuf(r_bufid);
428 	    break;
429 
430 
431 	  default:
432 	    /* Check if window with name exists. If not, send back error
433 	       message. If yes, copy the message over to window's pipe. */
434 	    receive_str(name);
435 	    len = strlen(name);
436 	    i = find_window(dgp->window_num, dgp->windows, name);
437 	    if (i < 0){
438 	       /* there is no window of that name: send error message */
439 	       INTERMED_ERROR(name, msgtag, sender,ITOC_WINDOW_DOESNT_EXIST);
440 	       freebuf(r_bufid);
441 	       break;
442 	    }
443 
444 	    add_msg(dgp->windows[i], r_bufid);
445 	    setrbuf(0);
446 	    break;
447 	 } /* end switch */
448       } /* endif r_bufid > 0 */
449 
450 
451       if (dgp->waiting_to_die)
452 	 continue;
453 
454       /* Process one message from each window's pipe. */
455 
456       for ( i = 0; i < dgp->window_num; i++ ) {
457 
458 	 win = dgp->windows[i];
459 
460 	 /* if wait_for_click is set, skip */
461 	 if ( win->wait_for_click )
462 	    continue;
463 
464 	 /* if window is waiting to be copied or waiting to get a copy, skip */
465 	 if ( win->copy_status )
466 	    continue;
467 
468 	 /* if no message in the pipe, skip */
469 	 if (win->buf.bufread == -1)
470 	    continue;
471 
472 	 /* else: process the message .... */
473 	 msgtag = 0;
474 	 r_bufid = get_next_msg(win);
475 	 setrbuf(r_bufid);
476 	 bufinfo(r_bufid, &bytes, &msgtag, &sender);
477 
478 	 if (msgtag == 0){
479 	    /* This means that the message was locally 'hand-packed' */
480 	    receive_int_array(&msgtag, 1);
481 	 }
482 
483 	 switch ( msgtag ) {
484 
485 	  case CTOI_USER_MESSAGE:
486 #ifdef USE_SYM_APPLICATION
487 	    user_dg_process_message(win->user, win, write_to);
488 #endif
489 	    break;
490 
491 	  case CTOI_QUIT_WINDOW:
492 	    /* delete this window */
493 	    spprint(write_to, "Igd_QuitWindow %u\n", win->id);
494 	    free_window(&dgp->window_num, dgp->windows, i);
495 	    i--;
496 	    break;
497 
498 
499 	  case CTOI_CHANGE_WINDOW_DESC:
500 	    /* change window descriptions */
501 	    receive_int_array(&number, 1);
502 	    for ( ; number > 0; number-- ) {
503 	       /* read out the key - value pairs */
504 	       receive_int_array(&key, 1);
505 	       set_window_desc_pvm(key, win);
506 	    }
507 	    desc = &(win->desc);
508 	    if ( win->window_displayed ) {
509 	       spprint(write_to, "Igd_SetAndExecuteWindowDesc %u %i %i %i %i %i %i %i {%s} {%s} %i %i %i %f {%s} {%s} {%s}\n",
510 		       win->id, desc->canvas_width, desc->canvas_height,
511 		       desc->viewable_width, desc->viewable_height,
512 		       desc->disp_nodelabels, desc->disp_nodeweights,
513 		       desc->disp_edgeweights, desc->node_dash,
514 		       desc->edge_dash, desc->node_radius,
515 		       desc->interactive_mode, desc->mouse_tracking,
516 		       desc->scale_factor, desc->nodelabel_font,
517 		       desc->nodeweight_font, desc->edgeweight_font);
518 	    }
519 	    break;
520 
521 
522 	  case CTOI_SET_GRAPH:
523 	  case CTOI_SET_AND_DRAW_GRAPH:
524 	    /* define the graph corresponding to this window */
525 	    g = &(win->g);
526 	    FREE(g->nodes);
527 	    FREE(g->edges);
528 
529 	    receive_int_array(&g->nodenum, 1);
530 	    if ( g->nodenum ) {
531 	       nodes = g->nodes =
532 		  (dg_node *) malloc(g->nodenum * sizeof(dg_node));
533 	       for ( j = 0; j < g->nodenum; j++ ) {
534 		  read_node_desc_from_pvm(nodes+j, win);
535 	       }
536 	    }
537 
538 	    receive_int_array(&g->edgenum, 1);
539 	    if ( g->edgenum ) {
540 	       edges = g->edges =
541 		  (dg_edge *) malloc(g->edgenum * sizeof(dg_edge));
542 	       for ( j = 0; j < g->edgenum; j++ ) {
543 		  read_edge_desc_from_pvm(edges+j, win);
544 	       }
545 	    }
546 
547 	    if ( msgtag == CTOI_SET_AND_DRAW_GRAPH || win->window_displayed )
548 	       display_graph_on_canvas(win, write_to);
549 
550 	    break;
551 
552 
553 	  case CTOI_DRAW_GRAPH:
554 	    /* first erase/create the window itself, then display all the nodes
555 	       and edges */
556 	    display_graph_on_canvas(win, write_to);
557 	    break;
558 
559 
560 	  case CTOI_DELETE_GRAPH:
561 	    /* delete the data structure of the graph and erase its window
562 	     if open */
563 	    FREE(win->g.nodes);
564 	    FREE(win->g.edges);
565 	    win->g.nodenum = win->g.deleted_nodenum = 0;
566 	    win->g.edgenum = win->g.deleted_edgenum = 0;
567 	    if ( win->window_displayed ){
568 	       spprint(write_to, "Igd_EraseWindow %u\n", win->id);
569 	    }
570 	    break;
571 
572 
573 	  case CTOI_WAIT_FOR_CLICK_NO_REPORT:
574 	    /* window will not get any messages until the Continue button
575 	       is pressed. the window has to be open to have an effect */
576 	    if ( win->window_displayed ) {
577 	       win->wait_for_click = 1;
578 	       spprint(write_to, "Igd_CApplWaitForClick %u\n", win->id);
579 	    } else {
580 	       INTERMED_ERROR(win->name, msgtag, win->owner_tid,
581 			      ITOC_WINDOW_ISNT_DISPLAYED);
582 	    }
583 	    break;
584 
585 
586 	  case CTOI_WAIT_FOR_CLICK_AND_REPORT:
587 	    /* window will not get any messages until the Continue button
588 	       is pressed. the window has to be open to have an effect.
589 	       the owner gets a message */
590 	    if ( win->window_displayed ) {
591 	       win->wait_for_click = 2;
592 	       spprint(write_to, "Igd_CApplWaitForClick %u\n", win->id);
593 	    } else {
594 	       INTERMED_ERROR(win->name, msgtag, win->owner_tid,
595 			      ITOC_WINDOW_ISNT_DISPLAYED);
596 	    }
597 	    break;
598 
599 
600 	  case CTOI_SAVE_GRAPH_TO_FILE:
601 	    /* save the graph into a file (only if it is displayed!) */
602 	    receive_str(fname);
603 	    if ( win->window_displayed ) {
604 	       spprint(write_to, "Igd_SaveGraph %u {%s}\n", win->id, fname);
605 	    } else {
606 	       INTERMED_ERROR(win->name, msgtag, win->owner_tid,
607 			      ITOC_WINDOW_ISNT_DISPLAYED);
608 	    }
609 	    break;
610 
611 
612 	  case CTOI_SAVE_GRAPH_PS_TO_FILE:
613 	    /* save postscript of the picture displayed. works only if
614 	       window is displayed. */
615 	    receive_str(fname);
616 	    if ( win->window_displayed ) {
617 	       spprint(write_to, "Igd_SavePs %u {%s}\n", win->id, fname);
618 	    } else {
619 	       INTERMED_ERROR(win->name, msgtag, win->owner_tid,
620 			      ITOC_WINDOW_ISNT_DISPLAYED);
621 	    }
622 	    break;
623 
624 
625 	  case CTOI_CLONE_WINDOW:
626 	    /* clone this window. if window is not displayed, only the
627 	     graph data structure will be copied over. */
628 	    /* wait_for_click, copy_status and text will not be copied over. */
629 	    receive_str(name2);
630 	    receive_str(title2);
631 
632 	    if ( find_window(dgp->window_num, dgp->windows, name2) >= 0 ) {
633 	       INTERMED_ERROR(win->name, msgtag, sender,
634 			      ITOC_WINDOW_ALREADY_EXISTS);
635 	       break;
636 	    }
637 
638 	    new_win = init_dgwin(dgp, sender, name2, title2);
639 	    copy_window_structure(new_win, win);
640 
641 	    if ( win->window_displayed ) {
642 	       spprint(write_to,
643 		       "Igd_CopyWindowDesc %u %u\n", new_win->id, win->id);
644 	       spprint(write_to,
645 		       "Igd_InitWindow %u {%s}\n", new_win->id, title2);
646 	       spprint(write_to, "Igd_DisplayWindow %u\n", new_win->id);
647 	       spprint(write_to, "Igd_EnableCAppl %u\n", new_win->id);
648 	       spprint(write_to, "Igd_CopyGraph %u %u\n", new_win->id,win->id);
649 	       new_win->window_displayed = 1;
650 	    }
651 	    break;
652 
653 
654 	  case CTOI_RENAME_WINDOW:
655 	    /* change the title of the window */
656 	    receive_str(win->title);
657 	    if ( win->window_displayed ){
658 	       spprint(write_to,
659 		       "Igd_RenameWindow %u {%s}\n", win->id, win->title);
660 	    }
661 	    break;
662 
663 
664 	  case CTOI_RESIZE_VIEWABLE_WINDOW:
665 	    /* change the sizes of canvas */
666 	    receive_int_array(&win->desc.viewable_width, 1);
667 	    receive_int_array(&win->desc.viewable_height, 1);
668 	    if ( win->window_displayed ){
669 	       spprint(write_to, "Igd_ResizeViewableWindow %u %i %i\n",
670 		       win->id, win->desc.viewable_width,
671 		       win->desc.viewable_height);
672 	    }
673 	    break;
674 
675 
676 	  case CTOI_RESIZE_CANVAS:
677 	    /* change the size of the canvas */
678 	    receive_int_array(&win->desc.canvas_width, 1);
679 	    receive_int_array(&win->desc.canvas_height, 1);
680 	    if ( win->window_displayed ){
681 	       spprint(write_to, "Igd_ResizeCanvas %u %i %i\n", win->id,
682 		       win->desc.canvas_width, win->desc.canvas_height);
683 	    }
684 	    break;
685 
686 
687 	  case WAITING_TO_GET_A_COPY:
688 	    /* Read out the name of the source-graph from the pipe.
689 	       If the source-graph is waiting to be copied, source and
690 	       target have found each other */
691 	    receive_str(win->source) ;
692 	    win->copy_status = 2;
693 
694 	    j = find_window(dgp->window_num, dgp->windows, win->source);
695 	    if ( j >= 0 && dgp->windows[j]->copy_status == 1 ) {
696 	       /* source graph exists and it is waiting to be copied */
697 	       source_win = dgp->windows[j];
698 
699 	       /* copy the data structure */
700 	       copy_window_structure(win, source_win);
701 
702 	       /* if the window is displayed, change picture */
703 	       if ( win->window_displayed ) {
704 		  display_graph_on_canvas(win, write_to);
705 	       }
706 
707 	       /* zero out the copy stati */
708 	       win->copy_status = 0;
709 	       win->source[0] = 0;
710 	       source_win->copy_status = 0;
711 	       source_win->target[0] = 0;
712 	    }
713 	    break;
714 
715 
716 	  case WAITING_TO_BE_COPIED:
717 	    /* Read out the name of the target graph from the pipe.
718 	       If the target-graph is waiting to get a copy, source and
719 	       target have found each other. */
720 	    receive_str(win->target);
721 	    win->copy_status = 1;
722 
723 	    j = find_window(dgp->window_num, dgp->windows, win->target);
724 	    if ( j >= 0 && dgp->windows[j]->copy_status == 2 ) {
725 	       /* target exists and waiting for a copy */
726 	       target_win = dgp->windows[j];
727 
728 	       /* copy the data structure */
729 	       copy_window_structure(target_win, win);
730 
731 	       /* if the target window is displayed, update the picture */
732 	       if ( target_win->window_displayed ) {
733 		  display_graph_on_canvas(target_win, write_to);
734 	       }
735 
736 	       /* zero out the copy stati */
737 	       win->copy_status = 0;
738 	       win->target[0] = 0;
739 	       target_win->copy_status = 0;
740 	       target_win->source[0] = 0;
741 	    }
742 	    break;
743 
744 
745 	  case CTOI_MODIFY_GRAPH:
746 	    /* Make changes in the graph. The data structure is updated,
747 	       and if the window is displayed, the picture gets updated, too */
748 
749 	    /* The message is in keyword - description pairs, with the
750 	       END_OF_MESSAGE keyword at the end. We switch on the keyword */
751 
752 	    do {
753 	       receive_int_array(&keyword, 1);
754 
755 	       switch ( keyword ) {
756 
757 		case MODIFY_ADD_NODES:
758 		  /* same format as in SET_GRAPH */
759 		  receive_int_array(&add_nodenum, 1);
760 		  if ( add_nodenum ) {
761 		     g = &(win->g);
762 		     nodenum = g->nodenum;
763 		     nodes = g->nodes = (dg_node *)
764 			realloc(g->nodes,
765 				(nodenum + add_nodenum) * sizeof(dg_node));
766 		     for (j = 0, new_nodenum = nodenum; j < add_nodenum; j++) {
767 			read_node_desc_from_pvm(nodes+new_nodenum, win);
768 			if (find_node(nodes[new_nodenum].node_id, g) < 0)
769 			   new_nodenum++;
770 		     }
771 		     g->nodenum = new_nodenum;
772 
773 		     if ( win->window_displayed ) {
774 			for ( j = nodenum; j < new_nodenum; j++ ) {
775 			   nod = nodes + j;
776 			   spprint(write_to,
777 				   "Igd_MakeNode %u %i %i %i {%s} {%s} %i\n",
778 				   win->id, nod->node_id, nod->posx,
779 				   nod->posy, nod->label, nod->dash,
780 				   nod->radius);
781 			   if ( *nod->weight != 0 ){
782 			      spprint(write_to,
783 				      "Igd_MakeNodeWeight %u %i {%s}\n",
784 				      win->id, nod->node_id, nod->weight);
785 			   }
786 			}
787 		     }
788 		  }
789 
790 		  break;
791 
792 
793 		case MODIFY_CHANGE_WEIGHTS_OF_NODES:
794 		  /* change weights of nodes. nodes not in the graph or nodes
795 		     already deleted are skipped, no error message is given. */
796 		  g = &(win->g);
797 		  receive_int_array(&change_nodenum, 1);
798 		  for ( j = 0; j < change_nodenum; j++ ) {
799 		     receive_int_array(&node_id, 1);
800 		     receive_str(new_weight);
801 		     if ( (k = find_node(node_id, g)) >= 0 ) {
802 			strcpy(g->nodes[k].weight, new_weight);
803 			if ( win->window_displayed ) {
804 			   strcpy(old_weight, g->nodes[k].weight);
805 			   if ( *old_weight != 0 ) {
806 			      if ( *new_weight != 0 ) {
807 				 spprint(write_to,
808 					 "Igd_ChangeOneNodeWeight %u %i {%s}\n"
809 					 , win->id, node_id, new_weight);
810 			      } else {
811 				 /* new weight == 0 */
812 				 spprint(write_to,
813 					 "Igd_DeleteNodeWeight %u %i\n",
814 					 win->id, node_id);
815 			      }
816 			   } else {
817 			      /* no weight before */
818 			      if ( *new_weight != 0 ) {
819 				 spprint(write_to,
820 					 "Igd_MakeNodeWeight %u %i {%s}\n",
821 					 win->id, node_id, new_weight);
822 			      }
823 			   }
824 			}
825 		     }
826 		  }
827 		  break;
828 
829 
830 		case MODIFY_CHANGE_LABELS_OF_NODES:
831 		  /* change labels of nodes. nodes not in the graph or nodes
832 		     already deleted are skipped, no error message is given */
833 		  g = &(win->g);
834 		  receive_int_array(&change_nodenum, 1);
835 		  for ( j = 0; j < change_nodenum; j++ ) {
836 		     receive_int_array(&node_id, 1);
837 		     receive_str(new_label);
838 		     if ( (k = find_node(node_id, g)) >= 0 ) {
839 			strcpy(g->nodes[k].label, new_label);
840 			if ( win->window_displayed ) {
841 			   spprint(write_to,
842 				   "Igd_ChangeOneNodeLabel %u %i {%s}\n",
843 				   win->id, node_id, new_label);
844 			}
845 		     }
846 		  }
847 		  break;
848 
849 
850 		case MODIFY_CHANGE_DASH_OF_NODES:
851 		  /* change dash pattern of individual nodes. nodes not in the
852 		     graph will not cause error messages */
853 		  g = &(win->g);
854 		  receive_int_array(&change_nodenum, 1);
855 		  for ( j = 0; j < change_nodenum; j++ ) {
856 		     receive_int_array(&node_id, 1);
857 		     receive_str(new_dash);
858 		     if ( (k = find_node(node_id, g)) >= 0 ) {
859 			strcpy(g->nodes[k].dash, new_dash);
860 			if ( win->window_displayed ){
861 			   spprint(write_to,
862 				   "Igd_ChangeOneNodeDash %u %i {%s}\n",
863 				   win->id, node_id, new_dash);
864 			}
865 		     }
866 		  }
867 		  break;
868 
869 
870 		case MODIFY_CHANGE_RADII_OF_NODES:
871 		  /* change radii of individual nodes. nodes not in the
872 		     graph will not cause error messages */
873 		  g = &(win->g);
874 		  receive_int_array(&change_nodenum, 1);
875 		  for ( j = 0; j < change_nodenum; j++ ) {
876 		     receive_int_array(&node_id, 1);
877 		     receive_int_array(&new_radius, 1);
878 		     if ( (k = find_node(node_id, g)) >= 0 ) {
879 			g->nodes[k].radius = new_radius;
880 			if ( win->window_displayed ){
881 			   spprint(write_to,
882 				   "Igd_ChangeOneNodeRadius %u %i %i\n",
883 				   win->id, node_id, new_radius);
884 			}
885 		     }
886 		  }
887 		  break;
888 
889 
890 		case MODIFY_DELETE_NODES:
891 		  /* nodes not in the graph will not cause error messages */
892 		  receive_int_array(&delete_nodenum, 1);
893 		  if ( delete_nodenum ) {
894 		     g = &(win->g);
895 		     old_deleted_nodenum = g->deleted_nodenum;
896 		     for ( j = 0; j < delete_nodenum; j++ ) {
897 			receive_int_array(&node_id, 1);
898 			if ( (k = find_node(node_id, g)) >= 0 ) {
899 			   g->nodes[k].deleted = 1;
900 			   g->deleted_nodenum++;
901 			   if ( win->window_displayed ){
902 			      spprint(write_to,
903 				      "Igd_DeleteNode %u %i\n", win->id,
904 				      node_id);
905 			   }
906 			}
907 		     }
908 		     if ( g->deleted_nodenum > old_deleted_nodenum ) {
909 			/* mark edges that have at least one deleted endpoint
910 			   to be deleted. Igd_DeleteNode already took care of
911 			   deleting these edges from the picture */
912 			for (k=g->edgenum-1, edg=g->edges; k >= 0; k--, edg++)
913 			   if ( ! edg->deleted &&
914 				((find_node(edg->tail, g) < 0) ||
915 				 (find_node(edg->head, g) < 0))){
916 			      edg->deleted = 1;
917 			      g->deleted_edgenum++;
918 			   }
919 		     }
920 		     /* if too many nodes and/or edges have been deleted,
921 			compress the graph */
922 		     if ( g->deleted_nodenum > 0.1 * g->nodenum ||
923 			 g->deleted_edgenum > 0.1 * g->edgenum )
924 			compress_graph(g);
925 		  }
926 
927 		  break;
928 
929 
930 		case MODIFY_ADD_EDGES:
931 		  /* same format as in SET_GRAPH. Nonvalid edges (one or
932 		   both endpoints is not in the graph will not cause an error
933 		   message. */
934 		  receive_int_array(&add_edgenum, 1);
935 		  if ( add_edgenum ) {
936 		     g = &(win->g);
937 		     edgenum = g->edgenum;
938 		     edges = g->edges = (dg_edge *)
939 			realloc(g->edges,
940 				(edgenum+add_edgenum)*sizeof(dg_edge));
941 		     for (j = 0, new_edgenum = edgenum; j < add_edgenum; j++) {
942 			edg = edges + new_edgenum;
943 			read_edge_desc_from_pvm(edg, win);
944 			if ((find_edge(edg->edge_id, g) < 0) &&
945 			    (find_node(edg->tail, g) >= 0) &&
946 			    (find_node(edg->head, g) >= 0))
947 			   new_edgenum++;
948 		     }
949 		     g->edgenum = new_edgenum;
950 
951 		     if ( win->window_displayed ) {
952 			for ( j = edgenum; j < new_edgenum; j++ ) {
953 			   edg = edges + j;
954 			   spprint(write_to, "Igd_MakeEdge %u %i %i %i {%s}\n",
955 				   win->id, edg->edge_id, edg->tail,
956 				   edg->head, edg->dash);
957 			   if ( *edg->weight != 0 ){
958 			      spprint(write_to,
959 				      "Igd_MakeEdgeWeight %u %i {%s}\n",
960 				      win->id, edg->edge_id, edg->weight);
961 			   }
962 			}
963 		     }
964 		  }
965 
966 		  break;
967 
968 
969 		case MODIFY_CHANGE_WEIGHTS_OF_EDGES:
970 		  /* change weights of edges. edges not in the graph or edges
971 		     already deleted are skipped, no error message is given. */
972 		  g = &(win->g);
973 		  receive_int_array(&change_edgenum, 1);
974 		  for ( j = 0; j < change_edgenum; j++ ) {
975 		     receive_int_array(&edge_id, 1);
976 		     receive_str(new_weight);
977 		     if ( (k = find_edge(edge_id, g)) >= 0 ) {
978 			strcpy(g->edges[k].weight, new_weight);
979 			if ( win->window_displayed ) {
980 			   strcpy(old_weight, g->edges[k].weight);
981 			   if ( *old_weight != 0 ) {
982 			      if ( *new_weight != 0 ) {
983 				 spprint(write_to,
984 					 "Igd_ChangeOneEdgeWeight %u %i {%s}\n"
985 					 , win->id, edge_id, new_weight);
986 			      } else {
987 				 /* new weight : 0 */
988 				 spprint(write_to,
989 					 "Igd_DeleteEdgeWeight %u %i\n",
990 					 win->id, edge_id);
991 			      }
992 			   } else {
993 			      /* no weight before */
994 			      if ( *new_weight != 0 ) {
995 				 spprint(write_to,
996 					 "Igd_MakeEdgeWeight %u %i {%s}\n",
997 					 win->id, edge_id, new_weight);
998 			      }
999 			   }
1000 			}
1001 		     }
1002 		  }
1003 
1004 		  break;
1005 
1006 
1007 		case MODIFY_CHANGE_DASH_OF_EDGES:
1008 		  /* change dash pattern of individual edges. edges not in the
1009 		     graph will not cause error messages */
1010 		  g = &(win->g);
1011 		  receive_int_array(&change_edgenum, 1);
1012 		  for ( j = 0; j < change_edgenum; j++ ) {
1013 		     receive_int_array(&edge_id, 1);
1014 		     receive_str(new_dash);
1015 		     if ( (k = find_edge(edge_id, g)) >= 0 ) {
1016 			strcpy(g->edges[k].dash, new_dash);
1017 			if ( win->window_displayed ){
1018 			   spprint(write_to,
1019 				   "Igd_ChangeOneEdgeDash %u %i {%s}\n",
1020 				   win->id, edge_id, new_dash);
1021 			}
1022 		     }
1023 		  }
1024 
1025 		  break;
1026 
1027 
1028 		case MODIFY_DELETE_EDGES:
1029 		  /* edges not in the graph will not cause error messages */
1030 		  g = &(win->g);
1031 		  receive_int_array(&delete_edgenum, 1);
1032 		  for ( j = 0; j < delete_edgenum; j++ ) {
1033 		     receive_int_array(&edge_id, 1);
1034 		     if ( (k = find_edge(edge_id, g)) >= 0 ) {
1035 			g->edges[k].deleted = 1;
1036 			g->deleted_edgenum++;
1037 			if ( win->window_displayed ) {
1038 			   spprint(write_to, "Igd_DeleteEdge %u %i\n",
1039 				   win->id, edge_id);
1040 			}
1041 		     }
1042 		  }
1043 		  /* if too many edges have been deleted, compress the
1044 		     graph */
1045 		  if ( g->deleted_edgenum > 0.1 * g->edgenum )
1046 		     compress_graph(g);
1047 
1048 		  break;
1049 
1050 
1051 		case MODIFY_DELETE_ALL_EDGES:
1052 		  /* will delete all edges from the graph */
1053 		  g = &(win->g);
1054 		  if ( win->window_displayed ) {
1055 		     for ( j = 0; j < g->edgenum; j++ )
1056 			if ( ! g->edges[j].deleted ){
1057 			   spprint(write_to, "Igd_DeleteEdge %u %i\n",
1058 				   win->id, g->edges[j].edge_id);
1059 			}
1060 		  }
1061 		  FREE(g->edges);
1062 		  g->edgenum = 0;
1063 
1064 		  break;
1065 
1066 		case MODIFY_END_OF_MESSAGE:
1067 		  break;
1068 
1069 
1070 		default:
1071 		  printf("Unrecognized keyword %i\n", keyword);
1072 		  break;
1073 
1074 
1075 	       } /* end switch (keyword) */
1076 
1077 	    } while ( keyword != MODIFY_END_OF_MESSAGE );
1078 
1079 	    break;
1080 
1081 
1082 	  case CTOI_CLEAR_MESSAGE:
1083 	    if ( win->window_displayed ) {
1084 	       spprint(write_to, "Igd_CApplClearCmsg %u\n", win->id);
1085 	    }
1086 	    break;
1087 
1088 	  case CTOI_PRINT_MESSAGE:
1089 	    if ( win->window_displayed ) {
1090 	       str = malloc(bytes);
1091 	       receive_str(str);
1092 	       spprint(write_to, "Igd_CApplSetCmsg %u {%s}\n", win->id, str);
1093 	       FREE(str);
1094 	    }
1095 	    break;
1096 
1097 	  case CTOI_APPEND_MESSAGE:
1098 	    if ( win->window_displayed ) {
1099 	       str = malloc(bytes);
1100 	       receive_str(str);
1101 	       spprint(write_to, "Igd_CApplAppendCmsg %u {%s}\n", win->id,str);
1102 	       FREE(str);
1103 	    }
1104 	    break;
1105 
1106 	  default:
1107 	    printf("Unknown message tag: %i\n", msgtag);
1108 	    break;
1109 
1110 	 } /* end switch (msgtag) */
1111 
1112 	 freebuf(r_bufid);
1113       } /* end for */
1114 
1115    } /* end while */
1116    return(0);
1117 }
1118 
1119 
1120 /*===========================================================================*/
1121 
1122 /*===========================================================================*\
1123  * Find the window with the given name in windows.
1124 \*===========================================================================*/
1125 
find_window(int window_num,window ** windows,char * name)1126 int find_window(int window_num, window **windows, char *name)
1127 {
1128    int i;
1129 
1130    for ( i = window_num - 1; i >= 0; i-- )
1131       if ( strcmp(windows[i]->name, name) == 0 )
1132 	 break;
1133 
1134    return(i);
1135 }
1136 
1137 /*===========================================================================*/
1138 
1139 /*===========================================================================*\
1140  * Read out the description of a node from pvm buffer
1141 \*===========================================================================*/
1142 
read_node_desc_from_pvm(dg_node * nod,window * win)1143 void read_node_desc_from_pvm(dg_node *nod, window *win)
1144 {
1145    int key;
1146 
1147    receive_int_array(&nod->node_id, 1);
1148    receive_int_array(&nod->posx, 1);
1149    receive_int_array(&nod->posy, 1);
1150    receive_int_array(&key, 1);
1151 
1152    if ( key & 0x08 ){
1153       receive_str(nod->weight);
1154    }else{
1155       *nod->weight = 0;
1156    }
1157    if ( key & 0x04 ) {
1158       receive_str(nod->label);
1159    } else {
1160       sprintf(nod->label, "%i", nod->node_id);
1161    }
1162    if ( key & 0x02 ) {
1163       receive_str(nod->dash);
1164    } else {
1165       strcpy(nod->dash, win->desc.node_dash);
1166    }
1167    if ( key & 0x01 ) {
1168       receive_int_array(&nod->radius, 1);
1169    } else {
1170       nod->radius = win->desc.node_radius;
1171    }
1172    nod->deleted = FALSE;
1173 }
1174 
1175 /*===========================================================================*/
1176 
1177 /*===========================================================================*\
1178  * Read out the description of an edge from pvm buffer
1179 \*===========================================================================*/
1180 
read_edge_desc_from_pvm(dg_edge * edg,window * win)1181 void read_edge_desc_from_pvm(dg_edge *edg, window *win)
1182 {
1183    int key;
1184 
1185    receive_int_array(&edg->edge_id, 1);
1186    receive_int_array(&edg->tail, 1);
1187    receive_int_array(&edg->head, 1);
1188    receive_int_array(&key, 1);
1189    if ( key & 0x08 ){
1190       receive_str(edg->weight);
1191    }else{
1192       *edg->weight = 0;
1193    }
1194    if ( key & 0x02 ) {
1195       receive_str(edg->dash);
1196    } else {
1197       strcpy(edg->dash, win->desc.edge_dash);
1198    }
1199    edg->deleted = FALSE;
1200 }
1201 
1202 /*===========================================================================*/
1203 
1204 /*===========================================================================*\
1205  * Find the index of node with node_id in the graph.
1206 \*===========================================================================*/
1207 
find_node(int node_id,dg_graph * g)1208 int find_node(int node_id, dg_graph *g)
1209 {
1210    int i;
1211 
1212    for ( i = g->nodenum-1; i >= 0; i-- )
1213       if ( g->nodes[i].node_id == node_id )
1214 	 break;
1215 
1216    if ( i >= 0 && ! g->nodes[i].deleted ) {
1217       return(i);
1218    } else {
1219       return(-1);
1220    }
1221 
1222    return(-1);
1223 }
1224 
1225 /*===========================================================================*/
1226 
1227 /*===========================================================================*\
1228  * Find the index of edge with edge_id in the graph.
1229 \*===========================================================================*/
1230 
find_edge(int edge_id,dg_graph * g)1231 int find_edge(int edge_id, dg_graph *g)
1232 {
1233    int i;
1234 
1235    for ( i = g->edgenum-1; i >= 0; i-- )
1236       if ( g->edges[i].edge_id == edge_id )
1237 	 break;
1238 
1239    if ( i >= 0 && ! g->edges[i].deleted ) {
1240       return(i);
1241    } else {
1242       return(-1);
1243    }
1244 
1245    return(-1);
1246 }
1247 
1248 /*===========================================================================*/
1249 
1250 /*===========================================================================*\
1251  * Compess the graph: delete nodes and edges that have been marked.
1252 \*===========================================================================*/
1253 
compress_graph(dg_graph * g)1254 void compress_graph(dg_graph *g)
1255 {
1256    dg_node *nodes = g->nodes;
1257    dg_edge *edges = g->edges;
1258    int new_nodenum, new_edgenum;
1259    int i;
1260 
1261    if ( g->deleted_nodenum ) {
1262       /* find the first deleted node */
1263       for ( i = 0; i < g->nodenum; i++ ) {
1264 	 if ( nodes[i].deleted )
1265 	    break;
1266       }
1267 
1268       for ( new_nodenum = i; i < g->nodenum; i++ ) {
1269 	 if ( ! nodes[i].deleted )
1270 	    nodes[new_nodenum++] = nodes[i];
1271 
1272       }
1273 
1274       g->nodes = (dg_node *) realloc(nodes, new_nodenum * sizeof(dg_node));
1275       g->nodenum = new_nodenum;
1276       g->deleted_nodenum = 0;
1277    }
1278 
1279    if ( g->deleted_edgenum ) {
1280       /* find the first deleted edge */
1281       for ( i = 0; i < g->edgenum; i++ ) {
1282 	 if ( edges[i].deleted )
1283 	    break;
1284       }
1285 
1286       for ( new_edgenum = i; i < g->edgenum; i++ ) {
1287 	 if ( ! edges[i].deleted )
1288 	    edges[new_edgenum++] = edges[i];
1289 
1290       }
1291 
1292       g->edges = (dg_edge *) realloc(edges, new_edgenum * sizeof(dg_edge));
1293       g->edgenum = new_edgenum;
1294       g->deleted_edgenum = 0;
1295    }
1296 
1297 }
1298 
1299 /*===========================================================================*/
1300 
1301 /*===========================================================================*\
1302  * Copy the source window into target window's structure.
1303  * The following will be copied over: desc and g.
1304  * It is assumed that space is already allocated for the target_window.
1305 \*===========================================================================*/
1306 
copy_window_structure(window * target_win,window * source_win)1307 void copy_window_structure(window *target_win, window *source_win)
1308 {
1309    int nodenum = source_win->g.nodenum;
1310    int edgenum = source_win->g.edgenum;
1311 
1312    target_win->desc = source_win->desc;
1313 
1314    FREE(target_win->g.nodes);
1315    FREE(target_win->g.edges);
1316 
1317    if ( (target_win->g.nodenum = nodenum) ) {
1318       target_win->g.nodes = (dg_node *) malloc(nodenum * sizeof(dg_node));
1319       memcpy(target_win->g.nodes, source_win->g.nodes,
1320 	     nodenum * sizeof(dg_node));
1321    }
1322 
1323    if ( (target_win->g.edgenum = edgenum) ) {
1324       target_win->g.edges = (dg_edge *) malloc(edgenum * sizeof(dg_edge));
1325       memcpy(target_win->g.edges, source_win->g.edges,
1326 	     edgenum * sizeof(dg_edge));
1327    }
1328 }
1329 
1330 /*===========================================================================*/
1331 
1332 /*===========================================================================*\
1333  * Display the graph in window's data structure on the canvas.
1334  * write_to is teh handle to wish.
1335 \*===========================================================================*/
1336 
display_graph_on_canvas(window * win,FILE * write_to)1337 void display_graph_on_canvas(window *win, FILE *write_to)
1338 {
1339    win_desc *desc = &(win->desc);
1340    dg_graph *g = &(win->g);
1341    int j;
1342    dg_node *nod;
1343    dg_edge *edg;
1344 
1345    if ( win->window_displayed ) {
1346 
1347       /* need to erase the window then reset the window descriptions */
1348       spprint(write_to, "Igd_EraseWindow %u\n", win->id);
1349       spprint(write_to, "Igd_SetAndExecuteWindowDesc %u %i %i %i %i %i %i %i {%s} {%s} %i %i %i %f %s %s %s\n",
1350 	      win->id, desc->canvas_width, desc->canvas_height,
1351 	      desc->viewable_width, desc->viewable_height,
1352 	      desc->disp_nodelabels, desc->disp_nodeweights,
1353 	      desc->disp_edgeweights, desc->node_dash, desc->edge_dash,
1354 	      desc->node_radius, desc->interactive_mode,
1355 	      desc->mouse_tracking, desc->scale_factor, desc->nodelabel_font,
1356 	      desc->nodeweight_font, desc->edgeweight_font);
1357 
1358    } else {
1359 
1360       /* create window and set window description */
1361       spprint(write_to, "Igd_SetWindowDesc %u %i %i %i %i %i %i %i {%s} {%s} %i %i %i %f %s %s %s\n",
1362 	      win->id, desc->canvas_width, desc->canvas_height,
1363 	      desc->viewable_width, desc->viewable_height,
1364 	      desc->disp_nodelabels, desc->disp_nodeweights,
1365 	      desc->disp_edgeweights, desc->node_dash, desc->edge_dash,
1366 	      desc->node_radius, desc->interactive_mode,
1367 	      desc->mouse_tracking, desc->scale_factor, desc->nodelabel_font,
1368 	      desc->nodeweight_font, desc->edgeweight_font);
1369       spprint(write_to, "Igd_InitWindow %u {%s}\n", win->id, win->title);
1370       spprint(write_to, "Igd_DisplayWindow %u\n", win->id);
1371       spprint(write_to, "Igd_EnableCAppl %u\n", win->id);
1372       win->window_displayed = 1;
1373    }
1374 
1375    /* now display the nodes and edges */
1376 
1377    if ( g->nodenum ) {
1378       for ( j = 0; j < g->nodenum; j++ ) {
1379 	 nod = g->nodes + j;
1380 	 if ( !nod->deleted ) {
1381 	    spprint(write_to, "Igd_MakeNode %u %i %i %i %s {%s} %i\n",
1382 		    win->id, nod->node_id, nod->posx, nod->posy,
1383 		    nod->label, nod->dash, nod->radius);
1384 	    if ( *nod->weight != 0 ){
1385 	       spprint(write_to, "Igd_MakeNodeWeight %u %i %s\n",
1386 		       win->id, nod->node_id, nod->weight);
1387 	    }
1388 	 }
1389       } /* endfor j */
1390    }
1391    if ( g->edgenum ) {
1392       for ( j = 0; j < g->edgenum; j++ ) {
1393 	 edg = g->edges + j;
1394 	 if ( !edg->deleted ) {
1395 	    spprint(write_to, "Igd_MakeEdge %u %i %i %i {%s}\n",
1396 		    win->id, edg->edge_id, edg->tail, edg->head,
1397 		    edg->dash);
1398 	    if ( *edg->weight != 0 ){
1399 	       spprint(write_to, "Igd_MakeEdgeWeight %u %i {%s}\n",
1400 		       win->id, edg->edge_id, edg->weight);
1401 	    }
1402 	 }
1403       } /* endfor j */
1404    }
1405 }
1406 
1407 /*===========================================================================*/
1408 
1409 /*===========================================================================*\
1410  * Disassemble data structure windows[i].
1411 \*===========================================================================*/
1412 
free_window(int * pwindow_num,window ** windows,int i)1413 void free_window(int *pwindow_num, window **windows, int i)
1414 {
1415    window *w = windows[i];
1416 
1417    FREE(w->g.nodes);
1418    FREE(w->g.edges);
1419    /* free the bufid fifo */
1420    FREE(w->buf.bufid);
1421    if (w->user){
1422 #ifdef USE_SYM_APPLICATION
1423       user_dg_free_window(&w->user, w);
1424 #else
1425       FREE(w->user);
1426 #endif
1427    }
1428    FREE(w);
1429 
1430    /* delete pointer from windows */
1431    if ( i < *pwindow_num - 1 )
1432       windows[i] = windows[*pwindow_num-1];
1433    (*pwindow_num)--;
1434 }
1435 
1436 /*===========================================================================*/
1437 
copy_win_desc_from_par(window * win,dg_params * par)1438 void copy_win_desc_from_par(window *win, dg_params *par)
1439 {
1440    win->desc.canvas_width = par->canvas_width;
1441    win->desc.canvas_height = par->canvas_height;
1442    win->desc.viewable_width = par->viewable_width;
1443    win->desc.viewable_height = par->viewable_height;
1444 
1445    win->desc.disp_nodelabels = par->disp_nodelabels;
1446    win->desc.disp_nodeweights = par->disp_nodeweights;
1447    win->desc.disp_edgeweights = par->disp_edgeweights;
1448 
1449    strcpy(win->desc.node_dash, par->node_dash);
1450    strcpy(win->desc.edge_dash, par->edge_dash);
1451 
1452    win->desc.node_radius = par->node_radius;
1453    win->desc.interactive_mode = par->interactive_mode;
1454    win->desc.mouse_tracking = par->mouse_tracking;
1455    win->desc.scale_factor = par->scale_factor;
1456 
1457    strcpy(win->desc.nodelabel_font, par->nodelabel_font);
1458    strcpy(win->desc.nodeweight_font, par->nodeweight_font);
1459    strcpy(win->desc.edgeweight_font, par->edgeweight_font);
1460 }
1461 
1462 /*===========================================================================*/
1463 
set_window_desc_pvm(int key,window * win)1464 void set_window_desc_pvm(int key, window *win)
1465 {
1466    win_desc *desc = &win->desc;
1467 
1468    switch ( key ) {
1469     case CANVAS_WIDTH:
1470       receive_int_array(&desc->canvas_width, 1);
1471       break;
1472     case CANVAS_HEIGHT:
1473       receive_int_array(&desc->canvas_height, 1);
1474       break;
1475     case VIEWABLE_WIDTH:
1476       receive_int_array(&desc->viewable_width, 1);
1477       break;
1478     case VIEWABLE_HEIGHT:
1479       receive_int_array(&desc->viewable_height, 1);
1480       break;
1481     case DISP_NODELABELS:
1482       receive_int_array(&desc->disp_nodelabels, 1);
1483       break;
1484     case DISP_NODEWEIGHTS:
1485       receive_int_array(&desc->disp_nodeweights, 1);
1486       break;
1487     case DISP_EDGEWEIGHTS:
1488       receive_int_array(&desc->disp_edgeweights, 1);
1489       break;
1490     case NODE_DASH:
1491       receive_str(desc->node_dash);
1492       break;
1493     case EDGE_DASH:
1494       receive_str(desc->edge_dash);
1495       break;
1496     case NODE_RADIUS:
1497       receive_int_array(&desc->node_radius, 1);
1498       break;
1499     case INTERACTIVE_MODE:
1500       receive_int_array(&desc->interactive_mode, 1);
1501       break;
1502     case MOUSE_TRACKING:
1503       receive_int_array(&desc->mouse_tracking, 1);
1504       break;
1505     case SCALE_FACTOR:
1506       receive_dbl_array(&desc->scale_factor, 1);
1507       break;
1508     case NODELABEL_FONT:
1509       receive_str(desc->nodelabel_font);
1510       break;
1511     case NODEWEIGHT_FONT:
1512       receive_str(desc->nodeweight_font);
1513       break;
1514     case EDGEWEIGHT_FONT:
1515       receive_str(desc->edgeweight_font);
1516       break;
1517    }
1518 }
1519 
1520 /*===========================================================================*/
1521 
wait_for_you_can_die(dg_prob * dgp,FILE * write_to)1522 void wait_for_you_can_die(dg_prob *dgp, FILE *write_to)
1523 {
1524    int bufid, s_bufid, bytes, msgtag, sender;
1525 
1526    FREE(dgp->windows);
1527    /* invoke the Igd_QuitAll function */
1528    spprint(write_to, "Igd_QuitAll\n");
1529 
1530    if (dgp->waiting_to_die == 2 * TRUE)
1531       exit(0);
1532 
1533    while (TRUE){
1534       receive_msg(ANYONE, ANYTHING);
1535       bufinfo(bufid, &bytes, &msgtag, &sender);
1536       if (msgtag != CTOI_YOU_CAN_DIE){
1537 	 s_bufid = init_send(DataInPlace);
1538 	 send_msg(sender, ITOC_APPLICATION_KILLED);
1539 	 freebuf(s_bufid);
1540       }else{
1541 	 exit(0);
1542       }
1543    }
1544 }
1545 
1546 /*===========================================================================*/
1547 
init_dgwin(dg_prob * dgp,int sender,char * name,char * title)1548 window *init_dgwin(dg_prob *dgp, int sender, char *name, char *title)
1549 {
1550    window *win = (window *) calloc(1, sizeof(window));
1551 
1552    win->owner_tid = sender;
1553    strcpy(win->name, name);
1554    strcpy(win->title, title);
1555    win->id = dgp->next_id++;
1556    /* initialize buf_fifo */
1557    win->buf.bufid = (int *) malloc(127 * ISIZE);
1558    win->buf.bufspace = 127;
1559    win->buf.bufread = -1;
1560    win->buf.bufwrite = 0;
1561 
1562    dgp->window_num++;
1563    if (dgp->window_num == 1)
1564       dgp->windows = (window **) malloc( sizeof(window *) );
1565    else
1566       dgp->windows = (window **)
1567 	 realloc(dgp->windows, dgp->window_num * sizeof(window *));
1568    dgp->windows[dgp->window_num-1] = win;
1569 #ifdef USE_SYM_APPLICATION
1570    CALL_USER_FUNCTION( user_dg_init_window(&win->user, win) );
1571 #else
1572    win->user = NULL;
1573 #endif
1574    return(win);
1575 }
1576 
1577 /*===========================================================================*/
1578 
add_msg(window * win,int bufid)1579 void add_msg(window *win, int bufid)
1580 {
1581    register buf_fifo *buf = &win->buf;
1582 
1583    if (buf->bufread == -1){
1584       /* then bufwrite must be 0 */
1585       buf->bufid[0] = bufid;
1586       buf->bufread = 0;
1587       buf->bufwrite = 1;
1588       return;
1589    }
1590    if (buf->bufread == buf->bufwrite){
1591       /* the list of bufid's is full */
1592       int *newbufid  = (int *) malloc((buf->bufspace + 128) * ISIZE);
1593       memcpy(newbufid, buf->bufid + buf->bufread,
1594 	     (buf->bufspace - buf->bufread) * ISIZE);
1595       memcpy(newbufid + (buf->bufspace - buf->bufread), buf->bufid,
1596 	     buf->bufread * ISIZE);
1597       FREE(buf->bufid);
1598       buf->bufid = newbufid;
1599       buf->bufread = 0;
1600       buf->bufwrite = buf->bufspace;
1601       buf->bufspace += 128;
1602    }
1603    buf->bufid[buf->bufwrite] = bufid;
1604    if (++buf->bufwrite == buf->bufspace)
1605       buf->bufwrite = 0;
1606 }
1607 
1608 /*===========================================================================*/
1609 
get_next_msg(window * win)1610 int get_next_msg(window *win)
1611 {
1612    register buf_fifo *buf = &win->buf;
1613    int bufid = buf->bufid[buf->bufread];
1614 
1615    if (++buf->bufread == buf->bufspace)
1616       buf->bufread = 0;
1617    if (buf->bufread == buf->bufwrite){
1618       buf->bufread = -1;
1619       buf->bufwrite = 0;
1620    }
1621    return( bufid );
1622 }
1623 
1624 
1625