1 /* $XConsortium: objects.c,v 1.5 92/03/20 15:56:06 eswu Exp $ */
2 /* Copyright International Business Machines, Corp. 1991
3 * All Rights Reserved
4 * Copyright Lexmark International, Inc. 1991
5 * All Rights Reserved
6 *
7 * License to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and that
10 * both that copyright notice and this permission notice appear in
11 * supporting documentation, and that the name of IBM or Lexmark not be
12 * used in advertising or publicity pertaining to distribution of the
13 * software without specific, written prior permission.
14 *
15 * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
16 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
17 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
18 * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
19 * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
20 * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
21 * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
22 * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
23 * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
24 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
25 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
26 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27 * THIS SOFTWARE.
28 */
29 /* OBJECTS CWEB V0025 ******** */
30 /*
31 :h1.OBJECTS Module - TYPE1IMAGER Objects Common Routines
32
33 This module defines and implements the C structures that represent
34 objects in the TYPE1IMAGER. All common routines for manipulating these
35 objects are defined in this module. Specific routines for
36 specific objects are defined in the modules that deal with that
37 object type.
38
39
40 &author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
41
42
43 :h3.Include Files
44
45 The included files are:
46 */
47 #define GLOBALS 1 /* see :hdref refid=debugvar. */
48 /*
49 The following two includes are C standards; we include them because we
50 use 'toupper' and the 'str'-type functions in this module. Potentially
51 these may be defined as macros; if these ".h" files do not exist on your
52 system it is a pretty safe bet that these are external entry points and
53 you do do not need to include these header files.
54 */
55
56 #include "types.h"
57 #include <string.h>
58 #include <ctype.h>
59 #include "util.h"
60
61 /*
62 override incorrect system functions; for example you might define
63 a macro for "strcpy" that diverts it to "my_strcpy".
64 */
65
66 /* moved these includes from above the */
67 /* was included first (it contains com- */
68 /* piler defines). dsr 081291 */
69 #include "objects.h"
70 #include "spaces.h"
71 #include "paths.h"
72 #include "regions.h"
73 #include "fonts.h"
74 #include "pictures.h"
75 #include "strokes.h"
76 #include "cluts.h"
77 static const char *TypeFmt(int);
78 static int ObjectPostMortem(struct xobject *obj);
79
80 /*
81 :h3.The "pointer" Macro - Define a Generic Pointer
82
83 Sadly, many compilers will give a warning message when a pointer to
84 one structure is assigned to a pointer to another. We've even seen
85 some that give severe errors (when the wrong pointer type is used as
86 an initializer or returned from a function). TYPE1IMAGER has routines
87 like Dup and Allocate that are perfectly willing to duplicate or
88 allocate any of a number of different types of structures. How to
89 declare them in a truely portable way?
90
91 Well, there is no single good answer that I've found. You can always
92 beg the question and "cast" everything. I find this distracting and the
93 resulting code ugly. On the other hand, we have found at least one
94 compiler that will accept "void *" as a generic pointer that can
95 assigned to any other pointer type without error or warning (apparently
96 this is also the ANSI standard). So, we define "void *" to be a generic
97 pointer. (You might have to change this for your compiler; the "ifndef"
98 allows the change to be made on the command line if you want.)
99 :i1/portability assumptions/
100 */
101 /*SHARED LINE(S) ORIGINATED HERE*/
102 /*
103 :h3.Functions Provided to the TYPE1IMAGER User
104
105 This module provides the following TYPE1IMAGER entry points:
106 */
107 /*SHARED LINE(S) ORIGINATED HERE*/
108 /*
109 Note that entry points that are intended for use external to TYPE1IMAGER
110 begin with the characters :q/xi/. Macros are used to make the names
111 more mnemonic.
112 */
113
114 /*
115 :h3.Functions Provided to Other Modules
116
117 This module provides the following functions for other modules:
118 */
119 /*SHARED LINE(S) ORIGINATED HERE*/
120 /*
121 Note that entry points that intended for use within TYPE1IMAGER, but
122 which must be global because they are used across module boundaries,
123 begin with the characters :q/I_/. Macros are used to make the names
124 more mnemonic.
125
126 Entry points totally within a module use mnemonic names and are
127 declared :hp2/static/. One of the compilers I used had a bug when
128 static functions were passed as addresses. Thus, some functions
129 which are logically "static" are not so declared.
130
131 Note also the trick of declaring routines, like Consume(), with a
132 variable number of arguments. To avoid the restrictions on variable
133 numbers of arguments in the macro processor, we just replace the
134 text 'Consume' with 'I_Consume'.
135 */
136 /*
137 :h3.Macros Provided to Other Modules
138
139 This is the module where we define all the useful constants like
140 TRUE, FALSE, and NULL, and simple expressions like MIN(), MAX(), and ABS().
141 We might as well get to it right here:
142 */
143 /*SHARED LINE(S) ORIGINATED HERE*/
144 /*
145 Notice that upper case is used for constant values and macro
146 definitions. I generally follow that convention.
147
148 Many more global macros are defined later in this module.
149 */
150 /*
151 :h2.Basic TYPE1IMAGER Object Structure
152
153 All TYPE1IMAGER objects which are available to the user have a common
154 header. This header is defined below:
155 */
156
157 /*SHARED LINE(S) ORIGINATED HERE*/
158 /*
159 The following define is an attempt to centralize the definition of the
160 common xobject data shared by structures that are derived from the
161 generic xobject structure. For example, the structure font, defined in
162 fonts.shr :
163 &code.
164 struct font {
165 char type;
166 char flag;
167 int references;
168 ... other data types & structs ...
169 }
170 &ecode.
171 would now be defined as:
172 &code.
173 struct font {
174 XOBJ_COMMON
175 ... other data types & structs ...
176 }
177 &ecode.
178 Thus we have a better-structured inheritance mechanism. 3-26-91 PNM
179 */
180 /*SHARED LINE(S) ORIGINATED HERE*/
181 /*
182 :h3.Object Type Definitions
183
184 These constants define the values which go in the 'type' field of
185 an TYPE1IMAGER object structure:
186 */
187 /*SHARED LINE(S) ORIGINATED HERE*/
188 /*
189 :h3.Flag Byte Definitions
190
191 Many programmers define flag bits as a mask (for example, 0x04), and
192 test, set, and reset them as follows:
193
194 &code.
195 if ((flag & PERMANENT) != 0)
196
197 flag |= PERMANENT;
198 flag &= &inv.PERMANENT;
199 :exmp.
200
201 I favor a style where the 'if' statement can ask a question:
202
203 &code.
204 if (ISPERMANENT(flag))
205
206 flag |= ISPERMANENT(ON);
207 flag &= &inv.ISPERMANENT(ON);
208
209 :exmp.
210 This said, we now define two bit settings of the flag byte of the
211 object. "ISPERMANENT" will be set by the user, when he calls
212 Permanent(). "ISIMMORTAL" will be used for compiled-in objects
213 that we don't want the user to ever destroy.
214 */
215 /*SHARED LINE(S) ORIGINATED HERE*/
216 /*
217 Flag bit definitions that apply to all objects are assigned
218 starting with the least significant (0x01) bit. Flag bit definitions
219 specific to a certain object type are assigned starting with the
220 most significant (0x80) bit. We hope they never meet.
221 */
222 /*
223 :h3 id=preserve.PRESERVE() Macro
224
225 Occasionally an TYPE1IMAGER operator is implemented by calling other
226 TYPE1IMAGER operators. For example, Arc2() calls Conic(). When we
227 call more than one operator as a subroutine, we have to be careful
228 of temporary objects. A temporary object will be consumed by the
229 subroutine operator and then is no longer available for the caller.
230 This can be prevented simply by bumping a temporary object's reference
231 count.
232 */
233 /*SHARED LINE(S) ORIGINATED HERE*/
234
235 /*
236 :h3.RefRoll() Macro to Detect References Count Rollover
237
238 The following macro is designed to check for reference count rollover.
239 A return value of TRUE means rollover has not occurred; a return value
240 of FALSE means we cannot increment the reference count. Note also that
241 those functions that use this macro must decrement the reference count
242 afterwards. 3-26-91 PNM
243 */
244
245 #define RefRoll(obj) (++(obj)->references > 0)
246
247 /*
248 :h2.TYPE1IMAGER Object Functions
249
250 :h3.INT32COPY() - Macro to Copy "long" Aligned Data
251
252 Copying arbitrary bytes in C is a bit of a problem. "strcpy" can't be
253 used, because 0 bytes are special-cased. Most environments have a
254 routine "memcopy" or "bcopy" or "bytecopy" that copies memory containing
255 zero bytes. Sadly, there is no standard on the name of such a routine,
256 which makes it impossible to write truely portable code to use it.
257
258 It turns out that TYPE1IMAGER, when it wants to copy data, frequently
259 knows that both the source and destination are aligned on "long"
260 boundaries. This allows us to copy by using "long *" pointers. This
261 is usually very efficient on almost all processors. Frequently, it
262 is more efficient than using general-purpose assembly language routines.
263 So, we define a macro to do this in a portable way. "dest" and "source"
264 must be long-aligned, and "bytes" must be a multiple of "sizeof(long)":
265 */
266 /*SHARED LINE(S) ORIGINATED HERE*/
267 /*
268 :h3.Allocate() - Allocating a Memory Block
269
270 Allocate returns a pointer to memory object that is a copy of
271 the template passed (if any). In addition, extra bytes may be
272 allocated contiguously with the object. (This may be useful for
273 variable size objects such as edge lists. See :hdref refid=regions..)
274
275 Allocate() always returns a non-immortal object, even if the template is
276 immortal. Therefore a non-NULL template must have a "flag" byte.
277
278 If the template is NULL, then 'size' bytes are cleared to all NULLs.
279
280 If the template is non-NULL, a new object is allocated in memory.
281 It therefore seems logical that its reference count field should be
282 set to 1. So, a nun-NULL template must also have a "references" field.
283 PNM 3-26-91
284 */
285
t1_Allocate(register int size,void * p,register int extra)286 struct xobject *t1_Allocate(
287 register int size, /* number of bytes to allocate & initialize */
288 void *p, /* example structure to allocate */
289 register int extra) /* any extra uninitialized bytes needed contiguously */
290 {
291 /* the actual argument p is one of
292 struct XYspace *
293 struct edgelist *
294 struct hintsegment *
295 struct region *
296 struct segment *
297 struct xobject *
298 */
299 register struct xobject *template = p;
300 register struct xobject *r;
301
302 /*
303 * round up 'size' and 'extra' to be an integer number of 'long's:
304 */
305 size = (size + sizeof(int32_t) - 1) & -sizeof(int32_t);
306 extra = (extra + sizeof(int32_t) - 1) & -sizeof(int32_t);
307 if (size + extra <= 0)
308 t1_abort("Non-positive allocate?");
309 r = (struct xobject *) Xalloc(size + extra);
310
311 while (r == NULL) {
312 if (!GimeSpace()) {
313 IfTrace1(TRUE, "malloc attempted %d bytes.\n",
314 size + extra);
315 t1_abort("We have REALLY run out of memory");
316 }
317 r = (struct xobject *) Xalloc(size + extra);
318 }
319
320 /*
321 * copy the template into the new memory:
322 */
323 if (template != NULL) {
324 /* Added references count decrement if template is not permanent.
325 This is for the case where Allocate is called by a Dupxxxx
326 function, which was in turn called by Unique(). (PNM) */
327 if (!ISPERMANENT(template->flag))
328 --template->references;
329 INT32COPY(r, template, size);
330 r->flag &= ~(ISPERMANENT(ON) | ISIMMORTAL(ON));
331 /* added reference field 3-2-6-91 PNM */
332 r->references = 1;
333 }
334 else {
335 register char **p1;
336
337 for (p1=(char **)r; size > 0; size -= sizeof(char *))
338 *p1++ = NULL;
339 }
340
341 if (MemoryDebug > 1) {
342 register int *L;
343 L = (int *) r;
344 IfTrace4(TRUE, "Allocating at %p: %x %x %x\n",
345 L, L[-1], L[0], L[1]);
346 }
347 return(r);
348 }
349
350 /*
351 :h3.Free() - Frees an Allocated Object
352
353 This routine makes a sanity check to make sure the "type" field of the
354 standard object structure has not been cleared. If the object is
355 not a standard structure, then the macro "NonObjectFree" is available
356 that does not perform this check.
357
358 In either case, the object must not be the NULL pointer. This preserves
359 portability, as the C system Xfree() will not always accept NULL.
360 */
361
Free(void * p)362 void Free(void *p) /* structure to free */
363 {
364 /* the actual argument p is one of
365 struct XYspace *
366 struct edgelist *
367 struct region *
368 struct segment *
369 struct xobject *
370 */
371 register struct xobject *obj = p;
372
373 if (obj->type == INVALIDTYPE)
374 t1_abort("Free of already freed object?");
375 obj->type = INVALIDTYPE;
376
377 if (MemoryDebug > 1) {
378 register int *L;
379 L = (int *) obj;
380 IfTrace4(TRUE,"Freeing at %p: %x %x %x\n", L, L[-1], L[0], L[1]);
381 }
382
383 Xfree(obj);
384 }
385
386 /*
387 :h3.Permanent() - Makes an Object Permanent
388
389 Real simple--just set a flag. Every routine that consumes its objects
390 (which is almost every user entry) must check this flag, and not consume
391 the object if it is set.
392
393 If a temporary object is made permanent, and there is more than one
394 reference to it, we must first Copy() it, then set the ISPERMANENT
395 flag. Note also that the reference count must be incremented when an
396 object is changed from temporary to permanent (see the ISUNIQUE macro).
397
398 Note that the purpose of this function is to convert an object into a
399 permanent object:
400 If it was permanent to begin with, we do nothing;
401 If it was temporary and unique, we set the PERMANENT flag and increment
402 the reference count;
403 If it was temporary and nonunique, we must make a unique Copy(), set
404 the PERMANENT flag, and set the reference count to 2. We must also
405 decrement the original object's reference count, because what we have
406 done is to change one of the old temporary handles to a permanent one.
407 3-26-91 PNM
408 */
409
t1_Permanent(void * p)410 struct xobject *t1_Permanent(void *p) /* object to be made permanent */
411 {
412 /* the actual argument p is one of
413 struct segment *
414 struct xobject *
415 */
416 register struct xobject *obj = p;
417
418 IfTrace1((MustTraceCalls),"Permanent(%p)\n", obj);
419
420 if ( (obj != NULL) && ( !(ISPERMANENT(obj->flag)) ) )
421 {
422 /* there is a non-NULL, temporary object to be made permanent.
423 If there are multiple references to this object, first get
424 a new COPY().
425 Note also that we have to decrement the reference count if
426 we do a Copy() here, because we are consuming the temporary
427 argument passed, and returning a unique, permanent one.
428 */
429 if ( obj->references > 1)
430 {
431 obj = Copy(obj);
432 }
433 /* now set the permanent flag, and increment the reference
434 count, since a temporary object has now become permanent. */
435 obj->references++;
436 obj->flag |= ISPERMANENT(ON);
437 }
438 return(obj);
439 }
440
441 #if 0
442 /*
443 :h3.Temporary() - Undoes the Effect of "Permanent()"
444
445 This simply resets the "ISPERMANENT" flag.
446
447 If a permanent object is made temporary, and there is more than one reference
448 to it, we must first Copy() it, then reset the ISPERMANENT flag. However,
449 if the permanent object has obly one reference, we need only decrement the
450 reference count ( and reset the flag).
451
452 Note that this function, in the case of a PERMANENT argument, basically
453 converts the PERMANENT handle to a TEMPORARY one. Thus, in the case of
454 a nonunique, permanent argument passed, we not only make a Copy(),
455 we also decrement the reference count, to reflect the fact that we have
456 lost a permanent handle and gained a temporary one.
457 PNM 3-2-6-91
458 */
459
460 struct xobject *xiTemporary(
461 register struct xobject *obj) /* object to be made not permanent */
462 {
463 IfTrace1((MustTraceCalls),"Temporary(%p)\n", obj);
464
465 if (obj != NULL) {
466 /* if it's already temporary, there's nothing to do. */
467 if ISPERMANENT(obj->flag)
468 {
469 /* if there are multiple references to this object, get a
470 Copy we can safely alter. Recall that the reference count
471 is incremented for permanent objects.
472 Recall further that Copy returns an object with the
473 same flag state and a reference count of 2 (for PERMANENT
474 objects).
475 Thus, regardless of whether or not we need to copy a
476 permanent object, we still decrement its reference
477 count and reset the flag.
478 */
479 if (obj->references != 2 || ISIMMORTAL(obj->flag))
480 {
481 /* not unique; consume handle, get a temporary Copy! */
482 obj = Copy(obj);
483 }
484 /* else decrement the reference count (since it's going from
485 permanent to temporary) and clear the flag. */
486 else {
487 obj->references--;
488 obj->flag &= ~ISPERMANENT(ON);
489 }
490 }
491 }
492 return(obj);
493 }
494 #endif
495
496 /*
497 :h3.Dup() - Duplicate an Object
498
499 Dup will increment the reference count of an object, only making a
500 Copy() if needed.
501 Note that Dup() retains the state of the permanent flag.
502 3-26-91 PNM
503 */
504
505
t1_Dup(register struct xobject * obj)506 struct xobject *t1_Dup(
507 register struct xobject *obj) /* object to be duplicated */
508 {
509 register char oldflag; /* copy of original object's flag byte */
510
511 IfTrace1((MustTraceCalls),"Dup(%p)\n", obj);
512
513 if (obj == NULL)
514 return(NULL);
515 /* An immortal object must be Copy'ed, so that we get a mortal
516 copy of it, since we try not to destroy immortal objects. */
517 if (ISIMMORTAL(obj->flag))
518 return(Copy(obj));
519
520 /* if incrementing the reference count doesn't cause the count
521 to wrap, simply return the object with the count bumped. Note
522 that the RefRoll macro increments the count to perform the
523 rollover check, so we must decrement the count. */
524 if (RefRoll(obj))
525 return(obj);
526
527 /* that didn't work out, so put the count back and call Copy(). */
528 --obj->references;
529 oldflag = obj->flag;
530 obj = Copy(obj);
531 if (ISPERMANENT(oldflag))
532 obj = Permanent(obj);
533 return(obj);
534 }
535
536 /*
537 :h3.Copy() - Make a New Copy of an Object
538
539 This is the generic Copy() where the object type is unknown. There
540 are specific Copyxxx functions for known object types.
541
542 Copy will create a NEW temporary object, and WILL NOT simply bump the
543 reference count.
544
545 Sometimes duplicating an object is just as simple as Allocating with it
546 as a template. But other objects are complicated linked lists. So, we
547 let each module provide us a routine (or macro) that duplicates the
548 objects it knows about.
549 */
550
t1_Copy(register struct xobject * obj)551 struct xobject *t1_Copy(
552 register struct xobject *obj) /* object to be Copy'ed */
553 {
554 if (obj == NULL)
555 return(NULL);
556
557 if (ISPATHTYPE(obj->type))
558 obj = (struct xobject *) CopyPath((struct segment *)obj);
559 else
560 switch (obj->type) {
561 case SPACETYPE:
562 obj = (struct xobject *) CopySpace((struct XYspace *)obj); break;
563 case FONTTYPE:
564 obj = (struct xobject *) CopyFont(obj); break;
565 case REGIONTYPE:
566 obj = (struct xobject *) CopyRegion((struct region *)obj); break;
567 case PICTURETYPE:
568 obj = (struct xobject *) CopyPicture(obj); break;
569 case LINESTYLETYPE:
570 obj = (struct xobject *) CopyLineStyle(obj); break;
571 case STROKEPATHTYPE:
572 obj = (struct xobject *) CopyStrokePath(obj); break;
573 case CLUTTYPE:
574 obj = (struct xobject *) CopyCLUT(obj); break;
575 default:
576 return(ArgErr("Copy: invalid object", obj, NULL));
577 }
578
579 return(obj);
580 }
581
582 /*
583 :h3.Destroy() - Destroys an Object
584
585 This can get complicated. Just like with Copy(), we let the experts
586 handle it.
587 */
Destroy(void * p)588 struct xobject *Destroy(void *p) /* object to be destroyed */
589 {
590 /* the actual argument p is one of
591 struct region *
592 struct segment *
593 struct xobject *
594 */
595 register struct xobject *obj = p;
596
597 IfTrace1((MustTraceCalls),"Destroy(%p)\n", obj);
598
599 if (obj == NULL)
600 return(NULL);
601 if (ISIMMORTAL(obj->flag)) {
602 IfTrace1(TRUE,"Destroy of immortal object %p ignored\n", obj);
603 return(NULL);
604 }
605 if (ISPATHTYPE(obj->type))
606 KillPath((struct segment *)obj);
607 else {
608 switch (obj->type) {
609 case REGIONTYPE:
610 KillRegion((struct region *)obj);
611 break;
612 case SPACETYPE:
613 KillSpace(obj);
614 break;
615 case LINESTYLETYPE:
616 KillLineStyle(obj);
617 break;
618 case FONTTYPE:
619 KillFont(obj);
620 break;
621 case PICTURETYPE:
622 KillPicture(obj);
623 break;
624 case STROKEPATHTYPE:
625 KillStrokePath(obj);
626 break;
627 case CLUTTYPE:
628 KillCLUT(obj);
629 break;
630 default:
631 return(ArgErr("Destroy: invalid object", obj, NULL));
632 }
633 }
634 return(NULL);
635 }
636 /*
637 :h2.Generally Useful Macros
638
639 :h3.FOLLOWING() - Macro to Point to the Data Following a Structure
640
641 There are several places in TYPE1IMAGER where we will allocate variable
642 data that belongs to a structure immediately after that structure.
643 This is a performance technique, because it reduces the number of
644 trips we have to take through Xalloc() and Xfree(). It turns out C has
645 a very convenient way to point past a structure--if 'p' is a pointer
646 to a structure, 'p+1' is a pointer to the data after it. This
647 behavior of C is somewhat startling and somewhat hard to follow, if
648 you are not used to it, so we define a macro to point to the data
649 following a structure:
650 */
651 /*SHARED LINE(S) ORIGINATED HERE*/
652 /*
653 :h3.TYPECHECK() - Verify the Type of an Argument
654
655 This macro tests the type of an argument. If the test fails, it consumes
656 any other arguments as necessary and causes the imbedding routine to
657 return the value 'whenBAD'.
658
659 Note that the consumeables list should be an argument list itself, for
660 example (0) or (2,A,B). See :hdref refid=consume. below.
661 */
662
663 /*SHARED LINE(S) ORIGINATED HERE*/
664 /*
665 :h3.ARGCHECK() - Perform an Arbitrary Check on an Argument
666
667 This macro is a generalization of TYPECHECK to take an arbitrary
668 predicate. If the error occurs (i.e., the predicate is true), the
669 arbitrary message 'msg' is returned.
670 */
671
672 /*SHARED LINE(S) ORIGINATED HERE*/
673 /*
674 :h3.TYPENULLCHECK() - Extension of TYPECHECK() for NULL arguments
675
676 Many routines allow NULLs to be passed as arguments. 'whenBAD' will
677 be returned in this case, too.
678 */
679
680 /*SHARED LINE(S) ORIGINATED HERE*/
681 /*
682 :h3.MAKECONSUME() - Create a "Consume"-type Macro
683
684 Consuming an object means destroying it if it is not permanent. This
685 logic is so common to all the routines, that it is immortalized in this
686 macro. For example, ConsumePath(p) can be simply defined as
687 MAKECONSUME(p,KillPath(p)). In effect, this macro operates on a
688 meta-level.
689 :i1/consuming objects/
690 */
691
692 /*SHARED LINE(S) ORIGINATED HERE*/
693
694 /*
695 :h3.MAKEUNIQUE() - Create a "Unique"-type Macro
696
697 Many routines are written to modify their arguments in place. Thus,
698 they want to insure that they duplicate an object if it is permanent.
699 This is called making an object "unique". For example, UniquePath(p)
700 can be simply defined as MAKEUNIQUE(p,DupPath(p)).
701 :i1/unique objects/
702 */
703
704 /*SHARED LINE(S) ORIGINATED HERE*/
705
706 /*
707 An object is unique (and directly alterable) if there is only one
708 reference to it, and it is not permanent (in which case we increment
709 the reference count, so we don't have to check the permanent bit).
710 3-26-91 PNM
711
712 Note the rules for making a unique object:
713 &drawing.
714 IF (obj->references = 1) return(obj);
715 ELSE (references > 1)
716 IF (ISPERMANENT(obj->flag)) return(Dupxxx(obj));
717 ELSE (nonunique, temporary object!)
718 obj->references--; return(Dupxxx(obj));
719 &edrawing.
720 If we must make a Copy of a nonunique, temporary object, we decrement
721 reference count of the original object!
722 */
723
724 /*
725 :h3.Unique() - Make a Unique Object
726
727 Here is a generic 'Unique' function if the object type is not known.
728 Why didn't we build it with the MAKEUNIQUE macro, you ask? Well, we
729 used to, but there is at least one damn compiler in the world that
730 raises errors if the types of an "(a) ? b : c" expression do not match.
731 Also, when we changed Dup() to retain the permanent/temporary flag, we
732 wanted to make sure "Unique" always returned a temporary object.
733
734 Note that we cannot use Dup() to create a copy of the object in question,
735 because Dup() may simply bump the reference count, and not return a
736 unique copy to us. That is why we use t1_Copy().
737
738 The purpose of this function is to make sure we have a copy of an object
739 that we can safely alter:
740 :ol.
741 :li.If we have a unique, temporary object, we simply return the argument.
742 :li.If we have a nonunique, temporary object, we have to make a new copy
743 of it, and decrement the reference count of the original object, to reflect
744 the fact that we traded temporary handles.
745 :li.If we have a permanent object, we make a temporary copy of it, but
746 we do not decrement the reference count of the original permanent object,
747 because permanent objects, by definition, are persistent. 3-2-6-91 PNM
748 :eol.
749 */
750
t1_Unique(struct xobject * obj)751 struct xobject *t1_Unique(struct xobject *obj)
752 {
753 /* if the original object is not already unique, make a unique
754 copy...Note also that if the object was not permanent, we must
755 consume the old handle! 3-26-91 PNM
756 NOTE : consumption of the old handle moved to Allocate. 4-18-91 */
757 if (!obj || obj->references == 1)
758 return(obj);
759
760 obj = Copy(obj);
761 /* and make sure we return a temporary object ! */
762 if (ISPERMANENT(obj->flag))
763 {
764 obj->flag &= ~ISPERMANENT(ON);
765 obj->references--;
766 }
767 return(obj);
768 }
769
770
771 /*
772 :h2.Initialization, Error, and Debug Routines
773
774 :h3 id=debugvar.Declarations for Debug Purposes
775
776 We declare all the debug flags here. Some link editors make the not
777 unreasonable restriction that only one module may declare and
778 initialize global variables; all the rest must declare the variable
779 'extern'. This is logical, but is somewhat awkward to implement with
780 C include files. We solve the problem by temporarily making the name
781 'extern' a null name if GLOBALS is defined. (GLOBALS is only defined
782 in this OBJECTS module.) Since 'externs' can't be initialized, we
783 have to handle that with #defines too.
784 :i1/GLOBALS (&#define.)/
785 */
786
787 /*SHARED LINE(S) ORIGINATED HERE*/
788 static const char *ErrorMessage = NULL;
789
790 /*
791 :h3.Pragmatics() - Set/Reset Debug Flags
792
793 We provide a controlled way for the TYPE1IMAGER user to set and reset
794 our debugging and tracing:
795 */
Pragmatics(const char * username,int value)796 static void Pragmatics(
797 const char *username, /* name of the flag */
798 int value) /* value to set it to */
799 {
800 register char *p; /* temporary loop variable */
801 #define NAMESIZE 40
802 char name[NAMESIZE]; /* buffer to store my copy of 'username' */
803
804 if (strlen(username) >= NAMESIZE)
805 t1_abort("Pragmatics name too large");
806 strcpy(name, username);
807 for (p = name; *p != '\0'; p++)
808 *p = toupper((unsigned char)*p);
809
810 if (!strcmp(name, "ALL"))
811 MustTraceCalls = InternalTrace = /* MustCrash = */
812 LineIOTrace = value;
813
814 else if (!strcmp(name, "LINEIOTRACE"))
815 LineIOTrace = value;
816
817 else if (!strcmp(name, "TRACECALLS"))
818 MustTraceCalls = value;
819
820 else if (!strcmp(name, "CHECKARGS"))
821 MustCheckArgs = value;
822
823 else if (!strcmp(name, "PROCESSHINTS"))
824 ProcessHints = value;
825
826 else if (!strcmp(name, "SAVEFONTPATHS"))
827 SaveFontPaths = value;
828
829 else if (!strcmp(name, "CRASTERCOMPRESSIONTYPE"))
830 CRASTERCompressionType = value;
831
832 else if (!strcmp(name, "CRASHONUSERERROR"))
833 MustCrash = value;
834
835 else if (!strcmp(name, "DEBUG"))
836 StrokeDebug = SpaceDebug = PathDebug = ConicDebug = LineDebug =
837 RegionDebug = MemoryDebug = FontDebug =
838 HintDebug = ImageDebug = OffPageDebug = value;
839
840 else if (!strcmp(name, "CONICDEBUG"))
841 ConicDebug = value;
842
843 else if (!strcmp(name, "LINEDEBUG"))
844 LineDebug = value;
845
846 else if (!strcmp(name, "REGIONDEBUG"))
847 RegionDebug = value;
848
849 else if (!strcmp(name, "PATHDEBUG"))
850 PathDebug = value;
851
852 else if (!strcmp(name, "SPACEDEBUG"))
853 SpaceDebug = value;
854
855 else if (!strcmp(name, "STROKEDEBUG"))
856 StrokeDebug = value;
857
858 else if (!strcmp(name, "MEMORYDEBUG"))
859 MemoryDebug = value;
860
861 else if (!strcmp(name, "FONTDEBUG"))
862 FontDebug = value;
863
864 else if (!strcmp(name, "HINTDEBUG"))
865 HintDebug = value;
866
867 else if (!strcmp(name, "IMAGEDEBUG"))
868 ImageDebug = value;
869
870 else if (!strcmp(name, "OFFPAGEDEBUG"))
871 OffPageDebug = value;
872
873 #ifdef MC68000
874 /*
875 The following pragmatics flag turns on or off instruction histograming
876 for performance analysis. It is only defined in the Delta card
877 environment.
878 */
879 else if (!strcmp(name, "PROFILE")) {
880 if (value)
881 StartProfile();
882 else
883 StopProfile();
884 }
885 #endif
886 else if (!strcmp(name, "FLUSHCACHE")) {
887 while (GimeSpace()) { ; }
888 }
889
890 else if (!strcmp(name, "CACHEDCHARS"))
891 CachedChars = (value <= 0) ? 1 : value;
892
893 else if (!strcmp(name, "CACHEDFONTS"))
894 CachedFonts = (value <= 0) ? 1 : value;
895
896 else if (!strcmp(name, "CACHEBLIMIT"))
897 CacheBLimit = value;
898
899 else if (!strcmp(name, "CONTINUITY"))
900 Continuity = value;
901
902
903 else {
904 printf("Pragmatics flag = '%s'\n", name);
905 ArgErr("Pragmatics: flag not known", NULL, NULL);
906 }
907 return;
908 }
909
910 /*
911 :h3.Consume() - Consume a List of Arguments
912
913 This general purpose routine is provided in the case where the object
914 type(s) to be consumed are unknown or not yet verified, and/or it is
915 not known whether the object is permanent.
916
917 If the type of the argument is known, it is faster to directly consume
918 that type, for example, ConsumeRegion() or ConsumePath(). Furthermore,
919 if it is already known that the object is temporary, it is faster to
920 just kill it rather than consume it, for example, KillSpace().
921 */
922
923 void
Consume(int n,...)924 Consume(int n, ...)
925 {
926 struct xobject *arg;
927 int i;
928 va_list ap;
929
930 va_start (ap, n);
931 for(i = 0; i < n; i++) {
932 arg = va_arg(ap, struct xobject *);
933 if (arg != NULL && !ISPERMANENT(arg->flag))
934 Destroy(arg);
935 }
936 va_end(ap);
937 return;
938 }
939
940 /*
941 :h3.TypeErr() - Handles "Invalid Object Type" Errors
942 */
943
TypeErr(const char * name,void * p,int expect,void * q)944 struct xobject *TypeErr(
945 const char *name, /* Name of routine (for error message) */
946 void *p, /* Object in error */
947 int expect, /* type expected */
948 void *q) /* object to return to caller */
949 {
950 /* the actual arguments p and q are one of
951 struct XYspace *
952 struct segment *
953 struct xobject *
954 */
955 struct xobject *obj = p;
956 struct xobject *ret = q;
957
958 static char typemsg[80];
959
960 if (MustCrash)
961 LineIOTrace = TRUE;
962
963 sprintf(typemsg, "Wrong object type in %s; expected %s seen %s\n",
964 name, TypeFmt(expect), TypeFmt(obj->type));
965 IfTrace0(TRUE,typemsg);
966
967 ObjectPostMortem(obj);
968
969 if (MustCrash)
970 t1_abort("Terminating because of CrashOnUserError...");
971 else
972 ErrorMessage = typemsg;
973
974 /* changed ISPERMANENT to ret->references > 1 3-26-91 PNM */
975 if (ret != NULL && (ret->references > 1))
976 ret = Dup(ret);
977 return(ret);
978 }
979
980 /*
981 :h4.TypeFmt() - Returns Pointer to English Name of Object Type
982
983 This is a subroutine of TypeErr().
984 */
985
TypeFmt(int type)986 static const char *TypeFmt(
987 int type) /* type field */
988 {
989 const char *r;
990
991 if (ISPATHTYPE(type))
992 if (type == TEXTTYPE)
993 r = "path or region (from TextPath)";
994 else
995 r = "path";
996 else {
997 switch (type) {
998 case INVALIDTYPE:
999 r = "INVALID (previously consumed?)";
1000 break;
1001 case REGIONTYPE:
1002 r = "region";
1003 break;
1004 case SPACETYPE:
1005 r = "XYspace";
1006 break;
1007 case LINESTYLETYPE:
1008 r = "linestyle";
1009 break;
1010 case FONTTYPE:
1011 r = "font";
1012 break;
1013 case PICTURETYPE:
1014 r = "picture";
1015 break;
1016 case STROKEPATHTYPE:
1017 r = "path (from StrokePath)";
1018 break;
1019 default:
1020 r = "UNKNOWN";
1021 break;
1022 }
1023 }
1024 return(r);
1025 }
1026 /*
1027 :h4.ObjectPostMortem() - Prints as Much as We Can About a Bad Object
1028
1029 This is a subroutine of TypeErr() and ArgErr().
1030 */
1031
ObjectPostMortem(register struct xobject * obj)1032 static int ObjectPostMortem(register struct xobject *obj)
1033 {
1034 Pragmatics("Debug", 10);
1035 IfTrace2(TRUE,"Bad object is of %s type %p\n", TypeFmt(obj->type), obj);
1036
1037 IfTrace0((obj == (struct xobject *) USER),
1038 "Suspect that InitImager() was omitted.\n");
1039 Pragmatics("Debug", 0);
1040
1041 /* NOTREACHED? */
1042 return 0;
1043 }
1044
1045 /*
1046 :h3.ArgErr() - Invalid Argument Passed to a Routine
1047
1048 A common routine to report argument errors. It is usually called
1049 is returned to the caller in case MustCrash is FALSE and ArgErr
1050 returns to its caller.
1051 */
1052
ArgErr(const char * str,void * p,void * q)1053 struct xobject *ArgErr(
1054 const char *str, /* description of error */
1055 void *p, /* object, if any, that was in error */
1056 void *q) /* object returned to caller or NULL */
1057 {
1058 /* the actual argument p is one of
1059 struct XYspace *
1060 struct segment *
1061 struct xobject *
1062 */
1063 struct xobject *obj = p;
1064 struct xobject *ret = q;
1065
1066 if (MustCrash)
1067 LineIOTrace = TRUE;
1068 IfTrace1(TRUE,"ARGUMENT ERROR-- %s.\n", str);
1069 if (obj != NULL)
1070 ObjectPostMortem(obj);
1071 if (MustCrash)
1072 t1_abort("Terminating because of CrashOnUserError...");
1073 else
1074 ErrorMessage = str;
1075 return(ret);
1076 }
1077
1078 /*
1079 :h3.t1_abort() - Crash Due to Error
1080
1081 We divide by zero, and if that doesn't work, call exit(), the results of
1082 which is system dependent (and thus is part of the Hourglass required
1083 environment).
1084 */
1085 static int test = 0;
1086
1087 /*ARGSUSED*/
t1_abort(const char * str)1088 void t1_abort(const char *str)
1089 {
1090 LineIOTrace = TRUE;
1091 IfTrace1(TRUE,"\nABORT: reason='%s'\n", str);
1092 TraceClose();
1093 test = 1/test;
1094 exit(99);
1095 }
1096
1097 /*
1098 :h3.REAL Miscellaneous Stuff
1099
1100 :h4.ErrorMsg() - Return the User an Error Message
1101 */
1102
ErrorMsg(void)1103 const char *ErrorMsg(void)
1104 {
1105 register const char *r;
1106
1107 r = ErrorMessage;
1108 ErrorMessage = NULL;
1109 return(r);
1110 }
1111
1112 /*
1113 :h4.InitImager() - Initialize TYPE1IMAGER
1114
1115 We check that a short is 16 bits and a long 32 bits; we have made
1116 those assumptions elsewhere in the code. (This is almost a C standard,
1117 anyway.) Note that TYPE1IMAGER makes no assumptions about the size of an
1118 'int'!
1119 :i1/portability assumptions/
1120 */
InitImager(void)1121 void InitImager(void)
1122 {
1123
1124 /* Check to see if we have been using our own malloc. If so,*/
1125 /* Undef malloc so that we can get to the system call. */
1126 /* All other calls to malloc are defined to Xalloc. */
1127
1128 if (sizeof(SHORT) != 2 || sizeof(int32_t) != 4)
1129 t1_abort("Fundamental TYPE1IMAGER assumptions invalid in this port");
1130 InitSpaces();
1131 InitFonts();
1132 InitFiles();
1133 /*
1134 In some environments, constants and/or exception handling need to be
1135 */
1136 LibInit();
1137 }
1138 /*
1139 :h4.TermImager() - Terminate TYPE1IMAGER
1140
1141 This only makes sense in a server environment; true TYPE1IMAGER needs do
1142 nothing.
1143 */
TermImager(void)1144 void TermImager(void)
1145 {
1146 return;
1147 }
1148 #if 0
1149 /*
1150 :h4.reportusage() - A Stub to Get a Clean Link with Portable PMP
1151 */
1152 void reportusage(void)
1153 {
1154 return;
1155 }
1156 #endif
1157