home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iritsm3s.zip / iritfltr / convdata.c next >
C/C++ Source or Header  |  1991-11-30  |  31KB  |  852 lines

  1. /*****************************************************************************
  2. * CONVDATA.C is an unsupported tool to help convert old (*.ply) data files   *
  3. * to the new (*.dat) format. This tool will be retired in future releases.   *
  4. *                                         *
  5. * To compile:                                     *
  6. *                                         *
  7. *    Under MSDOS, using Borland/Turbo C: 'tcc -ml convdata.c'         *
  8. *                                         *
  9. *    Under UNIX: 'cc -i convdata convdata.c'                     *
  10. *                                         *
  11. * Usage:                                     *
  12. *                                         *
  13. *    convdata < oldfile.ply > newfile.dat                     *
  14. *                                         *
  15. *    or                                     *
  16. *                                         *
  17. *    convdata oldfile.ply > newfile.dat                     *
  18. *****************************************************************************/
  19.  
  20. #ifdef __MSDOS__
  21. #include <stdlib.h>
  22. #include <conio.h>
  23. #endif /* __MSDOS__ */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <math.h>
  28. #include <string.h>
  29.  
  30. #ifdef NO_VOID_PTR
  31. #define VoidPtr        char *
  32. #else
  33. #define VoidPtr        void *
  34. #endif /* NO_VOID_PTR */
  35.  
  36. #ifndef LINE_LEN
  37. #define LINE_LEN    255
  38. #endif  LINE_LEN
  39.  
  40. #define NAME_LEN    6
  41.  
  42. #ifndef TRUE
  43. #define TRUE        1
  44. #define FALSE        0
  45. #endif
  46.  
  47. #ifndef NULL
  48. #define NULL        0
  49. #endif
  50.  
  51. #define FILE_TYPE_DATA    1
  52. #define FILE_TYPE_VIEW    2
  53.  
  54. #define GEN_COPY(Dest, Src, Size)       memcpy(Dest, Src, Size)
  55.  
  56. #define    UNGET_STACK_SIZE    5
  57.  
  58. /*****************************************************************************
  59. * Tokens definitions goes into here                                          *
  60. *****************************************************************************/
  61. #define TOKEN_OPEN_PAREN    1
  62. #define TOKEN_CLOSE_PAREN    2
  63.  
  64. #define TOKEN_NUMBER        10 /* Not used as number & names are decoded */
  65.                     /* according to their places in grammer. */
  66.  
  67. #define TOKEN_VERTEX    20
  68. #define TOKEN_POLYGON    21
  69. #define TOKEN_POLYLINE    22
  70. #define TOKEN_POINTLIST    23
  71. #define TOKEN_OBJECT    24
  72. #define TOKEN_COLOR    25
  73. #define TOKEN_INTERNAL    26
  74. #define TOKEN_NORMAL    27
  75. #define TOKEN_PLANE    28
  76. #define TOKEN_CBEZIER    29
  77. #define TOKEN_SBEZIER    30
  78. #define TOKEN_CNURB    31
  79. #define TOKEN_SNURB    32
  80.  
  81. #define TOKEN_OTHER    100            /* Probably names & numbers. */
  82. #define TOKEN_EOF    -1
  83.  
  84. #define VERTEX_ENTRY    0x0001              /* Entry type, up to 16 types. */
  85. #define POLYGON_ENTRY    0x0002
  86. #define POLYLINE_ENTRY    0x0004
  87. #define OBJECT_ENTRY    0x0008
  88. #define COLOR_ENTRY    0x0010
  89.  
  90. #define POLYGON        1
  91. #define POLYLINE    2
  92. #define POINTLIST    3
  93.  
  94. /*****************************************************************************
  95. * Parser error codes are following:                                          *
  96. *****************************************************************************/
  97. #define P_ERR_NUMBER_EXPECTED        1
  98. #define P_ERR_OPEN_PAREN_EXPECTED    2
  99. #define P_ERR_CLOSE_PAREN_EXPECTED    3
  100. #define P_ERR_LIST_COMP_UNDEF        4
  101. #define P_ERR_UNDEF_EXPR_HEADER        5
  102. #define P_ERR_NAME_TOO_LONG        6
  103. #define P_ERR_PT_TYPE_EXPECTED        7
  104.  
  105. #define P_WRN_OBJ_NAME_TRUNC        100
  106.  
  107. /*****************************************************************************
  108. * And some more definitions ...                                              *
  109. *****************************************************************************/
  110.  
  111. typedef unsigned char Byte;
  112.  
  113. typedef struct BinTree {       /* The entries are saved as binary trees. */
  114.     struct BinTree *right, *left;              /* Classic, isnt it !? */
  115.     union {
  116.     VoidPtr              PVoid;
  117.     struct VertexStruct  *PVertex;
  118.     struct PolygonStruct *PPolygon;
  119.     struct ObjectStruct  *PObject;
  120.     } Data;
  121.     char Name[NAME_LEN];
  122.     Byte EntryType;                /* Kind of pointer in union. */
  123.     Byte Used;         /* TRUE if allready has been used (multi - referenced). */
  124. } BinTree;
  125.  
  126. typedef struct FileDescription {  /* Each data file loaded gets such struct. */
  127.     BinTree *VertexPointer,            /* Pointers on the binary trees ...  */
  128.         *PolygonPointer,
  129.         *ObjectPointer;
  130. } FileDescription;
  131.  
  132. /* Use the following structure if linear list operations are to be performed */
  133. /* on VertexStruct/PolygonStruct/ObjectStruct (Virtual functions...).         */
  134. typedef struct LinearListStruct {
  135.     struct LinearListStruct *Pnext;
  136. } LinearListStruct;
  137.  
  138. typedef struct VertexStruct {
  139.     struct VertexStruct *Pnext;
  140.     float Coord[3];                       /* The 3D coords. */
  141.     float Normal[3];                       /* The 3D normal. */
  142.     Byte Transform;
  143.     Byte Internal;               /* If edge is Internal (IRIT output). */
  144.     Byte HasNormal;                /* If edge has a normal defined. */
  145. } VertexStruct;
  146.  
  147. typedef struct PolygonStruct {
  148.     struct PolygonStruct *Pnext;
  149.     VertexStruct *PVertex;                /* The polygon vertices. */
  150.     float Plane[4];                  /* The Polygon plane equation. */
  151.     Byte PolyType;             /* One of POLYGON, POLYLINE, POINTLIST. */
  152.     Byte HasPlane;              /* If polygon has a plane defined. */
  153. } PolygonStruct;
  154.  
  155. typedef struct ObjectStruct {
  156.     struct ObjectStruct *Pnext;
  157.     PolygonStruct *PPolygon;                /* The objects polygons. */
  158.     int Color;
  159. } ObjectStruct;
  160.  
  161. /* And function prototypes: */
  162.  
  163. FileDescription *GetDataFile(FILE *f);
  164. void GetViewFile(FILE *f, int FileExists);
  165. BinTree *GetBinTree(char *RecName, BinTree *Tree);
  166.  
  167. extern unsigned int _stklen = 32766;         /* Increase default stack size. */
  168.  
  169. static int  GlblToken =    0,          /* Used by the parser, to unget token. */
  170.         GlblLineCount = 1,         /* Used to locate errors in input file. */
  171.         GlblParserError = 0;        /* Save last error number found. */
  172. static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN];/* Save unget tokens.*/
  173. static struct FileDescription *Descriptor;
  174.  
  175. char *Real2Str(double R);
  176. static struct BinTree *AllocBinTree(int Entry, VoidPtr Data);
  177. static void UnGetToken(char *StringToken);
  178. static void GetStringToken(FILE *f, char *StringToken);
  179. static int GetToken(FILE *f, char *StringToken);
  180. static void GetVertexAttributes(VertexStruct *PVertex, FILE *f);
  181. static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f);
  182. static void GetObjectAttributes(ObjectStruct *PObject, FILE *f);
  183. static void EliminateComments(FILE *f);
  184. static void ParserError(int ErrNum, char *Msg);
  185. static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord);
  186. static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD,
  187.                             int EntryTypes);
  188. static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes);
  189. static char *MyMalloc(unsigned size);
  190. static void MyExit(int ExitCode);
  191.  
  192. /*****************************************************************************
  193. *                                         *
  194. *****************************************************************************/
  195. void main(int argc, char **argv)
  196. {
  197.     FILE *f = NULL;
  198.  
  199.     if (argc == 2 && (f = fopen(argv[1], "rt")) != NULL)
  200.     GetDataFile(f);
  201.     else GetDataFile(stdin);
  202.  
  203.     if (f) fclose(f);
  204.  
  205.     MyExit(0);
  206.  
  207.     printf("%lf", exp((double) argc));
  208. }
  209.  
  210. /*****************************************************************************
  211. * Dump out the new format (simpler, isnt it!?).                     *
  212. *****************************************************************************/
  213. void DumpOutObject(BinTree *T)
  214. {
  215.     int i;
  216.     struct ObjectStruct *PObject = T -> Data.PObject;
  217.     struct PolygonStruct *PPolygon = PObject -> PPolygon;
  218.     struct VertexStruct *PVertex;
  219.  
  220.     printf("[OBJECT [COLOR %d] %s\n", PObject -> Color, T -> Name);
  221.  
  222.     while (PPolygon) {
  223.     for (i = 0, PVertex = PPolygon -> PVertex;
  224.          PVertex != NULL;
  225.          i++, PVertex = PVertex -> Pnext);
  226.  
  227.     printf("    [%s", PPolygon -> PolyType == POLYLINE ? "POLYLINE" :
  228.         PPolygon -> PolyType == POLYGON ? "POLYGON" : "POINTLIST");
  229.     if (PPolygon -> HasPlane)
  230.         printf(" [PLANE %s %s %s %s]",
  231.         Real2Str(PPolygon -> Plane[0]),
  232.         Real2Str(PPolygon -> Plane[1]),
  233.         Real2Str(PPolygon -> Plane[2]),
  234.         Real2Str(PPolygon -> Plane[3]));
  235.     printf(" %d\n", i);
  236.  
  237.     PVertex = PPolygon -> PVertex;
  238.     while (PVertex) {
  239.         printf("\t[");
  240.         if (PVertex -> Internal)
  241.         printf("[INTERNAL] ");
  242.         if (PVertex -> HasNormal)
  243.         printf("[NORMAL %s %s %s] ",
  244.             Real2Str(PVertex->Normal[0]),
  245.             Real2Str(PVertex->Normal[1]),
  246.             Real2Str(PVertex->Normal[2]));
  247.         printf("%s %s %s]\n",
  248.             Real2Str(PVertex->Coord[0]),
  249.             Real2Str(PVertex->Coord[1]),
  250.             Real2Str(PVertex->Coord[2]));
  251.  
  252.         PVertex = PVertex -> Pnext;
  253.     }
  254.  
  255.     printf("    ]\n");
  256.     PPolygon = PPolygon -> Pnext;
  257.     }
  258.     printf("] /* OBJECT %s */\n", T -> Name);
  259. }
  260.  
  261. /*****************************************************************************
  262. * Convert a real number into a string.                         *
  263. *****************************************************************************/
  264. char *Real2Str(double R)
  265. {
  266.     static int i = 0;
  267.     static char Buffer[10][LINE_LEN];
  268.     int j, k;
  269.  
  270.     sprintf(Buffer[i], "%-8.6lg", R);
  271.  
  272.     for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
  273.     if (k >= LINE_LEN) {
  274.     fprintf(stderr, "Conversion of real number failed.\n");
  275.     MyExit(3);
  276.     }
  277.  
  278.     for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
  279.     if (strchr(Buffer[i], '.') != NULL)
  280.     for (; Buffer[i][j] == '0' && j > k; j--);
  281.     Buffer[i][j+1] = 0;
  282.  
  283.     j = i;
  284.     i = (i + 1) % 10;
  285.     return Buffer[j];
  286. }
  287.  
  288. /*****************************************************************************
  289. * Routine to read the data from    a given    file and update    the data structures  *
  290. * Descriptor (which returned) from it.                         *
  291. * If MoreFlag is on then more printed staff will be given...             *
  292. *****************************************************************************/
  293. FileDescription *GetDataFile(FILE *f)
  294. {
  295.     int    i;
  296.     char StringToken[LINE_LEN];
  297.     struct VertexStruct     *PVertex;
  298.     struct PolygonStruct *PPolygon;
  299.     struct ObjectStruct     *PObject;
  300.     struct BinTree     *PBinTree;
  301.  
  302.     GlblToken =    0;
  303.  
  304.     Descriptor = (FileDescription *) MyMalloc(sizeof(FileDescription));
  305.     /* As all the trees    are empty set the following: */
  306.     Descriptor -> VertexPointer       =
  307.     Descriptor -> PolygonPointer   =
  308.     Descriptor -> ObjectPointer       = (BinTree *) NULL;
  309.  
  310.     GlblLineCount = 1;                      /* Reset line counter. */
  311.     EliminateComments(f);         /* Skip all comments including '['. */
  312.     while (!feof(f)) {
  313.     GlblParserError = 0;                    /* Reset errors. */
  314.     switch (GetToken(f, StringToken)) {
  315.         case TOKEN_VERTEX:
  316.         PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct));
  317.         PVertex -> Transform = FALSE; /* Flag if vertex transformed. */
  318.         PVertex -> Internal = FALSE;  /* Flag if vertex is internal. */
  319.         PVertex -> HasNormal = FALSE;  /* Flag if vertex has normal. */
  320.         PBinTree = AllocBinTree(VERTEX_ENTRY, (VoidPtr) PVertex);
  321.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  322.         if (strlen(PBinTree -> Name) >= NAME_LEN)
  323.             ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name);
  324.         /* The following handle the optional attributes in record.   */
  325.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  326.             GetVertexAttributes(PVertex, f);      /* Get attributes. */
  327.         else UnGetToken(StringToken);
  328.         /* The following handles reading of 3 coord. of vertex.      */
  329.         for (i=0; i<3 ;i++) {
  330.             GetToken(f, StringToken);
  331.             if (sscanf(StringToken, "%f", &PVertex -> Coord[i]) != 1)
  332.             ParserError(P_ERR_NUMBER_EXPECTED, StringToken);
  333.         }
  334.         if ((i=GetToken(f, StringToken)) != TOKEN_CLOSE_PAREN)
  335.                 ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  336.         if (!GlblParserError)
  337.              InsertBinTree(&Descriptor -> VertexPointer, PBinTree);
  338.         break;
  339.          case TOKEN_POLYGON:
  340.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  341.         PPolygon -> PolyType = POLYGON;
  342.         PPolygon -> HasPlane = FALSE;
  343.         PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon);
  344.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  345.         if (strlen(PBinTree -> Name) >= NAME_LEN)
  346.             ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name);
  347.         /* The following handle the optional attributes in record. */
  348.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  349.             GetPolygonAttributes(PPolygon, f);
  350.         else UnGetToken(StringToken);
  351.         /* The following handles reading the members list. */
  352.         PPolygon -> PVertex = (VertexStruct *)
  353.               GetLinList(f, Descriptor, VERTEX_ENTRY);
  354.         if (!GlblParserError)
  355.                InsertBinTree(&Descriptor -> PolygonPointer, PBinTree);
  356.         break;
  357.          case TOKEN_POLYLINE:
  358.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  359.         PPolygon -> PolyType = POLYLINE;
  360.         PPolygon -> HasPlane = FALSE;
  361.         PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon);
  362.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  363.         if (strlen(PBinTree -> Name) >= NAME_LEN)
  364.             ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name);
  365.         /* The following handle the optional attributes in record. */
  366.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  367.             GetPolygonAttributes(PPolygon, f);
  368.         else UnGetToken(StringToken);
  369.         /* The following handles reading the members list. */
  370.         PPolygon -> PVertex = (VertexStruct *)
  371.             GetLinList(f, Descriptor, VERTEX_ENTRY);
  372.         if (!GlblParserError)
  373.                InsertBinTree(&Descriptor -> PolygonPointer, PBinTree);
  374.         break;
  375.          case TOKEN_POINTLIST:
  376.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  377.         PPolygon -> PolyType = POINTLIST;
  378.         PPolygon -> HasPlane = FALSE;
  379.         PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon);
  380.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  381.         if (strlen(PBinTree -> Name) >= NAME_LEN)
  382.             ParserError(P_ERR_NAME_TOO_LONG, PBinTree -> Name);
  383.         /* The following handle the optional attributes in record. */
  384.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  385.             GetPolygonAttributes(PPolygon, f);
  386.         else UnGetToken(StringToken);
  387.         /* The following handles reading the members list. */
  388.         PPolygon -> PVertex = (VertexStruct *)
  389.             GetLinList(f, Descriptor, VERTEX_ENTRY);
  390.         if (!GlblParserError)
  391.                InsertBinTree(&Descriptor -> PolygonPointer, PBinTree);
  392.         break;
  393.          case TOKEN_OBJECT:
  394.         PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct));
  395.         PObject-> Color = 1;
  396.         PBinTree = AllocBinTree(OBJECT_ENTRY, (VoidPtr) PObject);
  397.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  398.         if (strlen(PBinTree -> Name) >= NAME_LEN) {
  399.             /* Although this may be considered an error, no one      */
  400.             /* reference objects, so we can simply truncate it.      */
  401.             PBinTree -> Name[NAME_LEN - 1] = 0;
  402.         }
  403.         /* The following handle the optional attributes in record. */
  404.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  405.                     GetObjectAttributes(PObject, f);
  406.         else UnGetToken(StringToken);
  407.         /* The following handles reading the polygon list.         */
  408.         /* Note an object might be created from Polygons only.         */
  409.         PObject -> PPolygon = (PolygonStruct *)
  410.                 GetLinList(f, Descriptor, POLYGON_ENTRY);
  411.         if (!GlblParserError)
  412.             InsertBinTree(&Descriptor -> ObjectPointer, PBinTree);
  413.         DumpOutObject(PBinTree);
  414.         break;
  415.         default:
  416.         ParserError(P_ERR_UNDEF_EXPR_HEADER, StringToken);
  417.         break;
  418.     } /* Of switch. */
  419.     if (!feof(f)) EliminateComments(f);  /* Skip comments including '['. */
  420.     } /* Of while !eof. */
  421.  
  422.     return Descriptor;
  423. }
  424.  
  425. /*****************************************************************************
  426. * Routine to allocate one BinTree Item:                         *
  427. *****************************************************************************/
  428. static struct BinTree *AllocBinTree(int Entry, VoidPtr Data)
  429. {
  430.     struct BinTree *PBinTree;
  431.  
  432.     PBinTree = (BinTree *) MyMalloc(sizeof(BinTree));
  433.     PBinTree -> EntryType = Entry;
  434.     PBinTree -> Used = FALSE;
  435.     PBinTree -> Data.PVoid = Data;
  436.     PBinTree -> right = PBinTree -> left = (BinTree *) NULL;
  437.  
  438.     return PBinTree;
  439. }
  440.  
  441. /*****************************************************************************
  442. *   Routine to unget one token (on stack of UNGET_STACK_SIZE levels!)         *
  443. *****************************************************************************/
  444. static void UnGetToken(char *StringToken)
  445. {
  446.     if (GlblToken >= UNGET_STACK_SIZE) {
  447.      printf("Parser Internal stack overflow...\n");
  448.      MyExit(1);
  449.     }
  450.  
  451.     strcpy(GlblStringToken[GlblToken], StringToken);
  452.     GlblToken++;  /* GlblToken exists - Something in it (no overflow check). */
  453. }
  454.  
  455. /*****************************************************************************
  456. *   Routine to get the next token out of the input file    f.             *
  457. * Returns the next token found,    as StringToken.                     *
  458. * Note:    StringToken must be allocated before calling this routine!         *
  459. *****************************************************************************/
  460. static void GetStringToken(FILE *f, char *StringToken)
  461. {
  462.     int    len;
  463.     char c, *LocalStringToken;
  464.  
  465.     if (GlblToken) { /*    get first the unget token */
  466.     GlblToken--;
  467.     strcpy(StringToken, GlblStringToken[GlblToken]);
  468.     return;
  469.     }
  470.     /* skip white spaces: */
  471.     while ((!feof(f))
  472.      && (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
  473.         if (c == '\n') GlblLineCount++;         /* Count the lines. */
  474.  
  475.     LocalStringToken = StringToken;
  476.     if (c == '[')              /* Its a token by    itself so return it. */
  477.     *LocalStringToken++ = c;          /* Copy the token    into string. */
  478.     else {
  479.     if (!feof(f))
  480.          do    *LocalStringToken++ = c;      /* Copy the token    into string. */
  481.          while ((!feof(f)) &&
  482.               ((c = getc(f)) !=    ' ') &&    (c != '\t') && (c != '\n'));
  483.     if (c == '\n') ungetc(c, f);     /* Save it to be counted next time. */
  484.     }
  485.     *LocalStringToken =    NULL;                     /* Put    eos. */
  486.  
  487.     /* The following handles the spacial case were we have XXXX] - we must   */
  488.     /* split it    into two token XXXX and    ], UnGetToken(']') and return XXXX:  */
  489.     if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0))    {
  490.     /* Return CloseParan */
  491.     UnGetToken(&StringToken[len]);             /* Save next token. */
  492.     StringToken[len] = NULL;        /* Set end of string on    "]". */
  493.     }
  494. }
  495.  
  496. /*****************************************************************************
  497. *   Routine to get the next token out of the input file    f as token number.   *
  498. * Returns the next token number    found, with numeric result in NumericToken   *
  499. * if TokenType is TOKEN_NUMBER.                             *
  500. * Note:    StringToken must be allocated before calling this routine!         *
  501. *****************************************************************************/
  502. static int GetToken(FILE *f, char *StringToken)
  503. {
  504.     GetStringToken(f, StringToken);
  505.  
  506.     if (feof(f))                 return TOKEN_EOF;
  507.  
  508.     if (!strcmp(StringToken, "["))         return TOKEN_OPEN_PAREN;
  509.     if (!strcmp(StringToken, "]"))         return TOKEN_CLOSE_PAREN;
  510.  
  511.     if (!strcmp(StringToken, "VERTEX"))         return TOKEN_VERTEX;
  512.     if (!strcmp(StringToken, "POLYGON"))     return TOKEN_POLYGON;
  513.     if (!strcmp(StringToken, "POLYLINE"))    return TOKEN_POLYLINE;
  514.     if (!strcmp(StringToken, "POINTLIST"))   return TOKEN_POINTLIST;
  515.     if (!strcmp(StringToken, "OBJECT"))         return TOKEN_OBJECT;
  516.  
  517.     if (!strcmp(StringToken, "COLOR"))         return TOKEN_COLOR;
  518.     if (!strcmp(StringToken, "INTERNAL"))    return TOKEN_INTERNAL;
  519.     if (!strcmp(StringToken, "NORMAL"))      return TOKEN_NORMAL;
  520.     if (!strcmp(StringToken, "PLANE"))         return TOKEN_PLANE;
  521.  
  522.     if (!strcmp(StringToken, "CBEZIER"))     return TOKEN_CBEZIER;
  523.     if (!strcmp(StringToken, "SBEZIER"))     return TOKEN_SBEZIER;
  524.     if (!strcmp(StringToken, "CNURB"))       return TOKEN_CNURB;
  525.     if (!strcmp(StringToken, "SNURB"))       return TOKEN_SNURB;
  526.  
  527.     return TOKEN_OTHER;                  /* Must be number or name. */
  528. }
  529.  
  530. /*****************************************************************************
  531. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  532. * Note the '[' was allready read.                         *
  533. * Current supported attributes: [INTERNAL] - internal edge (IRIT output)     *
  534. *****************************************************************************/
  535. static void GetVertexAttributes(VertexStruct *PVertex, FILE *f)
  536. {
  537.     int i;
  538.     char StringToken[LINE_LEN];
  539.  
  540.  
  541.     do {
  542.     switch (GetToken(f, StringToken)) {
  543.         case TOKEN_INTERNAL:
  544.         PVertex -> Internal = TRUE;
  545.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  546.             ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  547.         break;
  548.         case TOKEN_NORMAL:
  549.         PVertex -> HasNormal = TRUE;
  550.         /* The following handles reading of 3 coord. of normal.    */
  551.         for (i=0; i<3 ;i++) {
  552.             GetToken(f, StringToken);
  553.             if (sscanf(StringToken, "%f", &PVertex -> Normal[i]) != 1)
  554.             ParserError(P_ERR_NUMBER_EXPECTED, StringToken);
  555.         }
  556.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  557.             ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  558.         break;
  559.         default: /* Ignore this option! */
  560.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  561.         break;
  562.     }
  563.     }
  564.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  565.  
  566.     UnGetToken(StringToken);
  567. }
  568.  
  569. /*****************************************************************************
  570. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  571. * Note the '[' was allready read.                         *
  572. * Current supported attributes: None                         *
  573. *****************************************************************************/
  574. static void GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f)
  575. {
  576.     int i;
  577.     char StringToken[LINE_LEN];
  578.  
  579.     do {
  580.     switch (GetToken(f, StringToken)) {
  581.         case TOKEN_PLANE:
  582.         PPolygon -> HasPlane = TRUE;
  583.         /* The following handles reading of 4 coord. of plane eqn.. */
  584.         for (i=0; i<4 ;i++) {
  585.             GetToken(f, StringToken);
  586.             if (sscanf(StringToken, "%f", &PPolygon -> Plane[i]) != 1)
  587.             ParserError(P_ERR_NUMBER_EXPECTED, StringToken);
  588.         }
  589.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  590.             ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  591.         break;
  592.         default:
  593.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  594.         break;
  595.     }
  596.     }
  597.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  598.  
  599.     UnGetToken(StringToken);
  600. }
  601.  
  602. /*****************************************************************************
  603. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  604. * Note the '[' was allready read.                         *
  605. * Current supported attributes: [COLOR C] - set color.                 *
  606. *****************************************************************************/
  607. static void GetObjectAttributes(ObjectStruct *PObject, FILE *f)
  608. {
  609.     int    i;
  610.     char StringToken[LINE_LEN];
  611.  
  612.     do {
  613.     switch (GetToken(f, StringToken)) {
  614.         case TOKEN_COLOR:
  615.         GetToken(f, StringToken);
  616.         if (sscanf(StringToken, "%d", &i) != 1)
  617.             ParserError(P_ERR_NUMBER_EXPECTED, StringToken);
  618.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  619.             ParserError(P_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  620.         PObject -> Color = i;
  621.         break;
  622.         default:
  623.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  624.         break;
  625.     }
  626.     }
  627.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  628.  
  629.     UnGetToken(StringToken);
  630. }
  631.  
  632. /*****************************************************************************
  633. * Routine to read the input tokens up to a '[' token - skip comments.         *
  634. * Note the routine reads the '[' token,    so next    is the expression itself.    *
  635. *****************************************************************************/
  636. static void EliminateComments(FILE *f)
  637. {
  638.     char StringToken[LINE_LEN];
  639.  
  640.     while ((!feof(f)) && (GetToken(f, StringToken) != TOKEN_OPEN_PAREN));
  641. }
  642.  
  643. /*****************************************************************************
  644. * Routine to print pasring error according to ErrNum and set GlblParserError.*
  645. *****************************************************************************/
  646. static void ParserError(int ErrNum, char *Msg)
  647. {
  648.     GlblParserError = TRUE;
  649.  
  650.     printf("Error in line %3d : ", GlblLineCount);
  651.  
  652.     switch (ErrNum) {
  653.     case P_ERR_NUMBER_EXPECTED:
  654.         printf("Numeric data expected, ");
  655.         break;
  656.     case P_ERR_OPEN_PAREN_EXPECTED:
  657.         printf("[ expected, ");
  658.         break;
  659.     case P_ERR_CLOSE_PAREN_EXPECTED:
  660.         printf("] expected, ");
  661.         break;
  662.     case P_ERR_LIST_COMP_UNDEF:
  663.         printf("List component undefined - ");
  664.         break;
  665.     case P_ERR_UNDEF_EXPR_HEADER:
  666.         printf("Undefined expression header - ");
  667.         break;
  668.     case P_ERR_NAME_TOO_LONG:
  669.         printf("Object Name too long (Max %d) - ", NAME_LEN - 1);
  670.         break;
  671.     case P_ERR_PT_TYPE_EXPECTED:
  672.         printf("Point type expected, ");
  673.         break;
  674.     default:
  675.         printf("Unknown error, ");
  676.         break;
  677.     }
  678.     printf("found %s.\n", Msg);
  679. }
  680.  
  681. /*****************************************************************************
  682. * Routine to insert new    element    into a binary tree. If the element already   *
  683. * exists then the new one replace it.                         *
  684. *****************************************************************************/
  685. static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord)
  686. {
  687.     int    Comparison;
  688.     BinTree *PBin;
  689.  
  690.     if (*Tree == (BinTree *) NULL)   /*    Only might happen if the tree empty. */
  691.     *Tree =    PNewRecord;
  692.     else {                  /* Search for the new place to put it. */
  693.      /* Test for Match - if    so replace old by new: */
  694.     if ((Comparison    = strcmp((*Tree) -> Name, PNewRecord -> Name)) == 0) {
  695.         PBin = *Tree;
  696.         *Tree = PNewRecord;                     /* Replace. */
  697.         switch (PBin -> EntryType) {      /* Free the data area (union). */
  698.         case VERTEX_ENTRY:
  699.             free((char *) PBin -> Data.PVertex);
  700.             break;
  701.         case POLYGON_ENTRY:
  702.             free((char *) PBin -> Data.PPolygon);
  703.             break;
  704.         case OBJECT_ENTRY:
  705.             free((char *) PBin -> Data.PObject);
  706.             break;
  707.         default:
  708.             /* Should not be, unless was not updated here... */
  709.             break;
  710.         }
  711.         free((char *) PBin);
  712.     }
  713.     else if    (Comparison > 0)       /* Go to right side - its bigger. */
  714.         if ((*Tree) -> right !=    (BinTree *) NULL)  /* Only if exist. */
  715.             InsertBinTree(&((*Tree) -> right), PNewRecord);
  716.         else (*Tree) ->    right =    PNewRecord;  /*    Put record in place. */
  717.          else if ((*Tree) -> left != (BinTree *) NULL) /* Only if exist. */
  718.             InsertBinTree(&((*Tree) -> left), PNewRecord);/*Smaller. */
  719.           else (*Tree) -> left = PNewRecord; /*    Put record in place. */
  720.     }
  721. }
  722.  
  723. /*****************************************************************************
  724. * Routine to Get an element from binary    tree. If the element is    found a         *
  725. * pointer to it    BinTree    record is return, NULL else...                 *
  726. *****************************************************************************/
  727. BinTree *GetBinTree(char *RecName, BinTree *Tree)
  728. {
  729.     int    Comparison;
  730.  
  731.     /* If the tree is empty - not found, return    NULL: */
  732.     if (Tree ==    (BinTree *) NULL) return (BinTree *) NULL;
  733.  
  734.     /* Test for    Match -    if so return that record: */
  735.     if ((Comparison = strcmp(Tree -> Name, RecName)) == 0)
  736.     return Tree;                  /* Found it - so return it ... */
  737.     else if (Comparison    > 0)
  738.           return GetBinTree(RecName, Tree -> right);
  739.      else return GetBinTree(RecName, Tree -> left);
  740. }
  741.  
  742. /*****************************************************************************
  743. * Routine to search for    Name in    the trees, allowed by EntryTypes, of the     *
  744. * file descrition FD. NULL returned if not found. The order of search is:    *
  745. * VERTEX ,  POLYGON ,  OBJECT.                             *
  746. * Once found, if was already used (multi-reference) it is copied fresh.         *
  747. *****************************************************************************/
  748. static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD,
  749.                                 int EntryTypes)
  750. {
  751.     BinTree *PBin;
  752.     VertexStruct *PVertex;
  753.     PolygonStruct *PPolygon;
  754.     ObjectStruct *PObject;
  755.  
  756.     if (EntryTypes & VERTEX_ENTRY) {          /* Check in vertices tree. */
  757.     if ((PBin = GetBinTree(Name, FD -> VertexPointer)) != NULL) {
  758.         if (PBin -> Used) {
  759.         PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct));
  760.         GEN_COPY(PVertex, PBin -> Data.PVertex, sizeof(VertexStruct));
  761.         return (LinearListStruct *) PVertex;
  762.         }
  763.         else {
  764.         PBin -> Used = TRUE;
  765.         return (LinearListStruct *) PBin -> Data.PVertex;
  766.         }
  767.     }
  768.     }
  769.     if (EntryTypes & POLYGON_ENTRY) {           /* Check in polygon tree. */
  770.     if ((PBin = GetBinTree(Name, FD -> PolygonPointer)) != NULL) {
  771.         if (PBin -> Used) {
  772.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  773.         GEN_COPY(PPolygon, PBin -> Data.PPolygon, sizeof(PolygonStruct));
  774.         return (LinearListStruct *) PPolygon;
  775.         }
  776.         else {
  777.         PBin -> Used = TRUE;
  778.         return (LinearListStruct *) PBin -> Data.PPolygon;
  779.         }
  780.     }
  781.     }
  782.     if (EntryTypes & OBJECT_ENTRY) {            /* Check in object tree. */
  783.     if ((PBin = GetBinTree(Name, FD -> ObjectPointer)) != NULL) {
  784.         if (PBin -> Used) {
  785.         PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct));
  786.         GEN_COPY(PObject, PBin -> Data.PObject, sizeof(ObjectStruct));
  787.         return (LinearListStruct *) PObject;
  788.         }
  789.         else {
  790.         PBin -> Used = TRUE;
  791.         return (LinearListStruct *) PBin -> Data.PObject;
  792.         }
  793.     }
  794.     }
  795.  
  796.     return NULL;                           /* Not found. */
  797. }
  798.  
  799. /*****************************************************************************
  800. * Routine to get linear    list of    names from file    f until    ']' is detected.     *
  801. * search for that names    in file    description FD unter the trees allowed         *
  802. * according to EntryTypes (1 bit per entry, see    ?????Entry is parser.h).     *
  803. * Create a linear list of pointers to them. Return that    linear list.         *
  804. *****************************************************************************/
  805. static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes)
  806. {
  807.     char StringToken[LINE_LEN];
  808.     struct LinearListStruct *PLinHead = NULL, *PLinTail = NULL, *PItem;
  809.  
  810.     while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) {
  811.     if ((PItem = GetNameFromFD(StringToken, FD, EntryTypes)) == NULL) {
  812.         ParserError(P_ERR_LIST_COMP_UNDEF, StringToken);/* Record undef. */
  813.         continue;             /* To next component to search for. */
  814.     }
  815.     if (PLinHead ==    NULL)                /* Its first record. */
  816.         PLinHead = PLinTail    = PItem;
  817.     else {                    /* Its record in the middle. */
  818.         PLinTail ->    Pnext =    PItem;
  819.         PLinTail = PItem;
  820.     }
  821.     }
  822.     if (PLinTail != NULL) PLinTail -> Pnext = NULL;    /* Mark end of list. */
  823.  
  824.     return (VoidPtr) PLinHead;
  825. }
  826.  
  827. /*****************************************************************************
  828. * My Routine to    allocate dynamic memory. All program requests must call this *
  829. * routine (no direct call to malloc). Dies if no memory.             *
  830. *****************************************************************************/
  831. static char *MyMalloc(unsigned size)
  832. {
  833.     char *p;
  834.  
  835.     if ((p = malloc(size)) != NULL) return p;
  836.  
  837.     printf("Not enough memory, exit\n");
  838.     MyExit(2);
  839.  
  840.     return NULL;                    /* Make warnings silent. */
  841. }
  842.  
  843. /*****************************************************************************
  844. * MyExit routine. Note it might call to CloseGraph without calling         *
  845. * InitGraph(), or call MouseClose() without MouseInit() etc. and it is the   *
  846. * responsibility of the individual modules to do nothing in these cases.     *
  847. *****************************************************************************/
  848. static void MyExit(int ExitCode)
  849. {
  850.     exit(ExitCode);
  851. }
  852.