1 #ifndef lint
2 static char *sccsid ="memut.c	(CWI)	1.1	85/03/01";
3 #endif
4 /* memory utilities */
5 
6 #include "ideal.h"
7 #include "y.tab.h"
8 
9 char *fooalloc;
10 #define	tryalloc(new,kind)	\
11 	if (!(new =(kind *) malloc(sizeof (kind)))) {\
12 	emergency ();\
13 	if (!(new =(kind *) malloc(sizeof (kind)))) {\
14 		fprintf (stderr, "ideal: Out of space\n");\
15 		exit (1);\
16 		}\
17 	};\
18 	for (fooalloc = (char *) new;\
19 		fooalloc < ((char *) new) + sizeof (kind);\
20 		fooalloc ++)\
21 		*fooalloc = '\0';
22 
23 STMTPTR stmtgen (kind, stmt)
24 int kind;
25 char *stmt;
26 {
27 	register STMTPTR newguy;
28 	tryalloc(newguy,STMTNODE);
29 	newguy->kind = kind;
30 	newguy->stmt = stmt;
31 	return (newguy);
32 }
33 
34 BOXPTR boxgen (name,stmtlist)
35 int name;
36 STMTPTR stmtlist;
37 {
38 	register BOXPTR newguy;
39 	STMTPTR bdstmt;
40 	tryalloc(newguy,BOXNODE);
41 	newguy->name = name;
42 	/* the stmts are in reverse order (check the yacc grammar) */
43 	newguy->stmtlist = reverse (stmtlist);
44 	if (bdstmt = nextstmt (BDLIST, stmtlist))
45 		bdstmt->stmt = (char *) reverse ((STMTPTR) bdstmt->stmt);
46 	return (newguy);
47 }
48 
49 NAMEPTR namegen (name)
50 int name;
51 {
52 	register NAMEPTR newguy;
53 	tryalloc(newguy,NAMENODE);
54 	newguy->name = name;
55 	return (newguy);
56 }
57 
58 EXPRPTR exprgen (expr)
59 EXPR expr;
60 {
61 	register EXPRPTR newguy;
62 	tryalloc(newguy,EXPRNODE);
63 	newguy->expr = expr;
64 	return (newguy);
65 }
66 
67 PUTPTR putgen (name, parm, p_or_c)
68 int name;
69 BOXPTR parm;
70 int p_or_c;
71 {
72 	register PUTPTR newguy;
73 	tryalloc(newguy,PUTNODE);
74 	newguy->name = name;
75 	newguy->parm = parm;
76 	newguy->p_or_c = p_or_c;
77 	return (newguy);
78 }
79 
80 PENPTR pengen (from, to, copies, start, end, pen)
81 EXPR from,
82 	to,
83 	copies,
84 	start,
85 	end;
86 BOXPTR pen;
87 {
88 	register PENPTR newguy;
89 	tryalloc(newguy,PEN_NODE);
90 	newguy->from = from;
91 	newguy->to = to;
92 	newguy->copies = copies;
93 	newguy->start = start;
94 	newguy->end = end;
95 	newguy->pen = pen;
96 	return (newguy);
97 }
98 
99 MISCPTR miscgen (info)
100 int info;
101 {
102 	register MISCPTR newguy;
103 	tryalloc(newguy,MISCNODE);
104 	newguy->info = info;
105 	return (newguy);
106 }
107 
108 INTLPTR intlgen (oper, left, right)
109 int oper;
110 EXPR left,
111 right;
112 {
113 	register INTLPTR newguy;
114 	tryalloc(newguy,EXPRINTL);
115 	newguy->leaf = FALSE;
116 	newguy->oper = oper;
117 	newguy->left = left;
118 	newguy->right = right;
119 	return (newguy);
120 }
121 
122 INTLPTR commagen (real, imag)
123 float real,
124 	imag;
125 {
126 	register INTLPTR newguy;
127 	tryalloc(newguy,EXPRINTL);
128 	newguy->leaf = FALSE;
129 	newguy->oper = ';';
130 	newguy->left = (EXPR) depgen ((VARPTR) NULL, real);
131 	newguy->right = (EXPR) depgen ((VARPTR) NULL, imag);
132 	return (newguy);
133 }
134 
135 EXTLPTR extlgen (path)
136 NAMEPTR path;
137 {
138 	register EXTLPTR newguy;
139 	tryalloc(newguy,EXPREXTL);
140 	newguy->leaf = TRUE;
141 	newguy->info.path = path;
142 	newguy->kind = PATH;
143 	return (newguy);
144 }
145 
146 EXTLPTR fextlgen (value)
147 float value;
148 {
149 	register EXTLPTR newguy;
150 	tryalloc(newguy,EXPREXTL);
151 	newguy->leaf = TRUE;
152 	newguy->info.const = value;
153 	newguy->kind = CONST;
154 	return (newguy);
155 }
156 
157 NOADPTR noadgen (defnode, edgevarlist, boxvarlist)
158 PUTPTR defnode;
159 VARPTR edgevarlist;
160 VARPTR boxvarlist;
161 {
162 	register NOADPTR newguy;
163 	tryalloc(newguy,NOAD);
164 	newguy->defnode = defnode;
165 	newguy->edgevarlist = edgevarlist;
166 	newguy->boxvarlist = boxvarlist;
167 	return (newguy);
168 }
169 
170 VARPTR vargen (name, re, deplist)
171 int name;
172 boolean re;
173 DEPPTR deplist;
174 {
175 	register VARPTR newguy;
176 	tryalloc(newguy,VARNODE);
177 	newguy->re_name = re?name:-name;
178 	newguy->deplist = deplist;
179 	return (newguy);
180 }
181 
182 static DEPPTR depavh = NULL;
183 static DEPPTR depavt = NULL;
184 
185 DEPPTR depgen (var, coeff)
186 VARPTR var;
187 float coeff;
188 {
189 	register DEPPTR newguy;
190 	if (depavh) {
191 		newguy = depavh;
192 		depavh = depavh->next;
193 		if (!depavh)
194 			depavt = NULL;
195 		newguy->next = NULL;
196 	} else
197 		tryalloc(newguy,DEPNODE);
198 	newguy->var = var;
199 	newguy->coeff = coeff;
200 	return (newguy);
201 }
202 
203 LINEPTR linegen (x0, y0, x1, y1)
204 float x0,
205 	y0,
206 	x1,
207 	y1;
208 {
209 	register LINEPTR newguy;
210 	tryalloc(newguy,LINENODE);
211 	newguy->kind = LINE;
212 	newguy->x0 = x0;
213 	newguy->y0 = y0;
214 	newguy->x1 = x1;
215 	newguy->y1 = y1;
216 	return (newguy);
217 }
218 
219 EDGEPTR edgeline (x0, y0, x1, y1)
220 float x0,
221 	y0,
222 	x1,
223 	y1;
224 {
225 	EDGEPTR newguy;
226 	tryalloc(newguy,EDGENODE);
227 	newguy->fax = (ARCPTR) NULL;
228 	newguy->sx = x0;
229 	newguy->sy = y0;
230 	newguy->ex = x1;
231 	newguy->ey = y1;
232 	newguy->stx = newguy->sx + 0.2*(newguy->ex - newguy->sx);
233 	newguy->sty = newguy->sy + 0.2*(newguy->ey - newguy->sy);
234 	newguy->etx = newguy->ex + 0.2*(newguy->sx - newguy->ex);
235 	newguy->ety = newguy->ey + 0.2*(newguy->sy - newguy->ey);
236 	dprintf "opaque polygon edge: %f,%f -- %f,%f\n",
237 		x0,y0, x1,y1
238 	);
239 	return (newguy);
240 }
241 
242 LINEPTR circgen (x0, y0, r)
243 float x0,
244 	y0,
245 	r;
246 {
247 	register CIRCPTR newguy;
248 	tryalloc(newguy,CIRCNODE);
249 	newguy->kind = CIRCLE;
250 	newguy->x0 = x0;
251 	newguy->y0 = y0;
252 	newguy->r = r;
253 	return ((LINEPTR) newguy);
254 }
255 
256 /*
257 LINEPTR arcgen (x0, y0, x1, y1, x2, y2, theta1, theta2, radius)
258 float x0,
259 	y0,
260 	x1,
261 	y1,
262 	x2,
263 	y2,
264 	theta1,
265 	theta2,
266 	radius;
267 {
268 	register ARCPTR newguy;
269 	tryalloc(newguy,ARCNODE);
270 	newguy->kind = ARC;
271 	newguy->x0 = x0;
272 	newguy->y0 = y0;
273 	newguy->x1 = x1;
274 	newguy->y1 = y1;
275 	newguy->x2 = x2;
276 	newguy->y2 = y2;
277 	newguy->theta1 = theta1;
278 	newguy->theta2 = theta2;
279 	newguy->radius = radius;
280 	return ((LINEPTR) newguy);
281 }
282 */
283 
284 LINEPTR angularc (x0, y0, radius, theta1, theta2)
285 float x0,
286 	y0,
287 	theta1,
288 	theta2,
289 	radius;
290 {
291 	/* theta1 and theta2 should be in radians */
292 	register ARCPTR newguy;
293 	tryalloc(newguy,ARCNODE);
294 	radius = fabs(radius);
295 	newguy->kind = ARC;
296 	newguy->x0 = x0;
297 	newguy->y0 = y0;
298 	newguy->x1 = x0 + cos (theta1)*radius;
299 	newguy->y1 = y0 + sin (theta1)*radius;
300 	newguy->x2 = x0 + cos (theta2)*radius;
301 	newguy->y2 = y0 + sin (theta2)*radius;
302 	theta1 = rprin (theta1);
303 	theta2 = rprin (theta2);
304 	while (theta2 - theta1 < EPSILON)
305 		theta2 += 2*PI;
306 	if (fabs(theta2 - theta1) > PI)
307 		radius *= -1;
308 	newguy->theta1 = theta1;
309 	newguy->theta2 = theta2;
310 	newguy->radius = radius;
311 	return ((LINEPTR) newguy);
312 }
313 
314 LINEPTR pointarc (x1,y1, x2,y2, x3,y3)
315 float x1,y1, x2,y2, x3,y3;
316 {
317 	float A, B, C, D, E, F;
318 	float denom, x, y;
319 	float startang, midang, endang;
320 	A = -2.0*(x2 - x1);
321 	B = -2.0*(y2 - y1);
322 	C = -2.0*(x3 - x2);
323 	D = -2.0*(y3 - y2);
324 	denom = A*D - B*C;
325 	if (fabs(denom) < EPSILON) {
326 		dprintf "pointarc: (%f,%f) (%f,%f) (%f,%f) collinear\n", x1,y1, x2,y2, x3,y3);
327 		return (linegen (x1,y1, x3,y3));
328 	}
329 	E = x1*x1 + y1*y1 - x2*x2 - y2*y2;
330 	F = x2*x2 + y2*y2 - x3*x3 - y3*y3;
331 	x = E*D - F*B;
332 	x /= denom;
333 	y = A*F - C*E;
334 	y /= denom;
335 	startang = rprin(atan2 (y1-y, x1-x));
336 	midang = rprin(atan2 (y2-y, x2-x));
337 	endang = rprin(atan2 (y3-y, x3-x));
338 	angorder (&startang, midang, &endang);
339 	dprintf "pointarc: (%f,%f) (%f,%f) (%f,%f)\n", x1,y1, x2,y2, x3,y3);
340 	dprintf "pointarc: (%f,%f) %f\n", x, y, hypot(x1-x,y1-y));
341 	dprintf "pointarc: /_%f -- /_%f\n", startang, endang);
342 	return (angularc (x, y, hypot(x1-x,y1-y), startang, endang));
343 }
344 
345 EDGEPTR edgearc (x1,y1, x2,y2, x3,y3)
346 float x1,y1, x2,y2, x3,y3;
347 {
348 	EDGEPTR newguy;
349 	tryalloc(newguy,EDGENODE);
350 	newguy->fax = (ARCPTR) pointarc (x1,y1, x2,y2, x3,y3);
351 	if (newguy->fax->kind == LINE) {
352 		newguy->sx = newguy->etx = x1;
353 		newguy->sy = newguy->ety = y1;
354 		newguy->ex = newguy->stx = x3;
355 		newguy->ey = newguy->sty = y3;
356 		tryfree(newguy->fax);
357 		newguy->fax = NULL;
358 		newguy->flipped = FALSE;
359 	} else if (newguy->fax->kind == ARC) {
360 		ARCPTR temp;
361 		temp = newguy->fax;
362 		newguy->sx = x1;
363 		newguy->sy = y1;
364 		newguy->ex = x3;
365 		newguy->ey = y3;
366 		newguy->stx = temp->x0 + fabs(temp->radius)*cos(temp->theta1 + 0.2);
367 		newguy->sty = temp->y0 + fabs(temp->radius)*sin(temp->theta1 + 0.2);
368 		newguy->etx = temp->x0 + fabs(temp->radius)*cos(temp->theta2 - 0.2);
369 		newguy->ety = temp->y0 + fabs(temp->radius)*sin(temp->theta2 - 0.2);
370 		if ((fabs(newguy->sx - temp->x1) > EPSILON)
371 			|| (fabs(newguy->sy - temp->y1) > EPSILON)) {
372 			newguy->flipped = TRUE;
373 			fexch(&newguy->stx,&newguy->etx);
374 			fexch(&newguy->sty,&newguy->ety);
375 		} else
376 			newguy->flipped = FALSE;
377 		dprintf "edgearc: (%f,%f) --> (%f,%f)\n",
378 			newguy->sx, newguy->sy,
379 			newguy->ex, newguy->ey
380 		);
381 		dprintf "edgearc: st (%f,%f); et (%f,%f)\n",
382 			newguy->stx, newguy->sty,
383 			newguy->etx, newguy->ety
384 		);
385 		dprintf "edgearc: %sflipped\n", newguy->flipped?"":"UN");
386 	} else impossible ("edgearc");
387 	return (newguy);
388 }
389 
390 LINEPTR textgen (command, string, x0, y0)
391 int command;
392 char *string;
393 float x0,
394 	y0;
395 {
396 	register TEXTPTR newguy;
397 	tryalloc(newguy,TEXTNODE);
398 	newguy->kind = STRING;
399 	newguy->command = command;
400 	newguy->string = string;
401 	newguy->x0 = x0;
402 	newguy->y0 = y0;
403 	return ((LINEPTR) newguy);
404 }
405 
406 LINEPTR splgen (knotlist)
407 EXPRPTR knotlist;
408 {
409 	register SPLPTR newguy;
410 	tryalloc(newguy,SPLNODE);
411 	newguy->kind = SPLINE;
412 	newguy->knotlist = knotlist;
413 	return ((LINEPTR) newguy);
414 }
415 
416 STRPTR strgen (command, string, at)
417 int command;
418 char *string;
419 EXPR at;
420 {
421 	register STRPTR newguy;
422 	tryalloc(newguy,STRNODE);
423 	newguy->command = command;
424 	newguy->string = string;
425 	newguy->at = at;
426 	return (newguy);
427 }
428 
429 
430 EQNPTR eqngen (eqn, noad)
431 EXPR eqn;
432 NOADPTR noad;
433 {
434 	register EQNPTR newguy;
435 	tryalloc(newguy,EQNNODE);
436 	newguy->eqn = eqn;
437 	newguy->noad = noad;
438 	return (newguy);
439 }
440 OPQPTR opqgen (code, alpha)
441 int code;
442 float alpha;
443 {
444 	OPQPTR newguy;
445 	tryalloc(newguy,OPQNODE);
446 	newguy->code = code;
447 	newguy->alpha = alpha;
448 	return (newguy);
449 }
450 
451 void depfree (doomed)
452 DEPPTR doomed;
453 {
454 	register DEPPTR doomwalk;
455 	if (!doomed || doomed == depavt)
456 		return;
457 	if (!depavh) {
458 		depavt = depavh = doomed;
459 		while (depavt->next)
460 			depavt = depavt->next;
461 		return;
462 	}
463 	doomwalk = doomed;
464 	while (doomwalk->next) {
465 		if (doomwalk->next == depavt)
466 			return;
467 		doomwalk = doomwalk->next;
468 	}
469 	depavt->next = doomed;
470 	depavt = doomwalk;
471 }
472 
473 void nextfree (doomed)
474 DEPPTR doomed;
475 {
476 	register DEPPTR walk;
477 	while (doomed) {
478 		walk = doomed->next;
479 		tryfree(doomed);
480 		doomed = walk;
481 	}
482 }
483 
484 void namefree (doomed)
485 NAMEPTR doomed;
486 {
487 	nextfree ((DEPPTR) doomed);
488 }
489 
490 void exprlsfree (doomed)
491 EXPRPTR doomed;
492 {
493 	register EXPRPTR walk;
494 	while (doomed) {
495 		walk = doomed->next;
496 		exprfree (doomed->expr);
497 		tryfree(doomed);
498 		doomed = walk;
499 	}
500 }
501 
502 void linefree (doomed)
503 LINEPTR doomed;
504 {
505 	nextfree ((DEPPTR) doomed);
506 }
507 
508 void intlfree (doomed)
509 INTLPTR doomed;
510 {
511 	depfree ((DEPPTR) doomed->left);
512 	depfree ((DEPPTR) doomed->right);
513 	tryfree(doomed);
514 }
515 
516 void noadfree (doomed)
517 NOADPTR doomed;
518 {
519 	if (!doomed)
520 		return;
521 	noadfree (doomed->son);
522 	noadfree (doomed->brother);
523 	varfree (doomed->edgevarlist);
524 	varfree (doomed->boxvarlist);
525 	linefree(doomed->linelist);
526 	tryfree(doomed);
527 }
528 
529 void varfree (doomed)
530 VARPTR doomed;
531 {
532 	if (!doomed)
533 		return;
534 	varfree (doomed->next);
535 	depfree (doomed->deplist);
536 	tryfree(doomed);
537 }
538 
539 
540 void exprfree (doomed)
541 EXPR doomed;
542 {
543 	if (!doomed)
544 		return;
545 	if (!((EXTLPTR) doomed)->leaf) {
546 		/* convention for functions (name in left, arg list hanging
547 		/* off right) will ream you if not careful
548 		/* This also depends on the allocator not complaining if
549 		/* you free things twice with no intervening allocation.
550 		/* (see processing of alpha[x,y] in idyac.y) */
551 		if (((INTLPTR) doomed)->oper == NAME) {
552 			exprfree (((EXPRPTR)((INTLPTR) doomed)->right)->expr);
553 			tryfree(((INTLPTR) doomed)->right);
554 		} else if (((INTLPTR) doomed)->oper == ';') {
555 			depfree ((DEPPTR)((INTLPTR) doomed)->left);
556 			depfree ((DEPPTR)((INTLPTR) doomed)->right);
557 		} else {
558 			exprfree (((INTLPTR) doomed)->left);
559 			exprfree (((INTLPTR) doomed)->right);
560 		}
561 	}
562 	tryfree(doomed);
563 }
564 
565 
566 
567 void boxfree (doomed)
568 BOXPTR doomed;
569 {
570 	register STMTPTR curstmt, nextstmt;
571 	for (curstmt = doomed->stmtlist;
572 		curstmt;
573 		curstmt = nextstmt) {
574 		switch (curstmt->kind) {
575 		case '=':
576 			exprfree ((EXPR) curstmt->stmt);
577 			break;
578 		case CONN:
579 			exprlsfree ((EXPRPTR) curstmt->stmt);
580 			break;
581 		case USING:
582 			exprfree (((PENPTR) curstmt->stmt)->from);
583 			exprfree (((PENPTR) curstmt->stmt)->to);
584 			exprfree (((PENPTR) curstmt->stmt)->copies);
585 			exprfree (((PENPTR) curstmt->stmt)->start);
586 			exprfree (((PENPTR) curstmt->stmt)->end);
587 			boxfree (((PENPTR) curstmt->stmt)->pen);
588 			tryfree(curstmt->stmt);
589 			break;
590 		case PUT:
591 			boxfree (((PUTPTR) curstmt->stmt)->parm);
592 			tryfree(curstmt->stmt);
593 			break;
594 		case DRAW:
595 			tryfree(curstmt->stmt);
596 			break;
597 		case STRING:
598 /* if using malloc to get string space, can use the real free here */
599 			free(((STRPTR) curstmt->stmt)->string);
600 			exprfree (((STRPTR) curstmt->stmt)->at);
601 			tryfree(curstmt->stmt);
602 			break;
603 		case SPLINE:
604 			exprlsfree ((EXPRPTR) curstmt->stmt);
605 			break;
606 		case OPAQUE:
607 			tryfree(curstmt->stmt);
608 			break;
609 		case BDLIST:
610 			exprlsfree ((EXPRPTR) curstmt->stmt);
611 			break;
612 		case VAR:
613 			namefree ((NAMEPTR) curstmt->stmt);
614 			break;
615 	}
616 	nextstmt = curstmt->next;
617 	tryfree(curstmt);
618 	}
619 }
620 
621 void emergency ()
622 {
623 	nextfree (depavh);
624 	depavh = depavt = NULL;
625 }
626