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