1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/special.c,v 1.19 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_SPECIAL_C_
22 
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25 
26 #include "animate.e"
27 #include "attr.e"
28 #include "auxtext.e"
29 #include "choice.e"
30 #include "cmd.e"
31 #include "color.e"
32 #include "cutpaste.e"
33 #include "cursor.e"
34 #include "dialog.e"
35 #include "drawing.e"
36 #include "dup.e"
37 #include "edit.e"
38 #include "exec.e"
39 #include "file.e"
40 #include "font.e"
41 #include "grid.e"
42 #include "group.e"
43 #include "list.e"
44 #include "mainloop.e"
45 #include "mainmenu.e"
46 #include "mark.e"
47 #include "menu.e"
48 #include "menuinfo.e"
49 #include "miniline.e"
50 #include "msg.e"
51 #include "move.e"
52 #include "names.e"
53 #include "obj.e"
54 #include "page.e"
55 #include "pattern.e"
56 #include "poly.e"
57 #include "raster.e"
58 #include "rect.e"
59 #include "remote.e"
60 #include "ruler.e"
61 #include "scroll.e"
62 #include "select.e"
63 #include "setup.e"
64 #include "special.e"
65 #include "stk.e"
66 #include "stretch.e"
67 #include "strtbl.e"
68 #include "tangram2.e"
69 #include "text.e"
70 #include "util.e"
71 #include "version.e"
72 #include "wb.e"
73 
74 int placingTopObj=FALSE;
75 int connectingPortsByWire=FALSE;
76 int connectingPortsFromInternalCommand=TRUE;
77 
78 char gszAttrSeparator[]=
79 "// -------- attribute separator (please do not modify or delete) -------- //";
80 
81 static int showWireSignalName=TRUE;
82 static int gnPinWarning=FALSE;
83 
84 static
CreatePinObj(obj_ptr1,obj_ptr2,sym_count)85 struct ObjRec *CreatePinObj(obj_ptr1, obj_ptr2, sym_count)
86    struct ObjRec *obj_ptr1, *obj_ptr2;
87    int sym_count;
88 {
89    struct ObjRec *obj_ptr=NULL;
90    struct ObjRec *saved_top_obj=topObj;
91    struct ObjRec *saved_bot_obj=botObj;
92    int cx1, cy1, cx2, cy2;
93 
94    curPage->top = topObj = NULL;
95    curPage->bot = botObj = NULL;
96    if (sym_count == 1) {
97       topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
98       if (topSel == NULL) FailAllocMessage();
99       topObj = botObj = obj_ptr1;
100       topSel->obj = obj_ptr1;
101       topSel->next = topSel->prev = NULL;
102       numObjSelected = 1;
103 
104       GroupSingleObj(TRUE);
105       obj_ptr = topSel->obj;
106       RemoveAllSel();
107    } else {
108       if (obj_ptr2->fattr != NULL) {
109          obj_ptr = obj_ptr2;
110          obj_ptr2 = obj_ptr1;
111          obj_ptr1 = obj_ptr;
112       }
113       cx1 = ((obj_ptr1->obbox.ltx+obj_ptr1->obbox.rbx)>>1);
114       cy1 = ((obj_ptr1->obbox.lty+obj_ptr1->obbox.rby)>>1);
115       cx2 = ((obj_ptr2->obbox.ltx+obj_ptr2->obbox.rbx)>>1);
116       cy2 = ((obj_ptr2->obbox.lty+obj_ptr2->obbox.rby)>>1);
117       MoveObj(obj_ptr2, cx1-cx2, cy1-cy2);
118       obj_ptr1->next = obj_ptr2;
119       obj_ptr1->prev = NULL;
120       obj_ptr2->next = NULL;
121       obj_ptr2->prev = obj_ptr1;
122       CreateGroupObj(obj_ptr1, obj_ptr2);
123       obj_ptr = topObj;
124    }
125    AdjObjBBox(obj_ptr);
126    obj_ptr->type = OBJ_PIN;
127 
128    curPage->top = topObj = saved_top_obj;
129    curPage->bot = botObj = saved_bot_obj;
130 
131    if (!gnPinWarning) {
132       gnPinWarning = TRUE;
133       strcpy(gszMsgBox, TgLoadString(STID_WARN_PIN_NOT_SUPPORTED));
134       if (PRTGIF) {
135          fprintf(stderr, "%s\n", gszMsgBox);
136       } else {
137          MsgBox(gszMsgBox, TOOL_NAME, STOP_MB);
138       }
139    }
140    return obj_ptr;
141 }
142 
ReadSymbol(FP,FileType)143 struct ObjRec *ReadSymbol(FP, FileType)
144    FILE *FP;
145    int FileType;
146 {
147    register struct AttrRec *attr_ptr;
148    struct ObjRec *obj_ptr, *obj_ptr1=NULL, *obj_ptr2=NULL;
149    int read_status, sym_count=0;
150 
151    SetWatchCursor(drawWindow);
152    SetWatchCursor(mainWindow);
153 
154    importingFile = TRUE; /* ignore 'state' info but set fileVersion */
155    readingPageNum = loadedCurPageNum = 0;
156    foundGoodStateObject = FALSE;
157    while ((read_status=ReadObj(FP, &obj_ptr)) == TRUE) {
158       if (obj_ptr != NULL) {
159          if (obj_ptr->type == OBJ_SYM) {
160             int done=FALSE;
161 
162             UnlockAnObj(obj_ptr);
163             obj_ptr->type = OBJ_ICON;
164 
165             attr_ptr = obj_ptr->lattr;
166             for ( ; attr_ptr != NULL; attr_ptr = attr_ptr->prev) {
167                attr_ptr->inherited = TRUE;
168             }
169             if (FileType == SYM_FILE_TYPE) {
170                done = TRUE;
171             } else {
172                if (obj_ptr1 == NULL) {
173                   obj_ptr1 = obj_ptr;
174                } else if (obj_ptr2 == NULL) {
175                   obj_ptr2 = obj_ptr;
176                }
177                if (++sym_count >= 2) {
178                   obj_ptr = CreatePinObj(obj_ptr1, obj_ptr2, sym_count);
179                   done = TRUE;
180                }
181             }
182             if (done) {
183                importingFile = FALSE;
184                SetDefaultCursor(mainWindow);
185                ShowCursor();
186                return obj_ptr;
187             }
188          } else {
189             FreeObj(obj_ptr);
190          }
191       }
192    }
193    importingFile = FALSE;
194    if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
195       RedrawColorWindow();
196    }
197    obj_ptr = NULL;
198    if (read_status == INVALID) {
199       sprintf(gszMsgBox, TgLoadString(STID_FILE_VER_ABORT_READ_SYMBOL),
200             fileVersion, TOOL_NAME, homePageURL);
201       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
202    } else if (FileType == PIN_FILE_TYPE && sym_count == 1) {
203       obj_ptr = CreatePinObj(obj_ptr1, obj_ptr2, sym_count);
204    }
205    SetDefaultCursor(mainWindow);
206    ShowCursor();
207    return obj_ptr;
208 }
209 
GetObjRepresentation(PathName,SymName,FileType)210 struct ObjRec *GetObjRepresentation(PathName, SymName, FileType)
211    char *PathName, *SymName;
212    int FileType;
213 {
214    char file_name[MAXPATHLENGTH], *rest=NULL;
215    char tmp_filename[MAXPATHLENGTH], tmp_filefullpath[MAXPATHLENGTH];
216    int short_name, tmp_linenum;
217    struct ObjRec *obj_ptr;
218    FILE *fp;
219 
220    sprintf(file_name, "%s%c%s.%s", PathName, DIR_SEP, SymName, SYM_FILE_EXT);
221    if ((short_name=IsPrefix(bootDir, file_name, &rest))) ++rest;
222 
223    if ((fp=fopen(file_name, "r")) == NULL) {
224       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
225             (short_name ? rest : file_name));
226       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
227       return NULL;
228    }
229 
230    strcpy(tmp_filefullpath, scanFileFullPath);
231    strcpy(tmp_filename, scanFileName);
232    tmp_linenum = scanLineNum;
233    UtilStrCpyN(scanFileFullPath, sizeof(scanFileFullPath), file_name);
234    strcpy(scanFileName, (short_name ? rest : file_name));
235    scanLineNum = 0;
236 
237    if ((obj_ptr=ReadSymbol(fp, FileType)) != NULL) {
238       obj_ptr->id = objId++;
239       obj_ptr->dirty = FALSE;
240       strcpy(obj_ptr->detail.r->s, SymName);
241       obj_ptr->detail.r->rotate = ROTATE0;
242       obj_ptr->detail.r->flip = NO_FLIP;
243       obj_ptr->detail.r->deck_index = (-1);
244       obj_ptr->detail.r->pin_connected = 0;
245       obj_ptr->detail.r->first_conn = obj_ptr->detail.r->last_conn = NULL;
246       AdjObjBBox(obj_ptr);
247    }
248 
249    strcpy(scanFileFullPath, tmp_filefullpath);
250    strcpy(scanFileName, tmp_filename);
251    scanLineNum = tmp_linenum;
252 
253    fclose(fp);
254    return obj_ptr;
255 }
256 
PlaceTopObj(ObjPtr,savedTopObj,savedBotObj)257 unsigned int PlaceTopObj(ObjPtr, savedTopObj, savedBotObj)
258    struct ObjRec *ObjPtr, *savedTopObj, *savedBotObj;
259 {
260    int x, y, grid_x, grid_y, dx, dy, placing=TRUE;
261    int cursor_x, cursor_y, orig_x, orig_y, obj_ltx, obj_lty, obj_rbx, obj_rby;
262    int grid_obj_ltx, grid_obj_lty, grid_dx=0, grid_dy=0;
263    Window root_win, child_win;
264    int root_x, root_y, first_time=TRUE;
265    unsigned int status, button_pressed=Button1;
266    XEvent input, ev;
267 
268    RedrawMsg(TRUE);
269 
270    XFlush(mainDisplay);
271    XSync(mainDisplay, False);
272 
273    placingTopObj = TRUE;
274    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
275          XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
276       ExposeEventHandler(&ev, TRUE);
277    }
278    obj_ltx = OFFSET_X(ObjPtr->obbox.ltx); obj_lty = OFFSET_Y(ObjPtr->obbox.lty);
279    obj_rbx = OFFSET_X(ObjPtr->obbox.rbx); obj_rby = OFFSET_Y(ObjPtr->obbox.rby);
280    GridXY(obj_ltx, obj_lty, &grid_obj_ltx, &grid_obj_lty);
281 
282    dx = dy = 0;
283    if (!debugNoPointerGrab) {
284       XGrabPointer(mainDisplay, drawWindow, False,
285             PointerMotionMask | ButtonPressMask,
286             GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
287    }
288    if (XCheckMaskEvent(mainDisplay, PointerMotionMask, &input)) {
289       first_time = FALSE;
290 
291       cursor_x = input.xmotion.x;
292       cursor_y = input.xmotion.y;
293       while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &input)) {
294          cursor_x = input.xmotion.x;
295          cursor_y = input.xmotion.y;
296       }
297       GridXY(cursor_x, cursor_y, &orig_x, &orig_y);
298       grid_dx = orig_x-grid_obj_ltx; grid_dy = orig_y-grid_obj_lty;
299       SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx, obj_lty+grid_dy,
300             obj_rbx+grid_dx, obj_rby+grid_dy);
301    }
302 
303    while (placing) {
304       XNextEvent(mainDisplay, &input);
305 
306       if (first_time) {
307          first_time = FALSE;
308 
309          XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
310                &root_x, &root_y, &cursor_x, &cursor_y, &status);
311 
312          GridXY(cursor_x, cursor_y, &orig_x, &orig_y);
313          grid_dx = orig_x-grid_obj_ltx; grid_dy = orig_y-grid_obj_lty;
314          SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx, obj_lty+grid_dy,
315                obj_rbx+grid_dx, obj_rby+grid_dy);
316       }
317 
318       if (input.type == Expose || input.type == VisibilityNotify) {
319 /*       SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx, obj_lty+grid_dy,
320                obj_rbx+grid_dx, obj_rby+grid_dy); */
321          if (savedTopObj != NULL && savedBotObj != NULL) {
322             struct ObjRec *saved_top_obj=topObj, *saved_bot_obj=botObj;
323 
324             curPage->top = topObj = NULL;
325             curPage->bot = botObj = NULL;
326             curPage->top = topObj = savedTopObj;
327             curPage->bot = botObj = savedBotObj;
328             placingTopObj = FALSE;
329             RedrawDrawWindow(botObj);
330             placingTopObj = TRUE;
331             curPage->top = topObj = saved_top_obj;
332             curPage->bot = botObj = saved_bot_obj;
333          }
334          ExposeEventHandler(&input, TRUE);
335          SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx, obj_lty+grid_dy,
336                obj_rbx+grid_dx, obj_rby+grid_dy);
337       } else if (input.type == ButtonPress) {
338          XUngrabPointer(mainDisplay, CurrentTime);
339          button_pressed = input.xbutton.button;
340          placing = FALSE;
341          SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx+dx,
342                obj_lty+grid_dy+dy, obj_rbx+grid_dx+dx, obj_rby+grid_dy+dy);
343          grid_dx = ABS_SIZE(grid_dx+dx);
344          grid_dy = ABS_SIZE(grid_dy+dy);
345          MoveObj(ObjPtr, grid_dx, grid_dy);
346          numRedrawBBox = 0;
347          ShowInterrupt(1);
348          placingTopObj = FALSE;
349          ObjPtr->tmp_parent = NULL;
350          DrawObj(drawWindow, ObjPtr);
351          HideInterrupt();
352       } else if (input.type == MotionNotify) {
353          int anywhere=(input.xmotion.state & (ShiftMask | ControlMask));
354          int saved_snap=snapOn;
355 
356          x = input.xmotion.x;
357          y = input.xmotion.y;
358          if (anywhere) snapOn = FALSE;
359          GridXY(x, y, &grid_x, &grid_y);
360          if (anywhere) snapOn = saved_snap;
361          SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx+dx,
362                obj_lty+grid_dy+dy, obj_rbx+grid_dx+dx, obj_rby+grid_dy+dy);
363          dx = grid_x - orig_x;
364          dy = grid_y - orig_y;
365          SelBox(drawWindow, revDefaultGC, obj_ltx+grid_dx+dx,
366                obj_lty+grid_dy+dy, obj_rbx+grid_dx+dx, obj_rby+grid_dy+dy);
367          MarkRulers(grid_x, grid_y);
368          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
369       }
370    }
371    XSync(mainDisplay, True);
372    placingTopObj = FALSE;
373    return button_pressed;
374 }
375 
376 static
UnMakeIconicOnInstantiate(obj_ptr)377 int UnMakeIconicOnInstantiate(obj_ptr)
378    struct ObjRec *obj_ptr;
379 {
380    register struct AttrRec *attr_ptr;
381 
382    for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
383       if (*attr_ptr->attr_name.s=='\0' &&
384             (strcmp(attr_ptr->attr_value.s, "unmakeiconic_on_instantiate")==0 ||
385             strcmp(attr_ptr->attr_value.s,
386             "unmakeiconic_on_instantiate_delete_attrs")==0)) {
387          return TRUE;
388       }
389    }
390    return FALSE;
391 }
392 
393 static
UnMakeIconicOnInstantiateDeleteAttrs(obj_ptr)394 int UnMakeIconicOnInstantiateDeleteAttrs(obj_ptr)
395    struct ObjRec *obj_ptr;
396 {
397    register struct AttrRec *attr_ptr;
398 
399    for (attr_ptr=obj_ptr->lattr; attr_ptr!=NULL; attr_ptr=attr_ptr->prev) {
400       if (*attr_ptr->attr_name.s=='\0' && strcmp(attr_ptr->attr_value.s,
401             "unmakeiconic_on_instantiate_delete_attrs")==0) {
402          return TRUE;
403       }
404    }
405    return FALSE;
406 }
407 
408 static
DeleteUnMakeIconicOnInstantiateText()409 void DeleteUnMakeIconicOnInstantiateText()
410 {
411    struct SelRec *sel_ptr;
412    struct ObjRec *text_obj_ptr=NULL;
413 
414    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
415       if (sel_ptr->obj->type == OBJ_TEXT) {
416          struct DynStrRec *dyn_str_ptr=GetTextFirstDynStr(sel_ptr->obj);
417 
418          if (strcmp(dyn_str_ptr->s, "unmakeiconic_on_instantiate") == 0) {
419             text_obj_ptr = sel_ptr->obj;
420             break;
421          }
422       }
423    }
424    if (text_obj_ptr == NULL) {
425       sprintf(gszMsgBox, TgLoadString(STID_CANT_FIND_NAMED_OBJ_IN_FUNC),
426             "unmakeiconic_on_instantiate",
427             "DeleteUnMakeIconicOnInstantiateText()");
428       TgAssert(FALSE, gszMsgBox, NULL);
429       XFlush(mainDisplay);
430       XSync(mainDisplay, False);
431       return;
432    }
433    MakeQuiescent();
434    topSel = (struct SelRec *)malloc(sizeof(struct SelRec));
435    if (topSel == NULL) FailAllocMessage();
436    topSel->next = NULL;
437    topSel->obj = text_obj_ptr;
438    topSel->prev = NULL;
439    botSel = topSel;
440    UpdSelBBox();
441    HighLightForward();
442    DelAllSelObj();
443 }
444 
Instantiate()445 void Instantiate()
446 {
447    char file_name[MAXPATHLENGTH], *rest=NULL, msg[MAXSTRING];
448    char sym_name[MAXPATHLENGTH], path_name[MAXPATHLENGTH];
449    char ext_str[MAXPATHLENGTH];
450    char tmp_filename[MAXPATHLENGTH], tmp_filefullpath[MAXPATHLENGTH];
451    int short_name=FALSE, file_type=INVALID, tmp_linenum=0, len=0, ext_len=0;
452    struct ObjRec *obj_ptr=NULL;
453    FILE *fp=NULL;
454    XEvent ev;
455 
456    MakeQuiescent();
457 
458    if (*curDomainName == '\0') {
459       strcpy(msg, TgLoadString(STID_SEL_A_SYM_TO_INSTAN_IN_NONE));
460    } else {
461       sprintf(msg, TgLoadString(STID_SEL_A_SYM_TO_INSTAN_IN_DOMAIN),
462             curDomainName);
463    }
464    if (SelectFromLibrary(msg, SYM_FILE_EXT, sym_name, path_name) == INVALID) {
465       return;
466    }
467    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
468          XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
469       ExposeEventHandler(&ev, TRUE);
470    }
471    sprintf(file_name, "%s%c%s", path_name, DIR_SEP, sym_name);
472 
473    len = strlen(sym_name);
474    sprintf(ext_str, ".%s", SYM_FILE_EXT);
475    ext_len = strlen(ext_str);
476    if (len > ext_len && strcmp(ext_str, &sym_name[len-ext_len]) == 0) {
477       sym_name[len-ext_len] = '\0';
478       file_type = SYM_FILE_TYPE;
479    } else {
480       sprintf(ext_str, ".%s", PIN_FILE_EXT);
481       ext_len = strlen(ext_str);
482       if (len > ext_len && strcmp(ext_str, &sym_name[len-ext_len]) == 0) {
483          sym_name[len-ext_len] = '\0';
484          file_type = PIN_FILE_TYPE;
485       }
486    }
487    if ((short_name=IsPrefix(bootDir, file_name, &rest))) ++rest;
488 
489    if (file_type == INVALID) {
490       sprintf(gszMsgBox, TgLoadString(STID_CANT_INSTAN_FILE_UNKNOWN_EXT),
491             (short_name ? rest : file_name));
492       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
493       return;
494    }
495    if ((fp=fopen(file_name, "r")) == NULL) {
496       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
497             (short_name ? rest : file_name));
498       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
499       return;
500    }
501    strcpy(tmp_filefullpath, scanFileFullPath);
502    strcpy(tmp_filename, scanFileName);
503    tmp_linenum = scanLineNum;
504    UtilStrCpyN(scanFileFullPath, sizeof(scanFileFullPath), file_name);
505    strcpy(scanFileName, (short_name ? rest : file_name));
506    scanLineNum = 0;
507 
508    SetWatchCursor(drawWindow);
509    SetWatchCursor(mainWindow);
510    if ((obj_ptr=ReadSymbol(fp, file_type)) != NULL) {
511       char *psz=NULL;
512       struct AttrRec *name_attr=NULL;
513 
514       sprintf(msg, TgLoadCachedString(CSTID_INSTANTIATING_FILE_DOTS),
515             (short_name ? rest : file_name));
516       SetStringStatus(msg);
517       obj_ptr->id = objId++;
518       obj_ptr->dirty = FALSE;
519       strcpy(obj_ptr->detail.r->s, sym_name);
520       obj_ptr->detail.r->rotate = ROTATE0;
521       obj_ptr->detail.r->flip = NO_FLIP;
522       obj_ptr->detail.r->deck_index = (-1);
523       obj_ptr->detail.r->pin_connected = 0;
524       obj_ptr->detail.r->first_conn = obj_ptr->detail.r->last_conn = NULL;
525       name_attr = FindAttrWithName(obj_ptr, "name=", NULL);
526       if (name_attr != NULL &&
527             (psz=strstr(name_attr->attr_value.s, "%d")) != NULL &&
528             (strstr(++psz, "%d")) == NULL) {
529          sprintf(gszMsgBox, name_attr->attr_value.s, obj_ptr->id-1);
530          DynStrSet(&name_attr->attr_value, gszMsgBox);
531          UpdAttr(name_attr);
532          UpdTextBBox(name_attr->obj);
533       }
534       AssignNewObjIds(obj_ptr);
535       AddObj(NULL, topObj, obj_ptr);
536       AdjObjBBox(obj_ptr);
537       PlaceTopObj(obj_ptr, NULL, NULL);
538 
539       SelectTopObj();
540       if (UnMakeIconicOnInstantiate(obj_ptr)) {
541          StartCompositeCmd();
542          RecordNewObjCmd();
543          UnMakeIconic();
544          if (UnMakeIconicOnInstantiateDeleteAttrs(obj_ptr)) {
545             gnDeleteAttrsWhileUngrouping = TRUE;
546             UngroupSelObj(TRUE, TRUE);
547             gnDeleteAttrsWhileUngrouping = FALSE;
548          } else {
549             UngroupSelObj(TRUE, TRUE);
550             DeleteUnMakeIconicOnInstantiateText();
551          }
552          EndCompositeCmd();
553       } else {
554          RecordNewObjCmd();
555       }
556       SetFileModified(TRUE);
557       justDupped = FALSE;
558    } else {
559       sprintf(gszMsgBox, TgLoadString(STID_CANT_FND_SYM_IN_NAMED_TO_INST),
560             (short_name ? rest : file_name));
561       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
562    }
563    fclose(fp);
564 
565    strcpy(scanFileFullPath, tmp_filefullpath);
566    strcpy(scanFileName, tmp_filename);
567    scanLineNum = tmp_linenum;
568 
569    SetDefaultCursor(mainWindow);
570    SetDefaultCursor(drawWindow);
571    Msg("");
572 
573    if (topSel != NULL && topSel == botSel && topSel->obj->type == OBJ_ICON) {
574       /* something has been instantiated */
575       char *psz=NULL;
576       struct AttrRec *name_attr=NULL, *exec_attr=NULL;
577 
578       name_attr = FindAttrWithName(topSel->obj, "name=", NULL);
579       if (name_attr != NULL &&
580             (psz=strstr(name_attr->attr_value.s, "%d")) != NULL &&
581             (strstr(++psz, "%d")) == NULL) {
582          sprintf(gszMsgBox, name_attr->attr_value.s, obj_ptr->id-1);
583          DynStrSet(&name_attr->attr_value, gszMsgBox);
584          UpdAttr(name_attr);
585          UpdTextBBox(name_attr->obj);
586          AdjObjBBox(name_attr->obj);
587          AdjObjCache(name_attr->obj);
588       }
589       exec_attr = FindAttrWithName(topSel->obj, "on_instantiate=", NULL);
590       if (exec_attr != NULL) {
591          DoExecLoop(topSel->obj, exec_attr);
592       }
593    }
594 /*
595  * Need to check for pins.
596  */
597 }
598 
ObjIsAPort(obj_ptr)599 int ObjIsAPort(obj_ptr)
600    struct ObjRec *obj_ptr;
601 {
602    struct AttrRec *attr_ptr=NULL;
603 
604    attr_ptr = FindAttrWithName(obj_ptr, "type=", NULL);
605    if (attr_ptr != NULL && strcmp(attr_ptr->attr_value.s, "port") == 0) {
606       /*
607        * if this is not called from ConnectTwoPortsByAWire() but from
608        * an internal command, "type=port" is enough for a point
609        */
610       if (connectingPortsFromInternalCommand) return TRUE;
611 
612       if (FindAttrWithName(obj_ptr, "signal_name=", NULL) != NULL &&
613             FindAttrWithName(obj_ptr, "name=", NULL) != NULL) {
614          struct ObjRec *owner_obj=obj_ptr->tmp_parent, *tmp_obj=NULL;
615 
616          owner_obj = obj_ptr->tmp_parent;
617          if (owner_obj == NULL) {
618             /* obj_ptr is a top-level object */
619             return (obj_ptr->type == OBJ_ICON || obj_ptr->type == OBJ_SYM);
620          } else {
621             if (owner_obj->type == OBJ_ICON || owner_obj->type == OBJ_SYM) {
622                if (FindAttrWithName(owner_obj, "name=", NULL) == NULL) {
623                   return FALSE;
624                }
625             } else {
626                if (owner_obj->type == OBJ_GROUP) {
627                   attr_ptr = FindAttrWithName(owner_obj, "type=", NULL);
628                   if (attr_ptr != NULL && strcmp(attr_ptr->attr_value.s,
629                         "tgBroadcastWire") == 0) {
630                      return TRUE;
631                   }
632                }
633                return FALSE;
634             }
635          }
636          for (tmp_obj=owner_obj->tmp_parent; tmp_obj != NULL;
637                tmp_obj=tmp_obj->tmp_parent) {
638             if (tmp_obj->type == OBJ_ICON || tmp_obj->type == OBJ_SYM) {
639                return FALSE;
640             }
641          }
642          return TRUE;
643       }
644    }
645    return FALSE;
646 }
647 
648 static
DoConnectTwoPorts()649 int DoConnectTwoPorts()
650 {
651    int poly_created=FALSE;
652    XGCValues values;
653 
654    MakeQuiescent();
655 
656    ResetWiringNodeInfo();
657    connectingPortsByWire = TRUE;
658    connectingPortsFromInternalCommand = FALSE;
659    UseWireMenuItemInModeItem(TRUE);
660 
661    values.line_width = 3;
662    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
663    SetCurChoice(DRAWPOLY);
664    gstWiringInfo.num_ports_to_connect = 2;
665    drawPolyHighlightedNode = NULL;
666    SetStringStatus(TgLoadString(STID_DRAW_AN_EDGE_BETWEEN_PORTS));
667    polyDrawn = FALSE;
668    for (;;) {
669       XEvent input;
670 
671       XNextEvent(mainDisplay, &input);
672       if (input.type == Expose || input.type == VisibilityNotify) {
673          ExposeEventHandler(&input, TRUE);
674       } else if (input.type == ConfigureNotify) {
675          Reconfigure(FALSE);
676       } else if (input.xany.window == drawWindow) {
677          polyDrawn = FALSE;
678          DrawingEventHandler(&input);
679          if (curChoice == DRAWPOLY) {
680             if (polyDrawn) {
681                break;
682             } else if (gstWiringInfo.num_ports_to_connect == (-1)) {
683                break;
684             }
685          } else {
686             polyDrawn = FALSE;
687             break;
688          }
689       }
690    }
691    gstWiringInfo.num_ports_to_connect = 0;
692    poly_created = polyDrawn;
693    values.line_width = 1;
694    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
695    connectingPortsByWire = FALSE;
696    connectingPortsFromInternalCommand = TRUE;
697    SetCurChoice(NOTHING);
698    RedrawModeWindow();
699    UseWireMenuItemInModeItem(FALSE);
700    UpdatePinnedMenu(MENU_MODE);
701 
702    return poly_created;
703 }
704 
705 static
AddWireAttributes(poly_obj_ptr,signal_name,p_obbox,auto_center)706 void AddWireAttributes(poly_obj_ptr, signal_name, p_obbox, auto_center)
707    struct ObjRec *poly_obj_ptr;
708    char *signal_name;
709    struct BBRec *p_obbox;
710    int auto_center;
711 {
712    struct ObjRec *text_obj_ptr=NULL;
713 
714    PrepareToReplaceAnObj(poly_obj_ptr);
715 
716    AddAttrByNameAndValue(poly_obj_ptr, "signal_name=", signal_name);
717    poly_obj_ptr->fattr->shown = TRUE;
718    poly_obj_ptr->fattr->nameshown = FALSE;
719    UpdAttr(poly_obj_ptr->fattr);
720    text_obj_ptr = poly_obj_ptr->fattr->obj;
721    if (auto_center) {
722       CenterObjInOBBox(text_obj_ptr, *p_obbox, NULL);
723       memcpy(p_obbox, &text_obj_ptr->obbox, sizeof(struct BBRec));
724       poly_obj_ptr->fattr->shown = FALSE;
725    } else {
726       MoveObj(text_obj_ptr, p_obbox->ltx-text_obj_ptr->obbox.ltx,
727             p_obbox->lty-text_obj_ptr->obbox.lty);
728    }
729    AddAttrByNameAndValue(poly_obj_ptr, "type=", "tgWire");
730    text_obj_ptr = poly_obj_ptr->fattr->obj;
731    MoveObj(text_obj_ptr, p_obbox->ltx-text_obj_ptr->obbox.ltx,
732          p_obbox->rby-text_obj_ptr->obbox.lty);
733 
734    AdjObjBBox(poly_obj_ptr);
735 
736    RecordReplaceAnObj(poly_obj_ptr);
737 }
738 
739 typedef struct tagChangeConnectionViewInfo {
740    /* only change view if do_change_view is TRUE */
741    int do_change_view;
742    int change_to_connect_view;
743    struct ObjRec *conn_view_obj, *disconn_view_obj;
744    int conn_fill, conn_pen, disconn_fill, disconn_pen;
745    /* _TANGRAM_II stuff */
746    struct ObjRec *port_obj;
747    char *signal_name;
748 } ChangeConnectionViewInfo;
749 
750 static
ChangeConnectionView(pravci)751 int ChangeConnectionView(pravci)
752    ReplAttrValueCallbackInfo *pravci;
753 {
754    ChangeConnectionViewInfo *pccvi=(
755          (ChangeConnectionViewInfo*)pravci->pv_userdata);
756 
757    if (pccvi == NULL) return FALSE;
758 
759    if (pccvi->do_change_view) {
760       if (pccvi->change_to_connect_view) {
761          ChangeObjFill(pccvi->disconn_view_obj, NONEPAT);
762          ChangeObjPen(pccvi->disconn_view_obj, NONEPAT);
763          ChangeObjFill(pccvi->conn_view_obj, pccvi->conn_fill);
764          ChangeObjPen(pccvi->conn_view_obj, pccvi->conn_pen);
765       } else {
766          ChangeObjFill(pccvi->conn_view_obj, NONEPAT);
767          ChangeObjPen(pccvi->conn_view_obj, NONEPAT);
768          ChangeObjFill(pccvi->disconn_view_obj, pccvi->disconn_fill);
769          ChangeObjPen(pccvi->disconn_view_obj, pccvi->disconn_pen);
770       }
771    }
772    if (cmdLineTgrm2) {
773       Tangram2UpdateInitAttr(pccvi->port_obj, pccvi->signal_name);
774    }
775    return TRUE;
776 }
777 
778 static
HasConnAndDisConnViewObjSubObjs(obj_ptr,pccvi)779 int HasConnAndDisConnViewObjSubObjs(obj_ptr, pccvi)
780    struct ObjRec *obj_ptr;
781    ChangeConnectionViewInfo *pccvi;
782 {
783    struct ObjRec *subobj=NULL;
784 
785    if (obj_ptr == NULL) return FALSE;
786    if (obj_ptr->type != OBJ_SYM && obj_ptr->type != OBJ_ICON &&
787          obj_ptr->type != OBJ_GROUP) {
788       return FALSE;
789    }
790    for (subobj=obj_ptr->detail.r->first; subobj != NULL; subobj=subobj->next) {
791       struct AttrRec *attr_ptr=FindAttrWithName(subobj, "view=", NULL);
792 
793       if (attr_ptr != NULL) {
794          char *psz_fill=NULL, *psz_pen=NULL, buf[MAXSTRING];
795 
796          UtilStrCpyN(buf, sizeof(buf), attr_ptr->attr_value.s);
797          psz_fill = strchr(buf, ',');
798          if (psz_fill != NULL) {
799             *psz_fill++ = '\0';
800             psz_pen = strchr(psz_fill, ',');
801             if (psz_pen != NULL) *psz_pen++ = '\0';
802          }
803          if (psz_fill != NULL && psz_pen != NULL) {
804             int fill=0, pen=0, ok=TRUE;
805 
806             UtilTrimBlanks(buf);
807             UtilTrimBlanks(psz_fill);
808             UtilTrimBlanks(psz_pen);
809             if (sscanf(psz_fill, "%d", &fill) != 1) ok = FALSE;
810             if (sscanf(psz_pen, "%d", &pen) != 1) ok = FALSE;
811             if (ok) {
812                fill = fill % MAXPATTERNS;
813                pen = pen % MAXPATTERNS;
814                if (ok && UtilStrICmp(buf, "conn") == 0) {
815                   pccvi->conn_fill = fill;
816                   pccvi->conn_pen = pen;
817                   pccvi->conn_view_obj = subobj;
818                } else if (ok && UtilStrICmp(buf, "disconn") == 0) {
819                   pccvi->disconn_fill = fill;
820                   pccvi->disconn_pen = pen;
821                   pccvi->disconn_view_obj = subobj;
822                }
823             }
824          }
825       }
826    }
827    return (pccvi->conn_view_obj != NULL && pccvi->disconn_view_obj != NULL);
828 }
829 
830 static
SetPortSignalName(port_obj,attr_ptr,attr_owner_obj,new_signal_name)831 int SetPortSignalName(port_obj, attr_ptr, attr_owner_obj, new_signal_name)
832    struct ObjRec *port_obj, *attr_owner_obj;
833    struct AttrRec *attr_ptr;
834    char *new_signal_name;
835 {
836    if (attr_ptr != NULL &&
837          strcmp(new_signal_name, attr_ptr->attr_value.s) != 0) {
838       char *old_signal_name=attr_ptr->attr_value.s;
839       ChangeConnectionViewInfo ccvi;
840 
841       memset(&ccvi, 0, sizeof(ChangeConnectionViewInfo));
842       if ((*old_signal_name == '\0' || *new_signal_name == '\0') &&
843             HasConnAndDisConnViewObjSubObjs(attr_ptr->owner, &ccvi)) {
844          ccvi.do_change_view = TRUE;
845          if (*old_signal_name == '\0') {
846             /* the port will become connected */
847             ccvi.change_to_connect_view = TRUE;
848          } else {
849             /* the port will become disconnected */
850             ccvi.change_to_connect_view = FALSE;
851          }
852       }
853       ccvi.port_obj = port_obj;
854       ccvi.signal_name = new_signal_name;
855       SetReplaceAttrValueCallback(
856             (ReplAttrValueCallback*)ChangeConnectionView, &ccvi);
857 
858       ReplaceAttrFirstValue(attr_owner_obj, attr_ptr, new_signal_name);
859       SetReplaceAttrValueCallback(NULL, NULL);
860       RecursivelyAdjObjBBox(attr_ptr->owner, attr_ptr->owner,
861             attr_owner_obj);
862       return TRUE;
863    }
864    return FALSE;
865 }
866 
867 static
DoNameWire(automatic)868 void DoNameWire(automatic)
869    int automatic;
870 {
871    struct AttrRec *first_attr_ptr=NULL, *last_attr_ptr=NULL;
872    struct ObjRec *first_attr_owner_obj=NULL, *last_attr_owner_obj=NULL;
873    struct BBRec bbox;
874    char signal_name[MAXSTRING], *existing_signal_name=NULL;
875    int need_to_clear=FALSE, need_to_redraw=FALSE;
876    int do_prompt=TRUE, must_prompt=FALSE;
877 
878    memcpy(&bbox, &topObj->bbox, sizeof(struct BBRec));
879    first_attr_ptr = FindAttrWithName(gstWiringInfo.first_port_obj,
880          "signal_name=", &first_attr_owner_obj);
881    while (first_attr_owner_obj != NULL &&
882          first_attr_owner_obj->tmp_parent != NULL) {
883       first_attr_owner_obj = first_attr_owner_obj->tmp_parent;
884    }
885    last_attr_ptr = FindAttrWithName(gstWiringInfo.last_port_obj,
886          "signal_name=", &last_attr_owner_obj);
887    while (last_attr_owner_obj != NULL &&
888          last_attr_owner_obj->tmp_parent != NULL) {
889       last_attr_owner_obj = last_attr_owner_obj->tmp_parent;
890    }
891    if (first_attr_ptr == NULL && last_attr_ptr == NULL) return;
892    if (first_attr_ptr != NULL && last_attr_ptr != NULL) {
893       if (strcmp(first_attr_ptr->attr_value.s, last_attr_ptr->attr_value.s) !=
894             0) {
895          if (*first_attr_ptr->attr_value.s == '\0' &&
896                *last_attr_ptr->attr_value.s == '\0') {
897             must_prompt = TRUE;
898          } else if (*first_attr_ptr->attr_value.s == '\0') {
899             existing_signal_name = last_attr_ptr->attr_value.s;
900          } else if (*last_attr_ptr->attr_value.s == '\0') {
901             existing_signal_name = first_attr_ptr->attr_value.s;
902          } else {
903             sprintf(gszMsgBox, TgLoadString(STID_Q_CNFLCT_SIG_NAME_OKAY_TO_CLR),
904                   first_attr_ptr->attr_value.s, gstWiringInfo.first_port_name,
905                   last_attr_ptr->attr_value.s, gstWiringInfo.last_port_name);
906             switch (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) {
907             case MB_ID_YES:
908                need_to_clear = TRUE;
909                must_prompt = TRUE;
910                break;
911             case MB_ID_NO:
912             case MB_ID_CANCEL:
913                return;
914             }
915          }
916       } else {
917          existing_signal_name = first_attr_ptr->attr_value.s;
918       }
919    } else if (first_attr_ptr == NULL) {
920       if (*last_attr_ptr->attr_value.s != '\0') {
921          existing_signal_name = last_attr_ptr->attr_value.s;
922       }
923    } else {
924       if (*first_attr_ptr->attr_value.s != '\0') {
925          existing_signal_name = first_attr_ptr->attr_value.s;
926       }
927    }
928    StartCompositeCmd();
929    if (need_to_clear) {
930       if (SetPortSignalName(gstWiringInfo.first_port_obj, first_attr_ptr,
931             first_attr_owner_obj, "")) {
932          UnionRect(&bbox, &first_attr_owner_obj->bbox, &bbox);
933          need_to_redraw = TRUE;
934       }
935       if (SetPortSignalName(gstWiringInfo.last_port_obj, last_attr_ptr,
936             last_attr_owner_obj, "")) {
937          UnionRect(&bbox, &last_attr_owner_obj->bbox, &bbox);
938          need_to_redraw = TRUE;
939       }
940    }
941    if (do_prompt) {
942       struct ObjRec *signal_name_obj=NULL;
943       struct BBRec obbox;
944       XEvent ev;
945       int show_wire_signal_name=(!automatic && showWireSignalName);
946 
947       *signal_name = '\0';
948       if (existing_signal_name != NULL) {
949          UtilStrCpyN(signal_name, sizeof(signal_name), existing_signal_name);
950       }
951       UtilTrimBlanks(signal_name);
952       if (must_prompt || !automatic) {
953          Dialog(TgLoadString(STID_PLS_ENT_SIG_NAME), NULL, signal_name);
954          UtilTrimBlanks(signal_name);
955       }
956       if (*signal_name == '\0') {
957          if (need_to_clear) {
958             sprintf(gszMsgBox, TgLoadString(STID_SIGNAL_NAMES_CLEARED),
959                   gstWiringInfo.first_port_name, gstWiringInfo.last_port_name);
960             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
961          }
962          EndCompositeCmd();
963 
964          if (need_to_redraw) {
965             SetFileModified(TRUE);
966             justDupped = FALSE;
967             RedrawAnArea(botObj,
968                   bbox.ltx-QUARTER_INCH-GRID_ABS_SIZE(1),
969                   bbox.lty-QUARTER_INCH-GRID_ABS_SIZE(1),
970                   bbox.rbx+QUARTER_INCH+GRID_ABS_SIZE(1),
971                   bbox.rby+QUARTER_INCH+GRID_ABS_SIZE(1));
972          }
973          return;
974       }
975       if (show_wire_signal_name) {
976          unsigned int button_pressed=Button1;
977 
978          SaveStatusStrings();
979          sprintf(gszMsgBox, TgLoadString(STID_PLACING_NAMED_SIGNAL),
980                signal_name);
981          SetStringStatus(gszMsgBox);
982          button_pressed = PasteString(signal_name, FALSE, FALSE);
983          RestoreStatusStrings();
984 
985          if (button_pressed != Button1) show_wire_signal_name = FALSE;
986 
987          memcpy(&obbox, &topObj->obbox, sizeof(struct BBRec));
988          signal_name_obj = topObj;
989          UnlinkObj(signal_name_obj);
990          FreeObj(signal_name_obj);
991 
992          XSync(mainDisplay, False);
993          if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev)) {
994             ExposeEventHandler(&ev, TRUE);
995          }
996       } else {
997          memcpy(&obbox, &topObj->obbox, sizeof(struct BBRec));
998       }
999       AddWireAttributes(topObj, signal_name, &obbox, !show_wire_signal_name);
1000       UnionRect(&bbox, &topObj->bbox, &bbox);
1001       if (SetPortSignalName(gstWiringInfo.first_port_obj, first_attr_ptr,
1002             first_attr_owner_obj, signal_name)) {
1003          UnionRect(&bbox, &first_attr_owner_obj->bbox, &bbox);
1004          need_to_redraw = TRUE;
1005       }
1006       if (SetPortSignalName(gstWiringInfo.last_port_obj, last_attr_ptr,
1007             last_attr_owner_obj, signal_name)) {
1008          UnionRect(&bbox, &last_attr_owner_obj->bbox, &bbox);
1009          need_to_redraw = TRUE;
1010       }
1011    }
1012    EndCompositeCmd();
1013 
1014    if (need_to_redraw) {
1015       SetFileModified(TRUE);
1016       justDupped = FALSE;
1017       RedrawAnArea(botObj,
1018             bbox.ltx-QUARTER_INCH-GRID_ABS_SIZE(1),
1019             bbox.lty-QUARTER_INCH-GRID_ABS_SIZE(1),
1020             bbox.rbx+QUARTER_INCH+GRID_ABS_SIZE(1),
1021             bbox.rby+QUARTER_INCH+GRID_ABS_SIZE(1));
1022       if (topSel!=NULL) HighLightForward();
1023    }
1024 }
1025 
ConnectTwoPortsByAWire()1026 void ConnectTwoPortsByAWire()
1027 {
1028    StartCompositeCmd();
1029    if (DoConnectTwoPorts()) {
1030       DoNameWire(FALSE);
1031    }
1032    EndCompositeCmd();
1033 }
1034 
RepeatConnectTwoPortsByAWire()1035 void RepeatConnectTwoPortsByAWire()
1036 {
1037    StartCompositeCmd();
1038    while (DoConnectTwoPorts()) {
1039       DoNameWire(TRUE);
1040 
1041       if (topSel!=NULL) { HighLightReverse(); RemoveAllSel(); }
1042    }
1043    EndCompositeCmd();
1044 }
1045 
1046 static
AddObjToAnchor(anchor,obj_ptr)1047 void AddObjToAnchor(anchor, obj_ptr)
1048    struct ObjRec *anchor, *obj_ptr;
1049 {
1050    obj_ptr->prev = NULL;
1051    obj_ptr->next = anchor->detail.r->first;
1052 
1053    anchor->detail.r->first->prev = obj_ptr;
1054    anchor->detail.r->first = obj_ptr;
1055    AdjObjOBBox(anchor);
1056 }
1057 
1058 static
AddBroadcastWireAttributes(poly_obj_ptr,signal_name,p_obbox,auto_center)1059 void AddBroadcastWireAttributes(poly_obj_ptr, signal_name, p_obbox, auto_center)
1060    struct ObjRec *poly_obj_ptr;
1061    char *signal_name;
1062    struct BBRec *p_obbox;
1063    int auto_center;
1064 {
1065    struct ObjRec *text_obj_ptr=NULL;
1066 
1067    PrepareToReplaceAnObj(poly_obj_ptr);
1068 
1069    AddAttrByNameAndValue(poly_obj_ptr, "broadcast_signal_name=", signal_name);
1070    poly_obj_ptr->fattr->shown = TRUE;
1071    poly_obj_ptr->fattr->nameshown = FALSE;
1072    UpdAttr(poly_obj_ptr->fattr);
1073    text_obj_ptr = poly_obj_ptr->fattr->obj;
1074    if (auto_center) {
1075       CenterObjInOBBox(text_obj_ptr, *p_obbox, NULL);
1076       memcpy(p_obbox, &text_obj_ptr->obbox, sizeof(struct BBRec));
1077       poly_obj_ptr->fattr->shown = FALSE;
1078    } else {
1079       MoveObj(text_obj_ptr, p_obbox->ltx-text_obj_ptr->obbox.ltx,
1080             p_obbox->lty-text_obj_ptr->obbox.lty);
1081    }
1082    AdjObjBBox(poly_obj_ptr);
1083 
1084    RecordReplaceAnObj(poly_obj_ptr);
1085 }
1086 
1087 static
DoNameBroadcastWire(signal_name,signal_name_diff)1088 void DoNameBroadcastWire(signal_name, signal_name_diff)
1089    char *signal_name;
1090    int signal_name_diff;
1091 {
1092    struct ObjRec *obj_ptr=NULL, *signal_name_obj=NULL;
1093    struct AttrRec *attr_ptr=NULL;
1094    struct BBRec bbox, obbox;
1095    int show_wire_signal_name=showWireSignalName;
1096    int already_has_broadcast_signal_name=FALSE;
1097    XEvent ev;
1098 
1099    memset(&obbox, 0, sizeof(obbox));
1100    memcpy(&bbox, &topObj->bbox, sizeof(struct BBRec));
1101 
1102    StartCompositeCmd();
1103 
1104    attr_ptr = FindAttrWithName(topObj, "broadcast_signal_name=", NULL);
1105    if (attr_ptr != NULL) {
1106       already_has_broadcast_signal_name = TRUE;
1107       if (strcmp(attr_ptr->attr_value.s, signal_name) != 0) {
1108          ReplaceAttrFirstValue(topObj, attr_ptr, signal_name);
1109          UnionRect(&bbox, &topObj->bbox, &bbox);
1110       }
1111    }
1112    for (obj_ptr=topObj->detail.r->last; obj_ptr != NULL;
1113          obj_ptr=obj_ptr->prev) {
1114       if (ObjIsAPort(obj_ptr)) {
1115          struct ObjRec *attr_owner_obj=NULL;
1116 
1117          attr_ptr = FindAttrWithName(obj_ptr, "signal_name=", &attr_owner_obj);
1118          while (attr_owner_obj != NULL && attr_owner_obj->tmp_parent != NULL) {
1119             attr_owner_obj = attr_owner_obj->tmp_parent;
1120          }
1121          if (SetPortSignalName(obj_ptr, attr_ptr, attr_owner_obj, "")) {
1122             UnionRect(&bbox, &attr_owner_obj->bbox, &bbox);
1123          }
1124       }
1125    }
1126    if (show_wire_signal_name && !already_has_broadcast_signal_name) {
1127       unsigned int button_pressed=Button1;
1128 
1129       SaveStatusStrings();
1130       sprintf(gszMsgBox, TgLoadString(STID_PLACING_NAMED_SIGNAL),
1131             signal_name);
1132       SetStringStatus(gszMsgBox);
1133       button_pressed = PasteString(signal_name, FALSE, FALSE);
1134       RestoreStatusStrings();
1135 
1136       if (button_pressed != Button1) show_wire_signal_name = FALSE;
1137 
1138       memcpy(&obbox, &topObj->obbox, sizeof(struct BBRec));
1139       signal_name_obj = topObj;
1140       UnlinkObj(signal_name_obj);
1141       FreeObj(signal_name_obj);
1142 
1143       XSync(mainDisplay, False);
1144       if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev)) {
1145          ExposeEventHandler(&ev, TRUE);
1146       }
1147    } else {
1148       memcpy(&obbox, &topObj->obbox, sizeof(struct BBRec));
1149    }
1150    if (!already_has_broadcast_signal_name) {
1151       AddBroadcastWireAttributes(topObj, signal_name, &obbox,
1152             !show_wire_signal_name);
1153       UnionRect(&bbox, &topObj->bbox, &bbox);
1154    }
1155    for (obj_ptr=topObj->detail.r->last; obj_ptr != NULL;
1156          obj_ptr=obj_ptr->prev) {
1157       if (ObjIsAPort(obj_ptr)) {
1158          struct ObjRec *attr_owner_obj=NULL;
1159          struct AttrRec *attr_ptr=NULL;
1160 
1161          attr_ptr = FindAttrWithName(obj_ptr, "signal_name=", &attr_owner_obj);
1162          while (attr_owner_obj != NULL && attr_owner_obj->tmp_parent != NULL) {
1163             attr_owner_obj = attr_owner_obj->tmp_parent;
1164          }
1165          if (SetPortSignalName(obj_ptr, attr_ptr, attr_owner_obj,
1166                signal_name)) {
1167             UnionRect(&bbox, &attr_owner_obj->bbox, &bbox);
1168          }
1169       }
1170    }
1171    EndCompositeCmd();
1172 
1173    SetFileModified(TRUE);
1174    justDupped = FALSE;
1175    RedrawAnArea(botObj,
1176          bbox.ltx-QUARTER_INCH-GRID_ABS_SIZE(1),
1177          bbox.lty-QUARTER_INCH-GRID_ABS_SIZE(1),
1178          bbox.rbx+QUARTER_INCH+GRID_ABS_SIZE(1),
1179          bbox.rby+QUARTER_INCH+GRID_ABS_SIZE(1));
1180    if (topSel!=NULL) HighLightForward();
1181 }
1182 
1183 static
TrySetCommonSignalName(attr_ptr,pszSignalName,szSignalName,pnSignalNameDiff)1184 void TrySetCommonSignalName(attr_ptr, pszSignalName, szSignalName,
1185       pnSignalNameDiff)
1186    struct AttrRec *attr_ptr;
1187    char *pszSignalName;
1188    int szSignalName, *pnSignalNameDiff;
1189 {
1190    if (*pnSignalNameDiff) {
1191       /* already see multiple signal names */
1192    } else if (*attr_ptr->attr_value.s == '\0') {
1193       /* nothing to do */
1194    } else if (*pszSignalName == '\0') {
1195       UtilStrCpyN(pszSignalName, szSignalName, attr_ptr->attr_value.s);
1196    } else if (strcmp(pszSignalName, attr_ptr->attr_value.s) != 0) {
1197       (*pnSignalNameDiff) = TRUE;
1198       *pszSignalName = '\0';
1199    }
1200 }
1201 
1202 static
CheckPortsAndBroadcastObj(ppAnchor,pnAnchorIsPoly,pnNumPorts,pszSignalName,szSignalName,pnSignalNameDiff,pnAlreadyHasBroadcastSignalName)1203 int CheckPortsAndBroadcastObj(ppAnchor, pnAnchorIsPoly, pnNumPorts,
1204       pszSignalName, szSignalName, pnSignalNameDiff,
1205       pnAlreadyHasBroadcastSignalName)
1206    struct ObjRec **ppAnchor;
1207    int *pnAnchorIsPoly, *pnNumPorts, szSignalName, *pnSignalNameDiff;
1208    int *pnAlreadyHasBroadcastSignalName;
1209    char *pszSignalName;
1210 {
1211    int num_ports=0, anchor_is_poly=FALSE, ok=TRUE, signal_name_diff=FALSE;
1212    int already_has_broadcast_signal_name=FALSE;
1213    struct ObjRec *anchor=NULL;
1214    struct SelRec *sel_ptr=NULL;
1215 
1216    *pszSignalName = '\0';
1217    for (sel_ptr=botSel; ok && sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1218       struct AttrRec *attr_ptr=NULL;
1219 
1220       switch (sel_ptr->obj->type) {
1221       case OBJ_GROUP:
1222       case OBJ_SYM:
1223       case OBJ_ICON:
1224       case OBJ_PIN:
1225          if ((attr_ptr=FindAttrWithName(sel_ptr->obj, "type=", NULL)) != NULL) {
1226             if (strcmp(attr_ptr->attr_value.s, "port") == 0) {
1227                if ((attr_ptr=FindAttrWithName(sel_ptr->obj, "signal_name=",
1228                      NULL)) != NULL) {
1229                   TrySetCommonSignalName(attr_ptr, pszSignalName, szSignalName,
1230                         &signal_name_diff);
1231                   num_ports++;
1232                }
1233             } else if (strcmp(attr_ptr->attr_value.s, "tgBroadcastWire") == 0) {
1234                anchor = sel_ptr->obj;
1235                anchor_is_poly = FALSE;
1236                if ((attr_ptr=FindAttrWithName(sel_ptr->obj,
1237                      "broadcast_signal_name=", NULL)) != NULL) {
1238                   TrySetCommonSignalName(attr_ptr, pszSignalName, szSignalName,
1239                         &signal_name_diff);
1240                   already_has_broadcast_signal_name = TRUE;
1241                }
1242             } else {
1243                return FALSE;
1244             }
1245          } else {
1246             return FALSE;
1247          }
1248          break;
1249       case OBJ_POLY:
1250          if (anchor == NULL) {
1251             anchor = sel_ptr->obj;
1252             anchor_is_poly = TRUE;
1253          } else {
1254             return FALSE;
1255          }
1256          break;
1257       default:
1258          return FALSE;
1259          break;
1260       }
1261    }
1262    if (anchor == NULL || num_ports == 0) {
1263       return FALSE;
1264    }
1265    *pnNumPorts = num_ports;
1266    *ppAnchor = anchor;
1267    *pnAnchorIsPoly = anchor_is_poly;
1268    *pnSignalNameDiff = signal_name_diff;
1269    *pnAlreadyHasBroadcastSignalName = already_has_broadcast_signal_name;
1270 
1271    return TRUE;
1272 }
1273 
ConnectPortsToBroadcastWire()1274 void ConnectPortsToBroadcastWire()
1275 {
1276    struct ObjRec *anchor=NULL;
1277    struct SelRec *sel_ptr=NULL;
1278    int num_ports=0, anchor_is_poly=FALSE, signal_name_diff=FALSE;
1279    int sel_ltx=selLtX, sel_lty=selLtY, sel_rbx=selRbX, sel_rby=selRbY;
1280    int already_has_broadcast_signal_name=FALSE;
1281    char existing_signal_name[MAXSTRING], new_signal_name[MAXSTRING];
1282 
1283    *existing_signal_name = '\0';
1284    if (!CheckPortsAndBroadcastObj(&anchor, &anchor_is_poly, &num_ports,
1285          existing_signal_name, sizeof(existing_signal_name),
1286          &signal_name_diff, &already_has_broadcast_signal_name)) {
1287       MsgBox(TgLoadString(STID_SEL_ONE_NONE_PORT_PLUS_BRDCST), TOOL_NAME,
1288             INFO_MB);
1289       return;
1290    }
1291    *new_signal_name = '\0';
1292    if (*existing_signal_name == '\0') {
1293       if (signal_name_diff) {
1294          /* conflicting signal names */
1295          sprintf(gszMsgBox, TgLoadString(STID_CONFLICT_SIG_NAME_ENT_NEW));
1296       } else {
1297          /* all ports have no signal names */
1298          sprintf(gszMsgBox, TgLoadString(STID_PLS_ENT_SIG_NAME));
1299       }
1300    } else {
1301       UtilStrCpyN(new_signal_name, sizeof(new_signal_name),
1302             existing_signal_name);
1303       sprintf(gszMsgBox, TgLoadString(STID_PLS_ENT_SIG_NAME));
1304    }
1305    if (!(*new_signal_name != '\0' && already_has_broadcast_signal_name)) {
1306       UtilTrimBlanks(new_signal_name);
1307       Dialog(gszMsgBox, TgLoadCachedString(CSTID_DLG_ACCEPT_CANCEL),
1308             new_signal_name);
1309       UtilTrimBlanks(new_signal_name);
1310       if (*new_signal_name == '\0') {
1311          return;
1312       }
1313    }
1314    StartCompositeCmd();
1315 
1316    HighLightReverse();
1317    if (anchor_is_poly) {
1318       struct SelRec *saved_top_sel=NULL, *saved_bot_sel=NULL;
1319       struct ObjRec *text_obj_ptr=NULL;
1320       struct BBRec obbox;
1321       int saved_num_obj_selected=0;
1322       char name[40];
1323 
1324       PrepareToReplaceAnObj(anchor);
1325       for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1326          if (sel_ptr->obj == anchor) {
1327             UnlinkSel(sel_ptr, &topSel, &botSel);
1328             numObjSelected--;
1329             break;
1330          }
1331       }
1332       saved_top_sel = topSel;
1333       saved_bot_sel = botSel;
1334       saved_num_obj_selected = numObjSelected;
1335       topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
1336       if (topSel == NULL) FailAllocMessage();
1337       topSel->obj = anchor;
1338       topSel->next = topSel->prev = NULL;
1339       numObjSelected = 1;
1340       GroupSingleObj(FALSE);
1341       topSel = saved_top_sel;
1342       botSel = saved_bot_sel;
1343       numObjSelected = saved_num_obj_selected;
1344       AddObjIntoSel(topObj, NULL, topSel, &topSel, &botSel);
1345       numObjSelected++;
1346       anchor = topObj;
1347 
1348       memcpy(&obbox, &anchor->obbox, sizeof(struct BBRec));
1349       AddAttrByNameAndValue(anchor, "type=", "tgBroadcastWire");
1350       text_obj_ptr = anchor->fattr->obj;
1351       MoveObj(text_obj_ptr, obbox.ltx-text_obj_ptr->obbox.ltx,
1352             obbox.rby-text_obj_ptr->obbox.lty);
1353       AdjObjBBox(anchor);
1354 
1355       sprintf(name, "tgAutoObj%d", anchor->id);
1356       memcpy(&obbox, &anchor->obbox, sizeof(struct BBRec));
1357       AddAttrByNameAndValue(anchor, "name=", name);
1358       text_obj_ptr = anchor->fattr->obj;
1359       MoveObj(text_obj_ptr, obbox.ltx-text_obj_ptr->obbox.ltx,
1360             obbox.rby-text_obj_ptr->obbox.lty);
1361       AdjObjBBox(anchor);
1362 
1363       RecordReplaceAnObj(anchor);
1364    }
1365    PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
1366 
1367    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1368       if (sel_ptr->obj != anchor) {
1369          UnlinkObj(sel_ptr->obj);
1370          AddObjToAnchor(anchor, sel_ptr->obj);
1371       }
1372    }
1373    RemoveAllSel();
1374    UnlinkObj(anchor);
1375    AddObj(NULL, topObj, anchor);
1376    topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
1377    if (topSel == NULL) FailAllocMessage();
1378    topSel->obj = anchor;
1379    topSel->prev = NULL;
1380    botSel->next = NULL;
1381    AdjObjBBox(anchor);
1382    UpdSelBBox();
1383    RecordCmd(CMD_MANY_TO_ONE, NULL, topSel, botSel, 1);
1384    RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1385          sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
1386          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1387          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1388    HighLightForward();
1389    SetFileModified(TRUE);
1390    justDupped = FALSE;
1391 
1392    DoNameBroadcastWire(new_signal_name, signal_name_diff);
1393    EndCompositeCmd();
1394 }
1395 
1396 #define DO_RENAME_SIGNAL_NAME 99
1397 #define DO_CLEAR_SIGNAL_NAME 999
1398 
1399 static
DoNameOrClearAPort(which)1400 void DoNameOrClearAPort(which)
1401    int which;
1402 {
1403    struct AttrRec *first_attr_ptr=NULL;
1404    struct ObjRec *first_attr_owner_obj=NULL;
1405    int ltx=0, lty=0, rbx=0, rby=0;
1406    char signal_name[MAXSTRING];
1407    ChangeConnectionViewInfo ccvi;
1408 
1409    memset(&ccvi, 0, sizeof(ChangeConnectionViewInfo));
1410    first_attr_ptr = FindAttrWithName(gstWiringInfo.first_port_obj,
1411          "signal_name=", &first_attr_owner_obj);
1412    while (first_attr_owner_obj != NULL &&
1413          first_attr_owner_obj->tmp_parent != NULL) {
1414       first_attr_owner_obj = first_attr_owner_obj->tmp_parent;
1415    }
1416    if (first_attr_ptr == NULL) {
1417 #ifdef _TGIF_DBG /* debug, do not translate */
1418       TgAssert(FALSE,
1419             "first_attr_ptr is NULL in DoNameOrClearAPort()", NULL);
1420       return;
1421 #endif /* _TGIF_DBG */
1422    }
1423    *signal_name = '\0';
1424    if (which == DO_CLEAR_SIGNAL_NAME && *first_attr_ptr->attr_value.s == '\0') {
1425       /* already cleared */
1426       return;
1427    }
1428    if (which == DO_RENAME_SIGNAL_NAME) {
1429       UtilStrCpyN(signal_name, sizeof(signal_name),
1430             first_attr_ptr->attr_value.s);
1431       sprintf(gszMsgBox, TgLoadString(STID_PLS_ENT_SIG_NAME_FOR_PORT),
1432             gstWiringInfo.first_port_name);
1433       if (Dialog(gszMsgBox, NULL, signal_name) == INVALID) return;
1434       UtilTrimBlanks(signal_name);
1435    }
1436    if (strcmp(signal_name, first_attr_ptr->attr_value.s) == 0) {
1437       return;
1438    }
1439    ltx = first_attr_owner_obj->bbox.ltx;
1440    lty = first_attr_owner_obj->bbox.lty;
1441    rbx = first_attr_owner_obj->bbox.rbx;
1442    rby = first_attr_owner_obj->bbox.rby;
1443 
1444    if (HasConnAndDisConnViewObjSubObjs(first_attr_ptr->owner, &ccvi)) {
1445       ccvi.do_change_view = TRUE;
1446       if (*signal_name != '\0') {
1447          /* the port will become connected */
1448          ccvi.change_to_connect_view = TRUE;
1449       } else {
1450          /* the port will become disconnected */
1451          ccvi.change_to_connect_view = FALSE;
1452       }
1453    }
1454    ccvi.port_obj = gstWiringInfo.first_port_obj;
1455    ccvi.signal_name = signal_name;
1456    SetReplaceAttrValueCallback(
1457          (ReplAttrValueCallback*)ChangeConnectionView, &ccvi);
1458 
1459    ReplaceAttrFirstValue(first_attr_owner_obj, first_attr_ptr,
1460          signal_name);
1461    SetReplaceAttrValueCallback(NULL, NULL);
1462    RecursivelyAdjObjBBox(first_attr_ptr->owner, first_attr_ptr->owner,
1463          first_attr_owner_obj);
1464 
1465    SetFileModified(TRUE);
1466    justDupped = FALSE;
1467    RedrawAreas(botObj,
1468          ltx-QUARTER_INCH-GRID_ABS_SIZE(1), lty-QUARTER_INCH-GRID_ABS_SIZE(1),
1469          rbx+QUARTER_INCH+GRID_ABS_SIZE(1), rby+QUARTER_INCH+GRID_ABS_SIZE(1),
1470          first_attr_owner_obj->bbox.ltx-QUARTER_INCH-GRID_ABS_SIZE(1),
1471          first_attr_owner_obj->bbox.lty-QUARTER_INCH-GRID_ABS_SIZE(1),
1472          first_attr_owner_obj->bbox.rbx+QUARTER_INCH+GRID_ABS_SIZE(1),
1473          first_attr_owner_obj->bbox.rby+QUARTER_INCH+GRID_ABS_SIZE(1));
1474 }
1475 
1476 static
DoRenameOrClearSignalNameForAPort(which)1477 void DoRenameOrClearSignalNameForAPort(which)
1478    int which;
1479 {
1480    int naming=TRUE;
1481 
1482    ShowCurChoiceMouseStatus(DRAWPOLY, 0, FALSE);
1483    SetHandCursor(drawWindow);
1484    while (naming) {
1485       XEvent input;
1486 
1487       XNextEvent(mainDisplay, &input);
1488       if (input.type == Expose || input.type == VisibilityNotify) {
1489          ExposeEventHandler(&input, TRUE);
1490       } else if (input.type == ConfigureNotify) {
1491          Reconfigure(FALSE);
1492       } else if (input.xany.window == drawWindow && input.type == ButtonPress) {
1493          if (input.xbutton.button == Button1) {
1494             if (drawPolyHighlightedNode != NULL) {
1495                HandlePressForPortInDrawWindow(FALSE);
1496                DoNameOrClearAPort(which);
1497                drawPolyHighlightedNode = NULL;
1498                SetWiringNodeInfo(NULL, NULL, NULL, TRUE);
1499                SetHandCursor(drawWindow);
1500                ShowCurChoiceMouseStatus(DRAWPOLY, 0, FALSE);
1501             }
1502          } else {
1503             XUngrabPointer(mainDisplay, CurrentTime);
1504             naming = FALSE;
1505             HandlePressForPortInDrawWindow(TRUE);
1506          }
1507       } else if (input.xany.window == drawWindow &&
1508             input.type == MotionNotify) {
1509          XEvent ev;
1510 
1511          HandleMotionForPortInDrawWindow(input.xmotion.x, input.xmotion.y);
1512          while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1513       } else if (input.type == KeyPress) {
1514          if (KeyPressEventIsEscape(&input.xkey)) {
1515             XUngrabPointer(mainDisplay, CurrentTime);
1516             naming = FALSE;
1517             HandlePressForPortInDrawWindow(TRUE);
1518          }
1519       }
1520    }
1521    SetDefaultCursor(drawWindow);
1522 }
1523 
1524 static
RenameOrClearSignalNameForAPort(which)1525 void RenameOrClearSignalNameForAPort(which)
1526    int which;
1527 {
1528    XGCValues values;
1529 
1530    MakeQuiescent();
1531 
1532    ResetWiringNodeInfo();
1533    connectingPortsByWire = TRUE;
1534    connectingPortsFromInternalCommand = FALSE;
1535    gstWiringInfo.num_ports_to_connect = which;
1536    drawPolyHighlightedNode = NULL;
1537 
1538    values.line_width = 3;
1539    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
1540 
1541    SaveStatusStrings();
1542    DoRenameOrClearSignalNameForAPort(which);
1543    RestoreStatusStrings();
1544 
1545    values.line_width = 1;
1546    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
1547 
1548    gstWiringInfo.num_ports_to_connect = 0;
1549    connectingPortsByWire = FALSE;
1550    connectingPortsFromInternalCommand = TRUE;
1551    ResetWiringNodeInfo();
1552    drawPolyHighlightedNode = NULL;
1553 }
1554 
RenameSignalNameForAPort()1555 void RenameSignalNameForAPort()
1556 {
1557    RenameOrClearSignalNameForAPort(DO_RENAME_SIGNAL_NAME);
1558 }
1559 
ClearSignalNameForAPort()1560 void ClearSignalNameForAPort()
1561 {
1562    RenameOrClearSignalNameForAPort(DO_CLEAR_SIGNAL_NAME);
1563 }
1564 
1565 static
CheckPortsAndObj(ppAnchor,pnNumPorts)1566 int CheckPortsAndObj(ppAnchor, pnNumPorts)
1567    struct ObjRec **ppAnchor;
1568    int *pnNumPorts;
1569 {
1570    int num_ports=0, ok=TRUE;
1571    struct ObjRec *anchor=NULL;
1572    struct SelRec *sel_ptr=NULL;
1573 
1574    for (sel_ptr=botSel; ok && sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1575       struct AttrRec *attr_ptr=NULL;
1576 
1577       switch (sel_ptr->obj->type) {
1578       case OBJ_GROUP:
1579       case OBJ_SYM:
1580       case OBJ_ICON:
1581       case OBJ_PIN:
1582          if ((attr_ptr=FindAttrWithName(sel_ptr->obj, "type=", NULL)) != NULL) {
1583             if (strcmp(attr_ptr->attr_value.s, "port") == 0 &&
1584                   FindAttrWithName(sel_ptr->obj, "signal_name=",
1585                   NULL) != NULL) {
1586                num_ports++;
1587             } else if (anchor == NULL) {
1588                anchor = sel_ptr->obj;
1589             } else {
1590                return FALSE;
1591             }
1592          } else if (anchor == NULL) {
1593             anchor = sel_ptr->obj;
1594          } else {
1595             return FALSE;
1596          }
1597          break;
1598       default:
1599          return FALSE;
1600          break;
1601       }
1602    }
1603    if (anchor == NULL || num_ports == 0) {
1604       return FALSE;
1605    }
1606    *pnNumPorts = num_ports;
1607    *ppAnchor = anchor;
1608 
1609    return TRUE;
1610 }
1611 
MergePortsWithAnObject()1612 void MergePortsWithAnObject()
1613 {
1614    int num_ports=0;
1615    int sel_ltx=selLtX, sel_lty=selLtY, sel_rbx=selRbX, sel_rby=selRbY;
1616    struct ObjRec *anchor=NULL;
1617    struct SelRec *sel_ptr=NULL;
1618 
1619    if (!CheckPortsAndObj(&anchor, &num_ports)) {
1620       MsgBox(TgLoadString(STID_SEL_ONE_NONE_PORT_PLUS_COMP), TOOL_NAME,
1621             INFO_MB);
1622       return;
1623    }
1624    HighLightReverse();
1625    PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
1626 
1627    for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
1628       if (sel_ptr->obj != anchor) {
1629          UnlinkObj(sel_ptr->obj);
1630          AddObjToAnchor(anchor, sel_ptr->obj);
1631       }
1632    }
1633    RemoveAllSel();
1634    UnlinkObj(anchor);
1635    AddObj(NULL, topObj, anchor);
1636    topSel = botSel = (struct SelRec *)malloc(sizeof(struct SelRec));
1637    if (topSel == NULL) FailAllocMessage();
1638    topSel->obj = anchor;
1639    topSel->prev = NULL;
1640    botSel->next = NULL;
1641    AdjObjBBox(anchor);
1642    UpdSelBBox();
1643    RecordCmd(CMD_MANY_TO_ONE, NULL, topSel, botSel, 1);
1644    RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
1645          sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
1646          selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1647          selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1648    HighLightForward();
1649    SetFileModified(TRUE);
1650    justDupped = FALSE;
1651 }
1652 
1653 static
RenumberObjId(obj_ptr)1654 void RenumberObjId(obj_ptr)
1655    struct ObjRec *obj_ptr;
1656 {
1657    struct AttrRec *attr_ptr=NULL;
1658    struct ObjRec *sub_obj=NULL;
1659 
1660    obj_ptr->id = objId++;
1661 
1662    switch (obj_ptr->type) {
1663    case OBJ_GROUP:
1664    case OBJ_ICON:
1665    case OBJ_SYM:
1666    case OBJ_PIN:
1667       for (sub_obj=obj_ptr->detail.r->last; sub_obj != NULL;
1668             sub_obj=sub_obj->prev) {
1669          RenumberObjId(sub_obj);
1670       }
1671       break;
1672    }
1673    for (attr_ptr=obj_ptr->lattr; attr_ptr != NULL; attr_ptr=attr_ptr->prev) {
1674       RenumberObjId(attr_ptr->obj);
1675    }
1676 }
1677 
RenumberObjectIds()1678 void RenumberObjectIds()
1679 {
1680    struct PageRec *page_ptr=NULL;
1681 
1682    if (gstWBInfo.do_whiteboard) {
1683       MsgBox(TgLoadString(STID_RENUMBER_OBJ_IDS_IN_WB), TOOL_NAME, INFO_MB);
1684       return;
1685    }
1686    if (!OkToFlushUndoBuffer(TgLoadString(STID_RENUMBER_OBJ_IDS_CAUSE_FLUSH))) {
1687       return;
1688    }
1689    MakeQuiescent();
1690    CleanUpCmds();
1691 
1692    objId = 0;
1693    for (page_ptr=firstPage; page_ptr != NULL; page_ptr=page_ptr->next) {
1694       struct ObjRec *obj_ptr=NULL;
1695 
1696       for (obj_ptr=page_ptr->bot; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
1697          RenumberObjId(obj_ptr);
1698       }
1699    }
1700    MsgBox(TgLoadString(STID_RENUMBER_OBJ_IDS_DONE), TOOL_NAME, INFO_MB);
1701    SetFileModified(TRUE);
1702 }
1703 
MakeSymbolic()1704 void MakeSymbolic()
1705 {
1706    int ltx=selLtX, lty=selLtY, rbx=selRbX, rby=selRbY;
1707    struct ObjRec *obj_ptr=NULL;
1708 
1709    if (curChoice == VERTEXMODE) {
1710       MsgBox(TgLoadString(STID_CANT_MAKESYMBOLIC_VERTEX_MODE), TOOL_NAME,
1711             INFO_MB);
1712       return;
1713    } else if (topSel == NULL || topSel != botSel) {
1714       MsgBox(TgLoadString(STID_SEL_ONLY_ONE_FOR_MAKESYMBOLIC), TOOL_NAME,
1715             INFO_MB);
1716       return;
1717    }
1718    obj_ptr = topSel->obj;
1719    if (obj_ptr->type == OBJ_SYM) return;
1720    if (obj_ptr->type == OBJ_PIN) {
1721       MsgBox(TgLoadString(STID_PIN_CANT_MADE_INTO_SYMBOL), TOOL_NAME, INFO_MB);
1722       return;
1723    }
1724    HighLightReverse();
1725    PrepareToReplaceAnObj(obj_ptr);
1726 /*
1727  * Need to check for pins.
1728  */
1729    if (obj_ptr->type != OBJ_GROUP && obj_ptr->type != OBJ_ICON) {
1730       GroupSingleObj(FALSE);
1731       obj_ptr = topSel->obj;
1732       if (obj_ptr->fattr != NULL) {
1733          Msg(TgLoadCachedString(CSTID_ATTR_PROMOTED_TO_NEW_SYMBOL));
1734       }
1735    }
1736    obj_ptr->type = OBJ_SYM;
1737    AdjObjBBox(obj_ptr);
1738    UpdSelBBox();
1739    RecordReplaceAnObj(obj_ptr);
1740 
1741    UpdSelBBox();
1742    RedrawAnArea(botObj,
1743          ltx-QUARTER_INCH-GRID_ABS_SIZE(1), lty-QUARTER_INCH-GRID_ABS_SIZE(1),
1744          rbx+QUARTER_INCH+GRID_ABS_SIZE(1), rby+QUARTER_INCH+GRID_ABS_SIZE(1));
1745    HighLightForward();
1746    SetFileModified(TRUE);
1747    justDupped = FALSE;
1748 
1749    Msg(TgLoadString(STID_SEL_OBJ_IS_NOW_SYMBOLIC));
1750 }
1751 
UnMakeSymbolic()1752 void UnMakeSymbolic()
1753 {
1754    register struct ObjRec *obj_ptr;
1755    register int ltx=0, lty=0, rbx=0, rby=0;
1756    struct SelRec *sel_ptr=topSel;
1757    int modified=FALSE;
1758 
1759    StartCompositeCmd();
1760    for ( ; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1761       obj_ptr = sel_ptr->obj;
1762       if (obj_ptr->type == OBJ_SYM) {
1763          PrepareToReplaceAnObj(obj_ptr);
1764          obj_ptr->type = OBJ_GROUP;
1765          AdjObjBBox(obj_ptr);
1766          RecordReplaceAnObj(obj_ptr);
1767          if (modified) {
1768             if (obj_ptr->bbox.ltx < ltx) ltx = obj_ptr->bbox.ltx;
1769             if (obj_ptr->bbox.lty < lty) lty = obj_ptr->bbox.lty;
1770             if (obj_ptr->bbox.rbx > rbx) rbx = obj_ptr->bbox.rbx;
1771             if (obj_ptr->bbox.rby > rby) rby = obj_ptr->bbox.rby;
1772          } else {
1773             ltx = obj_ptr->bbox.ltx; lty = obj_ptr->bbox.lty;
1774             rbx = obj_ptr->bbox.rbx; rby = obj_ptr->bbox.rby;
1775             modified = TRUE;
1776          }
1777       }
1778    }
1779    EndCompositeCmd();
1780    if (modified) {
1781       HighLightReverse();
1782       UpdSelBBox();
1783       RedrawAnArea(botObj, ltx-QUARTER_INCH-GRID_ABS_SIZE(1),
1784             lty-QUARTER_INCH-GRID_ABS_SIZE(1),rbx+QUARTER_INCH+GRID_ABS_SIZE(1),
1785             rby+QUARTER_INCH+GRID_ABS_SIZE(1));
1786       HighLightForward();
1787       SetFileModified(TRUE);
1788       justDupped = FALSE;
1789    }
1790 }
1791 
MakeIconic(sym_path,record_cmd)1792 int MakeIconic(sym_path, record_cmd)
1793    char *sym_path;
1794    int record_cmd;
1795 {
1796    char icon_name[MAXPATHLENGTH], file_name[MAXPATHLENGTH];
1797    char icon_full_name[MAXPATHLENGTH], *rest=NULL, *psz=NULL;
1798    char sym_ext_str[MAXSTRING];
1799    FILE *fp=NULL;
1800    int len, short_name, sym_ext_len, ltx, lty, rbx, rby, no_name=FALSE;
1801 
1802    if (topSel == NULL || topSel != botSel) {
1803       MsgBox(TgLoadString(STID_SEL_ONLY_ONE_FOR_MAKEICONIC), TOOL_NAME,
1804             INFO_MB);
1805       return FALSE;
1806    }
1807    if (sym_path == NULL) {
1808       *icon_name = '\0';
1809       Dialog(TgLoadString(STID_ENTER_NAME_FOR_THE_ICON), NULL, icon_name);
1810       len = strlen(icon_name);
1811       if (*icon_name == '\0') {
1812          Msg(TgLoadString(STID_NAME_NOT_SPEC_ICON_NOT_CREATE));
1813          return FALSE;
1814       }
1815    } else {
1816       strncpy(icon_name, sym_path, sizeof(icon_name)-1);
1817       icon_name[sizeof(icon_name)-1] = '\0';
1818       len = strlen(icon_name);
1819    }
1820    sprintf(sym_ext_str, ".%s", SYM_FILE_EXT);
1821    sym_ext_len = strlen(sym_ext_str);
1822 
1823    if (FileNameHasExtension(icon_name, OBJ_FILE_TYPE, NULL, NULL)) {
1824       MsgBox(TgLoadString(STID_CANT_SAVE_OBJ_ICON_NOT_CREATE), TOOL_NAME,
1825             INFO_MB);
1826       return FALSE;
1827    } else if (FileNameHasExtension(icon_name, SYM_FILE_TYPE, NULL, NULL)) {
1828       strcpy(icon_full_name, icon_name);
1829       if ((psz=UtilStrRChr(icon_name, '.')) != NULL) {
1830          *psz = '\0';
1831       } else {
1832          TgAssert(FALSE, TgLoadString(STID_CANT_FIND_DOT_IN_ICON_NAME_MI),
1833                NULL);
1834          return FALSE;
1835       }
1836    } else if (FileNameHasExtension(icon_name, PIN_FILE_TYPE, NULL, NULL)) {
1837       MsgBox(TgLoadString(STID_CANT_SAVE_PIN_ICON_NOT_CREATE), TOOL_NAME,
1838             INFO_MB);
1839       return FALSE;
1840    } else {
1841       strcpy(icon_full_name, icon_name);
1842       strcat(icon_full_name, sym_ext_str);
1843    }
1844    if (no_name) {
1845       MsgBox(TgLoadString(STID_NO_FILE_NAME_FILE_NOT_SAVED), TOOL_NAME,
1846             INFO_MB);
1847       return FALSE;
1848    }
1849    if (sym_path == NULL) {
1850       sprintf(file_name, "%s%c%s", curDir, DIR_SEP, icon_full_name);
1851    } else {
1852       strcpy(file_name, icon_full_name);
1853    }
1854    if (!OkayToCreateFile(file_name)) return FALSE;
1855    if ((short_name=IsPrefix(bootDir, file_name, &rest))) ++rest;
1856 
1857    if ((fp=fopen(file_name, "w")) == NULL) {
1858       sprintf(gszMsgBox, TgLoadString(STID_CANT_OPEN_FOR_WRITE_ICON_CRET),
1859             (short_name ? rest : file_name));
1860       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1861       return FALSE;
1862    }
1863    if (sym_path == NULL) {
1864       if (!DirInSymPath(curDir)) UpdateSymInfo();
1865    }
1866    sprintf(gszMsgBox, TgLoadCachedString(CSTID_CREATING_FILE_DOTS),
1867          (short_name ? rest : file_name));
1868    Msg(gszMsgBox);
1869    SetStringStatus(gszMsgBox);
1870 
1871    ltx = selLtX; lty = selLtY; rbx = selRbX; rby = selRbY;
1872 
1873    if (record_cmd) {
1874       PrepareToRecord(CMD_REPLACE, topSel, botSel, numObjSelected);
1875    }
1876    if (topSel->obj->type == OBJ_GROUP || topSel->obj->type == OBJ_SYM ||
1877          topSel->obj->type == OBJ_ICON || topSel->obj->type == OBJ_PIN) {
1878       JustMoveSelToTop();
1879    } else {
1880       GroupSingleObj(FALSE);
1881       if (topSel->obj->fattr != NULL) {
1882          Msg(TgLoadCachedString(CSTID_ATTR_PROMOTED_TO_NEW_ICON));
1883       }
1884    }
1885 
1886    topSel->obj->type = OBJ_SYM;
1887    strcpy(topSel->obj->detail.r->s, icon_name);
1888    topSel->obj->detail.r->rotate = ROTATE0;
1889    topSel->obj->detail.r->flip = NO_FLIP;
1890    topSel->obj->detail.r->deck_index = (-1);
1891 /*
1892  * Need to check for pins.
1893  * Need to handle the case where connection objects need to be dupped!
1894  */
1895    topSel->obj->detail.r->pin_connected = 0;
1896    topSel->obj->detail.r->first_conn = topSel->obj->detail.r->last_conn =
1897          NULL;
1898 
1899    writeFileFailed = FALSE;
1900    Save(fp, topSel->obj, 0, 1);
1901 
1902    if (writeFileFailed) {
1903       writeFileFailed = FALSE;
1904       FailToWriteFileMessage(file_name);
1905       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1906       unlink(file_name);
1907    } else {
1908       sprintf(gszMsgBox, TgLoadCachedString(CSTID_NAMED_FILE_CREATED),
1909             (short_name ? rest : file_name));
1910       Msg(gszMsgBox);
1911    }
1912    fclose(fp);
1913 
1914    if (record_cmd) {
1915       HighLightReverse();
1916    }
1917    topSel->obj->type = OBJ_ICON;
1918    topSel->obj->id = objId++;
1919    Msg(TgLoadString(STID_SEL_OBJ_IS_NOW_ICONIC));
1920    AdjObjBBox(topSel->obj);
1921    UpdSelBBox();
1922    if (record_cmd) {
1923       RecordCmd(CMD_REPLACE, NULL, topSel, botSel, numObjSelected);
1924       ltx = min(ltx,selLtX); lty = min(lty,selLtY);
1925       rbx = max(rbx,selRbX); rby = max(rby,selRbY);
1926       RedrawAnArea(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
1927             rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1));
1928       HighLightForward();
1929       SetFileModified(TRUE);
1930       justDupped = FALSE;
1931    }
1932    return TRUE;
1933 }
1934 
UnMakeIconic()1935 void UnMakeIconic()
1936 {
1937    register struct ObjRec *obj_ptr;
1938    struct SelRec *sel_ptr;
1939    struct AttrRec *attr_ptr;
1940    int modified=FALSE;
1941 
1942    HighLightReverse();
1943    StartCompositeCmd();
1944    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
1945       obj_ptr = sel_ptr->obj;
1946 /*
1947  * Need to check for pins.
1948  */
1949       if (obj_ptr->type == OBJ_ICON) {
1950          modified = TRUE;
1951          PrepareToReplaceAnObj(obj_ptr);
1952          obj_ptr->type = OBJ_GROUP;
1953          attr_ptr = obj_ptr->fattr;
1954          for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
1955             attr_ptr->inherited = FALSE;
1956          }
1957          AdjObjBBox(obj_ptr);
1958          RecordReplaceAnObj(obj_ptr);
1959       }
1960    }
1961    EndCompositeCmd();
1962    if (modified) {
1963       Msg(TgLoadString(STID_SEL_OBJS_ARE_NOW_GROUP));
1964       UpdSelBBox();
1965       RedrawAnArea(botObj, selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
1966             selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
1967       SetFileModified(TRUE);
1968       justDupped = FALSE;
1969    }
1970    HighLightForward();
1971 }
1972 
1973 typedef struct ImportAttrLineRec {
1974    char *s;
1975    struct ImportAttrLineRec *next, *prev;
1976 } *ImportAttrLineRecPtr;
1977 
1978 static struct ImportAttrLineRec *firstLine=NULL, *lastLine=NULL;
1979 static int numLines=0, nextX=0, nextY=0;
1980 static CVList gLineList;
1981 
1982 static
AddLine(buf)1983 void AddLine(buf)
1984    char *buf;
1985 {
1986    struct ImportAttrLineRec *line_ptr;
1987 
1988    line_ptr = (struct ImportAttrLineRec *)malloc(
1989          sizeof(struct ImportAttrLineRec));
1990    if (line_ptr == NULL) FailAllocMessage();
1991    line_ptr->s = buf;
1992    line_ptr->next = NULL;
1993    line_ptr->prev = lastLine;
1994    if (lastLine == NULL) {
1995       firstLine = line_ptr;
1996    } else {
1997       lastLine->next = line_ptr;
1998    }
1999    lastLine = line_ptr;
2000    numLines++;
2001 }
2002 
2003 static
FreeImportLines()2004 void FreeImportLines()
2005 {
2006    struct ImportAttrLineRec *next_line=NULL;
2007 
2008    for ( ; firstLine != NULL; firstLine=next_line) {
2009       next_line = firstLine->next;
2010       if (firstLine->s != NULL) free(firstLine->s);
2011       free(firstLine);
2012    }
2013    lastLine = NULL;
2014    numLines = 0;
2015 }
2016 
2017 static
ImportAnAttr(obj_ptr,attr_line_num,fname)2018 void ImportAnAttr(obj_ptr, attr_line_num, fname)
2019    struct ObjRec *obj_ptr;
2020    int attr_line_num;
2021    char *fname;
2022 {
2023    int ok=TRUE;
2024    char *c_ptr;
2025 
2026    if (firstLine == NULL) return;
2027    if ((c_ptr=strchr(firstLine->s, '=')) == NULL) {
2028       sprintf(gszMsgBox, TgLoadString(STID_GIVEN_LINE_SKIP_NOT_AN_ATTR),
2029             attr_line_num, fname);
2030       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2031       ok = FALSE;
2032    } else {
2033       *c_ptr = '\0';
2034       if (strchr(firstLine->s, '!') != NULL ||
2035             strchr(firstLine->s, '.') != NULL) {
2036          sprintf(gszMsgBox, TgLoadString(STID_GIVEN_LINE_SKIP_ILLEGAL_CHAR),
2037                attr_line_num, fname);
2038          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2039          ok = FALSE;
2040       }
2041       *c_ptr = '=';
2042    }
2043    if (ok) {
2044       char saved_ch='\0', *attr_name=NULL;
2045       struct AttrRec *attr_ptr=NULL;
2046       struct TextRec *text_ptr=NULL;
2047       MiniLineInfo *pMiniLine=NULL, *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
2048       struct ImportAttrLineRec *line_ptr;
2049       int move_next_y=FALSE, underline_on=FALSE, single_font_text=FALSE;
2050       int sz_unit=INVALID, double_byte=INVALID, font=INVALID, style=INVALID;
2051       int color_index=INVALID, saved_color_index=INVALID, overline_on=FALSE;
2052 
2053       c_ptr++;
2054       saved_ch = (*c_ptr);
2055       *c_ptr = '\0';
2056       attr_name = UtilStrDup(firstLine->s);
2057       if (attr_name == NULL) FailAllocMessage();
2058       *c_ptr = saved_ch;
2059 
2060       if ((attr_ptr=FindAttrWithName(obj_ptr, attr_name, NULL)) == NULL) {
2061          attr_ptr = AddAttrByNameAndValue(obj_ptr, attr_name, c_ptr);
2062          attr_ptr->shown = TRUE;
2063          attr_ptr->obj->color = colorIndex;
2064          if (mainDisplay != NULL) {
2065             UtilStrCpyN(attr_ptr->obj->color_str,
2066                   sizeof(attr_ptr->obj->color_str), colorMenuItems[colorIndex]);
2067          }
2068          MoveObj(attr_ptr->obj, nextX-attr_ptr->obj->x, nextY-attr_ptr->obj->y);
2069          text_ptr = attr_ptr->obj->detail.t;
2070          pFirstMiniLine = pLastMiniLine = text_ptr->minilines.first;
2071          move_next_y = TRUE;
2072       } else {
2073          MiniLineInfo *pNextMiniLine=NULL;
2074 
2075          single_font_text = SingleFontText(attr_ptr->obj->detail.t, &sz_unit,
2076                &double_byte, &font, &style, &underline_on, &overline_on) &&
2077                SingleColorText(attr_ptr->obj->detail.t, &color_index);
2078          if (single_font_text) {
2079             saved_color_index = colorIndex;
2080 
2081             PushCurFont();
2082             colorIndex = color_index;
2083             curFont = font;
2084             curSzUnit = sz_unit;
2085             curStyle = style;
2086             SetCanvasFont();
2087          }
2088          DynStrSet(&attr_ptr->attr_value, c_ptr);
2089          text_ptr = attr_ptr->obj->detail.t;
2090          text_ptr->cached_zoom = 0;
2091          if (text_ptr->cached_bitmap != None) {
2092             XFreePixmap(mainDisplay, text_ptr->cached_bitmap);
2093          }
2094          text_ptr->cached_bitmap = None;
2095          for (pMiniLine=text_ptr->minilines.first->next; pMiniLine != NULL;
2096                pMiniLine=pNextMiniLine) {
2097             pNextMiniLine = pMiniLine->next;
2098             FreeMiniLine(pMiniLine);
2099          }
2100          pFirstMiniLine = pLastMiniLine = text_ptr->minilines.last =
2101                text_ptr->minilines.first;
2102          text_ptr->minilines.first->next = text_ptr->minilines.first->prev =
2103                NULL;
2104          text_ptr->lines = 1;
2105          UpdAttr(attr_ptr);
2106       }
2107       free(attr_name);
2108       for (line_ptr=firstLine->next; line_ptr!=NULL; line_ptr=line_ptr->next) {
2109          CreateMiniLineFromString(line_ptr->s, &pFirstMiniLine, &pLastMiniLine);
2110          text_ptr->lines++;
2111       }
2112       if (single_font_text) {
2113          colorIndex = saved_color_index;
2114          PopCurFont();
2115       }
2116       text_ptr->minilines.first = pFirstMiniLine;
2117       text_ptr->minilines.last = pLastMiniLine;
2118       text_ptr->baseline_y = attr_ptr->obj->y+pFirstMiniLine->asc;
2119       RecalcTextMetrics(text_ptr, attr_ptr->obj->x, text_ptr->baseline_y);
2120       UpdTextBBox(attr_ptr->obj);
2121       if (move_next_y) {
2122          nextY += attr_ptr->obj->obbox.rby-attr_ptr->obj->obbox.lty;
2123       }
2124    }
2125    FreeImportLines();
2126 }
2127 
ImportAttrs()2128 void ImportAttrs()
2129 {
2130    char fname[MAXPATHLENGTH+1], *rest, *buf;
2131    XEvent ev;
2132    int short_name, ltx, lty, rbx, rby, line_num=0, attr_line_num=1;
2133    int empty_line=TRUE;
2134    FILE *fp;
2135    struct ObjRec *obj_ptr;
2136 
2137    if (topSel == NULL || topSel != botSel) {
2138       MsgBox(TgLoadString(STID_SEL_ONE_OBJ_FOR_IMPORTATTRS), TOOL_NAME,
2139             INFO_MB);
2140       return;
2141    }
2142    if (SelectFileNameToImport(TgLoadString(STID_SEL_TEXT_FILE_OF_ATTR_TO_IMP),
2143          TEXT_FILE_EXT, fname) == INVALID) {
2144       return;
2145    } else if (FileIsRemote(fname)) {
2146       MsgBox(TgLoadString(STID_CANT_IMPORT_REMOTE_TEXT_FILE), TOOL_NAME,
2147             INFO_MB);
2148       return;
2149    }
2150    XSync(mainDisplay, False);
2151    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev)) {
2152       ExposeEventHandler(&ev, TRUE);
2153    }
2154    if ((short_name=IsPrefix(bootDir, fname, &rest))) ++rest;
2155    if ((fp=fopen(fname, "r")) == NULL) {
2156       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
2157             (short_name ? rest : fname));
2158       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2159       return;
2160    }
2161    obj_ptr = topSel->obj;
2162    ltx = obj_ptr->bbox.ltx; lty = obj_ptr->bbox.lty;
2163    rbx = obj_ptr->bbox.rbx; rby = obj_ptr->bbox.rby;
2164 
2165    SetWatchCursor(drawWindow);
2166    SetWatchCursor(mainWindow);
2167 
2168    HighLightReverse();
2169    PrepareToReplaceAnObj(obj_ptr);
2170 
2171    nextX = obj_ptr->obbox.ltx;
2172    nextY = obj_ptr->obbox.rby;
2173    while ((buf=UtilGetALine(fp)) != NULL) {
2174       line_num++;
2175       if (empty_line) {
2176          empty_line = FALSE;
2177          attr_line_num = line_num;
2178       }
2179       if (*buf == '\0') {
2180          ImportAnAttr(obj_ptr, attr_line_num, fname);
2181          empty_line = TRUE;
2182       } else {
2183          AddLine(buf);
2184       }
2185    }
2186    ImportAnAttr(obj_ptr, attr_line_num, fname);
2187    fclose(fp);
2188 
2189    AdjObjBBox(obj_ptr);
2190 
2191    RecordReplaceAnObj(obj_ptr);
2192 
2193    SetDefaultCursor(mainWindow);
2194    ShowCursor();
2195 
2196    UpdSelBBox();
2197    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2198          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2199          obj_ptr->bbox.ltx-GRID_ABS_SIZE(1),
2200          obj_ptr->bbox.lty-GRID_ABS_SIZE(1),
2201          obj_ptr->bbox.rbx+GRID_ABS_SIZE(1),
2202          obj_ptr->bbox.rby+GRID_ABS_SIZE(1));
2203    HighLightForward();
2204    SetFileModified(TRUE);
2205    justDupped = FALSE;
2206 }
2207 
2208 #define INA_SKIP      0 /* skip this attribute */
2209 #define INA_OK        1 /* import this attribute */
2210 #define INA_MALFORMED 2 /* illegal attribute */
2211 #define INA_NEW       3 /* import this new attribute */
2212 
2213 static
OkayToImportNamedAttr(num_restricted,ppsz_restricted)2214 int OkayToImportNamedAttr(num_restricted, ppsz_restricted)
2215    int num_restricted;
2216    char **ppsz_restricted;
2217 {
2218    int i=0, found=FALSE, rc=INA_OK;
2219    char *psz=NULL, saved_ch='\0';
2220 
2221    if (firstLine == NULL || firstLine->s == NULL) return INA_SKIP;
2222 
2223    psz = strchr(firstLine->s, '=');
2224    if (psz == NULL) {
2225       sprintf(gszMsgBox, TgLoadString(STID_BAD_LINE_MAY_HAVE_DEL_EQUAL),
2226             firstLine->s);
2227       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2228       return INA_MALFORMED;
2229    }
2230    saved_ch = *(++psz);
2231    *psz = '\0';
2232    for (i=0; i < num_restricted; i++) {
2233       char *attr_name=ppsz_restricted[i];
2234 
2235       if (strcmp(attr_name, firstLine->s) == 0) {
2236          found = TRUE;
2237          break;
2238       }
2239    }
2240    *psz = saved_ch;
2241 
2242    if (!found) {
2243       rc = INA_SKIP;
2244       *psz = '\0';
2245       sprintf(gszMsgBox, TgLoadString(STID_ATTR_NAME_CHANGED_IMPORT_Q),
2246             firstLine->s);
2247       switch (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB)) {
2248       case MB_ID_YES: rc = INA_NEW; break;
2249       case MB_ID_NO: break;
2250       case MB_ID_CANCEL: break;
2251       }
2252       *psz = saved_ch;
2253    }
2254    return rc;
2255 }
2256 
2257 typedef struct tagLineInfo {
2258    int status;
2259    int attr_line_num;
2260    int num_lines;
2261    struct ImportAttrLineRec *first, *last;
2262 } LineInfo;
2263 
2264 static
CreateLineInfo(status,attr_line_num)2265 void CreateLineInfo(status, attr_line_num)
2266     int status, attr_line_num;
2267 {
2268    LineInfo *pli=(LineInfo*)malloc(sizeof(LineInfo));
2269 
2270    if (pli == NULL) FailAllocMessage();
2271    memset(pli, 0, sizeof(LineInfo));
2272 
2273    pli->status = status;
2274    pli->attr_line_num = attr_line_num;
2275    pli->num_lines = numLines;
2276    pli->first = firstLine;
2277    pli->last = lastLine;
2278 
2279    firstLine = lastLine = NULL;
2280    numLines = 0;
2281 
2282    ListAppend(&gLineList, pli);
2283 }
2284 
2285 static
DoImportNamedAttrs(fp,num_restricted,ppsz_restricted,pn_ok_count,pn_skip_count,pn_bad_count)2286 void DoImportNamedAttrs(fp, num_restricted, ppsz_restricted, pn_ok_count,
2287       pn_skip_count, pn_bad_count)
2288    FILE *fp;
2289    int num_restricted, *pn_ok_count, *pn_skip_count, *pn_bad_count;
2290    char **ppsz_restricted;
2291 {
2292    char *buf=NULL;
2293    int bad_count=0, skip_count=0, ok_count=0, status=0;
2294    int line_num=0, attr_line_num=1, just_read_separator=TRUE;
2295 
2296    CVListInit(&gLineList);
2297 
2298    while ((buf=UtilGetALine(fp)) != NULL) {
2299       line_num++;
2300       if (just_read_separator) {
2301          just_read_separator = FALSE;
2302          attr_line_num = line_num;
2303       }
2304       if (strstr(buf, gszAttrSeparator) != NULL) {
2305          status = OkayToImportNamedAttr(num_restricted, ppsz_restricted);
2306 
2307          switch (status) {
2308          case INA_SKIP: skip_count++; FreeImportLines(); break;
2309          case INA_OK: ok_count++; CreateLineInfo(status, attr_line_num); break;
2310          case INA_MALFORMED: bad_count++; FreeImportLines(); break;
2311          case INA_NEW: ok_count++; CreateLineInfo(status, attr_line_num); break;
2312          }
2313          just_read_separator = TRUE;
2314       } else {
2315          AddLine(buf);
2316       }
2317    }
2318    if (!just_read_separator) {
2319       status = OkayToImportNamedAttr(num_restricted, ppsz_restricted);
2320 
2321       switch (status) {
2322       case INA_SKIP: skip_count++; FreeImportLines(); break;
2323       case INA_OK: ok_count++; CreateLineInfo(status, attr_line_num); break;
2324       case INA_MALFORMED: bad_count++; FreeImportLines(); break;
2325       case INA_NEW: ok_count++; CreateLineInfo(status, attr_line_num); break;
2326       }
2327    }
2328    if (pn_ok_count != NULL) *pn_ok_count = ok_count;
2329    if (pn_skip_count != NULL) *pn_skip_count = skip_count;
2330    if (pn_bad_count != NULL) *pn_bad_count = bad_count;
2331 }
2332 
ImportNamedAttrs(fp,obj_ptr,num_restricted,ppsz_restricted,fname)2333 int ImportNamedAttrs(fp, obj_ptr, num_restricted, ppsz_restricted, fname)
2334    FILE *fp;
2335    struct ObjRec *obj_ptr;
2336    int num_restricted;
2337    char **ppsz_restricted, *fname;
2338 {
2339    int ltx=0, lty=0, rbx=0, rby=0, bad_count=0, skip_count=0, ok_count=0;
2340    CVListElem *elem=NULL;
2341 
2342    ltx = obj_ptr->bbox.ltx; lty = obj_ptr->bbox.lty;
2343    rbx = obj_ptr->bbox.rbx; rby = obj_ptr->bbox.rby;
2344 
2345    DoImportNamedAttrs(fp, num_restricted, ppsz_restricted, &ok_count,
2346          &skip_count, &bad_count);
2347 
2348    if (bad_count > 0) {
2349       sprintf(gszMsgBox, TgLoadString(STID_CANT_IMPORT_ATTR_GROUP_RETRY),
2350             TOOL_NAME);
2351       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2352       return FALSE;
2353    }
2354    if (ListEmpty(&gLineList)) return TRUE;
2355 
2356    SetWatchCursor(drawWindow);
2357    SetWatchCursor(mainWindow);
2358 
2359    HighLightReverse();
2360    PrepareToReplaceAnObj(obj_ptr);
2361 
2362    nextX = obj_ptr->obbox.ltx;
2363    nextY = obj_ptr->obbox.rby;
2364 
2365    for (elem=ListFirst(&gLineList); elem != NULL;
2366          elem=ListNext(&gLineList, elem)) {
2367       LineInfo *pli=(LineInfo*)(elem->obj);
2368 
2369       if (pli != NULL) {
2370          int attr_line_num=pli->attr_line_num;
2371 
2372          firstLine = pli->first;
2373          lastLine = pli->last;
2374          numLines = pli->num_lines;
2375 
2376          ImportAnAttr(obj_ptr, attr_line_num, fname);
2377       }
2378       elem->obj = NULL;
2379    }
2380    ListUnlinkAll(&gLineList);
2381 
2382    AdjObjBBox(obj_ptr);
2383 
2384    RecordReplaceAnObj(obj_ptr);
2385 
2386    SetDefaultCursor(mainWindow);
2387    ShowCursor();
2388 
2389    UpdSelBBox();
2390    RedrawAreas(botObj, ltx-GRID_ABS_SIZE(1), lty-GRID_ABS_SIZE(1),
2391          rbx+GRID_ABS_SIZE(1), rby+GRID_ABS_SIZE(1),
2392          obj_ptr->bbox.ltx-GRID_ABS_SIZE(1),
2393          obj_ptr->bbox.lty-GRID_ABS_SIZE(1),
2394          obj_ptr->bbox.rbx+GRID_ABS_SIZE(1),
2395          obj_ptr->bbox.rby+GRID_ABS_SIZE(1));
2396    HighLightForward();
2397    SetFileModified(TRUE);
2398    justDupped = FALSE;
2399 
2400    return TRUE;
2401 }
2402 
ExportAttrs()2403 void ExportAttrs()
2404 {
2405    char fname[MAXPATHLENGTH+1], full_fname[MAXPATHLENGTH+1];
2406    char *c_ptr, *dot_ptr, *rest;
2407    int short_name;
2408    FILE *fp;
2409    struct AttrRec *attr_ptr;
2410 
2411    if (topSel == NULL || topSel != botSel) {
2412       MsgBox(TgLoadString(STID_SEL_ONE_OBJ_FOR_EXPORTATTRS), TOOL_NAME,
2413             INFO_MB);
2414       return;
2415    } else if (topSel->obj->lattr == NULL) {
2416       MsgBox(TgLoadString(STID_SEL_OBJ_HAS_NO_ATTR_TO_EXPORT), TOOL_NAME,
2417             INFO_MB);
2418       return;
2419    }
2420    sprintf(gszMsgBox, TgLoadString(STID_WORKING_DIRECTORY_IS),
2421          (curDirIsLocal ? curDir : curLocalDir));
2422    *fname = '\0';
2423    Dialog(TgLoadString(STID_ENTER_TXT_FILE_TO_EXPORT_CRES), gszMsgBox, fname);
2424    if (*fname == '\0') return;
2425    if (*fname == DIR_SEP) {
2426       strcpy(full_fname, fname);
2427    } else {
2428       sprintf(full_fname, "%s%c%s", curDirIsLocal ? curDir : curLocalDir,
2429             DIR_SEP, fname);
2430    }
2431    if ((c_ptr=UtilStrRChr(full_fname, (int)DIR_SEP)) == NULL) {
2432       if ((dot_ptr=UtilStrRChr(full_fname, (int)'.')) == NULL) {
2433          sprintf(&full_fname[strlen(full_fname)], ".%s", TEXT_FILE_EXT);
2434       } else {
2435          if (strcmp(&dot_ptr[1], TEXT_FILE_EXT) != 0) {
2436             sprintf(&dot_ptr[strlen(dot_ptr)], ".%s", TEXT_FILE_EXT);
2437          }
2438       }
2439    } else {
2440       if ((dot_ptr=UtilStrRChr(c_ptr, (int)'.')) == NULL) {
2441          sprintf(&c_ptr[strlen(c_ptr)], ".%s", TEXT_FILE_EXT);
2442       } else {
2443          if (strcmp(&dot_ptr[1], TEXT_FILE_EXT) != 0) {
2444             sprintf(&dot_ptr[strlen(dot_ptr)], ".%s", TEXT_FILE_EXT);
2445          }
2446       }
2447    }
2448    if (!OkayToCreateFile(full_fname)) return;
2449 
2450    if ((short_name=IsPrefix(bootDir, full_fname, &rest))) ++rest;
2451    if ((fp=fopen(full_fname, "w")) == NULL) {
2452       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
2453             (short_name ? rest : full_fname));
2454       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2455       return;
2456    }
2457    sprintf(gszMsgBox, TgLoadCachedString(CSTID_WRITING_ATTR_TO_NAMED_FILE),
2458          (short_name ? rest : full_fname));
2459    Msg(gszMsgBox);
2460    writeFileFailed = FALSE;
2461 
2462    for (attr_ptr=topSel->obj->lattr; !writeFileFailed && attr_ptr != NULL;
2463          attr_ptr=attr_ptr->prev) {
2464       MiniLineInfo *pMiniLine=NULL;
2465 
2466       if (attr_ptr != topSel->obj->lattr) fprintf(fp, "\n");
2467       if (fprintf(fp, "%s%s\n", attr_ptr->attr_name.s,
2468             attr_ptr->attr_value.s) == EOF) {
2469          writeFileFailed = TRUE;
2470       }
2471       if (!writeFileFailed &&
2472             (pMiniLine=attr_ptr->obj->detail.t->minilines.first) != NULL) {
2473          for (pMiniLine=pMiniLine->next; !writeFileFailed && pMiniLine != NULL;
2474                pMiniLine=pMiniLine->next) {
2475             int need_to_free_tmp_buf=FALSE;
2476             char *tmp_buf=ConvertMiniLineToString(pMiniLine,
2477                   &need_to_free_tmp_buf);
2478 
2479             if (fprintf(fp, "%s\n", tmp_buf) == EOF) {
2480                writeFileFailed = TRUE;
2481             }
2482             if (need_to_free_tmp_buf) UtilFree(tmp_buf);
2483             if (writeFileFailed) break;
2484          }
2485       }
2486    }
2487    if (writeFileFailed) {
2488       writeFileFailed = FALSE;
2489       FailToWriteFileMessage(full_fname);
2490    } else {
2491       sprintf(gszMsgBox, TgLoadString(STID_ATTR_EXPORTED_TO_NAMED_FILE),
2492             (short_name ? rest : full_fname));
2493       Msg(gszMsgBox);
2494    }
2495    fclose(fp);
2496 }
2497 
2498 static
GetMergeSpec(obj_ptr,attr_name,pn_val,distance)2499 int GetMergeSpec(obj_ptr, attr_name, pn_val, distance)
2500    struct ObjRec *obj_ptr;
2501    char *attr_name;
2502    int *pn_val, distance;
2503 {
2504    struct AttrRec *attr_ptr=FindAttrWithName(obj_ptr, attr_name, NULL);
2505    char *c_ptr;
2506    double val;
2507 
2508    if (attr_ptr == NULL) {
2509       sprintf(gszMsgBox, TgLoadString(STID_CANT_FIND_ATTR_FOR_MERGEWTBL),
2510             attr_name);
2511       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2512       return FALSE;
2513    }
2514    if (distance && ((c_ptr=strstr(attr_ptr->attr_value.s, "in")) != NULL ||
2515          (c_ptr=strstr(attr_ptr->attr_value.s, "In")) != NULL ||
2516          (c_ptr=strstr(attr_ptr->attr_value.s, "IN")) != NULL)) {
2517       char saved_ch=(*c_ptr);
2518 
2519       *c_ptr = '\0';
2520       if (sscanf(attr_ptr->attr_value.s, "%lf", &val) != 1) {
2521          *c_ptr = saved_ch;
2522          sprintf(gszMsgBox, TgLoadString(STID_MALFORMED_ATTR_FOR_MERGEWTBL),
2523                attr_name);
2524          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2525          return FALSE;
2526       }
2527       *c_ptr = saved_ch;
2528       val = val * ((double)PIX_PER_INCH);
2529       *pn_val = round(val);
2530    } else if (distance &&
2531          ((c_ptr=strstr(attr_ptr->attr_value.s, "cm")) != NULL ||
2532          (c_ptr=strstr(attr_ptr->attr_value.s, "Cm")) != NULL ||
2533          (c_ptr=strstr(attr_ptr->attr_value.s, "CM")) != NULL)) {
2534       char saved_ch=(*c_ptr);
2535 
2536       *c_ptr = '\0';
2537       if (sscanf(attr_ptr->attr_value.s, "%lf", &val) != 1) {
2538          *c_ptr = saved_ch;
2539          sprintf(gszMsgBox, TgLoadString(STID_MALFORMED_ATTR_FOR_MERGEWTBL),
2540                attr_name);
2541          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2542          return FALSE;
2543       }
2544       *c_ptr = saved_ch;
2545       val = val * ((double)ONE_CM);
2546       *pn_val = round(val);
2547    } else {
2548       if (sscanf(attr_ptr->attr_value.s, "%d", pn_val) != 1) {
2549          sprintf(gszMsgBox, TgLoadString(STID_MALFORMED_ATTR_FOR_MERGEWTBL),
2550                attr_name);
2551          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2552          return FALSE;
2553       }
2554    }
2555    return TRUE;
2556 }
2557 
MergeWithTable()2558 void MergeWithTable()
2559 {
2560    char fname[MAXPATHLENGTH+1], *rest, paper_size_spec[80], *spec, **col_names;
2561    char *buf, *c_ptr, *val_ptr;
2562    XEvent ev;
2563    int i, short_name, columns_in_file, ok=TRUE, line_num, user_placement;
2564    int left_margin=0, top_margin=0, v_pitch=0, h_pitch=0, strip_double_quotes;
2565    int num_cols=0, num_rows=0, paper_w=0, paper_h=0, x, y, r, c;
2566    int tab_separated=TRUE;
2567    FILE *fp;
2568    struct ObjRec *template_obj;
2569 
2570    if (topSel == NULL || topSel != botSel) {
2571       MsgBox(TgLoadString(STID_SEL_ONE_OBJ_FOR_MERGEWTBL), TOOL_NAME, INFO_MB);
2572       return;
2573    }
2574    /* do not translate -- program constants */
2575    template_obj = topSel->obj;
2576    user_placement = (FindAttrWithName(template_obj, "USER_PLACEMENT", NULL) !=
2577          NULL);
2578    strip_double_quotes = (FindAttrWithName(template_obj, "STRIP_DOUBLE_QUOTES",
2579          NULL) != NULL);
2580    if (!user_placement) {
2581       /* do not translate -- program constants */
2582       if (!(GetMergeSpec(template_obj, "LEFT_MARGIN=", &left_margin, TRUE) &&
2583             GetMergeSpec(template_obj, "TOP_MARGIN=", &top_margin, TRUE) &&
2584             GetMergeSpec(template_obj, "V_PITCH=", &v_pitch, TRUE) &&
2585             GetMergeSpec(template_obj, "H_PITCH=", &h_pitch, TRUE) &&
2586             GetMergeSpec(template_obj, "NUM_COLS=", &num_cols, FALSE) &&
2587             GetMergeSpec(template_obj, "NUM_ROWS=", &num_rows, FALSE) &&
2588             GetMergeSpec(template_obj, "PAPER_WIDTH=", &paper_w, TRUE) &&
2589             GetMergeSpec(template_obj, "PAPER_HEIGHT=", &paper_h, TRUE))) {
2590          return;
2591       }
2592    }
2593    while (!DirIsRemote(curDir) && fileModified && !IsFiletUnSavable()) {
2594       XBell(mainDisplay, 0);
2595       switch (MsgBox(TgLoadString(STID_FILE_MOD_SAVE_BEFORE_MERGE), TOOL_NAME,
2596             YNC_MB)) {
2597       case MB_ID_YES: SaveFile(); break;
2598       case MB_ID_NO: SetFileModified(FALSE); break;
2599       case MB_ID_CANCEL: return;
2600       }
2601    }
2602    if (firstCmd != NULL) {
2603       if (MsgBox(TgLoadString(STID_Q_MERGEWTBL_CANT_UNDO_PROCEED), TOOL_NAME,
2604             YNC_MB) != MB_ID_YES) {
2605          return;
2606       }
2607       CleanUpCmds();
2608    }
2609    if (SelectFileNameToImport(TgLoadString(STID_SEL_TEXT_FILE_FOR_MERGEWTBL),
2610          TEXT_FILE_EXT, fname) == INVALID) {
2611       return;
2612    } else if (FileIsRemote(fname)) {
2613       MsgBox(TgLoadString(STID_CANT_MERGE_W_REMOTE_TEXT_FILE), TOOL_NAME,
2614             INFO_MB);
2615       return;
2616    }
2617    XSync(mainDisplay, False);
2618    if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev)) {
2619       ExposeEventHandler(&ev, TRUE);
2620    }
2621    if ((short_name=IsPrefix(bootDir, fname, &rest))) ++rest;
2622    if ((fp=fopen(fname, "r")) == NULL) {
2623       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
2624             (short_name ? rest : fname));
2625       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2626       return;
2627    }
2628    if ((spec=UtilGetALine(fp)) == NULL) {
2629       fclose(fp);
2630       sprintf(gszMsgBox, TgLoadString(STID_FIND_COL_NAMES_IN_FILE_ABORT),
2631             (short_name ? rest : fname));
2632       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2633       return;
2634    }
2635    columns_in_file = 1;
2636    val_ptr = spec;
2637    c_ptr = strchr(val_ptr, '\t');
2638    if (c_ptr == NULL && (c_ptr=strchr(val_ptr, ';')) != NULL) {
2639       tab_separated = FALSE;
2640       Msg(TgLoadCachedString(CSTID_SEMICOLON_USED_AS_SEPARATOR));
2641    } else {
2642       Msg(TgLoadCachedString(CSTID_TAB_USED_AS_SEPARATOR));
2643    }
2644    while (val_ptr != NULL) {
2645       if (c_ptr != NULL) *c_ptr = '\0';
2646       if (*val_ptr == '\0') {
2647          free(spec);
2648          fclose(fp);
2649          sprintf(gszMsgBox, TgLoadString(STID_MALFORMED_COL_NAMES_ABORT_MRG),
2650                (short_name ? rest : fname));
2651          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2652          return;
2653       }
2654       if (c_ptr == NULL) break;
2655       *c_ptr++ = (tab_separated ? '\t' : ';');
2656       val_ptr = c_ptr;
2657       c_ptr = strchr(val_ptr, tab_separated ? '\t' : ';');
2658 
2659       columns_in_file++;
2660    }
2661    col_names = (char**)malloc((columns_in_file+1)*sizeof(char*));
2662    if (col_names == NULL) {
2663       free(spec);
2664       fclose(fp);
2665       FailAllocMessage();
2666       return;
2667    }
2668    col_names[columns_in_file] = NULL;
2669    i = 0;
2670    val_ptr = spec;
2671    for (c_ptr=strchr(val_ptr, tab_separated ? '\t' : ';'); val_ptr != NULL;
2672          i++) {
2673       int len;
2674 
2675       if (c_ptr != NULL) *c_ptr = '\0';
2676       if (!tab_separated) {
2677          UtilTrimBlanks(val_ptr);
2678          if (strip_double_quotes && *val_ptr == '"') {
2679             len = strlen(val_ptr);
2680 
2681             if (val_ptr[len-1] == '"') {
2682                val_ptr[len-1] = '\0';
2683                val_ptr++;
2684             }
2685          }
2686       }
2687       len = strlen(val_ptr);
2688       if ((col_names[i]=(char*)malloc((len+2)*sizeof(char))) == NULL) {
2689          FailAllocMessage();
2690          columns_in_file = i;
2691          for (i=0; i < columns_in_file; i++) {
2692             if (col_names[i] != NULL) {
2693                free(col_names[i]);
2694             }
2695          }
2696          free(col_names);
2697          free(spec);
2698          fclose(fp);
2699          return;
2700       }
2701       sprintf(col_names[i], "%s=", val_ptr);
2702       if (FindAttrWithName(template_obj, col_names[i], NULL) == NULL) {
2703          free(col_names[i]);
2704          col_names[i] = NULL;
2705       }
2706       if (c_ptr == NULL) break;
2707       *c_ptr++ = (tab_separated ? '\t' : ';');
2708       val_ptr = c_ptr;
2709       c_ptr = strchr(val_ptr, tab_separated ? '\t' : ';');
2710    }
2711    free(spec);
2712 
2713    MakeQuiescent();
2714    UnlinkObj(template_obj);
2715    NewProc();
2716    if (pageLayoutMode == PAGE_TILE) {
2717       PageLayoutSubMenu(PAGE_STACK);
2718       while (lastPageNum > 1) {
2719          DeleteCurPage();
2720       }
2721    }
2722    if (!user_placement) {
2723       sprintf(paper_size_spec, "%1d x %1d", paper_w, paper_h);
2724       if (!SetPaperSize(paper_size_spec)) {
2725          return;
2726       }
2727       printMag = (float)100.0;
2728       UpdPageStyle(PORTRAIT);
2729    }
2730    UpdDrawWinBBox();
2731    AdjSplineVs();
2732    RedrawScrollBars();
2733    RedrawRulers();
2734    RedrawTitleWindow();
2735 
2736    SaveStatusStrings();
2737    if (user_placement) {
2738       strcpy(gszMsgBox, TgLoadString(STID_LF_BTN_PLACE_MRG_OTHER_CANCEL));
2739       Msg(gszMsgBox);
2740       SetStringStatus(gszMsgBox);
2741    }
2742    line_num = 1;
2743    x = left_margin;
2744    y = top_margin;
2745    r = c = 0;
2746    while (ok && (buf=UtilGetALine(fp)) != NULL) {
2747       struct ObjRec *obj_ptr=DupObj(template_obj);
2748 
2749       if (obj_ptr == NULL) {
2750          ok = FALSE;
2751          free(buf);
2752          break;
2753       }
2754       sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROCESSING_OBJ_NUMBER),
2755             line_num);
2756       SetStringStatus(gszMsgBox);
2757       XSync(mainDisplay, False);
2758 
2759       AddObj(NULL, topObj, obj_ptr);
2760       AdjObjBBox(obj_ptr);
2761       MoveObj(obj_ptr, x-obj_ptr->obbox.ltx, y-obj_ptr->obbox.lty);
2762 
2763       line_num++;
2764       i = 0;
2765       val_ptr = buf;
2766       replaceAttrFirstValueRedraw = FALSE;
2767       for (c_ptr=strchr(val_ptr, tab_separated ? '\t' : ';'); val_ptr != NULL;
2768             i++) {
2769          struct AttrRec *attr_ptr;
2770 
2771          if (c_ptr != NULL) *c_ptr = '\0';
2772 
2773          if (col_names[i] != NULL && (attr_ptr=FindAttrWithName(obj_ptr,
2774                col_names[i], NULL)) != NULL) {
2775             if (!tab_separated) UtilTrimBlanks(val_ptr);
2776             if (strip_double_quotes && *val_ptr == '"') {
2777                int len=strlen(val_ptr);
2778 
2779                if (val_ptr[len-1] == '"') {
2780                   val_ptr[len-1] = '\0';
2781                   ReplaceAttrFirstValue(obj_ptr, attr_ptr, &val_ptr[1]);
2782                   val_ptr[len-1] = '"';
2783                } else {
2784                   ReplaceAttrFirstValue(obj_ptr, attr_ptr, val_ptr);
2785                }
2786             } else {
2787                ReplaceAttrFirstValue(obj_ptr, attr_ptr, val_ptr);
2788             }
2789          }
2790          if (c_ptr == NULL) break;
2791          *c_ptr++ = (tab_separated ? '\t' : ';');
2792          val_ptr = c_ptr;
2793          c_ptr = strchr(val_ptr, tab_separated ? '\t' : ';');
2794       }
2795       replaceAttrFirstValueRedraw = TRUE;
2796       UnlinkObj(obj_ptr);
2797       if (firstCmd != NULL) CleanUpCmds();
2798       if (i+1 != columns_in_file) {
2799          ok = FALSE;
2800          sprintf(gszMsgBox, TgLoadString(STID_MALFORMED_TBL_LINE_ABORT_MRG),
2801                line_num, (short_name ? rest : fname));
2802          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2803          FreeObj(obj_ptr);
2804          ClearAndRedrawDrawWindow();
2805       } else {
2806          struct AttrRec *attr_ptr=NULL;
2807          int saved_history_depth=historyDepth;
2808 
2809          AdjObjBBox(obj_ptr);
2810          AddObj(NULL, topObj, obj_ptr);
2811          if (user_placement) {
2812             if ((attr_ptr=FindAttrWithName(obj_ptr, "name=",
2813                   NULL)) != NULL) {
2814                sprintf(gszMsgBox, TgLoadCachedString(CSTID_PLACING_NAMED_OBJ),
2815                      attr_ptr->attr_value.s);
2816                SetStringStatus(gszMsgBox);
2817                XSync(mainDisplay, False);
2818             }
2819             if (PlaceTopObj(obj_ptr, NULL, NULL) == Button3) {
2820                Msg(TgLoadString(STID_OPERATION_CANCEL_BY_USER));
2821                ok = FALSE;
2822             }
2823             AssignNewObjIds(obj_ptr);
2824          }
2825          numRedrawBBox = 0;
2826          obj_ptr->tmp_parent = NULL;
2827          DrawObj(drawWindow, obj_ptr);
2828          /* do not translate -- program constants */
2829          if ((attr_ptr=FindAttrWithName(obj_ptr, "EXEC_AFTER_MERGE=",
2830                NULL)) != NULL) {
2831             char name[MAXSTRING+1];
2832             struct AttrRec *next_attr_ptr=NULL;
2833 
2834             if (*attr_ptr->attr_value.s != '\0') {
2835                sprintf(name, "%s=", attr_ptr->attr_value.s);
2836                if ((next_attr_ptr=FindAttrWithName(obj_ptr, name, NULL)) !=
2837                      NULL) {
2838                   int saved_intr_check_interval=intrCheckInterval;
2839 
2840                   intrCheckInterval = 1;
2841                   ShowInterrupt(1);
2842                   if (!DoExec(next_attr_ptr, obj_ptr)) {
2843                      ok = FALSE;
2844                   }
2845                   while (HideInterrupt() > 0) ;
2846                   intrCheckInterval = saved_intr_check_interval;
2847                } else {
2848                   sprintf(gszMsgBox,
2849                         TgLoadString(STID_CANT_FND_NAMED_ATTR_ABORT_MRG),
2850                         attr_ptr->attr_value.s);
2851                   MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2852                   ok = FALSE;
2853                }
2854             }
2855             attr_ptr = next_attr_ptr;
2856          } else if ((attr_ptr=FindAttrWithName(obj_ptr, EXEC_ATTR, NULL)) !=
2857                NULL) {
2858             int saved_intr_check_interval=intrCheckInterval;
2859 
2860             intrCheckInterval = 1;
2861             ShowInterrupt(1);
2862             if (!DoExec(attr_ptr, obj_ptr)) {
2863                ok = FALSE;
2864             }
2865             while (HideInterrupt() > 0) ;
2866             intrCheckInterval = saved_intr_check_interval;
2867          }
2868          if (saved_history_depth != historyDepth) RestoreDefaultHistoryDepth();
2869          if (firstCmd != NULL) CleanUpCmds();
2870          if (ok && !user_placement) {
2871             c++;
2872             if (c >= num_cols) {
2873                c = 0;
2874                x = left_margin;
2875                r++;
2876                if (r >= num_rows) {
2877                   r = 0;
2878                   y = top_margin;
2879                   AddPageAfter();
2880                } else {
2881                   y += v_pitch;
2882                }
2883             } else {
2884                x += h_pitch;
2885             }
2886          }
2887       }
2888       free(buf);
2889    }
2890    fclose(fp);
2891 
2892    RestoreStatusStrings();
2893    sprintf(gszMsgBox, TgLoadString(STID_NUM_OBJECTS_GENERATED), line_num-1);
2894    MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2895 
2896    FreeObj(template_obj);
2897    for (i=0; i < columns_in_file; i++) {
2898       if (col_names[i] != NULL) {
2899          free(col_names[i]);
2900       }
2901    }
2902    free(col_names);
2903    if (firstCmd != NULL) CleanUpCmds();
2904    SetFileModified(TRUE);
2905    justDupped = FALSE;
2906 }
2907 
ExportToTable()2908 void ExportToTable()
2909 {
2910    char msg[MAXSTRING+1], fname[MAXPATHLENGTH+1], full_fname[MAXPATHLENGTH+1];
2911    char *c_ptr, *dot_ptr, *rest=NULL, *spec, *spec_copy, **col_names=NULL, *buf;
2912    int short_name, total, i, num_exported, buf_sz, ok=TRUE;
2913    FILE *fp;
2914    struct AttrRec *spec_attr=NULL;
2915    MiniLineInfo *pMiniLine=NULL;
2916    struct SelRec *sel_ptr=NULL;
2917 
2918    if (topSel == NULL) {
2919       MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
2920       return;
2921    }
2922    /* do not translate -- program constants */
2923    strcpy(msg, "!.TABLE_ATTRS=");
2924    spec_attr = FindAttrWithName(NULL, msg, NULL);
2925    if (spec_attr == NULL) {
2926       MsgBox(TgLoadString(STID_CANT_FND_TABLE_ATTRS_FILE_ATT), TOOL_NAME,
2927             INFO_MB);
2928       return;
2929    }
2930    sprintf(gszMsgBox, TgLoadString(STID_WORKING_DIRECTORY_IS),
2931          (curDirIsLocal ? curDir : curLocalDir));
2932    *fname = '\0';
2933    Dialog(TgLoadString(STID_ENTER_TXT_FILE_TO_EXPORT_CRES), gszMsgBox, fname);
2934 
2935    if (*fname == '\0') return;
2936 
2937    if (*fname == DIR_SEP) {
2938       strcpy(full_fname, fname);
2939    } else {
2940       sprintf(full_fname, "%s%c%s", curDirIsLocal ? curDir : curLocalDir,
2941             DIR_SEP, fname);
2942    }
2943    if ((c_ptr=UtilStrRChr(full_fname, (int)DIR_SEP)) == NULL) {
2944       if ((dot_ptr=UtilStrRChr(full_fname, (int)'.')) == NULL) {
2945          sprintf(&full_fname[strlen(full_fname)], ".%s", TEXT_FILE_EXT);
2946       } else {
2947          if (strcmp(&dot_ptr[1], TEXT_FILE_EXT) != 0) {
2948             sprintf(&dot_ptr[strlen(dot_ptr)], ".%s", TEXT_FILE_EXT);
2949          }
2950       }
2951    } else {
2952       if ((dot_ptr=UtilStrRChr(c_ptr, (int)'.')) == NULL) {
2953          sprintf(&c_ptr[strlen(c_ptr)], ".%s", TEXT_FILE_EXT);
2954       } else {
2955          if (strcmp(&dot_ptr[1], TEXT_FILE_EXT) != 0) {
2956             sprintf(&dot_ptr[strlen(dot_ptr)], ".%s", TEXT_FILE_EXT);
2957          }
2958       }
2959    }
2960    if (!OkayToCreateFile(full_fname)) return;
2961 
2962    if ((short_name=IsPrefix(bootDir, full_fname, &rest))) ++rest;
2963    if ((fp=fopen(full_fname, "w")) == NULL) {
2964       sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
2965             (short_name ? rest : full_fname));
2966       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2967       return;
2968    }
2969    sprintf(gszMsgBox, TgLoadCachedString(CSTID_WRITING_ATTRS_IN_TBL_FORM_TO),
2970          (short_name ? rest : full_fname));
2971    Msg(gszMsgBox);
2972    writeFileFailed = FALSE;
2973 
2974    total = 0;
2975    for (pMiniLine=spec_attr->obj->detail.t->minilines.first; pMiniLine != NULL;
2976          pMiniLine=pMiniLine->next) {
2977       int need_to_free_tmp_buf=FALSE;
2978       char *tmp_buf=ConvertMiniLineToString(pMiniLine, &need_to_free_tmp_buf);
2979 
2980       total += strlen(tmp_buf)+1;
2981       if (need_to_free_tmp_buf) UtilFree(tmp_buf);
2982    }
2983    if ((spec=(char*)malloc((total+1)*sizeof(char))) == NULL) {
2984       FailAllocMessage();
2985       fclose(fp);
2986       return;
2987    }
2988    c_ptr = spec;
2989    for (pMiniLine=spec_attr->obj->detail.t->minilines.first; pMiniLine != NULL;
2990          pMiniLine=pMiniLine->next) {
2991       int len=0, need_to_free_tmp_buf=FALSE;
2992       char *tmp_buf=NULL;
2993 
2994       if (pMiniLine == spec_attr->obj->detail.t->minilines.first) {
2995          char *attr_value=NULL;
2996 
2997          tmp_buf = ConvertMiniLineToString(pMiniLine, &need_to_free_tmp_buf);
2998          attr_value = UtilStrDup(tmp_buf);
2999          if (attr_value == NULL) FailAllocMessage();
3000          ParseAttrStr(tmp_buf, NULL, 0, attr_value, strlen(attr_value)+1);
3001          if (need_to_free_tmp_buf) UtilFree(tmp_buf);
3002          need_to_free_tmp_buf = TRUE;
3003          tmp_buf = attr_value;
3004       } else {
3005          tmp_buf = ConvertMiniLineToString(pMiniLine, &need_to_free_tmp_buf);
3006       }
3007       len = strlen(tmp_buf);
3008       strcpy(c_ptr, tmp_buf);
3009       if (need_to_free_tmp_buf) UtilFree(tmp_buf);
3010       c_ptr += len;
3011       *c_ptr++ = ',';
3012    }
3013    *c_ptr = '\0';
3014    if ((spec_copy=UtilStrDup(spec)) == NULL) {
3015       FailAllocMessage();
3016       free(spec);
3017       fclose(fp);
3018       return;
3019    }
3020    total = 0;
3021    for (c_ptr=strtok(spec_copy, " ,;\t\n\r"); c_ptr != NULL;
3022          c_ptr=strtok(NULL, " ,;\t\n\r")) {
3023       total++;
3024    }
3025    free(spec_copy);
3026 
3027    buf_sz = 0x400;
3028    spec_copy = UtilStrDup(spec);
3029    col_names = (char**)malloc((total+1)*sizeof(char*));
3030    buf = (char*)malloc((buf_sz+2)*sizeof(char));
3031    if (spec_copy == NULL || col_names == NULL || buf == NULL) {
3032       FailAllocMessage();
3033       if (col_names != NULL) free(col_names);
3034       if (spec_copy != NULL) free(spec_copy);
3035       if (buf != NULL) free(buf);
3036       free(spec);
3037       fclose(fp);
3038       return;
3039    }
3040    col_names[total] = NULL;
3041    i = 0;
3042    for (c_ptr=strtok(spec_copy, " ,;\t\n\r"); c_ptr != NULL && !writeFileFailed;
3043          c_ptr=strtok(NULL, " ,;\t\n\r"), i++) {
3044       int len=strlen(c_ptr);
3045 
3046       if ((col_names[i]=(char*)malloc((len+2)*sizeof(char))) == NULL) {
3047          FailAllocMessage();
3048          for (total=0; total < i; total++) free(col_names[i]);
3049          free(col_names);
3050          free(spec_copy);
3051          free(buf);
3052          free(spec);
3053          fclose(fp);
3054          return;
3055       }
3056       if (fprintf(fp, "%s%s", (i==0 ? "" : "\t"), c_ptr) == EOF) {
3057          writeFileFailed = TRUE;
3058       }
3059       sprintf(col_names[i], "%s=", c_ptr);
3060    }
3061    fprintf(fp, "\n");
3062 
3063    num_exported = 0;
3064    SaveStatusStrings();
3065    for (sel_ptr=botSel; ok && sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
3066       int percent=(i*10000/numObjSelected)/100, col;
3067       int something_exported=FALSE, cur_len=0;
3068 
3069       sprintf(gszMsgBox, TgLoadCachedString(CSTID_PROGRESS_PERCENT), percent);
3070       SetStringStatus(gszMsgBox);
3071       XSync(mainDisplay, False);
3072 
3073       for (col=0; ok && col < total; col++) {
3074          int len;
3075          struct AttrRec *attr_ptr=FindAttrWithName(sel_ptr->obj,
3076                col_names[col], NULL);
3077 
3078          if (attr_ptr != NULL) something_exported = TRUE;
3079 
3080          sprintf(gszMsgBox, "%s%s", (col==0 ? "" : "\t"),
3081                (attr_ptr==NULL ? "": attr_ptr->attr_value.s));
3082          len = strlen(gszMsgBox);
3083          while (len+cur_len >= buf_sz) {
3084             buf_sz += 0x400;
3085             buf = (char*)realloc(buf, (buf_sz+2)*sizeof(char));
3086             if (buf == NULL) {
3087                FailAllocMessage();
3088                ok = FALSE;
3089                break;
3090             }
3091          }
3092          if (ok) {
3093             sprintf(&buf[cur_len], gszMsgBox);
3094             cur_len += len;
3095          }
3096       }
3097       buf[cur_len] = '\0';
3098       if (something_exported) {
3099          num_exported++;
3100          if (fprintf(fp, "%s\n", buf) == EOF) {
3101             writeFileFailed = TRUE;
3102             ok = FALSE;
3103          }
3104       }
3105    }
3106    RestoreStatusStrings();
3107    sprintf(gszMsgBox, TgLoadString(STID_NUM_OBJECTS_EXPORTED), num_exported);
3108    Msg(gszMsgBox);
3109 
3110    for (i=0; i < total; i++) free(col_names[i]);
3111    free(col_names);
3112    free(spec_copy);
3113    if (buf != NULL) free(buf);
3114    free(spec);
3115    fclose(fp);
3116 
3117    if (writeFileFailed) {
3118       writeFileFailed = FALSE;
3119       FailToWriteFileMessage(full_fname);
3120    } else {
3121       sprintf(gszMsgBox, TgLoadString(STID_ATTRS_EXPORTED_TO_TBL_FILE),
3122             (short_name ? rest : full_fname));
3123       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3124    }
3125 }
3126 
ToggleShowWireSignalName()3127 void ToggleShowWireSignalName()
3128 {
3129    showWireSignalName = !showWireSignalName;
3130    sprintf(gszMsgBox, TgLoadString(showWireSignalName ?
3131          STID_WILL_SHOW_WIRE_SIGNAL_NAME : STID_WILL_HIDE_WIRE_SIGNAL_NAME));
3132    Msg(gszMsgBox);
3133 }
3134 
RefreshPortMenu(menu)3135 int RefreshPortMenu(menu)
3136    TgMenu *menu;
3137 {
3138    int ok=TRUE;
3139 
3140    /* Show Wire Signal Name */
3141    ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLESHOWWIRESIGNALNAME,
3142          showWireSignalName);
3143 
3144    return ok;
3145 }
3146 
CreatePortMenu(parent_menu,x,y,menu_info,status_str_xlated)3147 TgMenu *CreatePortMenu(parent_menu, x, y, menu_info, status_str_xlated)
3148    TgMenu *parent_menu;
3149    int x, y;
3150    TgMenuInfo *menu_info;
3151    int status_str_xlated; /* ignored, always 0 */
3152 {
3153    TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
3154 
3155    if (menu != NULL) {
3156       if (!RefreshPortMenu(menu)) {
3157          return TgDestroyMenu(menu, TRUE);
3158       }
3159       menu->refresh_proc = ((RefreshMenuFunc*)RefreshPortMenu);
3160    }
3161    return menu;
3162 }
3163 
RefreshSpecialMenu(menu)3164 void RefreshSpecialMenu(menu)
3165    TgMenu *menu;
3166 {
3167 }
3168 
SpecialMenu(X,Y,TrackMenubar)3169 int SpecialMenu(X, Y, TrackMenubar)
3170    int X, Y, TrackMenubar;
3171 {
3172    int rc=INVALID;
3173    TgMenu *menu=(specialMenuInfo.create_proc)(NULL, X, Y, &specialMenuInfo,
3174          FALSE);
3175 
3176    activeMenu = MENU_SPECIAL;
3177    if (menu != NULL) {
3178       menu->track_menubar = TrackMenubar;
3179 
3180       rc = TgMenuLoop(menu);
3181       TgDestroyMenu(menu, TRUE);
3182    }
3183    return rc;
3184 }
3185 
CleanUpSpecial()3186 void CleanUpSpecial()
3187 {
3188 }
3189 
InitSpecial()3190 int InitSpecial()
3191 {
3192    char *c_ptr=NULL;
3193 
3194    showWireSignalName = TRUE;
3195    if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"ShowWireSignalName")) !=
3196          NULL && UtilStrICmp(c_ptr, "false") == 0) {
3197       showWireSignalName = FALSE;
3198    }
3199    return TRUE;
3200 }
3201