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