/* $Id: file.c,v 10.1 92/10/06 23:10:25 ca Exp $ */ /* Disk I/O routines, including read & write world file, and also write PS file to make hard copy of the world configuration */ #ifdef UNICOS #include #else /* UNICOS */ #include #endif /* UNICOS */ #include #include #include "sim.h" #include "q.h" #include "list.h" #include "event.h" #include "component.h" #include "simx.h" #include "log.h" #include "comptypes.h" #include "eventdefs.h" #include "peer.h" #ifndef NoX #include "xtables.h" #endif COMP_OBJECT pop_comp_window(); extern int seed; #ifdef DEBUG extern Log debug_log; #endif extern int doXstuff; /* Read a line, separating it into words. Spaces and tabs delimit words; Single or double quotes may be used to include spaces in a word. Also, '#' and newline delimit comments, which are eliminated. Returns a list of words. Enough space to hold the line must be passed in buf. Note that the pointers returned will point into buf. The list must be lq_delete()'d afterword. Finally, physical lines may be concatenated into longer logical lines by making the last character of the line a '\'. */ list * read_line(fp, buf) FILE *fp; char *buf; { char *s = buf, *start, delim; int comment = FALSE, quoted = FALSE; int c, c1; list *l; /* Make the blank list */ if (!(l = l_create())) return(l); while ((c = getc(fp)) != EOF) { if (c == '\n') break; if (comment) continue; if (c == '\\') { if ((c1 = getc(fp)) == '\n') continue; else ungetc(c1, fp); } if (c == '#') { comment = TRUE; continue; } if (!isspace(c)) { /* Do that word */ if (c == '\'' || c == '\"') { delim = c; quoted = TRUE; c = getc(fp); } start = s; *start = c; s++; while ((c = getc(fp)) != EOF) { if (c == '\\') { if ((c = getc(fp)) == '\n') continue; else ungetc(c, fp); } if (c == '#' && !quoted) { ungetc(c, fp); break; } if (c == '\n') { ungetc(c, fp); break; } if ((isspace(c) && !quoted) || (quoted && c == delim)) break; *s++ = c; } *s++ = '\0'; if (!l_addt(l, (caddr_t)start)) { lq_delete(l); return(NULL); } } quoted = FALSE; } /* If at EOF, get rid of the list. (This means that the file must be terminated with a newline for it to work correctly.) */ if (c == EOF) { lq_delete(l); l = NULL; } return(l); } /* Look for a component in the list by name. Must match exactly. */ Component * find_comp(l, name) list *l; char *name; { Component *c; for (c = (Component *)l->l_head; c; c = c->co_next) if (!strcmp(name, c->co_name)) return(c); return(NULL); } static make_stuff(c, p) Component *c; Param *p; { #ifndef NoX #ifndef MOTIF if (p->p_flags & MeterMask & doXstuff) if (pop_meter(c, p, 0, 0, 0, 0) == ERROR) p->p_flags &= ~MeterMask; /* Error--turn the meter flag off */ #endif #endif if (p->p_flags & LogMask) if (!log_param_create(c, p)) p->p_flags &= ~LogMask; /* Error--turn logging flag off */ } #define XMARGIN 10 /* Read the world file & create the world. Returns list of components. Will work with either "save" or "snapshot" files. */ list * read_world(name) char *name; { FILE *fp; int make_menu; int i, xpos, ypos, def_xpos = XMARGIN, def_ypos = 10; int xinc = 20, yinc = 20; caddr_t result; list *l, *clist; l_elt *le; char *cname, *type; char *s; Component *c1, *c2; Neighbor *n; Param *p; char b[1024]; #ifndef NoX #ifndef MOTIF if (doXstuff) { xinc = the_environment.component_window_width * 2; yinc = the_environment.component_window_height * 5; } #endif #endif /* NoX */ clist = l_create(); if (!(fp = fopen(name, "r"))) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "read_world: couldn't open world file '%s'", name); #endif free((char *)clist); return(NULL); } while (l = read_line(fp, b)) { if (l->l_len < 1) { /* Blank line */ lq_delete(l); continue; } s = (char *)l->l_head->le_data; ucase(s); /*********** Create a component, and initialize its parameters */ if (!strcmp(l->l_head->le_data, "COMPONENT")) { le = l->l_head->le_next; cname = (char *)le->le_data; type = (char *)le->le_next->le_data; #ifndef NoX if (doXstuff) { if (le->le_next->le_next) { xpos = atoi((char *)le->le_next->le_next->le_data); ypos = atoi((char *)le->le_next->le_next->le_next->le_data); } else { xpos = def_xpos; ypos = def_ypos; if ((def_xpos += xinc) >= 2*the_environment.x_center) { def_xpos = XMARGIN; def_ypos += yinc; } } } #endif /* NoX */ ucase(type); for (i = 0; *component_types[i].typename; i++) if (!strcmp(component_types[i].typename, type)) { c1 = (Component *)((*component_types[i].action)(NULL, NULL, EV_CREATE, NULL, cname)); c1->co_picture = NULL; break; } if (!*component_types[i].typename) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "unknown type of component"); #endif c1 = NULL; } /* Free up the list... */ lq_delete(l); /* Add this comp the list */ if (c1) { le_addt(clist, c1); /* Make the component's window */ #ifndef NoX if (doXstuff) { if (( c1->co_picture = (COMP_OBJECT)pop_comp_window((COMPONENT *)c1,xpos, ypos)) == NULL) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "Couldn't make component window"); #endif } } #endif /* NoX */ } /*** Read lines to initialize parameters & flags of the new component. Stop when blank line read. Even if create failed, read lines anyway just to get rid of them. */ /* Start with first param */ if (c1) p = (Param *)c1->co_params->q_head; make_menu = FALSE; while (l = read_line(fp, b)) { if (l->l_len < 1) break; /* Blank line; stop */ if (!c1) continue; /* no component--keep going */ ucase(l->l_head->le_data); /*** If info window, turn on flag. Don't actually put the info window up until later, tho' */ if (!strcmp(l->l_head->le_data, "INFOWINDOW")) { make_menu = TRUE; continue; } /*** Otherwise, could be PARAM or PFLAGS. If PARAM, initialize the param's value by calling p_input with the string & also initialize its p_flags if they are on the line. If PFLAGS, just set the flags of the next param. */ if (strcmp(l->l_head->le_data, "PFLAGS")) { /* It's *not* FLAGS, so init the value & check for p_flags. */ le = l->l_head->le_next; /* le word contains the value */ for (; p; p = p->p_next) { /* Cengiz Alaettinoglu added ModifyMask below */ if (p->p_flags & (InputMask | ModifyMask)) { (*p->p_input)(p, le->le_data, c1); /* If there is another word on the line, use it for p_flags */ if (le->le_next) { sscanf(le->le_next->le_data, "%x", &p->p_flags); /* And if yet another, use it for p_display_type */ if (le->le_next->le_next) { s = (char *)le->le_next->le_next->le_data; sscanf(s, "%x", &p->p_display_type); } } /* Create any meters, logs, etc. */ make_stuff(c1, p); p = p->p_next; break; } } } else { /*** It is "PFLAGS", set the p_flags */ if (p) { /* Only if haven't reached end of param q */ s = (char *)l->l_head->le_next->le_data; sscanf(s, "%x", &p->p_flags); /* If another word is on the line, use it for p_display_type */ if (l->l_head->le_next->le_next) { s = (char *)l->l_head->le_next->le_next->le_data; sscanf(s, "%x", &p->p_display_type); } /* Create any meters, logs, etc. */ make_stuff(c1, p); p = p->p_next; } } } if (l) lq_delete(l); /* Wipe out the list */ #ifndef NoX /* Pop up the infowindow if necessary. */ #ifndef MOTIF /* The XMotif module keeps infowindows in it`s own file. */ if (c1) if (make_menu & doXstuff) pop_info_window(c1); #endif #endif /* NoX */ } /*********** Make two components neighbors. */ else if (!strcmp(l->l_head->le_data, "NEIGHBOR") || !strcmp(l->l_head->le_data, "NEIGHBOR1")) { /* Find the components in the list */ c1 = find_comp(clist, l->l_head->le_next->le_data); c2 = find_comp(clist, l->l_head->le_next->le_next->le_data); le = l->l_head->le_next->le_next->le_next; /* p_flags, if any */ if (!c1) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "couldn't find component '%s' in list", l->l_head->le_next->le_data); #endif lq_delete(l); continue; } if (!c2) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "couldn't find component '%s' in list", l->l_head->le_next->le_next->le_data); #endif lq_delete(l); continue; } /* NEIGHBOR1 ==> only one call, and also check for parameter flags */ /* NEIGHBOR ==> two calls, no parameter flags check */ result = (*c1->co_action)(NULL, c1, EV_NEIGHBOR, NULL, c2); if (result && !strcmp(l->l_head->le_data, "NEIGHBOR")) { if (!(*c2->co_action)(NULL, c2, EV_NEIGHBOR, NULL, c1)) (*c1->co_action)(NULL, c1, EV_UNEIGHBOR, NULL, c2); #ifndef NoX #ifdef MOTIF else if (doXstuff) connect_two_components(c1->co_picture,c2->co_picture); #endif #endif /* NoX */ } else { #ifndef NoX #ifdef MOTIF if (doXstuff) if (result && (NULL!=find_neighbor(c2->co_neighbors, c1))) connect_two_components(c1->co_picture,c2->co_picture); #endif #endif /* NoX */ if (result && le) { /* Find c2 in c1's neighbor list */ n = find_neighbor(c1->co_neighbors, c2); sscanf(le->le_data, "%x", &n->n_p->p_flags); if (le->le_next) sscanf(le->le_next->le_data, "%x", &n->n_p->p_display_type); make_stuff(c1, n->n_p); /* Check for pflags for n->n_pp as well. */ le = le->le_next->le_next; if (n->n_pp && le) { sscanf(le->le_data, "%x", &n->n_pp->p_flags); le = le->le_next; if (le) sscanf(le->le_data, "%x", &n->n_pp->p_display_type); make_stuff(c1, n->n_pp); } /* This is ugly, but necessary. If the info window is up, destroy it & redraw it so that any params associated with this neighbor appear. */ #ifndef NoX #ifndef MOTIF if (c1->co_menu_up & doXstuff) { unpop_info_window(c1); pop_info_window(c1); } #endif #endif /* NoX */ } } lq_delete(l); } else if (!strncmp(l->l_head->le_data, "PEER", strlen("PEER"))) { /*************************** by Cengiz Alaettinoglu read peer stuff ****************************/ /* Find the components in the list */ c1 = find_comp(clist, l->l_head->le_next->le_data); c2 = find_comp(clist, l->l_head->le_next->le_next->le_data); le = l->l_head->le_next->le_next->le_next; /* p_flags, if any */ if (!c1) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "couldn't find component '%s' in list", l->l_head->le_next->le_data); #endif lq_delete(l); continue; } if (!c2) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "couldn't find component '%s' in list", l->l_head->le_next->le_next->le_data); #endif lq_delete(l); continue; } result = (*c1->co_action)(NULL, c1, EV_MK_PEER, NULL, c2); if (result) if (!(*c2->co_action)(NULL, c2, EV_MK_PEER, NULL, c1)); peer_add(c1, c2); lq_delete(l); } #ifdef DEBUG else dbg_write(debug_log, DBG_ERR, (Component *)NULL, "World file line begins with unknown word '%s'", l->l_head->le_data); #endif } fclose(fp); return(clist); } /**************************************************************** Two routines to save the world in a file. One just saves components, and neighbors, the other saves all of that along with the state of all meters, log files, and infowindows. Both types of save can be read by read_world (above). Neither one is particularily fast or efficient, but that's okay. */ /* save_world & save_snapshot are just stubs that call save_whatever with the appropriate flag set. */ save_world(clist, filename) list *clist; /* Linked list of all components */ char *filename; { return(save_whatever(clist, filename, FALSE)); } save_snapshot(clist, filename) list *clist; /* Linked list of all components */ char *filename; { return(save_whatever(clist, filename, TRUE)); } save_whatever(clist, filename, snap) list *clist; /* Linked list of all components */ char *filename; int snap; /* boolean flag */ { int x = 0, y = 0; Component *c1, *c2; Neighbor *n; Param *p; Socket *s; l_elt *le; FILE *fp; Peer_Rec *l; /* Open file */ if (!(fp = fopen(filename, "w"))) { #ifdef DEBUG dbg_write(debug_log, DBG_ERR, (Component *)NULL, "save_whatever: couldn't open %s for writing", filename); #endif return(FALSE); } /* Write time & seed to the file. */ if (snap) { fprintf (fp, "# Seed %d\n", seed); fprintf (fp, "# Time of snapshot (ticks) %u\n", ev_now() ); } /*** First write out all components */ for (c1 = (Component *)clist->l_head; c1; c1 = c1->co_next) { #ifndef NoX component_xy(c1, &x, &y); /* Position of the component */ #endif fprintf(fp, "component '%s' %s %d %d\n", c1->co_name, component_types[c1->co_type].typename, x, y); /* State of infowindows if snapshot */ if (snap && c1->co_menu_up) fputs("infowindow\n", fp); /* Print out any parameters */ for (p = (Param *)c1->co_params->q_head; p; p = p->p_next) { if (snap) { /* Save flags as well as value */ if (p->p_flags & (InputMask | ModifyMask)) { fprintf(fp, "param %s %x %x\t # %s\n", (*p->p_make_short_text)(c1, p), p->p_flags, p->p_display_type, (*p->p_make_text)(c1, p)); } else { fprintf(fp, "pflags %x %x", p->p_flags, p->p_display_type); if (p->p_make_text) { fprintf(fp, "\t # %s", (*p->p_make_text)(c1, p)); } else if (p->p_make_short_text) { fprintf(fp, "\t # %s: %s", p->p_name, (*p->p_make_short_text)(c1, p)); } fprintf (fp, "\n"); } } else { if (p->p_flags & (InputMask | ModifyMask)) fprintf(fp, "param %s\t # %s\n", (*p->p_make_short_text)(c1, p), (*p->p_make_text)(c1, p)); } } fputs("\n", fp); } /* Write out all neighborings (<- what a horrible word!) */ for (c1 = (Component *)clist->l_head; c1; c1 = c1->co_next) for (n = (Neighbor *)c1->co_neighbors->l_head; n; n = n->n_next) { if (snap && n->n_p != NULL) { fprintf(fp, "neighbor1 '%s' '%s' %x %x", c1->co_name, n->n_c->co_name, n->n_p->p_flags, n->n_p->p_display_type); if (n->n_pp != NULL) { fprintf(fp, " %x %x", n->n_pp->p_flags, n->n_pp->p_display_type); } fputs("\n", fp); } else fprintf(fp, "neighbor1 '%s' '%s'\n", c1->co_name, n->n_c->co_name); } fputs("\n", fp); /********************** by Cengiz Alaettinoglu save peers ************************/ for (l = (Peer_Rec *) (peer_list->l_head); l != (Peer_Rec *) NULL; l = l->next) fprintf(fp, "peer '%s' '%s'\n", l->c1->co_name, l->c2->co_name); fclose(fp); return(TRUE); } #ifndef NoX #ifndef MOTIF /* eric */ /** routine to make a PostScript program to print out the world. It looks for the file "basicstuff.PS", copies it, and adds onto the end of it. "basicstuff.PS" should include various support functions that I will write in PostScript. */ create_PS_file(comps, name) list *comps; char *name; { FILE *fp; char buf[512]; double scale; int backwindow_y; Component *component; /* component we are drawing lines from */ XCOMPONENT *xcomponent; /* xcomponent we are drawing lines from */ Neighbor *neigh; /* the component's neighbors */ XWindowAttributes info; /* x information about a window */ int x1, x2, y1, y2; /* x,y for a component and its neighbors */ Window this_window, neighbor_window; /* windows for a component and its neighbors */ /* Copy the initial stuff from "basicstuff.PS" to the new output file */ /* Check for existence and access permissions */ if (access("basicstuff.PS", R_OK) == -1) return(0); sprintf(buf, "cp basicstuff.PS \"%s\"", name); if (system(buf) != 0) return(0); if (!(fp = fopen(name, "a"))) return(0); /* Write the preliminaries to the PS file */ XGetWindowAttributes(the_environment.the_display, the_environment.back_window, &info); backwindow_y = info.height; scale = (7.75 * 72.0) / (info.width - 2*the_environment.control_window_width); fprintf(fp, "%f dup scale\n50 150 translate\n\n", scale); fprintf(fp, "/CompHeight %d def\n/CompWidth %d def\n\n", the_environment.component_window_height, the_environment.component_window_width); fprintf(fp, "2 setlinewidth\n\n"); /* Loop through each component, drawing connecting lines */ fprintf(fp, "newpath\n"); for (component = (COMPONENT *) comps->l_head; component != NULL; component = component->co_next) { register XCOMPONENT *xc; /* get the x and y coordinates, relative to the back window, for the component's window. */ xcomponent = (XCOMPONENT *) component->co_picture; x1 = xcomponent->x + xcomponent->width / 2; y1 = backwindow_y - (xcomponent->y + the_environment.component_window_height / 2); /* Loop through each of the component's neighbors */ for (neigh =(NEIGHBOR *) (component->co_neighbors->l_head); neigh; neigh = neigh->n_next) { /* Get the x and y coordinates for the neighboring window */ xcomponent = (XCOMPONENT *) neigh->n_c->co_picture; x2 = xcomponent->x + xcomponent->width / 2; y2 = backwindow_y - (xcomponent->y + the_environment.component_window_height / 2); /* Draw the connecting line. */ fprintf(fp, "%d %d moveto %d %d lineto\n", x1, y1, x2, y2); } } fprintf(fp, "stroke\n\n"); /* Now loop again, this time drawing each comp. */ for (component = (COMPONENT *) comps->l_head; component != NULL; component = component->co_next) { xcomponent = (XCOMPONENT *) component->co_picture; fprintf(fp, "(%s) %d %d printcomp\n", component->co_name, xcomponent->x, backwindow_y - xcomponent->y); } fprintf(fp, "\nshowpage\n"); fclose(fp); return(1); } #else create_PS_file() { } #endif /* MOTIF */ #endif /* NoX */