diff --git a/VERSION b/VERSION index 55e52029..52d450f7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.594 +8.3.595 diff --git a/commands/CmdAB.c b/commands/CmdAB.c index ea3a57f9..375ac307 100644 --- a/commands/CmdAB.c +++ b/commands/CmdAB.c @@ -338,14 +338,17 @@ CmdArray( case ARRAY_WIDTH: if (locargc == 2) { + char *xsepvalue; for (la = lahead; la != NULL; la = la->ar_next) { + xsepvalue = DBWPrintValue(la->arrayInfo.ar_xsep, + w, TRUE); #ifdef MAGIC_WRAPPER if (doList) { tobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->arrayInfo.ar_xsep)); + Tcl_NewStringObj(xsepvalue, -1)); Tcl_SetObjResult(magicinterp, tobj); } else @@ -355,7 +358,7 @@ CmdArray( TxPrintf("Cell use \"%s\":", la->cellUse->cu_id); else TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name); - TxPrintf("x separation %d\n", la->arrayInfo.ar_xsep); + TxPrintf("x separation %s\n", xsepvalue); #ifdef MAGIC_WRAPPER } #endif @@ -374,14 +377,17 @@ CmdArray( case ARRAY_HEIGHT: if (locargc == 2) { + char *ysepvalue; for (la = lahead; la != NULL; la = la->ar_next) { + ysepvalue = DBWPrintValue(la->arrayInfo.ar_ysep, + w, FALSE); #ifdef MAGIC_WRAPPER if (doList) { tobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->arrayInfo.ar_ysep)); + Tcl_NewStringObj(ysepvalue, -1)); Tcl_SetObjResult(magicinterp, tobj); } else @@ -391,7 +397,7 @@ CmdArray( TxPrintf("Cell use \"%s\":", la->cellUse->cu_id); else TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name); - TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep); + TxPrintf("y separation %s\n", ysepvalue); #ifdef MAGIC_WRAPPER } #endif @@ -410,16 +416,21 @@ CmdArray( case ARRAY_PITCH: if (locargc == 2) { + char *xpitch, *ypitch; for (la = lahead; la != NULL; la = la->ar_next) { + xpitch = DBWPrintValue(la->arrayInfo.ar_xsep, + w, TRUE); + ypitch = DBWPrintValue(la->arrayInfo.ar_ysep, + w, FALSE); #ifdef MAGIC_WRAPPER if (doList) { tobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->arrayInfo.ar_xsep)); + Tcl_NewStringObj(xpitch, -1)); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->arrayInfo.ar_ysep)); + Tcl_NewStringObj(ypitch, -1)); Tcl_SetObjResult(magicinterp, tobj); } else @@ -429,8 +440,8 @@ CmdArray( TxPrintf("Cell use \"%s\":", la->cellUse->cu_id); else TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name); - TxPrintf("x separation %d ", la->arrayInfo.ar_xsep); - TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep); + TxPrintf("x separation %s ", xpitch); + TxPrintf("y separation %s\n", ypitch); #ifdef MAGIC_WRAPPER } #endif @@ -450,16 +461,21 @@ CmdArray( case ARRAY_POSITION: if (locargc == 2) { + char *xpos, *ypos; for (la = lahead; la != NULL; la = la->ar_next) { + xpos = DBWPrintValue(la->cellUse->cu_bbox.r_xbot, + w, TRUE); + ypos = DBWPrintValue(la->cellUse->cu_bbox.r_ybot, + w, FALSE); #ifdef MAGIC_WRAPPER if (doList) { tobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->cellUse->cu_bbox.r_xbot)); + Tcl_NewStringObj(xpos, -1)); Tcl_ListObjAppendElement(magicinterp, tobj, - Tcl_NewIntObj(la->cellUse->cu_bbox.r_ybot)); + Tcl_NewStringObj(ypos, -1)); Tcl_SetObjResult(magicinterp, tobj); } else @@ -469,8 +485,8 @@ CmdArray( TxPrintf("Cell use \"%s\":", la->cellUse->cu_id); else TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name); - TxPrintf("x=%d ", la->cellUse->cu_bbox.r_xbot); - TxPrintf("y=%d\n", la->cellUse->cu_bbox.r_ybot); + TxPrintf("x=%s ", xpos); + TxPrintf("y=%s\n", ypos); #ifdef MAGIC_WRAPPER } #endif @@ -874,13 +890,16 @@ CmdBox( TxRebuildCommand(cmd); return; } - else if (DBWSnapToGrid != DBW_SNAP_USER) + else if (DBWUnits != DBW_UNITS_USER) { distancex = cmdParseCoord(w, cmd->tx_argv[3], TRUE, FALSE); distancey = distancex; } else { + /* For user units, the distance may be different in the X and Y + * directions for a given value. + */ switch (direction) { case GEO_EAST: case GEO_WEST: @@ -908,15 +927,14 @@ CmdBox( case BOX_WIDTH: if (argc == 2) { + char *boxvalues; + boxvalues = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot, + w, TRUE); #ifdef MAGIC_WRAPPER - char *boxvalues = (char *)Tcl_Alloc(50); - sprintf(boxvalues, "%d", - boxptr->r_xtop - boxptr->r_xbot); - Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1)); #else - TxPrintf("%s box width is %d\n", - (refEdit) ? "Edit" : "Root", - boxptr->r_xtop - boxptr->r_xbot); + TxPrintf("%s box width is %s\n", (refEdit) ? "Edit" : "Root", + boxvalues); #endif return; } @@ -928,15 +946,14 @@ CmdBox( case BOX_HEIGHT: if (argc == 2) { + char *boxvalues; + boxvalues = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot, + w, FALSE); #ifdef MAGIC_WRAPPER - char *boxvalues = (char *)Tcl_Alloc(50); - sprintf(boxvalues, "%d", - boxptr->r_ytop - boxptr->r_ybot); - Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1)); #else - TxPrintf("%s box height is %d\n", - (refEdit) ? "Edit" : "Root", - boxptr->r_ytop - boxptr->r_ybot); + TxPrintf("%s box height is %s\n", (refEdit) ? "Edit" : "Root", + boxvalues); #endif return; } @@ -949,16 +966,24 @@ CmdBox( if (argc == 2) { #ifdef MAGIC_WRAPPER - char *boxvalues = (char *)Tcl_Alloc(50); - sprintf(boxvalues, "%d %d", - boxptr->r_xtop - boxptr->r_xbot, - boxptr->r_ytop - boxptr->r_ybot); - Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); + Tcl_Obj *tobj; +#endif + char *boxvaluex, *boxvaluey; + boxvaluex = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot, + w, TRUE); + boxvaluey = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot, + w, FALSE); +#ifdef MAGIC_WRAPPER + tobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluex, -1)); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluey, -1)); + Tcl_SetObjResult(magicinterp, tobj); #else - TxPrintf("%s box size is %d x %d\n", + TxPrintf("%s box size is %s x %s\n", (refEdit) ? "Edit" : "Root", - boxptr->r_xtop - boxptr->r_xbot, - boxptr->r_ytop - boxptr->r_ybot); + boxvaluex, boxvaluey); #endif return; } @@ -973,14 +998,22 @@ CmdBox( if (argc == 2) { #ifdef MAGIC_WRAPPER - char *boxvalues = (char *)Tcl_Alloc(50); - sprintf(boxvalues, "%d %d", - boxptr->r_xbot, boxptr->r_ybot); - Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); + Tcl_Obj *tobj; +#endif + char *boxvaluex, *boxvaluey; + boxvaluex = DBWPrintValue(boxptr->r_xbot, w, TRUE); + boxvaluey = DBWPrintValue(boxptr->r_ybot, w, FALSE); +#ifdef MAGIC_WRAPPER + tobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluex, -1)); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluey, -1)); + Tcl_SetObjResult(magicinterp, tobj); #else - TxPrintf("%s box lower-left corner at (%d, %d)\n", + TxPrintf("%s box lower-left corner at (%s, %s)\n", (refEdit) ? "Edit" : "Root", - boxptr->r_xbot, boxptr->r_ybot); + boxvaluex, boxvaluey); #endif return; } @@ -1012,16 +1045,31 @@ CmdBox( if (argc == 2) { #ifdef MAGIC_WRAPPER - char *boxvalues = (char *)Tcl_Alloc(50); - sprintf(boxvalues, "%d %d %d %d", - boxptr->r_xbot, boxptr->r_ybot, - boxptr->r_xtop, boxptr->r_ytop); - Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC); + Tcl_Obj *tobj; +#endif + char *boxvaluellx, *boxvaluelly; + char *boxvalueurx, *boxvalueury; + + boxvaluellx = DBWPrintValue(boxptr->r_xbot, w, TRUE); + boxvaluelly = DBWPrintValue(boxptr->r_ybot, w, FALSE); + boxvalueurx = DBWPrintValue(boxptr->r_xtop, w, TRUE); + boxvalueury = DBWPrintValue(boxptr->r_ytop, w, FALSE); +#ifdef MAGIC_WRAPPER + + tobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluellx, -1)); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvaluelly, -1)); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvalueurx, -1)); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj(boxvalueury, -1)); + Tcl_SetObjResult(magicinterp, tobj); #else - TxPrintf("%s box coordinates (%d, %d) to (%d, %d)\n", + TxPrintf("%s box coordinates (%s, %s) to (%s, %s)\n", (refEdit) ? "Edit" : "Root", - boxptr->r_xbot, boxptr->r_ybot, - boxptr->r_xtop, boxptr->r_ytop); + boxvaluellx, boxvaluelly, boxvalueurx, boxvalueury); #endif return; } diff --git a/commands/CmdE.c b/commands/CmdE.c index 650a8b5d..83813642 100644 --- a/commands/CmdE.c +++ b/commands/CmdE.c @@ -1122,12 +1122,13 @@ CmdExtract( } else if (argc == 2) { + char *halodisp; + halodisp = DBWPrintValue(ExtCurStyle->exts_sideCoupleHalo, + w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_Obj *tobj; - tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo); - Tcl_SetObjResult(magicinterp, tobj); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(halodisp, -1)); #else - TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo); + TxPrintf("Side overlap halo is %s\n", halodisp); #endif return; } @@ -1152,12 +1153,12 @@ CmdExtract( } else if (argc == 2) { + char *stepdisp; + stepdisp = DBWPrintValue(ExtCurStyle->exts_stepSize, w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_Obj *tobj; - tobj = Tcl_NewIntObj(ExtCurStyle->exts_stepSize); - Tcl_SetObjResult(magicinterp, tobj); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(stepdisp, -1)); #else - TxPrintf("Extraction step size is %d\n", ExtCurStyle->exts_stepSize); + TxPrintf("Extraction step size is %s\n", stepdisp); #endif return; } diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 8bb419f3..c4c91277 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -1084,25 +1084,33 @@ CmdSelect( */ case SEL_BBOX: + { + char *selllx, *sellly, *selurx, *selury; + GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea); + selllx = DBWPrintValue(selarea.r_xbot, w, TRUE); + sellly = DBWPrintValue(selarea.r_ybot, w, FALSE); + selurx = DBWPrintValue(selarea.r_xtop, w, TRUE); + selury = DBWPrintValue(selarea.r_ytop, w, FALSE); + #ifdef MAGIC_WRAPPER lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(selarea.r_xbot)); + Tcl_NewStringObj(selllx, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(selarea.r_ybot)); + Tcl_NewStringObj(sellly, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(selarea.r_xtop)); + Tcl_NewStringObj(selurx, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(selarea.r_ytop)); + Tcl_NewStringObj(selury, -1)); Tcl_SetObjResult(magicinterp, lobj); #else - TxPrintf("Select bounding box: %d %d %d %d\n", - selarea.r_xbot, selarea.r_ybot, - selarea.r_xtop, selarea.r_ytop); + TxPrintf("Select bounding box: %s %s %s %s\n", + selllx, sellly, selurx, selury); #endif return; + } /*-------------------------------------------------------------------- * Make a copy of the selection at its present loction but do not @@ -1985,23 +1993,25 @@ cmdLabelRectFunc( if (rect == NULL) { + char *labllx, *lablly, *laburx, *labury; + + /* Note: Ideally, the MagWindow pointer should be passed to this function */ + labllx = DBWPrintValue(label->lab_rect.r_xbot, (MagWindow *)NULL, TRUE); + lablly = DBWPrintValue(label->lab_rect.r_ybot, (MagWindow *)NULL, FALSE); + laburx = DBWPrintValue(label->lab_rect.r_xtop, (MagWindow *)NULL, TRUE); + labury = DBWPrintValue(label->lab_rect.r_ytop, (MagWindow *)NULL, FALSE); + #ifdef MAGIC_WRAPPER lobj = Tcl_GetObjResult(magicinterp); pobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, lobj, pobj); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewIntObj((double)label->lab_rect.r_xbot)); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewIntObj((double)label->lab_rect.r_ybot)); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewIntObj((double)label->lab_rect.r_xtop)); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewIntObj((double)label->lab_rect.r_ytop)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labllx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(lablly, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laburx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labury, -1)); Tcl_SetObjResult(magicinterp, lobj); #else - TxPrintf("%d %d %d %d\n", - label->lab_rect.r_xbot, label->lab_rect.r_ybot, - label->lab_rect.r_xtop, label->lab_rect.r_ytop); + TxPrintf("%s %s %s %s\n", labllx, lablly, laburx,labury); #endif } else if (!GEO_SAMERECT(label->lab_rect, *rect)) @@ -2317,11 +2327,13 @@ CmdSetLabel( { if (locargc == 2) { + char *labsize; + + labsize = DBWPrintValue(DefaultLabel->lab_size, w, FALSE); #ifdef MAGIC_WRAPPER - Tcl_SetObjResult(magicinterp, - Tcl_NewIntObj(DefaultLabel->lab_size)); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(labsize, -1)); #else - TxPrintf("%d\n", DefaultLabel->lab_size); + TxPrintf("%s\n", labsize); #endif } else @@ -2360,16 +2372,20 @@ CmdSetLabel( { if (locargc == 2) { + char *laboffx, *laboffy; + laboffx = DBWPrintValue(DefaultLabel->lab_offset.p_x, w, + TRUE); + laboffy = DBWPrintValue(DefaultLabel->lab_offset.p_y, w, + FALSE); #ifdef MAGIC_WRAPPER lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(DefaultLabel->lab_offset.p_x)); + Tcl_NewStringObj(laboffx, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(DefaultLabel->lab_offset.p_y)); + Tcl_NewStringObj(laboffy, -1)); Tcl_SetObjResult(magicinterp, lobj); #else - TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x, - DefaultLabel->lab_offset.p_y); + TxPrintf("%s %s\n", laboffx, laboffy); #endif } else @@ -2887,13 +2903,13 @@ CmdSnap( switch (n) { case SNAP_OFF: case SNAP_INTERNAL: - DBWSnapToGrid = DBW_SNAP_INTERNAL; + DBWSnapToGrid = DBW_UNITS_INTERNAL; return; case SNAP_LAMBDA: - DBWSnapToGrid = DBW_SNAP_LAMBDA; + DBWSnapToGrid = DBW_UNITS_LAMBDA; return; case SNAP_GRID: case SNAP_USER: case SNAP_ON: - DBWSnapToGrid = DBW_SNAP_USER; + DBWSnapToGrid = DBW_UNITS_USER; return; } @@ -2901,21 +2917,19 @@ printit: if (n == SNAP_LIST) /* list */ #ifdef MAGIC_WRAPPER Tcl_SetResult(magicinterp, - (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : - ((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"), + (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" : + ((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"), TCL_VOLATILE); #else - TxPrintf("%s\n", (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : - ((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user")); + TxPrintf("%s\n", (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" : + ((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user")); #endif else TxPrintf("Box is aligned to %s grid\n", - (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : - ((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user")); + (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" : + ((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user")); } - - /* * ---------------------------------------------------------------------------- * diff --git a/commands/CmdSubrs.c b/commands/CmdSubrs.c index f62c5386..89ddddfe 100644 --- a/commands/CmdSubrs.c +++ b/commands/CmdSubrs.c @@ -109,7 +109,7 @@ cmdScaleCoord( { char *endptr; double dval = 0; - int mscale = 1; + int mscale = 1, curunits; DBWclientRec *crec; if (*arg == '{') arg++; @@ -125,8 +125,18 @@ cmdScaleCoord( return 0; } - else if ((*endptr == 'l') - || ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_LAMBDA))) + /* Original behavior was to accept un-suffixed values according to the + * "snap" setting. This behavior remains in effect until the "units" + * command is used, in which case units follow the selected units + * value indepedendently of the snap setting. + */ + if (DBWUnits == DBW_UNITS_DEFAULT) + curunits = DBWSnapToGrid; + else + curunits = DBWUnits & DBW_UNITS_TYPE_MASK; + + if ((*endptr == 'l') + || ((*endptr == '\0') && (curunits == DBW_UNITS_LAMBDA))) { /* lambda or default units */ dval *= (double)DBLambda[1]; @@ -134,13 +144,13 @@ cmdScaleCoord( return round(dval); } else if ((*endptr == 'i') - || ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_INTERNAL))) + || ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL))) { /* internal units */ return round(dval); } else if ((*endptr == 'g') - || ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_USER))) + || ((*endptr == '\0') && (curunits == DBW_UNITS_USER))) { /* grid units */ if (w == (MagWindow *)NULL) @@ -166,6 +176,10 @@ cmdScaleCoord( } return round(dval); } + else if (*endptr == '\0' && (curunits == DBW_UNITS_MICRONS)) + { + mscale = 1000; + } else { /* natural units referred to the current cifoutput style */ diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index 3fa43752..fb7ded04 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -455,15 +455,18 @@ CmdTech( } if (!strncmp(cmd->tx_argv[2], "width", 5)) { + char *techwidth; tresult = DRCGetDefaultLayerWidth(t1); + techwidth = DBWPrintValue(tresult, w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techwidth, -1)); #else - TxPrintf("Minimum width is %d\n", tresult); + TxPrintf("Minimum width is %s\n", techwidth); #endif } else if (!strncmp(cmd->tx_argv[2], "spac", 4)) { + char *techspace; if (cmd->tx_argc >= 5) { t2 = DBTechNoisyNameType(cmd->tx_argv[4]); @@ -475,14 +478,16 @@ CmdTech( else t2 = t1; tresult = DRCGetDefaultLayerSpacing(t1, t2); + techspace = DBWPrintValue(tresult, w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techspace, -1)); #else - TxPrintf("Minimum spacing is %d\n", tresult); + TxPrintf("Minimum spacing is %s\n", techspace); #endif } else if (!strncmp(cmd->tx_argv[2], "surr", 4)) { + char *techsurround; if (cmd->tx_argc >= 5) { t2 = DBTechNoisyNameType(cmd->tx_argv[4]); @@ -498,14 +503,17 @@ CmdTech( } tresult = DRCGetDefaultLayerSurround(t1, t2); + techsurround = DBWPrintValue(tresult, w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techsurround, -1)); #else - TxPrintf("Minimum surround is %d\n", tresult); + TxPrintf("Minimum surround is %s\n", techsurround); #endif } else if (!strncmp(cmd->tx_argv[2], "direc", 5)) { + char *techdirec; + if (cmd->tx_argc >= 5) { t2 = DBTechNoisyNameType(cmd->tx_argv[4]); @@ -521,10 +529,11 @@ CmdTech( } tresult = DRCGetDirectionalLayerSurround(t1, t2); + techdirec = DBWPrintValue(tresult, w, TRUE); #ifdef MAGIC_WRAPPER - Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); + Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techdirec, -1)); #else - TxPrintf("Minimum surround (in one orientation) is %d\n", tresult); + TxPrintf("Minimum surround (in one orientation) is %s\n", techdirec); #endif } } @@ -754,6 +763,182 @@ cmdUnexpandFunc( return 0; } +/* + * ---------------------------------------------------------------------------- + * + * CmdUnits -- + * + * Implement the "units" command. + * + * Usage: + * units [value] [print|noprint] + * + * where "value" may be one of "default", "internal", "lambda", + * "user" (equivalently "grid"), or "microns". + * + * Results: + * None. + * + * Side effects: + * The global variable DBWUnits may be changed, which changes the + * behavior of magic when interpreting un-suffixed values or + * displaying values. + * + * Notes: + * The units behavior was previously dependent on what command was + * issued, with results usually being given in internal units, and + * with un-suffixed values following the snap behavior. Backwards- + * compatible behavior is used on startup or at any time by setting + * the units to "default". Otherwise, unit display follows the + * given "units" setting. + * + * ---------------------------------------------------------------------------- + */ + +#define UNITS_DEFAULT 0 +#define UNITS_INTERNAL 1 +#define UNITS_LAMBDA 2 +#define UNITS_GRID 3 +#define UNITS_USER 4 +#define UNITS_MICRONS 5 +#define UNITS_LIST 6 +#define UNITS_PRINT 7 +#define UNITS_NOPRINT 8 + +void +CmdUnits( + MagWindow *w, + TxCommand *cmd) +{ + static const char * const names[] = { "default", "internal", "lambda", + "grid", "user", "microns", "list", "print", "noprint", 0 }; + int idx, n = UNITS_LIST, n2, saveflag; + DBWclientRec *crec; + + if (cmd->tx_argc >= 2) + { + n = Lookup(cmd->tx_argv[1], names); + if (n < 0) + { + TxPrintf("Usage: units [default | internal | lambda | microns" + " | user] [print]\n"); + return; + } + if (DBWUnits != DBW_UNITS_DEFAULT) + saveflag = DBWUnits & DBW_UNITS_PRINT_FLAG; + else + saveflag = -1; + + switch (n) + { + case UNITS_DEFAULT: + DBWUnits = DBW_UNITS_DEFAULT; + break; + case UNITS_INTERNAL: + DBWUnits = DBW_UNITS_INTERNAL; + break; + case UNITS_LAMBDA: + DBWUnits = DBW_UNITS_LAMBDA; + break; + case UNITS_USER: + case UNITS_GRID: + DBWUnits = DBW_UNITS_USER; + break; + case UNITS_MICRONS: + DBWUnits = DBW_UNITS_MICRONS; + break; + case UNITS_PRINT: + saveflag = DBW_UNITS_PRINT_FLAG; + break; + case UNITS_NOPRINT: + saveflag = 0; + break; + } + if (n < 0) + { + TxError("Unrecognized units option %s\n.", cmd->tx_argv[1]); + return; + } + if (n != UNITS_LIST) + { + if ((cmd->tx_argc == 3) && (n != UNITS_DEFAULT)) + { + n2 = Lookup(cmd->tx_argv[2], names); + switch (n2) + { + case UNITS_PRINT: + DBWUnits |= DBW_UNITS_PRINT_FLAG; + break; + case UNITS_NOPRINT: + DBWUnits &= DBW_UNITS_TYPE_MASK; + break; + default: + TxError("Unrecognized units option %s\n.", cmd->tx_argv[2]); + break; + } + } + else if ((n != UNITS_DEFAULT) && (saveflag != -1)) + { + /* Preserve the previous value of the print/noprint flag */ + DBWUnits &= DBW_UNITS_TYPE_MASK; + DBWUnits |= saveflag; + } + return; + } + } + + if (DBWUnits == DBW_UNITS_DEFAULT) + idx = UNITS_DEFAULT; + else + switch (DBWUnits & DBW_UNITS_TYPE_MASK) + { + case DBW_UNITS_INTERNAL: + idx = UNITS_INTERNAL; + break; + case DBW_UNITS_LAMBDA: + idx = UNITS_LAMBDA; + break; + case DBW_UNITS_USER: + idx = UNITS_USER; + break; + case DBW_UNITS_MICRONS: + idx = UNITS_MICRONS; + break; + } + + if (n == UNITS_LIST) /* list */ + { +#ifdef MAGIC_WRAPPER + Tcl_Obj *tobj; + tobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj((char *)names[idx], -1)); + if (idx != UNITS_DEFAULT) + { + if (DBWUnits & DBW_UNITS_PRINT_FLAG) + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj("print", 5)); + else + Tcl_ListObjAppendElement(magicinterp, tobj, + Tcl_NewStringObj("noprint", 7)); + } + Tcl_SetObjResult(magicinterp, tobj); +#else + TxPrintf("%s", names[idx]); + if (idx != UNITS_DEFAULT) + if (DBWUnits & DBW_UNITS_PRINT_FLAG) + TxPrintf(" print"); + TxPrintf("\n"); +#endif + } + else if (idx == UNITS_DEFAULT) + TxPrintf("Reported units follow the snap setting.\n"); + else if (DBWUnits & DBW_UNITS_PRINT_FLAG) + TxPrintf("Values are reported as %s, along with the units.\n", names[idx]); + else + TxPrintf("Values are reported as %s\n", names[idx]); +} + /* * ---------------------------------------------------------------------------- * @@ -1696,18 +1881,20 @@ CmdWire( case VALUES: if (locargc == 2) { + char *wdisp; width = WireGetWidth(); type = WireGetType(); + wdisp = DBWPrintValue(width, w, TRUE); #ifdef MAGIC_WRAPPER lobj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, lobj, - Tcl_NewIntObj(width)); + Tcl_NewStringObj(wdisp, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(DBTypeLongNameTbl[type], -1)); Tcl_SetObjResult(magicinterp, lobj); #else - TxPrintf("Wire layer %s, width %d\n", - DBTypeLongNameTbl[type], width); + TxPrintf("Wire layer %s, width %s\n", + DBTypeLongNameTbl[type], wdisp); #endif } break; @@ -1732,12 +1919,14 @@ CmdWire( case WIDTH: if (locargc == 2) { + char *wdisp; width = WireGetWidth(); + wdisp = DBWPrintValue(width, w, TRUE); #ifdef MAGIC_WRAPPER - lobj = Tcl_NewIntObj(width); + lobj = Tcl_NewStringObj(wdisp, -1); Tcl_SetObjResult(magicinterp, lobj); #else - TxPrintf("Wire width is %d\n", width); + TxPrintf("Wire width is %s\n", wdisp); #endif } else if (locargc != 3) diff --git a/database/DBcellname.c b/database/DBcellname.c index 9d23dfe9..69262e7c 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -1621,6 +1621,7 @@ dbAbutmentUseFunc(selUse, use, transform, data) Rect bbox, refbox; Transform *trans; char *propvalue; + char *refllx, *reflly, *refurx, *refury; bool found; bool *dolist = (bool *)data; @@ -1653,21 +1654,25 @@ dbAbutmentUseFunc(selUse, use, transform, data) } GeoTransRect(trans, &bbox, &refbox); + /* NOTE: Ideally, the MagWindow pointer should get passed to this routine */ + refllx = DBWPrintValue(refbox.r_xbot, (MagWindow *)NULL, TRUE); + reflly = DBWPrintValue(refbox.r_ybot, (MagWindow *)NULL, FALSE); + refurx = DBWPrintValue(refbox.r_xtop, (MagWindow *)NULL, TRUE); + refury = DBWPrintValue(refbox.r_ytop, (MagWindow *)NULL, FALSE); + #ifdef MAGIC_WRAPPER if (*dolist) { pobj = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refllx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(reflly, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refurx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refury, -1)); Tcl_SetObjResult(magicinterp, pobj); } else #endif - TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot, - refbox.r_xtop, refbox.r_ytop); - + TxPrintf("Abutment box: %s %s %s %s\n", refllx, reflly, refurx, refury); return 0; } diff --git a/dbwind/DBWcommands.c b/dbwind/DBWcommands.c index 8995d854..e26004cf 100644 --- a/dbwind/DBWcommands.c +++ b/dbwind/DBWcommands.c @@ -54,7 +54,7 @@ extern void CmdRandom(), CmdSave(), CmdScaleGrid(), CmdSee(); extern void CmdSelect(), CmdSetLabel(), CmdSideways(); extern void CmdShell(), CmdSnap(); extern void CmdStretch(), CmdStraighten(); -extern void CmdTech(), CmdTool(), CmdUnexpand(); +extern void CmdTech(), CmdTool(), CmdUnexpand(), CmdUnits(); extern void CmdUpsidedown(), CmdWhat(), CmdWire(), CmdWriteall(); extern void CmdGoto(), CmdFlatten(), CmdXload(), CmdXor(); @@ -474,6 +474,9 @@ DBWInitCommands() WindAddCommand(DBWclientID, "unexpand unexpand subcells under box", CmdUnexpand, FALSE); + WindAddCommand(DBWclientID, + "units [type] set type of units parsed and displayed", + CmdUnits, FALSE); WindAddCommand(DBWclientID, "upsidedown flip selection and box upside down", CmdUpsidedown, FALSE); diff --git a/dbwind/DBWprocs.c b/dbwind/DBWprocs.c index 97c0094b..cb3cdeb3 100644 --- a/dbwind/DBWprocs.c +++ b/dbwind/DBWprocs.c @@ -25,6 +25,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include +#include "tcltk/tclmagic.h" #include "utils/main.h" #include "utils/magic.h" #include "utils/geometry.h" @@ -33,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/hash.h" #include "database/database.h" #include "utils/main.h" +#include "cif/cif.h" #include "commands/commands.h" #include "dbwind/dbwind.h" #include "graphics/graphics.h" @@ -653,6 +655,311 @@ DBWexit() return (CmdWarnWrite() == 1); } +/* + * ---------------------------------------------------------------------------- + * + * dbwValueFormat --- + * + * Remove unnecessary trailing zeros and decimal from a floating-point + * value formatted with "%.Nf" where N is the expected maximum number + * of places after the decimal, matching the argument "places". + * This makes the "%f" formatting work like "%g" formatting, but + * works around the limitation of "%.Ng" that it operates on the number + * of significant digits, not the number of decimal places. + * + * Results: + * None. + * + * Side effects: + * The string "buf" may be altered with a new terminating null character. + * + * ---------------------------------------------------------------------------- + */ + +void +dbwValueFormat(char *buf, + int places) +{ + char *p = buf + strlen(buf) - 1; + while (p > buf && *p == '0') *p-- = '\0'; + if (p > buf && *p == '.') *p = '\0'; +} + +/* + * ---------------------------------------------------------------------------- + * + * dbwPrintValue0 -- + * + * Convert a value in internal database units to a string based on + * the chosen display units as defined by DBWUnits (which is set + * with the "units" command). If DBWUnits has not been changed + * since startup, then the behavior is to print the internal units + * in string form. If DBWUnits has been set, then the units type + * determines how the output is displayed. + * + * If "is_square" is TRUE, then the value is in units squared, and + * scaling is done accordingly. In the case of DBW_UNITS_USER, + * where values are in grid multiples, the units for X and Y may + * differ, and "is_x" = TRUE indicates a measurement in the X direction, + * while false indicase a measurements in the Y direction. Naturally, + * if "is_square" is TRUE then "is_x" is ignored. "is_x" is also ignored + * for any output units other than user/grid units. + * + * If "is_cif" is true, then "value" is in CIF database units + * (centimicrons, nanometers, or angstroms, according to the + * scalefactor line in the tech file), rather than internal units. + * + * This routine is generally meant to be called as one of the three + * variants defined below it: DBWPrintValue(), DBWPrintSqValue(), + * or DBWPrintCIFValue(). + * + * Results: + * A pointer to a string. To facilitate printing up to four values + * (e.g., rectangle coordinates, such as from "box values"), a static + * string partitioned into four parts is created in this subroutine, + * and the result points to one position in the string, which is cycled + * through every four calls to the subroutine. The caller does not + * free the returned string. + * + * Side effects: + * None. + * + * NOTE: Prior to the introduction of the "units" command, magic had the + * inconsistent behavior that parsed input values on the command line + * would be interpreted per the "snap" setting, but output values were + * (almost) always given in internal units. This routine keeps the + * original behavior backwards-compatible, as inconsistent as it is. + * + * ---------------------------------------------------------------------------- + */ + +char * +dbwPrintValue0(int value, /* value to print, in internal units */ + MagWindow *w, /* current window, for use with grid */ + bool is_x, /* TRUE if value is an X dimension */ + bool is_square, /* TRUE if value is a dimension squared */ + bool is_cif) /* TRUE if value is in centimicrons */ +{ + char *result; + float oscale, dscale, fvalue; + DBWclientRec *crec; + int locunits; + + /* This routine is called often, so avoid constant use of malloc and + * free by keeping up to four printed results in static memory. + */ + static char resultstr[128]; + static unsigned char resultpos = 0; + + result = &resultstr[resultpos]; + resultpos += 32; + resultpos &= 127; /* At 128, cycle back to zero */ + + /* CIF database units are centimicrons/nanometers/angstroms as + * set by the "scalefactor" line in the tech file. When "is_cif" + * is TRUE, then "value" is in these units. Find the conversion + * factor to convert "value" to internal units, and then it can + * be subsequently converted to lambda, microns, etc. + */ + if (is_cif == TRUE) + dscale = CIFGetScale(100) / CIFGetOutputScale(1000); + else + dscale = 1.0; + + /* When printing user/grid units, check for a valid window */ + + locunits = DBWUnits; + if (locunits != DBW_UNITS_DEFAULT) locunits &= DBW_UNITS_TYPE_MASK; + + /* The MagWindow argument is only needed for user units, since the + * user grid values are found there. Setting MagWindow to NULL + * effectively disables printing values in user grid units, which + * then default to internal units. + */ + if (locunits == DBW_UNITS_USER) + { + if (w == (MagWindow *)NULL) + { + windCheckOnlyWindow(&w, DBWclientID); + if (w == (MagWindow *)NULL) + locunits = DBW_UNITS_DEFAULT; + } + } + + switch (locunits) + { + case DBW_UNITS_DEFAULT: + snprintf(result, 32, "%d", value); + break; + + case DBW_UNITS_INTERNAL: + if (is_cif) + { + if (is_square) + { + snprintf(result, 32, "%.6f", value * dscale * dscale); + dbwValueFormat(result, 6); + } + else + { + snprintf(result, 32, "%.3f", value * dscale); + dbwValueFormat(result, 3); + } + } + else + snprintf(result, 32, "%d", value); + if (is_square) + { + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29)) + strcat(result, "i^2"); + } + else + { + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31)) + strcat(result, "i"); + } + break; + + case DBW_UNITS_LAMBDA: + + oscale = (float)DBLambda[0]; + oscale /= (float)DBLambda[1]; + if (is_square) + { + fvalue = (float)value * oscale * oscale * dscale * dscale; + snprintf(result, 32, "%0.6f", (double)fvalue); + dbwValueFormat(result, 6); + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29)) + strcat(result, "l^2"); + } + else + { + fvalue = (float)value * oscale * dscale; + snprintf(result, 32, "%0.3f", (double)fvalue); + dbwValueFormat(result, 3); + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31)) + strcat(result, "l"); + } + break; + + case DBW_UNITS_MICRONS: + oscale = CIFGetOutputScale(1000); + if (is_square) + { + fvalue = (float)value * oscale * oscale * dscale * dscale; + snprintf(result, 32, "%0.6f", (double)fvalue); + dbwValueFormat(result, 6); + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 28)) + strcat(result, "um^2"); + } + else + { + fvalue = (float)value * oscale * dscale; + snprintf(result, 32, "%0.3f", (double)fvalue); + dbwValueFormat(result, 3); + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30)) + strcat(result, "um"); + } + break; + + case DBW_UNITS_USER: + if (is_square) + { + oscale = (float)((crec->dbw_gridRect.r_xtop - + crec->dbw_gridRect.r_xbot) * + (crec->dbw_gridRect.r_ytop - + crec->dbw_gridRect.r_ybot)); + } + else if (is_x) + { + oscale = (float)(crec->dbw_gridRect.r_xtop - + crec->dbw_gridRect.r_xbot); + } + else + { + oscale = (float)(crec->dbw_gridRect.r_ytop - + crec->dbw_gridRect.r_ybot); + } + fvalue = (float)value * oscale * dscale; + if (is_square) + { + fvalue *= dscale; + snprintf(result, 32, "%0.6f", (double)fvalue); + dbwValueFormat(result, 6); + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 27)) + strcat(result, "gx*gy"); + } + else + { + snprintf(result, 32, "%0.3f", (double)fvalue); + dbwValueFormat(result, 3); + if (is_x) + { + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30)) + strcat(result, "gx"); + } + else + { + if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30)) + strcat(result, "gy"); + } + } + break; + } + return result; +} + +/* + * ---------------------------------------------------------------------------- + * + * DBWPrintValue -- + * DBWPrintSqValue -- + * DBWPrintCIFValue -- + * DBWPrintCIFSqValue -- + * + * Convenience functions which call dbwPrintValue0() with specific + * fixed arguments, so that the calls are not full of boolean values. + * The "is_x" boolean is retained because it is used often. + * + * ---------------------------------------------------------------------------- + */ + +char * +DBWPrintValue(int value, /* value to print, in internal units */ + MagWindow *w, /* current window, for use with grid */ + bool is_x) /* TRUE if value is an X dimension */ +{ + /* Call dbwPrintValue0() with is_square = FALSE and is_cif = FALSE */ + return dbwPrintValue0(value, w, is_x, FALSE, FALSE); +} + +char * +DBWPrintSqValue(int value, /* value to print, in internal units */ + MagWindow *w) /* current window, for use with grid */ +{ + /* Call dbwPrintValue0() with is_square = TRUE and is_cif = FALSE */ + /* is_x is set to TRUE although it is unused. */ + return dbwPrintValue0(value, w, TRUE, TRUE, FALSE); +} + +char * +DBWPrintCIFValue(int value, /* value to print, in internal units */ + MagWindow *w, /* current window, for use with grid */ + bool is_x) /* TRUE if value is an X dimension */ +{ + /* Call dbwPrintValue0() with is_square = FALSE and is_cif = TRUE */ + return dbwPrintValue0(value, w, is_x, FALSE, TRUE); +} + +char * +DBWPrintCIFSqValue(int value, /* value to print, in internal units */ + MagWindow *w) /* current window, for use with grid */ +{ + /* Call dbwPrintValue0() with is_square = TRUE and is_cif = TRUE */ + /* is_x is set to TRUE although it is unused. */ + return dbwPrintValue0(value, w, TRUE, TRUE, TRUE); +} + /* * ---------------------------------------------------------------------------- * diff --git a/dbwind/DBWtools.c b/dbwind/DBWtools.c index 5722a661..73809b4f 100644 --- a/dbwind/DBWtools.c +++ b/dbwind/DBWtools.c @@ -65,11 +65,21 @@ typedef struct _crosshairRec { static CrosshairRec curCrosshair; /* Crosshair position */ /* - * If the following is DBW_SNAP_USER, the box gets snapped to the user's + * If the following is DBW_UNITS_USER, the box gets snapped to the user's * grid always, instead of snapping to the usual 1x1 grid. If the value - * is DBW_SNAP_INTERNAL, the box gets snapped to the internal grid. + * is DBW_UNITS_INTERNAL, the box gets snapped to the internal grid. */ -int DBWSnapToGrid = DBW_SNAP_LAMBDA; +int DBWSnapToGrid = DBW_UNITS_LAMBDA; + +/* + * The original behavior with respect to units was that un-suffixed + * values follow whatever the snap setting is (DBWSnapToGrid, above). + * Current behavior is that the original behavior is followed while + * DBWUnits is set to DBW_UNITS_DEFAULT. However, if the "units" + * command is given, then displayed and entered units follow that + * value independently of the snap setting. + */ +int DBWUnits = DBW_UNITS_DEFAULT; /* Forward reference: */ @@ -82,8 +92,8 @@ extern int DBWToolDraw(); * toolFindPoint -- * * Returns the point in root coordinates. - * If DBWSnapToGrid is DBW_SNAP_USER, pick the nearest point that is - * aligned with the window's grid. If DBWSnapToGrid is DBW_SNAP_LAMBDA, + * If DBWSnapToGrid is DBW_UNITS_USER, pick the nearest point that is + * aligned with the window's grid. If DBWSnapToGrid is DBW_UNITS_LAMBDA, * pick the nearest point that is an integer lambda value. * * Results: @@ -120,7 +130,7 @@ toolFindPoint(p, rootPoint, rootArea) if (!GEO_ENCLOSE(p, &WindCurrentWindow->w_screenArea)) return NULL; WindPointToSurface(WindCurrentWindow, p, rootPoint, rootArea); - if (DBWSnapToGrid != DBW_SNAP_INTERNAL) + if (DBWSnapToGrid != DBW_UNITS_INTERNAL) ToolSnapToGrid(WindCurrentWindow, rootPoint, rootArea); return WindCurrentWindow; @@ -844,8 +854,8 @@ DBWResetBox(CellDef *def) * Repositions the box by one of its corners. * If the point given to reposition the box is in screen coordinates, * the box corner is snapped to the user's grid (set with the :grid - * command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is - * DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer + * command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is + * DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer * lambda value. * * Results: @@ -948,8 +958,8 @@ ToolMoveBox(corner, point, screenCoords, rootDef) * * If the point given to reposition the box is in screen coordinates, * the box corner is snapped to the user's grid (set with the :grid - * command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is - * DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer + * command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is + * DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer * lambda value. * * Results: @@ -1092,7 +1102,7 @@ ToolSnapToGrid(w, p, rEnclose) if (crec == NULL || p == NULL) return; - if (DBWSnapToGrid == DBW_SNAP_LAMBDA) + if (DBWSnapToGrid == DBW_UNITS_LAMBDA) { lr.r_xbot = lr.r_ybot = 0; lr.r_xtop = DBLambda[1] / DBLambda[0]; diff --git a/dbwind/dbwind.h b/dbwind/dbwind.h index a46cce36..860b52a4 100644 --- a/dbwind/dbwind.h +++ b/dbwind/dbwind.h @@ -113,6 +113,7 @@ typedef struct DBW1 { extern WindClient DBWclientID; extern int DBWSnapToGrid; +extern int DBWUnits; extern int DBWMaxTechStyles; extern int DBWMaxTileStyles; @@ -121,13 +122,17 @@ extern int DBWNumStyles; extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth; /* - * Exported procedure headers for redisplay + * Exported procedure headers for redisplay and output */ extern int DBWWatchTiles(); extern void DBWAreaChanged(); extern void DBWLabelChanged(); extern void DBWDrawLabel(); +extern char *DBWPrintValue(int value, MagWindow *w, bool is_x); +extern char *DBWPrintSqValue(int value, MagWindow *w); +extern char *DBWPrintCIFValue(int value, MagWindow *w, bool is_x); +extern char *DBWPrintCIFSqValue(int value, MagWindow *w); /* * Exported procedures and variables related to the technology file @@ -169,14 +174,36 @@ extern void DBWBoxHandler(); #define TOOL_ILG -1 /* The following defines are used to indicate which coordinate system - * the cursor box snaps to when moved with mouse clicks (values for - * DBWSnapToGrid). + * is used when displaying or returning values. By default this is + * set to DBW_UNITS_INTERNAL. From magic version 8.3.595, this is + * independently set from "snap". For backwards compatibility, + * the value starts as DBW_UNITS_DEFAULT which implements the original + * behavior in which the "snap" setting dictates the dispaly units. + * Only if set to a non-negative value do the display units operate + * independently of the snap setting. + * + * NOTES: + * Lambda units are fixed by the tech file. + * Internal units are scalable. + * User units are scalable; this can be used, for example, to + * set a box position according to multiples of a track + * pitch, but is most often used manually with the "g" + * (for "grid") suffix; e.g., "move box e 1g" + * Micron units are dependent on the specified cifoutput style + * and how the tech file defines the scalefactor for it. */ -#define DBW_SNAP_INTERNAL 0 /* internal units (fine grid) */ -#define DBW_SNAP_LAMBDA 1 /* lambda units (coarse grid) */ -#define DBW_SNAP_USER 2 /* user grid units (user grid) */ -#define DBW_SNAP_MICRONS 3 /* micron units */ +#define DBW_UNITS_DEFAULT -1 /* backwards-compatible behavior */ +#define DBW_UNITS_INTERNAL 0 /* internal units */ +#define DBW_UNITS_LAMBDA 1 /* lambda units */ +#define DBW_UNITS_USER 2 /* user grid units */ +#define DBW_UNITS_MICRONS 3 /* micron units */ +#define DBW_UNITS_TYPE_MASK 3 /* everything but the flag field(s) */ +#define DBW_UNITS_PRINT_FLAG 4 /* flag used to indicate that + * the units should be printed + * with the value; e.g., + * "10um" instead of "10". + */ /* The following window mask can be used to select all database windows * for things like the mask parameter to DBWAreaChanged. diff --git a/drc/DRCmain.c b/drc/DRCmain.c index 323d02e5..bd24141c 100644 --- a/drc/DRCmain.c +++ b/drc/DRCmain.c @@ -184,9 +184,9 @@ drcSubstitute (cptr) DRCCookie * cptr; /* Design rule violated */ { static char *why_out = NULL; - char *whyptr, *sptr, *wptr; - int subscnt = 0, whylen; - float oscale, value; + char *whyptr, *sptr, *wptr, *vptr; + int subscnt = 0, whylen, saveunits; + float value; extern float CIFGetOutputScale(); whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag]; @@ -203,10 +203,14 @@ drcSubstitute (cptr) why_out = (char *)mallocMagic(whylen * sizeof(char)); strcpy(why_out, whyptr); - if (cptr->drcc_flags & DRC_CIFRULE) - oscale = CIFGetScale(100); /* 100 = microns to centimicrons */ - else - oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */ + /* For backwards compatibility: If the units are set to "default", + * then print the DRC value in microns, with units, which is how + * the output was previously presented. + */ + saveunits = DBWUnits; + if (saveunits == DBW_UNITS_DEFAULT) + DBWUnits = DBW_UNITS_MICRONS | DBW_UNITS_PRINT_FLAG; + wptr = why_out; while ((sptr = strchr(whyptr, '%')) != NULL) @@ -218,21 +222,29 @@ drcSubstitute (cptr) switch (*(sptr + 1)) { case 'd': - /* Replace with "dist" value in microns */ - value = (float)cptr->drcc_dist * oscale; - snprintf(wptr, 20, "%01.3gum", value); + if (cptr->drcc_flags & DRC_CIFRULE) + vptr = DBWPrintCIFValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE); + else + vptr = DBWPrintValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE); + snprintf(wptr, 20, "%s", vptr); wptr += strlen(wptr); break; case 'c': /* Replace with "cdist" value in microns */ - value = (float)cptr->drcc_cdist * oscale; - snprintf(wptr, 20, "%01.3gum", value); + if (cptr->drcc_flags & DRC_CIFRULE) + vptr = DBWPrintCIFValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE); + else + vptr = DBWPrintValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE); + snprintf(wptr, 20, "%s", vptr); wptr += strlen(wptr); break; case 'a': /* Replace with "cdist" value in microns squared */ - value = (float)cptr->drcc_cdist * oscale * oscale; - snprintf(wptr, 20, "%01.4gum^2", value); + if (cptr->drcc_flags & DRC_CIFRULE) + vptr = DBWPrintCIFSqValue(cptr->drcc_cdist, (MagWindow *)NULL); + else + vptr = DBWPrintSqValue(cptr->drcc_cdist, (MagWindow *)NULL); + snprintf(wptr, 20, "%s", vptr); wptr += strlen(wptr); break; default: @@ -245,6 +257,7 @@ drcSubstitute (cptr) /* copy remainder of string (including trailing null) */ strncpy(wptr, whyptr, strlen(whyptr) + 1); + DBWUnits = saveunits; return why_out; } @@ -425,6 +438,8 @@ drcListallError (celldef, rect, cptr, scx) } if (drcsave == DRCErrorCount) { + char *rllx, *rlly, *rurx, *rury; + DRCErrorCount += 1; h = HashFind(&DRCErrorTable, drcSubstitute(cptr)); lobj = (Tcl_Obj *) HashGetValue(h); @@ -433,10 +448,15 @@ drcListallError (celldef, rect, cptr, scx) pobj = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop)); - Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop)); + rllx = DBWPrintValue(r.r_xbot, (MagWindow *)NULL, TRUE); + rlly = DBWPrintValue(r.r_ybot, (MagWindow *)NULL, FALSE); + rurx = DBWPrintValue(r.r_xtop, (MagWindow *)NULL, TRUE); + rury = DBWPrintValue(r.r_ytop, (MagWindow *)NULL, FALSE); + + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rllx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rlly, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rurx, -1)); + Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rury, -1)); Tcl_ListObjAppendElement(magicinterp, lobj, pobj); HashSetValue(h, lobj); diff --git a/graphics/W3Dmain.c b/graphics/W3Dmain.c index 0fb2cc3f..6b3897dc 100644 --- a/graphics/W3Dmain.c +++ b/graphics/W3Dmain.c @@ -694,15 +694,22 @@ w3dCutBox(w, cmd) { if (crec->clipped) { + char *cllx, *clly, *curx, *cury; + + cllx = DBWPrintValue(crec->cutbox.r_xbot, w, TRUE); + clly = DBWPrintValue(crec->cutbox.r_ybot, w, TRUE); + curx = DBWPrintValue(crec->cutbox.r_xtop, w, TRUE); + cury = DBWPrintValue(crec->cutbox.r_ytop, w, TRUE); + Tcl_Obj *rlist = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(magicinterp, rlist, - Tcl_NewIntObj((int)(crec->cutbox.r_xbot))); + Tcl_NewStringObj(cllx, -1)); Tcl_ListObjAppendElement(magicinterp, rlist, - Tcl_NewIntObj((int)(crec->cutbox.r_ybot))); + Tcl_NewStringObj(clly, -1)); Tcl_ListObjAppendElement(magicinterp, rlist, - Tcl_NewIntObj((int)(crec->cutbox.r_xtop))); + Tcl_NewStringObj(curx, -1)); Tcl_ListObjAppendElement(magicinterp, rlist, - Tcl_NewIntObj((int)(crec->cutbox.r_ytop))); + Tcl_NewStringObj(cury, -1)); Tcl_SetObjResult(magicinterp, rlist); } diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index 29c1e97b..a9d0e82e 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -650,18 +650,20 @@ proc magic::boxview {win {cmdstr ""}} { set framename [winfo parent $win] if {$framename == "."} {return} - if {[catch {set cr [cif scale out]}]} {return} + set curunits [units list] + units microns noprint set bval [${win} box values] - set bllx [expr {[lindex $bval 0] * $cr }] - set blly [expr {[lindex $bval 1] * $cr }] - set burx [expr {[lindex $bval 2] * $cr }] - set bury [expr {[lindex $bval 3] * $cr }] + set bllx [lindex $bval 0] + set blly [lindex $bval 1] + set burx [lindex $bval 2] + set bury [lindex $bval 3] if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]} if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]} if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]} if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]} set titletext [format "box (%+g %+g) to (%+g %+g) microns" \ $bllx $blly $burx $bury] + units {*}$curunits ${framename}.titlebar.pos configure -text $titletext } } @@ -673,37 +675,27 @@ proc magic::cursorview {win} { } *bypass logcommands suspend set framename [winfo parent $win] - if {[catch {set cr [*bypass cif scale out]}]} { - *bypass logcommands resume - return - } - if {$cr == 0} {return} - set olst [${win} cursor internal] + set olst [${win} cursor microns] set olstx [lindex $olst 0] set olsty [lindex $olst 1] if {$Opts(crosshair)} { - *bypass crosshair ${olstx}i ${olsty}i - } - - # Use catch, because occasionally this fails on startup - if {[catch { - set olstx [expr {$olstx * $cr}] - set olsty [expr {$olsty * $cr}] - }]} { - *bypass logcommands resume - return + *bypass crosshair ${olstx}um ${olsty}um } if {[${win} box exists]} { + set curunits [${win} units list] + ${win} units microns noprint set dlst [${win} box position] - set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }] - set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }] + + set dx [expr {$olstx - [lindex $dlst 0]}] + set dy [expr {$olsty - [lindex $dlst 1]}] if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]} if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]} set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy] ${framename}.titlebar.pos configure -text $titletext + ${win} units {*}$curunits } else { set titletext [format "(%+g %+g) microns" $olstx $olsty] ${framename}.titlebar.pos configure -text $titletext @@ -834,7 +826,10 @@ proc magic::setscrollvalues {win} { *bypass logcommands suspend set svalues [${win} view get] + set curunits [units list] + units internal noprint set bvalues [${win} view bbox] + units {*}$curunits set framename [winfo parent ${win}] if {$framename == "."} { @@ -911,8 +906,11 @@ proc magic::scrollview { w win orient } { set v2 $scale($orient,update) set delta [expr {$v2 - $v1}] + set curunits [units list] + units internal noprint set bvalues [${win} view bbox] set wvalues [${win} windowpositions] + units {*}$curunits # Note that adding 0.000 in expression forces floating-point @@ -1299,7 +1297,17 @@ proc magic::openwrapper {{cell ""} {framename ""}} { $m add command -label "Grid off" -command {magic::grid off} $m add command -label "Snap-to-grid on" -command {magic::snap on} $m add command -label "Snap-to-grid off" -command {magic::snap off} - $m add command -label "Measure box" -command {magic::box } + $m add command -label "Measure box" -command {magic::box} + $m add separator + $m add command -label "Report internal units" -command {magic::units internal} + $m add command -label "Report lambda units" -command {magic::units lambda} + $m add command -label "Report micron units" -command {magic::units microns} + $m add command -label "Report grid units" -command {magic::units grid} + $m add check -label "Display units" -variable Opts(printunits) \ + -command [subst {if { \$Opts(printunits) } { \ + magic::units print } else { magic::units noprint } }] + + $m add separator $m add command -label "Set grid 0.05um" -command {magic::grid 0.05um} $m add command -label "Set grid 0.10um" -command {magic::grid 0.10um} diff --git a/utils/runstats.c b/utils/runstats.c index f8323ec6..ab8685b8 100644 --- a/utils/runstats.c +++ b/utils/runstats.c @@ -210,7 +210,7 @@ RunStatsRealTime(void) while (inct >= 10) { inct -= 10; incs++; } while (incs >= 60) { incs -= 60; incm++; } - sprintf(buf, "%ld:%02ld.%ld %ld:%02ld.%ld", + snprintf(buf, (size_t)50, "%ld:%02ld.%ld %ld:%02ld.%ld", totm, tots, tott, incm, incs, inct); lasttime = curtime; diff --git a/windows/windCmdAM.c b/windows/windCmdAM.c index 20edb953..a4fa9747 100644 --- a/windows/windCmdAM.c +++ b/windows/windCmdAM.c @@ -449,14 +449,26 @@ windCursorCmd(w, cmd) TxCommand *cmd; { Point p_in, p_out; - int resulttype = DBW_SNAP_INTERNAL; + int resulttype, saveunits; double cursx, cursy, oscale; + char *dispx, *dispy; DBWclientRec *crec; #ifdef MAGIC_WRAPPER Tcl_Obj *listxy; #endif + /* The original behavior was to use internal + * units by default. This remains the case + * unless units are set with the "units" + * command, in which case units follow the + * specified units. + */ + if (DBWUnits == DBW_UNITS_DEFAULT) + resulttype = DBW_UNITS_INTERNAL; + else + resulttype = DBWUnits; + if (cmd->tx_argc == 2) { if (StrIsInt(cmd->tx_argv[1])) @@ -465,17 +477,21 @@ windCursorCmd(w, cmd) (*GrSetCursorPtr)(atoi(cmd->tx_argv[1])); return; } + else if (*cmd->tx_argv[1] == 'i') + { + resulttype = DBW_UNITS_INTERNAL; + } else if (*cmd->tx_argv[1] == 'l') { - resulttype = DBW_SNAP_LAMBDA; + resulttype = DBW_UNITS_LAMBDA; } else if (*cmd->tx_argv[1] == 'u') { - resulttype = DBW_SNAP_USER; + resulttype = DBW_UNITS_USER; } else if (*cmd->tx_argv[1] == 'm') { - resulttype = DBW_SNAP_MICRONS; + resulttype = DBW_UNITS_MICRONS; } else if (*cmd->tx_argv[1] == 'w') { @@ -485,7 +501,7 @@ windCursorCmd(w, cmd) { resulttype = -2; // Use this value for "screen" } - else if (*cmd->tx_argv[1] != 'i') + else { TxError("Usage: cursor glyphnum\n"); TxError(" (or): cursor [internal | lambda | microns | user | window]\n"); @@ -506,54 +522,37 @@ windCursorCmd(w, cmd) WindPointToSurface(w, &p_in, &p_out, (Rect *)NULL); /* Snap the cursor position if snap is in effect */ - if (DBWSnapToGrid != DBW_SNAP_INTERNAL) + if (DBWSnapToGrid != DBW_UNITS_INTERNAL) ToolSnapToGrid(w, &p_out, (Rect *)NULL); } /* Transform the result to declared units with option "lambda" or "grid" */ - switch (resulttype) { - case -2: - case -1: - cursx = (double)p_in.p_x; - cursy = (double)p_in.p_y; - break; - case DBW_SNAP_INTERNAL: - cursx = (double)p_out.p_x; - cursy = (double)p_out.p_y; - break; - case DBW_SNAP_LAMBDA: - cursx = (double)(p_out.p_x * DBLambda[0]) / (double)DBLambda[1]; - cursy = (double)(p_out.p_y * DBLambda[0]) / (double)DBLambda[1]; - break; - case DBW_SNAP_MICRONS: - oscale = (double)CIFGetOutputScale(1000); - cursx = (double)(p_out.p_x * oscale); - cursy = (double)(p_out.p_y * oscale); - break; - case DBW_SNAP_USER: - crec = (DBWclientRec *)w->w_clientData; - cursx = (double)((p_out.p_x - crec->dbw_gridRect.r_xbot) - / (crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot)); - cursy = (double)((p_out.p_y - crec->dbw_gridRect.r_ybot) - / (crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot)); - break; - } - -#ifdef MAGIC_WRAPPER - listxy = Tcl_NewListObj(0, NULL); - if ((cursx == round(cursx)) && (cursy == round(cursy))) + saveunits = DBWUnits; + if (resulttype < 0) { - Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursx)); - Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursy)); + /* Not really internal units, but that prints integer units verbatim */ + DBWUnits = DBW_UNITS_INTERNAL; + cursx = (double)p_in.p_x; + cursy = (double)p_in.p_y; } else { - Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursx)); - Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursy)); + DBWUnits = resulttype; + cursx = (double)p_out.p_x; + cursy = (double)p_out.p_y; } + + dispx = DBWPrintValue(cursx, w, TRUE); + dispy = DBWPrintValue(cursy, w, FALSE); + DBWUnits = saveunits; + +#ifdef MAGIC_WRAPPER + listxy = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispx, -1)); + Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispy, -1)); Tcl_SetObjResult(magicinterp, listxy); #else - TxPrintf("%g %g\n", cursx, cursy); + TxPrintf("%s %s\n", dispx, dispy); #endif } diff --git a/windows/windCmdSZ.c b/windows/windCmdSZ.c index 7d4c7299..6e654211 100644 --- a/windows/windCmdSZ.c +++ b/windows/windCmdSZ.c @@ -820,6 +820,9 @@ windViewCmd(w, cmd) if (!strncmp(cmd->tx_argv[1], "get", 3)) { + /* NOTE: The surface area is in screen (pixel) coordinates + * and so does not follow the "units" display type. + */ #ifndef MAGIC_WRAPPER TxPrintf("(%d, %d) to (%d, %d)\n", w->w_surfaceArea.r_xbot, w->w_surfaceArea.r_ybot, @@ -838,19 +841,24 @@ windViewCmd(w, cmd) } else if (!strncmp(cmd->tx_argv[1], "bbox", 4)) { + char *vllx, *vlly, *vurx, *vury; + + vllx = DBWPrintValue(w->w_bbox->r_xbot, w, TRUE); + vlly = DBWPrintValue(w->w_bbox->r_ybot, w, FALSE); + vurx = DBWPrintValue(w->w_bbox->r_xtop, w, TRUE); + vury = DBWPrintValue(w->w_bbox->r_ytop, w, FALSE); + #ifndef MAGIC_WRAPPER - TxPrintf("(%d, %d) to (%d, %d)\n", - w->w_bbox->r_xbot, w->w_bbox->r_ybot, - w->w_bbox->r_xtop, w->w_bbox->r_ytop); + TxPrintf("(%s, %s) to (%s, %s)\n", vllx, vlly, vurx, vury); #else Tcl_ListObjAppendElement(magicinterp, listxy, - Tcl_NewIntObj((int)w->w_bbox->r_xbot)); + Tcl_NewStringObj(vllx, -1)); Tcl_ListObjAppendElement(magicinterp, listxy, - Tcl_NewIntObj((int)w->w_bbox->r_ybot)); + Tcl_NewStringObj(vlly, -1)); Tcl_ListObjAppendElement(magicinterp, listxy, - Tcl_NewIntObj((int)w->w_bbox->r_xtop)); + Tcl_NewStringObj(vurx, -1)); Tcl_ListObjAppendElement(magicinterp, listxy, - Tcl_NewIntObj((int)w->w_bbox->r_ytop)); + Tcl_NewStringObj(vury, -1)); Tcl_SetObjResult(magicinterp, listxy); #endif }