2
* Electric(tm) VLSI Design System
5
* Database text and file support module
6
* Written by: Steven M. Rubin, Static Free Software
8
* Copyright (c) 2000 Static Free Software.
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* Static Free Software
27
* Portola Valley, California 94028
28
* info@staticfreesoft.com
33
#include "egraphics.h"
39
# include <sys/time.h>
42
#define NUMDESCRIPTIONBUFS 4
44
static char *db_keywordbuffer;
45
static INTBIG db_keywordbufferlength = 0;
47
/* working memory for "db_tryfile()" */
48
static char *db_tryfilename;
49
static INTBIG db_tryfilenamelen = 0;
51
/* working memory for "describenodeproto()" */
52
static INTBIG db_descnpnodeswitch = 0;
53
static char *db_descnpoutput[NUMDESCRIPTIONBUFS];
54
static INTBIG db_descnpoutputsize[NUMDESCRIPTIONBUFS] = {0, 0};
56
/* working memory for "describenodeinst()" */
57
static INTBIG db_descninodeswitch = 0;
58
static char *db_descnioutput[NUMDESCRIPTIONBUFS];
59
static INTBIG db_descnioutputsize[NUMDESCRIPTIONBUFS] = {0, 0};
61
/* working memory for "describearcinst()" */
62
static INTBIG db_descaiarcswitch = 0;
63
static char *db_descaioutput[NUMDESCRIPTIONBUFS];
64
static INTBIG db_descaioutputsize[NUMDESCRIPTIONBUFS] = {0, 0};
66
/* working memory for "describearcproto()" */
67
static INTBIG db_descaparcswitch = 0;
68
static char *db_descapoutput[NUMDESCRIPTIONBUFS];
69
static INTBIG db_descapoutputsize[NUMDESCRIPTIONBUFS] = {0, 0};
71
/* working memory for "makeplural()" */
72
static INTBIG db_pluralbufsize = 0;
73
static char *db_pluralbuffer;
75
/* working memory for types of files */
86
static INTBIG db_filetypecount = 0;
87
static FILETYPES *db_filetypeinfo;
89
/* the infinite string package */
90
#define INFSTRCOUNT 8 /* number of infinite strings */
91
#define INFSTRDEFAULT 200 /* default infinite string length */
92
#define NOINFSTR ((INFSTR *)-1)
95
char *infstr; /* the string address */
96
INTBIG infstrlength; /* the length of the string */
97
INTBIG infstrptr; /* the location of the string end */
98
INTBIG infstrinuse; /* nonzero if in use */
101
static INFSTR db_infstrings[INFSTRCOUNT]; /* a stack of infinite strings */
102
static INFSTR *db_infstrstackptr[INFSTRCOUNT];/* a stack of infinite strings */
103
static INFSTR *db_curinf = NOINFSTR; /* the current infinite string */
104
static INTBIG db_infstrpointer; /* base position of the stack in the list */
105
static INTBIG db_infstrstackpos; /* position within the stack */
106
static BOOLEAN db_firstinf = FALSE; /* initialization flag */
108
/* prototypes for local routines */
109
static BOOLEAN db_beginsearch(char**);
110
static BOOLEAN db_makestringvar(INTBIG, INTBIG, INTBIG);
111
static BOOLEAN db_addstring(char*);
112
static FILE *db_tryfile(char*, char*, char*, char*, char**);
113
static void db_shuffle(char*, char*);
114
static INTBIG db_insensitivechar(INTBIG c);
117
* Routine to free all memory associated with this module.
119
void db_freetextmemory(void)
123
if (db_pluralbufsize > 0) efree(db_pluralbuffer);
124
if (db_keywordbufferlength != 0) efree(db_keywordbuffer);
125
if (db_tryfilenamelen != 0) efree(db_tryfilename);
126
for(i=0; i<INFSTRCOUNT; i++)
127
efree((char *)db_infstrings[i].infstr);
129
for(i=0; i<NUMDESCRIPTIONBUFS; i++)
130
if (db_descnpoutputsize[i] != 0) efree(db_descnpoutput[i]);
131
for(i=0; i<NUMDESCRIPTIONBUFS; i++)
132
if (db_descnioutputsize[i] != 0) efree(db_descnioutput[i]);
133
for(i=0; i<NUMDESCRIPTIONBUFS; i++)
134
if (db_descaioutputsize[i] != 0) efree(db_descaioutput[i]);
135
for(i=0; i<NUMDESCRIPTIONBUFS; i++)
136
if (db_descapoutputsize[i] != 0) efree(db_descapoutput[i]);
138
/* free file type memory */
139
for(i=0; i<db_filetypecount; i++)
141
efree((char *)db_filetypeinfo[i].extension);
142
efree((char *)db_filetypeinfo[i].winfilter);
143
efree((char *)db_filetypeinfo[i].shortname);
144
efree((char *)db_filetypeinfo[i].longname);
146
if (db_filetypecount > 0) efree((char *)db_filetypeinfo);
149
/************************* STRING PARSING *************************/
152
* routine to parse a lambda value of the form "nn.dd[u | " | cm | hmm | mm]"
153
* where the unlabeled number defaults to the current DISPLAYUNITS of the
154
* current technology but trailing letters can override. The input is in
157
INTBIG atola(char *pp)
159
REGISTER INTBIG hipart, lonum, loden, retval, units;
164
/* determine default scale amount */
167
if (*ptr == '-') { neg = -1; ptr++; } else neg = 1;
169
while (isdigit(*ptr)) ptr++;
170
lonum = 0; loden = 1;
174
while (isdigit(*ptr)) { lonum = lonum * 10 + (*ptr++ - '0'); loden *= 10; }
177
/* determine units */
179
if (ptr[0] == '"') units = (units & ~DISPLAYUNITS) | DISPUNITINCH; else
180
if (ptr[0] == 'c' && ptr[1] == 'm') units = (units & ~DISPLAYUNITS) | DISPUNITCM; else
181
if (ptr[0] == 'm' && ptr[1] == 'm') units = (units & ~DISPLAYUNITS) | DISPUNITMM;
182
if (ptr[0] == 'm' && ptr[1] == 'i' && ptr[2] == 'l') units = (units & ~DISPLAYUNITS) | DISPUNITMIL;
183
if (ptr[0] == 'u') units = (units & ~DISPLAYUNITS) | DISPUNITMIC; else
184
if (ptr[0] == 'c' && ptr[1] == 'u') units = (units & ~DISPLAYUNITS) | DISPUNITCMIC; else
185
if (ptr[0] == 'm' && ptr[1] == 'u') units = (units & ~DISPLAYUNITS) | DISPUNITMMIC;
187
/* convert to database units */
188
scale = db_getcurrentscale(el_units&INTERNALUNITS, units);
189
retval = rounddouble(((double)hipart) * scale + ((double)lonum)*scale / ((double)loden));
194
* routine to parse a fixed point value of the form "n.d" where
195
* "d" is evaluated to the nearest 120th (the value of WHOLE).
196
* The number is returned scaled by a factor of WHOLE. The input is in
199
INTBIG atofr(char *pp)
201
REGISTER INTBIG i, j, k;
204
if (*pp == '-') { n = -1; pp++; } else n = 1;
205
i = atoi(pp) * WHOLE;
206
while (isdigit(*pp)) pp++;
207
if (*pp++ != '.') return(i*n);
209
while (isdigit(*pp)) { j = j * 10 + (*pp++ - '0'); k *= 10; }
210
i += (j*WHOLE + k/2)/k;
214
/* routine to convert ascii to integer */
215
INTBIG myatoi(char *pp)
218
REGISTER INTBIG base, sign;
240
if ((*pp >= 'a' && *pp <= 'f') || (*pp >= 'A' && *pp <= 'F'))
242
if (base != 16) break;
244
if (*pp >= 'a' && *pp <= 'f') num += *pp++ - 'a' + 10; else
245
num += *pp++ - 'A' + 10;
247
} else if (isdigit(*pp))
249
if (*pp >= '8' && base == 8) break;
250
num = num * base + *pp++ - '0';
259
* Routine to convert a HUGE integer (64 bits) to a string.
260
* This routine does the work by hand, but it can be done with
261
* special "printf" format conversions, of which these are known:
266
char *hugeinttoa(INTHUGE a)
268
static char ret[NUMDESCRIPTIONBUFS][40];
269
static INTBIG which = 0;
270
REGISTER char *curbuf, digit;
271
REGISTER INTBIG i, neg;
273
curbuf = ret[which++];
274
if (which >= NUMDESCRIPTIONBUFS) which = 0;
276
if (a >= 0) neg = 0; else
285
digit = (char)(a % 10);
286
curbuf[--i] = '0' + digit;
295
char *explainduration(float duration)
297
static char elapsed[200];
299
INTBIG hours, minutes;
302
if (duration >= 3600.0)
304
hours = (INTBIG)(duration / 3600.0f);
305
duration -= (float)(hours * 3600);
306
sprintf(temp, "%ld hours, ", hours);
307
strcat(elapsed, temp);
309
if (duration >= 60.0)
311
minutes = (INTBIG)(duration / 60.0f);
312
duration -= (float)(minutes * 60);
313
sprintf(temp, "%ld minutes, ", minutes);
314
strcat(elapsed, temp);
316
sprintf(temp, "%g seconds", duration);
317
strcat(elapsed, temp);
322
* Routine to parse the version of Electric in "version" into three fields:
323
* the major version number, minor version, and a detail version number.
324
* The detail version number can be letters. If it is omitted, it is
325
* assumed to be 999. If it is a number, it is beyond 1000. For example:
326
* "6.02a" major=6, minor=2, detail=1 (a Prerelease)
327
* "6.02z" major=6, minor=2, detail=26 (a Prerelease)
328
* "6.02aa" major=6, minor=2, detail=27 (a Prerelease)
329
* "6.02az" major=6, minor=2, detail=52 (a Prerelease)
330
* "6.02ba" major=6, minor=2, detail=53 (a Prerelease)
331
* "6.02" major=6, minor=2, detail=999 (a Release)
332
* "6.02.1" major=6, minor=2, detail=1001 (a PostRelease, update)
334
void parseelectricversion(char *version, INTBIG *major, INTBIG *minor, INTBIG *detail)
338
/* parse the version fields */
341
while (isdigit(*pt) != 0) pt++;
342
if (*pt++ != '.') { *minor = *detail = 0; return; }
344
while (isdigit(*pt) != 0) pt++;
345
if (*pt == 0) { *detail = 999; return; }
348
*detail = atoi(&pt[1]) + 1000;
354
*detail = (*detail * 26) + tolower(*pt) - 'a' + 1;
358
#if 0 /* for debugging the version number */
359
ttyputmsg("Version '%s' is numbered %ld.%ld.%ld", version, *major, *minor, *detail);
364
* routine to determine which node prototype is referred to by "line"
365
* and return that nodeproto. The routine returns NONODEPROTO if the
366
* prototype cannot be determined.
368
NODEPROTO *getnodeproto(char *initline)
370
REGISTER NODEPROTO *np, *onp;
372
REGISTER TECHNOLOGY *tech, *t;
373
REGISTER INTBIG wantversion, save, saidtech, saidlib;
374
REGISTER LIBRARY *lib, *l;
375
REGISTER VIEW *wantview, *v;
376
REGISTER char *pt, *line;
378
/* make a copy of the argument so that it can be modified */
380
(void)addstringtoinfstr(initline);
381
line = returninfstr();
383
tech = el_curtech; lib = el_curlib;
384
saidtech = saidlib = 0;
385
for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
386
if (*pt != ':') pt = line; else
389
t = gettechnology(line);
390
if (t != NOTECHNOLOGY)
395
l = getlibrary(line);
405
/* try primitives in the technology */
406
if (saidlib == 0 || saidtech != 0)
408
for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
409
if (namesame(line, np->primname) == 0) return(np);
412
/* look for version numbers and view types */
413
for(pt = line; *pt != 0; pt++) if (*pt == ';' || *pt == '{') break;
417
c = db_findcellname(line, lib);
419
for(c = lib->firstcell; c != NOCELL; c = c->nextcell)
420
if (namesame(line, c->cellname) == 0) break;
423
if (c == NOCELL) return(NONODEPROTO);
426
wantview = el_unknownview;
429
wantversion = myatoi(pt+1);
430
for(pt++; *pt != 0; pt++) if (*pt == '{') break;
435
line = pt = (pt + 1);
436
for(; *pt != 0; pt++) if (*pt == '}') break;
437
if (*pt != '}') return(NONODEPROTO);
439
for(v = el_views; v != NOVIEW; v = v->nextview)
440
if (namesame(v->sviewname, line) == 0 || namesame(v->viewname, line) == 0) break;
442
if (v == NOVIEW) return(NONODEPROTO);
446
/* find desired view of facet */
447
for(np = c->firstincell; np != NONODEPROTO; np = np->nextincell)
448
if (np->cellview == wantview) break;
449
if (np == NONODEPROTO && wantview == el_unknownview)
451
/* if a version number was specified, let that guide the search */
454
for(np = c->firstincell; np != NONODEPROTO; np = np->nextincell)
456
for(onp = np->lastversion; onp != NONODEPROTO; onp = onp->lastversion)
457
if (onp->version == wantversion) return(onp);
461
/* first find a layout or schematic view */
462
for(np = c->firstincell; np != NONODEPROTO; np = np->nextincell)
463
if (np->cellview == el_layoutview || np->cellview == el_schematicview) return(np);
467
if (np == NONODEPROTO) return(NONODEPROTO);
470
/* get desired version */
471
if (wantversion < 0) return(np);
472
for(np = np->lastversion; np != NONODEPROTO; np = np->lastversion)
473
if (np->version == wantversion) return(np);
478
* routine to find cell "cellname". Returns NOCELL if it cannot be found
480
CELL *getcell(char *cellname)
484
cell = db_findcellname(cellname, el_curlib);
487
static COMCOMP db_cellp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
488
NOBACKUP, 0, " \t", M_("cell"), 0};
489
REGISTER INTBIG i, j;
491
i = parse(cellname, &db_cellp, FALSE);
492
if (i < 0) return(NOCELL);
493
for(j=0, cell = el_curlib->firstcell; cell != NOCELL; cell = cell->nextcell, j++)
494
if (j == i) return(cell);
500
* routine to find technology "techname". Returns NOTECHNOLOGY if it cannot
503
static COMCOMP db_technologyp = {NOKEYWORD, topoftechs, nexttechs, NOPARAMS,
504
NOBACKUP, 0, " \t", M_("technology"), 0};
505
TECHNOLOGY *gettechnology(char *techname)
508
REGISTER TECHNOLOGY *tech;
510
i = parse(techname, &db_technologyp, FALSE);
511
if (i < 0) return(NOTECHNOLOGY);
512
for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
513
if (tech->techindex == i) return(tech);
514
return(NOTECHNOLOGY);
518
* routine to find view "viewname". Returns NOVIEW if it cannot be found
520
static COMCOMP db_viewp = {NOKEYWORD, topofviews, nextviews, NOPARAMS,
521
NOBACKUP, 0, " \t", M_("view"), 0};
522
VIEW *getview(char *viewname)
524
REGISTER INTBIG i, j;
527
i = parse(viewname, &db_viewp, FALSE);
528
if (i < 0) return(NOVIEW);
529
for(j=0, v = el_views; v != NOVIEW; v = v->nextview, j++)
530
if (j == i) return(v);
535
* routine to find network "netname" in facet "facet". Returns NONETWORK
536
* if it cannot be found
538
NETWORK *getnetwork(char *netname, NODEPROTO *facet)
540
REGISTER INTBIG i, k;
542
REGISTER NETWORK *net;
544
for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
547
for(k=0; k<net->namecount; k++)
549
if (namesame(netname, pt) == 0) return(net);
550
pt += strlen(pt) + 1;
554
/* see if a global name is specified */
557
if (namesamen(netname, pt, k) == 0 && netname[k] == '-')
559
for(i=0; i<facet->globalnetcount; i++)
560
if (namesame(&netname[k+1], facet->globalnetnames[i]) == 0)
561
return(facet->globalnetworks[i]);
567
* routine to find network "netname" in facet "facet". Returns NONETWORK
568
* if it cannot be found. This routine allows for variations of the network
569
* name that may occur due to simulation, VHDL compilation, etc.
571
NETWORK *getcomplexnetwork(char *name, NODEPROTO *np)
573
REGISTER INTBIG len, i, l, k, c1, c2, addr;
574
REGISTER NETWORK *net;
577
/* try the direct approach */
578
net = getnetwork(name, np);
579
if (net != NONETWORK) return(net);
581
if (name[0] == 'N' && name[1] == 'E' && name[2] == 'T')
583
addr = atoi(&name[3]);
584
for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
585
if (net == (NETWORK *)addr) return(net);
588
/* if the name ends with "NV", try removing that */
590
if (name[len-2] == 'N' && name[len-1] == 'V')
593
net = getnetwork(name, np);
595
if (net != NONETWORK) return(net);
598
/* check for prefix "v(" and "l(" HSPICE prefixes (see also "simwindow.c:sim_window_findtrace()")*/
599
if ((name[0] == 'l' || name[0] == 'v') && name[1] == '(')
601
net = getnetwork(&name[2], np);
602
if (net != NONETWORK) return(net);
605
/* if there are underscores, see if they match original names */
606
for(pt = name; *pt != 0; pt++) if (*pt == '_') break;
610
for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
613
for(k=0; k<net->namecount; k++)
620
c1 = tolower(name[i]);
622
if (c1 == c2) continue;
623
if (c1 == '_' && !isalnum(c2)) continue;
626
if (i >= len) return(net);
628
pt += strlen(pt) + 1;
636
* routine to determine which arc prototype is referred to by "line"
637
* and return that arcproto. The routine returns NOARCPROTO if the prototype
638
* cannot be determined.
640
ARCPROTO *getarcproto(char *initline)
642
REGISTER ARCPROTO *ap;
643
REGISTER TECHNOLOGY *tech, *t;
644
REGISTER char *pt, *line;
646
/* make a copy of the argument so that it can be modified */
648
(void)addstringtoinfstr(initline);
649
line = returninfstr();
652
for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
653
if (*pt != ':') pt = line; else
656
t = gettechnology(line);
657
if (t != NOTECHNOLOGY) tech = t;
660
for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
661
if (namesame(pt, ap->protoname) == 0) return(ap);
666
* routine to find portproto "portname" on facet "facet". Returns NOPORTPROTO
667
* if it cannot be found
669
PORTPROTO *getportproto(NODEPROTO *facet, char *portname)
671
REGISTER PORTPROTO *pp;
673
for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
674
if (namesame(portname, pp->protoname) == 0) return(pp);
679
* routine to find library "libname". Returns NOLIBRARY if it cannot be found
681
LIBRARY *getlibrary(char *libname)
683
REGISTER LIBRARY *lib;
685
for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
686
if (namesame(libname, lib->libname) == 0) return(lib);
691
* routine to find tool "toolname". Returns NOTOOL if it cannot be found
693
TOOL *gettool(char *toolname)
697
for(i=0; i<el_maxtools; i++)
698
if (namesame(toolname, el_tools[i].toolname) == 0) return(&el_tools[i]);
709
{N_("none"), "ALLOFF", ALLOFF},
710
{N_("overlappable-1"), "COLORT1", COLORT1},
711
{N_("overlappable-2"), "COLORT2", COLORT2},
712
{N_("overlappable-3"), "COLORT3", COLORT3},
713
{N_("overlappable-4"), "COLORT4", COLORT4},
714
{N_("overlappable-5"), "COLORT5", COLORT5},
715
{N_("white"), "WHITE", WHITE},
716
{N_("black"), "BLACK", BLACK},
717
{N_("red"), "RED", RED},
718
{N_("blue"), "BLUE", BLUE},
719
{N_("green"), "GREEN", GREEN},
720
{N_("cyan"), "CYAN", CYAN},
721
{N_("magenta"), "MAGENTA", MAGENTA},
722
{N_("yellow"), "YELLOW", YELLOW},
723
{N_("gray"), "GRAY", GRAY},
724
{N_("orange"), "ORANGE", ORANGE},
725
{N_("purple"), "PURPLE", PURPLE},
726
{N_("brown"), "BROWN", BROWN},
727
{N_("light-gray"), "LGRAY", LGRAY},
728
{N_("dark-gray"), "DGRAY", DGRAY},
729
{N_("light-red"), "LRED", LRED},
730
{N_("dark-red"), "DRED", DRED},
731
{N_("light-green"), "LGREEN", LGREEN},
732
{N_("dark-green"), "DGREEN", DGREEN},
733
{N_("light-blue"), "LBLUE", LBLUE},
734
{N_("dark-blue"), "DBLUE", DBLUE},
739
* Routine to convert the color name "colorname" to a color. Returns negative on error.
741
INTBIG getecolor(char *colorname)
745
for(i=0; db_colors[i].name != 0; i++)
746
if (namesame(colorname, _(db_colors[i].name)) == 0)
747
return(db_colors[i].value);
752
* Routine to convert color "color" to a full name (i.e. "light-gray") in "colorname" and a
753
* symbol name (i.e. "LGRAY") in "colorsymbol". Returns true if the color is unknown.
755
BOOLEAN ecolorname(INTBIG color, char **colorname, char **colorsymbol)
759
for(i=0; db_colors[i].name != 0; i++)
760
if (db_colors[i].value == color)
762
*colorname = _(db_colors[i].name);
763
*colorsymbol = db_colors[i].symbol;
770
* routine to parse a set of commands in "list" against the keyword in
771
* "keyword" and return the index in the list of the keyword. A return of
772
* -1 indicates failure to parse the command and an error message will be
773
* issued if "noise" is nonzero.
775
INTBIG parse(char *keyword, COMCOMP *list, BOOLEAN noise)
777
REGISTER INTBIG i, j;
778
BOOLEAN (*toplist)(char**);
780
REGISTER char *pp, *(*nextinlist)(void);
782
us_pathiskey = list->ifmatch;
783
toplist = list->toplist;
784
nextinlist = list->nextcomcomp;
786
(void)(*toplist)(&keyword);
787
for(i=0, w=0; (pp = (*nextinlist)()) != 0; w++)
789
j = stringmatch(pp, keyword);
790
if (j == -2) return(w);
795
} else if (j == i) bst = -1;
798
/* if nothing found, give an error */
801
if (noise != 0) ttyputerr(_("Unknown command: %s"), keyword);
805
/* if there is unambiguous match, return it */
806
if (bst >= 0) return(bst);
808
/* print ambiguities */
812
(void)(*toplist)(&keyword);
813
for( ; (pp = (*nextinlist)()) != 0; )
815
if ((j = stringmatch(pp, keyword)) < 0) continue;
817
(void)addtoinfstr(' ');
818
(void)addstringtoinfstr(pp);
820
ttyputerr(_("%s ambiguous:%s"), keyword, returninfstr());
826
* routine to report the amount of match that string "keyword" and "input"
827
* have in common. Returns the number of characters that match. Returns -2
828
* if they are equal, -1 if there are extra characters at the end of "input"
829
* which make the match erroneous. Ignores case distinction.
831
INTBIG stringmatch(char *keyword, char *input)
836
for(j=0; (c = input[j]) != 0; j++)
838
if (isupper(c)) c = tolower(c);
839
d = keyword[j]; if (isupper(d)) d = tolower(d);
842
if (c != 0) return(-1);
843
if (keyword[j] == 0) return(-2);
847
/************************* COMMAND COMPLETION CODE *************************/
849
static INTBIG db_filestrlen;
850
static char db_filekey[100];
851
static char db_directorypath[256];
852
static char db_fileextension[10];
853
static INTBIG db_filecount, db_filetotal;
854
static char **db_filesindir;
856
void requiredextension(char *extension)
858
(void)strcpy(db_fileextension, extension);
861
BOOLEAN topoffile(char **a)
863
db_fileextension[0] = 0;
864
return(db_beginsearch(a));
867
BOOLEAN topoflibfile(char **a)
869
(void)strcpy(db_fileextension, ".elib");
870
return(db_beginsearch(a));
873
BOOLEAN db_beginsearch(char **a)
876
static char file[256];
879
/* build the full file name */
880
(void)strcpy(file, truepath(*a));
883
/* search for directory specifications */
884
for(i=strlen(file)-1; i > 0; i--) if (file[i] == DIRSEP) break;
885
if (file[i] == DIRSEP) i++;
886
(void)strcpy(db_filekey, &file[i]);
887
db_filestrlen = strlen(db_filekey);
889
strcpy(db_directorypath, file);
891
db_filetotal = filesindirectory(file, &db_filesindir);
893
/* advance pointer to after the directory separator */
895
for(i=strlen(pt)-1; i > 0; i--) if (pt[i] == DIRSEP) break;
896
if (i > 0) *a = &pt[i+1];
903
static char testfile[256];
907
if (db_filecount >= db_filetotal) break;
908
pt = db_filesindir[db_filecount];
911
/* see if the file is valid */
912
if (pt[0] == '.') continue;
913
if (strncmp(db_filekey, pt, db_filestrlen) != 0) continue;
914
(void)strcpy(testfile, db_directorypath);
915
(void)strcat(testfile, pt);
916
if (fileexistence(testfile) == 2)
918
strcpy(testfile, pt);
919
strcat(testfile, DIRSEPSTR);
922
if (db_fileextension[0] != 0)
924
if (strcmp(&pt[strlen(pt)-strlen(db_fileextension)], db_fileextension) != 0)
933
* routines to do command completion on technology names
935
static TECHNOLOGY *db_postechcomcomp;
936
BOOLEAN topoftechs(char **c) { db_postechcomcomp = el_technologies; return(TRUE); }
937
char *nexttechs(void)
939
REGISTER char *retname;
941
if (db_postechcomcomp == NOTECHNOLOGY) return(0);
942
retname = db_postechcomcomp->techname;
943
db_postechcomcomp = db_postechcomcomp->nexttechnology;
948
* routines to do command completion on technology names
950
static CELL *db_poscellcomcomp;
951
BOOLEAN topofcells(char **c) { db_poscellcomcomp = el_curlib->firstcell; return(TRUE); }
952
char *nextcells(void)
954
REGISTER char *retname;
956
if (db_poscellcomcomp == NOCELL) return(0);
957
retname = db_poscellcomcomp->cellname;
958
db_poscellcomcomp = db_poscellcomcomp->nextcell;
963
* routines to do command completion on view names
965
static VIEW *db_posviewcomcomp;
966
BOOLEAN topofviews(char **c) { db_posviewcomcomp = el_views; return(TRUE); }
967
char *nextviews(void)
969
REGISTER char *retname;
971
if (db_posviewcomcomp == NOVIEW) return(0);
972
retname = db_posviewcomcomp->viewname;
973
db_posviewcomcomp = db_posviewcomcomp->nextview;
978
* routines to do command completion on library names
980
static LIBRARY *db_poslibcomcomp;
981
BOOLEAN topoflibs(char **c)
983
db_poslibcomcomp = el_curlib;
988
REGISTER char *retname;
992
if (db_poslibcomcomp == NOLIBRARY) return(0);
993
if ((db_poslibcomcomp->userbits&HIDDENLIBRARY) == 0)
995
retname = db_poslibcomcomp->libname;
996
db_poslibcomcomp = db_poslibcomcomp->nextlibrary;
1000
db_poslibcomcomp = db_poslibcomcomp->nextlibrary;
1007
* routines to do command completion on tool names
1009
static INTBIG db_poscomcomp;
1010
BOOLEAN topoftools(char **c) { db_poscomcomp = 0; return(TRUE); }
1011
char *nexttools(void)
1013
if (db_poscomcomp >= el_maxtools) return(0);
1014
return(el_tools[db_poscomcomp++].toolname);
1018
* routines to do command completion on facet names
1020
static NODEPROTO *db_posnodeprotos;
1021
BOOLEAN topoffacets(char **c)
1024
REGISTER LIBRARY *lib;
1026
/* by default, assume the current library */
1027
db_posnodeprotos = el_curlib->firstnodeproto;
1029
/* see if a library specification was given */
1030
for(pt = *c; *pt != 0; pt++) if (*pt == ':') break;
1034
lib = getlibrary(*c);
1036
if (lib != NOLIBRARY)
1039
db_posnodeprotos = lib->firstnodeproto;
1044
char *nextfacets(void)
1048
if (db_posnodeprotos != NONODEPROTO)
1050
ret = describenodeproto(db_posnodeprotos);
1051
db_posnodeprotos = db_posnodeprotos->nextnodeproto;
1058
* routines to do command completion on arc names
1060
static ARCPROTO *db_posarcs;
1061
BOOLEAN topofarcs(char **c)
1064
REGISTER TECHNOLOGY *t;
1066
/* by default, assume the current technology */
1067
db_posarcs = el_curtech->firstarcproto;
1069
/* see if a technology specification was given */
1070
for(pt = *c; *pt != 0; pt++) if (*pt == ':') break;
1074
t = gettechnology(*c);
1076
if (t != NOTECHNOLOGY)
1079
db_posarcs = t->firstarcproto;
1084
char *nextarcs(void)
1088
if (db_posarcs != NOARCPROTO)
1090
ret = describearcproto(db_posarcs);
1091
db_posarcs = db_posarcs->nextarcproto;
1098
* routines to do command completion on network names
1100
static NETWORK *db_posnets;
1101
static INTBIG db_posinnet;
1102
static char *db_posinname;
1104
BOOLEAN topofnets(char **c)
1106
REGISTER NODEPROTO *np;
1108
db_posnets = NONETWORK;
1110
if (np == NONODEPROTO) return(FALSE);
1111
db_posnets = np->firstnetwork;
1112
if (db_posnets == NONETWORK) return(FALSE);
1114
db_posinname = db_posnets->netname;
1117
char *nextnets(void)
1123
if (db_posnets == NONETWORK) return(0);
1125
if (db_posinnet >= db_posnets->namecount)
1127
db_posnets = db_posnets->nextnetwork;
1128
if (db_posnets == NONETWORK) return(0);
1130
db_posinname = db_posnets->netname;
1133
db_posinname += strlen(db_posinname) + 1;
1141
/************************* OUTPUT PREPARATION *************************/
1144
* routine to return the full name of node "ni", including its local name.
1145
* Technology considerations are ignored.
1147
char *ntdescribenodeinst(NODEINST *ni)
1149
REGISTER TECHNOLOGY *curtech;
1152
if (ni == NONODEINST) return("***NONODEINST***");
1154
if (ni->proto->primindex == 0) return(describenodeinst(ni));
1155
curtech = el_curtech;
1156
el_curtech = ni->proto->tech;
1157
ret = describenodeinst(ni);
1158
el_curtech = curtech;
1162
/* routine to return the name of nodeinst "ni" */
1163
char *describenodeinst(NODEINST *ni)
1165
REGISTER char *name, *protoname;
1166
REGISTER VARIABLE *var;
1167
REGISTER INTBIG len;
1169
if (ni == NONODEINST) return("***NONODEINST***");
1171
/* see if there is a local name on the node */
1172
protoname = describenodeproto(ni->proto);
1173
var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
1174
if (var == NOVARIABLE) return(protoname);
1176
/* get output buffer */
1177
db_descninodeswitch++;
1178
if (db_descninodeswitch >= NUMDESCRIPTIONBUFS) db_descninodeswitch = 0;
1180
/* make sure buffer has enough room */
1181
len = strlen(protoname) + strlen((char *)var->addr) + 3;
1182
if (len > db_descnioutputsize[db_descninodeswitch])
1184
if (db_descnioutputsize[db_descninodeswitch] != 0)
1185
efree(db_descnioutput[db_descninodeswitch]);
1186
db_descnioutputsize[db_descninodeswitch] = 0;
1187
db_descnioutput[db_descninodeswitch] = (char *)emalloc(len, db_cluster);
1188
if (db_descnioutput[db_descninodeswitch] == 0) return("");
1189
db_descnioutputsize[db_descninodeswitch] = len;
1192
/* store the name */
1193
name = db_descnioutput[db_descninodeswitch];
1194
(void)strcpy(name, protoname);
1195
(void)strcat(name, "[");
1196
(void)strcat(name, (char *)var->addr);
1197
(void)strcat(name, "]");
1201
/* routine to return the name of arcinst "ai" */
1202
char *describearcinst(ARCINST *ai)
1204
REGISTER char *name, *pname;
1205
REGISTER VARIABLE *var;
1206
REGISTER INTBIG len;
1208
if (ai == NOARCINST) return("***NOARCINST***");
1210
/* get local arc name */
1211
pname = describearcproto(ai->proto);
1212
var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1213
if (var == NOVARIABLE) return(pname);
1215
/* get output buffer */
1216
db_descaiarcswitch++;
1217
if (db_descaiarcswitch >= NUMDESCRIPTIONBUFS) db_descaiarcswitch = 0;
1219
/* make sure buffer has enough room */
1220
len = strlen(pname) + strlen((char *)var->addr) + 3;
1221
if (len > db_descaioutputsize[db_descaiarcswitch])
1223
if (db_descaioutputsize[db_descaiarcswitch] != 0)
1224
efree(db_descaioutput[db_descaiarcswitch]);
1225
db_descaioutputsize[db_descaiarcswitch] = 0;
1226
db_descaioutput[db_descaiarcswitch] = (char *)emalloc(len, db_cluster);
1227
if (db_descaioutput[db_descaiarcswitch] == 0) return("");
1228
db_descaioutputsize[db_descaiarcswitch] = len;
1231
name = db_descaioutput[db_descaiarcswitch];
1232
(void)strcpy(name, pname);
1233
(void)strcat(name, "[");
1234
(void)strcat(name, (char *)var->addr);
1235
(void)strcat(name, "]");
1240
* routine to return the full name of facet "np", including its view type
1241
* (if any) and version (if not most recent). Library considerations are
1244
char *nldescribenodeproto(NODEPROTO *np)
1246
REGISTER LIBRARY *curlib;
1249
if (np == NONODEPROTO) return("***NONODEPROTO***");
1251
if (np->primindex != 0) return(np->primname);
1253
el_curlib = np->cell->lib;
1254
ret = describenodeproto(np);
1260
* routine to return the full name of facet "np", including its library name
1261
* (if different from the current), view type (if any), and version (if not
1264
char *describenodeproto(NODEPROTO *np)
1267
REGISTER char *name;
1268
REGISTER INTBIG len;
1270
if (np == NONODEPROTO) return("***NONODEPROTO***");
1272
/* simple tests for direct name use */
1273
if (np->primindex != 0)
1275
/* if a primitive in the current technology, simply use name */
1276
if (np->tech == el_curtech) return(np->primname);
1279
/* if view unknown, version recent, library current, simply use name */
1280
if (*np->cellview->sviewname == 0 && np->newestversion == np && np->cell->lib == el_curlib)
1281
return(np->cell->cellname);
1284
/* get output buffer */
1285
db_descnpnodeswitch++;
1286
if (db_descnpnodeswitch >= NUMDESCRIPTIONBUFS) db_descnpnodeswitch = 0;
1288
if (np->primindex != 0)
1290
len = strlen(np->primname) + strlen(np->tech->techname) + 2;
1293
/* compute size of buffer */
1294
if (np->cell->cellname == 0) return("***BOGUS***");
1295
len = strlen(np->cell->cellname) + 1;
1296
if (np->cell->lib != el_curlib) len += strlen(np->cell->lib->libname) + 1;
1297
if (np->newestversion != np)
1299
(void)sprintf(line, ";%ld", np->version);
1300
len += strlen(line);
1302
if (*np->cellview->sviewname != 0) len += strlen(np->cellview->sviewname) + 2;
1305
/* make sure buffer has enough room */
1306
if (len > db_descnpoutputsize[db_descnpnodeswitch])
1308
if (db_descnpoutputsize[db_descnpnodeswitch] != 0)
1309
efree(db_descnpoutput[db_descnpnodeswitch]);
1310
db_descnpoutputsize[db_descnpnodeswitch] = 0;
1311
db_descnpoutput[db_descnpnodeswitch] = (char *)emalloc(len, db_cluster);
1312
if (db_descnpoutput[db_descnpnodeswitch] == 0) return("");
1313
db_descnpoutputsize[db_descnpnodeswitch] = len;
1316
/* construct complete name */
1317
name = db_descnpoutput[db_descnpnodeswitch];
1318
if (np->primindex != 0)
1320
(void)strcpy(name, np->tech->techname);
1321
(void)strcat(name, ":");
1322
(void)strcat(name, np->primname);
1325
if (np->cell->lib != el_curlib)
1327
(void)strcpy(name, np->cell->lib->libname);
1328
(void)strcat(name, ":");
1329
(void)strcat(name, np->cell->cellname);
1330
} else (void)strcpy(name, np->cell->cellname);
1331
if (np->newestversion != np) (void)strcat(name, line);
1332
if (*np->cellview->sviewname != 0)
1334
(void)strcat(name, "{");
1335
(void)strcat(name, np->cellview->sviewname);
1336
(void)strcat(name, "}");
1342
/* routine to return the name of arcproto "ap" */
1343
char *describearcproto(ARCPROTO *ap)
1345
REGISTER char *name;
1346
REGISTER INTBIG len;
1348
if (ap == NOARCPROTO) return("***NOARCPROTO***");
1350
if (ap->tech == el_curtech) return(ap->protoname);
1352
/* get output buffer */
1353
db_descaparcswitch++;
1354
if (db_descaparcswitch >= NUMDESCRIPTIONBUFS) db_descaparcswitch = 0;
1356
/* make sure buffer has enough room */
1357
len = strlen(ap->tech->techname) + strlen(ap->protoname) + 2;
1358
if (len > db_descapoutputsize[db_descaparcswitch])
1360
if (db_descapoutputsize[db_descaparcswitch] != 0)
1361
efree(db_descapoutput[db_descaparcswitch]);
1362
db_descapoutputsize[db_descaparcswitch] = 0;
1363
db_descapoutput[db_descaparcswitch] = (char *)emalloc(len, db_cluster);
1364
if (db_descapoutput[db_descaparcswitch] == 0) return("");
1365
db_descapoutputsize[db_descaparcswitch] = len;
1368
name = db_descapoutput[db_descaparcswitch];
1369
(void)strcpy(name, ap->tech->techname);
1370
(void)strcat(name, ":");
1371
(void)strcat(name, ap->protoname);
1375
/* routine to return the name of the object whose geometry module is "geom" */
1376
char *geomname(GEOM *geom)
1378
if (geom == NOGEOM) return("***NOGEOM***");
1379
if (geom->entryisnode) return(describenodeinst(geom->entryaddr.ni));
1380
return(describearcinst(geom->entryaddr.ai));
1384
* routine to convert network "net" into a string
1386
char *describenetwork(NETWORK *net)
1389
REGISTER NODEPROTO *np;
1390
static char gennetname[50];
1393
if (net == NONETWORK) return("***NONETWORK***");
1395
if (net->globalnet >= 0)
1398
(void)addstringtoinfstr(_("Global"));
1399
(void)addtoinfstr('-');
1400
if (net->globalnet == 0) (void)addstringtoinfstr(_("Power")); else
1401
if (net->globalnet == 1) (void)addstringtoinfstr(_("Ground")); else
1404
if (net->globalnet >= np->globalnetcount)
1405
(void)addstringtoinfstr(_("UNKNOWN")); else
1406
(void)addstringtoinfstr(np->globalnetnames[net->globalnet]);
1408
return(returninfstr());
1410
if (net->namecount == 0)
1412
sprintf(gennetname, _("UNNAMED%ld"), (INTBIG)net);
1415
if (net->namecount == 1) return(net->netname);
1419
for(i=0; i<net->namecount; i++)
1421
if (i != 0) (void)addtoinfstr('/');
1422
(void)addstringtoinfstr(pt);
1423
pt += strlen(pt) + 1;
1425
return(returninfstr());
1428
char *describeportbits(PORTPROTO *pp)
1430
switch (pp->userbits&STATEBITS)
1432
case INPORT: return(_("Input"));
1433
case OUTPORT: return(_("Output"));
1434
case BIDIRPORT: return(_("Bidirectional"));
1435
case PWRPORT: return(_("Power"));
1436
case GNDPORT: return(_("Ground"));
1437
case CLKPORT: return(_("Clock"));
1438
case C1PORT: return(_("Clock Phase 1"));
1439
case C2PORT: return(_("Clock Phase 2"));
1440
case C3PORT: return(_("Clock Phase 3"));
1441
case C4PORT: return(_("Clock Phase 4"));
1442
case C5PORT: return(_("Clock Phase 5"));
1443
case C6PORT: return(_("Clock Phase 6"));
1444
case REFOUTPORT: return(_("Reference Output"));
1445
case REFINPORT: return(_("Reference Input"));
1451
* routine to name the variable at "addr" of type "type". It is assumed
1452
* to be an object that can hold other variables
1454
char *describeobject(INTBIG addr, INTBIG type)
1456
REGISTER NODEINST *ni;
1457
REGISTER NODEPROTO *np;
1458
REGISTER PORTARCINST *pi;
1459
REGISTER PORTEXPINST *pe;
1460
REGISTER PORTPROTO *pp;
1461
REGISTER ARCINST *ai;
1462
REGISTER ARCPROTO *ap;
1463
REGISTER GEOM *geom;
1464
REGISTER LIBRARY *lib;
1465
REGISTER TECHNOLOGY *tech;
1466
REGISTER TOOL *tool;
1467
REGISTER RTNODE *rtn;
1470
REGISTER WINDOWPART *win;
1471
REGISTER WINDOWFRAME *wf;
1472
REGISTER GRAPHICS *gra;
1473
REGISTER CONSTRAINT *con;
1474
REGISTER POLYGON *poly;
1480
ni = (NODEINST *)addr;
1481
(void)formatinfstr("NodeInstance(%s)", describenodeinst(ni));
1484
np = (NODEPROTO *)addr;
1485
if (np->primindex == 0) (void)formatinfstr("Facet(%s)", describenodeproto(np)); else
1486
(void)formatinfstr("Primitive(%s)", describenodeproto(np));
1489
pi = (PORTARCINST *)addr;
1490
if (pi == NOPORTARCINST) (void)addstringtoinfstr("PortArcInstance(NULL)"); else
1491
(void)formatinfstr("PortArcInstance(%ld)", (INTBIG)pi);
1494
pe = (PORTEXPINST *)addr;
1495
if (pe == NOPORTEXPINST) (void)addstringtoinfstr("PortExpInstance(NULL)"); else
1496
(void)formatinfstr("PortExpInstance(%ld)", (INTBIG)pe);
1499
pp = (PORTPROTO *)addr;
1500
if (pp == NOPORTPROTO) (void)addstringtoinfstr("PortPrototype(NULL)"); else
1501
(void)formatinfstr("PortPrototype(%s)", pp->protoname);
1504
ai = (ARCINST *)addr;
1505
(void)formatinfstr("ArcInstance(%s)", describearcinst(ai));
1508
ap = (ARCPROTO *)addr;
1509
(void)formatinfstr("ArcPrototype(%s)", describearcproto(ap));
1512
geom = (GEOM *)addr;
1513
if (geom == NOGEOM) (void)addstringtoinfstr("Geom(NULL)"); else
1514
(void)formatinfstr("Geom(%ld)", (INTBIG)geom);
1517
lib = (LIBRARY *)addr;
1518
if (lib == NOLIBRARY) (void)addstringtoinfstr("Library(NULL)"); else
1519
(void)formatinfstr("Library(%s)", lib->libname);
1522
tech = (TECHNOLOGY *)addr;
1523
if (tech == NOTECHNOLOGY) (void)addstringtoinfstr("Technology(NULL)"); else
1524
(void)formatinfstr("Technology(%s)", tech->techname);
1527
tool = (TOOL *)addr;
1528
if (tool == NOTOOL) (void)addstringtoinfstr("Tool(NULL)"); else
1529
(void)formatinfstr("Tool(%s)", tool->toolname);
1532
rtn = (RTNODE *)addr;
1533
if (rtn == NORTNODE) (void)addstringtoinfstr("Rtnode(NULL)"); else
1534
(void)formatinfstr("Rtnode(%ld)", (INTBIG)rtn);
1538
if (c == NOCELL) (void)addstringtoinfstr("Cell(NULL)"); else
1539
(void)formatinfstr("Cell(%s)", c->cellname);
1543
if (v == NOVIEW) (void)addstringtoinfstr("View(NULL)"); else
1544
(void)formatinfstr("View(%s)", v->viewname);
1547
win = (WINDOWPART *)addr;
1548
if (win != NOWINDOWPART) (void)formatinfstr("WindowPart(%s)", win->location); else
1549
(void)formatinfstr("WindowPart(%ld)", (INTBIG)win);
1552
gra = (GRAPHICS *)addr;
1553
if (gra == NOGRAPHICS) (void)addstringtoinfstr("Graphics(NULL)"); else
1554
(void)formatinfstr("Graphics(%ld)", (INTBIG)gra);
1557
con = (CONSTRAINT *)addr;
1558
if (con == NOCONSTRAINT) (void)addstringtoinfstr("Constraint(NULL)"); else
1559
(void)formatinfstr("Constraint(%s)", con->conname);
1562
wf = (WINDOWFRAME *)addr;
1563
(void)formatinfstr("WindowFrame(%ld)", (INTBIG)wf);
1566
poly = (POLYGON *)addr;
1567
(void)formatinfstr("Polygon(%ld)", (INTBIG)poly);
1570
(void)addstringtoinfstr("UNKNOWN(?)");
1573
return(returninfstr());
1577
* routine to convert a lambda number to ascii
1580
char *latoa(INTBIG i)
1582
static INTBIG latoaswitch = 0;
1583
static char output[OUTBUFS][20];
1584
double scale, number;
1587
/* get output buffer */
1588
cur = output[latoaswitch++];
1589
if (latoaswitch >= OUTBUFS) latoaswitch = 0;
1591
/* determine scaling */
1592
scale = db_getcurrentscale(el_units&INTERNALUNITS, el_units&DISPLAYUNITS);
1593
number = ((double)i) / scale;
1594
(void)sprintf(cur, "%g", number);
1596
switch (el_units&DISPLAYUNITS)
1598
case DISPUNITINCH: strcat(cur, "\""); break;
1599
case DISPUNITCM: strcat(cur, "cm"); break;
1600
case DISPUNITMM: strcat(cur, "mm"); break;
1601
case DISPUNITMIL: strcat(cur, "mil"); break;
1602
case DISPUNITMIC: strcat(cur, "u"); break;
1603
case DISPUNITCMIC: strcat(cur, "cu"); break;
1604
case DISPUNITMMIC: strcat(cur, "mu"); break;
1610
* routine to convert a fractional number to ascii
1612
#define FRTOANUMBUFS 10
1614
char *frtoa(INTBIG i)
1616
static INTBIG latoaswitch = 0;
1617
static char output[FRTOANUMBUFS][30];
1618
REGISTER INTBIG fra;
1620
REGISTER char *pp, *cur, *start;
1622
/* get output buffer */
1623
start = cur = &output[latoaswitch++][0];
1624
if (latoaswitch >= FRTOANUMBUFS) latoaswitch = 0;
1626
/* handle negative values */
1633
/* get the part to the left of the decimal point */
1634
(void)sprintf(cur, "%ld", i/WHOLE);
1636
/* see if there is anything to the right of the decimal point */
1639
(void)strcat(cur, ".");
1641
fra = (fra*100 + WHOLE/2) / WHOLE;
1642
(void)sprintf(temp, "%02ld", fra);
1643
(void)strcat(cur, temp);
1644
pp = cur; while (*pp != 0) pp++;
1645
while (*--pp == '0') *pp = 0;
1646
if (*pp == '.') *pp = 0;
1652
* routine to determine whether or not the string in "pp" is a number.
1653
* Returns true if it is.
1655
BOOLEAN isanumber(char *pp)
1657
INTBIG xflag, founddigits;
1659
/* ignore the minus sign */
1660
if (*pp == '+' || *pp == '-') pp++;
1662
/* special case for hexadecimal prefix */
1663
if (*pp == '0' && (pp[1] == 'x' || pp[1] == 'X'))
1669
/* there must be something to check */
1670
if (*pp == 0) return(FALSE);
1675
while (isxdigit(*pp))
1682
while (isdigit(*pp) || *pp == '.')
1684
if (*pp != '.') founddigits = 1;
1688
if (founddigits == 0) return(FALSE);
1689
if (*pp == 0) return(TRUE);
1691
/* handle exponent of floating point numbers */
1692
if (xflag != 0 || founddigits == 0 || (*pp != 'e' && *pp != 'E')) return(FALSE);
1694
if (*pp == '+' || *pp == '-') pp++;
1695
if (*pp == 0) return(FALSE);
1696
while (isdigit(*pp)) pp++;
1697
if (*pp == 0) return(TRUE);
1703
* routine to convert relative or absolute font values to absolute, in the
1706
INTBIG truefontsize(INTBIG font, WINDOWPART *w, TECHNOLOGY *tech)
1708
REGISTER INTBIG pixperlam, lambda, height;
1709
REGISTER LIBRARY *lib;
1711
/* keep special font codes */
1712
if (font == TXTEDITOR || font == TXTMENU) return(font);
1714
/* absolute font sizes are easy */
1715
if ((font&TXTPOINTS) != 0) return((font&TXTPOINTS) >> TXTPOINTSSH);
1717
/* detemine default, min, and max size of font */
1718
if (w->curnodeproto == NONODEPROTO) lib = el_curlib; else
1719
lib = w->curnodeproto->cell->lib;
1720
lambda = lib->lambda[tech->techindex];
1721
if ((font&TXTQLAMBDA) != 0)
1723
height = TXTGETQLAMBDA(font);
1724
height = height * lambda / 4;
1725
pixperlam = applyyscale(w, height);
1728
return(applyyscale(w, lambda));
1732
* routine to set the default text descriptor into "td". This text will be
1735
void defaulttextdescript(UINTBIG *descript, GEOM *geom)
1737
REGISTER VARIABLE *txtvar;
1738
REGISTER INTBIG dx, dy, goleft, goright, goup, godown;
1739
INTBIG *defdescript;
1740
REGISTER NODEINST *ni;
1741
REGISTER ARCINST *ai;
1742
static INTBIG user_default_text_style_key = 0, user_default_text_smart_style_key = 0;
1744
if (user_default_text_style_key == 0)
1745
user_default_text_style_key = makekey("USER_default_text_style");
1746
if (user_default_text_smart_style_key == 0)
1747
user_default_text_smart_style_key = makekey("USER_default_text_smart_style");
1749
txtvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, user_default_text_style_key);
1750
if (txtvar == NOVARIABLE)
1752
TDSETPOS(descript, VTPOSCENT);
1755
defdescript = (INTBIG *)txtvar->addr;
1756
TDSETPOS(descript, TDGETPOS(defdescript));
1757
TDSETSIZE(descript, TDGETSIZE(defdescript));
1758
TDSETFACE(descript, TDGETFACE(defdescript));
1759
TDSETITALIC(descript, TDGETITALIC(defdescript));
1760
TDSETBOLD(descript, TDGETBOLD(defdescript));
1761
TDSETUNDERLINE(descript, TDGETUNDERLINE(defdescript));
1766
if (geom->entryisnode)
1768
ni = geom->entryaddr.ni;
1769
if (ni->proto == gen_invispinprim)
1771
defaulttextsize(2, descript);
1774
defaulttextsize(3, descript);
1778
defaulttextsize(4, descript);
1781
/* handle smart text placement relative to attached object */
1782
txtvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, user_default_text_smart_style_key);
1783
if (txtvar != NOVARIABLE)
1785
/* figure out location of object relative to environment */
1787
if (geom->entryisnode)
1789
ni = geom->entryaddr.ni;
1790
if (ni->firstportarcinst != NOPORTARCINST)
1792
ai = ni->firstportarcinst->conarcinst;
1793
dx = (ai->end[0].xpos+ai->end[1].xpos)/2 -
1794
(ni->lowx+ni->highx)/2;
1795
dy = (ai->end[0].ypos+ai->end[1].ypos)/2 -
1796
(ni->lowy+ni->highy)/2;
1800
/* first move placement horizontally */
1801
goleft = goright = goup = godown = 0;
1802
if ((txtvar->addr&03) == 1)
1804
/* place label inside (towards center) */
1805
if (dx > 0) goright++; else
1806
if (dx < 0) goleft++;
1807
} else if ((txtvar->addr&03) == 2)
1809
/* place label outside (away from center) */
1810
if (dx > 0) goleft++; else
1811
if (dx < 0) goright++;
1814
/* next move placement vertically */
1815
if (((txtvar->addr>>2)&03) == 1)
1817
/* place label inside (towards center) */
1818
if (dy > 0) goup++; else
1819
if (dy < 0) godown++;
1820
} else if (((txtvar->addr>>2)&03) == 2)
1822
/* place label outside (away from center) */
1823
if (dy > 0) godown++; else
1828
switch (TDGETPOS(descript))
1833
TDSETPOS(descript, VTPOSLEFT);
1838
TDSETPOS(descript, VTPOSUPLEFT);
1842
case VTPOSDOWNRIGHT:
1843
TDSETPOS(descript, VTPOSDOWNLEFT);
1849
switch (TDGETPOS(descript))
1854
TDSETPOS(descript, VTPOSRIGHT);
1859
TDSETPOS(descript, VTPOSUPRIGHT);
1863
case VTPOSDOWNRIGHT:
1864
TDSETPOS(descript, VTPOSDOWNRIGHT);
1870
switch (TDGETPOS(descript))
1875
TDSETPOS(descript, VTPOSUP);
1879
case VTPOSDOWNRIGHT:
1880
TDSETPOS(descript, VTPOSUPRIGHT);
1885
TDSETPOS(descript, VTPOSUPLEFT);
1891
switch (TDGETPOS(descript))
1896
TDSETPOS(descript, VTPOSDOWN);
1900
case VTPOSDOWNRIGHT:
1901
TDSETPOS(descript, VTPOSDOWNRIGHT);
1906
TDSETPOS(descript, VTPOSDOWNLEFT);
1914
#define DEFNODETEXTSIZE TXTSETQLAMBDA(4)
1915
#define DEFARCTEXTSIZE TXTSETQLAMBDA(4)
1916
#define DEFEXPORTSIZE TXTSETQLAMBDA(8)
1917
#define DEFNONLAYOUTTEXTSIZE TXTSETQLAMBDA(4)
1918
#define DEFINSTTEXTSIZE TXTSETQLAMBDA(16)
1919
#define DEFFACETTEXTSIZE TXTSETQLAMBDA(4)
1922
* Routine to determine the size of text to use for a particular type of text:
1926
* 2: nonlayout text (text on an invisible pin, facet variables)
1927
* 5: facet instance name
1930
void defaulttextsize(INTBIG texttype, UINTBIG *descript)
1932
REGISTER VARIABLE *var;
1933
static INTBIG node_size_key = 0, arc_size_key = 0, export_size_key = 0,
1934
nonlayout_size_key = 0, instance_size_key = 0, facet_size_key = 0;
1936
if (node_size_key == 0)
1937
node_size_key = makekey("USER_default_node_text_size");
1938
if (arc_size_key == 0)
1939
arc_size_key = makekey("USER_default_arc_text_size");
1940
if (export_size_key == 0)
1941
export_size_key = makekey("USER_default_export_text_size");
1942
if (nonlayout_size_key == 0)
1943
nonlayout_size_key = makekey("USER_default_nonlayout_text_size");
1944
if (instance_size_key == 0)
1945
instance_size_key = makekey("USER_default_instance_text_size");
1946
if (facet_size_key == 0)
1947
facet_size_key = makekey("USER_default_facet_text_size");
1949
TDSETSIZE(descript, TXTSETQLAMBDA(4));
1953
var = getvalkey((INTBIG)us_tool, VTOOL, -1, node_size_key);
1954
if (var == NOVARIABLE) TDSETSIZE(descript, DEFNODETEXTSIZE); else
1956
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1957
TDSETSIZE(descript, var->addr);
1961
var = getvalkey((INTBIG)us_tool, VTOOL, -1, arc_size_key);
1962
if (var == NOVARIABLE) TDSETSIZE(descript, DEFARCTEXTSIZE); else
1964
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1965
TDSETSIZE(descript, var->addr);
1969
var = getvalkey((INTBIG)us_tool, VTOOL, -1, export_size_key);
1970
if (var == NOVARIABLE) TDSETSIZE(descript, DEFEXPORTSIZE); else
1972
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1973
TDSETSIZE(descript, var->addr);
1977
var = getvalkey((INTBIG)us_tool, VTOOL, -1, nonlayout_size_key);
1978
if (var == NOVARIABLE) TDSETSIZE(descript, DEFNONLAYOUTTEXTSIZE); else
1980
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1981
TDSETSIZE(descript, var->addr);
1985
var = getvalkey((INTBIG)us_tool, VTOOL, -1, instance_size_key);
1986
if (var == NOVARIABLE) TDSETSIZE(descript, DEFINSTTEXTSIZE); else
1988
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1989
TDSETSIZE(descript, var->addr);
1993
var = getvalkey((INTBIG)us_tool, VTOOL, -1, facet_size_key);
1994
if (var == NOVARIABLE) TDSETSIZE(descript, DEFFACETTEXTSIZE); else
1996
if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1997
TDSETSIZE(descript, var->addr);
2004
* Routine to get the X offset field of text descriptor words "td". This routine
2005
* implements the macro "TDGETXOFF".
2007
INTBIG gettdxoffset(UINTBIG *td)
2009
REGISTER INTBIG offset, scale;
2011
offset = (td[0] & VTXOFF) >> VTXOFFSH;
2012
if ((td[0]&VTXOFFNEG) != 0) offset = -offset;
2013
scale = TDGETOFFSCALE(td) + 1;
2014
return(offset * scale);
2018
* Routine to get the Y offset field of text descriptor words "td". This routine
2019
* implements the macro "TDGETYOFF".
2021
INTBIG gettdyoffset(UINTBIG *td)
2023
REGISTER INTBIG offset, scale;
2025
offset = (td[0] & VTYOFF) >> VTYOFFSH;
2026
if ((td[0]&VTYOFFNEG) != 0) offset = -offset;
2027
scale = TDGETOFFSCALE(td) + 1;
2028
return(offset * scale);
2032
* Routine to set the X offset field of text descriptor words "td" to "value".
2033
* This routine implements the macro "TDSETOFF".
2035
void settdoffset(UINTBIG *td, INTBIG x, INTBIG y)
2037
REGISTER INTBIG scale;
2039
td[0] = td[0] & ~(VTXOFF|VTYOFF|VTXOFFNEG|VTYOFFNEG);
2050
scale = maxi(x,y) >> VTOFFMASKWID;
2053
td[0] |= (x << VTXOFFSH);
2054
td[0] |= (y << VTYOFFSH);
2055
TDSETOFFSCALE(td, scale);
2059
* Routine to validate the variable offset (x,y) and clip or grid it
2060
* to acceptable values.
2062
void propervaroffset(INTBIG *x, INTBIG *y)
2064
REGISTER INTBIG scale, realx, realy, negx, negy;
2067
realx = *x; realy = *y;
2068
if (realx < 0) { realx = -realx; negx = -1; }
2069
if (realy < 0) { realy = -realy; negy = -1; }
2070
if (realx > 077777) realx = 077777;
2071
if (realy > 077777) realy = 077777;
2072
scale = (maxi(realx, realy) >> VTOFFMASKWID) + 1;
2075
*x = realx * scale * negx;
2076
*y = realy * scale * negy;
2080
* Routine to clear the text descriptor array in "t".
2081
* This routine implements the macro "TDCLEAR".
2083
void tdclear(UINTBIG *t)
2087
for(i=0; i<TEXTDESCRIPTSIZE; i++) t[i] = 0;
2091
* Routine to copy the text descriptor array in "s" to "d".
2092
* This routine implements the macro "TDCOPY".
2094
void tdcopy(UINTBIG *d, UINTBIG *s)
2098
for(i=0; i<TEXTDESCRIPTSIZE; i++) d[i] = s[i];
2102
* Routine to compare the text descriptor arrays in "t1" to "t2"
2103
* and return true if they are different.
2104
* This routine implements the macro "TDDIFF".
2106
BOOLEAN tddiff(UINTBIG *t1, UINTBIG *t2)
2110
for(i=0; i<TEXTDESCRIPTSIZE; i++)
2111
if (t1[i] != t2[i]) return(TRUE);
2116
* routine to make a printable string from variable "val", array index
2117
* "aindex". If "aindex" is negative, print the entire array. If "purpose" is
2118
* zero, the conversion is for human reading and should be easy to understand.
2119
* If "purpose" is positive, the conversion is for machine reading and should
2120
* be easy to parse. If "purpose" is negative, the conversion is for
2121
* parameter substitution and should be easy to understand but not hard to
2122
* parse (a combination of the two). If the variable is displayable and the name
2123
* is to be displayed, that part is added.
2125
char *describedisplayedvariable(VARIABLE *var, INTBIG aindex, INTBIG purpose)
2127
REGISTER char *name, *parstr;
2128
REGISTER INTBIG len;
2129
REGISTER VARIABLE *parval;
2131
if (var == NOVARIABLE)
2133
if (purpose <= 0) return("***UNKNOWN***"); else return("");
2138
/* add variable name if requested */
2139
if ((var->type&VDISPLAY) != 0)
2141
if ((var->type&VISARRAY) == 0) len = 1; else
2142
len = getlength(var);
2143
name = truevariablename(var);
2144
switch (TDGETDISPPART(var->textdescript))
2146
case VTDISPLAYNAMEVALUE:
2147
if (len > 1 && aindex >= 0)
2149
(void)formatinfstr("%s[%ld]=", name, aindex);
2152
(void)formatinfstr("%s=", name);
2155
case VTDISPLAYNAMEVALINH:
2156
parval = getparentvalkey(var->key, 1);
2157
if (parval == NOVARIABLE) parstr = "?"; else
2158
parstr = describevariable(parval, -1, purpose);
2159
if (len > 1 && aindex >= 0)
2161
(void)formatinfstr("%s[%ld]=%s;def=", name, aindex, parstr);
2164
(void)formatinfstr("%s=%s;def=", name, parstr);
2167
case VTDISPLAYNAMEVALINHALL:
2168
parval = getparentvalkey(var->key, 0);
2169
if (parval == NOVARIABLE) parstr = "?"; else
2170
parstr = describevariable(parval, -1, purpose);
2171
if (len > 1 && aindex >= 0)
2173
(void)formatinfstr("%s[%ld]=%s;def=", name, aindex, parstr);
2176
(void)formatinfstr("%s=%s;def=", name, parstr);
2181
(void)addstringtoinfstr(describevariable(var, aindex, purpose));
2182
return(returninfstr());
2186
* Routine to return the true name of variable "var". Leading "ATTR_" or "ATTRP_"
2187
* markers are removed.
2189
char *truevariablename(VARIABLE *var)
2191
REGISTER char *name;
2192
REGISTER INTBIG i, len;
2194
name = makename(var->key);
2195
if (strncmp(name, "ATTR_", 5) == 0)
2197
if (strncmp(name, "ATTRP_", 6) == 0)
2200
for(i=len-1; i>=0; i--) if (name[i] == '_') break;
2207
* routine to make a printable string from variable "val", array index
2208
* "aindex". If "aindex" is negative, print the entire array. If "purpose" is
2209
* zero, the conversion is for human reading and should be easy to understand.
2210
* If "purpose" is positive, the conversion is for machine reading and should
2211
* be easy to parse. If "purpose" is negative, the conversion is for
2212
* parameter substitution and should be easy to understand but not hard to
2213
* parse (a combination of the two).
2215
char *describevariable(VARIABLE *var, INTBIG aindex, INTBIG purpose)
2217
REGISTER BOOLEAN err;
2218
REGISTER INTBIG i, len, *addr;
2220
if (var == NOVARIABLE)
2222
if (purpose <= 0) return("***UNKNOWN***"); else return("");
2227
if ((var->type & (VCODE1|VCODE2)) != 0)
2229
/* special case for code: it is a string, the type applies to the result */
2230
err |= db_makestringvar(VSTRING, var->addr, purpose);
2233
if ((var->type&VISARRAY) != 0)
2235
/* compute the array length */
2236
len = getlength(var);
2237
addr = (INTBIG *)var->addr;
2239
/* if asking for a single entry, get it */
2242
/* special case when the variable is a general array of objects */
2243
if ((var->type&VTYPE) == VGENERAL)
2245
/* index the array in pairs */
2248
err |= db_makestringvar(addr[aindex+1], addr[aindex], purpose);
2251
/* normal array indexing */
2253
switch ((var->type&VTYPE))
2256
err |= db_makestringvar(var->type,
2257
((INTBIG)((char *)addr)[aindex]), purpose);
2261
err |= db_makestringvar(var->type,
2262
((INTBIG)((double *)addr)[aindex]), purpose);
2266
err |= db_makestringvar(var->type,
2267
((INTBIG)((INTSML *)addr)[aindex]), purpose);
2271
err |= db_makestringvar(var->type, addr[aindex], purpose);
2277
/* in an array, quote strings */
2278
if (purpose < 0) purpose = 0;
2279
err |= addtoinfstr('[');
2280
for(i=0; i<len; i++)
2282
if (i != 0) err |= addtoinfstr(',');
2284
/* special case when the variable is a general array of objects */
2285
if ((var->type&VTYPE) == VGENERAL)
2287
/* index the array in pairs */
2289
err |= db_makestringvar(addr[i+1], addr[i], purpose);
2293
/* normal array indexing */
2294
switch ((var->type&VTYPE))
2297
err |= db_makestringvar(var->type,
2298
((INTBIG)((char *)addr)[i]), purpose);
2302
err |= db_makestringvar(var->type,
2303
((INTBIG)((double *)addr)[i]), purpose);
2307
err |= db_makestringvar(var->type,
2308
((INTBIG)((INTSML *)addr)[i]), purpose);
2312
err |= db_makestringvar(var->type, addr[i], purpose);
2317
err |= addtoinfstr(']');
2319
} else err |= db_makestringvar(var->type, var->addr, purpose);
2321
if (err != 0) (void)db_error(DBNOMEM|DBDESCRIBEVARIABLE);
2322
return(returninfstr());
2326
* routine to make a string from the value in "addr" which has a type in
2327
* "type". "purpose" is an indicator of the purpose of this conversion:
2328
* zero indicates conversion for humans to read, positive indicates
2329
* conversion for a program to read (more terse) and negative indicates human
2330
* reading for parameter substitution (don't quote strings). Returns true
2331
* if there is a memory allocation error.
2333
BOOLEAN db_makestringvar(INTBIG type, INTBIG addr, INTBIG purpose)
2336
REGISTER BOOLEAN err;
2337
REGISTER NODEINST *ni;
2338
REGISTER NODEPROTO *np;
2339
REGISTER PORTARCINST *pi;
2340
REGISTER PORTEXPINST *pe;
2341
REGISTER PORTPROTO *pp;
2342
REGISTER ARCINST *ai;
2343
REGISTER ARCPROTO *ap;
2344
REGISTER GEOM *geom;
2345
REGISTER RTNODE *rtn;
2346
REGISTER LIBRARY *lib;
2347
REGISTER TECHNOLOGY *tech;
2348
REGISTER TOOL *tool;
2349
REGISTER NETWORK *net;
2350
REGISTER CELL *cell;
2351
REGISTER VIEW *view;
2352
REGISTER WINDOWPART *win;
2353
REGISTER GRAPHICS *gra;
2354
REGISTER VARIABLE *var;
2355
REGISTER CONSTRAINT *con;
2356
REGISTER WINDOWFRAME *wf;
2357
REGISTER POLYGON *poly;
2363
(void)sprintf(line, "%ld", addr);
2364
return(addstringtoinfstr(line));
2366
if (purpose == 0) err = addstringtoinfstr("Address="); else
2368
(void)sprintf(line, "0%lo", addr);
2369
err |= addstringtoinfstr(line);
2372
return(addtoinfstr((char)addr)?1:0);
2374
if ((char *)addr == NOSTRING || (char *)addr == 0)
2375
return(addstringtoinfstr("***NOSTRING***"));
2377
if (purpose >= 0) err |= addtoinfstr('"');
2378
if (purpose <= 0) err |= addstringtoinfstr((char *)addr); else
2379
err |= db_addstring((char *)addr);
2380
if (purpose >= 0) err |= addtoinfstr('"');
2384
(void)sprintf(line, "%g", castfloat(addr));
2385
return(addstringtoinfstr(line));
2387
ni = (NODEINST *)addr;
2388
if (ni == NONODEINST) return(addstringtoinfstr("***NONODEINST***"));
2391
var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
2392
if (var != NOVARIABLE) return(addstringtoinfstr((char *)var->addr));
2393
(void)sprintf(line, "node%ld", (INTBIG)ni);
2394
return(addstringtoinfstr(line));
2396
(void)sprintf(line, "node%ld", (INTBIG)ni);
2397
return(addstringtoinfstr(line));
2399
np = (NODEPROTO *)addr;
2400
if (purpose <= 0) return(addstringtoinfstr(describenodeproto(np)));
2401
return(db_addstring(describenodeproto(np)));
2403
pi = (PORTARCINST *)addr;
2404
if (pi == NOPORTARCINST) return(addstringtoinfstr("***NOPORTARCINST***"));
2405
(void)sprintf(line, "portarc%ld", (INTBIG)pi);
2406
return(addstringtoinfstr(line));
2408
pe = (PORTEXPINST *)addr;
2409
if (pe == NOPORTEXPINST) return(addstringtoinfstr("***NOPORTEXPINST***"));
2410
(void)sprintf(line, "portexp%ld", (INTBIG)pe);
2411
return(addstringtoinfstr(line));
2413
pp = (PORTPROTO *)addr;
2414
if (pp == NOPORTPROTO) return(addstringtoinfstr("***NOPORTPROTO***"));
2415
if (purpose <= 0) return(addstringtoinfstr(pp->protoname));
2416
return(db_addstring(pp->protoname));
2418
ai = (ARCINST *)addr;
2419
if (ai == NOARCINST) return(addstringtoinfstr("***NOARCINST***"));
2420
(void)sprintf(line, "arc%ld", (INTBIG)ai);
2421
return(addstringtoinfstr(line));
2423
ap = (ARCPROTO *)addr;
2424
if (purpose <= 0) return(addstringtoinfstr(describearcproto(ap)));
2425
return(db_addstring(describearcproto(ap)));
2427
geom = (GEOM *)addr;
2428
if (geom == NOGEOM) return(addstringtoinfstr("***NOGEOM***"));
2429
(void)sprintf(line, "geom%ld", (INTBIG)geom);
2430
return(addstringtoinfstr(line));
2432
lib = (LIBRARY *)addr;
2433
if (lib == NOLIBRARY) return(addstringtoinfstr("***NOLIBRARY***"));
2434
if (purpose <= 0) return(addstringtoinfstr(lib->libname));
2435
return(db_addstring(lib->libname));
2437
tech = (TECHNOLOGY *)addr;
2438
if (tech == NOTECHNOLOGY) return(addstringtoinfstr("***NOTECHNOLOGY***"));
2439
if (purpose <= 0) return(addstringtoinfstr(tech->techname));
2440
return(db_addstring(tech->techname));
2442
tool = (TOOL *)addr;
2443
if (tool == NOTOOL) return(addstringtoinfstr("***NOTOOL***"));
2444
if (purpose <= 0) return(addstringtoinfstr(tool->toolname));
2445
return(db_addstring(tool->toolname));
2447
rtn = (RTNODE *)addr;
2448
if (rtn == NORTNODE) return(addstringtoinfstr("***NORTNODE***"));
2449
(void)sprintf(line, "rtn%ld", (INTBIG)rtn);
2450
return(addstringtoinfstr(line));
2452
return(addstringtoinfstr(frtoa(addr)));
2454
net = (NETWORK *)addr;
2455
if (net == NONETWORK) return(addstringtoinfstr("***NONETWORK***"));
2456
if (purpose <= 0) return(addstringtoinfstr(describenetwork(net)));
2457
return(db_addstring(describenetwork(net)));
2459
cell = (CELL *)addr;
2460
if (cell == NOCELL) return(addstringtoinfstr("***NOCELL***"));
2461
if (purpose <= 0) return(addstringtoinfstr(cell->cellname));
2462
return(db_addstring(cell->cellname));
2464
view = (VIEW *)addr;
2465
if (view == NOVIEW) return(addstringtoinfstr("***NOVIEW***"));
2466
if (purpose <= 0) return(addstringtoinfstr(view->viewname));
2467
return(db_addstring(view->viewname));
2469
win = (WINDOWPART *)addr;
2470
if (win == NOWINDOWPART) return(addstringtoinfstr("***NOWINDOWPART***"));
2471
if (purpose <= 0) return(addstringtoinfstr(win->location));
2472
return(db_addstring(win->location));
2474
gra = (GRAPHICS *)addr;
2475
if (gra == NOGRAPHICS) return(addstringtoinfstr("***NOGRAPHICS***"));
2476
(void)sprintf(line, "gra%ld", (INTBIG)gra);
2477
return(addstringtoinfstr(line));
2479
con = (CONSTRAINT *)addr;
2480
if (con == NOCONSTRAINT) return(addstringtoinfstr("***NOCONSTRAINT***"));
2481
if (purpose <= 0) return(addstringtoinfstr(con->conname));
2482
return(db_addstring(con->conname));
2484
(void)sprintf(line, "***%ld-LONG-GENERAL-ARRAY***", ((type&VLENGTH)>>VLENGTHSH) / 2);
2485
return(addstringtoinfstr(line));
2487
wf = (WINDOWFRAME *)addr;
2488
if (wf == NOWINDOWFRAME) return(addstringtoinfstr("***NOWINDOWFRAME***"));
2489
(void)sprintf(line, "wf%ld", (INTBIG)wf);
2490
return(addstringtoinfstr(line));
2492
poly = (POLYGON *)addr;
2493
if (poly == NOPOLYGON) return(addstringtoinfstr("***NOPOLYGON***"));
2494
(void)sprintf(line, "poly%ld", (INTBIG)poly);
2495
return(addstringtoinfstr(line));
2501
* routine to add the string "str" to the infinite string and to quote the
2502
* special characters '[', ']', '"', and '^'. The routine returns nonzero
2503
* if there is memory problem with the infinite string package.
2505
BOOLEAN db_addstring(char *str)
2507
REGISTER BOOLEAN err;
2512
if (*str == '[' || *str == ']' || *str == '"' || *str == '^')
2513
err |= addtoinfstr('^');
2514
err |= addtoinfstr(*str++);
2520
* Routine to describe a simple variable "var". There can be no arrays, code,
2521
* or pointers to Electric objects in this variable.
2523
char *describesimplevariable(VARIABLE *var)
2525
static char line[50];
2527
switch (var->type&VTYPE)
2530
return((char *)var->addr);
2532
sprintf(line, "%ld", var->addr);
2535
strcpy(line, frtoa(var->addr));
2538
sprintf(line, "%ld", var->addr&0xFFFF);
2542
sprintf(line, "%g", castfloat(var->addr));
2549
* Routine to determine the variable type of "pt"; either an integer, float,
2550
* or string; and return the type and value in "type" and "addr".
2552
void getsimpletype(char *pt, INTBIG *type, INTBIG *addr)
2566
for(opt = pt; *opt != 0; opt++) if (*opt == '.')
2568
f = (float)atof(pt);
2569
i = (INTBIG)(f * WHOLE);
2584
* routine to make an abbreviation for the string "pt" in upper case if
2587
char *makeabbrev(char *pt, BOOLEAN upper)
2589
/* generate an abbreviated name for this prototype */
2597
if (upper) (void)addtoinfstr(*pt); else
2598
(void)addtoinfstr((char)(tolower(*pt)));
2601
if (!upper) (void)addtoinfstr(*pt); else
2602
(void)addtoinfstr((char)(toupper(*pt)));
2604
while (isalpha(*pt)) pt++;
2606
while (!isalpha(*pt) && *pt != 0) pt++;
2608
return(returninfstr());
2612
* routine to report the name of the internal unit in "units".
2614
char *unitsname(INTBIG units)
2616
switch (units & INTERNALUNITS)
2618
case INTUNITHMMIC: return(_("half-millimicron"));
2619
case INTUNITHDMIC: return(_("half-decimicron"));
2624
/************************* INTERNATIONALIZATION *************************/
2626
char *db_stoppingreason[] =
2628
N_("Contour gather"), /* STOPREASONCONTOUR */
2629
N_("DRC"), /* STOPREASONDRC */
2630
N_("Playback"), /* STOPREASONPLAYBACK */
2631
N_("Binary"), /* STOPREASONBINARY */
2632
N_("CIF"), /* STOPREASONCIF */
2633
N_("DXF"), /* STOPREASONDXF */
2634
N_("EDIF"), /* STOPREASONEDIF */
2635
N_("VHDL"), /* STOPREASONVHDL */
2636
N_("Compaction"), /* STOPREASONCOMPACT */
2637
N_("ERC"), /* STOPREASONERC */
2638
N_("Check-in"), /* STOPREASONCHECKIN */
2639
N_("Lock wait"), /* STOPREASONLOCK */
2640
N_("Network comparison"), /* STOPREASONNCC */
2641
N_("Port exploration"), /* STOPREASONPORT */
2642
N_("Routing"), /* STOPREASONROUTING */
2643
N_("Silicon compiler"), /* STOPREASONSILCOMP */
2644
N_("Display"), /* STOPREASONDISPLAY */
2645
N_("Simulation"), /* STOPREASONSIMULATE */
2646
N_("Deck generation"), /* STOPREASONDECK */
2647
N_("SPICE"), /* STOPREASONSPICE */
2648
N_("Check"), /* STOPREASONCHECK */
2649
N_("Array"), /* STOPREASONARRAY */
2650
N_("Iteration"), /* STOPREASONITERATE */
2651
N_("Replace"), /* STOPREASONREPLACE */
2652
N_("Spread"), /* STOPREASONSPREAD */
2653
N_("Execution"), /* STOPREASONEXECUTE */
2654
N_("Command file"), /* STOPREASONCOMFILE */
2655
N_("Selection"), /* STOPREASONSELECT */
2656
N_("Tracking"), /* STOPREASONTRACK */
2657
N_("Network evaluation"), /* STOPREASONNETWORK */
2662
* Routine to translate internal strings in the database.
2664
void db_inittranslation(void)
2668
/* pretranslate the reasons for stopping */
2669
for(i=0; db_stoppingreason[i] != 0; i++)
2670
db_stoppingreason[i] = _(db_stoppingreason[i]);
2674
* Routine to ensure that dialog "dia" is translated.
2676
void DiaTranslate(DIALOG *dia)
2681
if (dia->translated != 0) return;
2682
dia->translated = 1;
2683
if (dia->movable != 0) dia->movable = _(dia->movable);
2684
for(j=0; j<dia->items; j++)
2686
item = &dia->list[j];
2687
switch (item->type&ITEMTYPE)
2695
if (*item->msg != 0)
2696
item->msg = _(item->msg);
2703
* routine to convert "word" to its plural form, depending on the value
2704
* of "amount" (if "amount" is zero or multiple, pluralize the word).
2706
char *makeplural(char *word, INTBIG amount)
2710
if (amount == 1) return(word);
2712
if (len == 0) return(word);
2714
if (needed > db_pluralbufsize)
2716
if (db_pluralbufsize > 0) efree(db_pluralbuffer);
2717
db_pluralbufsize = 0;
2718
db_pluralbuffer = (char *)emalloc(needed, db_cluster);
2719
if (db_pluralbuffer == 0) return(word);
2720
db_pluralbufsize = needed;
2722
strcpy(db_pluralbuffer, word);
2723
if (isupper(word[len-1])) strcat(db_pluralbuffer, "S"); else
2724
strcat(db_pluralbuffer, "s");
2725
return(db_pluralbuffer);
2728
/************************* STRING MANIPULATION *************************/
2731
* this routine dynamically allocates a string to hold "str" and places
2732
* that string at "*addr". The routine returns true if the allocation
2733
* cannot be done. Memory is allocated from virtual cluster "cluster".
2736
BOOLEAN _allocstring(char **addr, char *str, CLUSTER *cluster, char *module, INTBIG line)
2738
*addr = (char *)_emalloc((strlen(str)+1), cluster, module, line);
2742
(void)db_error(DBNOMEM|DBALLOCSTRING);
2745
(void)strcpy(*addr, str);
2749
BOOLEAN allocstring(char **addr, char *str, CLUSTER *cluster)
2751
*addr = (char *)emalloc((strlen(str)+1), cluster);
2755
(void)db_error(DBNOMEM|DBALLOCSTRING);
2758
(void)strcpy(*addr, str);
2764
* this routine assumes that there is a dynamically allocated string at
2765
* "*addr" and that it is to be replaced with another dynamically allocated
2766
* string from "str". The routine returns true if the allocation
2767
* cannot be done. Memory is allocated from virtual cluster "cluster".
2770
BOOLEAN _reallocstring(char **addr, char *str, CLUSTER *cluster, char *module, INTBIG line)
2773
return(_allocstring(addr, str, cluster, module, line));
2776
BOOLEAN reallocstring(char **addr, char *str, CLUSTER *cluster)
2779
return(allocstring(addr, str, cluster));
2784
* Routine to convert character "c" to a case-insensitive character, with
2785
* special characters all ordered properly before the letters.
2787
INTBIG db_insensitivechar(INTBIG c)
2789
if (isupper(c)) return(tolower(c));
2792
case '[': return(1);
2793
case '\\': return(2);
2794
case ']': return(3);
2795
case '^': return(4);
2796
case '_': return(5);
2797
case '`': return(6);
2798
case '{': return(7);
2799
case '|': return(8);
2800
case '}': return(9);
2801
case '~': return(10);
2807
* name matching routine: ignores case
2809
INTBIG namesame(char *pt1, char *pt2)
2811
REGISTER INTBIG c1, c2;
2815
c1 = db_insensitivechar(*pt1++ & 0377);
2816
c2 = db_insensitivechar(*pt2++ & 0377);
2817
if (c1 != c2) return(c1-c2);
2823
INTBIG namesamen(char *pt1, char *pt2, INTBIG count)
2825
REGISTER INTBIG c1, c2, i;
2827
for(i=0; i<count; i++)
2829
c1 = db_insensitivechar(*pt1++ & 0377);
2830
c2 = db_insensitivechar(*pt2++ & 0377);
2831
if (c1 != c2) return(c1-c2);
2838
* Routine to compare two names "name1" and "name2" and return an
2839
* integer giving their sorting order (0 if equal, nonzero according
2840
* to order) in the same manner as any other string compare EXCEPT
2841
* that it considers numbers properly, so that the string "in10" comes
2842
* after the string "in9".
2844
INTBIG namesamenumeric(char *name1, char *name2)
2846
REGISTER char *pt1, *pt2, pt1save, pt2save, *number1, *number2,
2847
*nameend1, *nameend2;
2848
REGISTER INTBIG pt1index, pt2index, pt1number, pt2number;
2849
REGISTER INTBIG compare;
2852
for(pt1 = name1; *pt1 != 0; pt1++)
2854
if (*pt1 == '[') break;
2855
if (isdigit(*pt1) == 0) number1 = 0; else
2857
if (number1 == 0) number1 = pt1;
2861
for(pt2 = name2; *pt2 != 0; pt2++)
2863
if (*pt2 == '[') break;
2864
if (isdigit(*pt2) == 0) number2 = 0; else
2866
if (number2 == 0) number2 = pt2;
2869
nameend1 = pt1; nameend2 = pt2;
2870
pt1number = pt2number = 0;
2871
pt1index = pt2index = 0;
2872
if (number1 != 0 && number2 != 0)
2874
pt1number = myatoi(number1);
2875
pt2number = myatoi(number2);
2879
if (*pt1 == '[') pt1index = myatoi(&pt1[1]);
2880
if (*pt2 == '[') pt2index = myatoi(&pt2[1]);
2882
pt1save = *nameend1; *nameend1 = 0;
2883
pt2save = *nameend2; *nameend2 = 0;
2884
compare = namesame(name1, name2);
2885
*nameend1 = pt1save; *nameend2 = pt2save;
2886
if (compare != 0) return(compare);
2887
if (pt1number != pt2number) return(pt1number - pt2number);
2888
return(pt1index - pt2index);
2891
/******************** STRING PARSING ROUTINES ********************/
2894
* routine to scan off the next keyword in the string at "*ptin". The string
2895
* is terminated by any of the characters in "brk". The string is returned
2896
* (-1 if error) and the string pointer is advanced to the break character
2898
char *getkeyword(char **ptin, char *brk)
2900
REGISTER char *pt2, *b, *pt;
2901
REGISTER INTBIG len;
2903
/* skip leading blanks */
2905
while (*pt == ' ' || *pt == '\t') pt++;
2907
/* remember starting point */
2911
if (*pt2 == 0) break;
2912
for(b = brk; *b != 0; b++) if (*pt2 == *b) break;
2917
if (len+1 > db_keywordbufferlength)
2919
if (db_keywordbufferlength != 0) efree(db_keywordbuffer);
2920
db_keywordbufferlength = 0;
2921
db_keywordbuffer = (char *)emalloc(len+1, el_tempcluster);
2922
if (db_keywordbuffer == 0)
2927
db_keywordbufferlength = len+1;
2929
(void)strncpy(db_keywordbuffer, pt, len);
2930
db_keywordbuffer[len] = 0;
2932
return(db_keywordbuffer);
2936
* routine to return the next nonblank character in the string pointed
2937
* to by "ptin". The pointer is advanced past that character.
2939
char tonextchar(char **ptin)
2941
REGISTER char *pt, ret;
2943
/* skip leading blanks */
2945
while (*pt == ' ' || *pt == '\t') pt++;
2953
* routine to return the next nonblank character in the string pointed
2954
* to by "ptin". The pointer is advanced to that character.
2956
char seenextchar(char **ptin)
2960
/* skip leading blanks */
2962
while (*pt == ' ' || *pt == '\t') pt++;
2967
/******************** INFINITE STRING PACKAGE ********************/
2970
* this package provides temporary storage while building an arbitrarily
2971
* large string in sequential order. The first routine called must be
2972
* "initinfstr" followed by any number of calls to "addtoinfstr" or
2973
* "addstringtoinfstr" to add a character or a string to the end
2974
* of the string. When the string is built, a call to "returninfstr"
2975
* produces the entire string so far. The routines "initinfstr",
2976
* "addtoinfstr" and "addstringtoinfstr" return nonzero upon error.
2980
* routine to initialize a new infinite string
2982
BOOLEAN initinfstr(void)
2988
for(i=0; i<INFSTRCOUNT; i++)
2990
db_infstrings[i].infstr = (char *)emalloc((INFSTRDEFAULT+1), db_cluster);
2991
if (db_infstrings[i].infstr == 0)
2993
(void)db_error(DBNOMEM|DBINITINFSTR);
2996
db_infstrings[i].infstrlength = INFSTRDEFAULT;
2997
db_infstrings[i].infstrinuse = 0;
3000
db_infstrstackpos = -1;
3001
db_infstrpointer = 0;
3004
/* save any current infinite string on the stack */
3005
if (db_infstrstackpos >= INFSTRCOUNT)
3007
(void)db_error(DBRECURSIVE|DBINITINFSTR);
3010
if (db_infstrstackpos >= 0)
3011
db_infstrstackptr[db_infstrstackpos] = db_curinf;
3012
db_infstrstackpos++;
3014
/* grab a new infinite string and initialize it */
3015
for(i=0; i<INFSTRCOUNT; i++)
3017
db_curinf = &db_infstrings[db_infstrpointer % INFSTRCOUNT];
3019
if (db_curinf->infstrinuse == 0) break;
3021
if (i >= INFSTRCOUNT)
3023
(void)db_error(DBRECURSIVE|DBINITINFSTR);
3026
db_curinf->infstrptr = 0;
3027
db_curinf->infstrinuse = 1;
3028
db_curinf->infstr[db_curinf->infstrptr] = 0;
3032
BOOLEAN addtoinfstr(char ch)
3036
if (db_curinf == NOINFSTR)
3038
(void)db_error(DBBADOBJECT|DBADDTOINFSTR);
3041
if (db_curinf->infstrptr >= db_curinf->infstrlength)
3043
str = (char *)emalloc((db_curinf->infstrlength*2+1), db_cluster);
3046
(void)db_error(DBNOMEM|DBADDTOINFSTR);
3049
db_curinf->infstrlength *= 2;
3050
(void)strcpy(str, db_curinf->infstr);
3051
efree(db_curinf->infstr);
3052
db_curinf->infstr = str;
3054
db_curinf->infstr[db_curinf->infstrptr++] = ch;
3055
db_curinf->infstr[db_curinf->infstrptr] = 0;
3059
BOOLEAN addstringtoinfstr(char *pp)
3062
REGISTER INTBIG l, i, ori;
3064
if (db_curinf == NOINFSTR)
3066
(void)db_error(DBBADOBJECT|DBADDSTRINGTOINFSTR);
3069
if (pp == 0) l = 0; else
3071
if (db_curinf->infstrptr+l >= db_curinf->infstrlength)
3073
ori = db_curinf->infstrlength;
3074
while (db_curinf->infstrptr+l >= db_curinf->infstrlength)
3075
db_curinf->infstrlength *= 2;
3076
str = (char *)emalloc((db_curinf->infstrlength+1), db_cluster);
3079
db_curinf->infstrlength = ori;
3080
(void)db_error(DBNOMEM|DBADDSTRINGTOINFSTR);
3083
(void)strcpy(str, db_curinf->infstr);
3084
efree(db_curinf->infstr);
3085
db_curinf->infstr = str;
3087
for(i=0; i<l; i++) db_curinf->infstr[db_curinf->infstrptr++] = pp[i];
3088
db_curinf->infstr[db_curinf->infstrptr] = 0;
3093
* Routine to do a variable-arguments "sprintf" to line "line" which
3096
void evsnprintf(char *line, INTBIG len, char *msg, va_list ap)
3098
#ifdef HAVE_VSNPRINTF
3099
(void)vsnprintf(line, len-1, msg, ap);
3102
(void)_vsnprintf(line, len-1, msg, ap);
3104
(void)vsprintf(line, msg, ap);
3109
BOOLEAN formatinfstr(char *msg, ...)
3115
evsnprintf(line, 8192, msg, ap);
3117
return(addstringtoinfstr(line));
3120
char *returninfstr(void)
3122
REGISTER char *retval;
3124
if (db_curinf == NOINFSTR)
3126
(void)db_error(DBBADOBJECT|DBRETURNINFSTR);
3130
/* get the inifinite string */
3131
retval = db_curinf->infstr;
3132
db_curinf->infstrinuse = 0;
3134
/* if stacked, unstack */
3135
db_infstrstackpos--;
3136
if (db_infstrstackpos >= 0)
3137
db_curinf = db_infstrstackptr[db_infstrstackpos];
3141
/****************************** FILES IN FACETS ******************************/
3152
* Routine to create an object for gathering arrays of strings.
3153
* Returns a pointer that can be used with "addtostringarray", "keepstringarray", "stringarraytotextfacet", and
3155
* Returns zero one error.
3157
void *newstringarray(CLUSTER *cluster)
3161
sa = (STRINGARRAY *)emalloc(sizeof (STRINGARRAY), cluster);
3162
if (sa == 0) return(0);
3163
sa->stringlimit = 0;
3164
sa->stringcount = 0;
3165
sa->cluster = cluster;
3169
void killstringarray(void *vsa)
3173
sa = (STRINGARRAY *)vsa;
3174
if (sa == 0) return;
3176
if (sa->stringlimit > 0) efree((char *)sa->strings);
3180
void clearstrings(void *vsa)
3185
sa = (STRINGARRAY *)vsa;
3186
if (sa == 0) return;
3187
for(i=0; i<sa->stringcount; i++) efree(sa->strings[i]);
3188
sa->stringcount = 0;
3191
void addtostringarray(void *vsa, char *string)
3193
REGISTER char **newbuf;
3194
REGISTER INTBIG i, newlimit;
3197
sa = (STRINGARRAY *)vsa;
3198
if (sa == 0) return;
3199
if (sa->stringcount >= sa->stringlimit)
3201
newlimit = sa->stringlimit * 2;
3202
if (newlimit <= 0) newlimit = 10;
3203
if (newlimit < sa->stringcount) newlimit = sa->stringcount;
3204
newbuf = (char **)emalloc(newlimit * (sizeof (char *)), sa->cluster);
3205
if (newbuf == 0) return;
3206
for(i=0; i<sa->stringcount; i++) newbuf[i] = sa->strings[i];
3207
if (sa->stringlimit > 0) efree((char *)sa->strings);
3208
sa->strings = newbuf;
3209
sa->stringlimit += 10;
3211
if (allocstring(&sa->strings[sa->stringcount], string, sa->cluster)) return;
3216
* routine called when done adding lines to string array "vsa". The collection of lines is
3217
* stored in the "FACET_message" variable on the facet "np". It is made permanent if
3218
* "permanent" is true.
3220
void stringarraytotextfacet(void *vsa, NODEPROTO *np, BOOLEAN permanent)
3223
REGISTER INTBIG type;
3225
sa = (STRINGARRAY *)vsa;
3226
if (sa == 0) return;
3227
if (sa->stringcount <= 0) return;
3228
type = VSTRING|VISARRAY|(sa->stringcount<<VLENGTHSH);
3229
if (!permanent) type |= VDONTSAVE;
3230
(void)setvalkey((INTBIG)np, VNODEPROTO, el_facet_message_key, (INTBIG)sa->strings, type);
3234
* routine called when done adding lines to string array "vsa". The collection of lines is
3237
char **getstringarray(void *vsa, INTBIG *count)
3241
sa = (STRINGARRAY *)vsa;
3242
if (sa == 0) { *count = 0; return(0); }
3243
*count = sa->stringcount;
3244
return(sa->strings);
3247
/************************* TIME HANDLING *************************/
3250
* Time functions are centralized here to account for different time
3251
* systems on different computers.
3255
* Routine to return the current time in seconds since January 1, 1970.
3257
UINTBIG getcurrenttime(void)
3261
(void)time(&curtime);
3262
curtime -= machinetimeoffset();
3267
* Routine to convert the time "curtime" to a string describing the date.
3268
* This string does *NOT* have a carriage-return after it.
3270
char *timetostring(UINTBIG curtime)
3272
static char timebuf[30];
3274
curtime += machinetimeoffset();
3275
strcpy(timebuf, ctime((time_t *)&curtime));
3281
* Routine to parse the time in "curtime" and convert it to the year,
3282
* month (0 = January), and day of month.
3284
void parsetime(UINTBIG curtime, INTBIG *year, INTBIG *month, INTBIG *mday,
3285
INTBIG *hour, INTBIG *minute, INTBIG *second)
3289
curtime += machinetimeoffset();
3290
tm = localtime((time_t *)&curtime);
3291
*month = tm->tm_mon;
3292
*mday = tm->tm_mday;
3293
*year = tm->tm_year + 1900;
3294
*hour = tm->tm_hour;
3295
*minute = tm->tm_min;
3296
*second = tm->tm_sec;
3299
INTBIG parsemonth(char *monthname)
3301
REGISTER INTBIG mon;
3302
static char *name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
3303
"Aug", "Sep", "Oct", "Nov", "Dec"};
3305
for (mon=0; mon<12; mon++)
3306
if (namesame(name[mon], monthname) == 0) break;
3307
if (mon < 12) return(mon+1);
3311
/******************** SUBROUTINES FOR FILE I/O ****************/
3313
INTBIG setupfiletype(char *extension, char *winfilter, INTBIG mactype, BOOLEAN binary,
3314
char *shortname, char *longname)
3319
oldcount = db_filetypecount;
3321
newlist = (FILETYPES *)emalloc(db_filetypecount * (sizeof (FILETYPES)), db_cluster);
3322
for(i=0; i<oldcount; i++)
3324
newlist[i].extension = db_filetypeinfo[i].extension;
3325
newlist[i].winfilter = db_filetypeinfo[i].winfilter;
3326
newlist[i].mactype = db_filetypeinfo[i].mactype;
3327
newlist[i].binary = db_filetypeinfo[i].binary;
3328
newlist[i].shortname = db_filetypeinfo[i].shortname;
3329
newlist[i].longname = db_filetypeinfo[i].longname;
3331
if (oldcount > 0) efree((char *)db_filetypeinfo);
3332
db_filetypeinfo = newlist;
3333
(void)allocstring(&db_filetypeinfo[oldcount].extension, extension, db_cluster);
3334
(void)allocstring(&db_filetypeinfo[oldcount].winfilter, winfilter, db_cluster);
3335
db_filetypeinfo[oldcount].mactype = mactype;
3336
db_filetypeinfo[oldcount].binary = binary;
3337
(void)allocstring(&db_filetypeinfo[oldcount].shortname, shortname, db_cluster);
3338
(void)allocstring(&db_filetypeinfo[oldcount].longname, longname, db_cluster);
3343
* Routine to return the extension, short name, and long name of file type "filetype".
3345
void describefiletype(INTBIG filetype, char **extension, char **winfilter, INTBIG *mactype,
3346
BOOLEAN *binary, char **shortname, char **longname)
3348
REGISTER INTBIG index;
3350
index = filetype & FILETYPE;
3351
*extension = db_filetypeinfo[index].extension;
3352
*winfilter = db_filetypeinfo[index].winfilter;
3353
*mactype = db_filetypeinfo[index].mactype;
3354
*binary = db_filetypeinfo[index].binary;
3355
*shortname = db_filetypeinfo[index].shortname;
3356
*longname = db_filetypeinfo[index].longname;
3360
* Routine to return the filetype associated with short name "shortname".
3361
* Returns zero on error.
3363
INTBIG getfiletype(char *shortname)
3367
for(i=0; i<db_filetypecount; i++)
3368
if (namesame(shortname, db_filetypeinfo[i].shortname) == 0) return(i);
3373
* routine to find the actual file name in a path/file specification. The
3374
* input path name is in "file" and a pointer to the file name is returned.
3375
* Note that this routine handles the directory separating characters for
3376
* all operating systems ('\' on Windows, '/' on UNIX, and ':' on Macintosh)
3377
* because the strings may be from other systems.
3379
char *skippath(char *file)
3383
pt = &file[strlen(file)-1];
3384
while (pt != file && pt[-1] != '\\' && pt[-1] != '/' && pt[-1] != ':') pt--;
3389
* routine to return the size of file whose stream is "f"
3391
INTBIG filesize(FILE *f)
3393
INTBIG savepos, endpos;
3396
(void)fseek(f, 0L, 2); /* SEEK_END */
3398
(void)fseek(f, savepos, 0); /* SEEK_SET */
3403
* routine to open a file whose name is "file". The type of the file is in "filetype" (whose
3404
* possible valyes are listed in "global.h"). The file may be in the directory "otherdir".
3405
* The stream is returned (NULL if it can't be found), and the true name of the file (with
3406
* extensions and proper directory) is returned in "truename".
3408
FILE *xopen(char *file, INTBIG filetype, char *otherdir, char **truename)
3414
char rarg[3], *extension, *winfilter, *shortname, *longname;
3416
/* determine extension to use */
3417
describefiletype(filetype&FILETYPE, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3419
/* determine argument to "fopen" */
3420
if ((filetype&FILETYPEWRITE) != 0) strcpy(rarg, "w"); else
3421
if ((filetype&FILETYPEAPPEND) != 0) strcpy(rarg, "a"); else
3423
if (binary != 0) strcat(rarg, "b");
3425
/* remove "~" from the file name */
3426
pp = truepath(file);
3428
/* add the extension and look for the file */
3429
if (*extension != 0)
3431
f = db_tryfile(pp, rarg, extension, (char *)0, truename);
3432
if (f != NULL) return(f);
3435
/* try the file directly */
3436
f = db_tryfile(pp, rarg, (char *)0, (char *)0, truename);
3437
if (f != NULL) return(f);
3439
/* if no other directory given, stop now */
3440
if (otherdir == 0 || *otherdir == 0) return(NULL);
3442
/* if directory path is in file name, stop now */
3443
if (*pp == '/') return(NULL);
3445
/* try the file in the other directory with the extension */
3446
f = db_tryfile(pp, rarg, extension, otherdir, truename);
3447
if (f != NULL) return(f);
3449
/* try the file in the other directory with no extension */
3450
f = db_tryfile(pp, rarg, (char *)0, otherdir, truename);
3451
if (f != NULL) return(f);
3456
* routine to try to find a file with name "pp", read with argument "rarg",
3457
* with extension "extension" (if it is nonzero) and in directory "otherdir"
3458
* (if it is nonzero). Returns the file descriptor, and a pointer to the
3459
* actual file name in "truename"
3461
FILE *db_tryfile(char *pp, char *rarg, char *extension, char *otherdir, char **truename)
3463
REGISTER INTBIG len;
3466
len = strlen(pp) + 1;
3467
if (extension != 0) len += strlen(extension) + 1;
3468
if (otherdir != 0) len += strlen(otherdir) + 1;
3469
if (len > db_tryfilenamelen)
3471
if (db_tryfilenamelen != 0) efree(db_tryfilename);
3472
db_tryfilenamelen = 0;
3473
db_tryfilename = (char *)emalloc(len, db_cluster);
3474
if (db_tryfilename == 0) return(NULL);
3475
db_tryfilenamelen = len;
3477
db_tryfilename[0] = 0;
3480
(void)strcat(db_tryfilename, otherdir);
3481
len = strlen(db_tryfilename);
3482
if (db_tryfilename[len-1] != DIRSEP)
3484
db_tryfilename[len++] = DIRSEP;
3485
db_tryfilename[len] = 0;
3488
(void)strcat(db_tryfilename, pp);
3491
(void)strcat(db_tryfilename, ".");
3492
(void)strcat(db_tryfilename, extension);
3495
/* now extend this to the full path name */
3496
pt = fullfilename(db_tryfilename);
3497
len = strlen(pt) + 1;
3498
if (len > db_tryfilenamelen)
3500
efree(db_tryfilename);
3501
db_tryfilenamelen = 0;
3502
db_tryfilename = (char *)emalloc(len, db_cluster);
3503
if (db_tryfilename == 0) return(NULL);
3504
db_tryfilenamelen = len;
3506
strcpy(db_tryfilename, pt);
3507
*truename = db_tryfilename;
3508
return(fopen(db_tryfilename, rarg));
3512
* Routine to create the file "name" and return a stream pointer. "filetype" is the type
3513
* of file being created (from the table in "global.h"). If "prompt" is zero, the path
3514
* is already fully set and the user should not be further querried. Otherwise,
3515
* "prompt" is the string to use when describing this file (and the final name selected
3516
* by the user is returned in "truename"). The routine returns zero on error. However,
3517
* to differentiate errors in file creation from user aborts, the "truename" is set to zero
3518
* if the user aborts the command.
3520
FILE *xcreate(char *name, INTBIG filetype, char *prompt, char **truename)
3523
REGISTER char *pt, *next;
3524
char warg[3], *extension, *winfilter, *shortname, *longname;
3525
static char truenamelocal[256];
3529
/* determine extension to use */
3530
describefiletype(filetype&FILETYPE, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3532
pt = truepath(name);
3533
if (prompt != 0 && (us_tool->toolstate&USEDIALOGS) != 0)
3535
next = (char *)fileselect(prompt, filetype | FILETYPEWRITE, pt);
3536
if (next == 0 || *next == 0)
3538
if (truename != 0) *truename = 0;
3541
setdefaultcursortype(NULLCURSOR); /* the hourglass cursor */
3546
(void)strcpy(truenamelocal, pt);
3547
*truename = truenamelocal;
3550
/* determine argument to "fopen" */
3552
if (binary) strcat(warg, "b");
3553
f = fopen(pt, warg);
3557
void mac_settypecreator(char*, INTBIG, INTBIG);
3559
if (mactype == 'TEXT')
3561
mac_settypecreator(pt, 'TEXT', 'ttxt');
3564
mac_settypecreator(pt, mactype, 'Elec');
3572
* Routine to append to the file "name" and return a stream pointer
3574
FILE *xappend(char *name)
3576
return(fopen(truepath(name), "a"));
3580
* Routine to close stream "f"
3582
void xclose(FILE *f)
3588
* Routine to flush stream "f"
3590
void xflushbuf(FILE *f)
3596
* Routine to report the EOF condition on stream "f"
3598
BOOLEAN xeof(FILE *f)
3600
if (feof(f) != 0) return(TRUE);
3605
* Routine to seek to position "pos", nature "nat", on stream "f"
3607
void xseek(FILE *f, INTBIG pos, INTBIG nat)
3613
* Routine to return the current position in stream "f"
3615
INTBIG xtell(FILE *f)
3621
* Routine to write the formatted message "s" with parameters "p1" through "p9"
3624
void xprintf(FILE *f, char *s, ...)
3629
(void)vfprintf(f, s, ap);
3634
* Routine to get the next character in stream "f"
3636
INTSML xgetc(FILE *f)
3642
* Routine to "unget" the character "c" back to stream "f"
3644
void xungetc(char c, FILE *f)
3650
* Routine to put the character "c" into stream "f"
3652
void xputc(char c, FILE *f)
3658
* Routine to put the string "s" into stream "f"
3660
void xputs(char *s, FILE *f)
3666
* Routine to read "count" elements of size "size" from stream "f" into the buffer
3667
* at "buf". Returns the number of objects read (ideally, "size").
3669
INTBIG xfread(char *buf, INTBIG size, INTBIG count, FILE *f)
3671
#if 0 /* limits reads to BUFSIZE */
3672
REGISTER INTBIG amtjustread, amttoread, totalamtread;
3677
amttoread = mini(count, BUFSIZ/size);
3678
amtjustread = fread(buf, size, amttoread, f);
3679
totalamtread += amtjustread;
3680
if (amtjustread != amttoread)
3682
if (ferror(f) != 0) clearerr(f); else
3684
if (feof(f) != 0) break;
3687
count -= amtjustread;
3688
buf += amtjustread*size;
3690
return(totalamtread);
3692
REGISTER INTBIG ret;
3696
ret = fread(buf, size, count, f);
3697
if (ret == count || feof(f) != 0) break;
3705
* Routine to write "count" elements of size "size" to stream "f" from the buffer
3706
* at "buf". Returns the number of bytes written.
3708
INTBIG xfwrite(char *buf, INTBIG size, INTBIG count, FILE *f)
3710
REGISTER INTBIG ret;
3714
ret = fwrite(buf, size, count, f);
3715
if (ret == count || feof(f) != 0) break;
3722
* routine to read a line of text from a file. The file is in stream "file"
3723
* and the text is placed in the array "line" which is only "limit" characters
3724
* long. The routine returns false if sucessful, true if end-of-file is
3727
BOOLEAN xfgets(char *line, INTBIG limit, FILE *file)
3730
REGISTER INTBIG c, total;
3739
if (pp == line) return(TRUE);
3743
if (*pp == '\n' || *pp == '\r') break;
3745
if ((++total) >= limit) break;
3751
/******************** SUBROUTINES FOR ENCRYPTION ****************/
3754
* A one-rotor machine designed along the lines of Enigma but considerably trivialized
3756
# define ROTORSZ 256 /* a power of two */
3757
# define MASK (ROTORSZ-1)
3758
void myencrypt(char *text, char *key)
3760
INTBIG ic, i, k, temp, n1, n2, nr1, nr2;
3763
char *pt, t1[ROTORSZ], t2[ROTORSZ], t3[ROTORSZ], deck[ROTORSZ];
3764
static char readable[ROTORSZ] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-";
3766
/* first setup the machine */
3768
for (i=0; i<13; i++) seed = seed*key[i] + i;
3769
for(i=0; i<ROTORSZ; i++)
3775
for(i=0; i<ROTORSZ; i++)
3777
seed = 5*seed + key[i%13];
3778
random = seed % 65521;
3780
ic = (random&MASK) % (k+1);
3784
t1[ic] = (char)temp;
3785
if (t3[k] != 0) continue;
3786
ic = (random&MASK) % k;
3787
while (t3[ic] != 0) ic = (ic+1) % k;
3791
for(i=0; i<ROTORSZ; i++) t2[t1[i]&MASK] = (char)i;
3793
/* now run the machine */
3797
for(pt = text; *pt; pt++)
3799
nr1 = deck[n1]&MASK;
3800
nr2 = deck[nr1]&MASK;
3801
i = t2[(t3[(t1[(*pt+nr1)&MASK]+nr2)&MASK]-nr2)&MASK]-nr1;
3802
*pt = readable[i&63];
3808
if (n2 == ROTORSZ) n2 = 0;
3809
db_shuffle(deck, key);
3814
void db_shuffle(char *deck, char *key)
3816
INTBIG i, ic, k, temp;
3818
static INTBIG seed = 123;
3820
for(i=0; i<ROTORSZ; i++)
3822
seed = 5*seed + key[i%13];
3823
random = seed % 65521;
3825
ic = (random&MASK) % (k+1);
3828
deck[ic] = (char)temp;