Back to index

tetex-bin  3.0
objects.c
Go to the documentation of this file.
00001 /* $XConsortium: objects.c,v 1.5 92/03/20 15:56:06 eswu Exp $ */
00002 /* Copyright International Business Machines, Corp. 1991
00003  * All Rights Reserved
00004  * Copyright Lexmark International, Inc. 1991
00005  * All Rights Reserved
00006  *
00007  * License to use, copy, modify, and distribute this software and its
00008  * documentation for any purpose and without fee is hereby granted,
00009  * provided that the above copyright notice appear in all copies and that
00010  * both that copyright notice and this permission notice appear in
00011  * supporting documentation, and that the name of IBM or Lexmark not be
00012  * used in advertising or publicity pertaining to distribution of the
00013  * software without specific, written prior permission.
00014  *
00015  * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
00016  * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
00018  * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE
00019  * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
00020  * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF THE
00021  * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
00022  * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN NO EVENT SHALL
00023  * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
00024  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00025  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00026  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
00027  * THIS SOFTWARE.
00028  */
00029  /* OBJECTS  CWEB         V0025 ********                             */
00030 /*
00031 :h1.OBJECTS Module - TYPE1IMAGER Objects Common Routines
00032  
00033 This module defines and implements the C structures that represent
00034 objects in the TYPE1IMAGER.  All common routines for manipulating these
00035 objects are defined in this module.  Specific routines for
00036 specific objects are defined in the modules that deal with that
00037 object type.
00038  
00039  
00040 &author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
00041  
00042  
00043 :h3.Include Files
00044  
00045 The included files are:
00046 */
00047 #define   GLOBALS  1         /* see :hdref refid=debugvar.                   */
00048 /*
00049 The following two includes are C standards; we include them because we
00050 use 'toupper' and the 'str'-type functions in this module.  Potentially
00051 these may be defined as macros; if these ".h" files do not exist on your
00052 system it is a pretty safe bet that these are external entry points and
00053 you do do not need to include these header files.
00054 */
00055 
00056 #include  "types.h"
00057 #include  <string.h>
00058 #include  <ctype.h>
00059  
00060 /*
00061 override incorrect system functions; for example you might define
00062 a macro for "strcpy" that diverts it to "my_strcpy".
00063 */
00064  
00065                                /* moved these includes from above the    */
00066                                /*   was included first (it contains com- */
00067                                /*   piler defines).  dsr 081291          */
00068 #include  "objects.h"
00069 #include  "spaces.h"
00070 #include  "paths.h"
00071 #include  "regions.h"
00072 #include  "fonts.h"
00073 #include  "pictures.h"
00074 #include  "strokes.h"
00075 #include  "cluts.h"
00076 static char *TypeFmt();
00077 static int ObjectPostMortem(struct xobject *obj);
00078 
00079 /*
00080 :h3.The "pointer" Macro - Define a Generic Pointer
00081  
00082 Sadly, many compilers will give a warning message when a pointer to
00083 one structure is assigned to a pointer to another.  We've even seen
00084 some that give severe errors (when the wrong pointer type is used as
00085 an initializer or returned from a function).  TYPE1IMAGER has routines
00086 like Dup and Allocate that are perfectly willing to duplicate or
00087 allocate any of a number of different types of structures.  How to
00088 declare them in a truely portable way?
00089  
00090 Well, there is no single good answer that I've found.  You can always
00091 beg the question and "cast" everything.  I find this distracting and the
00092 resulting code ugly.  On the other hand, we have found at least one
00093 compiler that will accept "void *" as a generic pointer that can
00094 assigned to any other pointer type without error or warning (apparently
00095 this is also the ANSI standard).  So, we define "void *" to be a generic
00096 pointer.  (You might have to change this for your compiler; the "ifndef"
00097 allows the change to be made on the command line if you want.)
00098 :i1/portability assumptions/
00099 */
00100 /*SHARED LINE(S) ORIGINATED HERE*/
00101 /*
00102 :h3.Functions Provided to the TYPE1IMAGER User
00103  
00104 This module provides the following TYPE1IMAGER entry points:
00105 */
00106 /*SHARED LINE(S) ORIGINATED HERE*/
00107 /*
00108 Note that entry points that are intended for use external to TYPE1IMAGER
00109 begin with the characters :q/xi/.  Macros are used to make the names
00110 more mnemonic.
00111 */
00112  
00113 /*
00114 :h3.Functions Provided to Other Modules
00115  
00116 This module provides the following functions for other modules:
00117 */
00118 /*SHARED LINE(S) ORIGINATED HERE*/
00119 /*
00120 Note that entry points that intended for use within TYPE1IMAGER, but
00121 which must be global because they are used across module boundaries,
00122 begin with the characters :q/I_/.  Macros are used to make the names
00123 more mnemonic.
00124  
00125 Entry points totally within a module use mnemonic names and are
00126 declared :hp2/static/.  One of the compilers I used had a bug when
00127 static functions were passed as addresses.  Thus, some functions
00128 which are logically "static" are not so declared.
00129  
00130 Note also the trick of declaring routines, like Consume(), with a
00131 variable number of arguments.  To avoid the restrictions on variable
00132 numbers of arguments in the macro processor, we just replace the
00133 text 'Consume' with 'I_Consume'.
00134 */
00135 /*
00136 :h3.Macros Provided to Other Modules
00137  
00138 This is the module where we define all the useful constants like
00139 TRUE, FALSE, and NULL, and simple expressions like MIN(), MAX(), and ABS().
00140 We might as well get to it right here:
00141 */
00142 /*SHARED LINE(S) ORIGINATED HERE*/
00143 /*
00144 Notice that upper case is used for constant values and macro
00145 definitions.  I generally follow that convention.
00146  
00147 Many more global macros are defined later in this module.
00148 */
00149 /*
00150 :h2.Basic TYPE1IMAGER Object Structure
00151  
00152 All TYPE1IMAGER objects which are available to the user have a common
00153 header.  This header is defined below:
00154 */
00155  
00156 /*SHARED LINE(S) ORIGINATED HERE*/
00157 /*
00158 The following define is an attempt to centralize the definition of the
00159 common xobject data shared by structures that are derived from the
00160 generic xobject structure. For example, the structure font, defined in
00161 fonts.shr :
00162 &code.
00163     struct font {
00164            char type;
00165            char flag;
00166            int references;
00167            ... other data types & structs ...
00168            }
00169 &ecode.
00170 would now be defined as:
00171 &code.
00172     struct font {
00173            XOBJ_COMMON
00174            ... other data types & structs ...
00175            }
00176 &ecode.
00177 Thus we have a better-structured inheritance mechanism. 3-26-91 PNM
00178 */
00179 /*SHARED LINE(S) ORIGINATED HERE*/
00180 /*
00181 :h3.Object Type Definitions
00182  
00183 These constants define the values which go in the 'type' field of
00184 an TYPE1IMAGER object structure:
00185 */
00186 /*SHARED LINE(S) ORIGINATED HERE*/
00187 /*
00188 :h3.Flag Byte Definitions
00189  
00190 Many programmers define flag bits as a mask (for example, 0x04), and
00191 test, set, and reset them as follows:
00192  
00193 &code.
00194         if ((flag & PERMANENT) != 0)
00195  
00196         flag |= PERMANENT;
00197         flag &= &inv.PERMANENT;
00198 :exmp.
00199  
00200 I favor a style where the 'if' statement can ask a question:
00201  
00202 &code.
00203         if (ISPERMANENT(flag))
00204  
00205         flag |= ISPERMANENT(ON);
00206         flag &= &inv.ISPERMANENT(ON);
00207  
00208 :exmp.
00209 This said, we now define two bit settings of the flag byte of the
00210 object.  "ISPERMANENT" will be set by the user, when he calls
00211 Permanent().  "ISIMMORTAL" will be used for compiled-in objects
00212 that we don't want the user to ever destroy.
00213 */
00214 /*SHARED LINE(S) ORIGINATED HERE*/
00215 /*
00216 Flag bit definitions that apply to all objects are assigned
00217 starting with the least significant (0x01) bit.  Flag bit definitions
00218 specific to a certain object type are assigned starting with the
00219 most significant (0x80) bit.  We hope they never meet.
00220 */
00221 /*
00222 :h3 id=preserve.PRESERVE() Macro
00223  
00224 Occasionally an TYPE1IMAGER operator is implemented by calling other
00225 TYPE1IMAGER operators.  For example, Arc2() calls Conic().  When we
00226 call more than one operator as a subroutine, we have to be careful
00227 of temporary objects.  A temporary object will be consumed by the
00228 subroutine operator and then is no longer available for the caller.
00229 This can be prevented simply by bumping a temporary object's reference
00230 count.
00231 */
00232 /*SHARED LINE(S) ORIGINATED HERE*/
00233  
00234 /*
00235 :h3.RefRoll() Macro to Detect References Count Rollover
00236  
00237 The following macro is designed to check for reference count rollover.
00238 A return value of TRUE means rollover has not occurred; a return value
00239 of FALSE means we cannot increment the reference count.  Note also that
00240 those functions that use this macro must decrement the reference count
00241 afterwards.  3-26-91 PNM
00242 */
00243  
00244 #define RefRoll(obj)  (++(obj)->references > 0)
00245  
00246 /*
00247 :h2.TYPE1IMAGER Object Functions
00248  
00249 :h3.LONGCOPY() - Macro to Copy "long" Aligned Data
00250  
00251 Copying arbitrary bytes in C is a bit of a problem.  "strcpy" can't be
00252 used, because 0 bytes are special-cased.  Most environments have a
00253 routine "memcopy" or "bcopy" or "bytecopy" that copies memory containing
00254 zero bytes.  Sadly, there is no standard on the name of such a routine,
00255 which makes it impossible to write truely portable code to use it.
00256  
00257 It turns out that TYPE1IMAGER, when it wants to copy data, frequently
00258 knows that both the source and destination are aligned on "long"
00259 boundaries.  This allows us to copy by using "long *" pointers.  This
00260 is usually very efficient on almost all processors.  Frequently, it
00261 is more efficient than using general-purpose assembly language routines.
00262 So, we define a macro to do this in a portable way.  "dest" and "source"
00263 must be long-aligned, and "bytes" must be a multiple of "sizeof(long)":
00264 */
00265 /*SHARED LINE(S) ORIGINATED HERE*/
00266 /*
00267 :h3.Allocate() - Allocating a Memory Block
00268  
00269 Allocate returns a pointer to memory object that is a copy of
00270 the template passed (if any).  In addition, extra bytes may be
00271 allocated contiguously with the object.  (This may be useful for
00272 variable size objects such as edge lists.  See :hdref refid=regions..)
00273  
00274 Allocate() always returns a non-immortal object, even if the template is
00275 immortal.  Therefore a non-NULL template must have a "flag" byte.
00276  
00277 If the template is NULL, then 'size' bytes are cleared to all NULLs.
00278  
00279 If the template is non-NULL, a new object is allocated in memory.
00280 It therefore seems logical that its reference count field should be
00281 set to 1. So, a nun-NULL template must also have a "references" field.
00282 PNM 3-26-91
00283 */
00284  
00285 struct xobject *t1_Allocate(size, template, extra)  /* non-ANSI; type checking was too strict */
00286        register int size;    /* number of bytes to allocate & initialize     */
00287        register struct xobject *template;  /* example structure to allocate  */
00288        register int extra;   /* any extra uninitialized bytes needed contiguously */
00289 {
00290 #ifdef WIN32
00291        extern char *Xalloc(int); /* standard C routine */
00292 #else
00293        extern char *Xalloc();  /* standard C routine                         */
00294 #endif 
00295        register struct xobject *r;
00296  
00297        /*
00298        * round up 'size' and 'extra' to be an integer number of 'long's:
00299        */
00300        size = (size + sizeof(LONG) - 1) & -sizeof(LONG);
00301        extra = (extra + sizeof(LONG) - 1) & -sizeof(LONG);
00302        if (size + extra <= 0)
00303                t1_abort("Non-positive allocate?");
00304        r = (struct xobject *) Xalloc(size + extra);
00305  
00306        while (r == NULL) {
00307                if (!GimeSpace()) {
00308                        IfTrace1(TRUE, "malloc attempted %d bytes.\n",
00309                                            size + extra);
00310                        t1_abort("We have REALLY run out of memory");
00311                }
00312                r = (struct xobject *) Xalloc(size + extra);
00313        }
00314  
00315        /*
00316        * copy the template into the new memory:
00317        */
00318        if (template != NULL) {
00319        /* Added references count decrement if template is not permanent.
00320           This is for the case where Allocate is called by a Dupxxxx
00321           function, which was in turn called by Unique(). (PNM)        */
00322                if (!ISPERMANENT(template->flag))
00323                    --template->references;
00324                LONGCOPY(r, template, size);
00325                r->flag &= ~(ISPERMANENT(ON) | ISIMMORTAL(ON));
00326        /* added reference field 3-2-6-91 PNM */
00327                r->references = 1;
00328        }
00329        else {
00330                register char **p1;
00331  
00332                for (p1=(char **)r; size > 0; size -= sizeof(char *))
00333                        *p1++ = NULL;
00334        }
00335  
00336        if (MemoryDebug > 1) {
00337                register int *L;
00338                L = (int *) r;
00339                IfTrace4(TRUE, "Allocating at %p: %x %x %x\n",
00340                                            L, L[-1], L[0], L[1]);
00341        }
00342        return(r);
00343 }
00344  
00345 /*
00346 :h3.Free() - Frees an Allocated Object
00347  
00348 This routine makes a sanity check to make sure the "type" field of the
00349 standard object structure has not been cleared.  If the object is
00350 not a standard structure, then the macro "NonObjectFree" is available
00351 that does not perform this check.
00352  
00353 In either case, the object must not be the NULL pointer.  This preserves
00354 portability, as the C system Xfree() will not always accept NULL.
00355 */
00356  
00357 void Free(obj)              /* non-ANSI to avoid overly strict type checking */
00358        register struct xobject *obj;  /* structure to free                   */
00359 {
00360        if (obj->type == INVALIDTYPE)
00361                t1_abort("Free of already freed object?");
00362        obj->type = INVALIDTYPE;
00363  
00364        if (MemoryDebug > 1) {
00365                register int *L;
00366                L = (int *) obj;
00367                IfTrace4(TRUE,"Freeing at %p: %x %x %x\n", L, L[-1], L[0], L[1]);
00368        }
00369  
00370        Xfree(obj);
00371 }
00372  
00373 /*
00374 :h3.Permanent() - Makes an Object Permanent
00375  
00376 Real simple--just set a flag.  Every routine that consumes its objects
00377 (which is almost every user entry) must check this flag, and not consume
00378 the object if it is set.
00379  
00380 If a temporary object is made permanent, and there is more than one
00381 reference to it, we must first Copy() it, then set the ISPERMANENT
00382 flag. Note also that the reference count must be incremented when an
00383 object is changed from temporary to permanent (see the ISUNIQUE macro).
00384  
00385 Note that the purpose of this function is to convert an object into a
00386 permanent object:
00387   If it was permanent to begin with, we do nothing;
00388   If it was temporary and unique, we set the PERMANENT flag and increment
00389 the reference count;
00390   If it was temporary and nonunique, we must make a unique Copy(), set
00391 the PERMANENT flag, and set the reference count to 2. We must also
00392 decrement the original object's reference count, because what we have
00393 done is to change one of the old temporary handles to a permanent one.
00394 3-26-91 PNM
00395 */
00396  
00397 struct xobject *t1_Permanent(obj) /* non-ANSI to avoid overly strict type checking */
00398        register struct xobject *obj;  /* object to be made permanent         */
00399 {
00400        IfTrace1((MustTraceCalls),"Permanent(%p)\n", obj);
00401  
00402        if ( (obj != NULL) && ( !(ISPERMANENT(obj->flag)) ) )
00403        {
00404        /* there is a non-NULL, temporary object to be made permanent.
00405           If there are multiple references to this object, first get
00406           a new COPY().
00407           Note also that we have to decrement the reference count if
00408           we do a Copy() here, because we are consuming the temporary
00409           argument passed, and returning a unique, permanent one.
00410        */
00411            if ( obj->references > 1)
00412            {
00413                obj = Copy(obj);
00414            }
00415            /* now set the permanent flag, and increment the reference
00416               count, since a temporary object has now become permanent. */
00417            obj->references++;
00418            obj->flag |= ISPERMANENT(ON);
00419        }
00420        return(obj);
00421 }
00422  
00423 /*
00424 :h3.Temporary() - Undoes the Effect of "Permanent()"
00425  
00426 This simply resets the "ISPERMANENT" flag.
00427  
00428 If a permanent object is made temporary, and there is more than one reference
00429 to it, we must first Copy() it, then reset the ISPERMANENT flag. However,
00430 if the permanent object has obly one reference, we need only decrement the
00431 reference count ( and reset the flag).
00432  
00433 Note that this function, in the case of a PERMANENT argument, basically
00434 converts the PERMANENT handle to a TEMPORARY one. Thus, in the case of
00435 a nonunique, permanent argument passed, we not only make a Copy(),
00436 we also decrement the reference count, to reflect the fact that we have
00437 lost a permanent handle and gained a temporary one.
00438 PNM 3-2-6-91
00439 */
00440  
00441 struct xobject *xiTemporary(obj) /* non-ANSI to avoid overly strict type checking */
00442        register struct xobject *obj;  /* object to be made permanent         */
00443 {
00444        IfTrace1((MustTraceCalls),"Temporary(%p)\n", obj);
00445  
00446        if (obj != NULL) {
00447                /* if it's already temporary, there's nothing to do. */
00448                if ISPERMANENT(obj->flag)
00449                {
00450                /* if there are multiple references to this object, get a
00451                   Copy we can safely alter. Recall that the reference count
00452                   is incremented for permanent objects.
00453                   Recall further that Copy returns an object with the
00454                   same flag state and a reference count of 2 (for PERMANENT
00455                   objects).
00456                   Thus, regardless of whether or not we need to copy a
00457                   permanent object, we still decrement its reference
00458                   count and reset the flag.
00459                */
00460                    if (obj->references != 2 || ISIMMORTAL(obj->flag))
00461                    {
00462                /* not unique; consume handle, get a temporary Copy! */
00463                        obj = Copy(obj);
00464                    }
00465                /* else decrement the reference count (since it's going from
00466                   permanent to temporary) and clear the flag. */
00467                    else {
00468                        obj->references--;
00469                        obj->flag &= ~ISPERMANENT(ON);
00470                    }
00471                }
00472        }
00473        return(obj);
00474 }
00475  
00476 /*
00477 :h3.Dup() - Duplicate an Object
00478  
00479 Dup will increment the reference count of an object, only making a
00480 Copy() if needed.
00481 Note that Dup() retains the state of the permanent flag.
00482 3-26-91 PNM
00483 */
00484  
00485  
00486 struct xobject *t1_Dup(obj)   /* non-ANSI avoids overly strict type checking  */
00487        register struct xobject *obj;  /* object to be duplicated             */
00488 {
00489        register char oldflag;   /* copy of original object's flag byte */
00490  
00491        IfTrace1((MustTraceCalls),"Dup(%p)\n", obj);
00492  
00493        if (obj == NULL)
00494                return(NULL);
00495        /* An immortal object must be Copy'ed, so that we get a mortal
00496           copy of it, since we try not to destroy immortal objects. */
00497        if (ISIMMORTAL(obj->flag))
00498            return(Copy(obj));
00499  
00500        /* if incrementing the reference count doesn't cause the count
00501           to wrap, simply return the object with the count bumped. Note
00502           that the RefRoll macro increments the count to perform the
00503           rollover check, so we must decrement the count. */
00504        if (RefRoll(obj))
00505            return(obj);
00506  
00507        /* that didn't work out, so put the count back and call Copy(). */
00508        --obj->references;
00509        oldflag = obj->flag;
00510        obj = Copy(obj);
00511        if (ISPERMANENT(oldflag))
00512                obj = Permanent(obj);
00513        return(obj);
00514 }
00515  
00516 /*
00517 :h3.Copy() - Make a New Copy of an Object
00518  
00519 This is the generic Copy() where the object type is unknown.  There
00520 are specific Copyxxx functions for known object types.
00521  
00522 Copy will create a NEW temporary object, and WILL NOT simply bump the
00523 reference count.
00524  
00525 Sometimes duplicating an object is just as simple as Allocating with it
00526 as a template.  But other objects are complicated linked lists.  So, we
00527 let each module provide us a routine (or macro) that duplicates the
00528 objects it knows about.
00529 */
00530  
00531 struct xobject *t1_Copy(obj)
00532        register struct xobject *obj;  /* object to be  Copy'ed              */
00533 {
00534        if (obj == NULL)
00535                return(NULL);
00536  
00537        if (ISPATHTYPE(obj->type))
00538                obj = (struct xobject *) CopyPath(obj);
00539        else
00540                switch (obj->type) {
00541                    case SPACETYPE:
00542                        obj = (struct xobject *) CopySpace(obj); break;
00543                    case FONTTYPE:
00544                        obj = (struct xobject *) CopyFont(obj); break;
00545                    case REGIONTYPE:
00546                        obj = (struct xobject *) CopyRegion(obj); break;
00547                    case PICTURETYPE:
00548                        obj = (struct xobject *) CopyPicture(obj); break;
00549                    case LINESTYLETYPE:
00550                        obj = (struct xobject *) CopyLineStyle(obj); break;
00551                    case STROKEPATHTYPE:
00552                        obj = (struct xobject *) CopyStrokePath(obj); break;
00553                    case CLUTTYPE:
00554                        obj = (struct xobject *) CopyCLUT(obj); break;
00555                    default:
00556                        return(ArgErr("Copy: invalid object", obj, NULL));
00557                }
00558  
00559         return(obj);
00560 }
00561  
00562 /*
00563 :h3.Destroy() - Destroys an Object
00564  
00565 This can get complicated.  Just like with Copy(), we let the experts
00566 handle it.
00567 */
00568 struct xobject *Destroy(obj) /* non-ANSI avoids overly strict type checking  */
00569        register struct xobject *obj;  /* object to be destroyed              */
00570 {
00571        IfTrace1((MustTraceCalls),"Destroy(%p)\n", obj);
00572  
00573        if (obj == NULL)
00574                return(NULL);
00575        if (ISIMMORTAL(obj->flag)) {
00576                IfTrace1(TRUE,"Destroy of immortal object %p ignored\n", obj);
00577                return(NULL);
00578        }
00579        if (ISPATHTYPE(obj->type))
00580                KillPath(obj);
00581        else {
00582                switch (obj->type) {
00583                    case REGIONTYPE:
00584                        KillRegion(obj);
00585                        break;
00586                    case SPACETYPE:
00587                        KillSpace(obj);
00588                        break;
00589                    case LINESTYLETYPE:
00590                        KillLineStyle(obj);
00591                        break;
00592                    case FONTTYPE:
00593                        KillFont(obj);
00594                        break;
00595                    case PICTURETYPE:
00596                        KillPicture(obj);
00597                        break;
00598                    case STROKEPATHTYPE:
00599                        KillStrokePath(obj);
00600                        break;
00601                    case CLUTTYPE:
00602                        KillCLUT(obj);
00603                        break;
00604                    default:
00605                        return(ArgErr("Destroy: invalid object", obj, NULL));
00606                }
00607        }
00608        return(NULL);
00609 }
00610 /*
00611 :h2.Generally Useful Macros
00612  
00613 :h3.FOLLOWING() - Macro to Point to the Data Following a Structure
00614  
00615 There are several places in TYPE1IMAGER where we will allocate variable
00616 data that belongs to a structure immediately after that structure.
00617 This is a performance technique, because it reduces the number of
00618 trips we have to take through Xalloc() and Xfree().  It turns out C has
00619 a very convenient way to point past a structure--if 'p' is a pointer
00620 to a structure, 'p+1' is a pointer to the data after it.  This
00621 behavior of C is somewhat startling and somewhat hard to follow, if
00622 you are not used to it, so we define a macro to point to the data
00623 following a structure:
00624 */
00625 /*SHARED LINE(S) ORIGINATED HERE*/
00626 /*
00627 :h3.TYPECHECK() - Verify the Type of an Argument
00628  
00629 This macro tests the type of an argument.  If the test fails, it consumes
00630 any other arguments as necessary and causes the imbedding routine to
00631 return the value 'whenBAD'.
00632  
00633 Note that the consumeables list should be an argument list itself, for
00634 example (0) or (2,A,B).  See :hdref refid=consume. below.
00635 */
00636  
00637 /*SHARED LINE(S) ORIGINATED HERE*/
00638 /*
00639 :h3.ARGCHECK() - Perform an Arbitrary Check on an Argument
00640  
00641 This macro is a generalization of TYPECHECK to take an arbitrary
00642 predicate.  If the error occurs (i.e., the predicate is true), the
00643 arbitrary message 'msg' is returned.
00644 */
00645  
00646 /*SHARED LINE(S) ORIGINATED HERE*/
00647 /*
00648 :h3.TYPENULLCHECK() - Extension of TYPECHECK() for NULL arguments
00649  
00650 Many routines allow NULLs to be passed as arguments.  'whenBAD' will
00651 be returned in this case, too.
00652 */
00653  
00654 /*SHARED LINE(S) ORIGINATED HERE*/
00655 /*
00656 :h3.MAKECONSUME() - Create a "Consume"-type Macro
00657  
00658 Consuming an object means destroying it if it is not permanent.  This
00659 logic is so common to all the routines, that it is immortalized in this
00660 macro.  For example, ConsumePath(p) can be simply defined as
00661 MAKECONSUME(p,KillPath(p)).  In effect, this macro operates on a
00662 meta-level.
00663 :i1/consuming objects/
00664 */
00665  
00666 /*SHARED LINE(S) ORIGINATED HERE*/
00667  
00668 /*
00669 :h3.MAKEUNIQUE() - Create a "Unique"-type Macro
00670  
00671 Many routines are written to modify their arguments in place.  Thus,
00672 they want to insure that they duplicate an object if it is permanent.
00673 This is called making an object "unique".  For example, UniquePath(p)
00674 can be simply defined as MAKEUNIQUE(p,DupPath(p)).
00675 :i1/unique objects/
00676 */
00677  
00678 /*SHARED LINE(S) ORIGINATED HERE*/
00679  
00680 /*
00681 An object is unique (and directly alterable) if there is only one
00682 reference to it, and it is not permanent (in which case we increment
00683 the reference count, so we don't have to check the permanent bit).
00684 3-26-91 PNM
00685  
00686 Note the rules for making a unique object:
00687 &drawing.
00688    IF  (obj->references = 1)    return(obj);
00689    ELSE (references > 1)
00690        IF (ISPERMANENT(obj->flag))    return(Dupxxx(obj));
00691        ELSE (nonunique, temporary object!)
00692            obj->references--; return(Dupxxx(obj));
00693 &edrawing.
00694 If we must make a Copy of a nonunique, temporary object, we decrement
00695 reference count of the original object!
00696 */
00697  
00698 /*
00699 :h3.Unique() - Make a Unique Object
00700  
00701 Here is a generic 'Unique' function if the object type is not known.
00702 Why didn't we build it with the MAKEUNIQUE macro, you ask?  Well, we
00703 used to, but there is at least one damn compiler in the world that
00704 raises errors if the types of an "(a) ? b : c" expression do not match.
00705 Also, when we changed Dup() to retain the permanent/temporary flag, we
00706 wanted to make sure "Unique" always returned a temporary object.
00707  
00708 Note that we cannot use Dup() to create a copy of the object in question,
00709 because Dup() may simply bump the reference count, and not return a
00710 unique copy to us. That is why we use t1_Copy().
00711  
00712 The purpose of this function is to make sure we have a copy of an object
00713 that we can safely alter:
00714 :ol.
00715 :li.If we have a unique, temporary object, we simply return the argument.
00716 :li.If we have a nonunique, temporary object, we have to make a new copy
00717 of it, and decrement the reference count of the original object, to reflect
00718 the fact that we traded temporary handles.
00719 :li.If we have a permanent object, we make a temporary copy of it, but
00720 we do not decrement the reference count of the original permanent object,
00721 because permanent objects, by definition, are persistent. 3-2-6-91 PNM
00722 :eol.
00723 */
00724  
00725 struct xobject *t1_Unique(obj)
00726        struct xobject *obj;
00727 {
00728     /* if the original object is not already unique, make a unique
00729        copy...Note also that if the object was not permanent, we must
00730        consume the old handle! 3-26-91 PNM
00731        NOTE : consumption of the old handle moved to Allocate. 4-18-91 */
00732     if (!obj || obj->references == 1)
00733         return(obj);
00734  
00735     obj = Copy(obj);
00736     /* and make sure we return a temporary object ! */
00737     if (ISPERMANENT(obj->flag))
00738     {
00739         obj->flag &= ~ISPERMANENT(ON);
00740         obj->references--;
00741     }
00742     return(obj);
00743 }
00744  
00745  
00746 /*
00747 :h2.Initialization, Error, and Debug Routines
00748  
00749 :h3 id=debugvar.Declarations for Debug Purposes
00750  
00751 We declare all the debug flags here.  Some link editors make the not
00752 unreasonable restriction that only one module may declare and
00753 initialize global variables; all the rest must declare the variable
00754 'extern'.  This is logical, but is somewhat awkward to implement with
00755 C include files.  We solve the problem by temporarily making the name
00756 'extern' a null name if GLOBALS is defined.  (GLOBALS is only defined
00757 in this OBJECTS module.)  Since 'externs' can't be initialized, we
00758 have to handle that with #defines too.
00759 :i1/GLOBALS (&#define.)/
00760 */
00761  
00762 /*SHARED LINE(S) ORIGINATED HERE*/
00763 static char *ErrorMessage = NULL;
00764  
00765 /*
00766 :h3.Pragmatics() - Set/Reset Debug Flags
00767  
00768 We provide a controlled way for the TYPE1IMAGER user to set and reset
00769 our debugging and tracing:
00770 */
00771 void Pragmatics(username, value)
00772        char *username;       /* name of the flag                             */
00773        int value;            /* value to set it to                           */
00774 {
00775        register char *p;     /* temporary loop variable                      */
00776 #define    NAMESIZE   40
00777        char name[NAMESIZE];  /* buffer to store my copy of 'username'        */
00778  
00779        if (strlen(username) >= NAMESIZE)
00780                t1_abort("Pragmatics name too large");
00781        strcpy(name, username);
00782        for (p = name; *p != '\0'; p++)
00783                *p = toupper(*p);
00784  
00785        if (!strcmp(name, "ALL"))
00786                MustTraceCalls = InternalTrace = /* MustCrash = */
00787                     LineIOTrace = value;
00788  
00789        else if (!strcmp(name, "LINEIOTRACE"))
00790                LineIOTrace = value;
00791  
00792        else if (!strcmp(name, "TRACECALLS"))
00793                MustTraceCalls = value;
00794  
00795        else if (!strcmp(name, "CHECKARGS"))
00796                MustCheckArgs = value;
00797  
00798        else if (!strcmp(name, "PROCESSHINTS"))
00799                ProcessHints = value;
00800  
00801        else if (!strcmp(name, "SAVEFONTPATHS"))
00802                SaveFontPaths = value;
00803  
00804        else if (!strcmp(name, "CRASTERCOMPRESSIONTYPE"))
00805                CRASTERCompressionType = value;
00806  
00807        else if (!strcmp(name, "CRASHONUSERERROR"))
00808                MustCrash = value;
00809  
00810        else if (!strcmp(name, "DEBUG"))
00811                StrokeDebug = SpaceDebug = PathDebug = ConicDebug = LineDebug =
00812                           RegionDebug = MemoryDebug = FontDebug =
00813                           HintDebug = ImageDebug = OffPageDebug = value;
00814  
00815        else if (!strcmp(name, "CONICDEBUG"))
00816                ConicDebug = value;
00817  
00818        else if (!strcmp(name, "LINEDEBUG"))
00819                LineDebug = value;
00820  
00821        else if (!strcmp(name, "REGIONDEBUG"))
00822                RegionDebug = value;
00823  
00824        else if (!strcmp(name, "PATHDEBUG"))
00825                PathDebug = value;
00826  
00827        else if (!strcmp(name, "SPACEDEBUG"))
00828                SpaceDebug = value;
00829  
00830        else if (!strcmp(name, "STROKEDEBUG"))
00831                StrokeDebug = value;
00832  
00833        else if (!strcmp(name, "MEMORYDEBUG"))
00834                MemoryDebug = value;
00835  
00836        else if (!strcmp(name, "FONTDEBUG"))
00837                FontDebug = value;
00838  
00839        else if (!strcmp(name, "HINTDEBUG"))
00840                HintDebug = value;
00841  
00842        else if (!strcmp(name, "IMAGEDEBUG"))
00843                ImageDebug = value;
00844  
00845        else if (!strcmp(name, "OFFPAGEDEBUG"))
00846                OffPageDebug = value;
00847  
00848 #ifdef  MC68000
00849 /*
00850 The following pragmatics flag turns on or off instruction histograming
00851 for performance analysis.  It is only defined in the Delta card
00852 environment.
00853 */
00854        else if (!strcmp(name, "PROFILE")) {
00855                if (value)
00856                        StartProfile();
00857                else
00858                        StopProfile();
00859        }
00860 #endif
00861        else if (!strcmp(name, "FLUSHCACHE")) {
00862                while (GimeSpace()) { ; }
00863        }
00864  
00865        else if (!strcmp(name, "CACHEDCHARS"))
00866                CachedChars = (value <= 0) ? 1 : value;
00867  
00868        else if (!strcmp(name, "CACHEDFONTS"))
00869                CachedFonts = (value <= 0) ? 1 : value;
00870  
00871        else if (!strcmp(name, "CACHEBLIMIT"))
00872                CacheBLimit = value;
00873  
00874        else if (!strcmp(name, "CONTINUITY"))
00875                Continuity = value;
00876  
00877  
00878        else {
00879                printf("Pragmatics flag = '%s'\n", name);
00880                ArgErr("Pragmatics:  flag not known", NULL, NULL);
00881        }
00882        return;
00883 }
00884  
00885 /*
00886 :h3.Consume() - Consume a List of Arguments
00887  
00888 This general purpose routine is provided in the case where the object
00889 type(s) to be consumed are unknown or not yet verified, and/or it is
00890 not known whether the object is permanent.
00891  
00892 If the type of the argument is known, it is faster to directly consume
00893 that type, for example, ConsumeRegion() or ConsumePath().  Furthermore,
00894 if it is already known that the object is temporary, it is faster to
00895 just kill it rather than consume it, for example, KillSpace().
00896 */
00897  
00898 #ifdef KPATHSEA
00899 void Consume PVAR1C(int, n, ap)
00900 {
00901   struct xobject *arg;
00902   int i;
00903 
00904   for(i = 0; i < n; i++) {
00905     arg = va_arg(ap, struct xobject *);
00906     if (arg != NULL && !ISPERMANENT(arg->flag))
00907       Destroy(arg);
00908   }
00909   va_end(ap);
00910   return;
00911 }}
00912 #else
00913 void Consume(n, obj1, obj2, obj3) /* non-ANSI avoids overly strict type checking */
00914        int n;
00915        struct xobject *obj1,*obj2,*obj3;
00916 {
00917        switch(n) {
00918  
00919            case 0:
00920                return;
00921  
00922            case 1:
00923                if (obj1 != NULL && !ISPERMANENT(obj1->flag))
00924                        Destroy(obj1);
00925                return;
00926  
00927            case 2:
00928                if (obj1 != NULL && !ISPERMANENT(obj1->flag))
00929                        Destroy(obj1);
00930                if (obj2 != NULL && !ISPERMANENT(obj2->flag))
00931                        Destroy(obj2);
00932                return;
00933  
00934            case 3:
00935                if (obj1 != NULL && !ISPERMANENT(obj1->flag))
00936                        Destroy(obj1);
00937                if (obj2 != NULL && !ISPERMANENT(obj2->flag))
00938                        Destroy(obj2);
00939                if (obj3 != NULL && !ISPERMANENT(obj3->flag))
00940                        Destroy(obj3);
00941                return;
00942  
00943            default:
00944                t1_abort("Consume:  too many objects");
00945        }
00946 }
00947 #endif /* WIN32 */
00948 /*
00949 :h3.TypeErr() - Handles "Invalid Object Type" Errors
00950 */
00951  
00952 struct xobject *TypeErr(name, obj, expect, ret) /* non-ANSI avoids overly strict type checking */
00953        char *name;           /* Name of routine (for error message)          */
00954        struct xobject *obj;  /* Object in error                              */
00955        int expect;           /* type expected                                */
00956        struct xobject *ret;  /* object to return to caller                   */
00957 {
00958        static char typemsg[80];
00959  
00960        if (MustCrash)
00961                LineIOTrace = TRUE;
00962  
00963        sprintf(typemsg, "Wrong object type in %s; expected %s seen %s\n",
00964                   name, TypeFmt(expect), TypeFmt(obj->type));
00965        IfTrace0(TRUE,typemsg);
00966  
00967        ObjectPostMortem(obj);
00968  
00969        if (MustCrash)
00970                t1_abort("Terminating because of CrashOnUserError...");
00971        else
00972                ErrorMessage = typemsg;
00973  
00974 /* changed ISPERMANENT to ret->references > 1 3-26-91 PNM */
00975        if (ret != NULL && (ret->references > 1))
00976                ret = Dup(ret);
00977        return(ret);
00978 }
00979  
00980 /*
00981 :h4.TypeFmt() - Returns Pointer to English Name of Object Type
00982  
00983 This is a subroutine of TypeErr().
00984 */
00985  
00986 static char *TypeFmt(type)
00987        int type;             /* type field                                   */
00988 {
00989        char *r;
00990  
00991        if (ISPATHTYPE(type))
00992                if (type == TEXTTYPE)
00993                        r = "path or region (from TextPath)";
00994                else
00995                        r = "path";
00996        else {
00997                switch (type) {
00998                    case INVALIDTYPE:
00999                        r = "INVALID (previously consumed?)";
01000                        break;
01001                    case REGIONTYPE:
01002                        r = "region";
01003                        break;
01004                    case SPACETYPE:
01005                        r = "XYspace";
01006                        break;
01007                    case LINESTYLETYPE:
01008                        r = "linestyle";
01009                        break;
01010                    case FONTTYPE:
01011                        r = "font";
01012                        break;
01013                    case PICTURETYPE:
01014                        r = "picture";
01015                        break;
01016                    case STROKEPATHTYPE:
01017                        r = "path (from StrokePath)";
01018                        break;
01019                    default:
01020                        r = "UNKNOWN";
01021                        break;
01022                }
01023        }
01024        return(r);
01025 }
01026 /*
01027 :h4.ObjectPostMortem() - Prints as Much as We Can About a Bad Object
01028  
01029 This is a subroutine of TypeErr() and ArgErr().
01030 */
01031  
01032 static int ObjectPostMortem(register struct xobject *obj)
01033 {
01034        extern struct XYspace *USER;
01035  
01036        Pragmatics("Debug", 10);
01037        IfTrace2(TRUE,"Bad object is of %s type %p\n", TypeFmt(obj->type), obj);
01038  
01039        IfTrace0((obj == (struct xobject *) USER),
01040                   "Suspect that InitImager() was omitted.\n");
01041        Pragmatics("Debug", 0);
01042 
01043        /* NOTREACHED? */
01044        return 0;
01045 }
01046  
01047 /*
01048 :h3.ArgErr() - Invalid Argument Passed to a Routine
01049  
01050 A common routine to report argument errors.  It is usually called
01051 is returned to the caller in case MustCrash is FALSE and ArgErr
01052 returns to its caller.
01053 */
01054  
01055 struct xobject *ArgErr(str, obj, ret) /* non-ANSI avoids overly strict type checking */
01056        char *str;         /* description of error                         */
01057        struct xobject *obj;  /* object, if any, that was in error            */
01058        struct xobject *ret;  /* object returned to caller or NULL            */
01059 {
01060        if (MustCrash)
01061                LineIOTrace = TRUE;
01062        IfTrace1(TRUE,"ARGUMENT ERROR-- %s.\n", str);
01063        if (obj != NULL)
01064                ObjectPostMortem(obj);
01065        if (MustCrash)
01066                t1_abort("Terminating because of CrashOnUserError...");
01067        else
01068                ErrorMessage = str;
01069        return(ret);
01070 }
01071  
01072 /*
01073 :h3.t1_abort() - Crash Due to Error
01074  
01075 We divide by zero, and if that doesn't work, call exit(), the results of
01076 which is system dependent (and thus is part of the Hourglass required
01077 environment).
01078 */
01079 static int test = 0;
01080  
01081 /*ARGSUSED*/
01082 void t1_abort(str)
01083        char *str;
01084 {
01085        LineIOTrace = TRUE;
01086        IfTrace1(TRUE,"\nABORT: reason='%s'\n", str);
01087        TraceClose();
01088        test = 1/test;
01089        exit(99);
01090 }
01091  
01092 /*
01093 :h3.REAL Miscellaneous Stuff
01094  
01095 :h4.ErrorMsg() - Return the User an Error Message
01096 */
01097  
01098 char *ErrorMsg()
01099 {
01100        register char *r;
01101  
01102        r = ErrorMessage;
01103        ErrorMessage = NULL;
01104        return(r);
01105 }
01106  
01107 /*
01108 :h4.InitImager() - Initialize TYPE1IMAGER
01109  
01110 We check that a short is 16 bits and a long 32 bits; we have made
01111 those assumptions elsewhere in the code.  (This is almost a C standard,
01112 anyway.)  Note that TYPE1IMAGER makes no assumptions about the size of an
01113 'int'!
01114 :i1/portability assumptions/
01115 */
01116 void InitImager()
01117 {
01118  
01119 /* Check to see if we have been using our own malloc.  If so,*/
01120 /* Undef malloc so that we can get to the system call. */
01121 /* All other calls to malloc are defined to Xalloc.  */
01122  
01123        if (sizeof(SHORT) != 2 || sizeof(LONG) != 4)
01124           t1_abort("Fundamental TYPE1IMAGER assumptions invalid in this port");
01125        InitSpaces();
01126        InitFonts();
01127        InitFiles();
01128 /*
01129 In some environments, constants and/or exception handling need to be
01130 */
01131        LibInit();
01132 }
01133 /*
01134 :h4.TermImager() - Terminate TYPE1IMAGER
01135  
01136 This only makes sense in a server environment; true TYPE1IMAGER needs do
01137 nothing.
01138 */
01139 void TermImager()
01140 {
01141        return;
01142 }
01143 /*
01144 :h4.reportusage() - A Stub to Get a Clean Link with Portable PMP
01145 */
01146 void reportusage()
01147 {
01148        return;
01149 }