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