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

  1. /*****************************************************************************
  2. *   Module to read a graphic data file into the    given structure.         *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 2.0, Mar. 1990   *
  5. *****************************************************************************/
  6.  
  7. /* #define DEBUG         /* Defines some helpfull printing routines. */
  8.  
  9. #ifdef __MSDOS__
  10. #include <stdlib.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 "genmat.h"
  19. #include "parser.h"
  20.  
  21. static int  GlblToken =    0,          /* Used by the parser, to unget token. */
  22.         GlblLineCount = 1,         /* Used to locate errors in input file. */
  23.         GlblParserError = 0;        /* Save last error number found. */
  24. static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN];/* Save unget tokens.*/
  25. static struct FileDescription *Descriptor;
  26.  
  27. static struct BinTree *AllocBinTree(int Entry, VoidPtr Data);
  28. static void UnGetToken(char *StringToken);
  29. static void GetStringToken(FILE *f, char *StringToken);
  30. static int GetToken(FILE *f, char *StringToken);
  31. static void GetVertexAttributes(VertexStruct *PVertex, FILE *f);
  32. static int GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f);
  33. static void GetObjectAttributes(ObjectStruct *PObject, FILE *f);
  34. static void EliminateComments(FILE *f);
  35. static void ParserError(int ErrNum, char *Msg);
  36. static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord);
  37. static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD,
  38.                             int EntryTypes);
  39. static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes);
  40.  
  41. #ifdef DEBUG
  42. void PrintAllBinTrees(FileDescription *FD);
  43. void PrintBinTree(BinTree *Tree);
  44. #endif DEBUG
  45.  
  46. /*****************************************************************************
  47. * Routine to read the data from    a given    file and update    the data structures  *
  48. * Descriptor (which returned) from it.                         *
  49. * If MoreFlag is on then more printed staff will be given...             *
  50. *****************************************************************************/
  51. FileDescription *GetDataFile(FILE *f)
  52. {
  53.     int    i;
  54.     char StringToken[LINE_LEN];
  55.     struct VertexStruct       *PVertex;
  56.     struct PolygonStruct   *PPolygon;
  57.     struct ObjectStruct       *PObject;
  58.     struct BinTree       *PBinTree;
  59.  
  60.     GlblToken =    0;
  61.  
  62.     Descriptor = (FileDescription *) MyMalloc(sizeof(FileDescription));
  63.     /* As all the trees    are empty set the following: */
  64.     Descriptor -> VertexPointer       =
  65.     Descriptor -> PolygonPointer   =
  66.     Descriptor -> PolylinePointer  =
  67.     Descriptor -> ObjectPointer       = (BinTree *) NULL;
  68.  
  69.     GlblLineCount = 1;                      /* Reset line counter. */
  70.     EliminateComments(f);         /* Skip all comments including '['. */
  71.     while (!feof(f)) {
  72.     GlblParserError = 0;                    /* Reset errors. */
  73.     switch (GetToken(f, StringToken)) {
  74.         case TOKEN_VERTEX:
  75.         ++NumOfVertices;
  76.  
  77.         PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct));
  78.         PVertex -> Transform = FALSE;  /* If vertex was transformed. */
  79.         PVertex -> HasNormal = FALSE;          /* If vertex has normal. */
  80.         PBinTree = AllocBinTree(VERTEX_ENTRY, (VoidPtr) PVertex);
  81.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  82.         /* The following handle the optional attributes in record.   */
  83.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  84.             GetVertexAttributes(PVertex, f);  /* Get attributes. */
  85.         else UnGetToken(StringToken);
  86.         /* The following handles reading of 3 coord. of vertex. */
  87.         for (i=0; i<3    ;i++) {
  88.             GetToken(f, StringToken);
  89.             if (sscanf(StringToken, "%f", &PVertex -> Coord[i]) != 1)
  90.                 ParserError(P_ERR_NumberExpected, StringToken);
  91.         }
  92.         if ((i=GetToken(f, StringToken)) != TOKEN_CLOSE_PAREN)
  93.             ParserError(P_ERR_CloseParanExpected, StringToken);
  94.         if (!GlblParserError)
  95.             InsertBinTree(&Descriptor -> VertexPointer, PBinTree);
  96.         break;
  97.         case TOKEN_POLYGON:
  98.         fprintf(stderr, "\b\b\b\b\b%5d", ++NumOfPolygons);
  99.  
  100.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  101.         PPolygon -> Polyline = FALSE;
  102.         PPolygon -> FlipPlaneDir = 1;    /* Can be one of 1, -1 only. */
  103.         PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon);
  104.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  105.         /* The following handle the optional attributes in record.   */
  106.         i = FALSE;        /* Let see if polygon has plane defined:   */
  107.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  108.             i = GetPolygonAttributes(PPolygon, f);
  109.         else UnGetToken(StringToken);
  110.         /* The following handles reading the members list. */
  111.         PPolygon -> PVertex = (VertexStruct *)
  112.             GetLinList(f, Descriptor, VERTEX_ENTRY);
  113.  
  114.         /* Update Plane equation if has non or set the flip plane    */
  115.         /* dir if do has one.                         */
  116.         i = UpdateEqnPolygon(PPolygon, i);
  117.  
  118.         /* Dont put it in if parser error, and clip its vertex list  */
  119.         /* if failed to find PLANE equation or polygon is back         */
  120.         /* and we are required to delete these (free it if you like).*/
  121.         if (!GlblParserError) {
  122.             if (!i) PPolygon -> PVertex = NULL;
  123.             InsertBinTree(&Descriptor -> PolygonPointer, PBinTree);
  124.         }
  125.         break;
  126.         case TOKEN_POLYLINE:
  127.         fprintf(stderr, "\b\b\b\b\b%5d", ++NumOfPolygons);
  128.  
  129.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  130.         PPolygon -> Polyline = TRUE;
  131.         PPolygon -> FlipPlaneDir = 1;   /* Can be one of 1, -1 only. */
  132.         PBinTree = AllocBinTree(POLYGON_ENTRY, (VoidPtr) PPolygon);
  133.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  134.         /* The following handle the optional attributes in record.   */
  135.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  136.             GetPolygonAttributes(PPolygon, f);
  137.         else UnGetToken(StringToken);
  138.         /* The following handles reading the members list. */
  139.         PPolygon -> PVertex = (VertexStruct *)
  140.             GetLinList(f, Descriptor, VERTEX_ENTRY);
  141.         if (!GlblParserError)
  142.             InsertBinTree(&Descriptor -> PolylinePointer, PBinTree);
  143.         break;
  144.         case TOKEN_OBJECT:
  145.         PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct));
  146.         PObject -> Color = ShadingInfo.DefaultColor;
  147.         PBinTree = AllocBinTree(OBJECT_ENTRY, (VoidPtr) PObject);
  148.         GetToken(f, PBinTree -> Name);            /* Get the name. */
  149.         /* The following handle the optional attributes in record.   */
  150.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  151.             GetObjectAttributes(PObject, f);
  152.         else UnGetToken(StringToken);
  153.         /* The following handles reading the polygon list. Note      */
  154.         /* an object might be created from Polygons/Polylines only.  */
  155.         PObject -> PPolygon = (PolygonStruct *)
  156.             GetLinList(f, Descriptor, POLYGON_ENTRY | POLYLINE_ENTRY);
  157.         /* Make sure no empty polygons exists (such as ones that had */
  158.         /* no PLANE for some reason.                     */
  159.         PPolygon = PObject -> PPolygon;
  160.         if (PPolygon)
  161.             while (PPolygon -> PVertex == NULL)
  162.             PPolygon = PObject -> PPolygon = PPolygon -> Pnext;
  163.         if (PPolygon)
  164.             while (PPolygon -> Pnext != NULL) {
  165.             if (PPolygon -> Pnext -> PVertex == NULL)
  166.                 PPolygon -> Pnext = PPolygon -> Pnext -> Pnext;
  167.             else PPolygon = PPolygon -> Pnext;
  168.             }
  169.  
  170.         if (!GlblParserError)
  171.             InsertBinTree(&Descriptor -> ObjectPointer, PBinTree);
  172.         break;
  173.         default:
  174.         ParserError(P_ERR_UndefExprHeader, StringToken);
  175.         break;
  176.     } /* Of switch. */
  177.     if (!feof(f)) EliminateComments(f);  /* Skip comments including '['. */
  178.     } /* Of while !eof. */
  179.  
  180.     return Descriptor;
  181. }
  182.  
  183. /*****************************************************************************
  184. * Routine to allocate one BinTree Item:                         *
  185. *****************************************************************************/
  186. static struct BinTree *AllocBinTree(int Entry, VoidPtr Data)
  187. {
  188.     struct BinTree *PBinTree;
  189.  
  190.     PBinTree = (BinTree *) MyMalloc(sizeof(BinTree));
  191.     PBinTree -> EntryType = Entry;
  192.     PBinTree -> Used = FALSE;
  193.     PBinTree -> Data.PVoid = Data;
  194.     PBinTree -> right = PBinTree -> left = (BinTree *) NULL;
  195.  
  196.     return PBinTree;
  197. }
  198.  
  199. /*****************************************************************************
  200. * The view file    should be 4 by 4 matrix.                     *
  201. *****************************************************************************/
  202. void GetViewFile(FILE *f, int FileExists)
  203. {
  204.     int    i, j;
  205.     char StringToken[LINE_LEN];
  206.     MatrixType PerspMat, Mat;
  207.  
  208.     if (FileExists) {
  209.     for (i=0; i<4; i++)
  210.         for (j=0; j<4; j++)
  211.         if (GetToken(f, StringToken) != TOKEN_OTHER ||
  212.             sscanf(StringToken, "%lf", &GlblViewMat[i][j]) != 1) {
  213.             fprintf(stderr, "Wrong input data in view file, dies\n");
  214.             MyExit(1);
  215.         }
  216.  
  217.     if (GetToken(f, StringToken) == TOKEN_OTHER &&
  218.         sscanf(StringToken, "%lf", &PerspMat[0][0]) == 1) {
  219.         for (i=0; i<4; i++)
  220.         for (j=0; j<4; j++) {
  221.             if (i==0 && j==0) continue;       /* Already got first one. */
  222.             if (GetToken(f, StringToken) != TOKEN_OTHER ||
  223.             sscanf(StringToken, "%lf", &PerspMat[i][j]) != 1) {
  224.             fprintf(stderr, "Wrong input data in view file, dies\n");
  225.             MyExit(1);
  226.             }
  227.         }
  228.         MultTwo4by4(GlblViewMat, GlblViewMat, PerspMat);
  229.     }
  230.     }
  231.     else { /* Set default isometric view: */
  232.     /* 90 - 35.2644 = 54.7356. */
  233.     GenMatRotX1(DEG2RAD(-54.7356), Mat);
  234.     GenMatRotZ1(M_PI + M_PI / 4, GlblViewMat);
  235.     MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
  236.     }
  237. }
  238.  
  239. /*****************************************************************************
  240. *   Routine to unget one token (on stack of UNGET_STACK_SIZE levels!)         *
  241. *****************************************************************************/
  242. static void UnGetToken(char *StringToken)
  243. {
  244.     if (GlblToken >= UNGET_STACK_SIZE) {
  245.      fprintf(stderr, "Parser Internal stack overflow...\n");
  246.      MyExit(1);
  247.     }
  248.  
  249.     strcpy(GlblStringToken[GlblToken], StringToken);
  250.     GlblToken++;  /* GlblToken exists - Something in it (no overflow check). */
  251. }
  252.  
  253. /*****************************************************************************
  254. *   Routine to get the next token out of the input file    f.             *
  255. * Returns the next token found,    as StringToken.                     *
  256. * Note:    StringToken must be allocated before calling this routine!         *
  257. *****************************************************************************/
  258. static void GetStringToken(FILE *f, char *StringToken)
  259. {
  260.     int    len;
  261.     char c, *LocalStringToken;
  262.  
  263.     if (GlblToken) {                   /* Get first the unget token. */
  264.     GlblToken--;
  265.     strcpy(StringToken, GlblStringToken[GlblToken]);
  266.     return;
  267.     }
  268.     /* skip white spaces: */
  269.     while ((!feof(f))
  270.      && (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
  271.         if (c == '\n') GlblLineCount++;         /* Count the lines. */
  272.  
  273.     LocalStringToken = StringToken;
  274.     if (c == '[')              /* Its a token by    itself so return it. */
  275.     *LocalStringToken++ = c;          /* Copy the token    into string. */
  276.     else {
  277.     if (!feof(f))
  278.          do    *LocalStringToken++ = c;      /* Copy the token    into string. */
  279.          while ((!feof(f)) &&
  280.               ((c = getc(f)) !=    ' ') &&    (c != '\t') && (c != '\n'));
  281.     if (c == '\n') ungetc(c, f);     /* Save it to be counted next time. */
  282.     }
  283.     *LocalStringToken =    NULL;                     /* Put    eos. */
  284.  
  285.     /* The following handles the spacial case were we have XXXX] - we must   */
  286.     /* split it    into two token XXXX and    ], UnGetToken(']') and return XXXX:  */
  287.     if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0))    {
  288.     /* Return CloseParan */
  289.     UnGetToken(&StringToken[len]);             /* Save next token. */
  290.     StringToken[len] = NULL;        /* Set end of string on    "]". */
  291.     }
  292. }
  293.  
  294. /*****************************************************************************
  295. *   Routine to get the next token out of the input file    f as token number.   *
  296. * Returns the next token number    found, with numeric result in NumericToken   *
  297. * if TokenType is TOKEN_NUMBER.                             *
  298. * Note:    StringToken must be allocated before calling this routine!         *
  299. *****************************************************************************/
  300. static int GetToken(FILE *f, char *StringToken)
  301. {
  302.     GetStringToken(f, StringToken);
  303.  
  304.     if (feof(f))                 return TOKEN_EOF;
  305.  
  306.     if (!strcmp(StringToken, "["))         return TOKEN_OPEN_PAREN;
  307.     if (!strcmp(StringToken, "]"))         return TOKEN_CLOSE_PAREN;
  308.  
  309.     if (!strcmp(StringToken, "VERTEX"))         return TOKEN_VERTEX;
  310.     if (!strcmp(StringToken, "POLYGON"))     return TOKEN_POLYGON;
  311.     if (!strcmp(StringToken, "POLYLINE"))    return TOKEN_POLYLINE;
  312.     if (!strcmp(StringToken, "OBJECT"))         return TOKEN_OBJECT;
  313.  
  314.     if (!strcmp(StringToken, "COLOR"))         return TOKEN_COLOR;
  315.     if (!strcmp(StringToken, "RGB"))         return TOKEN_RGB;
  316.     if (!strcmp(StringToken, "INTERNAL"))    return TOKEN_INTERNAL;
  317.     if (!strcmp(StringToken, "NORMAL"))      return TOKEN_NORMAL;
  318.     if (!strcmp(StringToken, "PLANE"))       return TOKEN_PLANE;
  319.  
  320.     return TOKEN_OTHER;                  /* Must be number or name. */
  321. }
  322.  
  323. /*****************************************************************************
  324. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  325. * Note the '[' was allready read.                         *
  326. * Current supported attributes: None.                         *
  327. *****************************************************************************/
  328. static void GetVertexAttributes(VertexStruct *PVertex, FILE *f)
  329. {
  330.     int i;
  331.     char StringToken[LINE_LEN];
  332.     float Size;
  333.  
  334.     do {
  335.     switch (GetToken(f, StringToken)) {
  336.         case TOKEN_NORMAL:
  337.         PVertex -> HasNormal = TRUE;
  338.         /* The following handles reading of 3 coord. of vertex. */
  339.         for (i=0, Size = 0.0; i<3 ;i++) {
  340.             GetToken(f, StringToken);
  341.             if (sscanf(StringToken, "%f", &PVertex -> Normal[i]) != 1)
  342.             ParserError(P_ERR_NumberExpected, StringToken);
  343.             Size += SQR(PVertex -> Normal[i]);
  344.         }
  345.         /* Make sure vector length is one unit: */
  346.         Size = sqrt(Size);
  347.         for (i=0; i<3 ;i++) PVertex -> Normal[i] /= Size;
  348.  
  349.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  350.             ParserError(P_ERR_CloseParanExpected, StringToken);
  351.         break;
  352.         default:                      /* Ignore this option! */
  353.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  354.         break;
  355.     }
  356.     }
  357.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  358.  
  359.     UnGetToken(StringToken);
  360. }
  361.  
  362. /*****************************************************************************
  363. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  364. * Note the '[' was allready read.                         *
  365. * Current supported attributes: [PLANE A B C D].                 *
  366. * Returns TRUE if polygon PLANE attribute has been read.             *
  367. *****************************************************************************/
  368. static int GetPolygonAttributes(PolygonStruct *PPolygon, FILE *f)
  369. {
  370.     int    i, HasPlane = FALSE;
  371.     char StringToken[LINE_LEN];
  372.  
  373.     do {
  374.     switch (GetToken(f, StringToken)) {
  375.         case TOKEN_PLANE:
  376.         for (i=0; i<4; i++) {
  377.             GetToken(f, StringToken);
  378.             if (sscanf(StringToken, "%f", &PPolygon -> Plane[i]) != 1)
  379.             ParserError(P_ERR_NumberExpected, StringToken);
  380.         }
  381.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  382.             ParserError(P_ERR_CloseParanExpected, StringToken);
  383.         HasPlane = TRUE;
  384.         break;
  385.         default:
  386.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  387.         break;
  388.     }
  389.     }
  390.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  391.  
  392.     UnGetToken(StringToken);
  393.  
  394.     return HasPlane;
  395. }
  396.  
  397. /*****************************************************************************
  398. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  399. * Note the '[' was allready read.                         *
  400. * Current supported attributes: [COLOR C] [COLOR R G B] - set color.         *
  401. *****************************************************************************/
  402. static void GetObjectAttributes(ObjectStruct *PObject, FILE *f)
  403. {
  404.     int    i;
  405.     char StringToken[LINE_LEN];
  406.  
  407.     do {
  408.     switch (GetToken(f, StringToken)) {
  409.         case TOKEN_COLOR:
  410.         GetToken(f, StringToken);
  411.         if (sscanf(StringToken, "%d", &i) != 1)
  412.             ParserError(P_ERR_NumberExpected, StringToken);
  413.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  414.             ParserError(P_ERR_CloseParanExpected, StringToken);
  415.         PObject -> Color = i;
  416.         break;
  417.         case TOKEN_RGB:
  418.         PObject -> Color = RGB_COLOR_GIVEN;
  419.         /* The following handles reading of 3 coord. of normal.    */
  420.         for (i=0; i<3 ;i++) {
  421.             GetToken(f, StringToken);
  422.             if (sscanf(StringToken, "%d", &PObject -> RGBColor[i]) != 1)
  423.             ParserError(P_ERR_NumberExpected, StringToken);
  424.         }
  425.         if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  426.             ParserError(P_ERR_CloseParanExpected, StringToken);
  427.         break;
  428.         default:
  429.         while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  430.         break;
  431.     }
  432.     }
  433.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  434.  
  435.     UnGetToken(StringToken);
  436. }
  437.  
  438. /*****************************************************************************
  439. * Routine to read the input tokens up to a '[' token - skip comments.         *
  440. * Note the routine reads the '[' token,    so next    is the expression itself.    *
  441. *****************************************************************************/
  442. static void EliminateComments(FILE *f)
  443. {
  444.     char StringToken[LINE_LEN];
  445.  
  446.     while ((!feof(f)) && (GetToken(f, StringToken) != TOKEN_OPEN_PAREN));
  447. }
  448.  
  449. /*****************************************************************************
  450. * Routine to print pasring error according to ErrNum and set GlblParserError.*
  451. *****************************************************************************/
  452. static void ParserError(int ErrNum, char *Msg)
  453. {
  454.     GlblParserError = TRUE;
  455.  
  456.     if (MoreFlag == 0) return;                  /* Dont print nothing. */
  457.  
  458.     fprintf(stderr, "\nError in line %3d : ", GlblLineCount);
  459.  
  460.     switch (ErrNum) {
  461.     case P_ERR_NumberExpected:
  462.         fprintf(stderr, "Numeric Data Expected, ");
  463.         break;
  464.     case P_ERR_CloseParanExpected:
  465.         fprintf(stderr, "] expected, ");
  466.         break;
  467.     case P_ERR_ListCompUndef:
  468.         fprintf(stderr, "List component undefined -");
  469.         break;
  470.     case P_ERR_UndefExprHeader:
  471.         fprintf(stderr, "Undefined expression header -");
  472.         break;
  473.     default:
  474.         fprintf(stderr, "Unknown error, ");
  475.         break;
  476.     }
  477.     fprintf(stderr, " found %s.\n", Msg);
  478. }
  479.  
  480. /*****************************************************************************
  481. * Routine to insert new    element    into a binary tree. If the element already   *
  482. * exists then the new one replace it.                         *
  483. *****************************************************************************/
  484. static void InsertBinTree(BinTree **Tree, BinTree *PNewRecord)
  485. {
  486.     int    Comparison;
  487.     BinTree *PBin;
  488.  
  489.     if (*Tree == (BinTree *) NULL)   /*    Only might happen if the tree empty. */
  490.     *Tree =    PNewRecord;
  491.     else {                  /* Search for the new place to put it. */
  492.      /* Test for Match - if    so replace old by new: */
  493.     if ((Comparison    = strcmp((*Tree) -> Name, PNewRecord -> Name)) == 0) {
  494.         PBin = *Tree;
  495.         *Tree = PNewRecord;                     /* Replace. */
  496.         switch (PBin -> EntryType) {      /* Free the data area (union). */
  497.         case VERTEX_ENTRY:
  498.             free((char *) PBin -> Data.PVertex);
  499.             break;
  500.         case POLYGON_ENTRY:
  501.             free((char *) PBin -> Data.PPolygon);
  502.             break;
  503.         case OBJECT_ENTRY:
  504.             free((char *) PBin -> Data.PObject);
  505.             break;
  506.         default:
  507.             /* Should not be, unless was not updated here... */
  508.             break;
  509.         }
  510.         free((char *) PBin);
  511.     }
  512.     else if    (Comparison > 0)       /* go to right side - its bigger. */
  513.         if ((*Tree) -> right !=    (BinTree *) NULL)  /* Only if exist. */
  514.             InsertBinTree(&((*Tree) -> right), PNewRecord);
  515.         else (*Tree) ->    right =    PNewRecord;  /*    Put record in place. */
  516.          else if ((*Tree) -> left != (BinTree *) NULL) /* Only if exist. */
  517.             InsertBinTree(&((*Tree) -> left), PNewRecord);/* Smaller.*/
  518.           else (*Tree) -> left = PNewRecord; /*    Put record in place. */
  519.     }
  520. }
  521.  
  522. /*****************************************************************************
  523. * Routine to Get an element from binary    tree. If the element is    found a         *
  524. * pointer to it    BinTree    record is return, NULL else...                 *
  525. *****************************************************************************/
  526. BinTree *GetBinTree(char *RecName, BinTree *Tree)
  527. {
  528.     int    Comparison;
  529.  
  530.     /* If the tree is empty - not found, return    NULL: */
  531.     if (Tree ==    (BinTree *) NULL) return (BinTree *) NULL;
  532.  
  533.     /* Test for    Match -    if so return that record: */
  534.     if ((Comparison = strcmp(Tree -> Name, RecName)) == 0)
  535.     return Tree;  /* Found it - so return it ... */
  536.     else if (Comparison    > 0)
  537.           return GetBinTree(RecName, Tree -> right);
  538.      else return GetBinTree(RecName, Tree -> left);
  539. }
  540.  
  541. /*****************************************************************************
  542. * Routine to search for    Name in    the trees, allowed by EntryTypes, of the     *
  543. * file descrition FD. NULL returned if not found. The order of search is:    *
  544. * VERTEX ,  POLYGON ,  OBJECT.                             *
  545. * Once found, if was already used (multi-reference) it is copied fresh.         *
  546. *****************************************************************************/
  547. static LinearListStruct *GetNameFromFD(char *Name, FileDescription *FD,
  548.                                 int EntryTypes)
  549. {
  550.     BinTree *PBin;
  551.     VertexStruct *PVertex;
  552.     PolygonStruct *PPolygon;
  553.     ObjectStruct *PObject;
  554.  
  555.     if (EntryTypes & VERTEX_ENTRY) {          /* Check in vertices tree. */
  556.     if ((PBin = GetBinTree(Name, FD -> VertexPointer)) != NULL) {
  557.         if (PBin -> Used) {
  558.         PVertex = (VertexStruct *) MyMalloc(sizeof(VertexStruct));
  559.         GEN_COPY(PVertex, PBin -> Data.PVertex, sizeof(VertexStruct));
  560.         return (LinearListStruct *) PVertex;
  561.         }
  562.         else {
  563.         PBin -> Used = TRUE;
  564.         return (LinearListStruct *) PBin -> Data.PVertex;
  565.         }
  566.     }
  567.     }
  568.     if (EntryTypes & POLYGON_ENTRY) {           /* Check in polygon tree. */
  569.     if ((PBin = GetBinTree(Name, FD -> PolygonPointer)) != NULL) {
  570.         if (PBin -> Used) {
  571.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  572.         GEN_COPY(PPolygon, PBin -> Data.PPolygon, sizeof(PolygonStruct));
  573.         return (LinearListStruct *) PPolygon;
  574.         }
  575.         else {
  576.         PBin -> Used = TRUE;
  577.         return (LinearListStruct *) PBin -> Data.PPolygon;
  578.         }
  579.     }
  580.     }
  581.     if (EntryTypes & POLYLINE_ENTRY) {          /* Check in polyline tree. */
  582.     if ((PBin = GetBinTree(Name, FD -> PolylinePointer)) != NULL) {
  583.         if (PBin -> Used) {
  584.         PPolygon = (PolygonStruct *) MyMalloc(sizeof(PolygonStruct));
  585.         GEN_COPY(PPolygon, PBin -> Data.PPolyline, sizeof(PolygonStruct));
  586.         return (LinearListStruct *) PPolygon;
  587.         }
  588.         else {
  589.         PBin -> Used = TRUE;
  590.         return (LinearListStruct *) PBin -> Data.PPolyline;
  591.         }
  592.     }
  593.     }
  594.     if (EntryTypes & OBJECT_ENTRY) {            /* Check in object tree. */
  595.     if ((PBin = GetBinTree(Name, FD -> ObjectPointer)) != NULL) {
  596.         if (PBin -> Used) {
  597.         PObject = (ObjectStruct *) MyMalloc(sizeof(ObjectStruct));
  598.         GEN_COPY(PObject, PBin -> Data.PObject, sizeof(ObjectStruct));
  599.         return (LinearListStruct *) PObject;
  600.         }
  601.         else {
  602.         PBin -> Used = TRUE;
  603.         return (LinearListStruct *) PBin -> Data.PObject;
  604.         }
  605.     }
  606.     }
  607.  
  608.     return NULL;                           /* Not found. */
  609. }
  610.  
  611. /*****************************************************************************
  612. * Routine to get linear    list of    names from file    f until    ']' is detected.     *
  613. * search for that names    in file    description FD unter the trees allowed         *
  614. * according to EntryTypes (1 bit per entry, see    ?????Entry is parser.h).     *
  615. * Create a linear list of pointers to them. Return that    linear list.         *
  616. *****************************************************************************/
  617. static VoidPtr GetLinList(FILE *f, FileDescription *FD, int EntryTypes)
  618. {
  619.     char StringToken[LINE_LEN];
  620.     struct LinearListStruct *PLinHead = NULL, *PLinTail = NULL, *PItem;
  621.  
  622.     while (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN) {
  623.     if ((PItem = GetNameFromFD(StringToken, FD, EntryTypes)) == NULL) {
  624.         ParserError(P_ERR_ListCompUndef, StringToken);  /* Record undef. */
  625.         continue;             /* To next component to search for. */
  626.     }
  627.     if (PLinHead ==    NULL)                /* Its first record. */
  628.         PLinHead = PLinTail    = PItem;
  629.     else {                    /* Its record in the middle. */
  630.         PLinTail ->    Pnext =    PItem;
  631.         PLinTail = PItem;
  632.     }
  633.     }
  634.     if (PLinTail != NULL) PLinTail -> Pnext = NULL;    /* Mark end of list. */
  635.  
  636.     return (VoidPtr) PLinHead;
  637. }
  638.  
  639. #ifdef    DEBUG
  640.  
  641. /*****************************************************************************
  642. * Routine to Print all the trees in the    file description:             *
  643. *****************************************************************************/
  644. void PrintAllBinTrees(FileDescription *FD)
  645. {
  646.     fprintf(stderr, "******************* Vertices ******************\n");
  647.     PrintBinTree(FD -> VertexPointer);
  648.     fprintf(stderr, "******************* Polygons ******************\n");
  649.     PrintBinTree(FD -> PolygonPointer);
  650.     fprintf(stderr, "****************** Polyliness *****************\n");
  651.     PrintBinTree(FD -> PolylinePointer);
  652.     fprintf(stderr, "******************* Objects *******************\n");
  653.     PrintBinTree(FD -> ObjectPointer);
  654. }
  655.  
  656. /*****************************************************************************
  657. * Routine to Print the Names in    tree in    lexicorgaphic order. Used only for   *
  658. * debuging - to    see trees content...                         *
  659. *****************************************************************************/
  660. void PrintBinTree(BinTree *Tree)
  661. {
  662.     /* If the tree is empty - not found, return    NULL: */
  663.     if (Tree ==    (BinTree *) NULL) return;
  664.  
  665.     PrintBinTree(Tree -> right);
  666.     fprintf(stderr, "%s\n", Tree -> Name);
  667.     PrintBinTree(Tree -> left);
  668. }
  669.  
  670. #endif  DEBUG
  671.