1 /*
2 * EFargs.c -
3 *
4 * General command-line argument processing and overall initialization
5 * for the .ext file flattener.
6 *
7 * *********************************************************************
8 * * Copyright (C) 1985, 1990 Regents of the University of California. *
9 * * Permission to use, copy, modify, and distribute this *
10 * * software and its documentation for any purpose and without *
11 * * fee is hereby granted, provided that the above copyright *
12 * * notice appear in all copies. The University of California *
13 * * makes no representations about the suitability of this *
14 * * software for any purpose. It is provided "as is" without *
15 * * express or implied warranty. Export of this software outside *
16 * * of the United States of America may require an export license. *
17 * *********************************************************************
18 */
19
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/extflat/EFargs.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
22 #endif /* not lint */
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "utils/magic.h"
30 #include "utils/paths.h"
31 #include "utils/geometry.h"
32 #include "utils/hash.h"
33 #include "utils/utils.h"
34 #include "utils/malloc.h"
35 #include "utils/pathvisit.h"
36 #include "extflat/extflat.h"
37 #include "extflat/EFint.h"
38
39 #define atoCap(s) ((EFCapValue)atof(s))
40
41 /* --------------------- Visible outside extflat ---------------------- */
42
43 /* Command-line flags */
44 EFCapValue EFCapThreshold = 2; /* -c/-C: (fF) smallest interesting C */
45 int EFResistThreshold = 10; /* -r/-R: (Ohms) smallest interesting R */
46 int EFOutputFlags = 0; /* -t: output of nodename trailing #!'s */
47 char *EFSearchPath = NULL; /* -p: Search path for .ext files */
48 char *EFArgTech = NULL; /* -T: Tech specified on command line */
49
50 /* Misc globals */
51 float EFScale = 0.0; /* Uninitialized scale factor */
52 char *EFVersion = MAGIC_VERSION;/* Version number of .ext format we read */
53 char *EFLibPath = NULL; /* Library search path for .ext files */
54 char *EFTech = NULL;
55 char *EFStyle = NULL; /* Start with no extraction style */
56 bool EFCompat = TRUE; /* Start with backwards compatibility enabled */
57
58 #ifdef MAGIC_WRAPPER
59 extern char *Path; /* magic's search path---note this should */
60 /* be done with #include "utils/main.h" but */
61 /* this is easier. */
62 #endif
63
64
65 /* -------------------- Visible only inside extflat ------------------- */
66
67 /* Command-line flags */
68 bool efWarn = FALSE; /* -v: Warn about duplicate node names */
69 bool efHNStats = FALSE; /* -z: TRUE if we gather mem usage stats */
70 bool efWatchNodes = FALSE; /* -n: TRUE if watching nodes in table below */
71 HashTable efWatchTable; /* -n: Names to watch, keyed by HierName */
72
73 /* Misc globals */
74 int efResists[128]; /* Sheet resistivity for each resist class */
75 int efNumResistClasses = 0; /* Number of resist classes */
76 bool efResistChanged = FALSE; /* TRUE if .ext resist classes mismatch */
77 bool efScaleChanged = FALSE; /* TRUE if .ext scales mismatch */
78
79 /* Forward declarations */
80 #ifndef MAGIC_WRAPPER
81 extern int efLoadPathFunc();
82 extern void efLoadSearchPath();
83 #endif
84
85 /*
86 * ----------------------------------------------------------------------------
87 *
88 * EFArgs --
89 *
90 * Process command-line arguments that are relevant to the extractor
91 * flattener. Arguments that are specific to the calling function
92 * are processed by the procedure (*argsProc)(), which should
93 * have the following form:
94 *
95 * (*argsProc)(pargc, pargv, cdata)
96 * int *pargc;
97 * char ***pargv;
98 * ClientData cdata;
99 * {
100 * }
101 *
102 * If we don't recognize an argument, we call (*argsProc)() with
103 * *pargc and *pargv pointing to the position in the argument
104 * vector that we didn't recognize. If (*argsProc)() also doesn't
105 * recognize the argument, it exits; otherwise, it updates *pargc
106 * and *pargv to point past the argument it gobbled off and returns.
107 * If argsProc is NULL, then any arguments we don't recognize are
108 * considered errors.
109 *
110 * Arguments processed are:
111 *
112 * -T techname Specify the name of the technology, leaving
113 * EFArgTech pointing to the technology name.
114 * -p path Use the colon-separated search path 'path'
115 * for finding .ext files. Overrides any paths
116 * found in .magicrc files.
117 * -s sym=value Set the name 'sym' in the symbol hash table to
118 * have value 'value', where 'value' is an integer.
119 * Certain attributes interpreted during circuit
120 * flattening may have symbolic values; the -s flag
121 * provides a means of associating a numeric value
122 * with a symbol.
123 * -S symfile Read the file 'symfile', which should consist of
124 * lines of the form sym=value, processing each line
125 * as though it were an argument to -s.
126 *
127 * The following flags are for debugging purposes only:
128 * -n nodename For debugging: print all merges involving
129 * the node named 'nodename'.
130 * -N nodefile For debugging: print all merges involving
131 * any of the nodes whose names appear in the
132 * file 'nodefile' (one node name per line).
133 * -v Warn about unusual occurrences while flattening
134 * the circuit; mainly for debugging.
135 * -z Print memory utilized for names.
136 *
137 * Results:
138 * Returns a pointer to a string containing the base name
139 * of the input .ext file.
140 *
141 * Side effects:
142 * Can set global variables based on the values of command-line
143 * arguments.
144 * err_result, if non-null, is set to TRUE if an error occurred.
145 * err_result is only used by the Tcl version of Magic.
146 *
147 * ----------------------------------------------------------------------------
148 */
149
150 char *
EFArgs(argc,argv,err_result,argsProc,cdata)151 EFArgs(argc, argv, err_result, argsProc, cdata)
152 int argc; /* Number of command-line args */
153 char *argv[]; /* Vector of command-line args */
154 bool *err_result; /* Set to TRUE if error occurs */
155 bool (*argsProc)(); /* Called for args we don't recognize */
156 ClientData cdata; /* Passed to (*argsProc)() */
157 {
158 static char libpath[FNSIZE];
159 char *realIn, line[1024], *inname = NULL, *name, *cp;
160 HierName *hierName;
161 FILE *f;
162
163 char usage_text[] =
164 "Standard arguments: [-R] [-C] [-r rthresh] [-c cthresh] [-v]\n"
165 "[-p searchpath] [-s sym=value] [-S symfile] [-t trimchars]\n"
166 #ifdef MAGIC_WRAPPER
167 "[rootfile]\n";
168 #else
169 "[-T techname] rootfile\n";
170 #endif
171
172 if (err_result != NULL) *err_result = FALSE;
173
174 /* Hash table of nodes we're going to watch if -N given */
175 HashInitClient(&efWatchTable, 32, HT_CLIENTKEYS,
176 efHNCompare, (char *(*)()) NULL,
177 efHNHash, (int (*)()) NULL);
178
179 /* Process command line options */
180 for (argc--, argv++; argc-- > 0; argv++)
181 {
182 if (argv[0][0] != '-')
183 {
184 if (inname)
185 {
186 TxError("Warning: multiple input files specified; ");
187 TxError("ignoring \"%s\"\n", inname);
188 }
189 inname = argv[0];
190 continue;
191 }
192
193 switch (argv[0][1])
194 {
195 /*** NORMAL OPTIONS ***/
196 case 'c':
197 if ((cp = ArgStr(&argc, &argv, "cap threshold")) == NULL)
198 goto usage;
199 EFCapThreshold = atoCap(cp); /* Femtofarads */
200 break;
201 case 'p':
202 EFSearchPath = ArgStr(&argc, &argv, "search path");
203 if (EFSearchPath == NULL)
204 goto usage;
205 break;
206 case 'r':
207 if ((cp = ArgStr(&argc, &argv, "resist threshold")) == NULL)
208 goto usage;
209 EFResistThreshold = atoi(cp); /* Ohms */
210 break;
211 case 's':
212 if ((cp = ArgStr(&argc, &argv, "symbolic name")) == NULL)
213 goto usage;
214 efSymAdd(cp);
215 break;
216 case 't':
217 if ((cp = ArgStr(&argc, &argv, "trim characters")) == NULL)
218 goto usage;
219 if (strchr(cp, '!')) EFOutputFlags |= EF_TRIMGLOB;
220 if (strchr(cp, '#')) EFOutputFlags |= EF_TRIMLOCAL;
221 if (strchr(cp, ',')) EFOutputFlags |= EF_CONVERTCOMMA;
222 if (strchr(cp, '=')) EFOutputFlags |= EF_CONVERTEQUAL;
223 if (strchr(cp, '[')) EFOutputFlags |= EF_CONVERTBRACKETS;
224 if (strchr(cp, ']')) EFOutputFlags |= EF_CONVERTBRACKETS;
225 break;
226 case 'C':
227 EFCapThreshold = (EFCapValue)INFINITE_THRESHOLD_F;
228 break;
229 case 'R':
230 EFResistThreshold = INFINITE_THRESHOLD;
231 break;
232 case 'S':
233 if ((cp = ArgStr(&argc, &argv, "symbol file")) == NULL)
234 goto usage;
235 efSymAddFile(cp);
236 break;
237
238 #ifndef MAGIC_WRAPPER
239 case 'T':
240 if ((EFArgTech = ArgStr(&argc, &argv, "tech name")) == NULL)
241 goto usage;
242 break;
243 #endif
244
245 /*** OPTIONS FOR DEBUGGING ***/
246 case 'n':
247 if ((name = ArgStr(&argc, &argv, "nodename")) == NULL)
248 goto usage;
249 printf("Watching node '%s'\n", name);
250 hierName = EFStrToHN((HierName *) NULL, name);
251 (void) HashFind(&efWatchTable, (char *) hierName);
252 efWatchNodes = TRUE;
253 break;
254 case 'N':
255 if ((name = ArgStr(&argc, &argv, "filename")) == NULL)
256 goto usage;
257
258 /* Add everything in the file to the hash table */
259 f = fopen(name, "r");
260 if (f == NULL)
261 {
262 perror(name);
263 break;
264 }
265 while (fgets(line, sizeof line, f))
266 {
267 cp = strchr(line, '\n');
268 if (cp) *cp = '\0';
269 printf("Watching node '%s'\n", line);
270 hierName = EFStrToHN((HierName *) NULL, line);
271 (void) HashFind(&efWatchTable, (char *) hierName);
272 }
273 (void) fclose(f);
274 efWatchNodes = TRUE;
275 break;
276 case 'v':
277 efWarn = TRUE;
278 break;
279 case 'z':
280 efHNStats = TRUE;
281 break;
282 case 'h':
283 if (argsProc != NULL) (*argsProc)(&argc, &argv, cdata);
284 TxPrintf(usage_text);
285 if (err_result != NULL) *err_result = TRUE;
286 return NULL;
287
288 /*** Try a caller-supplied argument processing function ***/
289 default:
290 if (argsProc == NULL)
291 goto usage;
292 if ((*argsProc)(&argc, &argv, cdata))
293 {
294 TxError("\n");
295 goto usage;
296 }
297 break;
298 }
299 }
300
301 /* Find the search path if one was not specified */
302 if (EFSearchPath == NULL)
303 #ifdef MAGIC_WRAPPER
304 /* Set the search path to be the same as magic's search path */
305 EFSearchPath = StrDup(NULL, Path);
306 #else
307 efLoadSearchPath(&EFSearchPath);
308 #endif
309
310 EFLibPath = libpath;
311 *EFLibPath = 0; /* start with no path */
312 if (EFArgTech) (void) sprintf(EFLibPath, EXT_PATH, EFArgTech);
313
314 if (inname == NULL)
315 #ifdef MAGIC_WRAPPER
316 return NULL;
317 #else
318 goto usage;
319 #endif
320
321 /* Eliminate trailing .ext from input name */
322 if ((cp = strrchr(inname, '.')) && strcmp(cp, ".ext") == 0)
323 {
324 realIn = (char *) mallocMagic((unsigned)(cp - inname + 1));
325 (void) strncpy(realIn, inname, cp - inname);
326 realIn[cp - inname] = '\0';
327 inname = realIn;
328 }
329 return inname;
330
331 usage:
332 TxError(usage_text);
333
334 #ifdef MAGIC_WRAPPER
335 if (err_result != NULL) *err_result = TRUE;
336 return NULL;
337 #else
338 exit (1);
339 /*NOTREACHED*/
340 #endif
341 }
342
343 #ifndef MAGIC_WRAPPER
344
345 /*
346 * ----------------------------------------------------------------------------
347 *
348 * efLoadSearchPath --
349 *
350 * Load the search path string pointed to by 'path'
351 * with whatever is specified in the .magicrc files
352 * in $CAD_ROOT/magic/sys, ~, and ., searched in that
353 * order with the last path taking precedence. See paths.h.
354 *
355 * Results:
356 * None.
357 *
358 * Side effects:
359 * Leaves *path pointing to the correct search path,
360 * which may either be static or allocated via StrDup().
361 *
362 * ----------------------------------------------------------------------------
363 */
364
365 void
efLoadSearchPath(path)366 efLoadSearchPath(path)
367 char **path;
368 {
369 PaVisit *pv;
370
371 *path = NULL;
372 pv = PaVisitInit();
373 PaVisitAddClient(pv, "path", efLoadPathFunc, (ClientData) path);
374 PaVisitFiles(DOT_MAGIC_PATH, ".magicrc", pv);
375 PaVisitFree(pv);
376 if (*path == NULL)
377 *path = ".";
378 }
379
380 int
efLoadPathFunc(line,ppath)381 efLoadPathFunc(line, ppath)
382 char *line;
383 char **ppath;
384 {
385 char *cp, *dp, c;
386 char path[BUFSIZ];
387
388 /* Skip leading blanks */
389 for (cp = &line[4]; *cp && isspace(*cp); cp++)
390 /* Nothing */;
391
392 /* Copy the path into 'path' */
393 for (dp = path; (c = *cp++) && !isspace(c) && c != '\n'; )
394 {
395 if (c == '"')
396 {
397 while ((c = *cp++) && c != '"')
398 *dp++ = c;
399 if (c == '\0')
400 break;
401 }
402 else *dp++ = c;
403 }
404 *dp = '\0';
405 (void) StrDup(ppath, path);
406 return 0; /* continue search */
407 }
408
409 #endif
410