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