home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / IRIT / IRITS.ZIP / DATAPRSR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  30.2 KB  |  854 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d polygonal solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. * Data File Interpreter module - handle data files - to/from geom objects    *
  7. *****************************************************************************/
  8.  
  9. #ifdef __MSDOS__
  10. #include <graphics.h>
  11. #endif /* __MSDOS__ */
  12.  
  13. #include <stdio.h>
  14. #include <ctype.h>
  15. #include <math.h>
  16. #include <string.h>
  17. #include "program.h"
  18. #include "allocatg.h"
  19. #include "objects.h"
  20. #include "geomat3d.h"
  21. #include "dataprsl.h"
  22. #include "dataprsg.h"                /* Visible to the other modules. */
  23.  
  24. #ifndef __MSDOS__
  25. #include "xgraphic.h"
  26. #endif /* __MSDOS__ */
  27.  
  28. static int  DPGlblLineCount,         /* Used to locate errors in input file. */
  29.         DPGlblParserError;            /* Save last error number found. */
  30. static char DPGlblTokenError[LINE_LEN]; /* Last token where error was found. */
  31. static jmp_buf LclLongJumpBuffer;           /* Used in error traping. */
  32. /* The following are used to hold binary trees of Vertices & Polygon/lines.  */
  33. static struct BinTree *VertexRoot = NULL, *PolygonRoot = NULL;
  34.  
  35. static int  GlblToken =    0;          /* Used by the parser, to unget token. */
  36. static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN];/* Save unget tokens.*/
  37.  
  38. /*****************************************************************************
  39. * Routine to print the data from given object into given file FileName.         *
  40. *****************************************************************************/
  41. void DataPrsrPutObject(char *FileName, ObjectStruct *PObj)
  42. {
  43.     char *FileType = NULL, *Pchar;
  44.     char FullFileName[LINE_LEN];
  45.     FILE *f = NULL;
  46.  
  47.     DPGlblParserError = 0;
  48.     VertexRoot = PolygonRoot = NULL;
  49.  
  50.     /* If the following gain control and is non zero - its from error! */
  51.     if (setjmp(LclLongJumpBuffer) != 0) {
  52.     if (f != NULL) fclose(f);
  53.     return;
  54.     }
  55.  
  56.     switch (PObj -> ObjType) {
  57.     case GEOMETRIC_OBJ:
  58.         FileType = ".ply";
  59.         break;
  60.     case MATRIX_OBJ:
  61.         FileType = ".mat";
  62.         break;
  63.     default:
  64.         ParserError(DP_ERR_OnlyMatGeomObj, "");
  65.     }
  66.  
  67.     if ((Pchar = strchr(FileName, '.')) != (char *) NULL)
  68.     *Pchar = NULL;             /* Make sure no file type is given. */
  69.     if (strlen(FileName) == 0) ParserError(DP_ERR_EmptyName, "");
  70.  
  71.     strcpy(FullFileName, FileName);
  72.     strcat(FullFileName, FileType);
  73.  
  74.     if ((f = fopen(FullFileName, "w")) == NULL)
  75.     ParserError(DP_ERR_OpenFail, FullFileName);
  76.  
  77.     switch (PObj -> ObjType) {
  78.     case GEOMETRIC_OBJ:
  79.         DataPrsrPutGeomObject(f, PObj);
  80.         break;
  81.     case MATRIX_OBJ:
  82.         DataPrsrPutMatObject(f, PObj);
  83.         break;
  84.     }
  85.  
  86.     fclose(f);
  87.     return;
  88. }
  89.  
  90. /*****************************************************************************
  91. * Routine to print the data from given geometric object into given file f    *
  92. *****************************************************************************/
  93. static void DataPrsrPutGeomObject(FILE *f, ObjectStruct *PObj)
  94. {
  95.     int i, CountVertices = 0, BaseVertices, CountPolys = 0;
  96.     char *s;
  97.     struct PolygonStruct *PPoly = PObj -> U.Pl;
  98.     struct VertexStruct *PVertex, *PVFirst;
  99.  
  100.     while (PPoly) {
  101.     PVFirst = PVertex = PPoly -> V;
  102.     BaseVertices = CountVertices;       /* To know index of first vertex. */
  103.     if (PVertex == NULL)
  104.         FatalError("DataPrsrPutGeomObject: Attemp to dump empty polygon, exit\n");
  105.  
  106.     do {                  /* Assume at list one edge in polygon! */
  107.         if (IS_INTERNAL_EDGE(PVertex)) s = "[INTERNAL] ";
  108.         else s = "";
  109.  
  110.         /* Make real zero, if number is smaller than EPSILON: */
  111.         for (i=0; i<3; i++) if (ABS(PVertex -> Pt[i]) < EPSILON)
  112.         PVertex -> Pt[i] = 0.0;
  113. #        ifdef DOUBLE
  114.         fprintf(f, "[VERTEX V%-3d %s%10lg %10lg %10lg]\n",
  115. #        else
  116.         fprintf(f, "[VERTEX V%-3d %s%10g %10g %10g]\n",
  117. #        endif /* DOUBLE */
  118.         CountVertices++, s,
  119.         PVertex -> Pt[0], PVertex -> Pt[1], PVertex -> Pt[2]);
  120.         PVertex = PVertex -> Pnext;
  121.     }
  122.     while (PVertex != PVFirst && PVertex != NULL);
  123.  
  124.         if (IS_POLYLINE_GEOM_OBJ(PObj))
  125.          fprintf(f, "[POLYLINE P%-3d", CountPolys++);
  126.     else {
  127.         for (i=0; i<4; i++) if (ABS(PPoly -> Plane[i]) < EPSILON)
  128.         PPoly -> Plane[i] = 0.0;
  129. #        ifdef DOUBLE
  130.         fprintf(f, "[POLYGON P%-3d [PLANE %10lg %10lg %10lg %10lg]",
  131. #        else
  132.         fprintf(f, "[POLYGON P%-3d [PLANE %10g %10g %10g %10lg]",
  133. #        endif /* DOUBLE */
  134.         CountPolys++, PPoly -> Plane[0], PPoly -> Plane[1],
  135.                   PPoly -> Plane[2], PPoly -> Plane[3]);
  136.     }
  137.  
  138.     for (i=BaseVertices; i<CountVertices; i++) {
  139.         if ((i-BaseVertices) % 10 == 0) fprintf(f, "\n\t");
  140.         fprintf(f, "V%-3d ", i);
  141.     }
  142.     fprintf(f, "]\n\n");
  143.  
  144.     PPoly = PPoly -> Pnext;
  145.     }
  146.     fprintf(f, "[OBJECT %s [COLOR %d]", PObj -> Name, GET_OBJECT_COLOR(PObj));
  147.     for (i=0; i<CountPolys; i++) {
  148.     if (i % 10 == 0) fprintf(f, "\n\t");
  149.     fprintf(f, "P%-4d", i);
  150.     }
  151.     fprintf(f, "]\n");
  152. }
  153.  
  154. /*****************************************************************************
  155. * Routine to print the data from given matrix object into given file f         *
  156. *****************************************************************************/
  157. static void DataPrsrPutMatObject(FILE *f, ObjectStruct *PObj)
  158. {
  159.     int i, j;
  160.  
  161.     for (i=0; i<4; i++) {
  162.     for (j=0; j<4; j++)
  163. #        ifdef DOUBLE
  164.         fprintf(f, "%17.8le ",
  165. #        else
  166.         fprintf(f, "%17.8e ",
  167. #        endif /* DOUBLE */
  168.             PObj -> U.Mat[i][j]);
  169.     fprintf(f, "\n");
  170.     }
  171.     fprintf(f, "MATRIX %s\n", PObj -> Name);
  172. }
  173.  
  174. /*****************************************************************************
  175. * Routine to read the data from    a given    file and scans for the Geometric     *
  176. * object named ObjName. Returns a pointer to the data structure represent    *
  177. * that geometic object. If ObjName is NULL, returns first object in file.    *
  178. *****************************************************************************/
  179. ObjectStruct *DataPrsrGetObject(char *FileName, char *ObjName)
  180. {
  181.     int    i, ObjType;
  182.     char FullFileName[LINE_LEN];
  183.     FILE *f = NULL;
  184.     ObjectStruct *PObj;
  185.  
  186.     DPGlblParserError = 0;
  187.     VertexRoot = PolygonRoot = NULL;
  188.  
  189.     /* If the following gain control and is non zero - its from error! */
  190.     if (setjmp(LclLongJumpBuffer) != 0) {
  191.     if (f != NULL) fclose(f);
  192.     return NULL;
  193.     }
  194.  
  195.     if (strlen(FileName) == 0) ParserError(DP_ERR_EmptyName, "");
  196.  
  197.     strcpy(FullFileName, FileName);
  198.     if (strchr(FullFileName, '.') == NULL) strcat(FullFileName, ".ply");
  199.  
  200.     i = strlen(FullFileName) - 4;
  201.     if (stricmp(&FullFileName[i], ".ply") == 0) ObjType = GEOMETRIC_OBJ;
  202.     else
  203.     if (stricmp(&FullFileName[i], ".mat") == 0) ObjType = MATRIX_OBJ;
  204.     else
  205.     ParserError(DP_ERR_WrongFileType, FullFileName);
  206.  
  207.     if ((f = fopen(FullFileName, "r")) == NULL)
  208.     ParserError(DP_ERR_OpenFail, FullFileName);
  209.  
  210.     switch (ObjType) {
  211.     case GEOMETRIC_OBJ:
  212.         PObj = DataPrsrGetGeomObject(f, ObjName);
  213.         break;
  214.     case MATRIX_OBJ:
  215.         PObj = DataPrsrGetMatObject(f);
  216.         break;
  217.     }
  218.  
  219.     fclose(f);
  220.     return PObj;
  221. }
  222.  
  223. /*****************************************************************************
  224. * Routine to read the data from    a given    file and scans for the Geometric     *
  225. * object named ObjName. Returns a pointer to the data structure represent    *
  226. * that geometic object. If ObjName is NULL, returns first object in file.    *
  227. *****************************************************************************/
  228. static ObjectStruct *DataPrsrGetGeomObject(FILE *f, char *ObjName)
  229. {
  230.     int i, PlaneDefined, PolyType = 0, Color;
  231.     char StringToken[LINE_LEN], CrntObjName[OBJ_NAME_LEN];
  232.     struct BinTree *PBinTree;
  233.     struct VertexStruct       *PVertex;
  234.     struct PolygonStruct   *PPolygon;
  235.     struct ObjectStruct       *PObject;
  236.  
  237.     VertexRoot = PolygonRoot = NULL;          /* Start from empty trees. */
  238.     GlblToken =    0;
  239.     DPGlblLineCount = 1;                  /* Reset line counter. */
  240.  
  241.     EliminateComments(f);         /* Skip all comments including '['. */
  242.  
  243.     /* Set the long jump address to trap errors, and start the parser: */
  244.     while (!feof(f)) {
  245.      switch    (GetToken(f, StringToken)) {
  246.          case TKN_VERTEX:
  247.           PVertex = AllocVertex(0, 0, NULL, NULL);
  248.           PBinTree = AllocBinTree("", NULL, NULL, (VoidPtr) PVertex);
  249.           GetToken(f, PBinTree -> Name);        /* Get the name. */
  250.           /* The following handles the optional attr definition:     */
  251.           if (GetToken(f, StringToken) == TKN_OPEN_PARAN) {
  252.               GetVertexAttr(f, PVertex);
  253.           }
  254.           else {
  255.               UnGetToken(StringToken);
  256.           }
  257.           /* The following handles reading of 3    coord. of vertex. */
  258.           for (i=0; i<3    ;i++) {
  259.               GetToken(f, StringToken);
  260. #              ifdef DOUBLE
  261.               if (sscanf(StringToken, "%lf", &PVertex -> Pt[i]) != 1)
  262. #              else
  263.               if (sscanf(StringToken, "%f", &PVertex -> Pt[i]) != 1)
  264. #              endif /* DOUBLE */
  265.                   ParserError(DP_ERR_NumberExpected, StringToken);
  266.           }
  267.           if ((i=GetToken(f, StringToken)) != TKN_CLOSE_PARAN)
  268.             ParserError(DP_ERR_CloseParanExpected, StringToken);
  269.           InsertBinTree(&VertexRoot, PBinTree);
  270.           break;
  271.          case TKN_POLYGON:
  272.           if (PolyType && PolyType != TKN_POLYGON)
  273.               ParserError(DP_ERR_MixedPolygonLine, "");
  274.           else PolyType = TKN_POLYGON;
  275.           PPolygon = AllocPolygon(NULL, NULL, 0, 0);
  276.           RST_CONVEX_POLY(PPolygon);           /* May be not convex! */
  277.           PBinTree = AllocBinTree("", NULL, NULL, (VoidPtr) PPolygon);
  278.           GetToken(f, PBinTree -> Name);        /* Get the name. */
  279.           /* The following handles the optional attr definition:     */
  280.           PlaneDefined = FALSE;
  281.           if (GetToken(f, StringToken) == TKN_OPEN_PARAN) {
  282.               GetPolyAttr(f, PPolygon, &PlaneDefined);
  283.           }
  284.           else {
  285.               UnGetToken(StringToken);
  286.           }
  287.           /* The following handles reading the vertex list */
  288.           PPolygon -> V = GetVertexList(f, VertexRoot, PolyType);
  289.           if (!PlaneDefined) DPUpdatePolyPlane(PPolygon);
  290.           InsertBinTree(&PolygonRoot, PBinTree);
  291.           break;
  292.          case TKN_POLYLINE:
  293.           if (PolyType && PolyType != TKN_POLYLINE)
  294.               ParserError(DP_ERR_MixedPolygonLine, "");
  295.           else PolyType = TKN_POLYLINE;
  296.           PPolygon = AllocPolygon(NULL, NULL, 0, 0);
  297.           PBinTree = AllocBinTree("", NULL, NULL, (VoidPtr) PPolygon);
  298.           GetToken(f, PBinTree -> Name);        /* Get the name. */
  299.           /* The following handles the optional attr definition:     */
  300.           PlaneDefined = FALSE;
  301.           if (GetToken(f, StringToken) == TKN_OPEN_PARAN) {
  302.               GetPolyAttr(f, PPolygon, &PlaneDefined);
  303.           }
  304.           else {
  305.               UnGetToken(StringToken);
  306.           }
  307.           /* The following handles reading the vertex list */
  308.           PPolygon -> V = GetVertexList(f, VertexRoot, PolyType);
  309.           if (!PlaneDefined) DPUpdatePolyPlane(PPolygon);
  310.           InsertBinTree(&PolygonRoot, PBinTree);
  311.           break;
  312.          case TKN_OBJECT:
  313.           PObject = GenGeomObject("", NULL, NULL);
  314.           GetToken(f, CrntObjName);            /* Get the name. */
  315.           Color = LoadColor;
  316.           if (GetToken(f, StringToken) == TKN_OPEN_PARAN) {
  317.               GetObjectAttr(f, &Color);
  318.           }
  319.           else {
  320.               UnGetToken(StringToken);
  321.           }
  322.           /* The following handles reading the polygon list.         */
  323.           /* Note object might be created from Polygons/lines only.  */
  324.           PObject -> U.Pl = GetPolyList(f, PolygonRoot);
  325.           if (ObjName == NULL || strlen(ObjName) == 0 ||
  326.               strcmp(CrntObjName, ObjName) == 0) {
  327.               /* We got it - free unused data and return it: */
  328.               DataPrsrFreeAll(VertexRoot, PolygonRoot);
  329.               if (PolyType == TKN_POLYLINE)
  330.               SET_POLYLINE_GEOM_OBJ(PObject);/* Mark as polyline.*/
  331.               SET_OBJECT_COLOR(PObject, Color);
  332.               return PObject;
  333.           }
  334.           else {
  335.               PObject -> U.Pl = NULL;  /* Dont free the polys twice! */
  336.               MyFree((VoidPtr) PObject, OBJECT_TYPE);/* Not the one! */
  337.           }
  338.           break;
  339.          default:
  340.           ParserError(DP_ERR_UndefExprHeader, StringToken);
  341.           break;
  342.      } /* of switch    */
  343.      if (!feof(f)) EliminateComments(f);/* Skip comments including '['. */
  344.     } /* of while !eof */
  345.  
  346.     /* If we are here, object was not found in file - return NULL. */
  347.     DataPrsrFreeAll(VertexRoot, PolygonRoot);
  348.     return NULL;
  349. }
  350.  
  351. /*****************************************************************************
  352. * Routine to read the data from    a given    file and scans for the Matrix        *
  353. * object. The file is assumed to hold 16 (4 by 4 matrix) float numbers.      *
  354. *****************************************************************************/
  355. static ObjectStruct *DataPrsrGetMatObject(FILE *f)
  356. {
  357.     int i, j;
  358.     MatrixType Mat;
  359.  
  360.     for (i=0; i<4; i++)
  361.     for (j=0; j<4; j++)
  362.         if (1 !=
  363. #        ifdef DOUBLE
  364.             fscanf(f, "%lg",
  365. #        else
  366.             fscanf(f, "%g",
  367. #        endif /* DOUBLE */
  368.             &Mat[i][j]))
  369.         ParserError(DP_ERR_NonMatrixObject, "");
  370.  
  371.     return GenMatObject("", Mat, NULL);
  372. }
  373.  
  374. /*****************************************************************************
  375. *   Routine to update the Plane equation of the given polygon by the order   *
  376. * of the first 3 vertices of that polygon.                     *
  377. *****************************************************************************/
  378. static void DPUpdatePolyPlane(PolygonStruct *PPoly)
  379. {
  380.     int i;
  381.     VectorType V1, V2;
  382.     RealType Len;
  383.     struct VertexStruct *V;
  384.  
  385.     V = PPoly -> V;    PT_SUB(V1, V -> Pt, V -> Pnext -> Pt);
  386.     V = V -> Pnext;    PT_SUB(V2, V -> Pt, V -> Pnext -> Pt);
  387.  
  388.     VecCrossProd(PPoly -> Plane, V1, V2);           /* Find Plane Normal. */
  389.  
  390.     PPoly -> Plane[3] = (-DOT_PROD(PPoly -> Plane, PPoly -> V -> Pt));
  391.  
  392.     /* Normalize the plane such that the normal has length of 1: */
  393.     Len = PT_LENGTH(PPoly -> Plane);
  394.     for (i=0; i<4; i++) PPoly -> Plane[i] /= Len;
  395. }
  396.  
  397. /*****************************************************************************
  398. * Allocate one BinTree Structure:                         *
  399. *****************************************************************************/
  400. static struct BinTree * AllocBinTree(char *Name,
  401.                 BinTree * Right, BinTree * Left, VoidPtr Ptr)
  402. {
  403.     struct BinTree *p;
  404.  
  405.     p = (BinTree *) MyMalloc(sizeof(BinTree), OTHER_TYPE);
  406.  
  407.     strcpy(p -> Name, Name);
  408.     p -> Right = Right;
  409.     p -> Left = Left;
  410.     p -> U.PVoid = Ptr;
  411.  
  412.     return p;
  413. }
  414.  
  415. /*****************************************************************************
  416. * Free all the old data saved in the vertices/polygons trees.             *
  417. * Note that unused vertices/polygons are also freed (tested via their Count) *
  418. *****************************************************************************/
  419. static void DataPrsrFreeAll(BinTree *VertexRoot, BinTree *PolygonRoot)
  420. {
  421.     DataPrsrFreeTree(VertexRoot, VERTEX_TYPE);
  422.     DataPrsrFreeTree(PolygonRoot, POLYGON_TYPE);
  423. }
  424.  
  425. /*****************************************************************************
  426. * Free all the old data saved in the vertices/polygons trees.             *
  427. * Note that all vertices/polygons are also freed.                 *
  428. *****************************************************************************/
  429. static void DataPrsrFreeTree(BinTree *Root, int ObjType)
  430. {
  431.     if (Root == NULL) return;
  432.  
  433.     DataPrsrFreeTree(Root->Right, ObjType);
  434.     DataPrsrFreeTree(Root->Left, ObjType);
  435.  
  436.     switch (ObjType) {
  437.     case VERTEX_TYPE:
  438.         MyFree((char *) Root->U.PVertex, VERTEX_TYPE);
  439.         break;
  440.     case POLYGON_TYPE:
  441.         MyFree((char *) Root->U.PPolygon, POLYGON_TYPE);
  442.         break;
  443.     }
  444. }
  445.  
  446. /*****************************************************************************
  447. *   Routine to unget one token (on stack of UNGET_STACK_SIZE levels!)         *
  448. *****************************************************************************/
  449. static void UnGetToken(char *StringToken)
  450. {
  451.     if (GlblToken >= UNGET_STACK_SIZE) {
  452.     ParserError(DP_ERR_InternalStackOF, StringToken);
  453.     return;
  454.     }
  455.  
  456.     strcpy(GlblStringToken[GlblToken], StringToken);
  457.     GlblToken++;  /* GlblToken exists - Something in it (no overflow check). */
  458. }
  459.  
  460. /*****************************************************************************
  461. *   Routine to get the next token out of the input file    f.             *
  462. * Returns the next token found,    as StringToken.                     *
  463. * Note:    StringToken must be allocated before calling this routine!         *
  464. *****************************************************************************/
  465. static void GetStringToken(FILE *f, char *StringToken)
  466. {
  467.     int    len;
  468.     char c, *LocalStringToken;
  469.  
  470.     if (GlblToken) { /*    get first the unget token */
  471.     GlblToken--;
  472.     strcpy(StringToken, GlblStringToken[GlblToken]);
  473.     return;
  474.     }
  475.     /* skip white spaces: */
  476.     while ((!feof(f))
  477.      && (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
  478.         if (c == '\n') DPGlblLineCount++;         /* Count the lines. */
  479.  
  480.     LocalStringToken = StringToken;
  481.     if (c == '[')              /* Its a token by    itself so return it. */
  482.     *LocalStringToken++ = c;          /* Copy the token    into string. */
  483.     else {
  484.     if (!feof(f))
  485.          do    *LocalStringToken++ = c;      /* Copy the token    into string. */
  486.          while ((!feof(f)) &&
  487.               ((c = getc(f)) !=    ' ') &&    (c != '\t') && (c != '\n'));
  488.     if (c == '\n') ungetc(c, f);     /* Save it to be counted next time. */
  489.     }
  490.     *LocalStringToken =    NULL;                     /* Put    eos. */
  491.  
  492.     /* The following handles the spacial case were we have XXXX] - we must   */
  493.     /* split it    into two token XXXX and    ], UnGetToken(']') and return XXXX:  */
  494.     if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0))    {
  495.     /* Return CloseParan */
  496.     UnGetToken(&StringToken[len]);             /* Save next token. */
  497.     StringToken[len] = NULL;        /* Set end of string on    "]". */
  498.     }
  499. }
  500.  
  501. /*****************************************************************************
  502. *   Routine to get the next token out of the input file    f as token number.   *
  503. * Returns the next token number    found, with numeric result in NumericToken   *
  504. * if TokenType is TKN_NUMBER.                             *
  505. * Note:    StringToken must be allocated before calling this routine!         *
  506. *****************************************************************************/
  507. static int GetToken(FILE *f, char *StringToken)
  508. {
  509.     int RetVal;
  510.  
  511.     GetStringToken(f, StringToken);
  512.  
  513.     if (feof(f))                 RetVal = TKN_EOF;
  514.  
  515.     else
  516.     if (!strcmp(StringToken, "["))         RetVal = TKN_OPEN_PARAN;
  517.     else
  518.     if (!strcmp(StringToken, "]"))         RetVal = TKN_CLOSE_PARAN;
  519.     else
  520.  
  521.     if (!strcmp(StringToken, "VERTEX"))         RetVal = TKN_VERTEX;
  522.     else
  523.     if (!strcmp(StringToken, "POLYGON"))     RetVal = TKN_POLYGON;
  524.     else
  525.     if (!strcmp(StringToken, "POLYLINE"))    RetVal = TKN_POLYLINE;
  526.     else
  527.     if (!strcmp(StringToken, "OBJECT"))         RetVal = TKN_OBJECT;
  528.  
  529.     else
  530.     if (!strcmp(StringToken, "PLANE"))         RetVal = TKN_PLANE;
  531.     else
  532.     if (!strcmp(StringToken, "INTERNAL"))    RetVal = TKN_INTERNAL;
  533.     else
  534.     if (!strcmp(StringToken, "COLOR"))         RetVal = TKN_COLOR;
  535.  
  536.     else
  537.     RetVal = TKN_OTHER;                  /* Must be number or name. */
  538.  
  539.     return RetVal;
  540. }
  541.  
  542. /*****************************************************************************
  543. * Routine to read the input tokens up to a '[' token - skip comments.         *
  544. * Note the routine reads the '[' token,    so next    is the expression itself.    *
  545. *****************************************************************************/
  546. static void EliminateComments(FILE *f)
  547. {
  548.     char StringToken[LINE_LEN];
  549.  
  550.     while ((!feof(f)) && (GetToken(f, StringToken) != TKN_OPEN_PARAN));
  551. }
  552.  
  553. /*****************************************************************************
  554. * Routine to print pasring error according to ErrNum and set GlblParserError.*
  555. *****************************************************************************/
  556. static void ParserError(int ErrNum, char *Msg)
  557. {
  558.     DPGlblParserError = ErrNum;
  559.     strcpy(DPGlblTokenError, Msg);    /* Keep the message in safe place... */
  560.  
  561.     DataPrsrFreeAll(VertexRoot, PolygonRoot); /* In case of non empty trees. */
  562.     VertexRoot = PolygonRoot = NULL;
  563.  
  564.     longjmp(LclLongJumpBuffer, 1);                   /* Jump to... */
  565. }
  566.  
  567. /*****************************************************************************
  568. * Routine to insert new    element    into a binary tree. If the element already   *
  569. * exists then the new one replace it.                         *
  570. *****************************************************************************/
  571. static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord)
  572. {
  573.     int    Comparison;
  574.  
  575.     if (*Tree == NULL)             /* Only might happen if tree empty. */
  576.     *Tree =    PNewRecord;
  577.     else {  /* Search for the new place    to put it */
  578.      /* Test for Match - if    so replace old by new: */
  579.     if ((Comparison    = strcmp((*Tree) -> Name, PNewRecord -> Name)) == 0) {
  580.         ParserError(DP_ERR_SameName, PNewRecord -> Name);
  581.         return;
  582.     }
  583.     else if    (Comparison > 0)       /* go to right side - its bigge.r */
  584.           InsertBinTree(&((*Tree) -> Right), PNewRecord);
  585.          else InsertBinTree(&((*Tree) -> Left), PNewRecord); /* smaller. */
  586.     }
  587. }
  588.  
  589. /*****************************************************************************
  590. * Routine to Get an element from binary    tree. If the element is    found a         *
  591. * pointer to it    BinTree    record is return, NULL else...                 *
  592. *****************************************************************************/
  593. static BinTree *GetBinTree(char *Name, BinTree *Tree)
  594. {
  595.     int    Comparison;
  596.  
  597.     /* If the tree is empty - not found, return    NULL: */
  598.     if (Tree ==    (BinTree *) NULL) return (BinTree *) NULL;
  599.  
  600.     /* Test for    Match -    if so return that record: */
  601.     if ((Comparison = strcmp(Tree -> Name, Name)) == 0)
  602.     return Tree;                  /* Found it - so return it ... */
  603.     else if (Comparison    > 0)
  604.           return GetBinTree(Name, Tree -> Right);
  605.      else return GetBinTree(Name, Tree -> Left);
  606. }
  607.  
  608. /*****************************************************************************
  609. * Routine to get linear    list of    names from file    f until    ']' is detected.     *
  610. * search for that names    in BinTree VetrexRoot.                     *
  611. * Create a linear list of pointers to them. Return that    linear list.         *
  612. * If PolyType == TKN_POLYLINE, then the list in NULL terminated, otherwise   *
  613. * (TKN_POLYGON) it is made circular.                         *
  614. *****************************************************************************/
  615. static struct VertexStruct *GetVertexList(FILE *f, struct BinTree *VertexRoot,
  616.                                 int PolyType)
  617. {
  618.     char StringToken[LINE_LEN];
  619.     struct VertexStruct *PLinHead = NULL, *PLinTail = NULL;
  620.     BinTree *PBin;
  621.  
  622.     while (GetToken(f, StringToken) != TKN_CLOSE_PARAN) {
  623.     if ((PBin = GetBinTree(StringToken, VertexRoot)) == NULL) {
  624.         ParserError(DP_ERR_ListCompUndef, StringToken); /* Record undef. */
  625.         return NULL;
  626.     }
  627.     if (PLinHead ==    NULL)                /* Its first record. */
  628.         PLinHead = PLinTail    = AllocVertex(0, 0, NULL, NULL);
  629.     else {                    /* its record in the middle. */
  630.         PLinTail ->    Pnext =    AllocVertex(0, 0, NULL, NULL);
  631.         PLinTail = PLinTail    -> Pnext;
  632.     }
  633.  
  634.     /* Copy the point coordinates: */
  635.     PT_COPY(PLinTail -> Pt, PBin -> U.PVertex -> Pt);
  636.     PLinTail -> Count = PBin -> U.PVertex -> Count;
  637.     PLinTail -> Tags = PBin -> U.PVertex -> Tags;
  638.     }
  639.     if (PLinTail != NULL)
  640.     if (PolyType == TKN_POLYLINE)
  641.          PLinTail -> Pnext = NULL;         /* Mark end of linear list. */
  642.     else PLinTail -> Pnext = PLinHead;       /* Make it circular list. */
  643.  
  644.     return PLinHead;
  645. }
  646.  
  647. /*****************************************************************************
  648. * Routine to get linear    list of    polygons from file f, find them in the         *
  649. * binary tree PolygonRoot, and concat them into a linear list.             *
  650. *****************************************************************************/
  651. static struct PolygonStruct *GetPolyList(FILE *f, struct BinTree *PolygonRoot)
  652. {
  653.     char StringToken[LINE_LEN];
  654.     struct PolygonStruct *PLinHead = NULL, *PLinTail = NULL;
  655.     BinTree *PBin;
  656.  
  657.     while (GetToken(f, StringToken) != TKN_CLOSE_PARAN) {
  658.     if ((PBin = GetBinTree(StringToken, PolygonRoot)) == NULL) {
  659.         ParserError(DP_ERR_ListCompUndef, StringToken); /* Record undef. */
  660.         return NULL;
  661.     }
  662.     if (PLinHead ==    NULL)                /* Its first record. */
  663.         PLinHead = PLinTail    = AllocPolygon(0, 0, NULL, NULL);
  664.     else {                    /* Its record in the middle. */
  665.         PLinTail ->    Pnext = AllocPolygon(0, 0, NULL, NULL);
  666.         PLinTail = PLinTail    -> Pnext;
  667.     }
  668.     /* Polygon can be referred only one - we zap its vertex list: */
  669.     if (PBin -> U.PPolygon -> V == NULL)
  670.         ParserError(DP_ERR_PolyDupRefer, StringToken);
  671.  
  672.     PLANE_COPY(PLinTail -> Plane, PBin -> U.PPolygon -> Plane);
  673.     PLinTail -> Count = PBin -> U.PPolygon -> Count;
  674.     PLinTail -> Tags = PBin -> U.PPolygon -> Tags;
  675.     PLinTail -> V = PBin -> U.PPolygon -> V;
  676.     PBin -> U.PPolygon -> V = NULL;
  677.     }
  678.     if (PLinTail != NULL)
  679.     PLinTail -> Pnext = NULL;         /* Mark end of linear list. */
  680.  
  681.     return PLinHead;
  682. }
  683.  
  684. /*****************************************************************************
  685. * Routine to get polygon/polyline attributes. Attribute is allways of the    *
  686. * form [ATTR data1 data2 ...]. It is assumed the '[' was allready read.      *
  687. *****************************************************************************/
  688. static void GetPolyAttr(FILE *f, PolygonStruct *PPolygon, int *PlaneDefined)
  689. {
  690.     int i;
  691.     char StringToken[LINE_LEN];
  692.  
  693.     *PlaneDefined = FALSE;
  694.  
  695.     switch (GetToken(f, StringToken)) {
  696.     case TKN_PLANE:
  697.         for (i=0; i<4; i++) {
  698.         GetToken(f, StringToken);
  699. #        ifdef DOUBLE
  700.             if (sscanf(StringToken, "%lf", &PPolygon -> Plane[i]) != 1)
  701. #        else
  702.             if (sscanf(StringToken, "%f", &PPolygon -> Plane[i]) != 1)
  703. #        endif /* DOUBLE */
  704.             ParserError(DP_ERR_NumberExpected, StringToken);
  705.         }
  706.         if (GetToken(f, StringToken) != TKN_CLOSE_PARAN)
  707.         ParserError(DP_ERR_CloseParanExpected, StringToken);
  708.         *PlaneDefined = TRUE;
  709.         break;
  710.     default:
  711.         ParserError(DP_ERR_UndefAttr, StringToken);
  712.         break;
  713.     }
  714. }
  715.  
  716. /*****************************************************************************
  717. * Routine to get vertex attributes. Attribute is allways of the form:         *
  718. * [ATTR data1 data2 ...]. It is assumed the '[' was allready read.         *
  719. *****************************************************************************/
  720. static void GetVertexAttr(FILE *f, VertexStruct *PVertex)
  721. {
  722.     char StringToken[LINE_LEN];
  723.  
  724.     switch (GetToken(f, StringToken)) {
  725.     case TKN_INTERNAL:
  726.         if (GetToken(f, StringToken) != TKN_CLOSE_PARAN)
  727.         ParserError(DP_ERR_CloseParanExpected, StringToken);
  728.         SET_INTERNAL_EDGE(PVertex);
  729.         break;
  730.     default:
  731.         ParserError(DP_ERR_UndefAttr, StringToken);
  732.         break;
  733.     }
  734. }
  735.  
  736. /*****************************************************************************
  737. * Routine to get object attributes. Attribute is allways of the form:         *
  738. * [ATTR data1 data2 ...]. It is assumed the '[' was allready read.         *
  739. *****************************************************************************/
  740. static void GetObjectAttr(FILE *f, int *Color)
  741. {
  742.     int i;
  743.     char StringToken[LINE_LEN];
  744.  
  745.     switch (GetToken(f, StringToken)) {
  746.     case TKN_COLOR:
  747.         GetToken(f, StringToken);
  748.         if (sscanf(StringToken, "%d", &i) != 1)
  749.         ParserError(DP_ERR_NumberExpected, StringToken);
  750.         if (GetToken(f, StringToken) != TKN_CLOSE_PARAN)
  751.         ParserError(DP_ERR_CloseParanExpected, StringToken);
  752.         *Color = i;
  753.         break;
  754.     default:
  755.         ParserError(DP_ERR_UndefAttr, StringToken);
  756.         break;
  757.     }
  758. }
  759.  
  760. /*****************************************************************************
  761. *   Routine to return evaluation error if happen one, zero elsewhere         *
  762. *****************************************************************************/
  763. int DataPrsrParseError(char **ErrorMsg)
  764. {
  765.     int    Temp;
  766.     char TempCopy[LINE_LEN];
  767.  
  768.     if ((Temp = DPGlblParserError) == 0) return 0;
  769.  
  770.     strcpy(TempCopy, DPGlblTokenError);
  771.     DPGlblParserError = 0;
  772.  
  773.     switch (Temp) {
  774.     case DP_ERR_NumberExpected:
  775.         sprintf(DPGlblTokenError, "Line %d: Numeric data expected - found %s",
  776.         DPGlblLineCount, TempCopy);
  777.         break;
  778.     case DP_ERR_CloseParanExpected:
  779.         sprintf(DPGlblTokenError, "Line %d: ']' expected - found %s",
  780.         DPGlblLineCount, TempCopy);
  781.         break;
  782.     case DP_ERR_ListCompUndef:
  783.         sprintf(DPGlblTokenError, "Line %d: Undefined list element - \"%s\"",
  784.         DPGlblLineCount, TempCopy);
  785.         break;
  786.     case DP_ERR_UndefExprHeader:
  787.         sprintf(DPGlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
  788.         DPGlblLineCount, TempCopy);
  789.         break;
  790.     case DP_ERR_InternalStackOF:
  791.         sprintf(DPGlblTokenError, "Line %d: Internal stack O.F. (report it!)",
  792.         DPGlblLineCount);
  793.         break;
  794.     case DP_ERR_SameName:
  795.         sprintf(DPGlblTokenError, "Line %d: Item defined more than once - \"%s\"",
  796.         DPGlblLineCount, TempCopy);
  797.         break;
  798.     case DP_ERR_PolyDupRefer:
  799.         sprintf(DPGlblTokenError, "Line %d: Polygon refered more than once - \"%s\"",
  800.         DPGlblLineCount, TempCopy);
  801.         break;
  802.     case DP_ERR_UndefAttr:
  803.         sprintf(DPGlblTokenError, "Line %d: Undefined attribute - \"%s\"",
  804.         DPGlblLineCount, TempCopy);
  805.         break;
  806.     case DP_ERR_OnlyMatGeomObj:
  807.         sprintf(DPGlblTokenError, "Only matrix or geometric objects allowed");
  808.         break;
  809.     case DP_ERR_EmptyName:
  810.         sprintf(DPGlblTokenError, "Empty file name was given");
  811.         break;
  812.     case DP_ERR_OpenFail:
  813.         sprintf(DPGlblTokenError, "Fail to open file - %s",    TempCopy);
  814.         break;
  815.     case DP_ERR_WrongFileType:
  816.         sprintf(DPGlblTokenError, "Only '.mat' or '.ply' types allowed, found - %s",
  817.         TempCopy);
  818.         break;
  819.     case DP_ERR_MixedPolygonLine:
  820.         sprintf(DPGlblTokenError, "Line %d: Mixed polygon/polylines is not allowed is same file",
  821.         DPGlblLineCount);
  822.         break;
  823.     case DP_ERR_NonMatrixObject:
  824.         sprintf(DPGlblTokenError, "Line %d: No matrix object element found",
  825.             DPGlblLineCount);
  826.         break;
  827.     default:
  828.         sprintf(DPGlblTokenError, "Data file parser - undefined error");
  829.         break;
  830.     }
  831.  
  832.     *ErrorMsg = DPGlblTokenError;
  833.  
  834.     return Temp;
  835. }
  836.  
  837. #ifdef    DEBUG
  838.  
  839. /*****************************************************************************
  840. * Routine to Print the Names in    tree in    lexicorgaphic order. Used only for   *
  841. * debuging - to    see trees content...                         *
  842. *****************************************************************************/
  843. static void PrintBinTree(BinTree *Tree)
  844. {
  845.     /* If the tree is empty - not found, return    NULL: */
  846.     if (Tree ==    (BinTree *) NULL) return;
  847.  
  848.     PrintBinTree(Tree -> Right);
  849.     printf("%s\n", Tree -> Name);
  850.     PrintBinTree(Tree -> Left);
  851. }
  852.  
  853. #endif /* DEBUG */
  854.