/* * CmdFI.c -- * * Commands with names beginning with the letters F through I. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/commands/CmdFI.c,v 1.4 2010/06/24 12:37:15 tim Exp $"; #endif /* not lint */ #include #include #include #ifdef USE_READLINE #ifdef HAVE_READLINE #include #include #else #include "readline/readline/readline.h" #include "readline/readline/history.h" #endif #endif #include "tcltk/tclmagic.h" #include "utils/magic.h" #include "utils/geometry.h" #include "utils/utils.h" #include "utils/undo.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/main.h" #include "commands/commands.h" #include "textio/textio.h" #include "utils/macros.h" #include "drc/drc.h" #include "textio/txcommands.h" #include "utils/styles.h" #include "graphics/graphics.h" #include "extract/extract.h" #include "utils/malloc.h" #include "select/select.h" #include "sim/sim.h" #include "gcr/gcr.h" /* C99 compat */ #include "cif/cif.h" /* The following structure is used by CmdFill to keep track of * areas to be filled. */ struct cmdFillArea { Rect cfa_area; /* Area to fill. */ TileType cfa_type; /* Type of material. */ struct cmdFillArea *cfa_next; /* Next in list of areas to fill. */ }; /* The following structure passes arguments needed by the */ /* DBWFeedbackAdd command to the feedPolyFunc() callback routine. */ struct cmdFPArg { CellDef *def; int style; char *text; }; #define FEEDMAGNIFY 20 /* Allow feedback to be drawn to 1/20 of an */ /* internal unit. */ /* * ---------------------------------------------------------------------------- * * feedPolyFunc -- * * This procedure generates feedback entries in a polygonal area * by calling DBWFeedbackArea per tile on simple 1-bit types in * a plane. The use of the temporary plane allows us to use the * same path decomposition routine used for CIF input, polygon * drawing, and wire segments. * * ---------------------------------------------------------------------------- */ int feedPolyFunc( Tile *tile, struct cmdFPArg *arg) { Rect area; TiToRect(tile, &area); DBWFeedbackAdd(&area, arg->text, arg->def, FEEDMAGNIFY, arg->style | (TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))); /* (preserve information about the geometry of a diagonal tile) */ return 0; } /* * ---------------------------------------------------------------------------- * * CmdFeedback -- * * Implement the "feedback" command, which provides facilities * for querying and manipulating feedback information provided * by other commands when they have troubles or want to highlight * certain things. * * Usage: * feedback option [additional_args] * * Results: * None. * * Side effects: * Depends on the option. * * ---------------------------------------------------------------------------- */ #undef CLEAR #define ADD 0 #define CLEAR 1 #define COUNT 2 #define FIND 3 #define FEED_HELP 4 #define SAVE 5 #define WHY 6 void CmdFeedback( MagWindow *w, TxCommand *cmd) { static const char * const cmdFeedbackOptions[] = { "add text [style] [points...] create new feedback area over box", "clear [substring] clear all or selected feedback info", "count count # feedback entries", "find [nth] put box over next [or nth] entry", "help print this message", "save file save feedback areas in file", "why print all feedback messages under box", NULL }; static const char * const cmdFeedbackStyleNames[] = { "dotted", "medium", "outline", "pale", "solid", NULL }; static const int cmdFeedbackStyles[] = { STYLE_DOTTEDHIGHLIGHTS, STYLE_MEDIUMHIGHLIGHTS, STYLE_OUTLINEHIGHLIGHTS, STYLE_PALEHIGHLIGHTS, STYLE_SOLIDHIGHLIGHTS, -1 }; static int nth = 0; /* Last entry displayed in * "feedback find". */ int option, i, style, pstart; Rect box, r; char *text; const char * const *msg; CellDef *rootDef; HashTable table; HashEntry *h; FILE *f; if (cmd->tx_argc < 2) { badusage: TxPrintf("Wrong number of arguments for \"feedback\" command.\n"); TxPrintf("Type \":feedback help\" for help.\n"); return; } option = Lookup(cmd->tx_argv[1], cmdFeedbackOptions); if (option < 0) { TxError("%s isn't a valid feedback option. Try one of:\n", cmd->tx_argv[1]); TxError(" add find\n"); TxError(" clear help\n"); TxError(" count save\n"); TxError(" save\n"); return; } pstart = 4; /* argument # where point list starts, if any */ switch (option) { case ADD: style = STYLE_PALEHIGHLIGHTS; if (cmd->tx_argc > 3) { i = Lookup(cmd->tx_argv[3], cmdFeedbackStyleNames); if (i < 0) { if (StrIsNumeric(cmd->tx_argv[3])) pstart = 3; else { style = GrGetStyleFromName(cmd->tx_argv[3]); if (style < 0) { TxError("%s isn't a valid display style. Try one of:\n", cmd->tx_argv[3]); TxError(" dotted, pale, medium, solid, outline,\n"); TxError(" or a long name from the .dstyle file\n"); break; } if (style < 1 || style >= TECHBEGINSTYLES) { TxError("Numbered styles must be between 1 and %d\n", TECHBEGINSTYLES - 1); break; } } } else style = cmdFeedbackStyles[i]; } if (cmd->tx_argc - pstart > 0) { /* points must be in X Y pairs */ if ((cmd->tx_argc - pstart) & 1) goto badusage; if (w == NULL) return; rootDef = ((CellUse *) w->w_surfaceID)->cu_def; /* Read coordinates in FEEDMAGNIFY x internal units, */ /* then scale the highlight accordingly. */ if ((cmd->tx_argc - pstart) == 2) { /* Single point highlight. Style MUST be outlined */ /* or else the point won't be visible. */ if (GrStyleTable[style].outline == 0) style = STYLE_OUTLINEHIGHLIGHTS; box.r_xbot = box.r_xtop = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, TRUE, FEEDMAGNIFY); box.r_ybot = box.r_ytop = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, FALSE, FEEDMAGNIFY); DBWFeedbackAdd(&box, cmd->tx_argv[2], rootDef, FEEDMAGNIFY, style); } else if ((cmd->tx_argc - pstart) == 4) { /* Single line highlight. Style MUST be outlined, */ /* or else the line won't be visible. */ if (GrStyleTable[style].outline == 0) style = STYLE_OUTLINEHIGHLIGHTS; r.r_xbot = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, TRUE, FEEDMAGNIFY); r.r_ybot = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, FALSE, FEEDMAGNIFY); r.r_xtop = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, TRUE, FEEDMAGNIFY); r.r_ytop = cmdScaleCoord(w, cmd->tx_argv[pstart++], FALSE, FALSE, FEEDMAGNIFY); if (r.r_xbot != r.r_xtop && r.r_ybot != r.r_ytop) { /* Line at an angle. The hack of setting TT_SIDE */ /* without setting TT_DIAGONAL allows the drawing */ /* routine to treat this case as a line, not a */ /* triangle. */ style |= TT_SIDE; if ((r.r_xbot > r.r_xtop && r.r_ybot < r.r_ytop) || (r.r_xbot < r.r_xtop && r.r_ybot > r.r_ytop)) style |= TT_DIRECTION; } GeoCanonicalRect(&r, &box); DBWFeedbackAdd(&box, cmd->tx_argv[2], rootDef, FEEDMAGNIFY, style); } else { Plane *plane; PaintResultType ptable[2] = {1, 1}; /* simple 1 bit table */ TileTypeBitMask feedSimpleMask; Point *plist; int points, j; struct cmdFPArg fpargs; points = (cmd->tx_argc - pstart) >> 1; plist = (Point *)mallocMagic(points * sizeof(Point)); fpargs.def = rootDef; fpargs.style = style; fpargs.text = cmd->tx_argv[2]; for (i = 0, j = pstart; i < points; i++) { plist[i].p_x = cmdScaleCoord(w, cmd->tx_argv[j++], FALSE, TRUE, FEEDMAGNIFY); plist[i].p_y = cmdScaleCoord(w, cmd->tx_argv[j++], FALSE, FALSE, FEEDMAGNIFY); } plane = DBNewPlane((ClientData)0); TTMaskZero(&feedSimpleMask); TTMaskSetType(&feedSimpleMask, 1); PaintPolygon(plist, points, plane, ptable, (PaintUndoInfo *)NULL, FALSE); i = DBWFeedbackCount; DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &feedSimpleMask, feedPolyFunc, (ClientData)&fpargs); TiFreePlane(plane); if (i == DBWFeedbackCount) { /* Pathological condition---feedback area is so thin */ /* that the decomposition to rectangles and triangles */ /* was degenerate. If so, then we can just treat the */ /* plist as several lines and/or points. */ if (GrStyleTable[style].outline == 0) style = STYLE_OUTLINEHIGHLIGHTS; for (i = 0; i < points - 1; i++) { r.r_xbot = plist[i].p_x; r.r_ybot = plist[i].p_y; r.r_xtop = plist[i + 1].p_x; r.r_ytop = plist[i + 1].p_y; if (r.r_xbot != r.r_xtop && r.r_ybot != r.r_ytop) { style |= TT_SIDE; if ((r.r_xbot > r.r_xtop && r.r_ybot < r.r_ytop) || (r.r_xbot < r.r_xtop && r.r_ybot > r.r_ytop)) style |= TT_DIRECTION; } GeoCanonicalRect(&r, &box); DBWFeedbackAdd(&box, cmd->tx_argv[2], rootDef, FEEDMAGNIFY, style); } } freeMagic(plist); } } else { w = ToolGetBoxWindow(&box, (int *) NULL); if (w == NULL) return; rootDef = ((CellUse *) w->w_surfaceID)->cu_def; DBWFeedbackAdd(&box, cmd->tx_argv[2], rootDef, 1, style); } break; case CLEAR: if (cmd->tx_argc == 3) DBWFeedbackClear(cmd->tx_argv[2]); else if (cmd->tx_argc == 2) DBWFeedbackClear(NULL); else goto badusage; nth = 0; break; case COUNT: if (cmd->tx_argc != 2) goto badusage; #ifdef MAGIC_WRAPPER Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(DBWFeedbackCount)); #else TxPrintf("There are %d feedback areas.\n", DBWFeedbackCount); #endif break; case FIND: if (cmd->tx_argc > 3) goto badusage; if (DBWFeedbackCount == 0) { TxPrintf("There are no feedback areas right now.\n"); break; } if (cmd->tx_argc == 3) { nth = atoi(cmd->tx_argv[2]); if ((nth > DBWFeedbackCount) || (nth <= 0)) { TxError("Sorry, but only feedback areas 1-%d exist.\n", DBWFeedbackCount); nth = 1; } } else { nth += 1; if (nth > DBWFeedbackCount) nth = 1; } text = DBWFeedbackNth(nth-1, &box, &rootDef, (int *) NULL); ToolMoveBox(TOOL_BL, &box.r_ll, FALSE, rootDef); ToolMoveCorner(TOOL_TR, &box.r_ur, FALSE, rootDef); TxPrintf("Feedback #%d: %s\n", nth, text); break; case FEED_HELP: if (cmd->tx_argc > 2) goto badusage; TxPrintf("Feedback commands have the form \"feedback option\",\n"); TxPrintf("where option is one of:\n"); for (msg = cmdFeedbackOptions; *msg != NULL; msg++) TxPrintf("%s\n", *msg); break; case SAVE: if (cmd->tx_argc != 3) goto badusage; f = PaOpen(cmd->tx_argv[2], "w", (char *) NULL, ".", (char *) NULL, (char **) NULL); if (f == NULL) { TxError("Can't open file %s.\n", cmd->tx_argv[2]); break; } for (i = 0; i < DBWFeedbackCount; i++) { int j, style; text = DBWFeedbackNth(i, &box, (CellDef **) NULL, &style); fprintf(f, "box %d %d %d %d\n", box.r_xbot, box.r_ybot, box.r_xtop, box.r_ytop); fprintf(f, "feedback add \""); /* Be careful to backslash any quotes in the text! */ for ( ; *text != 0; text += 1) { if (*text == '"') fputc('\\', f); fputc(*text, f); } fputc('"', f); for (j = 0; cmdFeedbackStyles[j] >= 0; j++) { if (cmdFeedbackStyles[j] == style) { fprintf(f, " %s", cmdFeedbackStyleNames[j]); break; } } fprintf(f, "\n"); } (void) fclose(f); break; case WHY: if (cmd->tx_argc > 2) goto badusage; w = ToolGetBoxWindow(&box, (int *) NULL); if (w == NULL) return; rootDef = ((CellUse *) w->w_surfaceID)->cu_def; HashInit(&table, 16, 0); for (i = 0; i < DBWFeedbackCount; i++) { Rect area; CellDef *fbRootDef; text = DBWFeedbackNth(i, &area, &fbRootDef, (int *) NULL); if (rootDef != fbRootDef) continue; if (!GEO_OVERLAP(&box, &area)) continue; h = HashFind(&table, text); if (HashGetValue(h) == 0) TxPrintf("%s\n", text); HashSetValue(h, 1); } HashKill(&table); break; } } /* * ---------------------------------------------------------------------------- * * CmdFill -- * * Implement the "fill" command. Find all paint touching one side * of the box, and paint it across to the other side of the box. Can * operate in any of four directions. * * Usage: * fill direction [layers] * * Results: * None. * * Side effects: * Modifies the edit cell definition. * * ---------------------------------------------------------------------------- */ /* Data passed between CmdFill and cmdFillFunc: */ int cmdFillDir; /* Direction in which to fill. */ Rect cmdFillRootBox; /* Root coords of box. */ struct cmdFillArea *cmdFillList; /* List of areas to fill. */ void CmdFill( MagWindow *w, /* Window in which command was invoked. */ TxCommand *cmd) /* Describes the command that was invoked. */ { TileTypeBitMask maskBits; Rect editBox; SearchContext scx; extern int cmdFillFunc(Tile *tile, TreeContext *cxp); if (cmd->tx_argc < 2 || cmd->tx_argc > 3) { TxError("Usage: %s direction [layers]\n", cmd->tx_argv[0]); return; } windCheckOnlyWindow(&w, DBWclientID); if ( w == (MagWindow *) NULL ) { TxError("Point to a window\n"); return; } /* Find and check validity of position argument. */ cmdFillDir = GeoNameToPos(cmd->tx_argv[1], TRUE, TRUE); if (cmdFillDir < 0) return; /* Figure out which layers to fill. */ if (cmd->tx_argc < 3) maskBits = DBAllButSpaceAndDRCBits; else { if (!CmdParseLayers(cmd->tx_argv[2], &maskBits)) return; } /* Figure out which material to search for and invoke a search * procedure to find it. */ if (!ToolGetEditBox(&editBox)) return; GeoTransRect(&EditToRootTransform, &editBox, &cmdFillRootBox); scx.scx_area = cmdFillRootBox; switch (cmdFillDir) { case GEO_NORTH: scx.scx_area.r_ytop = scx.scx_area.r_ybot + 1; scx.scx_area.r_ybot -= 1; break; case GEO_SOUTH: scx.scx_area.r_ybot = scx.scx_area.r_ytop - 1; scx.scx_area.r_ytop += 1; break; case GEO_EAST: scx.scx_area.r_xtop = scx.scx_area.r_xbot + 1; scx.scx_area.r_xbot -= 1; break; case GEO_WEST: scx.scx_area.r_xbot = scx.scx_area.r_xtop - 1; scx.scx_area.r_xtop += 1; break; } scx.scx_use = (CellUse *) w->w_surfaceID; scx.scx_trans = GeoIdentityTransform; cmdFillList = (struct cmdFillArea *) NULL; (void) DBTreeSrTiles(&scx, &maskBits, ((DBWclientRec *) w->w_clientData)->dbw_bitmask, cmdFillFunc, (ClientData) NULL); /* Now that we've got all the material, scan over the list * painting the material and freeing up the entries on the list. */ while (cmdFillList != NULL) { DBPaint(EditCellUse->cu_def, &cmdFillList->cfa_area, cmdFillList->cfa_type); freeMagic((char *) cmdFillList); cmdFillList = cmdFillList->cfa_next; } SelectClear(); DBAdjustLabels(EditCellUse->cu_def, &editBox); DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editBox); DBWAreaChanged(EditCellUse->cu_def, &editBox, DBW_ALLWINDOWS, &maskBits); DBReComputeBbox(EditCellUse->cu_def); } /* Important note: these procedures can't paint the tiles directly, * because a search is in progress over the same planes and if we * paint here it may mess up the search. Instead, the procedures * save areas on a list. The list is post-processed to paint the * areas once the search is finished. */ int cmdFillFunc( Tile *tile, /* Tile to fill with. */ TreeContext *cxp) /* Describes state of search. */ { Rect r1, r2; struct cmdFillArea *cfa; TiToRect(tile, &r1); GeoTransRect(&cxp->tc_scx->scx_trans, &r1, &r2); GeoClip(&r2, &cmdFillRootBox); switch (cmdFillDir) { case GEO_NORTH: r2.r_ytop = cmdFillRootBox.r_ytop; break; case GEO_SOUTH: r2.r_ybot = cmdFillRootBox.r_ybot; break; case GEO_EAST: r2.r_xtop = cmdFillRootBox.r_xtop; break; case GEO_WEST: r2.r_xbot = cmdFillRootBox.r_xbot; break; } GeoTransRect(&RootToEditTransform, &r2, &r1); cfa = (struct cmdFillArea *) mallocMagic(sizeof(struct cmdFillArea)); cfa->cfa_area = r1; cfa->cfa_type = TiGetType(tile); cfa->cfa_next = cmdFillList; cmdFillList = cfa; return 0; } /* * ---------------------------------------------------------------------------- * * CmdFindBox -- * * Center the display on a corner of the box. If 'zoom', then make the box * fill the window. * * Usage: * findbox [zoom] * * Results: * None. * * Side effects: * The window underneath the cursor is moved. * * ---------------------------------------------------------------------------- */ void CmdFindBox( MagWindow *w, TxCommand *cmd) { CellDef *boxDef; Rect box; if (w == NULL) { TxError("Point to a window first.\n"); return; }; if (!ToolGetBox(&boxDef, &box)) { TxError("Put the box in a window first.\n"); return; }; if (boxDef != (((CellUse *) w->w_surfaceID)->cu_def)) { TxError("The box is not in the same coordinate %s", "system as the window.\n"); return; }; if (cmd->tx_argc == 1) { /* center view on box */ Point rootPoint; Rect newArea, oldArea; rootPoint.p_x = (box.r_xbot + box.r_xtop)/2; rootPoint.p_y = (box.r_ybot + box.r_ytop)/2; oldArea = w->w_surfaceArea; newArea.r_xbot = rootPoint.p_x - (oldArea.r_xtop - oldArea.r_xbot)/2; newArea.r_xtop = newArea.r_xbot - oldArea.r_xbot + oldArea.r_xtop; newArea.r_ybot = rootPoint.p_y - (oldArea.r_ytop - oldArea.r_ybot)/2; newArea.r_ytop = newArea.r_ybot - oldArea.r_ybot + oldArea.r_ytop; WindMove(w, &newArea); return; } else if (cmd->tx_argc == 2) { int expand; /* zoom in to box */ if (strcmp(cmd->tx_argv[1], "zoom") != 0) goto usage; /* Allow a 5% ring around the box on each side. */ expand = (box.r_xtop - box.r_xbot)/20; if (expand < 2) expand = 2; box.r_xtop += expand; box.r_xbot -= expand; expand = (box.r_ytop - box.r_ybot)/20; if (expand < 2) expand = 2; box.r_ytop += expand; box.r_ybot -= expand; WindMove(w, &box); return; }; usage: TxError("Usage: findbox [zoom]\n"); } /* * ---------------------------------------------------------------------------- * * cmdFindLabelFunc -- * * Callback function from CmdFindLabel. Return 1 to stop the search on the * Nth instance of the label named "label", where N is passed through the * client data as lsr_occur. * * The client data record lsr_rect is left pointing to the label location * when the Nth label instance is found. * * ---------------------------------------------------------------------------- */ typedef struct _labsearchrec { Rect lsr_rect; int lsr_occur; } LabSearchRec; int cmdFindLabelFunc( Rect *rect, char *name, Label *label, LabSearchRec *cdarg) { if (cdarg->lsr_occur == 0) { cdarg->lsr_rect = *rect; return 1; } else cdarg->lsr_occur--; return 0; } /* * ---------------------------------------------------------------------------- * * CmdFindLabel -- * * Find a label and set the box to it. * * Usage: * findlabel [-glob] name * * Results: * None. In TCL, the -glob option will generate a list of matching * nodes returned in the interpreter result. * * Side effects: * The box may be moved. If "-glob" is specified, in the non-Tcl * version, matching label names are printed. * * ---------------------------------------------------------------------------- */ void CmdFindLabel( MagWindow *w, TxCommand *cmd) { CellDef *boxDef; CellUse *labUse; Rect box; char *labname; int found, occur, plainargs; bool doglob = FALSE; /* csh-style glob matching (see utils/match.c) */ LabSearchRec lsr; int dbListLabels(SearchContext *scx, Label *label, TerminalPath *tpath, ClientData cdarg); /* forward declaration */ plainargs = cmd->tx_argc; if ((plainargs > 2) && !strncmp(cmd->tx_argv[1], "-glob", 5)) { plainargs--; doglob = TRUE; } if ((plainargs != 2) && (plainargs != 3)) goto usage; occur = 0; if (plainargs == 3) { char *occurstr = cmd->tx_argv[plainargs - 1]; if (StrIsInt(occurstr)) occur = atoi(occurstr); } if (w == NULL) { TxError("Point to a window first.\n"); return; }; if (!ToolGetBox(&boxDef, &box)) { TxError("Put the box in a window first.\n"); return; }; if (boxDef != (((CellUse *) w->w_surfaceID)->cu_def)) { TxError("The box is not in the same coordinate %s", "system as the window.\n"); return; }; labname = cmd->tx_argv[1 + ((doglob) ? 1 : 0)]; labUse = EditCellUse; if (labUse == NULL) labUse = (CellUse *)w->w_surfaceID; if (doglob) { /* Pattern-matching label search */ SearchContext scx; scx.scx_use = labUse; scx.scx_area = labUse->cu_def->cd_bbox; scx.scx_trans = GeoIdentityTransform; DBSearchLabel(&scx, &DBAllButSpaceAndDRCBits, 0, labname, dbListLabels, (ClientData) 0); } else { /* Exact-match label search (corrected by Nishit, 10/14/04) */ lsr.lsr_occur = occur; found = DBSrLabelLoc(labUse, labname, cmdFindLabelFunc, (ClientData) &lsr); if (found) { if (lsr.lsr_rect.r_xbot == lsr.lsr_rect.r_xtop) lsr.lsr_rect.r_xtop++; if (lsr.lsr_rect.r_ybot == lsr.lsr_rect.r_ytop) lsr.lsr_rect.r_ytop++; ToolMoveBox(TOOL_BL, &lsr.lsr_rect.r_ll, FALSE, labUse->cu_def); ToolMoveCorner(TOOL_TR, &lsr.lsr_rect.r_ur, FALSE, labUse->cu_def); } else { TxError("Couldn't find label %s\n", labname); } } return; usage: TxError("Usage: findlabel [-glob] label_name\n"); } /* * Callback routine for listing pattern-matched labels. * Always return zero to keep the search going. */ int dbListLabels( SearchContext *scx, Label *label, /* Pointer to label structure */ TerminalPath *tpath, /* Full pathname of terminal */ ClientData cdarg) /* (unused) */ { char *n = tpath->tp_next; char c = *n; strcpy(n, label->lab_text); #ifdef MAGIC_WRAPPER Tcl_AppendElement(magicinterp, tpath->tp_first); #else TxPrintf("%s\n", tpath->tp_first); #endif *n = c; return 0; } /* * ---------------------------------------------------------------------------- * * CmdFlush -- * * Implement the "flush" command. * Throw away all changes made within magic to the specified cell, * and re-read it from disk. If no cell is specified, the default * is the current edit cell. If "-dereference" is specified as an * option, then re-read the cell from the search path instead of * the file path that has been associated with the cell. * * Usage: * flush [cellname] [-dereference] * * Results: * None. * * Side effects: * THIS IS NOT UNDO-ABLE! * Modifies the specified CellDef. * * ---------------------------------------------------------------------------- */ void CmdFlush( MagWindow *w, TxCommand *cmd) { CellDef *def; int action; static const char * const actionNames[] = { "no", "yes", 0 }; char *prompt; bool dereference = FALSE; bool noprompt = FALSE; /* no interactive confirm when changed */ if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "-deref", 6)) { dereference = TRUE; cmd->tx_argc--; } if (!strcmp(cmd->tx_argv[cmd->tx_argc - 1], "-noprompt")) { noprompt = TRUE; cmd->tx_argc--; } if (cmd->tx_argc > 2) { TxError("Usage: flush [cellname] [-noprompt] [-dereference]\n"); return; } if (cmd->tx_argc == 1) { if (EditCellUse != NULL) def = EditCellUse->cu_def; else def = ((CellUse *)w->w_surfaceID)->cu_def; } else { def = DBCellLookDef(cmd->tx_argv[1]); if (def == (CellDef *) NULL) { /* an error message has already been printed by the database */ return; } } bool has_changes = (def->cd_flags & (CDMODIFIED|CDSTAMPSCHANGED|CDBOXESCHANGED)) != 0; if (!noprompt && has_changes) { prompt = TxPrintString("Really throw away all changes made" " to cell %s? ", def->cd_name); action = TxDialog(prompt, actionNames, 0); if (action == 0) /* No */ return; } cmdFlushCell(def, dereference); SelectClear(); TxPrintf("[Flushed%s]\n", has_changes ? " Modifications were Discarded" : ""); } /* * ---------------------------------------------------------------------------- * * CmdGetcell -- * * Implement the ":getcell" command. * * Usage: * getcell cellName [child refPointChild] [parent refPointParent] * * where the refPoints are either a label name, e.g., SOCKET_A, or an x-y * pair of integers, e.g., 100 200. The words "child" and "parent" are * keywords, and may be abbreviated. * * Results: * None. * * Side effects: * Makes cellName a subcell of the edit cell, positioned so * that refPointChild in the child cell (or the lower-left * corner of its bounding box) ends up at location refPointParent * in the edit cell (or the location of the box tool's lower-left). * * ---------------------------------------------------------------------------- */ void CmdGetcell( MagWindow *w, /* Window in which command was invoked. */ TxCommand *cmd) /* Describes command arguments. */ { CellUse dummy, *newUse; Transform editTrans; SearchContext scx; CellDef *def; Rect newBox; /* Leaves scx.scx_trans set to the transform from the child to root */ if (!cmdDumpParseArgs("getcell", w, cmd, &dummy, &scx)) return; def = dummy.cu_def; /* Create the new use. */ newUse = DBCellNewUse(def, (char *) NULL); if (!DBLinkCell(newUse, EditCellUse->cu_def)) { (void) DBCellDeleteUse(newUse); TxError("Could not link in new cell\n"); return; } GeoTransTrans(&scx.scx_trans, &RootToEditTransform, &editTrans); DBSetTrans(newUse, &editTrans); if (DBCellFindDup(newUse, EditCellUse->cu_def) != NULL) { DBCellDeleteUse(newUse); TxError("Can't place a cell on an exact copy of itself.\n"); return; } DBPlaceCell(newUse, EditCellUse->cu_def); /* * Reposition the box tool to around the gotten cell to show * that it has become the current cell. */ GeoTransRect(&EditToRootTransform, &newUse->cu_bbox, &newBox); DBWSetBox(EditRootDef, &newBox); /* Select the new use */ SelectClear(); SelectCell(newUse, EditRootDef, &scx.scx_trans, FALSE); /* Redisplay and mark for design-rule checking */ DBReComputeBbox(EditCellUse->cu_def); DBWAreaChanged(EditCellUse->cu_def, &newUse->cu_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); DRCCheckThis(EditCellUse->cu_def, TT_CHECKSUBCELL, &newUse->cu_bbox); #ifdef MAGIC_WRAPPER /* If using the TCL wrapper, set the TCL return value to the */ /* name of the new use. */ if (newUse->cu_id) Tcl_SetResult(magicinterp, newUse->cu_id, TCL_VOLATILE); #endif } #ifndef NO_SIM_MODULE /* * ---------------------------------------------------------------------------- * * CmdGetnode -- * * Implement the "getnode" command. * Returns the name of the node pointed by the mouse * * Usage: * getnode * getnode abort [string] * getnode alias [on | off] * getnode globals [on | off] * getnode fast * * Results: * None. * * Side effects: * The GetNode hash tables may be modified. * ---------------------------------------------------------------------------- */ void CmdGetnode( MagWindow *w, TxCommand *cmd) { #define TBLSIZE 50 #define STRINGS 0 bool is_fast = FALSE; /* check arguments to command */ switch (cmd->tx_argc) { case 1 : break; case 2 : if (strcmp("abort", cmd->tx_argv[1]) == 0) { if (!SimInitGetnode) { HashKill(&SimGetnodeTbl); SimInitGetnode = TRUE; SimRecomputeSel = TRUE; } return; } else if (strcmp("fast", cmd->tx_argv[1]) == 0) { is_fast = TRUE; } else { if (!strcmp("alias", cmd->tx_argv[1])) { TxPrintf("Aliases %s\n", (SimGetnodeAlias) ? "on" : "off"); return; } else if (strncmp("global", cmd->tx_argv[1], 6) == 0) { TxPrintf("Node names ending in ! are %s\n", (SimIgnoreGlobals) ? "local (off)" : "global (on)"); return; } else goto badusage; } break; case 3 : if (strcmp("alias", cmd->tx_argv[1]) == 0) { if (strcmp("on", cmd->tx_argv[2]) == 0) { if (!SimGetnodeAlias) { HashInit(&SimGNAliasTbl, 120, STRINGS); } SimGetnodeAlias = TRUE; return; } else if (strcmp("off", cmd->tx_argv[2]) == 0) { if (SimGetnodeAlias) { HashKill(&SimGNAliasTbl); } SimGetnodeAlias = FALSE; return; } else goto badusage; } else if (strncmp("global", cmd->tx_argv[1], 6) == 0) { if (strcmp("off", cmd->tx_argv[2]) == 0) { SimIgnoreGlobals = TRUE; return; } else if (strcmp("on", cmd->tx_argv[2]) == 0) { SimIgnoreGlobals = FALSE; return; } else goto badusage; } else if (strcmp("abort", cmd->tx_argv[1]) == 0) { if (SimInitGetnode) { HashInit(&SimGetnodeTbl, TBLSIZE, STRINGS); SimInitGetnode = FALSE; } SimRecomputeSel = TRUE; HashFind(&SimGetnodeTbl, cmd->tx_argv[2]); return; } else { goto badusage; } break; default : goto badusage; } windCheckOnlyWindow(&w, DBWclientID); if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID)) { TxError("Put the cursor in a layout window\n"); return; } if( is_fast == TRUE ) { SimRecomputeSel = TRUE; SimGetsnode(); } else SimGetnode(); if (SimGetnodeAlias) { /* "erase" the hash table */ HashKill(&SimGNAliasTbl); HashInit(&SimGNAliasTbl, 120, STRINGS); } return; badusage: TxError("Usage: getnode [abort [str]]\n"); TxError(" or: getnode alias [on | off]\n"); TxError(" or: getnode globals [on | off]\n"); TxError(" or: getnode fast\n"); } #endif /* * ---------------------------------------------------------------------------- * * CmdGrid -- * * Implement the "gridspace" command. * Toggle the grid on or off in the selected window. * * Usage: * gridspace [spacing [spacing [xorig yorig]]] * gridspace on|off|box|state|help|multiple * * Results: * None. * * Side effects: * None, except to enable or disable grid display. * * ---------------------------------------------------------------------------- */ #define GRID_BOX 0 #define GRID_HELP 1 #define GRID_MULTIPLE 2 #define GRID_OFF 3 #define GRID_ON 4 #define GRID_STATE 5 #define GRID_TOGGLE 6 #define GRID_WHAT 7 void CmdGrid( MagWindow *w, TxCommand *cmd) { int option, locargc; int xSpacing, ySpacing, xOrig, yOrig, multiple; DBWclientRec *crec; char *boxvalues; static const char * const cmdGridOptions[] = { "box [values] report the box representing the user grid", "help print this message", "multiple [m] set the grid multiple for drawing grids at large scales", "off turn off the user grid", "on turn on the user grid", "state report the state of the user grid", "toggle toggle the state (on/off) of the user grid", "what (equivalent to option \"box\")", NULL }; windCheckOnlyWindow(&w, DBWclientID); if (w == (MagWindow *) NULL) return; crec = (DBWclientRec *) w->w_clientData; locargc = cmd->tx_argc; if (locargc == 1) option = GRID_TOGGLE; else if ((locargc == 2) && !strcmp(cmd->tx_argv[1], "0")) option = GRID_OFF; else option = Lookup(cmd->tx_argv[1], cmdGridOptions); /* Process various options with two arguments */ switch (option) { case GRID_BOX: if (locargc > 2) { locargc--; break; } case GRID_WHAT: #ifdef MAGIC_WRAPPER boxvalues = (char *)Tcl_Alloc(50); sprintf(boxvalues, "%d %d %d %d", crec->dbw_gridRect.r_xbot, crec->dbw_gridRect.r_ybot, crec->dbw_gridRect.r_xtop, crec->dbw_gridRect.r_ytop); Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); #else TxPrintf("Grid unit box is (%d, %d) to (%d, %d)\n", crec->dbw_gridRect.r_xbot, crec->dbw_gridRect.r_ybot, crec->dbw_gridRect.r_xtop, crec->dbw_gridRect.r_ytop); #endif return; case GRID_STATE: #ifdef MAGIC_WRAPPER Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(crec->dbw_flags & DBW_GRID)); #else TxPrintf("Grid is %s\n", (crec->dbw_flags & DBW_GRID) ? "on" : "off"); #endif return; case GRID_HELP: TxPrintf("Usage: grid [xSpacing [ySpacing [xOrig yOrig]]]]\n"); TxPrintf("or grid