~ubuntu-branches/ubuntu/intrepid/electric/intrepid

« back to all changes in this revision

Viewing changes to src/db/dbtext.c

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2008-07-23 02:09:53 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080723020953-1gmnv7q2wpsdbnop
Tags: 8.07-0ubuntu1
* New Upstream version. Please check changelog for details. (LP: #242720)
* debian/control
  - Add build dependencies *-jdk, cdbs and bsh.
  - Remove build dependency dpatch. We will be using CDBS simple patchsys.
  - Refreshed runtime dependencies to default-jre | java2-runtime and bsh.
  - Added home page field.
  - Standard version 3.8.0.
  - Modify Maintainer value to match the DebianMaintainerField
    specification.
  - Changed email address for original maintainer to indicate who has
    refreshed the packaging.
* debian/rules
  - Revamped to use cdbs.
  - Added get-orig-source target.
* debian/patches
  - 00list, 02_sensible-browser.dpatch, 01_errors-numbers.dpatch,
    03_manpage.dpatch - Deleted, not relevant anymore.
  - 01_fix_build_xml.patch - Patch to fix the build.xml.
* debian/ant.properties
  - File to set various compilation properties.
* debian/electric.1
  - Remove the entry that causes lintian warning.
* debian/electric.desktop
  - Change as suggested by desktop-file-validate.
* debian/electric.docs
  - Updated as per changes in file names.
* debian/electric.svg
  - Name changed from electric_icon.svg.
* debian/install
  - Added appropriate locations for jar file, desktop file and wrapper shell
    script.
* debian/README.source
  - Added to comply with standards version 3.8.0.
* debian/TODO.Debian
  - Name changed form TODO.
* debain/wrapper/electric
  - Wrapper shell script to launch the application.
* debian/manpages
  - Added for installation of manpage.
* debian/watch
  - Updated to match jar files instead of older tar.gz files.
* debian/dirs
  - Removed, not needed anymore.
* debian/{electric.doc-base, electric.examples, substvars}
  - Removed, not relevant anymore.
* debian/*.debhelper
  - Removed auto generated files. Not relevant anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Electric(tm) VLSI Design System
3
 
 *
4
 
 * File: dbtext.c
5
 
 * Database text and file support module
6
 
 * Written by: Steven M. Rubin, Static Free Software
7
 
 *
8
 
 * Copyright (c) 2000 Static Free Software.
9
 
 *
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.
14
 
 *
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.
19
 
 *
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.
24
 
 *
25
 
 * Static Free Software
26
 
 * 4119 Alpine Road
27
 
 * Portola Valley, California 94028
28
 
 * info@staticfreesoft.com
29
 
 */
30
 
 
31
 
#include "global.h"
32
 
#include "database.h"
33
 
#include "egraphics.h"
34
 
#include "edialogs.h"
35
 
#include "usr.h"
36
 
#include "tecgen.h"
37
 
#include <time.h>
38
 
#ifdef TM_IN_SYS_TIME
39
 
#  include <sys/time.h>
40
 
#endif
41
 
 
42
 
#define NUMDESCRIPTIONBUFS 4
43
 
 
44
 
static char  *db_keywordbuffer;
45
 
static INTBIG db_keywordbufferlength = 0;
46
 
 
47
 
/* working memory for "db_tryfile()" */
48
 
static char  *db_tryfilename;
49
 
static INTBIG db_tryfilenamelen = 0;
50
 
 
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};
55
 
 
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};
60
 
 
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};
65
 
 
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};
70
 
 
71
 
/* working memory for "makeplural()" */
72
 
static INTBIG db_pluralbufsize = 0;
73
 
static char  *db_pluralbuffer;
74
 
 
75
 
/* working memory for types of files */
76
 
typedef struct
77
 
{
78
 
        char   *extension;
79
 
        char   *winfilter;
80
 
        INTBIG  mactype;
81
 
        BOOLEAN binary;
82
 
        char   *shortname;
83
 
        char   *longname;
84
 
} FILETYPES;
85
 
 
86
 
static INTBIG     db_filetypecount = 0;
87
 
static FILETYPES *db_filetypeinfo;
88
 
 
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)
93
 
typedef struct
94
 
{
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 */
99
 
} INFSTR;
100
 
 
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 */
107
 
 
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);
115
 
 
116
 
/*
117
 
 * Routine to free all memory associated with this module.
118
 
 */
119
 
void db_freetextmemory(void)
120
 
{
121
 
        REGISTER INTBIG i;
122
 
 
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);
128
 
 
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]);
137
 
 
138
 
        /* free file type memory */
139
 
        for(i=0; i<db_filetypecount; i++)
140
 
        {
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);
145
 
        }
146
 
        if (db_filetypecount > 0) efree((char *)db_filetypeinfo);
147
 
}
148
 
 
149
 
/************************* STRING PARSING *************************/
150
 
 
151
 
/*
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
155
 
 * the string "pp".
156
 
 */
157
 
INTBIG atola(char *pp)
158
 
{
159
 
        REGISTER INTBIG hipart, lonum, loden, retval, units;
160
 
        REGISTER INTBIG neg;
161
 
        REGISTER char *ptr;
162
 
        double scale;
163
 
 
164
 
        /* determine default scale amount */
165
 
        ptr = pp;
166
 
 
167
 
        if (*ptr == '-') { neg = -1;   ptr++; } else neg = 1;
168
 
        hipart = atoi(ptr);
169
 
        while (isdigit(*ptr)) ptr++;
170
 
        lonum = 0;   loden = 1;
171
 
        if (*ptr == '.')
172
 
        {
173
 
                ptr++;
174
 
                while (isdigit(*ptr)) { lonum = lonum * 10 + (*ptr++ - '0'); loden *= 10; }
175
 
        }
176
 
 
177
 
        /* determine units */
178
 
        units = el_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;
186
 
 
187
 
        /* convert to database units */
188
 
        scale = db_getcurrentscale(el_units&INTERNALUNITS, units);
189
 
        retval = rounddouble(((double)hipart) * scale + ((double)lonum)*scale / ((double)loden));
190
 
        return(retval*neg);
191
 
}
192
 
 
193
 
/*
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
197
 
 * the string "pp".
198
 
 */
199
 
INTBIG atofr(char *pp)
200
 
{
201
 
        REGISTER INTBIG i, j, k;
202
 
        REGISTER INTBIG n;
203
 
 
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);
208
 
        j = 0;   k = 1;
209
 
        while (isdigit(*pp)) { j = j * 10 + (*pp++ - '0'); k *= 10; }
210
 
        i += (j*WHOLE + k/2)/k;
211
 
        return(i*n);
212
 
}
213
 
 
214
 
/* routine to convert ascii to integer */
215
 
INTBIG myatoi(char *pp)
216
 
{
217
 
        REGISTER INTBIG num;
218
 
        REGISTER INTBIG base, sign;
219
 
 
220
 
        base = 10;
221
 
        num = 0;
222
 
        sign = 1;
223
 
        if (*pp == '-')
224
 
        {
225
 
                pp++;
226
 
                sign = -1;
227
 
        }
228
 
        if (*pp == '0')
229
 
        {
230
 
                pp++;
231
 
                base = 8;
232
 
                if (*pp == 'x')
233
 
                {
234
 
                        pp++;
235
 
                        base = 16;
236
 
                }
237
 
        }
238
 
        for(;;)
239
 
        {
240
 
                if ((*pp >= 'a' && *pp <= 'f') || (*pp >= 'A' && *pp <= 'F'))
241
 
                {
242
 
                        if (base != 16) break;
243
 
                        num = num * 16;
244
 
                        if (*pp >= 'a' && *pp <= 'f') num += *pp++ - 'a' + 10; else
245
 
                                num += *pp++ - 'A' + 10;
246
 
                        continue;
247
 
                } else if (isdigit(*pp))
248
 
                {
249
 
                        if (*pp >= '8' && base == 8) break;
250
 
                        num = num * base + *pp++ - '0';
251
 
                        continue;
252
 
                }
253
 
                break;
254
 
        }
255
 
        return(num * sign);
256
 
}
257
 
 
258
 
/*
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:
262
 
 *    Windows: "%I64d"
263
 
 *    Sun:     "%PRIx64"
264
 
 *    Linux:   "%lld"
265
 
 */
266
 
char *hugeinttoa(INTHUGE a)
267
 
{
268
 
        static char ret[NUMDESCRIPTIONBUFS][40];
269
 
        static INTBIG which = 0;
270
 
        REGISTER char *curbuf, digit;
271
 
        REGISTER INTBIG i, neg;
272
 
 
273
 
        curbuf = ret[which++];
274
 
        if (which >= NUMDESCRIPTIONBUFS) which = 0;
275
 
 
276
 
        if (a >= 0) neg = 0; else
277
 
        {
278
 
                neg = 1;
279
 
                a = -a;
280
 
        }
281
 
 
282
 
        curbuf[i=39] = 0;
283
 
        while (i > 0)
284
 
        {
285
 
                digit = (char)(a % 10);
286
 
                curbuf[--i] = '0' + digit;
287
 
                a /= 10;
288
 
                if (a == 0) break;
289
 
        }
290
 
        if (neg != 0)
291
 
                curbuf[--i] = '-';
292
 
        return(&curbuf[i]);
293
 
}
294
 
 
295
 
char *explainduration(float duration)
296
 
{
297
 
        static char elapsed[200];
298
 
        char temp[50];
299
 
        INTBIG hours, minutes;
300
 
 
301
 
        elapsed[0] = 0;
302
 
        if (duration >= 3600.0)
303
 
        {
304
 
                hours = (INTBIG)(duration / 3600.0f);
305
 
                duration -= (float)(hours * 3600);
306
 
                sprintf(temp, "%ld hours, ", hours);
307
 
                strcat(elapsed, temp);
308
 
        }
309
 
        if (duration >= 60.0)
310
 
        {
311
 
                minutes = (INTBIG)(duration / 60.0f);
312
 
                duration -= (float)(minutes * 60);
313
 
                sprintf(temp, "%ld minutes, ", minutes);
314
 
                strcat(elapsed, temp);
315
 
        }
316
 
        sprintf(temp, "%g seconds", duration);
317
 
        strcat(elapsed, temp);
318
 
        return(elapsed);
319
 
}
320
 
 
321
 
/*
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)
333
 
 */
334
 
void parseelectricversion(char *version, INTBIG *major, INTBIG *minor, INTBIG *detail)
335
 
{
336
 
        REGISTER char *pt;
337
 
 
338
 
        /* parse the version fields */
339
 
        pt = version;
340
 
        *major = atoi(pt);
341
 
        while (isdigit(*pt) != 0) pt++;
342
 
        if (*pt++ != '.') { *minor = *detail = 0;   return; }
343
 
        *minor = atoi(pt);
344
 
        while (isdigit(*pt) != 0) pt++;
345
 
        if (*pt == 0) { *detail = 999;   return; }
346
 
        if (*pt == '.')
347
 
        {
348
 
                *detail = atoi(&pt[1]) + 1000;
349
 
        } else
350
 
        {
351
 
                *detail = 0;
352
 
                while (isalpha(*pt))
353
 
                {
354
 
                        *detail = (*detail * 26) + tolower(*pt) - 'a' + 1;
355
 
                        pt++;
356
 
                }
357
 
        }
358
 
#if 0           /* for debugging the version number */
359
 
        ttyputmsg("Version '%s' is numbered %ld.%ld.%ld", version, *major, *minor, *detail);
360
 
#endif
361
 
}
362
 
 
363
 
/*
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.
367
 
 */
368
 
NODEPROTO *getnodeproto(char *initline)
369
 
{
370
 
        REGISTER NODEPROTO *np, *onp;
371
 
        REGISTER CELL *c;
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;
377
 
 
378
 
        /* make a copy of the argument so that it can be modified */
379
 
        (void)initinfstr();
380
 
        (void)addstringtoinfstr(initline);
381
 
        line = returninfstr();
382
 
 
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
387
 
        {
388
 
                *pt = 0;
389
 
                t = gettechnology(line);
390
 
                if (t != NOTECHNOLOGY)
391
 
                {
392
 
                        tech = t;
393
 
                        saidtech++;
394
 
                }
395
 
                l = getlibrary(line);
396
 
                if (l != NOLIBRARY)
397
 
                {
398
 
                        lib = l;
399
 
                        saidlib++;
400
 
                }
401
 
                *pt++ = ':';
402
 
                line = pt;
403
 
        }
404
 
 
405
 
        /* try primitives in the technology */
406
 
        if (saidlib == 0 || saidtech != 0)
407
 
        {
408
 
                for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
409
 
                        if (namesame(line, np->primname) == 0) return(np);
410
 
        }
411
 
 
412
 
        /* look for version numbers and view types */
413
 
        for(pt = line; *pt != 0; pt++) if (*pt == ';' || *pt == '{') break;
414
 
        save = *pt;
415
 
        *pt = 0;
416
 
#ifdef HASHCELLNAMES
417
 
        c = db_findcellname(line, lib);
418
 
#else
419
 
        for(c = lib->firstcell; c != NOCELL; c = c->nextcell)
420
 
                if (namesame(line, c->cellname) == 0) break;
421
 
#endif
422
 
        *pt = (char)save;
423
 
        if (c == NOCELL) return(NONODEPROTO);
424
 
 
425
 
        wantversion = -1;
426
 
        wantview = el_unknownview;
427
 
        if (save == ';')
428
 
        {
429
 
                wantversion = myatoi(pt+1);
430
 
                for(pt++; *pt != 0; pt++) if (*pt == '{') break;
431
 
                save = *pt;
432
 
        }
433
 
        if (save == '{')
434
 
        {
435
 
                line = pt = (pt + 1);
436
 
                for(; *pt != 0; pt++) if (*pt == '}') break;
437
 
                if (*pt != '}') return(NONODEPROTO);
438
 
                *pt = 0;
439
 
                for(v = el_views; v != NOVIEW; v = v->nextview)
440
 
                        if (namesame(v->sviewname, line) == 0 || namesame(v->viewname, line) == 0) break;
441
 
                *pt = '}';
442
 
                if (v == NOVIEW) return(NONODEPROTO);
443
 
                wantview = v;
444
 
        }
445
 
 
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)
450
 
        {
451
 
                /* if a version number was specified, let that guide the search */
452
 
                if (wantversion > 0)
453
 
                {
454
 
                        for(np = c->firstincell; np != NONODEPROTO; np = np->nextincell)
455
 
                        {
456
 
                                for(onp = np->lastversion; onp != NONODEPROTO; onp = onp->lastversion)
457
 
                                        if (onp->version == wantversion) return(onp);
458
 
                        }
459
 
                }
460
 
 
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);
464
 
 
465
 
                /* take any view */
466
 
                np = c->firstincell;
467
 
                if (np == NONODEPROTO) return(NONODEPROTO);
468
 
        }
469
 
 
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);
474
 
        return(NONODEPROTO);
475
 
}
476
 
 
477
 
/*
478
 
 * routine to find cell "cellname".  Returns NOCELL if it cannot be found
479
 
 */
480
 
CELL *getcell(char *cellname)
481
 
{
482
 
        REGISTER CELL *cell;
483
 
#ifdef HASHCELLNAMES
484
 
        cell = db_findcellname(cellname, el_curlib);
485
 
        return(cell);
486
 
#else
487
 
        static COMCOMP db_cellp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
488
 
                NOBACKUP, 0, " \t", M_("cell"), 0};
489
 
        REGISTER INTBIG i, j;
490
 
 
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);
495
 
        return(NOCELL);
496
 
#endif
497
 
}
498
 
 
499
 
/*
500
 
 * routine to find technology "techname".  Returns NOTECHNOLOGY if it cannot
501
 
 * be found
502
 
 */
503
 
static COMCOMP db_technologyp = {NOKEYWORD, topoftechs, nexttechs, NOPARAMS,
504
 
        NOBACKUP, 0, " \t", M_("technology"), 0};
505
 
TECHNOLOGY *gettechnology(char *techname)
506
 
{
507
 
        REGISTER INTBIG i;
508
 
        REGISTER TECHNOLOGY *tech;
509
 
 
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);
515
 
}
516
 
 
517
 
/*
518
 
 * routine to find view "viewname".  Returns NOVIEW if it cannot be found
519
 
 */
520
 
static COMCOMP db_viewp = {NOKEYWORD, topofviews, nextviews, NOPARAMS,
521
 
        NOBACKUP, 0, " \t", M_("view"), 0};
522
 
VIEW *getview(char *viewname)
523
 
{
524
 
        REGISTER INTBIG i, j;
525
 
        REGISTER VIEW *v;
526
 
 
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);
531
 
        return(NOVIEW);
532
 
}
533
 
 
534
 
/*
535
 
 * routine to find network "netname" in facet "facet".  Returns NONETWORK
536
 
 * if it cannot be found
537
 
 */
538
 
NETWORK *getnetwork(char *netname, NODEPROTO *facet)
539
 
{
540
 
        REGISTER INTBIG i, k;
541
 
        REGISTER char *pt;
542
 
        REGISTER NETWORK *net;
543
 
 
544
 
        for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
545
 
        {
546
 
                pt = net->netname;
547
 
                for(k=0; k<net->namecount; k++)
548
 
                {
549
 
                        if (namesame(netname, pt) == 0) return(net);
550
 
                        pt += strlen(pt) + 1;
551
 
                }
552
 
        }
553
 
 
554
 
        /* see if a global name is specified */
555
 
        pt = _("Global");
556
 
        k = strlen(pt);
557
 
        if (namesamen(netname, pt, k) == 0 && netname[k] == '-')
558
 
        {
559
 
                for(i=0; i<facet->globalnetcount; i++)
560
 
                        if (namesame(&netname[k+1], facet->globalnetnames[i]) == 0)
561
 
                                return(facet->globalnetworks[i]);
562
 
        }
563
 
        return(NONETWORK);
564
 
}
565
 
 
566
 
/*
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.
570
 
 */
571
 
NETWORK *getcomplexnetwork(char *name, NODEPROTO *np)
572
 
{
573
 
        REGISTER INTBIG len, i, l, k, c1, c2, addr;
574
 
        REGISTER NETWORK *net;
575
 
        REGISTER char *pt;
576
 
 
577
 
        /* try the direct approach */
578
 
        net = getnetwork(name, np);
579
 
        if (net != NONETWORK) return(net);
580
 
 
581
 
        if (name[0] == 'N' && name[1] == 'E' && name[2] == 'T')
582
 
        {
583
 
                addr = atoi(&name[3]);
584
 
                for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
585
 
                        if (net == (NETWORK *)addr) return(net);
586
 
        }
587
 
 
588
 
        /* if the name ends with "NV", try removing that */
589
 
        len = strlen(name);
590
 
        if (name[len-2] == 'N' && name[len-1] == 'V')
591
 
        {
592
 
                name[len-2] = 0;
593
 
                net = getnetwork(name, np);
594
 
                name[len-2] = 'N';
595
 
                if (net != NONETWORK) return(net);
596
 
        }
597
 
 
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] == '(')
600
 
        {
601
 
                net = getnetwork(&name[2], np);
602
 
                if (net != NONETWORK) return(net);
603
 
        }
604
 
 
605
 
        /* if there are underscores, see if they match original names */
606
 
        for(pt = name; *pt != 0; pt++) if (*pt == '_') break;
607
 
        if (*pt != 0)
608
 
        {
609
 
                len = strlen(name);
610
 
                for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
611
 
                {
612
 
                        pt = net->netname;
613
 
                        for(k=0; k<net->namecount; k++)
614
 
                        {
615
 
                                l = strlen(pt);
616
 
                                if (l == len)
617
 
                                {
618
 
                                        for(i=0; i<len; i++)
619
 
                                        {
620
 
                                                c1 = tolower(name[i]);
621
 
                                                c2 = tolower(pt[i]);
622
 
                                                if (c1 == c2) continue;
623
 
                                                if (c1 == '_' && !isalnum(c2)) continue;
624
 
                                                break;
625
 
                                        }
626
 
                                        if (i >= len) return(net);
627
 
                                }
628
 
                                pt += strlen(pt) + 1;
629
 
                        }
630
 
                }
631
 
        }
632
 
        return(NONETWORK);
633
 
}
634
 
 
635
 
/*
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.
639
 
 */
640
 
ARCPROTO *getarcproto(char *initline)
641
 
{
642
 
        REGISTER ARCPROTO *ap;
643
 
        REGISTER TECHNOLOGY *tech, *t;
644
 
        REGISTER char *pt, *line;
645
 
 
646
 
        /* make a copy of the argument so that it can be modified */
647
 
        (void)initinfstr();
648
 
        (void)addstringtoinfstr(initline);
649
 
        line = returninfstr();
650
 
 
651
 
        tech = el_curtech;
652
 
        for(pt = line; *pt != 0; pt++) if (*pt == ':') break;
653
 
        if (*pt != ':') pt = line; else
654
 
        {
655
 
                *pt = 0;
656
 
                t = gettechnology(line);
657
 
                if (t != NOTECHNOLOGY) tech = t;
658
 
                *pt++ = ':';
659
 
        }
660
 
        for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
661
 
                if (namesame(pt, ap->protoname) == 0) return(ap);
662
 
        return(NOARCPROTO);
663
 
}
664
 
 
665
 
/*
666
 
 * routine to find portproto "portname" on facet "facet".  Returns NOPORTPROTO
667
 
 * if it cannot be found
668
 
 */
669
 
PORTPROTO *getportproto(NODEPROTO *facet, char *portname)
670
 
{
671
 
        REGISTER PORTPROTO *pp;
672
 
 
673
 
        for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
674
 
                if (namesame(portname, pp->protoname) == 0) return(pp);
675
 
        return(NOPORTPROTO);
676
 
}
677
 
 
678
 
/*
679
 
 * routine to find library "libname".  Returns NOLIBRARY if it cannot be found
680
 
 */
681
 
LIBRARY *getlibrary(char *libname)
682
 
{
683
 
        REGISTER LIBRARY *lib;
684
 
 
685
 
        for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
686
 
                if (namesame(libname, lib->libname) == 0) return(lib);
687
 
        return(NOLIBRARY);
688
 
}
689
 
 
690
 
/*
691
 
 * routine to find tool "toolname".  Returns NOTOOL if it cannot be found
692
 
 */
693
 
TOOL *gettool(char *toolname)
694
 
{
695
 
        REGISTER INTBIG i;
696
 
 
697
 
        for(i=0; i<el_maxtools; i++)
698
 
                if (namesame(toolname, el_tools[i].toolname) == 0) return(&el_tools[i]);
699
 
        return(NOTOOL);
700
 
}
701
 
 
702
 
static struct
703
 
{
704
 
        char  *name;
705
 
        char  *symbol;
706
 
        INTBIG value;
707
 
} db_colors[] =
708
 
{
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},
735
 
        {NULL, NULL, 0}
736
 
};
737
 
 
738
 
/*
739
 
 * Routine to convert the color name "colorname" to a color.  Returns negative on error.
740
 
 */
741
 
INTBIG getecolor(char *colorname)
742
 
{
743
 
        REGISTER INTBIG i;
744
 
 
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);
748
 
        return(-1);
749
 
}
750
 
 
751
 
/*
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.
754
 
 */
755
 
BOOLEAN ecolorname(INTBIG color, char **colorname, char **colorsymbol)
756
 
{
757
 
        REGISTER INTBIG i;
758
 
 
759
 
        for(i=0; db_colors[i].name != 0; i++)
760
 
                if (db_colors[i].value == color)
761
 
        {
762
 
                *colorname = _(db_colors[i].name);
763
 
                *colorsymbol = db_colors[i].symbol;
764
 
                return(FALSE);
765
 
        }
766
 
        return(TRUE);
767
 
}
768
 
 
769
 
/*
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.
774
 
 */
775
 
INTBIG parse(char *keyword, COMCOMP *list, BOOLEAN noise)
776
 
{
777
 
        REGISTER INTBIG i, j;
778
 
        BOOLEAN (*toplist)(char**);
779
 
        INTBIG w, bst;
780
 
        REGISTER char *pp, *(*nextinlist)(void);
781
 
 
782
 
        us_pathiskey = list->ifmatch;
783
 
        toplist = list->toplist;
784
 
        nextinlist = list->nextcomcomp;
785
 
 
786
 
        (void)(*toplist)(&keyword);
787
 
        for(i=0, w=0; (pp = (*nextinlist)()) != 0; w++)
788
 
        {
789
 
                j = stringmatch(pp, keyword);
790
 
                if (j == -2) return(w);
791
 
                if (j < 0) continue;
792
 
                if (j > i)
793
 
                {
794
 
                        i = j;   bst = w;
795
 
                } else if (j == i) bst = -1;
796
 
        }
797
 
 
798
 
        /* if nothing found, give an error */
799
 
        if (i == 0)
800
 
        {
801
 
                if (noise != 0) ttyputerr(_("Unknown command: %s"), keyword);
802
 
                return(-1);
803
 
        }
804
 
 
805
 
        /* if there is unambiguous match, return it */
806
 
        if (bst >= 0) return(bst);
807
 
 
808
 
        /* print ambiguities */
809
 
        if (noise != 0)
810
 
        {
811
 
                (void)initinfstr();
812
 
                (void)(*toplist)(&keyword);
813
 
                for( ; (pp = (*nextinlist)()) != 0; )
814
 
                {
815
 
                        if ((j = stringmatch(pp, keyword)) < 0) continue;
816
 
                        if (j < i) continue;
817
 
                        (void)addtoinfstr(' ');
818
 
                        (void)addstringtoinfstr(pp);
819
 
                }
820
 
                ttyputerr(_("%s ambiguous:%s"), keyword, returninfstr());
821
 
        }
822
 
        return(-1);
823
 
}
824
 
 
825
 
/*
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.
830
 
 */
831
 
INTBIG stringmatch(char *keyword, char *input)
832
 
{
833
 
        REGISTER INTBIG j;
834
 
        REGISTER char c, d;
835
 
 
836
 
        for(j=0; (c = input[j]) != 0; j++)
837
 
        {
838
 
                if (isupper(c)) c = tolower(c);
839
 
                d = keyword[j];  if (isupper(d)) d = tolower(d);
840
 
                if (c != d) break;
841
 
        }
842
 
        if (c != 0) return(-1);
843
 
        if (keyword[j] == 0) return(-2);
844
 
        return(j);
845
 
}
846
 
 
847
 
/************************* COMMAND COMPLETION CODE *************************/
848
 
 
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;
855
 
 
856
 
void requiredextension(char *extension)
857
 
{
858
 
        (void)strcpy(db_fileextension, extension);
859
 
}
860
 
 
861
 
BOOLEAN topoffile(char **a)
862
 
{
863
 
        db_fileextension[0] = 0;
864
 
        return(db_beginsearch(a));
865
 
}
866
 
 
867
 
BOOLEAN topoflibfile(char **a)
868
 
{
869
 
        (void)strcpy(db_fileextension, ".elib");
870
 
        return(db_beginsearch(a));
871
 
}
872
 
 
873
 
BOOLEAN db_beginsearch(char **a)
874
 
{
875
 
        INTBIG i;
876
 
        static char file[256];
877
 
        char *pt;
878
 
 
879
 
        /* build the full file name */
880
 
        (void)strcpy(file, truepath(*a));
881
 
        *a = file;
882
 
 
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);
888
 
        file[i] = 0;
889
 
        strcpy(db_directorypath, file);
890
 
        db_filecount = 0;
891
 
        db_filetotal = filesindirectory(file, &db_filesindir);
892
 
 
893
 
        /* advance pointer to after the directory separator */
894
 
        pt = *a;
895
 
        for(i=strlen(pt)-1; i > 0; i--) if (pt[i] == DIRSEP) break;
896
 
        if (i > 0) *a = &pt[i+1];
897
 
        return(TRUE);
898
 
}
899
 
 
900
 
char *nextfile(void)
901
 
{
902
 
        char *pt;
903
 
        static char testfile[256];
904
 
 
905
 
        for(;;)
906
 
        {
907
 
                if (db_filecount >= db_filetotal) break;
908
 
                pt = db_filesindir[db_filecount];
909
 
                db_filecount++;
910
 
 
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)
917
 
                {
918
 
                        strcpy(testfile, pt);
919
 
                        strcat(testfile, DIRSEPSTR);
920
 
                        return(testfile);
921
 
                }
922
 
                if (db_fileextension[0] != 0)
923
 
                {
924
 
                        if (strcmp(&pt[strlen(pt)-strlen(db_fileextension)], db_fileextension) != 0)
925
 
                                continue;
926
 
                }
927
 
                return(pt);
928
 
        }
929
 
        return(0);
930
 
}
931
 
 
932
 
/*
933
 
 * routines to do command completion on technology names
934
 
 */
935
 
static TECHNOLOGY *db_postechcomcomp;
936
 
BOOLEAN topoftechs(char **c) { db_postechcomcomp = el_technologies; return(TRUE); }
937
 
char *nexttechs(void)
938
 
{
939
 
        REGISTER char *retname;
940
 
 
941
 
        if (db_postechcomcomp == NOTECHNOLOGY) return(0);
942
 
        retname = db_postechcomcomp->techname;
943
 
        db_postechcomcomp = db_postechcomcomp->nexttechnology;
944
 
        return(retname);
945
 
}
946
 
 
947
 
/*
948
 
 * routines to do command completion on technology names
949
 
 */
950
 
static CELL *db_poscellcomcomp;
951
 
BOOLEAN topofcells(char **c) { db_poscellcomcomp = el_curlib->firstcell; return(TRUE); }
952
 
char *nextcells(void)
953
 
{
954
 
        REGISTER char *retname;
955
 
 
956
 
        if (db_poscellcomcomp == NOCELL) return(0);
957
 
        retname = db_poscellcomcomp->cellname;
958
 
        db_poscellcomcomp = db_poscellcomcomp->nextcell;
959
 
        return(retname);
960
 
}
961
 
 
962
 
/*
963
 
 * routines to do command completion on view names
964
 
 */
965
 
static VIEW *db_posviewcomcomp;
966
 
BOOLEAN topofviews(char **c) { db_posviewcomcomp = el_views; return(TRUE); }
967
 
char *nextviews(void)
968
 
{
969
 
        REGISTER char *retname;
970
 
 
971
 
        if (db_posviewcomcomp == NOVIEW) return(0);
972
 
        retname = db_posviewcomcomp->viewname;
973
 
        db_posviewcomcomp = db_posviewcomcomp->nextview;
974
 
        return(retname);
975
 
}
976
 
 
977
 
/*
978
 
 * routines to do command completion on library names
979
 
 */
980
 
static LIBRARY *db_poslibcomcomp;
981
 
BOOLEAN topoflibs(char **c)
982
 
{
983
 
        db_poslibcomcomp = el_curlib;
984
 
        return(TRUE);
985
 
}
986
 
char *nextlibs(void)
987
 
{
988
 
        REGISTER char *retname;
989
 
 
990
 
        for(;;)
991
 
        {
992
 
                if (db_poslibcomcomp == NOLIBRARY) return(0);
993
 
                if ((db_poslibcomcomp->userbits&HIDDENLIBRARY) == 0)
994
 
                {
995
 
                        retname = db_poslibcomcomp->libname;
996
 
                        db_poslibcomcomp = db_poslibcomcomp->nextlibrary;
997
 
                        break;
998
 
                } else
999
 
                {
1000
 
                        db_poslibcomcomp = db_poslibcomcomp->nextlibrary;
1001
 
                }
1002
 
        }
1003
 
        return(retname);
1004
 
}
1005
 
 
1006
 
/*
1007
 
 * routines to do command completion on tool names
1008
 
 */
1009
 
static INTBIG db_poscomcomp;
1010
 
BOOLEAN topoftools(char **c) { db_poscomcomp = 0; return(TRUE); }
1011
 
char *nexttools(void)
1012
 
{
1013
 
        if (db_poscomcomp >= el_maxtools) return(0);
1014
 
        return(el_tools[db_poscomcomp++].toolname);
1015
 
}
1016
 
 
1017
 
/*
1018
 
 * routines to do command completion on facet names
1019
 
 */
1020
 
static NODEPROTO *db_posnodeprotos;
1021
 
BOOLEAN topoffacets(char **c)
1022
 
{
1023
 
        REGISTER char *pt;
1024
 
        REGISTER LIBRARY *lib;
1025
 
 
1026
 
        /* by default, assume the current library */
1027
 
        db_posnodeprotos = el_curlib->firstnodeproto;
1028
 
 
1029
 
        /* see if a library specification was given */
1030
 
        for(pt = *c; *pt != 0; pt++) if (*pt == ':') break;
1031
 
        if (*pt == ':')
1032
 
        {
1033
 
                *pt = 0;
1034
 
                lib = getlibrary(*c);
1035
 
                *pt++ = ':';
1036
 
                if (lib != NOLIBRARY)
1037
 
                {
1038
 
                        *c = pt;
1039
 
                        db_posnodeprotos = lib->firstnodeproto;
1040
 
                }
1041
 
        }
1042
 
        return(TRUE);
1043
 
}
1044
 
char *nextfacets(void)
1045
 
{
1046
 
        REGISTER char *ret;
1047
 
 
1048
 
        if (db_posnodeprotos != NONODEPROTO)
1049
 
        {
1050
 
                ret = describenodeproto(db_posnodeprotos);
1051
 
                db_posnodeprotos = db_posnodeprotos->nextnodeproto;
1052
 
                return(ret);
1053
 
        }
1054
 
        return(0);
1055
 
}
1056
 
 
1057
 
/*
1058
 
 * routines to do command completion on arc names
1059
 
 */
1060
 
static ARCPROTO *db_posarcs;
1061
 
BOOLEAN topofarcs(char **c)
1062
 
{
1063
 
        REGISTER char *pt;
1064
 
        REGISTER TECHNOLOGY *t;
1065
 
 
1066
 
        /* by default, assume the current technology */
1067
 
        db_posarcs = el_curtech->firstarcproto;
1068
 
 
1069
 
        /* see if a technology specification was given */
1070
 
        for(pt = *c; *pt != 0; pt++) if (*pt == ':') break;
1071
 
        if (*pt == ':')
1072
 
        {
1073
 
                *pt = 0;
1074
 
                t = gettechnology(*c);
1075
 
                *pt++ = ':';
1076
 
                if (t != NOTECHNOLOGY)
1077
 
                {
1078
 
                        *c = pt;
1079
 
                        db_posarcs = t->firstarcproto;
1080
 
                }
1081
 
        }
1082
 
        return(TRUE);
1083
 
}
1084
 
char *nextarcs(void)
1085
 
{
1086
 
        REGISTER char *ret;
1087
 
 
1088
 
        if (db_posarcs != NOARCPROTO)
1089
 
        {
1090
 
                ret = describearcproto(db_posarcs);
1091
 
                db_posarcs = db_posarcs->nextarcproto;
1092
 
                return(ret);
1093
 
        }
1094
 
        return(0);
1095
 
}
1096
 
 
1097
 
/*
1098
 
 * routines to do command completion on network names
1099
 
 */
1100
 
static NETWORK *db_posnets;
1101
 
static INTBIG db_posinnet;
1102
 
static char *db_posinname;
1103
 
 
1104
 
BOOLEAN topofnets(char **c)
1105
 
{
1106
 
        REGISTER NODEPROTO *np;
1107
 
 
1108
 
        db_posnets = NONETWORK;
1109
 
        np = getcurfacet();
1110
 
        if (np == NONODEPROTO) return(FALSE);
1111
 
        db_posnets = np->firstnetwork;
1112
 
        if (db_posnets == NONETWORK) return(FALSE);
1113
 
        db_posinnet = 0;
1114
 
        db_posinname = db_posnets->netname;
1115
 
        return(TRUE);
1116
 
}
1117
 
char *nextnets(void)
1118
 
{
1119
 
        REGISTER char *ret;
1120
 
 
1121
 
        for(;;)
1122
 
        {
1123
 
                if (db_posnets == NONETWORK) return(0);
1124
 
                ret = db_posinname;
1125
 
                if (db_posinnet >= db_posnets->namecount)
1126
 
                {
1127
 
                        db_posnets = db_posnets->nextnetwork;
1128
 
                        if (db_posnets == NONETWORK) return(0);
1129
 
                        db_posinnet = 0;
1130
 
                        db_posinname = db_posnets->netname;
1131
 
                } else
1132
 
                {
1133
 
                        db_posinname += strlen(db_posinname) + 1;
1134
 
                        db_posinnet++;
1135
 
                        break;
1136
 
                }
1137
 
        }
1138
 
        return(ret);
1139
 
}
1140
 
 
1141
 
/************************* OUTPUT PREPARATION *************************/
1142
 
 
1143
 
/*
1144
 
 * routine to return the full name of node "ni", including its local name.
1145
 
 * Technology considerations are ignored.
1146
 
 */
1147
 
char *ntdescribenodeinst(NODEINST *ni)
1148
 
{
1149
 
        REGISTER TECHNOLOGY *curtech;
1150
 
        REGISTER char *ret;
1151
 
 
1152
 
        if (ni == NONODEINST) return("***NONODEINST***");
1153
 
 
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;
1159
 
        return(ret);
1160
 
}
1161
 
 
1162
 
/* routine to return the name of nodeinst "ni" */
1163
 
char *describenodeinst(NODEINST *ni)
1164
 
{
1165
 
        REGISTER char *name, *protoname;
1166
 
        REGISTER VARIABLE *var;
1167
 
        REGISTER INTBIG len;
1168
 
 
1169
 
        if (ni == NONODEINST) return("***NONODEINST***");
1170
 
 
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);
1175
 
 
1176
 
        /* get output buffer */
1177
 
        db_descninodeswitch++;
1178
 
        if (db_descninodeswitch >= NUMDESCRIPTIONBUFS) db_descninodeswitch = 0;
1179
 
 
1180
 
        /* make sure buffer has enough room */
1181
 
        len = strlen(protoname) + strlen((char *)var->addr) + 3;
1182
 
        if (len > db_descnioutputsize[db_descninodeswitch])
1183
 
        {
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;
1190
 
        }
1191
 
 
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, "]");
1198
 
        return(name);
1199
 
}
1200
 
 
1201
 
/* routine to return the name of arcinst "ai" */
1202
 
char *describearcinst(ARCINST *ai)
1203
 
{
1204
 
        REGISTER char *name, *pname;
1205
 
        REGISTER VARIABLE *var;
1206
 
        REGISTER INTBIG len;
1207
 
 
1208
 
        if (ai == NOARCINST) return("***NOARCINST***");
1209
 
 
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);
1214
 
 
1215
 
        /* get output buffer */
1216
 
        db_descaiarcswitch++;
1217
 
        if (db_descaiarcswitch >= NUMDESCRIPTIONBUFS) db_descaiarcswitch = 0;
1218
 
 
1219
 
        /* make sure buffer has enough room */
1220
 
        len = strlen(pname) + strlen((char *)var->addr) + 3;
1221
 
        if (len > db_descaioutputsize[db_descaiarcswitch])
1222
 
        {
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;
1229
 
        }
1230
 
 
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, "]");
1236
 
        return(name);
1237
 
}
1238
 
 
1239
 
/*
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
1242
 
 * ignored.
1243
 
 */
1244
 
char *nldescribenodeproto(NODEPROTO *np)
1245
 
{
1246
 
        REGISTER LIBRARY *curlib;
1247
 
        REGISTER char *ret;
1248
 
 
1249
 
        if (np == NONODEPROTO) return("***NONODEPROTO***");
1250
 
 
1251
 
        if (np->primindex != 0) return(np->primname);
1252
 
        curlib = el_curlib;
1253
 
        el_curlib = np->cell->lib;
1254
 
        ret = describenodeproto(np);
1255
 
        el_curlib = curlib;
1256
 
        return(ret);
1257
 
}
1258
 
 
1259
 
/*
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
1262
 
 * most recent).
1263
 
 */
1264
 
char *describenodeproto(NODEPROTO *np)
1265
 
{
1266
 
        char line[50];
1267
 
        REGISTER char *name;
1268
 
        REGISTER INTBIG len;
1269
 
 
1270
 
        if (np == NONODEPROTO) return("***NONODEPROTO***");
1271
 
 
1272
 
        /* simple tests for direct name use */
1273
 
        if (np->primindex != 0)
1274
 
        {
1275
 
                /* if a primitive in the current technology, simply use name */
1276
 
                if (np->tech == el_curtech) return(np->primname);
1277
 
        } else
1278
 
        {
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);
1282
 
        }
1283
 
 
1284
 
        /* get output buffer */
1285
 
        db_descnpnodeswitch++;
1286
 
        if (db_descnpnodeswitch >= NUMDESCRIPTIONBUFS) db_descnpnodeswitch = 0;
1287
 
 
1288
 
        if (np->primindex != 0)
1289
 
        {
1290
 
                len = strlen(np->primname) + strlen(np->tech->techname) + 2;
1291
 
        } else
1292
 
        {
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)
1298
 
                {
1299
 
                        (void)sprintf(line, ";%ld", np->version);
1300
 
                        len += strlen(line);
1301
 
                }
1302
 
                if (*np->cellview->sviewname != 0) len += strlen(np->cellview->sviewname) + 2;
1303
 
        }
1304
 
 
1305
 
        /* make sure buffer has enough room */
1306
 
        if (len > db_descnpoutputsize[db_descnpnodeswitch])
1307
 
        {
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;
1314
 
        }
1315
 
 
1316
 
        /* construct complete name */
1317
 
        name = db_descnpoutput[db_descnpnodeswitch];
1318
 
        if (np->primindex != 0)
1319
 
        {
1320
 
                (void)strcpy(name, np->tech->techname);
1321
 
                (void)strcat(name, ":");
1322
 
                (void)strcat(name, np->primname);
1323
 
        } else
1324
 
        {
1325
 
                if (np->cell->lib != el_curlib)
1326
 
                {
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)
1333
 
                {
1334
 
                        (void)strcat(name, "{");
1335
 
                        (void)strcat(name, np->cellview->sviewname);
1336
 
                        (void)strcat(name, "}");
1337
 
                }
1338
 
        }
1339
 
        return(name);
1340
 
}
1341
 
 
1342
 
/* routine to return the name of arcproto "ap" */
1343
 
char *describearcproto(ARCPROTO *ap)
1344
 
{
1345
 
        REGISTER char *name;
1346
 
        REGISTER INTBIG len;
1347
 
 
1348
 
        if (ap == NOARCPROTO) return("***NOARCPROTO***");
1349
 
 
1350
 
        if (ap->tech == el_curtech) return(ap->protoname);
1351
 
 
1352
 
        /* get output buffer */
1353
 
        db_descaparcswitch++;
1354
 
        if (db_descaparcswitch >= NUMDESCRIPTIONBUFS) db_descaparcswitch = 0;
1355
 
 
1356
 
        /* make sure buffer has enough room */
1357
 
        len = strlen(ap->tech->techname) + strlen(ap->protoname) + 2;
1358
 
        if (len > db_descapoutputsize[db_descaparcswitch])
1359
 
        {
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;
1366
 
        }
1367
 
 
1368
 
        name = db_descapoutput[db_descaparcswitch];
1369
 
        (void)strcpy(name, ap->tech->techname);
1370
 
        (void)strcat(name, ":");
1371
 
        (void)strcat(name, ap->protoname);
1372
 
        return(name);
1373
 
}
1374
 
 
1375
 
/* routine to return the name of the object whose geometry module is "geom" */
1376
 
char *geomname(GEOM *geom)
1377
 
{
1378
 
        if (geom == NOGEOM) return("***NOGEOM***");
1379
 
        if (geom->entryisnode) return(describenodeinst(geom->entryaddr.ni));
1380
 
        return(describearcinst(geom->entryaddr.ai));
1381
 
}
1382
 
 
1383
 
/*
1384
 
 * routine to convert network "net" into a string
1385
 
 */
1386
 
char *describenetwork(NETWORK *net)
1387
 
{
1388
 
        REGISTER char *pt;
1389
 
        REGISTER NODEPROTO *np;
1390
 
        static char gennetname[50];
1391
 
        REGISTER INTBIG i;
1392
 
 
1393
 
        if (net == NONETWORK) return("***NONETWORK***");
1394
 
 
1395
 
        if (net->globalnet >= 0)
1396
 
        {
1397
 
                (void)initinfstr();
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
1402
 
                {
1403
 
                        np = net->parent;
1404
 
                        if (net->globalnet >= np->globalnetcount)
1405
 
                                (void)addstringtoinfstr(_("UNKNOWN")); else
1406
 
                                        (void)addstringtoinfstr(np->globalnetnames[net->globalnet]);
1407
 
                }
1408
 
                return(returninfstr());
1409
 
        }
1410
 
        if (net->namecount == 0)
1411
 
        {
1412
 
                sprintf(gennetname, _("UNNAMED%ld"), (INTBIG)net);
1413
 
                return(gennetname);
1414
 
        }
1415
 
        if (net->namecount == 1) return(net->netname);
1416
 
 
1417
 
        (void)initinfstr();
1418
 
        pt = net->netname;
1419
 
        for(i=0; i<net->namecount; i++)
1420
 
        {
1421
 
                if (i != 0) (void)addtoinfstr('/');
1422
 
                (void)addstringtoinfstr(pt);
1423
 
                pt += strlen(pt) + 1;
1424
 
        }
1425
 
        return(returninfstr());
1426
 
}
1427
 
 
1428
 
char *describeportbits(PORTPROTO *pp)
1429
 
{
1430
 
        switch (pp->userbits&STATEBITS)
1431
 
        {
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"));
1446
 
        }
1447
 
        return("Unknown");
1448
 
}
1449
 
 
1450
 
/*
1451
 
 * routine to name the variable at "addr" of type "type".  It is assumed
1452
 
 * to be an object that can hold other variables
1453
 
 */
1454
 
char *describeobject(INTBIG addr, INTBIG type)
1455
 
{
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;
1468
 
        REGISTER CELL *c;
1469
 
        REGISTER VIEW *v;
1470
 
        REGISTER WINDOWPART *win;
1471
 
        REGISTER WINDOWFRAME *wf;
1472
 
        REGISTER GRAPHICS *gra;
1473
 
        REGISTER CONSTRAINT *con;
1474
 
        REGISTER POLYGON *poly;
1475
 
 
1476
 
        (void)initinfstr();
1477
 
        switch (type&VTYPE)
1478
 
        {
1479
 
                case VNODEINST:
1480
 
                        ni = (NODEINST *)addr;
1481
 
                        (void)formatinfstr("NodeInstance(%s)", describenodeinst(ni));
1482
 
                        break;
1483
 
                case VNODEPROTO:
1484
 
                        np = (NODEPROTO *)addr;
1485
 
                        if (np->primindex == 0) (void)formatinfstr("Facet(%s)", describenodeproto(np)); else
1486
 
                                (void)formatinfstr("Primitive(%s)", describenodeproto(np));
1487
 
                        break;
1488
 
                case VPORTARCINST:
1489
 
                        pi = (PORTARCINST *)addr;
1490
 
                        if (pi == NOPORTARCINST) (void)addstringtoinfstr("PortArcInstance(NULL)"); else
1491
 
                                (void)formatinfstr("PortArcInstance(%ld)", (INTBIG)pi);
1492
 
                        break;
1493
 
                case VPORTEXPINST:
1494
 
                        pe = (PORTEXPINST *)addr;
1495
 
                        if (pe == NOPORTEXPINST) (void)addstringtoinfstr("PortExpInstance(NULL)"); else
1496
 
                                (void)formatinfstr("PortExpInstance(%ld)", (INTBIG)pe);
1497
 
                        break;
1498
 
                case VPORTPROTO:
1499
 
                        pp = (PORTPROTO *)addr;
1500
 
                        if (pp == NOPORTPROTO) (void)addstringtoinfstr("PortPrototype(NULL)"); else
1501
 
                                (void)formatinfstr("PortPrototype(%s)", pp->protoname);
1502
 
                        break;
1503
 
                case VARCINST:
1504
 
                        ai = (ARCINST *)addr;
1505
 
                        (void)formatinfstr("ArcInstance(%s)", describearcinst(ai));
1506
 
                        break;
1507
 
                case VARCPROTO:
1508
 
                        ap = (ARCPROTO *)addr;
1509
 
                        (void)formatinfstr("ArcPrototype(%s)", describearcproto(ap));
1510
 
                        break;
1511
 
                case VGEOM:
1512
 
                        geom = (GEOM *)addr;
1513
 
                        if (geom == NOGEOM) (void)addstringtoinfstr("Geom(NULL)"); else
1514
 
                                (void)formatinfstr("Geom(%ld)", (INTBIG)geom);
1515
 
                        break;
1516
 
                case VLIBRARY:
1517
 
                        lib = (LIBRARY *)addr;
1518
 
                        if (lib == NOLIBRARY) (void)addstringtoinfstr("Library(NULL)"); else
1519
 
                                (void)formatinfstr("Library(%s)", lib->libname);
1520
 
                        break;
1521
 
                case VTECHNOLOGY:
1522
 
                        tech = (TECHNOLOGY *)addr;
1523
 
                        if (tech == NOTECHNOLOGY) (void)addstringtoinfstr("Technology(NULL)"); else
1524
 
                                (void)formatinfstr("Technology(%s)", tech->techname);
1525
 
                        break;
1526
 
                case VTOOL:
1527
 
                        tool = (TOOL *)addr;
1528
 
                        if (tool == NOTOOL) (void)addstringtoinfstr("Tool(NULL)"); else
1529
 
                                (void)formatinfstr("Tool(%s)", tool->toolname);
1530
 
                        break;
1531
 
                case VRTNODE:
1532
 
                        rtn = (RTNODE *)addr;
1533
 
                        if (rtn == NORTNODE) (void)addstringtoinfstr("Rtnode(NULL)"); else
1534
 
                                (void)formatinfstr("Rtnode(%ld)", (INTBIG)rtn);
1535
 
                        break;
1536
 
                case VCELL:
1537
 
                        c = (CELL *)addr;
1538
 
                        if (c == NOCELL) (void)addstringtoinfstr("Cell(NULL)"); else
1539
 
                                (void)formatinfstr("Cell(%s)", c->cellname);
1540
 
                        break;
1541
 
                case VVIEW:
1542
 
                        v = (VIEW *)addr;
1543
 
                        if (v == NOVIEW) (void)addstringtoinfstr("View(NULL)"); else
1544
 
                                (void)formatinfstr("View(%s)", v->viewname);
1545
 
                        break;
1546
 
                case VWINDOWPART:
1547
 
                        win = (WINDOWPART *)addr;
1548
 
                        if (win != NOWINDOWPART) (void)formatinfstr("WindowPart(%s)", win->location); else
1549
 
                                (void)formatinfstr("WindowPart(%ld)", (INTBIG)win);
1550
 
                        break;
1551
 
                case VGRAPHICS:
1552
 
                        gra = (GRAPHICS *)addr;
1553
 
                        if (gra == NOGRAPHICS) (void)addstringtoinfstr("Graphics(NULL)"); else
1554
 
                                (void)formatinfstr("Graphics(%ld)", (INTBIG)gra);
1555
 
                        break;
1556
 
                case VCONSTRAINT:
1557
 
                        con = (CONSTRAINT *)addr;
1558
 
                        if (con == NOCONSTRAINT) (void)addstringtoinfstr("Constraint(NULL)"); else
1559
 
                                (void)formatinfstr("Constraint(%s)", con->conname);
1560
 
                        break;
1561
 
                case VWINDOWFRAME:
1562
 
                        wf = (WINDOWFRAME *)addr;
1563
 
                        (void)formatinfstr("WindowFrame(%ld)", (INTBIG)wf);
1564
 
                        break;
1565
 
                case VPOLYGON:
1566
 
                        poly = (POLYGON *)addr;
1567
 
                        (void)formatinfstr("Polygon(%ld)", (INTBIG)poly);
1568
 
                        break;
1569
 
                default:
1570
 
                        (void)addstringtoinfstr("UNKNOWN(?)");
1571
 
                        break;
1572
 
        }
1573
 
        return(returninfstr());
1574
 
}
1575
 
 
1576
 
/*
1577
 
 * routine to convert a lambda number to ascii
1578
 
 */
1579
 
#define OUTBUFS 8
1580
 
char *latoa(INTBIG i)
1581
 
{
1582
 
        static INTBIG latoaswitch = 0;
1583
 
        static char output[OUTBUFS][20];
1584
 
        double scale, number;
1585
 
        REGISTER char *cur;
1586
 
 
1587
 
        /* get output buffer */
1588
 
        cur = output[latoaswitch++];
1589
 
        if (latoaswitch >= OUTBUFS) latoaswitch = 0;
1590
 
 
1591
 
        /* determine scaling */
1592
 
        scale = db_getcurrentscale(el_units&INTERNALUNITS, el_units&DISPLAYUNITS);
1593
 
        number = ((double)i) / scale;
1594
 
        (void)sprintf(cur, "%g", number);
1595
 
 
1596
 
        switch (el_units&DISPLAYUNITS)
1597
 
        {
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;
1605
 
        }
1606
 
        return(cur);
1607
 
}
1608
 
 
1609
 
/*
1610
 
 * routine to convert a fractional number to ascii
1611
 
 */
1612
 
#define FRTOANUMBUFS 10
1613
 
 
1614
 
char *frtoa(INTBIG i)
1615
 
{
1616
 
        static INTBIG latoaswitch = 0;
1617
 
        static char output[FRTOANUMBUFS][30];
1618
 
        REGISTER INTBIG fra;
1619
 
        char temp[3];
1620
 
        REGISTER char *pp, *cur, *start;
1621
 
 
1622
 
        /* get output buffer */
1623
 
        start = cur = &output[latoaswitch++][0];
1624
 
        if (latoaswitch >= FRTOANUMBUFS) latoaswitch = 0;
1625
 
 
1626
 
        /* handle negative values */
1627
 
        if (i < 0)
1628
 
        {
1629
 
                *cur++ = '-';
1630
 
                i = -i;
1631
 
        }
1632
 
 
1633
 
        /* get the part to the left of the decimal point */
1634
 
        (void)sprintf(cur, "%ld", i/WHOLE);
1635
 
 
1636
 
        /* see if there is anything to the right of the decimal point */
1637
 
        if ((i%WHOLE) != 0)
1638
 
        {
1639
 
                (void)strcat(cur, ".");
1640
 
                fra = i % WHOLE;
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;
1647
 
        }
1648
 
        return(start);
1649
 
}
1650
 
 
1651
 
/*
1652
 
 * routine to determine whether or not the string in "pp" is a number.
1653
 
 * Returns true if it is.
1654
 
 */
1655
 
BOOLEAN isanumber(char *pp)
1656
 
{
1657
 
        INTBIG xflag, founddigits;
1658
 
 
1659
 
        /* ignore the minus sign */
1660
 
        if (*pp == '+' || *pp == '-') pp++;
1661
 
 
1662
 
        /* special case for hexadecimal prefix */
1663
 
        if (*pp == '0' && (pp[1] == 'x' || pp[1] == 'X'))
1664
 
        {
1665
 
                pp += 2;
1666
 
                xflag = 1;
1667
 
        } else xflag = 0;
1668
 
 
1669
 
        /* there must be something to check */
1670
 
        if (*pp == 0) return(FALSE);
1671
 
 
1672
 
        founddigits = 0;
1673
 
        if (xflag != 0)
1674
 
        {
1675
 
                while (isxdigit(*pp))
1676
 
                {
1677
 
                        pp++;
1678
 
                        founddigits = 1;
1679
 
                }
1680
 
        } else
1681
 
        {
1682
 
                while (isdigit(*pp) || *pp == '.')
1683
 
                {
1684
 
                        if (*pp != '.') founddigits = 1;
1685
 
                        pp++;
1686
 
                }
1687
 
        }
1688
 
        if (founddigits == 0) return(FALSE);
1689
 
        if (*pp == 0) return(TRUE);
1690
 
 
1691
 
        /* handle exponent of floating point numbers */
1692
 
        if (xflag != 0 || founddigits == 0 || (*pp != 'e' && *pp != 'E')) return(FALSE);
1693
 
        pp++;
1694
 
        if (*pp == '+' || *pp == '-') pp++;
1695
 
        if (*pp == 0) return(FALSE);
1696
 
        while (isdigit(*pp)) pp++;
1697
 
        if (*pp == 0) return(TRUE);
1698
 
 
1699
 
        return(FALSE);
1700
 
}
1701
 
 
1702
 
/*
1703
 
 * routine to convert relative or absolute font values to absolute, in the
1704
 
 * window "w"
1705
 
 */
1706
 
INTBIG truefontsize(INTBIG font, WINDOWPART *w, TECHNOLOGY *tech)
1707
 
{
1708
 
        REGISTER INTBIG pixperlam, lambda, height;
1709
 
        REGISTER LIBRARY *lib;
1710
 
 
1711
 
        /* keep special font codes */
1712
 
        if (font == TXTEDITOR || font == TXTMENU) return(font);
1713
 
 
1714
 
        /* absolute font sizes are easy */
1715
 
        if ((font&TXTPOINTS) != 0) return((font&TXTPOINTS) >> TXTPOINTSSH);
1716
 
 
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)
1722
 
        {
1723
 
                height = TXTGETQLAMBDA(font);
1724
 
                height = height * lambda / 4;
1725
 
                pixperlam = applyyscale(w, height);
1726
 
                return(pixperlam);
1727
 
        }
1728
 
        return(applyyscale(w, lambda));
1729
 
}
1730
 
 
1731
 
/*
1732
 
 * routine to set the default text descriptor into "td".  This text will be
1733
 
 * placed on "geom".
1734
 
 */
1735
 
void defaulttextdescript(UINTBIG *descript, GEOM *geom)
1736
 
{
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;
1743
 
 
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");
1748
 
 
1749
 
        txtvar = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, user_default_text_style_key);
1750
 
        if (txtvar == NOVARIABLE)
1751
 
        {
1752
 
                TDSETPOS(descript, VTPOSCENT);
1753
 
        } else
1754
 
        {
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));
1762
 
        }
1763
 
        if (geom != NOGEOM)
1764
 
        {
1765
 
                /* set text size */
1766
 
                if (geom->entryisnode)
1767
 
                {
1768
 
                        ni = geom->entryaddr.ni;
1769
 
                        if (ni->proto == gen_invispinprim)
1770
 
                        {
1771
 
                                defaulttextsize(2, descript);
1772
 
                        } else
1773
 
                        {
1774
 
                                defaulttextsize(3, descript);
1775
 
                        }
1776
 
                } else
1777
 
                {
1778
 
                        defaulttextsize(4, descript);
1779
 
                }
1780
 
 
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)
1784
 
                {
1785
 
                        /* figure out location of object relative to environment */
1786
 
                        dx = dy = 0;
1787
 
                        if (geom->entryisnode)
1788
 
                        {
1789
 
                                ni = geom->entryaddr.ni;
1790
 
                                if (ni->firstportarcinst != NOPORTARCINST)
1791
 
                                {
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;
1797
 
                                }
1798
 
                        }
1799
 
 
1800
 
                        /* first move placement horizontally */
1801
 
                        goleft = goright = goup = godown = 0;
1802
 
                        if ((txtvar->addr&03) == 1)
1803
 
                        {
1804
 
                                /* place label inside (towards center) */
1805
 
                                if (dx > 0) goright++; else
1806
 
                                        if (dx < 0) goleft++;
1807
 
                        } else if ((txtvar->addr&03) == 2)
1808
 
                        {
1809
 
                                /* place label outside (away from center) */
1810
 
                                if (dx > 0) goleft++; else
1811
 
                                        if (dx < 0) goright++;
1812
 
                        }
1813
 
 
1814
 
                        /* next move placement vertically */
1815
 
                        if (((txtvar->addr>>2)&03) == 1)
1816
 
                        {
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)
1821
 
                        {
1822
 
                                /* place label outside (away from center) */
1823
 
                                if (dy > 0) godown++; else
1824
 
                                        if (dy < 0) goup++;
1825
 
                        }
1826
 
                        if (goleft != 0)
1827
 
                        {
1828
 
                                switch (TDGETPOS(descript))
1829
 
                                {
1830
 
                                        case VTPOSCENT:
1831
 
                                        case VTPOSRIGHT:
1832
 
                                        case VTPOSLEFT:
1833
 
                                                TDSETPOS(descript, VTPOSLEFT);
1834
 
                                                break;
1835
 
                                        case VTPOSUP:
1836
 
                                        case VTPOSUPLEFT:
1837
 
                                        case VTPOSUPRIGHT:
1838
 
                                                TDSETPOS(descript, VTPOSUPLEFT);
1839
 
                                                break;
1840
 
                                        case VTPOSDOWN:
1841
 
                                        case VTPOSDOWNLEFT:
1842
 
                                        case VTPOSDOWNRIGHT:
1843
 
                                                TDSETPOS(descript, VTPOSDOWNLEFT);
1844
 
                                                break;
1845
 
                                }
1846
 
                        }
1847
 
                        if (goright != 0)
1848
 
                        {
1849
 
                                switch (TDGETPOS(descript))
1850
 
                                {
1851
 
                                        case VTPOSCENT:
1852
 
                                        case VTPOSRIGHT:
1853
 
                                        case VTPOSLEFT:
1854
 
                                                TDSETPOS(descript, VTPOSRIGHT);
1855
 
                                                break;
1856
 
                                        case VTPOSUP:
1857
 
                                        case VTPOSUPLEFT:
1858
 
                                        case VTPOSUPRIGHT:
1859
 
                                                TDSETPOS(descript, VTPOSUPRIGHT);
1860
 
                                                break;
1861
 
                                        case VTPOSDOWN:
1862
 
                                        case VTPOSDOWNLEFT:
1863
 
                                        case VTPOSDOWNRIGHT:
1864
 
                                                TDSETPOS(descript, VTPOSDOWNRIGHT);
1865
 
                                                break;
1866
 
                                }
1867
 
                        }
1868
 
                        if (goup != 0)
1869
 
                        {
1870
 
                                switch (TDGETPOS(descript))
1871
 
                                {
1872
 
                                        case VTPOSCENT:
1873
 
                                        case VTPOSUP:
1874
 
                                        case VTPOSDOWN:
1875
 
                                                TDSETPOS(descript, VTPOSUP);
1876
 
                                                break;
1877
 
                                        case VTPOSRIGHT:
1878
 
                                        case VTPOSUPRIGHT:
1879
 
                                        case VTPOSDOWNRIGHT:
1880
 
                                                TDSETPOS(descript, VTPOSUPRIGHT);
1881
 
                                                break;
1882
 
                                        case VTPOSLEFT:
1883
 
                                        case VTPOSUPLEFT:
1884
 
                                        case VTPOSDOWNLEFT:
1885
 
                                                TDSETPOS(descript, VTPOSUPLEFT);
1886
 
                                                break;
1887
 
                                }
1888
 
                        }
1889
 
                        if (godown != 0)
1890
 
                        {
1891
 
                                switch (TDGETPOS(descript))
1892
 
                                {
1893
 
                                        case VTPOSCENT:
1894
 
                                        case VTPOSUP:
1895
 
                                        case VTPOSDOWN:
1896
 
                                                TDSETPOS(descript, VTPOSDOWN);
1897
 
                                                break;
1898
 
                                        case VTPOSRIGHT:
1899
 
                                        case VTPOSUPRIGHT:
1900
 
                                        case VTPOSDOWNRIGHT:
1901
 
                                                TDSETPOS(descript, VTPOSDOWNRIGHT);
1902
 
                                                break;
1903
 
                                        case VTPOSLEFT:
1904
 
                                        case VTPOSUPLEFT:
1905
 
                                        case VTPOSDOWNLEFT:
1906
 
                                                TDSETPOS(descript, VTPOSDOWNLEFT);
1907
 
                                                break;
1908
 
                                }
1909
 
                        }
1910
 
                }
1911
 
        }
1912
 
}
1913
 
 
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)
1920
 
 
1921
 
/*
1922
 
 * Routine to determine the size of text to use for a particular type of text:
1923
 
 * 3:  node name
1924
 
 * 4:  arc name
1925
 
 * 1:  export label
1926
 
 * 2:  nonlayout text (text on an invisible pin, facet variables)
1927
 
 * 5:  facet instance name
1928
 
 * 6:  facet text
1929
 
 */
1930
 
void defaulttextsize(INTBIG texttype, UINTBIG *descript)
1931
 
{
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;
1935
 
 
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");
1948
 
 
1949
 
        TDSETSIZE(descript, TXTSETQLAMBDA(4));
1950
 
        switch (texttype)
1951
 
        {
1952
 
                case 3:
1953
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, node_size_key);
1954
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFNODETEXTSIZE); else
1955
 
                        {
1956
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1957
 
                                        TDSETSIZE(descript, var->addr);
1958
 
                        }
1959
 
                        break;
1960
 
                case 4:
1961
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, arc_size_key);
1962
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFARCTEXTSIZE); else
1963
 
                        {
1964
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1965
 
                                        TDSETSIZE(descript, var->addr);
1966
 
                        }
1967
 
                        break;
1968
 
                case 1:
1969
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, export_size_key);
1970
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFEXPORTSIZE); else
1971
 
                        {
1972
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1973
 
                                        TDSETSIZE(descript, var->addr);
1974
 
                        }                               
1975
 
                        break;
1976
 
                case 2:
1977
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, nonlayout_size_key);
1978
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFNONLAYOUTTEXTSIZE); else
1979
 
                        {
1980
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1981
 
                                        TDSETSIZE(descript, var->addr);
1982
 
                        }
1983
 
                        break;
1984
 
                case 5:
1985
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, instance_size_key);
1986
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFINSTTEXTSIZE); else
1987
 
                        {
1988
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1989
 
                                        TDSETSIZE(descript, var->addr);
1990
 
                        }
1991
 
                        break;
1992
 
                case 6:
1993
 
                        var = getvalkey((INTBIG)us_tool, VTOOL, -1, facet_size_key);
1994
 
                        if (var == NOVARIABLE) TDSETSIZE(descript, DEFFACETTEXTSIZE); else
1995
 
                        {
1996
 
                                if ((var->type&VISARRAY) != 0) TDCOPY(descript, (UINTBIG *)var->addr); else
1997
 
                                        TDSETSIZE(descript, var->addr);
1998
 
                        }
1999
 
                        break;
2000
 
        }
2001
 
}
2002
 
 
2003
 
/*
2004
 
 * Routine to get the X offset field of text descriptor words "td".  This routine
2005
 
 * implements the macro "TDGETXOFF".
2006
 
 */
2007
 
INTBIG gettdxoffset(UINTBIG *td)
2008
 
{
2009
 
        REGISTER INTBIG offset, scale;
2010
 
 
2011
 
        offset = (td[0] & VTXOFF) >> VTXOFFSH;
2012
 
        if ((td[0]&VTXOFFNEG) != 0) offset = -offset;
2013
 
        scale = TDGETOFFSCALE(td) + 1;
2014
 
        return(offset * scale);
2015
 
}
2016
 
 
2017
 
/*
2018
 
 * Routine to get the Y offset field of text descriptor words "td".  This routine
2019
 
 * implements the macro "TDGETYOFF".
2020
 
 */
2021
 
INTBIG gettdyoffset(UINTBIG *td)
2022
 
{
2023
 
        REGISTER INTBIG offset, scale;
2024
 
 
2025
 
        offset = (td[0] & VTYOFF) >> VTYOFFSH;
2026
 
        if ((td[0]&VTYOFFNEG) != 0) offset = -offset;
2027
 
        scale = TDGETOFFSCALE(td) + 1;
2028
 
        return(offset * scale);
2029
 
}
2030
 
 
2031
 
/*
2032
 
 * Routine to set the X offset field of text descriptor words "td" to "value".
2033
 
 * This routine implements the macro "TDSETOFF".
2034
 
 */
2035
 
void settdoffset(UINTBIG *td, INTBIG x, INTBIG y)
2036
 
{
2037
 
        REGISTER INTBIG scale;
2038
 
 
2039
 
        td[0] = td[0] & ~(VTXOFF|VTYOFF|VTXOFFNEG|VTYOFFNEG);
2040
 
        if (x < 0)
2041
 
        {
2042
 
                x = -x;
2043
 
                td[0] |= VTXOFFNEG;
2044
 
        }
2045
 
        if (y < 0)
2046
 
        {
2047
 
                y = -y;
2048
 
                td[0] |= VTYOFFNEG;
2049
 
        }
2050
 
        scale = maxi(x,y) >> VTOFFMASKWID;
2051
 
        x /= (scale + 1);
2052
 
        y /= (scale + 1);
2053
 
        td[0] |= (x << VTXOFFSH);
2054
 
        td[0] |= (y << VTYOFFSH);
2055
 
        TDSETOFFSCALE(td, scale);
2056
 
}
2057
 
 
2058
 
/*
2059
 
 * Routine to validate the variable offset (x,y) and clip or grid it
2060
 
 * to acceptable values.
2061
 
 */
2062
 
void propervaroffset(INTBIG *x, INTBIG *y)
2063
 
{
2064
 
        REGISTER INTBIG scale, realx, realy, negx, negy;
2065
 
 
2066
 
        negx = negy = 1;
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;
2073
 
        realx /= scale;
2074
 
        realy /= scale;
2075
 
        *x = realx * scale * negx;
2076
 
        *y = realy * scale * negy;
2077
 
}
2078
 
 
2079
 
/*
2080
 
 * Routine to clear the text descriptor array in "t".
2081
 
 * This routine implements the macro "TDCLEAR".
2082
 
 */
2083
 
void tdclear(UINTBIG *t)
2084
 
{
2085
 
        REGISTER INTBIG i;
2086
 
 
2087
 
        for(i=0; i<TEXTDESCRIPTSIZE; i++) t[i] = 0;
2088
 
}
2089
 
 
2090
 
/*
2091
 
 * Routine to copy the text descriptor array in "s" to "d".
2092
 
 * This routine implements the macro "TDCOPY".
2093
 
 */
2094
 
void tdcopy(UINTBIG *d, UINTBIG *s)
2095
 
{
2096
 
        REGISTER INTBIG i;
2097
 
 
2098
 
        for(i=0; i<TEXTDESCRIPTSIZE; i++) d[i] = s[i];
2099
 
}
2100
 
 
2101
 
/*
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".
2105
 
 */
2106
 
BOOLEAN tddiff(UINTBIG *t1, UINTBIG *t2)
2107
 
{
2108
 
        REGISTER INTBIG i;
2109
 
 
2110
 
        for(i=0; i<TEXTDESCRIPTSIZE; i++)
2111
 
                if (t1[i] != t2[i]) return(TRUE);
2112
 
        return(FALSE);
2113
 
}
2114
 
 
2115
 
/*
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.
2124
 
 */
2125
 
char *describedisplayedvariable(VARIABLE *var, INTBIG aindex, INTBIG purpose)
2126
 
{
2127
 
        REGISTER char *name, *parstr;
2128
 
        REGISTER INTBIG len;
2129
 
        REGISTER VARIABLE *parval;
2130
 
 
2131
 
        if (var == NOVARIABLE)
2132
 
        {
2133
 
                if (purpose <= 0) return("***UNKNOWN***"); else return("");
2134
 
        }
2135
 
 
2136
 
        (void)initinfstr();
2137
 
 
2138
 
        /* add variable name if requested */
2139
 
        if ((var->type&VDISPLAY) != 0)
2140
 
        {
2141
 
                if ((var->type&VISARRAY) == 0) len = 1; else
2142
 
                        len = getlength(var);
2143
 
                name = truevariablename(var);
2144
 
                switch (TDGETDISPPART(var->textdescript))
2145
 
                {
2146
 
                        case VTDISPLAYNAMEVALUE:
2147
 
                                if (len > 1 && aindex >= 0)
2148
 
                                {
2149
 
                                        (void)formatinfstr("%s[%ld]=", name, aindex);
2150
 
                                } else
2151
 
                                {
2152
 
                                        (void)formatinfstr("%s=", name);
2153
 
                                }
2154
 
                                break;
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)
2160
 
                                {
2161
 
                                        (void)formatinfstr("%s[%ld]=%s;def=", name, aindex, parstr);
2162
 
                                } else
2163
 
                                {
2164
 
                                        (void)formatinfstr("%s=%s;def=", name, parstr);
2165
 
                                }
2166
 
                                break;
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)
2172
 
                                {
2173
 
                                        (void)formatinfstr("%s[%ld]=%s;def=", name, aindex, parstr);
2174
 
                                } else
2175
 
                                {
2176
 
                                        (void)formatinfstr("%s=%s;def=", name, parstr);
2177
 
                                }
2178
 
                                break;
2179
 
                }
2180
 
        }
2181
 
        (void)addstringtoinfstr(describevariable(var, aindex, purpose));
2182
 
        return(returninfstr());
2183
 
}
2184
 
 
2185
 
/*
2186
 
 * Routine to return the true name of variable "var".  Leading "ATTR_" or "ATTRP_"
2187
 
 * markers are removed.
2188
 
 */
2189
 
char *truevariablename(VARIABLE *var)
2190
 
{
2191
 
        REGISTER char *name;
2192
 
        REGISTER INTBIG i, len;
2193
 
 
2194
 
        name = makename(var->key);
2195
 
        if (strncmp(name, "ATTR_", 5) == 0)
2196
 
                return(name + 5);
2197
 
        if (strncmp(name, "ATTRP_", 6) == 0)
2198
 
        {
2199
 
                len = strlen(name);
2200
 
                for(i=len-1; i>=0; i--) if (name[i] == '_') break;
2201
 
                return(name + i);
2202
 
        }
2203
 
        return(name);
2204
 
}
2205
 
 
2206
 
/*
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).
2214
 
 */
2215
 
char *describevariable(VARIABLE *var, INTBIG aindex, INTBIG purpose)
2216
 
{
2217
 
        REGISTER BOOLEAN err;
2218
 
        REGISTER INTBIG i, len, *addr;
2219
 
 
2220
 
        if (var == NOVARIABLE)
2221
 
        {
2222
 
                if (purpose <= 0) return("***UNKNOWN***"); else return("");
2223
 
        }
2224
 
 
2225
 
        err = initinfstr();
2226
 
 
2227
 
        if ((var->type & (VCODE1|VCODE2)) != 0)
2228
 
        {
2229
 
                /* special case for code: it is a string, the type applies to the result */
2230
 
                err |= db_makestringvar(VSTRING, var->addr, purpose);
2231
 
        } else
2232
 
        {
2233
 
                if ((var->type&VISARRAY) != 0)
2234
 
                {
2235
 
                        /* compute the array length */
2236
 
                        len = getlength(var);
2237
 
                        addr = (INTBIG *)var->addr;
2238
 
 
2239
 
                        /* if asking for a single entry, get it */
2240
 
                        if (aindex >= 0)
2241
 
                        {
2242
 
                                /* special case when the variable is a general array of objects */
2243
 
                                if ((var->type&VTYPE) == VGENERAL)
2244
 
                                {
2245
 
                                        /* index the array in pairs */
2246
 
                                        aindex *= 2;
2247
 
                                        if (aindex < len)
2248
 
                                                err |= db_makestringvar(addr[aindex+1], addr[aindex], purpose);
2249
 
                                } else
2250
 
                                {
2251
 
                                        /* normal array indexing */
2252
 
                                        if (aindex < len)
2253
 
                                                switch ((var->type&VTYPE))
2254
 
                                        {
2255
 
                                                case VCHAR:
2256
 
                                                        err |= db_makestringvar(var->type,
2257
 
                                                                ((INTBIG)((char *)addr)[aindex]), purpose);
2258
 
                                                        break;
2259
 
 
2260
 
                                                case VDOUBLE:
2261
 
                                                        err |= db_makestringvar(var->type,
2262
 
                                                                ((INTBIG)((double *)addr)[aindex]), purpose);
2263
 
                                                        break;
2264
 
 
2265
 
                                                case VSHORT:
2266
 
                                                        err |= db_makestringvar(var->type,
2267
 
                                                                ((INTBIG)((INTSML *)addr)[aindex]), purpose);
2268
 
                                                        break;
2269
 
 
2270
 
                                                default:
2271
 
                                                        err |= db_makestringvar(var->type, addr[aindex], purpose);
2272
 
                                                        break;
2273
 
                                        }
2274
 
                                }
2275
 
                        } else
2276
 
                        {
2277
 
                                /* in an array, quote strings */
2278
 
                                if (purpose < 0) purpose = 0;
2279
 
                                err |= addtoinfstr('[');
2280
 
                                for(i=0; i<len; i++)
2281
 
                                {
2282
 
                                        if (i != 0) err |= addtoinfstr(',');
2283
 
 
2284
 
                                        /* special case when the variable is a general array of objects */
2285
 
                                        if ((var->type&VTYPE) == VGENERAL)
2286
 
                                        {
2287
 
                                                /* index the array in pairs */
2288
 
                                                if (i+1 < len)
2289
 
                                                        err |= db_makestringvar(addr[i+1], addr[i], purpose);
2290
 
                                                i++;
2291
 
                                        } else
2292
 
                                        {
2293
 
                                                /* normal array indexing */
2294
 
                                                switch ((var->type&VTYPE))
2295
 
                                                {
2296
 
                                                        case VCHAR:
2297
 
                                                                err |= db_makestringvar(var->type,
2298
 
                                                                        ((INTBIG)((char *)addr)[i]), purpose);
2299
 
                                                                break;
2300
 
 
2301
 
                                                        case VDOUBLE:
2302
 
                                                                err |= db_makestringvar(var->type,
2303
 
                                                                        ((INTBIG)((double *)addr)[i]), purpose);
2304
 
                                                                break;
2305
 
 
2306
 
                                                        case VSHORT:
2307
 
                                                                err |= db_makestringvar(var->type,
2308
 
                                                                        ((INTBIG)((INTSML *)addr)[i]), purpose);
2309
 
                                                                break;
2310
 
 
2311
 
                                                        default:
2312
 
                                                                err |= db_makestringvar(var->type, addr[i], purpose);
2313
 
                                                                break;
2314
 
                                                }
2315
 
                                        }
2316
 
                                }
2317
 
                                err |= addtoinfstr(']');
2318
 
                        }
2319
 
                } else err |= db_makestringvar(var->type, var->addr, purpose);
2320
 
        }
2321
 
        if (err != 0) (void)db_error(DBNOMEM|DBDESCRIBEVARIABLE);
2322
 
        return(returninfstr());
2323
 
}
2324
 
 
2325
 
/*
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.
2332
 
 */
2333
 
BOOLEAN db_makestringvar(INTBIG type, INTBIG addr, INTBIG purpose)
2334
 
{
2335
 
        char line[100];
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;
2358
 
 
2359
 
        switch (type&VTYPE)
2360
 
        {
2361
 
                case VINTEGER:
2362
 
                case VSHORT:
2363
 
                        (void)sprintf(line, "%ld", addr);
2364
 
                        return(addstringtoinfstr(line));
2365
 
                case VADDRESS:
2366
 
                        if (purpose == 0) err = addstringtoinfstr("Address="); else
2367
 
                                err = FALSE;
2368
 
                        (void)sprintf(line, "0%lo", addr);
2369
 
                        err |= addstringtoinfstr(line);
2370
 
                        return(err);
2371
 
                case VCHAR:
2372
 
                        return(addtoinfstr((char)addr)?1:0);
2373
 
                case VSTRING:
2374
 
                        if ((char *)addr == NOSTRING || (char *)addr == 0)
2375
 
                                return(addstringtoinfstr("***NOSTRING***"));
2376
 
                        err = FALSE;
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('"');
2381
 
                        return(err);
2382
 
                case VFLOAT:
2383
 
                case VDOUBLE:
2384
 
                        (void)sprintf(line, "%g", castfloat(addr));
2385
 
                        return(addstringtoinfstr(line));
2386
 
                case VNODEINST:
2387
 
                        ni = (NODEINST *)addr;
2388
 
                        if (ni == NONODEINST) return(addstringtoinfstr("***NONODEINST***"));
2389
 
                        if (purpose == 0)
2390
 
                        {
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));
2395
 
                        }
2396
 
                        (void)sprintf(line, "node%ld", (INTBIG)ni);
2397
 
                        return(addstringtoinfstr(line));
2398
 
                case VNODEPROTO:
2399
 
                        np = (NODEPROTO *)addr;
2400
 
                        if (purpose <= 0) return(addstringtoinfstr(describenodeproto(np)));
2401
 
                        return(db_addstring(describenodeproto(np)));
2402
 
                case VPORTARCINST:
2403
 
                        pi = (PORTARCINST *)addr;
2404
 
                        if (pi == NOPORTARCINST) return(addstringtoinfstr("***NOPORTARCINST***"));
2405
 
                        (void)sprintf(line, "portarc%ld", (INTBIG)pi);
2406
 
                        return(addstringtoinfstr(line));
2407
 
                case VPORTEXPINST:
2408
 
                        pe = (PORTEXPINST *)addr;
2409
 
                        if (pe == NOPORTEXPINST) return(addstringtoinfstr("***NOPORTEXPINST***"));
2410
 
                        (void)sprintf(line, "portexp%ld", (INTBIG)pe);
2411
 
                        return(addstringtoinfstr(line));
2412
 
                case VPORTPROTO:
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));
2417
 
                case VARCINST:
2418
 
                        ai = (ARCINST *)addr;
2419
 
                        if (ai == NOARCINST) return(addstringtoinfstr("***NOARCINST***"));
2420
 
                        (void)sprintf(line, "arc%ld", (INTBIG)ai);
2421
 
                        return(addstringtoinfstr(line));
2422
 
                case VARCPROTO:
2423
 
                        ap = (ARCPROTO *)addr;
2424
 
                        if (purpose <= 0) return(addstringtoinfstr(describearcproto(ap)));
2425
 
                        return(db_addstring(describearcproto(ap)));
2426
 
                case VGEOM:
2427
 
                        geom = (GEOM *)addr;
2428
 
                        if (geom == NOGEOM) return(addstringtoinfstr("***NOGEOM***"));
2429
 
                        (void)sprintf(line, "geom%ld", (INTBIG)geom);
2430
 
                        return(addstringtoinfstr(line));
2431
 
                case VLIBRARY:
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));
2436
 
                case VTECHNOLOGY:
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));
2441
 
                case VTOOL:
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));
2446
 
                case VRTNODE:
2447
 
                        rtn = (RTNODE *)addr;
2448
 
                        if (rtn == NORTNODE) return(addstringtoinfstr("***NORTNODE***"));
2449
 
                        (void)sprintf(line, "rtn%ld", (INTBIG)rtn);
2450
 
                        return(addstringtoinfstr(line));
2451
 
                case VFRACT:
2452
 
                        return(addstringtoinfstr(frtoa(addr)));
2453
 
                case VNETWORK:
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)));
2458
 
                case VCELL:
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));
2463
 
                case VVIEW:
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));
2468
 
                case VWINDOWPART:
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));
2473
 
                case VGRAPHICS:
2474
 
                        gra = (GRAPHICS *)addr;
2475
 
                        if (gra == NOGRAPHICS) return(addstringtoinfstr("***NOGRAPHICS***"));
2476
 
                        (void)sprintf(line, "gra%ld", (INTBIG)gra);
2477
 
                        return(addstringtoinfstr(line));
2478
 
                case VCONSTRAINT:
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));
2483
 
                case VGENERAL:
2484
 
                        (void)sprintf(line, "***%ld-LONG-GENERAL-ARRAY***", ((type&VLENGTH)>>VLENGTHSH) / 2);
2485
 
                        return(addstringtoinfstr(line));
2486
 
                case VWINDOWFRAME:
2487
 
                        wf = (WINDOWFRAME *)addr;
2488
 
                        if (wf == NOWINDOWFRAME) return(addstringtoinfstr("***NOWINDOWFRAME***"));
2489
 
                        (void)sprintf(line, "wf%ld", (INTBIG)wf);
2490
 
                        return(addstringtoinfstr(line));
2491
 
                case VPOLYGON:
2492
 
                        poly = (POLYGON *)addr;
2493
 
                        if (poly == NOPOLYGON) return(addstringtoinfstr("***NOPOLYGON***"));
2494
 
                        (void)sprintf(line, "poly%ld", (INTBIG)poly);
2495
 
                        return(addstringtoinfstr(line));
2496
 
        }
2497
 
        return(FALSE);
2498
 
}
2499
 
 
2500
 
/*
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.
2504
 
 */
2505
 
BOOLEAN db_addstring(char *str)
2506
 
{
2507
 
        REGISTER BOOLEAN err;
2508
 
 
2509
 
        err = FALSE;
2510
 
        while (*str != 0)
2511
 
        {
2512
 
                if (*str == '[' || *str == ']' || *str == '"' || *str == '^')
2513
 
                        err |= addtoinfstr('^');
2514
 
                err |= addtoinfstr(*str++);
2515
 
        }
2516
 
        return(err);
2517
 
}
2518
 
 
2519
 
/*
2520
 
 * Routine to describe a simple variable "var".  There can be no arrays, code,
2521
 
 * or pointers to Electric objects in this variable.
2522
 
 */
2523
 
char *describesimplevariable(VARIABLE *var)
2524
 
{
2525
 
        static char line[50];
2526
 
 
2527
 
        switch (var->type&VTYPE)
2528
 
        {
2529
 
                case VSTRING:
2530
 
                        return((char *)var->addr);
2531
 
                case VINTEGER:
2532
 
                        sprintf(line, "%ld", var->addr);
2533
 
                        return(line);
2534
 
                case VFRACT:
2535
 
                        strcpy(line, frtoa(var->addr));
2536
 
                        return(line);
2537
 
                case VSHORT:
2538
 
                        sprintf(line, "%ld", var->addr&0xFFFF);
2539
 
                        return(line);
2540
 
                case VFLOAT:
2541
 
                case VDOUBLE:
2542
 
                        sprintf(line, "%g", castfloat(var->addr));
2543
 
                        return(line);
2544
 
        }
2545
 
        return("");
2546
 
}
2547
 
 
2548
 
/*
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".
2551
 
 */
2552
 
void getsimpletype(char *pt, INTBIG *type, INTBIG *addr)
2553
 
{
2554
 
        REGISTER char *opt;
2555
 
        REGISTER INTBIG i;
2556
 
        float f;
2557
 
 
2558
 
        if (!isanumber(pt))
2559
 
        {
2560
 
                *type = VSTRING;
2561
 
                *addr = (INTBIG)pt;
2562
 
                return;
2563
 
        }
2564
 
        *type = VINTEGER;
2565
 
        *addr = atoi(pt);
2566
 
        for(opt = pt; *opt != 0; opt++) if (*opt == '.')
2567
 
        {
2568
 
                f = (float)atof(pt);
2569
 
                i = (INTBIG)(f * WHOLE);
2570
 
                if (i / WHOLE == f)
2571
 
                {
2572
 
                        *type = VFRACT;
2573
 
                        *addr = i;
2574
 
                } else
2575
 
                {
2576
 
                        *type = VFLOAT;
2577
 
                        *addr = castint(f);
2578
 
                }
2579
 
                break;
2580
 
        }
2581
 
}
2582
 
 
2583
 
/*
2584
 
 * routine to make an abbreviation for the string "pt" in upper case if
2585
 
 * "upper" is true
2586
 
 */
2587
 
char *makeabbrev(char *pt, BOOLEAN upper)
2588
 
{
2589
 
        /* generate an abbreviated name for this prototype */
2590
 
        (void)initinfstr();
2591
 
        while (*pt != 0)
2592
 
        {
2593
 
                if (isalpha(*pt))
2594
 
                {
2595
 
                        if (isupper(*pt))
2596
 
                        {
2597
 
                                if (upper) (void)addtoinfstr(*pt); else
2598
 
                                        (void)addtoinfstr((char)(tolower(*pt)));
2599
 
                        } else
2600
 
                        {
2601
 
                                if (!upper) (void)addtoinfstr(*pt); else
2602
 
                                        (void)addtoinfstr((char)(toupper(*pt)));
2603
 
                        }
2604
 
                        while (isalpha(*pt)) pt++;
2605
 
                }
2606
 
                while (!isalpha(*pt) && *pt != 0) pt++;
2607
 
        }
2608
 
        return(returninfstr());
2609
 
}
2610
 
 
2611
 
/*
2612
 
 * routine to report the name of the internal unit in "units".
2613
 
 */
2614
 
char *unitsname(INTBIG units)
2615
 
{
2616
 
        switch (units & INTERNALUNITS)
2617
 
        {
2618
 
                case INTUNITHMMIC:   return(_("half-millimicron"));
2619
 
                case INTUNITHDMIC:   return(_("half-decimicron"));
2620
 
        }
2621
 
        return("?");
2622
 
}
2623
 
 
2624
 
/************************* INTERNATIONALIZATION *************************/
2625
 
 
2626
 
char *db_stoppingreason[] =
2627
 
{
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 */
2658
 
        0
2659
 
};
2660
 
 
2661
 
/*
2662
 
 * Routine to translate internal strings in the database.
2663
 
 */
2664
 
void db_inittranslation(void)
2665
 
{
2666
 
        REGISTER INTBIG i;
2667
 
 
2668
 
        /* pretranslate the reasons for stopping */
2669
 
        for(i=0; db_stoppingreason[i] != 0; i++)
2670
 
                db_stoppingreason[i] = _(db_stoppingreason[i]);
2671
 
}
2672
 
 
2673
 
/*
2674
 
 * Routine to ensure that dialog "dia" is translated.
2675
 
 */
2676
 
void DiaTranslate(DIALOG *dia)
2677
 
{
2678
 
        REGISTER INTBIG j;
2679
 
        DIALOGITEM *item;
2680
 
 
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++)
2685
 
        {
2686
 
                item = &dia->list[j];
2687
 
                switch (item->type&ITEMTYPE)
2688
 
                {
2689
 
                        case BUTTON:
2690
 
                        case DEFBUTTON:
2691
 
                        case CHECK:
2692
 
                        case RADIO:
2693
 
                        case MESSAGE:
2694
 
                        case EDITTEXT:
2695
 
                                if (*item->msg != 0)
2696
 
                                        item->msg = _(item->msg);
2697
 
                                break;
2698
 
                }
2699
 
        }
2700
 
}
2701
 
 
2702
 
/*
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).
2705
 
 */
2706
 
char *makeplural(char *word, INTBIG amount)
2707
 
{
2708
 
        INTBIG needed, len;
2709
 
 
2710
 
        if (amount == 1) return(word);
2711
 
        len = strlen(word);
2712
 
        if (len == 0) return(word);
2713
 
        needed = len + 2;
2714
 
        if (needed > db_pluralbufsize)
2715
 
        {
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;
2721
 
        }
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);
2726
 
}
2727
 
 
2728
 
/************************* STRING MANIPULATION *************************/
2729
 
 
2730
 
/*
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".
2734
 
 */
2735
 
#ifdef DEBUGMEMORY
2736
 
BOOLEAN _allocstring(char **addr, char *str, CLUSTER *cluster, char *module, INTBIG line)
2737
 
{
2738
 
        *addr = (char *)_emalloc((strlen(str)+1), cluster, module, line);
2739
 
        if (*addr == 0)
2740
 
        {
2741
 
                *addr = NOSTRING;
2742
 
                (void)db_error(DBNOMEM|DBALLOCSTRING);
2743
 
                return(TRUE);
2744
 
        }
2745
 
        (void)strcpy(*addr, str);
2746
 
        return(FALSE);
2747
 
}
2748
 
#else
2749
 
BOOLEAN allocstring(char **addr, char *str, CLUSTER *cluster)
2750
 
{
2751
 
        *addr = (char *)emalloc((strlen(str)+1), cluster);
2752
 
        if (*addr == 0)
2753
 
        {
2754
 
                *addr = NOSTRING;
2755
 
                (void)db_error(DBNOMEM|DBALLOCSTRING);
2756
 
                return(TRUE);
2757
 
        }
2758
 
        (void)strcpy(*addr, str);
2759
 
        return(FALSE);
2760
 
}
2761
 
#endif
2762
 
 
2763
 
/*
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".
2768
 
 */
2769
 
#ifdef DEBUGMEMORY
2770
 
BOOLEAN _reallocstring(char **addr, char *str, CLUSTER *cluster, char *module, INTBIG line)
2771
 
{
2772
 
        efree(*addr);
2773
 
        return(_allocstring(addr, str, cluster, module, line));
2774
 
}
2775
 
#else
2776
 
BOOLEAN reallocstring(char **addr, char *str, CLUSTER *cluster)
2777
 
{
2778
 
        efree(*addr);
2779
 
        return(allocstring(addr, str, cluster));
2780
 
}
2781
 
#endif
2782
 
 
2783
 
/*
2784
 
 * Routine to convert character "c" to a case-insensitive character, with
2785
 
 * special characters all ordered properly before the letters.
2786
 
 */
2787
 
INTBIG db_insensitivechar(INTBIG c)
2788
 
{
2789
 
        if (isupper(c)) return(tolower(c));
2790
 
        switch (c)
2791
 
        {
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);
2802
 
        }
2803
 
        return(c);
2804
 
}
2805
 
 
2806
 
/*
2807
 
 * name matching routine: ignores case
2808
 
 */
2809
 
INTBIG namesame(char *pt1, char *pt2)
2810
 
{
2811
 
        REGISTER INTBIG c1, c2;
2812
 
 
2813
 
        for(;;)
2814
 
        {
2815
 
                c1 = db_insensitivechar(*pt1++ & 0377);
2816
 
                c2 = db_insensitivechar(*pt2++ & 0377);
2817
 
                if (c1 != c2) return(c1-c2);
2818
 
                if (c1 == 0) break;
2819
 
        }
2820
 
        return(0);
2821
 
}
2822
 
 
2823
 
INTBIG namesamen(char *pt1, char *pt2, INTBIG count)
2824
 
{
2825
 
        REGISTER INTBIG c1, c2, i;
2826
 
 
2827
 
        for(i=0; i<count; i++)
2828
 
        {
2829
 
                c1 = db_insensitivechar(*pt1++ & 0377);
2830
 
                c2 = db_insensitivechar(*pt2++ & 0377);
2831
 
                if (c1 != c2) return(c1-c2);
2832
 
                if (c1 == 0) break;
2833
 
        }
2834
 
        return(0);
2835
 
}
2836
 
 
2837
 
/*
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".
2843
 
 */
2844
 
INTBIG namesamenumeric(char *name1, char *name2)
2845
 
{
2846
 
        REGISTER char *pt1, *pt2, pt1save, pt2save, *number1, *number2,
2847
 
                *nameend1, *nameend2;
2848
 
        REGISTER INTBIG pt1index, pt2index, pt1number, pt2number;
2849
 
        REGISTER INTBIG compare;
2850
 
 
2851
 
        number1 = 0;
2852
 
        for(pt1 = name1; *pt1 != 0; pt1++)
2853
 
        {
2854
 
                if (*pt1 == '[') break;
2855
 
                if (isdigit(*pt1) == 0) number1 = 0; else
2856
 
                {
2857
 
                        if (number1 == 0) number1 = pt1;
2858
 
                }
2859
 
        }
2860
 
        number2 = 0;
2861
 
        for(pt2 = name2; *pt2 != 0; pt2++)
2862
 
        {
2863
 
                if (*pt2 == '[') break;
2864
 
                if (isdigit(*pt2) == 0) number2 = 0; else
2865
 
                {
2866
 
                        if (number2 == 0) number2 = pt2;
2867
 
                }
2868
 
        }
2869
 
        nameend1 = pt1;   nameend2 = pt2;
2870
 
        pt1number = pt2number = 0;
2871
 
        pt1index = pt2index = 0;
2872
 
        if (number1 != 0 && number2 != 0)
2873
 
        {
2874
 
                pt1number = myatoi(number1);
2875
 
                pt2number = myatoi(number2);
2876
 
                nameend1 = number1;
2877
 
                nameend2 = number2;
2878
 
        }
2879
 
        if (*pt1 == '[') pt1index = myatoi(&pt1[1]);
2880
 
        if (*pt2 == '[') pt2index = myatoi(&pt2[1]);
2881
 
 
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);
2889
 
}
2890
 
 
2891
 
/******************** STRING PARSING ROUTINES ********************/
2892
 
 
2893
 
/*
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
2897
 
 */
2898
 
char *getkeyword(char **ptin, char *brk)
2899
 
{
2900
 
        REGISTER char *pt2, *b, *pt;
2901
 
        REGISTER INTBIG len;
2902
 
 
2903
 
        /* skip leading blanks */
2904
 
        pt = *ptin;
2905
 
        while (*pt == ' ' || *pt == '\t') pt++;
2906
 
 
2907
 
        /* remember starting point */
2908
 
        pt2 = pt;
2909
 
        for(;;)
2910
 
        {
2911
 
                if (*pt2 == 0) break;
2912
 
                for(b = brk; *b != 0; b++) if (*pt2 == *b) break;
2913
 
                if (*b != 0) break;
2914
 
                pt2++;
2915
 
        }
2916
 
        len = pt2 - pt;
2917
 
        if (len+1 > db_keywordbufferlength)
2918
 
        {
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)
2923
 
                {
2924
 
                        ttyputnomemory();
2925
 
                        return(NOSTRING);
2926
 
                }
2927
 
                db_keywordbufferlength = len+1;
2928
 
        }
2929
 
        (void)strncpy(db_keywordbuffer, pt, len);
2930
 
        db_keywordbuffer[len] = 0;
2931
 
        *ptin = pt2;
2932
 
        return(db_keywordbuffer);
2933
 
}
2934
 
 
2935
 
/*
2936
 
 * routine to return the next nonblank character in the string pointed
2937
 
 * to by "ptin".  The pointer is advanced past that character.
2938
 
 */
2939
 
char tonextchar(char **ptin)
2940
 
{
2941
 
        REGISTER char *pt, ret;
2942
 
 
2943
 
        /* skip leading blanks */
2944
 
        pt = *ptin;
2945
 
        while (*pt == ' ' || *pt == '\t') pt++;
2946
 
        ret = *pt;
2947
 
        if (ret != 0) pt++;
2948
 
        *ptin = pt;
2949
 
        return(ret);
2950
 
}
2951
 
 
2952
 
/*
2953
 
 * routine to return the next nonblank character in the string pointed
2954
 
 * to by "ptin".  The pointer is advanced to that character.
2955
 
 */
2956
 
char seenextchar(char **ptin)
2957
 
{
2958
 
        REGISTER char *pt;
2959
 
 
2960
 
        /* skip leading blanks */
2961
 
        pt = *ptin;
2962
 
        while (*pt == ' ' || *pt == '\t') pt++;
2963
 
        *ptin = pt;
2964
 
        return(*pt);
2965
 
}
2966
 
 
2967
 
/******************** INFINITE STRING PACKAGE ********************/
2968
 
 
2969
 
/*
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.
2977
 
 */
2978
 
 
2979
 
/*
2980
 
 * routine to initialize a new infinite string
2981
 
 */
2982
 
BOOLEAN initinfstr(void)
2983
 
{
2984
 
        REGISTER INTBIG i;
2985
 
 
2986
 
        if (!db_firstinf)
2987
 
        {
2988
 
                for(i=0; i<INFSTRCOUNT; i++)
2989
 
                {
2990
 
                        db_infstrings[i].infstr = (char *)emalloc((INFSTRDEFAULT+1), db_cluster);
2991
 
                        if (db_infstrings[i].infstr == 0)
2992
 
                        {
2993
 
                                (void)db_error(DBNOMEM|DBINITINFSTR);
2994
 
                                return(TRUE);
2995
 
                        }
2996
 
                        db_infstrings[i].infstrlength = INFSTRDEFAULT;
2997
 
                        db_infstrings[i].infstrinuse = 0;
2998
 
                }
2999
 
                db_firstinf = TRUE;
3000
 
                db_infstrstackpos = -1;
3001
 
                db_infstrpointer = 0;
3002
 
        }
3003
 
 
3004
 
        /* save any current infinite string on the stack */
3005
 
        if (db_infstrstackpos >= INFSTRCOUNT)
3006
 
        {
3007
 
                (void)db_error(DBRECURSIVE|DBINITINFSTR);
3008
 
                return(TRUE);
3009
 
        }
3010
 
        if (db_infstrstackpos >= 0)
3011
 
                db_infstrstackptr[db_infstrstackpos] = db_curinf;
3012
 
        db_infstrstackpos++;
3013
 
 
3014
 
        /* grab a new infinite string and initialize it */
3015
 
        for(i=0; i<INFSTRCOUNT; i++)
3016
 
        {
3017
 
                db_curinf = &db_infstrings[db_infstrpointer % INFSTRCOUNT];
3018
 
                db_infstrpointer++;
3019
 
                if (db_curinf->infstrinuse == 0) break;
3020
 
        }
3021
 
        if (i >= INFSTRCOUNT)
3022
 
        {
3023
 
                (void)db_error(DBRECURSIVE|DBINITINFSTR);
3024
 
                return(TRUE);
3025
 
        }
3026
 
        db_curinf->infstrptr = 0;
3027
 
        db_curinf->infstrinuse = 1;
3028
 
        db_curinf->infstr[db_curinf->infstrptr] = 0;
3029
 
        return(FALSE);
3030
 
}
3031
 
 
3032
 
BOOLEAN addtoinfstr(char ch)
3033
 
{
3034
 
        REGISTER char *str;
3035
 
 
3036
 
        if (db_curinf == NOINFSTR)
3037
 
        {
3038
 
                (void)db_error(DBBADOBJECT|DBADDTOINFSTR);
3039
 
                return(TRUE);
3040
 
        }
3041
 
        if (db_curinf->infstrptr >= db_curinf->infstrlength)
3042
 
        {
3043
 
                str = (char *)emalloc((db_curinf->infstrlength*2+1), db_cluster);
3044
 
                if (str == 0)
3045
 
                {
3046
 
                        (void)db_error(DBNOMEM|DBADDTOINFSTR);
3047
 
                        return(TRUE);
3048
 
                }
3049
 
                db_curinf->infstrlength *= 2;
3050
 
                (void)strcpy(str, db_curinf->infstr);
3051
 
                efree(db_curinf->infstr);
3052
 
                db_curinf->infstr = str;
3053
 
        }
3054
 
        db_curinf->infstr[db_curinf->infstrptr++] = ch;
3055
 
        db_curinf->infstr[db_curinf->infstrptr] = 0;
3056
 
        return(FALSE);
3057
 
}
3058
 
 
3059
 
BOOLEAN addstringtoinfstr(char *pp)
3060
 
{
3061
 
        REGISTER char *str;
3062
 
        REGISTER INTBIG l, i, ori;
3063
 
 
3064
 
        if (db_curinf == NOINFSTR)
3065
 
        {
3066
 
                (void)db_error(DBBADOBJECT|DBADDSTRINGTOINFSTR);
3067
 
                return(TRUE);
3068
 
        }
3069
 
        if (pp == 0) l = 0; else
3070
 
                l = strlen(pp);
3071
 
        if (db_curinf->infstrptr+l >= db_curinf->infstrlength)
3072
 
        {
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);
3077
 
                if (str == 0)
3078
 
                {
3079
 
                        db_curinf->infstrlength = ori;
3080
 
                        (void)db_error(DBNOMEM|DBADDSTRINGTOINFSTR);
3081
 
                        return(TRUE);
3082
 
                }
3083
 
                (void)strcpy(str, db_curinf->infstr);
3084
 
                efree(db_curinf->infstr);
3085
 
                db_curinf->infstr = str;
3086
 
        }
3087
 
        for(i=0; i<l; i++) db_curinf->infstr[db_curinf->infstrptr++] = pp[i];
3088
 
        db_curinf->infstr[db_curinf->infstrptr] = 0;
3089
 
        return(FALSE);
3090
 
}
3091
 
 
3092
 
/*
3093
 
 * Routine to do a variable-arguments "sprintf" to line "line" which
3094
 
 * is "len" in size.
3095
 
 */
3096
 
void evsnprintf(char *line, INTBIG len, char *msg, va_list ap)
3097
 
{
3098
 
#ifdef HAVE_VSNPRINTF
3099
 
        (void)vsnprintf(line, len-1, msg, ap);
3100
 
#else
3101
 
#  ifdef WIN32
3102
 
        (void)_vsnprintf(line, len-1, msg, ap);
3103
 
#  else
3104
 
        (void)vsprintf(line, msg, ap);
3105
 
#  endif
3106
 
#endif
3107
 
}
3108
 
 
3109
 
BOOLEAN formatinfstr(char *msg, ...)
3110
 
{
3111
 
        va_list ap;
3112
 
        char line[8192];
3113
 
 
3114
 
        var_start(ap, msg);
3115
 
        evsnprintf(line, 8192, msg, ap);
3116
 
        va_end(ap);
3117
 
        return(addstringtoinfstr(line));
3118
 
}
3119
 
 
3120
 
char *returninfstr(void)
3121
 
{
3122
 
        REGISTER char *retval;
3123
 
 
3124
 
        if (db_curinf == NOINFSTR)
3125
 
        {
3126
 
                (void)db_error(DBBADOBJECT|DBRETURNINFSTR);
3127
 
                return("");
3128
 
        }
3129
 
 
3130
 
        /* get the inifinite string */
3131
 
        retval = db_curinf->infstr;
3132
 
        db_curinf->infstrinuse = 0;
3133
 
 
3134
 
        /* if stacked, unstack */
3135
 
        db_infstrstackpos--;
3136
 
        if (db_infstrstackpos >= 0)
3137
 
                db_curinf = db_infstrstackptr[db_infstrstackpos];
3138
 
        return(retval);
3139
 
}
3140
 
 
3141
 
/****************************** FILES IN FACETS ******************************/
3142
 
 
3143
 
typedef struct
3144
 
{
3145
 
        char   **strings;
3146
 
        INTBIG   stringcount;
3147
 
        INTBIG   stringlimit;
3148
 
        CLUSTER *cluster;
3149
 
} STRINGARRAY;
3150
 
 
3151
 
/*
3152
 
 * Routine to create an object for gathering arrays of strings.
3153
 
 * Returns a pointer that can be used with "addtostringarray", "keepstringarray", "stringarraytotextfacet", and
3154
 
 * "killstringarray"
3155
 
 * Returns zero one error.
3156
 
 */
3157
 
void *newstringarray(CLUSTER *cluster)
3158
 
{
3159
 
        STRINGARRAY *sa;
3160
 
 
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;
3166
 
        return((void *)sa);
3167
 
}
3168
 
 
3169
 
void killstringarray(void *vsa)
3170
 
{
3171
 
        STRINGARRAY *sa;
3172
 
 
3173
 
        sa = (STRINGARRAY *)vsa;
3174
 
        if (sa == 0) return;
3175
 
        clearstrings(sa);
3176
 
        if (sa->stringlimit > 0) efree((char *)sa->strings);
3177
 
        efree((char *)sa);
3178
 
}
3179
 
 
3180
 
void clearstrings(void *vsa)
3181
 
{
3182
 
        STRINGARRAY *sa;
3183
 
        REGISTER INTBIG i;
3184
 
 
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;
3189
 
}
3190
 
 
3191
 
void addtostringarray(void *vsa, char *string)
3192
 
{
3193
 
        REGISTER char **newbuf;
3194
 
        REGISTER INTBIG i, newlimit;
3195
 
        STRINGARRAY *sa;
3196
 
 
3197
 
        sa = (STRINGARRAY *)vsa;
3198
 
        if (sa == 0) return;
3199
 
        if (sa->stringcount >= sa->stringlimit)
3200
 
        {
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;
3210
 
        }
3211
 
        if (allocstring(&sa->strings[sa->stringcount], string, sa->cluster)) return;
3212
 
        sa->stringcount++;
3213
 
}
3214
 
 
3215
 
/*
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.
3219
 
 */
3220
 
void stringarraytotextfacet(void *vsa, NODEPROTO *np, BOOLEAN permanent)
3221
 
{
3222
 
        STRINGARRAY *sa;
3223
 
        REGISTER INTBIG type;
3224
 
 
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);
3231
 
}
3232
 
 
3233
 
/*
3234
 
 * routine called when done adding lines to string array "vsa".  The collection of lines is
3235
 
 * returned to you.
3236
 
 */
3237
 
char **getstringarray(void *vsa, INTBIG *count)
3238
 
{
3239
 
        STRINGARRAY *sa;
3240
 
 
3241
 
        sa = (STRINGARRAY *)vsa;
3242
 
        if (sa == 0) { *count = 0;   return(0); }
3243
 
        *count = sa->stringcount;
3244
 
        return(sa->strings);
3245
 
}
3246
 
 
3247
 
/************************* TIME HANDLING *************************/
3248
 
 
3249
 
/*
3250
 
 * Time functions are centralized here to account for different time
3251
 
 * systems on different computers.
3252
 
 */
3253
 
 
3254
 
/*
3255
 
 * Routine to return the current time in seconds since January 1, 1970.
3256
 
 */
3257
 
UINTBIG getcurrenttime(void)
3258
 
{
3259
 
        time_t curtime;
3260
 
 
3261
 
        (void)time(&curtime);
3262
 
        curtime -= machinetimeoffset();
3263
 
        return(curtime);
3264
 
}
3265
 
 
3266
 
/*
3267
 
 * Routine to convert the time "curtime" to a string describing the date.
3268
 
 * This string does *NOT* have a carriage-return after it.
3269
 
 */
3270
 
char *timetostring(UINTBIG curtime)
3271
 
{
3272
 
        static char timebuf[30];
3273
 
 
3274
 
        curtime += machinetimeoffset();
3275
 
        strcpy(timebuf, ctime((time_t *)&curtime));
3276
 
        timebuf[24] = 0;
3277
 
        return(timebuf);
3278
 
}
3279
 
 
3280
 
/*
3281
 
 * Routine to parse the time in "curtime" and convert it to the year,
3282
 
 * month (0 = January), and day of month.
3283
 
 */
3284
 
void parsetime(UINTBIG curtime, INTBIG *year, INTBIG *month, INTBIG *mday,
3285
 
        INTBIG *hour, INTBIG *minute, INTBIG *second)
3286
 
{
3287
 
        struct tm *tm;
3288
 
 
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;
3297
 
}
3298
 
 
3299
 
INTBIG parsemonth(char *monthname)
3300
 
{
3301
 
        REGISTER INTBIG mon;
3302
 
        static char *name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
3303
 
                "Aug", "Sep", "Oct", "Nov", "Dec"};
3304
 
 
3305
 
        for (mon=0; mon<12; mon++)
3306
 
                if (namesame(name[mon], monthname) == 0) break;
3307
 
        if (mon < 12) return(mon+1);
3308
 
        return(0);
3309
 
}
3310
 
 
3311
 
/******************** SUBROUTINES FOR FILE I/O ****************/
3312
 
 
3313
 
INTBIG setupfiletype(char *extension, char *winfilter, INTBIG mactype, BOOLEAN binary,
3314
 
        char *shortname, char *longname)
3315
 
{
3316
 
        FILETYPES *newlist;
3317
 
        INTBIG oldcount, i;
3318
 
 
3319
 
        oldcount = db_filetypecount;
3320
 
        db_filetypecount++;
3321
 
        newlist = (FILETYPES *)emalloc(db_filetypecount * (sizeof (FILETYPES)), db_cluster);
3322
 
        for(i=0; i<oldcount; i++)
3323
 
        {
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;
3330
 
        }
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);
3339
 
        return(oldcount);
3340
 
}
3341
 
 
3342
 
/*
3343
 
 * Routine to return the extension, short name, and long name of file type "filetype".
3344
 
 */
3345
 
void describefiletype(INTBIG filetype, char **extension, char **winfilter, INTBIG *mactype,
3346
 
        BOOLEAN *binary, char **shortname, char **longname)
3347
 
{
3348
 
        REGISTER INTBIG index;
3349
 
 
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;
3357
 
}
3358
 
 
3359
 
/*
3360
 
 * Routine to return the filetype associated with short name "shortname".
3361
 
 * Returns zero on error.
3362
 
 */
3363
 
INTBIG getfiletype(char *shortname)
3364
 
{
3365
 
        REGISTER INTBIG i;
3366
 
 
3367
 
        for(i=0; i<db_filetypecount; i++)
3368
 
                if (namesame(shortname, db_filetypeinfo[i].shortname) == 0) return(i);
3369
 
        return(0);
3370
 
}
3371
 
 
3372
 
/*
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.
3378
 
 */
3379
 
char *skippath(char *file)
3380
 
{
3381
 
        REGISTER char *pt;
3382
 
 
3383
 
        pt = &file[strlen(file)-1];
3384
 
        while (pt != file && pt[-1] != '\\' && pt[-1] != '/' && pt[-1] != ':') pt--;
3385
 
        return(pt);
3386
 
}
3387
 
 
3388
 
/*
3389
 
 * routine to return the size of file whose stream is "f"
3390
 
 */
3391
 
INTBIG filesize(FILE *f)
3392
 
{
3393
 
        INTBIG savepos, endpos;
3394
 
 
3395
 
        savepos = ftell(f);
3396
 
        (void)fseek(f, 0L, 2);  /* SEEK_END */
3397
 
        endpos = ftell(f);
3398
 
        (void)fseek(f, savepos, 0);     /* SEEK_SET */
3399
 
        return(endpos);
3400
 
}
3401
 
 
3402
 
/*
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".
3407
 
 */
3408
 
FILE *xopen(char *file, INTBIG filetype, char *otherdir, char **truename)
3409
 
{
3410
 
        REGISTER FILE *f;
3411
 
        REGISTER char *pp;
3412
 
        INTBIG mactype;
3413
 
        BOOLEAN binary;
3414
 
        char rarg[3], *extension, *winfilter, *shortname, *longname;
3415
 
 
3416
 
        /* determine extension to use */
3417
 
        describefiletype(filetype&FILETYPE, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3418
 
 
3419
 
        /* determine argument to "fopen" */
3420
 
        if ((filetype&FILETYPEWRITE) != 0) strcpy(rarg, "w"); else
3421
 
                if ((filetype&FILETYPEAPPEND) != 0) strcpy(rarg, "a"); else
3422
 
                        strcpy(rarg, "r");
3423
 
        if (binary != 0) strcat(rarg, "b");
3424
 
 
3425
 
        /* remove "~" from the file name */
3426
 
        pp = truepath(file);
3427
 
 
3428
 
        /* add the extension and look for the file */
3429
 
        if (*extension != 0)
3430
 
        {
3431
 
                f = db_tryfile(pp, rarg, extension, (char *)0, truename);
3432
 
                if (f != NULL) return(f);
3433
 
        }
3434
 
 
3435
 
        /* try the file directly */
3436
 
        f = db_tryfile(pp, rarg, (char *)0, (char *)0, truename);
3437
 
        if (f != NULL) return(f);
3438
 
 
3439
 
        /* if no other directory given, stop now */
3440
 
        if (otherdir == 0 || *otherdir == 0) return(NULL);
3441
 
 
3442
 
        /* if directory path is in file name, stop now */
3443
 
        if (*pp == '/') return(NULL);
3444
 
 
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);
3448
 
 
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);
3452
 
        return(NULL);
3453
 
}
3454
 
 
3455
 
/*
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"
3460
 
 */
3461
 
FILE *db_tryfile(char *pp, char *rarg, char *extension, char *otherdir, char **truename)
3462
 
{
3463
 
        REGISTER INTBIG len;
3464
 
        REGISTER char *pt;
3465
 
 
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)
3470
 
        {
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;
3476
 
        }
3477
 
        db_tryfilename[0] = 0;
3478
 
        if (otherdir != 0)
3479
 
        {
3480
 
                (void)strcat(db_tryfilename, otherdir);
3481
 
                len = strlen(db_tryfilename);
3482
 
                if (db_tryfilename[len-1] != DIRSEP)
3483
 
                {
3484
 
                        db_tryfilename[len++] = DIRSEP;
3485
 
                        db_tryfilename[len] = 0;
3486
 
                }
3487
 
        }
3488
 
        (void)strcat(db_tryfilename, pp);
3489
 
        if (extension != 0)
3490
 
        {
3491
 
                (void)strcat(db_tryfilename, ".");
3492
 
                (void)strcat(db_tryfilename, extension);
3493
 
        }
3494
 
 
3495
 
        /* now extend this to the full path name */
3496
 
        pt = fullfilename(db_tryfilename);
3497
 
        len = strlen(pt) + 1;
3498
 
        if (len > db_tryfilenamelen)
3499
 
        {
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;
3505
 
        }
3506
 
        strcpy(db_tryfilename, pt);
3507
 
        *truename = db_tryfilename;
3508
 
        return(fopen(db_tryfilename, rarg));
3509
 
}
3510
 
 
3511
 
/*
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.
3519
 
 */
3520
 
FILE *xcreate(char *name, INTBIG filetype, char *prompt, char **truename)
3521
 
{
3522
 
        REGISTER FILE *f;
3523
 
        REGISTER char *pt, *next;
3524
 
        char warg[3], *extension, *winfilter, *shortname, *longname;
3525
 
        static char truenamelocal[256];
3526
 
        INTBIG mactype;
3527
 
        BOOLEAN binary;
3528
 
 
3529
 
        /* determine extension to use */
3530
 
        describefiletype(filetype&FILETYPE, &extension, &winfilter, &mactype, &binary, &shortname, &longname);
3531
 
 
3532
 
        pt = truepath(name);
3533
 
        if (prompt != 0 && (us_tool->toolstate&USEDIALOGS) != 0)
3534
 
        {
3535
 
                next = (char *)fileselect(prompt, filetype | FILETYPEWRITE, pt);
3536
 
                if (next == 0 || *next == 0)
3537
 
                {
3538
 
                        if (truename != 0) *truename = 0;
3539
 
                        return(NULL);
3540
 
                }
3541
 
                setdefaultcursortype(NULLCURSOR);               /* the hourglass cursor */
3542
 
                pt = next;
3543
 
        }
3544
 
        if (truename != 0)
3545
 
        {
3546
 
                (void)strcpy(truenamelocal, pt);
3547
 
                *truename = truenamelocal;
3548
 
        }
3549
 
 
3550
 
        /* determine argument to "fopen" */
3551
 
        strcpy(warg, "w");
3552
 
        if (binary) strcat(warg, "b");
3553
 
        f = fopen(pt, warg);
3554
 
#ifdef  MACOS
3555
 
        if (f != NULL)
3556
 
        {
3557
 
                void mac_settypecreator(char*, INTBIG, INTBIG);
3558
 
 
3559
 
                if (mactype == 'TEXT')
3560
 
                {
3561
 
                        mac_settypecreator(pt, 'TEXT', 'ttxt');
3562
 
                } else
3563
 
                {
3564
 
                        mac_settypecreator(pt, mactype, 'Elec');
3565
 
                }
3566
 
        }
3567
 
#endif
3568
 
        return(f);
3569
 
}
3570
 
 
3571
 
/*
3572
 
 * Routine to append to the file "name" and return a stream pointer
3573
 
 */
3574
 
FILE *xappend(char *name)
3575
 
{
3576
 
        return(fopen(truepath(name), "a"));
3577
 
}
3578
 
 
3579
 
/*
3580
 
 * Routine to close stream "f"
3581
 
 */
3582
 
void xclose(FILE *f)
3583
 
{
3584
 
        (void)fclose(f);
3585
 
}
3586
 
 
3587
 
/*
3588
 
 * Routine to flush stream "f"
3589
 
 */
3590
 
void xflushbuf(FILE *f)
3591
 
{
3592
 
        (void)fflush(f);
3593
 
}
3594
 
 
3595
 
/*
3596
 
 * Routine to report the EOF condition on stream "f"
3597
 
 */
3598
 
BOOLEAN xeof(FILE *f)
3599
 
{
3600
 
        if (feof(f) != 0) return(TRUE);
3601
 
        return(FALSE);
3602
 
}
3603
 
 
3604
 
/*
3605
 
 * Routine to seek to position "pos", nature "nat", on stream "f"
3606
 
 */
3607
 
void xseek(FILE *f, INTBIG pos, INTBIG nat)
3608
 
{
3609
 
        fseek(f, pos, nat);
3610
 
}
3611
 
 
3612
 
/*
3613
 
 * Routine to return the current position in stream "f"
3614
 
 */
3615
 
INTBIG xtell(FILE *f)
3616
 
{
3617
 
        return(ftell(f));
3618
 
}
3619
 
 
3620
 
/*
3621
 
 * Routine to write the formatted message "s" with parameters "p1" through "p9"
3622
 
 * to stream "f".
3623
 
 */
3624
 
void xprintf(FILE *f, char *s, ...)
3625
 
{
3626
 
        va_list ap;
3627
 
 
3628
 
        var_start(ap, s);
3629
 
        (void)vfprintf(f, s, ap);
3630
 
        va_end(ap);
3631
 
}
3632
 
 
3633
 
/*
3634
 
 * Routine to get the next character in stream "f"
3635
 
 */
3636
 
INTSML xgetc(FILE *f)
3637
 
{
3638
 
        return(getc(f));
3639
 
}
3640
 
 
3641
 
/*
3642
 
 * Routine to "unget" the character "c" back to stream "f"
3643
 
 */
3644
 
void xungetc(char c, FILE *f)
3645
 
{
3646
 
        (void)ungetc(c, f);
3647
 
}
3648
 
 
3649
 
/*
3650
 
 * Routine to put the character "c" into stream "f"
3651
 
 */
3652
 
void xputc(char c, FILE *f)
3653
 
{
3654
 
        putc(c, f);
3655
 
}
3656
 
 
3657
 
/*
3658
 
 * Routine to put the string "s" into stream "f"
3659
 
 */
3660
 
void xputs(char *s, FILE *f)
3661
 
{
3662
 
        (void)fputs(s, f);
3663
 
}
3664
 
 
3665
 
/*
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").
3668
 
 */
3669
 
INTBIG xfread(char *buf, INTBIG size, INTBIG count, FILE *f)
3670
 
{
3671
 
#if 0           /* limits reads to BUFSIZE */
3672
 
        REGISTER INTBIG amtjustread, amttoread, totalamtread;
3673
 
 
3674
 
        totalamtread = 0;
3675
 
        while (count > 0)
3676
 
        {
3677
 
                amttoread = mini(count, BUFSIZ/size);
3678
 
                amtjustread = fread(buf, size, amttoread, f);
3679
 
                totalamtread += amtjustread;
3680
 
                if (amtjustread != amttoread)
3681
 
                {
3682
 
                        if (ferror(f) != 0) clearerr(f); else
3683
 
                        {
3684
 
                                if (feof(f) != 0) break;
3685
 
                        }
3686
 
                }
3687
 
                count -= amtjustread;
3688
 
                buf += amtjustread*size;
3689
 
        }
3690
 
        return(totalamtread);
3691
 
#else
3692
 
        REGISTER INTBIG ret;
3693
 
 
3694
 
        for(;;)
3695
 
        {
3696
 
                ret = fread(buf, size, count, f);
3697
 
                if (ret == count || feof(f) != 0) break;
3698
 
                clearerr(f);
3699
 
        }
3700
 
        return(ret);
3701
 
#endif
3702
 
}
3703
 
 
3704
 
/*
3705
 
 * Routine to write "count" elements of size "size" to stream "f" from the buffer
3706
 
 * at "buf".  Returns the number of bytes written.
3707
 
 */
3708
 
INTBIG xfwrite(char *buf, INTBIG size, INTBIG count, FILE *f)
3709
 
{
3710
 
        REGISTER INTBIG ret;
3711
 
 
3712
 
        for(;;)
3713
 
        {
3714
 
                ret = fwrite(buf, size, count, f);
3715
 
                if (ret == count || feof(f) != 0) break;
3716
 
                clearerr(f);
3717
 
        }
3718
 
        return(ret);
3719
 
}
3720
 
 
3721
 
/*
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
3725
 
 * reached.
3726
 
 */
3727
 
BOOLEAN xfgets(char *line, INTBIG limit, FILE *file)
3728
 
{
3729
 
        REGISTER char *pp;
3730
 
        REGISTER INTBIG c, total;
3731
 
 
3732
 
        pp = line;
3733
 
        total = 1;
3734
 
        for(;;)
3735
 
        {
3736
 
                c = xgetc(file);
3737
 
                if (c == EOF)
3738
 
                {
3739
 
                        if (pp == line) return(TRUE);
3740
 
                        break;
3741
 
                }
3742
 
                *pp = (char)c;
3743
 
                if (*pp == '\n' || *pp == '\r') break;
3744
 
                pp++;
3745
 
                if ((++total) >= limit) break;
3746
 
        }
3747
 
        *pp = 0;
3748
 
        return(FALSE);
3749
 
}
3750
 
 
3751
 
/******************** SUBROUTINES FOR ENCRYPTION ****************/
3752
 
 
3753
 
/*
3754
 
 * A one-rotor machine designed along the lines of Enigma but considerably trivialized
3755
 
 */
3756
 
# define ROTORSZ 256            /* a power of two */
3757
 
# define MASK    (ROTORSZ-1)
3758
 
void myencrypt(char *text, char *key)
3759
 
{
3760
 
        INTBIG ic, i, k, temp, n1, n2, nr1, nr2;
3761
 
        UINTBIG random;
3762
 
        INTBIG seed;
3763
 
        char *pt, t1[ROTORSZ], t2[ROTORSZ], t3[ROTORSZ], deck[ROTORSZ];
3764
 
        static char readable[ROTORSZ] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-";
3765
 
 
3766
 
        /* first setup the machine */
3767
 
        seed = 123;
3768
 
        for (i=0; i<13; i++) seed = seed*key[i] + i;
3769
 
        for(i=0; i<ROTORSZ; i++)
3770
 
        {
3771
 
                t1[i] = (char)i;
3772
 
                t3[i] = 0;
3773
 
                deck[i] = (char)i;
3774
 
        }
3775
 
        for(i=0; i<ROTORSZ; i++)
3776
 
        {
3777
 
                seed = 5*seed + key[i%13];
3778
 
                random = seed % 65521;
3779
 
                k = ROTORSZ-1 - i;
3780
 
                ic = (random&MASK) % (k+1);
3781
 
                random >>= 8;
3782
 
                temp = t1[k];
3783
 
                t1[k] = t1[ic];
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;
3788
 
                t3[k] = (char)ic;
3789
 
                t3[ic] = (char)k;
3790
 
        }
3791
 
        for(i=0; i<ROTORSZ; i++) t2[t1[i]&MASK] = (char)i;
3792
 
 
3793
 
        /* now run the machine */
3794
 
        n1 = 0;
3795
 
        n2 = 0;
3796
 
        nr2 = 0;
3797
 
        for(pt = text; *pt; pt++)
3798
 
        {
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];
3803
 
                n1++;
3804
 
                if (n1 == ROTORSZ)
3805
 
                {
3806
 
                        n1 = 0;
3807
 
                        n2++;
3808
 
                        if (n2 == ROTORSZ) n2 = 0;
3809
 
                        db_shuffle(deck, key);
3810
 
                }
3811
 
        }
3812
 
}
3813
 
 
3814
 
void db_shuffle(char *deck, char *key)
3815
 
{
3816
 
        INTBIG i, ic, k, temp;
3817
 
        UINTBIG random;
3818
 
        static INTBIG seed = 123;
3819
 
 
3820
 
        for(i=0; i<ROTORSZ; i++)
3821
 
        {
3822
 
                seed = 5*seed + key[i%13];
3823
 
                random = seed % 65521;
3824
 
                k = ROTORSZ-1 - i;
3825
 
                ic = (random&MASK) % (k+1);
3826
 
                temp = deck[k];
3827
 
                deck[k] = deck[ic];
3828
 
                deck[ic] = (char)temp;
3829
 
        }
3830
 
}