Compare commits

...

19 Commits

Author SHA1 Message Date
R. Timothy Edwards d9e6c78adb Corrected an issue that was caused by early work on extresist:
The original version of extresist only worked with 4-terminal FET
devices, and handling of devices with fewer terminals was ignored,
and never properly dealt with.  This commit fixes the issues with
devices such as diodes that have fewer terminals.
2026-05-27 10:52:44 -04:00
R. Timothy Edwards d8580be739 Corrected a problem caused by fixing the "select visible" command
with respect to visible/invisible labels and cells.  The change
inadvertently made the "select area" command option stop selecting
labels on the same type as the layers being selected.  This has
been fixed.
2026-05-26 17:01:45 -04:00
R. Timothy Edwards 1a16502a69 Fixed a potential string overrun crash condition when doing
"getnode", as there is no limit on the length of a hierarchical
node name, and no check on the string length when copying back into
a fixed-length character array.
2026-05-25 14:39:12 -04:00
R. Timothy Edwards 5ecf10c022 Updated the version to go along with the merge of pull request #521
from Sylvain Munaut, which fixes an issue with the "property" command
when using the recently-added plane properties.
2026-05-25 12:07:33 -04:00
Sylvain Munaut e366cf6a4c commands: Fix parsing of plane properties in case of single string
The previous code would iterate over `proplen` chunks of strings
but would not initialize `proplen` for plane properties.

Technically for plane properties you don't need to "pre-count"
the string chunks but given how the code is currently written
it's easier to do the counting in all cases.

Also makes sure proprec is init to NULL so that if argument is
empty, property is set to NULL and not random value on the stack.

Fixes #520

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2026-05-25 12:49:52 +02:00
R. Timothy Edwards 7ecebb5dd6 Corrected a stupid omission to set the plane hint during a search
in "extresist", which when missing causes the plane to be searched
repeatedly from the same point instead of from the last place searched.
Can knock down the "extresist" time by up to 50%.
2026-05-24 22:01:29 -04:00
R. Timothy Edwards 099d513011 Corrected the "Pick" button action in the "Library Manager" window;
this had two issues:  (1) "getcell" was not being called with
"child 0 0", leading to child cells that are not placed where
expected in relation to a grid snap setting;  and (2) "cursor"
was assuming internal units and needed that to be explicitly
stated using "cursor internal".
2026-05-24 16:23:18 -04:00
R. Timothy Edwards e45399d347 Yet another optimization on "extresist", to remove the calls to
DBPaint() and DBErase(), which are meant as high-level calls from
the "paint" and "erase" commands and are not appropriate for low-
level tasks like erasing all contacts out of a database.  This
cut maybe 40 to 50% time off of the resistance extraction.
2026-05-22 12:02:03 -04:00
R. Timothy Edwards 7a3717b02a Another performance optimization to "extresist", this one to
avoid re-parsing a linked list from the current breakpoint
to the end to find all entries pointing to the same node.
Instead, the change to be made is saved in a hash table and
applied at the following link, so only one pass through the
linked list is required.
2026-05-21 19:55:50 -04:00
R. Timothy Edwards a062fdcfe0 Continued optimizing poorly written routines in "extresist".
Changed the "ResDissolveContacts()" routine to avoid running both
redundant and useless code.  Changed the breakpoint sorting
routine from a bubble sort to a merge sort for linked lists
longer than 16, as merge sort is more efficient for long lists.
2026-05-20 19:02:22 -04:00
Ahmed Nematallah 29447a35cd Delete duplicate magicps.pro file
This file exists in the magic directory, and is the one the build system uses, this file is a duplicate that has one different line "/ms { rectfill } bind def", and is not used anywhere

Keeping two duplicate files causes issues like them being out of sync, therefore it would be great if it was deleted
2026-05-19 12:22:37 -04:00
Ahmed Nematallah 1dcd09e20c Update the postscript file to be able to support much more stipples
The postscript template had a hardcoded stipple length of 29, any more stipples would cause problems with a postscript parser. This was particularly a problem since the default mos.24bit.dstyle has 36 stipples already.

It also used a base-30 encoding.

I have updated the template to fix both issues, it now uses base-10 encoding, and can support up to 255 stipples (which is the maximum length allowed by the current approach of using fonts)

I was also wondering if it made more sense to encode this file directly into the C program as a literal, as half of it already is in the C program. (some "begin"s have an "end" in strings directly embedded in magic, so this file basically serves as a large string that has to be loaded each time from disk, while other parts of the string are stored normally in memory)
2026-05-19 12:22:37 -04:00
R. Timothy Edwards 9626b5e8c9 Changed two sprintf() to snprint() on recommendation from an AI. 2026-05-19 12:21:54 -04:00
R. Timothy Edwards 256955f48e Created alternative algorithms for routines ResParallelCheck() and
ResTriangleCheck().  By using hash tables, I reduced
ResParallelCheck() from O(N^2) to O(N), and I reduced
ResTriangleCheck() from O(N^3) to O(N^2);  however, it is a bit
better than that because previously there was an N^2 loop over
items in the same list, so if one list happened to be very long,
then N^2 would be huge; whereas now the N^2 is the length of two
lists multiplied together, where both lists would have to be very
long to have the same performance impact.  It appears that long
resistor lists are pathological and rare.  For an example
pathological case, the extresist runtime has been reduced from
hours to seconds.
2026-05-15 21:38:32 -04:00
R. Timothy Edwards b983e33be7 Corrected an error with the recently-added "exception" DRC rule.
The logical expression for determining an excepted area was wrong
for one direction, resulting in false positive DRC violations.
2026-05-15 11:04:23 -04:00
R. Timothy Edwards db224105a7 Found another couple of places where the environment variable
HOME was checked but no check was made on whether or not the
result was NULL.  This resolves issue #490 in the github issue
tracker.

Also:  Modified the way that "select visible" works to check if
labels and/or cells are rendered visible in the window.  If not,
then they are not selected.  Previously, cell instances and
labels would be selected whether or not they were visible.
This resolves issue #503 in the github issue tracker.
2026-05-13 09:46:21 -04:00
R. Timothy Edwards e5a6cf0df9 Handled the case in which environment variable HOME is not set.
See github issue tracker issue #490.  There were two cases:  When
running without the Tk console, a NULL value was being passed to a
string comparison.  When running with the Tk console, two variables
were not initialized.  Both prolems have been fixed.
2026-05-13 08:51:16 -04:00
R. Timothy Edwards 22e182f908 One additional modification to check for a space in the option
with no following text.
2026-05-13 08:38:11 -04:00
R. Timothy Edwards 0013dda92d Response to issue #513 in the github issue tracker: The command-
line parser does not recognize arguments that are both in the
same word and also space separated;  this is easy to do from, e.g.,
a python interpreter by setting an option as a single string as
in "-d null";  it is harder to do from the command line, but can
be done with quotes, as in 'magic "-d null"'.

The utils/args.c routine parses this with ArgStr(), which recognizes
two cases, one in which the option is split across two arguments,
and one in which the option is one word without space separation.

I modified ArgStr() to accept a third syntax in which the option
is in a single argument but is also space-separated.  This simply
detects a space in the third character position and moves forward
to the next non-space character and returns that position.
2026-05-13 08:30:32 -04:00
23 changed files with 828 additions and 264 deletions

View File

@ -1 +1 @@
8.3.642 8.3.652

View File

@ -2324,7 +2324,7 @@ CmdDoProperty(
TxCommand *cmd, TxCommand *cmd,
int argstart) int argstart)
{ {
PropertyRecord *proprec; PropertyRecord *proprec = NULL;
char *value; char *value;
bool propfound, dolist; bool propfound, dolist;
int proptype, proplen, propvalue, i; int proptype, proplen, propvalue, i;
@ -2662,31 +2662,31 @@ CmdDoProperty(
* the valid number of arguments, then again to parse the * the valid number of arguments, then again to parse the
* values, once the property record has been allocated * values, once the property record has been allocated
*/ */
if (proptype == PROPERTY_TYPE_PLANE) value = cmd->tx_argv[argstart + 1];
for (proplen = 0; *value != '\0'; )
{ {
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord)); if (isspace(*value) && (*value != '\0')) value++;
plane = DBNewPlane((ClientData)TT_SPACE); if (!isspace(*value))
proprec->prop_value.prop_plane = plane;
}
else
{
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; *value != '\0'; )
{ {
if (isspace(*value) && (*value != '\0')) value++; proplen++;
if (!isspace(*value)) while (!isspace(*value) && (*value != '\0')) value++;
{
proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
} }
if (proplen > 0) }
if (proplen > 0)
{
if (proptype == PROPERTY_TYPE_PLANE)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
} else {
proprec = (PropertyRecord *)mallocMagic( proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + sizeof(PropertyRecord) +
(proplen - 2) * sizeof(int)); (proplen - 2) * sizeof(int));
}
proprec->prop_type = proptype;
proprec->prop_len = proplen;
} }
proprec->prop_type = proptype;
proprec->prop_len = proplen;
/* Second pass */ /* Second pass */
value = cmd->tx_argv[argstart + 1]; value = cmd->tx_argv[argstart + 1];

View File

@ -635,10 +635,21 @@ cmdSelectArea(
int i; int i;
for (i = 0; i < DBNumUserLayers; i++) for (i = 0; i < DBNumUserLayers; i++)
{ {
if((TTMaskHasType(&mask, i)) && !(TTMaskHasType(&crec->dbw_visibleLayers, i))) if ((TTMaskHasType(&mask, i)) &&
!(TTMaskHasType(&crec->dbw_visibleLayers, i)))
TTMaskClearType(&mask, i); TTMaskClearType(&mask, i);
} }
/* Remove L_CELL and L_LABEL if crec->dbw_flags indicates that
* they are not visible in the layout window.
*/
if (!(crec->dbw_flags & DBW_SEELABELS)) TTMaskClearType(&mask, L_LABEL);
if (!(crec->dbw_flags & DBW_SEECELLS)) TTMaskClearType(&mask, L_CELL);
} }
else if (option == SEL_AREA)
TTMaskSetType(&mask, L_LABEL);
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch); SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
} }
@ -1027,7 +1038,7 @@ CmdSelect(
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
* Select everything under the box, perhaps looking only at * Select everything under the box, perhaps looking only at
* particular layers, but only if its visible. * particular layers, but only if it's visible.
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */

View File

@ -2016,8 +2016,8 @@ badTransform:
if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/')) if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/'))
{ {
char *homedir = getenv("HOME"); char *homedir = getenv("HOME");
if (strncmp(cellDef->cd_file, homedir, strlen(homedir)) || if (homedir && (strncmp(cellDef->cd_file, homedir, strlen(homedir)) ||
*(cellDef->cd_file + strlen(homedir)) != '/') *(cellDef->cd_file + strlen(homedir)) != '/'))
{ {
char *homeroot = strrchr(homedir, '/'); char *homeroot = strrchr(homedir, '/');
int rootlen = (int)(homeroot - homedir) + 1; int rootlen = (int)(homeroot - homedir) + 1;
@ -2060,9 +2060,10 @@ badTransform:
if (*pathptr == '~') if (*pathptr == '~')
{ {
char *homedir = getenv("HOME"); char *homedir = getenv("HOME");
if (!strncmp(subCellDef->cd_file, homedir, strlen(homedir)) if (homedir && (!strncmp(subCellDef->cd_file, homedir,
&& (!strcmp(subCellDef->cd_file + strlen(homedir), strlen(homedir)) &&
pathptr + 1))) (!strcmp(subCellDef->cd_file + strlen(homedir),
pathptr + 1))))
pathOK = TRUE; pathOK = TRUE;
} }
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE; else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
@ -2254,9 +2255,9 @@ badTransform:
/* Check if the path is the same as the current directory */ /* Check if the path is the same as the current directory */
char *homedir = getenv("HOME"); char *homedir = getenv("HOME");
if (!strncmp(cwddir, homedir, strlen(homedir)) if (homedir && (!strncmp(cwddir, homedir, strlen(homedir))
&& (!strcmp(cwddir + strlen(homedir), && (!strcmp(cwddir + strlen(homedir),
pathptr + 1))) pathptr + 1))))
pathOK = TRUE; pathOK = TRUE;
} }
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE; else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;

View File

@ -830,7 +830,7 @@ drcTile (tile, dinfo, arg)
* an exception area. Exception rules are ignored if * an exception area. Exception rules are ignored if
* the edge is outside an exception area. * the edge is outside an exception area.
*/ */
if (!isinside && (!(cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0)) if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
continue; continue;
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0)) if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
continue; continue;

View File

@ -26,17 +26,19 @@ StipplePattern begin
/FontMatrix [1 0 0 1 0 0] def /FontMatrix [1 0 0 1 0 0] def
/FontBBox [0 0 1 1] def /FontBBox [0 0 1 1] def
/Encoding 256 array def /Encoding 256 array def
/PattName (P0) def /PattName (P000) def
/tmpStr 1 string def /tmpStr 3 string def
/NoPatt {<00>} def /NoPatt {<00>} def
0 1 255 { Encoding exch /NoPatt put } for 0 1 255 { Encoding exch /NoPatt put } for
/BuildChar { /BuildChar {
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load 1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def 64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
end end
/dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch /dp { StipplePattern begin
putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch dup 10 tmpStr cvrs /num exch def
store end } def PattName 1 num putinterval
PattName 0 num length 1 add getinterval cvn
dup Encoding exch 4 -1 roll exch put exch store end } def
/sf { findfont exch scalefont setfont } bind def /sf { findfont exch scalefont setfont } bind def
/sp { patterns setfont 2 setlinewidth } def /sp { patterns setfont 2 setlinewidth } def
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath /lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
@ -68,4 +70,3 @@ end
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox /tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
/h exch def /w exch def /y exch def /x exch def bx } def /h exch def /w exch def /y exch def /x exch def bx } def

View File

@ -1218,7 +1218,7 @@ PlotVersatec(scx, layers, xMask, user_scale)
/* Compute the name of the file to use for output, and open it. */ /* Compute the name of the file to use for output, and open it. */
sprintf(fileName, "%s/magicPlotXXXXXX", PlotTempDirectory); snprintf(fileName, 200, "%s/magicPlotXXXXXX", PlotTempDirectory);
result = mkstemp(fileName); result = mkstemp(fileName);
if (result == -1) if (result == -1)
{ {
@ -1474,7 +1474,7 @@ PlotVersatec(scx, layers, xMask, user_scale)
TxPrintf("\n"); TxPrintf("\n");
fclose(file); fclose(file);
sprintf(command, PlotVersCommand, PlotVersPrinter, fileName); snprintf(command, 300, PlotVersCommand, PlotVersPrinter, fileName);
if (system(command) != 0) if (system(command) != 0)
{ {
TxError("Couldn't execute spooler command to print \"%s\"\n", TxError("Couldn't execute spooler command to print \"%s\"\n",

View File

@ -48,7 +48,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
int xj, yj, direction; int xj, yj, direction;
resNode **PendingList; resNode **PendingList;
{ {
resNode *resptr; resNode *resptr = NULL;
resDevice *resDev; resDevice *resDev;
tElement *tcell; tElement *tcell;
int newnode; int newnode;
@ -64,7 +64,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
ri = (resInfo *) TiGetClientPTR(tp); ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList; resDev = ri->deviceList;
if ((ri->sourceEdge & direction) != 0) if ((((ri->sourceEdge & direction) != 0) && (resDev->rd_nterms == 4))
|| (resDev->rd_nterms > 2))
{ {
if (resDev->rd_fet_source == (resNode *) NULL) if (resDev->rd_fet_source == (resNode *) NULL)
{ {
@ -73,11 +74,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
resDev->rd_fet_source = resptr; resDev->rd_fet_source = resptr;
} }
else else
{
resptr = resDev->rd_fet_source; resptr = resDev->rd_fet_source;
}
} }
else else if (resDev->rd_nterms > 3)
{ {
if (resDev->rd_fet_drain == (resNode *) NULL) if (resDev->rd_fet_drain == (resNode *) NULL)
{ {
@ -86,9 +85,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
resDev->rd_fet_drain = resptr; resDev->rd_fet_drain = resptr;
} }
else else
{
resptr = resDev->rd_fet_drain; resptr = resDev->rd_fet_drain;
}
} }
if (newnode) if (newnode)
{ {
@ -99,7 +96,10 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
resptr->rn_te = tcell; resptr->rn_te = tcell;
ResAddToQueue(resptr, PendingList); ResAddToQueue(resptr, PendingList);
} }
NEWBREAK(resptr, tile, xj, yj, NULL); if (resptr != NULL)
{
NEWBREAK(resptr, tile, xj, yj, NULL);
}
} }
/* /*
@ -131,20 +131,14 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
ri = (resInfo *) TiGetClientPTR(tp); ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList; resDev = ri->deviceList;
/* Arrived at a device that has a terminal connected to substrate */ if (resDev->rd_fet_subs == (resNode *)NULL)
/* that is not a FET bulk terminal (e.g., varactor, diode). */
if (resDev->rd_nterms < 4) return;
if (resDev->rd_fet_subs == (resNode *) NULL)
{ {
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode))); resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
newnode = TRUE; newnode = TRUE;
resDev->rd_fet_subs = resptr; resDev->rd_fet_subs = resptr;
} }
else else
{ resptr = resDev->rd_fet_subs;
resptr = resDev->rd_fet_subs;
}
if (newnode) if (newnode)
{ {

View File

@ -148,30 +148,49 @@ void
ResDissolveContacts(contacts) ResDissolveContacts(contacts)
ResContactPoint *contacts; ResContactPoint *contacts;
{ {
TileType t, oldtype; TileType t, conttype;
Tile *tp; Tile *tp;
TileTypeBitMask residues; TileType residue[NP][NT];
int pNum;
bzero((char *)residue, NP * NT * sizeof(TileType));
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact) for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
{ {
oldtype=contacts->cp_type; conttype = contacts->cp_type;
#ifdef PARANOID #ifdef PARANOID
if (oldtype == TT_SPACE) if (conttype == TT_SPACE)
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode); TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
#endif #endif
DBFullResidueMask(oldtype, &residues);
DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype); /* Fill in details of the residue types for each contact type.
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++) * This is done only once per contact type. This could be refined
if (TTMaskHasType(&residues, t)) * further by temporarily changing the paint table directly or
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t); * creating a separate paint table which erases contact cuts and
* replaces them with the residues.
*/
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]); if (residue[DBPlane(conttype)][conttype] == TT_SPACE)
GOTOPOINT(tp, &(contacts->cp_rect.r_ll)); for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
residue[pNum][conttype] = DBPlaneToResidue(conttype, pNum);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (DBTypeOnPlane(conttype, pNum))
{
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
DBStdEraseTbl(conttype, pNum), (PaintUndoInfo *)NULL);
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
DBStdPaintTbl(residue[pNum][conttype], pNum),
(PaintUndoInfo *)NULL);
}
}
#ifdef PARANOID #ifdef PARANOID
if (TiGetTypeExact(tp) == contacts->cp_type) tp = PlaneGetHint(ResDef->cd_planes[DBPlane(conttype)]);
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
if (TiGetTypeExact(tp) == conttype)
TxError("Error in Contact Preprocess Routines\n"); TxError("Error in Contact Preprocess Routines\n");
#endif #endif
} }
@ -378,13 +397,14 @@ ResAddBreakpointFunc(tile, dinfo, node)
* *
* ResFindNewContactTiles -- * ResFindNewContactTiles --
* *
* Dissolving contacts eliminated the tiles that contacts->nextcontact
* pointed to. This procedure finds the tile now under center and sets
* that tile's ti_client field to point to the contact. The old value
* of clientdata is set to nextTilecontact.
* *
* Results: none * Results: none
* *
* Side Effects: dissolving contacts eliminated the tiles that * Side Effects: modifies information in the contact records.
* contacts->nextcontact pointed to. This procedure finds the tile now under
* center and sets that tile's ti_client field to point to the contact. The
* old value of clientdata is set to nextTilecontact.
* *
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
*/ */
@ -396,29 +416,40 @@ ResFindNewContactTiles(contacts)
int pNum; int pNum;
Tile *tile; Tile *tile;
TileTypeBitMask mask; TileTypeBitMask mask;
TileType lastType = TT_SPACE;
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact) for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
{ {
DBFullResidueMask(contacts->cp_type, &mask); /* Avoid re-running the following code for the same contact type */
if (contacts->cp_type != lastType)
/* Watch for types that connect to the substrate plane or well; */
/* e.g., psubstratepdiff connects to nwell but not through a */
/* contact. */
if (ExtCurStyle->exts_globSubstratePlane != -1)
{ {
TileTypeBitMask cMask; lastType = contacts->cp_type;
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type], DBFullResidueMask(contacts->cp_type, &mask);
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
if (!TTMaskIsZero(&cMask)) /* Watch for types that connect to the substrate plane or well; */
TTMaskSetMask(&mask, &cMask); /* e.g., psubstratepdiff connects to nwell but not through a */
/* contact. */
if (ExtCurStyle->exts_globSubstratePlane != -1)
{
TileTypeBitMask cMask;
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
if (!TTMaskIsZero(&cMask))
TTMaskSetMask(&mask, &cMask);
}
} }
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{ {
if (!DBTypeOnPlane(contacts->cp_type, pNum) &&
(pNum != ExtCurStyle->exts_globSubstratePlane))
continue;
tile = PlaneGetHint(ResDef->cd_planes[pNum]); tile = PlaneGetHint(ResDef->cd_planes[pNum]);
GOTOPOINT(tile, &(contacts->cp_center)); GOTOPOINT(tile, &(contacts->cp_center));
PlaneSetHint(ResDef->cd_planes[pNum], tile);
#ifdef PARANOID #ifdef PARANOID
if (tile == (Tile *) NULL) if (tile == (Tile *) NULL)
{ {
@ -476,10 +507,11 @@ ResFindNewContactTiles(contacts)
/* /*
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
* *
* ResProcessTiles--Calls ResEachTile with processed tiles belonging to * ResProcessTiles --
* nodes in ResNodeQueue. When all the tiles corresponding *
* to a node have been processed, the node is moved to * Calls ResEachTile with processed tiles belonging to nodes in ResNodeQueue.
* ResNodeList. * When all the tiles corresponding to a node have been processed, the node
* is moved to ResNodeList.
* *
* Results: Return 1 if any error occurred, 0 otherwise. * Results: Return 1 if any error occurred, 0 otherwise.
* *
@ -1381,6 +1413,7 @@ FindStartTile(resisdata, SourcePoint)
{ {
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
GOTOPOINT(tile, &workingPoint); GOTOPOINT(tile, &workingPoint);
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
SourcePoint->p_x = workingPoint.p_x; SourcePoint->p_x = workingPoint.p_x;
SourcePoint->p_y = workingPoint.p_y; SourcePoint->p_y = workingPoint.p_y;
@ -1414,6 +1447,7 @@ FindStartTile(resisdata, SourcePoint)
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
GOTOPOINT(tile, &workingPoint); GOTOPOINT(tile, &workingPoint);
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
if (IsSplit(tile)) if (IsSplit(tile))
{ {
@ -1765,6 +1799,7 @@ ResGetDevice(pt, type)
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]); tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
GOTOPOINT(tile, &workingPoint); GOTOPOINT(tile, &workingPoint);
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
const ClientData ticlient = TiGetClient(tile); const ClientData ticlient = TiGetClient(tile);
if (IsSplit(tile)) if (IsSplit(tile))

View File

@ -76,10 +76,9 @@ ResCalcTileResistance(tile, info, pendingList, doneList)
if (x < MinX) MinX = x; if (x < MinX) MinX = x;
if (y > MaxY) MaxY = y; if (y > MaxY) MaxY = y;
if (y < MinY) MinY = y; if (y < MinY) MinY = y;
if (p1->br_this->rn_why == RES_NODE_DEVICE) if (p1->br_this->rn_why == RES_NODE_DEVICE)
{
device = TRUE; device = TRUE;
}
} }
/* Finally, produce resistors for partition. Keep track of */ /* Finally, produce resistors for partition. Keep track of */
@ -125,7 +124,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
resNode **pendingList, **doneList; resNode **pendingList, **doneList;
resResistor **resList; resResistor **resList;
{ {
int height; int count, height;
bool merged; bool merged;
TileType ttype; TileType ttype;
Breakpoint *p1, *p2, *p3; Breakpoint *p1, *p2, *p3;
@ -134,6 +133,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
resNode *currNode; resNode *currNode;
float rArea; float rArea;
resInfo *info = (resInfo *)TiGetClientPTR(tile); resInfo *info = (resInfo *)TiGetClientPTR(tile);
HashTable BreakTable;
HashEntry *he;
merged = FALSE; merged = FALSE;
height = TOP(tile) - BOTTOM(tile); height = TOP(tile) - BOTTOM(tile);
@ -163,21 +164,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
ttype = TiGetTypeExact(tile); ttype = TiGetTypeExact(tile);
/* Re-sort nodes left to right. */ /* Re-sort nodes left to right. */
count = ResSortBreaks(&info->breakList, TRUE);
ResSortBreaks(&info->breakList, TRUE); /* For long lists (defined as >= 16 entries), make a hash table of
* the node pointer conversions so that each node can be updated
* as we walk the list, instead of walking the rest of the list in
* a nested loop for each entry.
*/
if (count >= 16)
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
/* /*
* Eliminate breakpoints with the same X coordinate and merge * Eliminate breakpoints with the same X coordinate and merge
* their nodes. * their nodes.
*/ */
p2= info->breakList; p2 = info->breakList;
/* Add extra left area to leftmost node */ /* Add extra left area to leftmost node */
p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile)); p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile));
while (p2->br_next != NULL) while (p2->br_next != NULL)
{ {
/* Has the node been recorded as needing to be replaced? */
if (count >= 16)
{
while (TRUE)
{
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
if (!he) break;
p2->br_this = (resNode *)HashGetValue(he);
}
}
p1 = p2; p1 = p2;
p2 = p2->br_next; p2 = p2->br_next;
if (p2->br_loc.p_x == p1->br_loc.p_x) if (p2->br_loc.p_x == p1->br_loc.p_x)
@ -215,25 +233,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
/* /*
* Was the node used in another info or breakpoint? * Was the node used in another info or breakpoint?
* If so, replace the old node with the new one. * If so, replace the old node with the new one.
*
* Short lists: Walk the list to the end and change
* nodes on the fly.
* Long lists: Record the change to be made in the
* hash table so that it can be executed as each list
* entry is encountered.
*/ */
if (count >= 16)
p3 = p2->br_next;
while (p3 != NULL)
{ {
if (p3->br_this == currNode) he = HashFind(&BreakTable, (char *)currNode);
p3->br_this = p2->br_this; HashSetValue(he, (char *)p2->br_this);
p3 = p3->br_next;
} }
} else
{
p3 = p2->br_next;
while (p3 != NULL)
{
if (p3->br_this == currNode)
p3->br_this = p2->br_this;
/* p3 = p3->br_next;
* If the X coordinates don't match, make a resistor between }
* the breakpoints. }
*/ }
else /*
{ * If the X coordinates don't match, make a resistor between
* the breakpoints.
*/
else
{
resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor)); resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor));
resistor->rr_nextResistor = (*resList); resistor->rr_nextResistor = (*resList);
resistor->rr_lastResistor = NULL; resistor->rr_lastResistor = NULL;
@ -276,6 +307,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
} }
} }
if (count >= 16) HashKill(&BreakTable);
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x); p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
freeMagic((char *)p2); freeMagic((char *)p2);
info->breakList = NULL; info->breakList = NULL;
@ -301,7 +334,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
resNode **pendingList, **doneList; resNode **pendingList, **doneList;
resResistor **resList; resResistor **resList;
{ {
int width; int count, width;
bool merged; bool merged;
TileType ttype; TileType ttype;
Breakpoint *p1, *p2, *p3; Breakpoint *p1, *p2, *p3;
@ -310,6 +343,8 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
resNode *currNode; resNode *currNode;
float rArea; float rArea;
resInfo *info = (resInfo *)TiGetClientPTR(tile); resInfo *info = (resInfo *)TiGetClientPTR(tile);
HashTable BreakTable;
HashEntry *he;
merged = FALSE; merged = FALSE;
width = RIGHT(tile) - LEFT(tile); width = RIGHT(tile) - LEFT(tile);
@ -329,7 +364,15 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
} }
/* Re-sort nodes south to north. */ /* Re-sort nodes south to north. */
ResSortBreaks(&info->breakList, FALSE); count = ResSortBreaks(&info->breakList, FALSE);
/* For long lists (defined as >= 16 entries), make a hash table of
* the node pointer conversions so that each node can be updated
* as we walk the list, instead of walking the rest of the list in
* a nested loop for each entry.
*/
if (count >= 16)
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
/* Simplified split tile handling */ /* Simplified split tile handling */
if (IsSplit(tile)) if (IsSplit(tile))
@ -353,51 +396,75 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile)); p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
while (p2->br_next != NULL) while (p2->br_next != NULL)
{ {
/* Has the node been recorded as needing to be replaced? */
if (count >= 16)
{
while (TRUE)
{
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
if (!he) break;
p2->br_this = (resNode *)HashGetValue(he);
}
}
p1 = p2; p1 = p2;
p2 = p2->br_next; p2 = p2->br_next;
if (p1->br_loc.p_y == p2->br_loc.p_y) if (p1->br_loc.p_y == p2->br_loc.p_y)
{ {
if (p2->br_this == p1->br_this) if (p2->br_this == p1->br_this)
{ {
currNode = NULL; currNode = NULL;
p1->br_next = p2->br_next; p1->br_next = p2->br_next;
freeMagic((char *)p2); freeMagic((char *)p2);
p2 = p1; p2 = p1;
} }
else if (p2->br_this == resCurrentNode) else if (p2->br_this == resCurrentNode)
{ {
currNode = p1->br_this; currNode = p1->br_this;
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
freeMagic((char *)p1); freeMagic((char *)p1);
merged = TRUE; merged = TRUE;
} }
else if (p1->br_this == resCurrentNode) else if (p1->br_this == resCurrentNode)
{ {
currNode = p2->br_this; currNode = p2->br_this;
p1->br_next = p2->br_next; p1->br_next = p2->br_next;
ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList); ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList);
merged = TRUE; merged = TRUE;
freeMagic((char *)p2); freeMagic((char *)p2);
p2 = p1; p2 = p1;
} }
else else
{ {
currNode = p1->br_this; currNode = p1->br_this;
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList); ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
freeMagic((char *)p1); freeMagic((char *)p1);
} }
/* /*
* Was the node used in another info or breakpoint? * Was the node used in another info or breakpoint?
* If so, replace the old node with the new one. * If so, replace the old node with the new one.
*
* Short lists: Walk the list to the end and change
* nodes on the fly.
* Long lists: Record the change to be made in the
* hash table so that it can be executed as each list
* entry is encountered.
*/ */
p3 = p2->br_next; if (count >= 16)
while (p3 != NULL)
{ {
if (p3->br_this == currNode) he = HashFind(&BreakTable, (char *)currNode);
p3->br_this = p2->br_this; HashSetValue(he, (char *)p2->br_this);
}
else
{
p3 = p2->br_next;
while (p3 != NULL)
{
if (p3->br_this == currNode)
p3->br_this = p2->br_this;
p3 = p3->br_next; p3 = p3->br_next;
}
} }
} }
@ -491,7 +558,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
* breakpoint, then return. * breakpoint, then return.
*/ */
if (info->breakList->br_next == NULL) if (info->breakList->br_next == NULL)
{ {
freeMagic((char *)info->breakList); freeMagic((char *)info->breakList);
info->breakList = NULL; info->breakList = NULL;
@ -525,7 +592,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
(devedge & TOPEDGE) == devedge || (devedge & TOPEDGE) == devedge ||
(devedge & BOTTOMEDGE) == devedge) (devedge & BOTTOMEDGE) == devedge)
{ {
ResSortBreaks(&info->breakList,TRUE); ResSortBreaks(&info->breakList, TRUE);
p2 = NULL; p2 = NULL;
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next) for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{ {
@ -919,21 +986,207 @@ ResDoContacts(contact, nodes, resList)
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* ResSortBreaks -- * BreakCompare --
*
* Helper routine for MergeSortBreaks() (below). Simple
* comparison of the breakpoint position. Comparison is
* done for the X position if "xsort" is TRUE, and the Y
* position if "xsort" is FALSE.
*
* Return value:
* Return -1 if the (x or y) position of a is less than the
* (x or y) position of b; return +1 if the position of a is
* greater than the position of b; and return 0 if they have
* equal positions.
*
* Side effect:
* None.
*
*-------------------------------------------------------------------------
*/
int
BreakCompare(
Breakpoint *a,
Breakpoint *b,
int xsort)
{
if (xsort == TRUE)
{
if (a->br_loc.p_x < b->br_loc.p_x) return -1;
if (a->br_loc.p_x > b->br_loc.p_x) return 1;
}
else
{
if (a->br_loc.p_y < b->br_loc.p_y) return -1;
if (a->br_loc.p_y > b->br_loc.p_y) return 1;
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* MergeSorted --
*
* Helper routine for MergeSortBreaks() (below). Merge sort
* merging routine.
*
*-------------------------------------------------------------------------
*/
Breakpoint *
MergeSorted(
Breakpoint *a,
Breakpoint *b,
int xsort)
{
Breakpoint head;
Breakpoint *tail = &head;
head.br_next = NULL;
while (a != NULL && b != NULL)
{
if (BreakCompare(a, b, xsort) <= 0)
{
tail->br_next = a;
a = a->br_next;
}
else
{
tail->br_next = b;
b = b->br_next;
}
tail = tail->br_next;
}
tail->br_next = (a != NULL) ? a : b;
return head.br_next;
}
/*
*-------------------------------------------------------------------------
*
* SplitList --
*
* Helper routine for MergeSortBreaks() (below). Merge sort
* splitting routine.
* *
* Results: * Results:
* None * None.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
void void
SplitList(
Breakpoint *source,
Breakpoint **front,
Breakpoint **back)
{
Breakpoint *slow;
Breakpoint *fast;
if (source == NULL || source->br_next == NULL)
{
*front = source;
*back = NULL;
return;
}
slow = source;
fast = source->br_next;
while (fast != NULL)
{
fast = fast->br_next;
if (fast != NULL)
{
slow = slow->br_next;
fast = fast->br_next;
}
}
*front = source;
*back = slow->br_next;
slow->br_next = NULL;
}
/*
*-------------------------------------------------------------------------
*
* MergeSortBreaks --
*
* See "ResSortBreaks" below. Alternative to bubble sort for long
* linked lists.
*
* Results:
* Pointer to a sorted breakpoint list.
*
* Side effects:
* The breakpoints are sorted.
*
*-------------------------------------------------------------------------
*/
Breakpoint *
MergeSortBreaks(Breakpoint *list, int xsort)
{
Breakpoint *a, *b;
if (list == NULL || list->br_next == NULL)
return list;
SplitList(list, &a, &b);
a = MergeSortBreaks(a, xsort);
b = MergeSortBreaks(b, xsort);
return MergeSorted(a, b, xsort);
}
/*
*-------------------------------------------------------------------------
*
* ResSortBreaks --
*
* Sort breakpoints, either in the X direction (if "xsort" is TRUE)
* or in the Y direction (if "xsort" is FALSE). For short lists
* (< 16 elements), a simple bubble sort is used. For larger lists,
* a merge sort is used. Most resistor networks are short, but
* power/ground networks can be huge and cause a performance
* bottleneck.
*
* Results:
* Return the length of the list (maximum truncated at 16) so that
* the calling routine can determine if this is a long or a short
* linked list and treat it accordingly.
*
*-------------------------------------------------------------------------
*/
int
ResSortBreaks(masterlist, xsort) ResSortBreaks(masterlist, xsort)
Breakpoint **masterlist; Breakpoint **masterlist;
int xsort; int xsort;
{ {
Breakpoint *p1, *p2, *p3, *p4; Breakpoint *p1, *p2, *p3, *p4;
bool changed; bool changed;
int count = 0;
for (p1 = *masterlist; p1; p1 = p1->br_next)
{
count++;
if (count > 16)
{
*masterlist = MergeSortBreaks(*masterlist, xsort);
return count;
}
}
/* Simple bubble sort */
changed = TRUE; changed = TRUE;
while (changed == TRUE) while (changed == TRUE)
@ -970,5 +1223,6 @@ ResSortBreaks(masterlist, xsort)
} }
} }
} }
return count;
} }

View File

@ -26,7 +26,6 @@ extern void ResEliminateResistor();
extern void ResCleanNode(); extern void ResCleanNode();
extern void ResFixBreakPoint(); extern void ResFixBreakPoint();
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -406,13 +405,70 @@ ResSeriesCheck(resptr)
int int
ResParallelCheck(resptr) ResParallelCheck(resptr)
resNode *resptr; resNode *resptr;
{ {
resResistor *r1,*r2; resResistor *r1, *r2;
resNode *resptr2,*resptr3; resNode *resptr2, *resptr3;
int status = UNTOUCHED; int status = UNTOUCHED;
resElement *rcell1, *rcell2; resElement *rcell1, *rcell2;
int rcount = 0;
/* When the number of resistors gets to be large enough, it is more efficient to
* sort the resistor list and then do a single pass to see if any two consecutive
* items in the sorted list can be merged, than to do a double loop through the
* resistor list at ~O(N^2).
*/
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
{
rcount++;
if (rcount >= 10) break;
}
if (rcount >= 10)
{
HashTable NodeResTable;
HashEntry *he;
/* Hash the connections */
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
{
/* One connection is always resptr; find the other one */
resptr3 = rcell2->re_thisEl->rr_connection1;
if (resptr3 == resptr) resptr3 = rcell2->re_thisEl->rr_connection2;
he = HashFind(&NodeResTable, (char *)resptr3);
if ((rcell1 = (resElement*)HashGetValue(he)))
{
r1 = rcell1->re_thisEl;
r2 = rcell2->re_thisEl;
if (TTMaskHasType(ResNoMergeMask+r1->rr_tt, r2->rr_tt)) continue;
ResFixParallel(r1, r2);
status = PARALLEL;
resptr2 = NULL;
if (resptr3->rn_status & RES_TRUE)
{
resptr2 = resptr3;
resptr2->rn_status &= ~RES_TRUE;
}
ResDoneWithNode(resptr);
if (resptr2 != NULL) ResDoneWithNode(resptr2);
break;
}
else
HashSetValue(he, (char *)rcell2);
}
HashKill(&NodeResTable);
return status;
}
/* This does the same thing as above, but for a small number of resistors
* per node, it avoids the overhead of creating and destroying hash tables.
*/
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL; for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
rcell1 = rcell1->re_nextEl) rcell1 = rcell1->re_nextEl)
@ -447,6 +503,7 @@ ResParallelCheck(resptr)
} }
if (status == PARALLEL) break; if (status == PARALLEL) break;
} }
return status; return status;
} }
@ -473,6 +530,179 @@ ResTriangleCheck(resptr)
float r1, r2, r3, denom; float r1, r2, r3, denom;
resNode *n1, *n2, *n3; resNode *n1, *n2, *n3;
resElement *rcell1, *rcell2, *rcell3, *element; resElement *rcell1, *rcell2, *rcell3, *element;
int rcount = 0;
/* When the size of the linked list of resistors is long, it is faster to
* hash the neighboring connections and then find the first entry in the
* neighbor's node list that is another neighbor.
*/
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
{
rcount++;
if (rcount >= 10) break;
}
if (rcount >= 10)
{
HashTable NodeResTable;
HashEntry *he, *he2;
HashSearch hs;
/* Hash the neighboring connections */
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
{
rr2 = rcell2->re_thisEl;
/* One connection is always resptr; find the other one */
n2 = rr2->rr_connection1;
if (n2 == resptr) n2 = rr2->rr_connection2;
he = HashFind(&NodeResTable, (char *)n2);
if (!(rcell1 = (resElement *)HashGetValue(he)))
HashSetValue(he, (char *)rcell2);
}
HashStartSearch(&hs);
while ((he = HashNext(&NodeResTable, &hs)))
{
/* Get each node that neighbors resptr */
n1 = (resNode *)he->h_key.h_ptr;
rcell1 = (resElement *)HashGetValue(he);
rr1 = rcell1->re_thisEl;
/* Check the list of resistors of neighbor n1 for any resistor whose
* other end is also a neighbor of resptr.
*/
for (rcell3 = n1->rn_re; rcell3 != NULL; rcell3 = rcell3->re_nextEl)
{
rr3 = rcell3->re_thisEl;
/* Resistor can't be merged */
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr3->rr_tt))
continue;
/* One connection is always n1; find the other one */
n2 = rr3->rr_connection1;
if (n2 == n1) n2 = rr3->rr_connection2;
he2 = HashLookOnly(&NodeResTable, (char *)n2);
if (he2)
{
/* Found a triangle */
rcell2 = (resElement *)HashGetValue(he2);
rr2 = rcell2->re_thisEl;
/* . . . But it can't be merged */
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt))
continue;
if (TTMaskHasType(ResNoMergeMask + rr2->rr_tt, rr3->rr_tt))
continue;
status = TRIANGLE;
if ((denom = rr1->rr_value + rr2->rr_value + rr3->rr_value) != 0.0)
{
denom = 1.0 /denom;
/* calculate new values for resistors */
r1 = (((float)rr1->rr_value) * ((float)rr2->rr_value)) * denom;
r2 = (((float)rr2->rr_value) * ((float)rr3->rr_value)) * denom;
r3 = (((float)rr1->rr_value) * ((float)rr3->rr_value)) * denom;
rr1->rr_value = r1 + 0.5;
rr2->rr_value = r2 + 0.5;
rr3->rr_value = r3 + 0.5;
ASSERT(rr1->rr_value >= 0, "Triangle");
ASSERT(rr2->rr_value >= 0, "Triangle");
ASSERT(rr3->rr_value >= 0, "Triangle");
}
else
{
rr1->rr_value = 0;
rr2->rr_value = 0;
rr3->rr_value = 0;
}
n3 = (resNode *)mallocMagic((unsigned)(sizeof(resNode)));
/* Where should the new node be put? It */
/* is arbitrarily assigned to the location */
/* occupied by the first node. */
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
n3->rn_less = NULL;
n3->rn_more = ResNodeList;
ResNodeList->rn_less = n3;
ResNodeList = n3;
if (resptr == rr1->rr_connection1)
{
ResDeleteResPointer(rr1->rr_connection2, rr1);
rr1->rr_connection2 = n3;
}
else
{
ResDeleteResPointer(rr1->rr_connection1, rr1);
rr1->rr_connection1 = n3;
}
if (n2 == rr2->rr_connection1)
{
ResDeleteResPointer(rr2->rr_connection2, rr2);
rr2->rr_connection2 = n3;
}
else
{
ResDeleteResPointer(rr2->rr_connection1, rr2);
rr2->rr_connection1 = n3;
}
if (n1 == rr3->rr_connection1)
{
ResDeleteResPointer(rr3->rr_connection2, rr3);
rr3->rr_connection2 = n3;
}
else
{
ResDeleteResPointer(rr3->rr_connection1, rr3);
rr3->rr_connection1 = n3;
}
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
element->re_nextEl = NULL;
element->re_thisEl = rr1;
n3->rn_re = element;
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
element->re_nextEl = n3->rn_re;
element->re_thisEl = rr2;
n3->rn_re = element;
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
element->re_nextEl = n3->rn_re;
element->re_thisEl = rr3;
n3->rn_re = element;
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
n1->rn_status &= ~RES_TRUE;
else
n1 = NULL;
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
n2->rn_status &= ~RES_TRUE;
else
n2 = NULL;
ResDoneWithNode(resptr);
if (n1 != NULL) ResDoneWithNode(n1);
if (n2 != NULL) ResDoneWithNode(n2);
break;
}
}
if (status == TRIANGLE) break;
}
HashKill(&NodeResTable);
return status;
}
/* This does the same thing as above, but for a small number of resistors
* per node, avoiding the overhead of creating and destroying hash tables.
*/
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL; for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
rcell1 = rcell1->re_nextEl) rcell1 = rcell1->re_nextEl)
@ -609,9 +839,9 @@ ResTriangleCheck(resptr)
* *
* ResMergeNodes-- * ResMergeNodes--
* *
* results: none * Results: none
* *
* side effects: appends all the cElement, jElement, tElement and * Side Effects: appends all the cElement, jElement, tElement and
* resElement structures from node 2 onto node 1. Node 2 is * resElement structures from node 2 onto node 1. Node 2 is
* then eliminated. * then eliminated.
* *
@ -780,7 +1010,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
* ResDeleteResPointer-- Deletes the pointer from a node to a resistor. * ResDeleteResPointer-- Deletes the pointer from a node to a resistor.
* Used when a resistor is deleted. * Used when a resistor is deleted.
* *
* Results:none * Results: none
* *
* Side Effects: Modifies a node's resistor list. * Side Effects: Modifies a node's resistor list.
* *
@ -788,7 +1018,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
*/ */
void void
ResDeleteResPointer(node,resistor) ResDeleteResPointer(node, resistor)
resNode *node; resNode *node;
resResistor *resistor; resResistor *resistor;
@ -829,7 +1059,7 @@ ResDeleteResPointer(node,resistor)
* *
* ResEliminateResistor-- * ResEliminateResistor--
* *
* Results:none * Results: none
* *
* Side Effects: Deletes a resistor. Does not delete pointers from nodes to * Side Effects: Deletes a resistor. Does not delete pointers from nodes to
* resistor. * resistor.
@ -867,8 +1097,7 @@ ResEliminateResistor(resistor, homelist)
* they are no longer needed. If the 'info' option is used, * they are no longer needed. If the 'info' option is used,
* the node is eradicated. * the node is eradicated.
* *
* Results: * Results: none.
* None.
* *
* Side Effects: frees memory * Side Effects: frees memory
* *

View File

@ -1356,7 +1356,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
} }
if (extDev->subs == extNode) if (extDev->subs == extNode)
{ {
if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL)) if ((subs = layoutDev->rd_fet_subs) != NULL)
{ {
if (subs->rn_name != NULL && notdecremented) if (subs->rn_name != NULL && notdecremented)
{ {
@ -1422,7 +1422,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
extNode->status |= DONTKILL; extNode->status |= DONTKILL;
} }
} }
else else if (layoutDev->rd_nterms > 3)
{ {
if ((source = layoutDev->rd_fet_source) != NULL) if ((source = layoutDev->rd_fet_source) != NULL)
{ {
@ -1469,7 +1469,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
} }
} }
} }
else if (extDev->drain == extNode) else if ((extDev->drain == extNode) && (layoutDev->rd_nterms > 3))
{ {
/* Check for devices with only one terminal. If it was cast as source, */ /* Check for devices with only one terminal. If it was cast as source, */
/* then swap it with the drain so that the code below handles it */ /* then swap it with the drain so that the code below handles it */

View File

@ -12,6 +12,7 @@
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */ #endif /* not lint */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> /* for qsort() */
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
@ -386,7 +387,7 @@ ResMoveDevices(node1, node2)
devptr = devptr->te_nextt; devptr = devptr->te_nextt;
if (device->rd_fet_gate == node1) if (device->rd_fet_gate == node1)
device->rd_fet_gate = node2; device->rd_fet_gate = node2;
else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1)) else if (device->rd_fet_subs == node1)
device->rd_fet_subs = node2; device->rd_fet_subs = node2;
else if (device->rd_fet_source == node1) else if (device->rd_fet_source == node1)
device->rd_fet_source = node2; device->rd_fet_source = node2;
@ -401,6 +402,29 @@ ResMoveDevices(node1, node2)
node1->rn_te = NULL; node1->rn_te = NULL;
} }
/*
*-------------------------------------------------------------------------
*
* qrescompare ---
*
* Sort routine for qsort() to be used by ResScrunchNet(). Sorts in
* order of the resistor value, smallest to largest.
*-------------------------------------------------------------------------
*/
int
qrescompare(const void *one, const void *two)
{
int cval;
resResistor *r1 = *((resResistor **)one);
resResistor *r2 = *((resResistor **)two);
if (r1->rr_value < r2->rr_value) return -1;
else if (r1->rr_value == r2->rr_value) return 0;
else return 1;
}
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -424,29 +448,82 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
float tolerance; float tolerance;
{ {
resResistor *locallist = NULL, *current, *working; resResistor *current, *working;
resNode *node1, *node2; resNode *node1, *node2;
resElement *rcell1; resElement *rcell1;
int c1, c2; int c1, c2, count = 0;
/* Sort resistors by size */ /* Method used to sort resistors by size depends on list length */
current = *reslist; for (current = *reslist; current; current = current->rr_nextResistor)
while (current != NULL)
{ {
working = current; count++;
current = current->rr_nextResistor; if (count >= 10) break;
if (working == *reslist) }
*reslist = current;
else /* Sort resistors by size */
working->rr_lastResistor->rr_nextResistor = current;
if (current != NULL) if (count >= 10)
current->rr_lastResistor = working->rr_lastResistor; {
int i;
resResistor **resSortList;
ResAddResistorToList(working, &locallist); /* For long lists, sort using qsort() */
/* NOTE: It might be better to use the same merge sort used for
* MergeSortBreaks() in ResMakeRes.c, as it does not incur the
* overhead of allocating memory and populating the array.
*/
count = 0;
for (current = *reslist; current; current = current->rr_nextResistor)
count++;
resSortList = (resResistor **)mallocMagic(count * sizeof(resResistor *));
count = 0;
for (current = *reslist; current; current = current->rr_nextResistor)
{
resSortList[count] = current;
count++;
}
/* Sort the list */
qsort(resSortList, count, sizeof(resResistor *), qrescompare);
/* Regenerate links on sorted list */
for (i = 0; i < count; i++)
{
current = resSortList[i];
current->rr_nextResistor = (i == count - 1) ? NULL : resSortList[i + 1];
current->rr_lastResistor = (i == 0) ? NULL : resSortList[i - 1];
}
*reslist = resSortList[0];
freeMagic(resSortList);
}
else
{
/* Original method: Walk the linked list and re-sort by size. */
resResistor *locallist = NULL;
current = *reslist;
while (current != NULL)
{
working = current;
current = current->rr_nextResistor;
if (working == *reslist)
*reslist = current;
else
working->rr_lastResistor->rr_nextResistor = current;
if (current != NULL)
current->rr_lastResistor = working->rr_lastResistor;
ResAddResistorToList(working, &locallist);
}
*reslist = locallist;
} }
*reslist = locallist;
while (*reslist != NULL && (*reslist)->rr_value < tolerance) while (*reslist != NULL && (*reslist)->rr_value < tolerance)
{ {
current = *reslist; current = *reslist;
@ -501,8 +578,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
} }
} }
/* /*
* If the current resistor isn't a deadend, add its value and * If the current resistor isn't a dead end, add its value and
* area to that of the next smallest one. If it is a deadend, * area to that of the next smallest one. If it is a dead end,
* simply add its area to its node. * simply add its area to its node.
*/ */
if (c1 != 0 && c2 != 0) if (c1 != 0 && c2 != 0)
@ -567,7 +644,7 @@ ResAddResistorToList(resistor, locallist)
resResistor *resistor, **locallist; resResistor *resistor, **locallist;
{ {
resResistor *local,*last=NULL; resResistor *local, *last = NULL;
for (local = *locallist; local != NULL; local = local->rr_nextResistor) for (local = *locallist; local != NULL; local = local->rr_nextResistor)
{ {

View File

@ -231,7 +231,8 @@ ResAddPlumbing(tile, dinfo, arg)
resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice))); resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice)));
resDev->rd_nterms = nterms; resDev->rd_nterms = nterms;
resDev->rd_terminals = (resNode **) mallocMagic(nterms * sizeof(resNode *));
resDev->rd_terminals = (resNode **)mallocMagic(nterms * sizeof(resNode *));
for (i = 0; i != nterms; i++) for (i = 0; i != nterms; i++)
resDev->rd_terminals[i] = (resNode *) NULL; resDev->rd_terminals[i] = (resNode *) NULL;
@ -733,6 +734,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
tile = PlaneGetHint(Def->cd_planes[pNum]); tile = PlaneGetHint(Def->cd_planes[pNum]);
GOTOPOINT(tile, &(TileList->area.r_ll)); GOTOPOINT(tile, &(TileList->area.r_ll));
PlaneSetHint(Def->cd_planes[pNum], tile);
tt = TiGetType(tile); tt = TiGetType(tile);
tstruct = (resInfo *) TiGetClientPTR(tile); tstruct = (resInfo *) TiGetClientPTR(tile);

View File

@ -51,16 +51,24 @@ typedef struct resistor
#define rr_connection1 rr_node[0] #define rr_connection1 rr_node[0]
#define rr_connection2 rr_node[1] #define rr_connection2 rr_node[1]
/* Definitions for old FET-style MOSFET devices */ /* Definitions for old FET-style MOSFET devices. Actual devices may have
* any number of terminals. "GATE" is the identifying type; "SUBS" is
* the substrate/well connection (if it exists), and the other terminals
* make up the remaining entries. Memory will be allocated for the
* substrate whether or not one is defined for the device. If the device
* does not define a substrate connection, then this entry will remain
* NULL.
*/
#define RT_GATE 0 #define RT_GATE 0
#define RT_SOURCE 1 #define RT_SUBS 1
#define RT_DRAIN 2 #define RT_SOURCE 2
#define RT_SUBS 3 #define RT_DRAIN 3
#define rd_fet_gate rd_terminals[RT_GATE] #define rd_fet_gate rd_terminals[RT_GATE]
#define rd_fet_subs rd_terminals[RT_SUBS]
#define rd_fet_source rd_terminals[RT_SOURCE] #define rd_fet_source rd_terminals[RT_SOURCE]
#define rd_fet_drain rd_terminals[RT_DRAIN] #define rd_fet_drain rd_terminals[RT_DRAIN]
#define rd_fet_subs rd_terminals[RT_SUBS]
typedef struct device typedef struct device
{ {
@ -543,7 +551,7 @@ extern void ResCheckExtNodes();
extern void ResSortByGate(); extern void ResSortByGate();
extern void ResFixDevName(); extern void ResFixDevName();
extern void ResWriteLumpFile(); extern void ResWriteLumpFile();
extern void ResSortBreaks(); extern int ResSortBreaks();
extern Plane *extResPrepSubstrate(); extern Plane *extResPrepSubstrate();
/* C99 compat */ /* C99 compat */

View File

@ -471,12 +471,11 @@ SelectArea(scx, types, xMask, globmatch)
if (TTMaskHasType(types, L_LABEL)) if (TTMaskHasType(types, L_LABEL))
{ {
if (globmatch != NULL) if (globmatch != NULL)
DBCellCopyGlobLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea, DBCellCopyGlobLabels(scx, types, xMask, SelectUse, &labelArea,
globmatch); globmatch);
else else
DBCellCopyAllLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea); DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
} }
else (void) DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
/* Select cell uses. */ /* Select cell uses. */
@ -835,6 +834,8 @@ chunkdone:
if (DBIsContact(type)) if (DBIsContact(type))
TTMaskSetOnlyType(&typeMask, type); TTMaskSetOnlyType(&typeMask, type);
/* Allow labels to be selected as part of the chunk */
TTMaskSetType(&typeMask, L_LABEL);
SelectArea(&newscx, &typeMask, xMask, NULL); SelectArea(&newscx, &typeMask, xMask, NULL);
} }

View File

@ -93,7 +93,7 @@ SimConnectFunc(
TileType loctype, ctype; TileType loctype, ctype;
TileType newdinfo = 0; TileType newdinfo = 0;
int i, pNum; int i, pNum;
static char nodeName[256]; static char nodeName[MAXPATHNAME];
CellDef *def; CellDef *def;
TerminalPath *tpath = cx->tc_filter->tf_tpath; TerminalPath *tpath = cx->tc_filter->tf_tpath;
@ -133,7 +133,8 @@ SimConnectFunc(
char c = *n; char c = *n;
SigDisableInterrupts(); SigDisableInterrupts();
strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first)); strncpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first),
MAXPATHNAME);
SigEnableInterrupts(); SigEnableInterrupts();
*n = c; *n = c;

View File

@ -35,10 +35,10 @@ proc magic::libcallback {command} {
switch $command { switch $command {
load {$winname load $celldef} load {$winname load $celldef}
place {$winname getcell $celldef} place {$winname getcell $celldef child 0 0}
pick { pick {
magic::tool pick magic::tool pick
$winname getcell $celldef $winname getcell $celldef child 0 0
magic::startselect $winname pick magic::startselect $winname pick
} }
} }

View File

@ -1,70 +0,0 @@
%%BeginProlog
%
% PostScript prolog for output from magic plot
% Version: 1.0
% written by Tim Edwards 4/05/00 JHU Applied Physics Laboratory
%
%%BeginResource: procset MAGICproc 1.0 1
% supporting definitions
/MAGICsave save def
/bop { 1 setlinecap 0 setlinejoin 6 setmiterlimit 0 setgray } def
/ninit { /nChars matrix currentmatrix dup 0 get 0 eq {1} {0}
ifelse get abs 72 8.5 mul mul 64 div ceiling cvi def } def
/minit { 1 1 dtransform abs dup 1 exch div /onePix exch def
dup /resY exch def 1 exch div /iresY exch def
abs dup /resX exch def 1 exch div /iresX exch def
/bX 64 iresX mul def /bY 64 iresY mul def
/pattFont StipplePattern definefont pop
/patterns /pattFont findfont [iresX 64 mul 0 0 iresY 64 mul 0 0] makefont def
/ca nChars 1 add string def
} def
/StipplePattern 45 dict def
StipplePattern begin
/FontType 3 def
/FontMatrix [1 0 0 1 0 0] def
/FontBBox [0 0 1 1] def
/Encoding 256 array def
/PattName (P0) def
/tmpStr 1 string def
/NoPatt {<00>} def
0 1 255 { Encoding exch /NoPatt put } for
/BuildChar {
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
end
/dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch
putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch
store end } def
/sf { findfont exch scalefont setfont } bind def
/sp { patterns setfont 2 setlinewidth } def
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
flattenpath pathbbox grestore exch 4 -1 roll exch sub 3 1 roll sub
just 4 and 0 gt {just 8 and 0 eq {0.5 mul} if}{pop 0} ifelse exch
just 1 and 0 gt {just 2 and 0 eq {0.5 mul} if}{pop 0} ifelse exch
rmoveto show grestore } def
/sl { 0 1 nChars { exch dup 3 1 roll ca 3 1 roll put } for pop } def
/sc { setcmykcolor } bind def
/l1 { onePix setlinewidth } def
/l2 { onePix 2 mul setlinewidth } def
/l3 { onePix 3 mul setlinewidth } def
/ml { moveto lineto stroke } bind def
/vl { moveto 0 exch rlineto stroke } bind def
/hl { moveto 0 rlineto stroke } bind def
/mr { rectstroke } bind def
/mx { 4 copy rectstroke 4 -1 roll 4 -1 roll 4 copy moveto rlineto stroke
3 -1 roll dup neg 4 1 roll add moveto rlineto stroke } bind def
/pl { gsave translate /d exch def 0 d neg moveto 0 d lineto stroke
d neg 0 moveto d 0 lineto stroke grestore } bind def
/bx { x resX mul cvi 63 not and dup iresX mul exch
w resX mul sub abs 63 add cvi 64 idiv /w exch def
y resY mul cvi 63 not and dup iresY mul exch
h resY mul sub abs 63 add cvi 64 idiv /h exch def
/ch ca 0 w getinterval def
moveto h { ch gsave show grestore 0 bY rmoveto } repeat grestore } def
/fb {/h exch def /w exch def /y exch def /x exch def gsave newpath
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
/h exch def /w exch def /y exch def /x exch def bx } def

View File

@ -249,6 +249,9 @@ proc ::tkcon::Init {} {
if {![info exists PRIV(histfile)]} { if {![info exists PRIV(histfile)]} {
set PRIV(histfile) [file join $env($envHome) $histfile] set PRIV(histfile) [file join $env($envHome) $histfile]
} }
} else {
set PRIV(rcfile) ""
set PRIV(histfile) ""
} }
## Handle command line arguments before sourcing resource file to ## Handle command line arguments before sourcing resource file to

View File

@ -651,9 +651,9 @@ proc magic::startselect {window {option {}}} {
select nocycle select nocycle
} }
} }
set Opts(origin) [cursor] set Opts(origin) [cursor internal]
set Opts(motion) [bind ${window} <Motion>] set Opts(motion) [bind ${window} <Motion>]
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor\]; \ bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor internal\]; \
set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \ set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \
set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \ set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \
*bypass select move \${x} \${y}}] *bypass select move \${x} \${y}}]

View File

@ -21,6 +21,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */ #endif /* not lint */
#include <stdio.h> #include <stdio.h>
#include <ctype.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/utils.h" #include "utils/utils.h"
@ -34,12 +35,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* ArgStr -- * ArgStr --
* *
* Process a single argument that is supposed to have a string value. * Process a single argument that is supposed to have a string value.
* A string argument can appear in two ways: * A string argument can appear in three ways:
* *
* -avalue (a single element of argv) * -avalue (a single element of argv)
* -a value (two elements of argv) * -a value (two elements of argv)
* "-a value" (a single element of argv, space-separated)
* *
* Both are recognized. * All three forms are recognized.
* *
* Results: * Results:
* Returns a pointer to the value, or NULL if there wasn't one. * Returns a pointer to the value, or NULL if there wasn't one.
@ -56,15 +58,29 @@ char *
ArgStr( ArgStr(
int *pargc, int *pargc,
char ***pargv, char ***pargv,
const char *argType)/* For error messages: what the following string is const char *argType) /* For error messages: what the following
* supposed to be interpreted as. * string is supposed to be interpreted as.
*/ */
{ {
char **argv = *pargv; char **argv = *pargv;
char *result; char *result;
char *argptr;
if (argv[0][2]) argptr = argv[0];
return (&argv[0][2]); argptr++;
if (*argptr == '\0')
{
TxError("Bad argument %s\n", argv[0]);
return NULL;
}
argptr++;
if (*argptr != '\0')
{
while (isspace(*argptr) && (*argptr != '\0'))
argptr++;
return argptr;
}
if ((*pargc)-- > 0) if ((*pargc)-- > 0)
{ {
@ -74,5 +90,5 @@ ArgStr(
} }
TxError("-%c requires a following %s\n", argv[0][1], argType); TxError("-%c requires a following %s\n", argv[0][1], argType);
return (NULL); return NULL;
} }

View File

@ -988,7 +988,8 @@ mainInitFinal()
} }
} }
if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/')) if (getcwd(cwd, 512) == NULL || ((home != NULL) && (strcmp(cwd, home)))
|| (RCFileName[0] == '/'))
{ {
/* Read in the .magicrc file from the current directory, if */ /* Read in the .magicrc file from the current directory, if */
/* different from HOME. */ /* different from HOME. */