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

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