/***************************************************************************** * CONVDATA.C is an unsupported tool to help convert old (*.ply) data files * * to the new (*.dat) format. This tool will be retired in future releases. * * * * To compile: * * * * Under MSDOS, using Borland/Turbo C: 'tcc -ml convdata.c' * * * * Under UNIX: 'cc -i convdata convdata.c' * * * * Usage: * * * * convdata < oldfile.ply > newfile.dat * * * * or * * * * convdata oldfile.ply > newfile.dat * *****************************************************************************/ #ifdef __MSDOS__ #include #include #endif /* __MSDOS__ */ #include #include #include #include #ifdef NO_VOID_PTR #define VoidPtr char * #else #define VoidPtr void * #endif /* NO_VOID_PTR */ #ifndef LINE_LEN #define LINE_LEN 255 #endif LINE_LEN #define NAME_LEN 6 #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif #define FILE_TYPE_DATA 1 #define FILE_TYPE_VIEW 2 #define GEN_COPY(Dest, Src, Size) memcpy(Dest, Src, Size) #define UNGET_STACK_SIZE 5 /***************************************************************************** * Tokens definitions goes into here * *****************************************************************************/ #define TOKEN_OPEN_PAREN 1 #define TOKEN_CLOSE_PAREN 2 #define TOKEN_NUMBER 10 /* Not used as number & names are decoded */ /* according to their places in grammer. */ #define TOKEN_VERTEX 20 #define TOKEN_POLYGON 21 #define TOKEN_POLYLINE 22 #define TOKEN_POINTLIST 23 #define TOKEN_OBJECT 24 #define TOKEN_COLOR 25 #define TOKEN_INTERNAL 26 #define TOKEN_NORMAL 27 #define TOKEN_PLANE 28 #define TOKEN_CBEZIER 29 #define TOKEN_SBEZIER 30 #define TOKEN_CNURB 31 #define TOKEN_SNURB 32 #define TOKEN_OTHER 100 /* Probably names & numbers. */ #define TOKEN_EOF -1 #define VERTEX_ENTRY 0x0001 /* Entry type, up to 16 types. */ #define POLYGON_ENTRY 0x0002 #define POLYLINE_ENTRY 0x0004 #define OBJECT_ENTRY 0x0008 #define COLOR_ENTRY 0x0010 #define POLYGON 1 #define POLYLINE 2 #define POINTLIST 3 /***************************************************************************** * Parser error codes are following: * *****************************************************************************/ #define P_ERR_NUMBER_EXPECTED 1 #define P_ERR_OPEN_PAREN_EXPECTED 2 #define P_ERR_CLOSE_PAREN_EXPECTED 3 #define P_ERR_LIST_COMP_UNDEF 4 #define P_ERR_UNDEF_EXPR_HEADER 5 #define P_ERR_NAME_TOO_LONG 6 #define P_ERR_PT_TYPE_EXPECTED 7 #define P_WRN_OBJ_NAME_TRUNC 100 /***************************************************************************** * And some more definitions ... * *****************************************************************************/ typedef unsigned char Byte; typedef struct BinTree { /* The entries are saved as binary trees. */ struct BinTree *right, *left; /* Classic, isnt it !? */ union { VoidPtr PVoid; struct VertexStruct *PVertex; struct PolygonStruct *PPolygon; struct ObjectStruct *PObject; } Data; char Name[NAME_LEN]; Byte EntryType; /* Kind of pointer in union. */ Byte Used; /* TRUE if allready has been used (multi - referenced). */ } BinTree; typedef struct FileDescription { /* Each data file loaded gets such struct. */ BinTree *VertexPointer, /* Pointers on the binary trees ... */ *PolygonPointer, *ObjectPointer; } FileDescription; /* Use the following structure if linear list operations are to be performed */ /* on VertexStruct/PolygonStruct/ObjectStruct (Virtual functions...). */ typedef struct LinearListStruct { struct LinearListStruct *Pnext; } LinearListStruct; typedef struct VertexStruct { struct VertexStruct *Pnext; float Coord[3]; /* The 3D coords. */ float Normal[3]; /* The 3D normal. */ Byte Transform; Byte Internal; /* If edge is Internal (IRIT output). */ Byte HasNormal; /* If edge has a normal defined. */ } VertexStruct; typedef struct PolygonStruct { struct PolygonStruct *Pnext; VertexStruct *PVertex; /* The polygon vertices. */ float Plane[4]; /* The Polygon plane equation. */ Byte PolyType; /* One of POLYGON, POLYLINE, POINTLIST. */ Byte HasPlane; /* If polygon has a plane defined. */ } PolygonStruct; typedef struct ObjectStruct { struct ObjectStruct *Pnext; PolygonStruct *PPolygon; /* The objects polygons. */ int Color; } ObjectStruct; /* And function prototypes: */ FileDescription *GetDataFile(FILE *f); void GetViewFile(FILE *f, int FileExists); BinTree *GetBinTree(char *RecName, BinTree *Tree); extern unsigned int _stklen = 32766; /* Increase default stack size. */ static int GlblToken = 0, /* Used by the parser, to unget token. */ GlblLineCount = 1, /* Used to locate errors in input file. */ GlblParserError = 0; /* Save last error number found. */ static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN];/* Save unget tokens.*/ static struct FileDescription *Descriptor; char *Real2Str(double R); static struct BinTree *AllocBinTree(int Entry, VoidPtr Data); static void UnGetToken(char *StringToken); static void GetStringToken(FILE *f, char *StringToken); static int GetToken(FILE *f, char *StringToken); static void GetVertexAttributes(VertexStruct *PVertex, FILE *f); static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f); static void GetObjectAttributes(ObjectStruct *PObject, FILE *f); static void EliminateComments(FILE *f); static void ParserError(int ErrNum, char *Msg); static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord); static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD, int EntryTypes); static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes); static char *MyMalloc(unsigned size); static void MyExit(int ExitCode); /***************************************************************************** * * *****************************************************************************/ void main(int argc, char **argv) { FILE *f = NULL; if (argc == 2 && (f = fopen(argv[1], "rt")) != NULL) GetDataFile(f); else GetDataFile(stdin); if (f) fclose(f); MyExit(0); printf("%lf", exp((double) argc)); } /***************************************************************************** * Dump out the new format (simpler, isnt it!?). * *****************************************************************************/ void DumpOutObject(BinTree *T) { int i; struct ObjectStruct *PObject = T -> Data.PObject; struct PolygonStruct *PPolygon = PObject -> PPolygon; struct VertexStruct *PVertex; printf("[OBJECT [COLOR %d] %s\n", PObject -> Color, T -> Name); while (PPolygon) { for (i = 0, PVertex = PPolygon -> PVertex; PVertex != NULL; i++, PVertex = PVertex -> Pnext); printf(" [%s", PPolygon -> PolyType == POLYLINE ? "POLYLINE" : PPolygon -> PolyType == POLYGON ? "POLYGON" : "POINTLIST"); if (PPolygon -> HasPlane) printf(" [PLANE %s %s %s %s]", Real2Str(PPolygon -> Plane[0]), Real2Str(PPolygon -> Plane[1]), Real2Str(PPolygon -> Plane[2]), Real2Str(PPolygon -> Plane[3])); printf(" %d\n", i); PVertex = PPolygon -> PVertex; while (PVertex) { printf("\t["); if (PVertex -> Internal) printf("[INTERNAL] "); if (PVertex -> HasNormal) printf("[NORMAL %s %s %s] ", Real2Str(PVertex->Normal[0]), Real2Str(PVertex->Normal[1]), Real2Str(PVertex->Normal[2])); printf("%s %s %s]\n", Real2Str(PVertex->Coord[0]), Real2Str(PVertex->Coord[1]), Real2Str(PVertex->Coord[2])); PVertex = PVertex -> Pnext; } printf(" ]\n"); PPolygon = PPolygon -> Pnext; } printf("] /* OBJECT %s */\n", T -> Name); } /***************************************************************************** * Convert a real number into a string. * *****************************************************************************/ char *Real2Str(double R) { static int i = 0; static char Buffer[10][LINE_LEN]; int j, k; sprintf(Buffer[i], "%-8.6lg", R); for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++); if (k >= LINE_LEN) { fprintf(stderr, "Conversion of real number failed.\n"); MyExit(3); } for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--); if (strchr(Buffer[i], '.') != NULL) for (; Buffer[i][j] == '0' && j > k; j--); Buffer[i][j+1] = 0; j = i; i = (i + 1) % 10; return Buffer[j]; } /***************************************************************************** * Routine to read the data from a given file and update the data structures * * Descriptor (which returned) from it. * * If MoreFlag is on then more printed staff will be given... * *****************************************************************************/ FileDescription *GetDataFile(FILE *f) { int i; char StringToken[LINE_LEN]; struct VertexStruct *PVertex; struct PolygonStruct *PPolygon; struct ObjectStruct *PObject; struct BinTree *PBinTree; GlblToken = 0; Descriptor = (FileDescription *) MyMalloc(sizeof(FileDescription)); /* As all the trees are empty set the following: */ Descriptor -> VertexPointer = Descriptor -> PolygonPointer = Descriptor -> ObjectPointer = (BinTree *) NULL; GlblLineCount = 1; /* Reset line counter. */ EliminateComments(f); /* Skip all comments including '['. */ while (!feof(f)) { GlblParserError = 0; /* Reset errors. */ switch (GetToken(f, StringToken)) { case TOKEN_VERTEX: PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct)); PVertex -> Transform = FALSE; /* Flag if vertex transformed. */ PVertex -> Internal = FALSE; /* Flag if vertex is internal. */ PVertex -> HasNormal = FALSE; /* Flag if vertex has normal. */ PBinTree = AllocBinTree(VERTEX_ENTRY, (VoidPtr) PVertex); GetToken(f, PBinTree -> Name); /* Get the name. */ if (strlen(PBinTree -> Name) >= NAME_LEN) ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name); /* The following handle the optional attributes in record. */ if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) GetVertexAttributes(PVertex, f); /* Get attributes. */ else UnGetToken(StringToken); /* The following handles reading of 3 coord. of vertex. */ for (i=0; i<3 ;i++) { GetToken(f, StringToken); if (sscanf(StringToken, "%f", &PVertex -> Coord[i]) != 1) ParserError(P_ERR_NUMBER_EXPECTED, StringToken); } if ((i=GetToken(f, StringToken)) != TOKEN_CLOSE_PAREN) ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken); if (!GlblParserError) InsertBinTree(&Descriptor -> VertexPointer, PBinTree); break; case TOKEN_POLYGON: PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct)); PPolygon -> PolyType = POLYGON; PPolygon -> HasPlane = FALSE; PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon); GetToken(f, PBinTree -> Name); /* Get the name. */ if (strlen(PBinTree -> Name) >= NAME_LEN) ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name); /* The following handle the optional attributes in record. */ if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) GetPolygonAttributes(PPolygon, f); else UnGetToken(StringToken); /* The following handles reading the members list. */ PPolygon -> PVertex = (VertexStruct *) GetLinList(f, Descriptor, VERTEX_ENTRY); if (!GlblParserError) InsertBinTree(&Descriptor -> PolygonPointer, PBinTree); break; case TOKEN_POLYLINE: PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct)); PPolygon -> PolyType = POLYLINE; PPolygon -> HasPlane = FALSE; PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon); GetToken(f, PBinTree -> Name); /* Get the name. */ if (strlen(PBinTree -> Name) >= NAME_LEN) ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name); /* The following handle the optional attributes in record. */ if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) GetPolygonAttributes(PPolygon, f); else UnGetToken(StringToken); /* The following handles reading the members list. */ PPolygon -> PVertex = (VertexStruct *) GetLinList(f, Descriptor, VERTEX_ENTRY); if (!GlblParserError) InsertBinTree(&Descriptor -> PolygonPointer, PBinTree); break; case TOKEN_POINTLIST: PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct)); PPolygon -> PolyType = POINTLIST; PPolygon -> HasPlane = FALSE; PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon); GetToken(f, PBinTree -> Name); /* Get the name. */ if (strlen(PBinTree -> Name) >= NAME_LEN) ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name); /* The following handle the optional attributes in record. */ if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) GetPolygonAttributes(PPolygon, f); else UnGetToken(StringToken); /* The following handles reading the members list. */ PPolygon -> PVertex = (VertexStruct *) GetLinList(f, Descriptor, VERTEX_ENTRY); if (!GlblParserError) InsertBinTree(&Descriptor -> PolygonPointer, PBinTree); break; case TOKEN_OBJECT: PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct)); PObject-> Color = 1; PBinTree = AllocBinTree(OBJECT_ENTRY, (VoidPtr) PObject); GetToken(f, PBinTree -> Name); /* Get the name. */ if (strlen(PBinTree -> Name) >= NAME_LEN) { /* Although this may be considered an error, no one */ /* reference objects, so we can simply truncate it. */ PBinTree -> Name[NAME_LEN - 1] = 0; } /* The following handle the optional attributes in record. */ if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) GetObjectAttributes(PObject, f); else UnGetToken(StringToken); /* The following handles reading the polygon list. */ /* Note an object might be created from Polygons only. */ PObject -> PPolygon = (PolygonStruct *) GetLinList(f, Descriptor, POLYGON_ENTRY); if (!GlblParserError) InsertBinTree(&Descriptor -> ObjectPointer, PBinTree); DumpOutObject(PBinTree); break; default: ParserError(P_ERR_UNDEF_EXPR_HEADER, StringToken); break; } /* Of switch. */ if (!feof(f)) EliminateComments(f); /* Skip comments including '['. */ } /* Of while !eof. */ return Descriptor; } /***************************************************************************** * Routine to allocate one BinTree Item: * *****************************************************************************/ static struct BinTree *AllocBinTree(int Entry, VoidPtr Data) { struct BinTree *PBinTree; PBinTree = (BinTree *) MyMalloc(sizeof(BinTree)); PBinTree -> EntryType = Entry; PBinTree -> Used = FALSE; PBinTree -> Data.PVoid = Data; PBinTree -> right = PBinTree -> left = (BinTree *) NULL; return PBinTree; } /***************************************************************************** * Routine to unget one token (on stack of UNGET_STACK_SIZE levels!) * *****************************************************************************/ static void UnGetToken(char *StringToken) { if (GlblToken >= UNGET_STACK_SIZE) { printf("Parser Internal stack overflow...\n"); MyExit(1); } strcpy(GlblStringToken[GlblToken], StringToken); GlblToken++; /* GlblToken exists - Something in it (no overflow check). */ } /***************************************************************************** * Routine to get the next token out of the input file f. * * Returns the next token found, as StringToken. * * Note: StringToken must be allocated before calling this routine! * *****************************************************************************/ static void GetStringToken(FILE *f, char *StringToken) { int len; char c, *LocalStringToken; if (GlblToken) { /* get first the unget token */ GlblToken--; strcpy(StringToken, GlblStringToken[GlblToken]); return; } /* skip white spaces: */ while ((!feof(f)) && (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n'))) if (c == '\n') GlblLineCount++; /* Count the lines. */ LocalStringToken = StringToken; if (c == '[') /* Its a token by itself so return it. */ *LocalStringToken++ = c; /* Copy the token into string. */ else { if (!feof(f)) do *LocalStringToken++ = c; /* Copy the token into string. */ while ((!feof(f)) && ((c = getc(f)) != ' ') && (c != '\t') && (c != '\n')); if (c == '\n') ungetc(c, f); /* Save it to be counted next time. */ } *LocalStringToken = NULL; /* Put eos. */ /* The following handles the spacial case were we have XXXX] - we must */ /* split it into two token XXXX and ], UnGetToken(']') and return XXXX: */ if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0)) { /* Return CloseParan */ UnGetToken(&StringToken[len]); /* Save next token. */ StringToken[len] = NULL; /* Set end of string on "]". */ } } /***************************************************************************** * Routine to get the next token out of the input file f as token number. * * Returns the next token number found, with numeric result in NumericToken * * if TokenType is TOKEN_NUMBER. * * Note: StringToken must be allocated before calling this routine! * *****************************************************************************/ static int GetToken(FILE *f, char *StringToken) { GetStringToken(f, StringToken); if (feof(f)) return TOKEN_EOF; if (!strcmp(StringToken, "[")) return TOKEN_OPEN_PAREN; if (!strcmp(StringToken, "]")) return TOKEN_CLOSE_PAREN; if (!strcmp(StringToken, "VERTEX")) return TOKEN_VERTEX; if (!strcmp(StringToken, "POLYGON")) return TOKEN_POLYGON; if (!strcmp(StringToken, "POLYLINE")) return TOKEN_POLYLINE; if (!strcmp(StringToken, "POINTLIST")) return TOKEN_POINTLIST; if (!strcmp(StringToken, "OBJECT")) return TOKEN_OBJECT; if (!strcmp(StringToken, "COLOR")) return TOKEN_COLOR; if (!strcmp(StringToken, "INTERNAL")) return TOKEN_INTERNAL; if (!strcmp(StringToken, "NORMAL")) return TOKEN_NORMAL; if (!strcmp(StringToken, "PLANE")) return TOKEN_PLANE; if (!strcmp(StringToken, "CBEZIER")) return TOKEN_CBEZIER; if (!strcmp(StringToken, "SBEZIER")) return TOKEN_SBEZIER; if (!strcmp(StringToken, "CNURB")) return TOKEN_CNURB; if (!strcmp(StringToken, "SNURB")) return TOKEN_SNURB; return TOKEN_OTHER; /* Must be number or name. */ } /***************************************************************************** * Routine to read from input file f the following [ATTR ...] [ATTR ...]. * * Note the '[' was allready read. * * Current supported attributes: [INTERNAL] - internal edge (IRIT output) * *****************************************************************************/ static void GetVertexAttributes(VertexStruct *PVertex, FILE *f) { int i; char StringToken[LINE_LEN]; do { switch (GetToken(f, StringToken)) { case TOKEN_INTERNAL: PVertex -> Internal = TRUE; if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken); break; case TOKEN_NORMAL: PVertex -> HasNormal = TRUE; /* The following handles reading of 3 coord. of normal. */ for (i=0; i<3 ;i++) { GetToken(f, StringToken); if (sscanf(StringToken, "%f", &PVertex -> Normal[i]) != 1) ParserError(P_ERR_NUMBER_EXPECTED, StringToken); } if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken); break; default: /* Ignore this option! */ while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN); break; } } while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN); UnGetToken(StringToken); } /***************************************************************************** * Routine to read from input file f the following [ATTR ...] [ATTR ...]. * * Note the '[' was allready read. * * Current supported attributes: None * *****************************************************************************/ static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f) { int i; char StringToken[LINE_LEN]; do { switch (GetToken(f, StringToken)) { case TOKEN_PLANE: PPolygon -> HasPlane = TRUE; /* The following handles reading of 4 coord. of plane eqn.. */ for (i=0; i<4 ;i++) { GetToken(f, StringToken); if (sscanf(StringToken, "%f", &PPolygon -> Plane[i]) != 1) ParserError(P_ERR_NUMBER_EXPECTED, StringToken); } if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken); break; default: while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN); break; } } while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN); UnGetToken(StringToken); } /***************************************************************************** * Routine to read from input file f the following [ATTR ...] [ATTR ...]. * * Note the '[' was allready read. * * Current supported attributes: [COLOR C] - set color. * *****************************************************************************/ static void GetObjectAttributes(ObjectStruct *PObject, FILE *f) { int i; char StringToken[LINE_LEN]; do { switch (GetToken(f, StringToken)) { case TOKEN_COLOR: GetToken(f, StringToken); if (sscanf(StringToken, "%d", &i) != 1) ParserError(P_ERR_NUMBER_EXPECTED, StringToken); if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken); PObject -> Color = i; break; default: while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN); break; } } while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN); UnGetToken(StringToken); } /***************************************************************************** * Routine to read the input tokens up to a '[' token - skip comments. * * Note the routine reads the '[' token, so next is the expression itself. * *****************************************************************************/ static void EliminateComments(FILE *f) { char StringToken[LINE_LEN]; while ((!feof(f)) && (GetToken(f, StringToken) != TOKEN_OPEN_PAREN)); } /***************************************************************************** * Routine to print pasring error according to ErrNum and set GlblParserError.* *****************************************************************************/ static void ParserError(int ErrNum, char *Msg) { GlblParserError = TRUE; printf("Error in line %3d : ", GlblLineCount); switch (ErrNum) { case P_ERR_NUMBER_EXPECTED: printf("Numeric data expected, "); break; case P_ERR_OPEN_PAREN_EXPECTED: printf("[ expected, "); break; case P_ERR_CLOSE_PAREN_EXPECTED: printf("] expected, "); break; case P_ERR_LIST_COMP_UNDEF: printf("List component undefined - "); break; case P_ERR_UNDEF_EXPR_HEADER: printf("Undefined expression header - "); break; case P_ERR_NAME_TOO_LONG: printf("Object Name too long (Max %d) - ", NAME_LEN - 1); break; case P_ERR_PT_TYPE_EXPECTED: printf("Point type expected, "); break; default: printf("Unknown error, "); break; } printf("found %s.\n", Msg); } /***************************************************************************** * Routine to insert new element into a binary tree. If the element already * * exists then the new one replace it. * *****************************************************************************/ static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord) { int Comparison; BinTree *PBin; if (*Tree == (BinTree *) NULL) /* Only might happen if the tree empty. */ *Tree = PNewRecord; else { /* Search for the new place to put it. */ /* Test for Match - if so replace old by new: */ if ((Comparison = strcmp((*Tree) -> Name, PNewRecord -> Name)) == 0) { PBin = *Tree; *Tree = PNewRecord; /* Replace. */ switch (PBin -> EntryType) { /* Free the data area (union). */ case VERTEX_ENTRY: free((char *) PBin -> Data.PVertex); break; case POLYGON_ENTRY: free((char *) PBin -> Data.PPolygon); break; case OBJECT_ENTRY: free((char *) PBin -> Data.PObject); break; default: /* Should not be, unless was not updated here... */ break; } free((char *) PBin); } else if (Comparison > 0) /* Go to right side - its bigger. */ if ((*Tree) -> right != (BinTree *) NULL) /* Only if exist. */ InsertBinTree(&((*Tree) -> right), PNewRecord); else (*Tree) -> right = PNewRecord; /* Put record in place. */ else if ((*Tree) -> left != (BinTree *) NULL) /* Only if exist. */ InsertBinTree(&((*Tree) -> left), PNewRecord);/*Smaller. */ else (*Tree) -> left = PNewRecord; /* Put record in place. */ } } /***************************************************************************** * Routine to Get an element from binary tree. If the element is found a * * pointer to it BinTree record is return, NULL else... * *****************************************************************************/ BinTree *GetBinTree(char *RecName, BinTree *Tree) { int Comparison; /* If the tree is empty - not found, return NULL: */ if (Tree == (BinTree *) NULL) return (BinTree *) NULL; /* Test for Match - if so return that record: */ if ((Comparison = strcmp(Tree -> Name, RecName)) == 0) return Tree; /* Found it - so return it ... */ else if (Comparison > 0) return GetBinTree(RecName, Tree -> right); else return GetBinTree(RecName, Tree -> left); } /***************************************************************************** * Routine to search for Name in the trees, allowed by EntryTypes, of the * * file descrition FD. NULL returned if not found. The order of search is: * * VERTEX , POLYGON , OBJECT. * * Once found, if was already used (multi-reference) it is copied fresh. * *****************************************************************************/ static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD, int EntryTypes) { BinTree *PBin; VertexStruct *PVertex; PolygonStruct *PPolygon; ObjectStruct *PObject; if (EntryTypes & VERTEX_ENTRY) { /* Check in vertices tree. */ if ((PBin = GetBinTree(Name, FD -> VertexPointer)) != NULL) { if (PBin -> Used) { PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct)); GEN_COPY(PVertex, PBin -> Data.PVertex, sizeof(VertexStruct)); return (LinearListStruct *) PVertex; } else { PBin -> Used = TRUE; return (LinearListStruct *) PBin -> Data.PVertex; } } } if (EntryTypes & POLYGON_ENTRY) { /* Check in polygon tree. */ if ((PBin = GetBinTree(Name, FD -> PolygonPointer)) != NULL) { if (PBin -> Used) { PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct)); GEN_COPY(PPolygon, PBin -> Data.PPolygon, sizeof(PolygonStruct)); return (LinearListStruct *) PPolygon; } else { PBin -> Used = TRUE; return (LinearListStruct *) PBin -> Data.PPolygon; } } } if (EntryTypes & OBJECT_ENTRY) { /* Check in object tree. */ if ((PBin = GetBinTree(Name, FD -> ObjectPointer)) != NULL) { if (PBin -> Used) { PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct)); GEN_COPY(PObject, PBin -> Data.PObject, sizeof(ObjectStruct)); return (LinearListStruct *) PObject; } else { PBin -> Used = TRUE; return (LinearListStruct *) PBin -> Data.PObject; } } } return NULL; /* Not found. */ } /***************************************************************************** * Routine to get linear list of names from file f until ']' is detected. * * search for that names in file description FD unter the trees allowed * * according to EntryTypes (1 bit per entry, see ?????Entry is parser.h). * * Create a linear list of pointers to them. Return that linear list. * *****************************************************************************/ static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes) { char StringToken[LINE_LEN]; struct LinearListStruct *PLinHead = NULL, *PLinTail = NULL, *PItem; while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) { if ((PItem = GetNameFromFD(StringToken, FD, EntryTypes)) == NULL) { ParserError(P_ERR_LIST_COMP_UNDEF, StringToken);/* Record undef. */ continue; /* To next component to search for. */ } if (PLinHead == NULL) /* Its first record. */ PLinHead = PLinTail = PItem; else { /* Its record in the middle. */ PLinTail -> Pnext = PItem; PLinTail = PItem; } } if (PLinTail != NULL) PLinTail -> Pnext = NULL; /* Mark end of list. */ return (VoidPtr) PLinHead; } /***************************************************************************** * My Routine to allocate dynamic memory. All program requests must call this * * routine (no direct call to malloc). Dies if no memory. * *****************************************************************************/ static char *MyMalloc(unsigned size) { char *p; if ((p = malloc(size)) != NULL) return p; printf("Not enough memory, exit\n"); MyExit(2); return NULL; /* Make warnings silent. */ } /***************************************************************************** * MyExit routine. Note it might call to CloseGraph without calling * * InitGraph(), or call MouseClose() without MouseInit() etc. and it is the * * responsibility of the individual modules to do nothing in these cases. * *****************************************************************************/ static void MyExit(int ExitCode) { exit(ExitCode); }