9d0d557457b37a430bdf44f2f7fdc10e7de127f9
[occt.git] / src / StepFile / recfile.pc
1 /* 
2  Copyright (c) 1999-2014 OPEN CASCADE SAS
3
4  This file is part of Open CASCADE Technology software library.
5
6  This library is free software; you can redistribute it and/or modify it under
7  the terms of the GNU Lesser General Public License version 2.1 as published
8  by the Free Software Foundation, with special exception defined in the file
9  OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10  distribution for complete text of the license and disclaimer of any warranty.
11
12  Alternatively, this file may be used under the terms of Open CASCADE
13  commercial license or contractual agreement.
14 */ 
15
16 #include "stdio.h"
17 #include "string.h"
18 #include "stdlib.h"
19 #if defined(HAVE_MALLOC_H)
20 #include "malloc.h"
21 #endif
22 #include "recfile.ph" 
23 /*  enregistrement d'un fichier d'interface sous forme de records
24     gere les scopes
25
26     Ce fichier comprend 3 parties
27     - les routines traitant les char*, avec la notion de texte courant
28     - les declarations des donnees de travail proprement dites pour le fichier
29     - le corps des programmes d'enregistrement
30 */
31
32
33 /*           ROUTINES UTILITAIRES de traitement des textes (char*)          */
34
35 /*     Gestion du texte courant : c'est un texte alloue dynamiquement
36        rec_restext en alloue un (jete le precedent alloue si pas lu)
37        rec_gettext lit le texte en cours, qui ne sera pas desalloue ensuite
38        rec_settext en force un autre en jetant le precedent (idem rec_newtext)
39        tandis que rec_newtext alloue un texte, sans lien avec le courant
40 */
41
42 #define Maxcar 50000
43
44   static struct carpage {
45     struct carpage* next;        /*  chainage des pages de caracteres  */
46     int             used;        /*  place deja prise  */
47     char  cars[Maxcar+1];        /*  page de caracteres  */
48   } *onecarpage;
49
50   static char* restext = NULL ;  /* texte courant  (allocation dynamique) */
51   /* static int   resalloc = 0 ;*/    /*   alloue (memoire a liberer) ou non   */
52
53 static char txt_cart_p[]   = "CARTESIAN_POINT";
54
55 void rec_restext(char* newtext, int lentext)         /* destine a etre appele de l'exterieur */
56 {
57   char *res, *text;
58   if(strcmp(newtext,txt_cart_p)==0) {
59     restext = txt_cart_p;
60     return;
61   }
62   
63   if (onecarpage->used > Maxcar-lentext-1) {   /* allouer nouvelle page */
64     struct carpage *newpage;
65     int sizepage = sizeof(struct carpage);
66     if (lentext >= Maxcar) sizepage += (lentext+1 - Maxcar);
67     newpage = (struct carpage*) malloc (sizepage);
68     newpage->next = onecarpage;
69     onecarpage = newpage;
70     onecarpage->used = 0;
71   }
72   restext  = onecarpage->cars + onecarpage->used;
73   onecarpage->used += (lentext + 1);
74 /*   strcpy   */
75   res = restext ; text = newtext;
76   while (*text != '\0') { *res=*text ; res++ ; text++ ; }
77   *res = '\0' ;
78 }
79
80 void rec_gettext(char* *r)
81 /*  Le resultat retourne (pointeur) est destine a etre inclus dans un struct */
82 { *r = restext; }
83
84 void rec_settext(char* s)
85 /* substituer le texte courant par un autre deja alloue */
86 {  restext = s ;  }
87
88 char* rec_newtext(char* r)
89 /*  routine utilitaire creant une chaine dynamique a partir d'un char[]  */
90 {
91   char* savrestext;
92   char* s0;
93   savrestext = restext;
94   rec_restext(r,(int)strlen(r));
95   s0 = restext;
96   restext = savrestext;
97   return (s0);
98 }
99
100
101
102 static int modeprint = 0 ;  /* CONTROLE D'IMPRESSION (pour appel depuis yacc)*/
103
104 /*      DECLARATIONS des donnees de travail (en cours d'enregistrement)     */
105
106 static int  typarg ;       /* type du dernier argument lu */
107 static int  nbrec  = 0;    /* nombre total d'enregistrements de donnees */
108 static int  nbhead = 0;    /* nb de records pris par le Header */
109 static int  nbpar  = 0;    /* nb de parametres lus au total */
110 static int  yarec  = 0;    /* presence Record deja cree (1 apres Ident) */
111
112 static struct rec {          /*  DESCRIPTION D'UN RECORD  */
113   char* ident ;       /* identifieur du record  (en #12345...) ou scope-end */
114   char* type  ;       /* type du record  (peut etre sublist) */
115 /*  int nbarg ;          nombre de parametres (arguments) du record, not used */
116   struct unarg* first ;  /* 1er argument */
117 /*  struct unarg* last  ;dernier argument, not used */
118   struct rec*   next  ;  /* record suivant */
119 }  *currec ;           /* currec meme : record courant */
120
121 #define Maxrec 5000
122 static struct recpage {
123   struct recpage*  next;
124   int              used;
125   struct rec       args[Maxrec+1];
126 } *onerecpage;
127
128 static struct rec* firstrec ;  /* 1er record du fichier */
129 static struct rec* lastrec  ;  /* dernier record du fichier */
130
131 static char* curtype;          /* type dernier record (ou = sublist) */
132 static char* subarg ;          /* ident dernier record (sub-list eventuel) */
133 static int   numsub ;          /* numero de sous-liste en cours */
134
135
136 static struct unarg {          /*  DESCRIPTION D'UN ARGUMENT  */
137   int type ;     /* type de l'arg, dans une liste courte : entier, reel ... */
138   char* val ;    /* valeur alphanum de l'arg */
139   struct unarg* next ;  /* argument suivant dans la liste pour ce record */
140 }  *curarg ;
141
142 #define Maxarg 10000
143 static struct argpage {        /*  Allocation optimisee des arguments  */
144   struct argpage*  next;
145   int              used;
146   struct unarg     args[Maxarg+1];
147 } *oneargpage;
148
149
150 static struct scope {          /*  DESCRIPTION D'UN SCOPE  */
151                         /* les scopes sont empilables sans limite */
152   struct scope* prev;   /* scope precedent, auquel il faudra revenir */
153   struct rec*   rec;    /* record interrompu par le scope (a reprendre) */
154 }   *curscope ;         /*  curscope est le scope en cours */
155
156
157 /*               Constantes litterales               */
158 static char txt_sublist[]  = "/* (SUB) */" ;
159 static char txt_scope[]    = "SCOPE" ;
160 static char txt_endscope[] = "ENDSCOPE" ;
161 static char txt_nil[]      = " " ;
162 static char sub1[]         = "$1" ;  /* optimisation ... */
163 static char sub2[]         = "$2" ;
164 static char argtype1[] = "(IF#TnEHBx";  /* types arguments (2 1es lettres) */
165 static char argtype2[] = ")nlIxdnxix";
166 static char idzero[]   = "#0";
167
168
169 /*              Trace pour controle            */
170 void recfile_modeprint(int mode)
171 {  modeprint = mode;  }
172
173 static int   lastno;
174 extern int   steplineno;
175 extern int   modcom;
176 extern int   modend;
177
178 void rec_inityyll ()
179 {  
180   steplineno = 0;
181   modcom = 0;
182   modend = 0;
183   lastno = -1;
184 }
185
186
187 /*   INITIALISATION   */
188
189 void rec_debfile()
190 {
191   /*initialization of recpage*/
192   onerecpage = (struct recpage*) malloc ( sizeof(struct recpage) );
193   onerecpage->used = 0; onerecpage->next = NULL;
194
195   onecarpage = (struct carpage*) malloc ( sizeof(struct carpage) );
196   onecarpage->used = 0; onecarpage->next = NULL;  restext = NULL;
197   yarec = 0;  nbhead = nbrec = nbpar = 0 ; firstrec = NULL ; lastrec = NULL ;
198   curtype = txt_sublist;
199   currec = NULL ; curarg = NULL ;
200   curscope = NULL ;
201   oneargpage = (struct argpage*) malloc ( sizeof(struct argpage) );
202   oneargpage->next = NULL; oneargpage->used = 0;
203   rec_inityyll();
204 }
205
206 /*   INTERMEDIAIRE : passage de Header a Data    */
207 void rec_finhead()  {  nbhead = nbrec;  }
208
209 /*   CONCLUSION  :  actuellement, ne fait rien   */
210
211 void rec_finfile()  {  }
212
213
214 /*   GESTION DES RECORDS   */
215
216 /*   ENREGISTRER UN RECORD (deja pret)    */
217 static void rec_new(struct rec* newrec)
218 /*  nouveau record a enregistrer  */
219 {
220  nbrec ++ ;
221  if ( firstrec == NULL ) firstrec = newrec ;
222  if ( lastrec  != NULL ) lastrec->next = newrec ;
223  lastrec = newrec ;
224 }
225
226 /*  type du dernier argument lu  */
227 void rec_typarg(int argtype)
228 {  typarg = argtype;  }
229
230 /*   ENREGISTRER UNE ENTITE (record courant)   */
231 void rec_newent()
232 {
233  rec_new(currec) ;     /*  le record courant (currec) est enregistre  */
234
235 /*  gestion des sous-listes : si currec a un suivant note (cf pointeur suite),
236     alors c'est une sous-liste et le suivant est son contenant
237     EN CE CAS, il faut memoriser cette sous-liste en argument courant
238     En effet, d'une part la liste est reconnue comme un argument, d'autre part
239     part elle se termine par ")" : c'est donc ici qu'elle sera enregistree */
240
241  rec_typarg (rec_argSub) ;
242
243  subarg = currec->ident ;      /* si sous-liste, sera argument du contenant */
244 /*                          rec_check(1) ;    */
245  currec = currec->next ;       /* si nul, c'est qu'une autre entite suit */
246  lastrec->next = NULL ;
247 }
248
249
250 static struct rec*rec_newrec()
251 {
252   struct rec* newrec;
253   if (onerecpage->used >= Maxrec) {
254     struct recpage* newrecpage;
255     newrecpage = (struct recpage*) malloc ( sizeof (struct recpage) );
256     newrecpage->next = onerecpage;
257     onerecpage = newrecpage;
258     onerecpage->used = 0;
259   }
260   newrec = &(onerecpage->args[onerecpage->used]);
261   onerecpage->used++;
262
263   return newrec;
264 }
265
266
267 /*   RECORD COURANT :   */
268
269 /*   creer et preciser l'identifieur   */
270 void rec_ident()
271 {
272   currec = rec_newrec();
273   /*currec = (struct rec*) malloc (sizeof (struct rec)) ;*/
274   /*currec->nbarg = 0 ;*/
275   rec_gettext(&(currec->ident)) ;
276   currec->next = NULL ; currec->first = NULL ; /*currec->last = NULL ;*/
277   yarec = 1;
278 }
279
280 /*   preciser le type ; demarrage de la description de l'entite  */
281 void rec_type()
282 {
283 /* Pour le header : pas d'ident, donc en simuler un : derive de rec_ident */
284   if (!yarec) {
285     /*currec = (struct rec*) malloc (sizeof (struct rec)) ;*/
286     currec = rec_newrec();
287     /*currec->nbarg = 0 ;*/
288     currec->ident = idzero;  /* Ident bidon (il en faut un ...) */
289     currec->next = NULL ; currec->first = NULL ; /*currec->last = NULL ;*/
290   }
291   rec_gettext(&(currec->type)) ;
292   yarec = numsub = 0 ;      /* debut de l'entite */
293 }
294
295 /*  type d une liste qui n est pas une entite mais un argument
296     par defaut (cf rec_deblist) il n est pas defini donc mis = "/ (SUB) /" */
297 void rec_listype()
298 {  rec_gettext(&(curtype));  }
299
300 /*  ajouter un argument (type & valeur deja connus) */
301 void rec_newarg()
302 {
303   struct unarg *newarg;
304   nbpar ++;
305   /*currec->nbarg ++ ;*/
306 /*  newarg = (struct unarg*) malloc (sizeof (struct unarg)) ;  */
307   if (oneargpage->used >= Maxarg) {
308     struct argpage* newargpage;
309     newargpage = (struct argpage*) malloc ( sizeof(struct argpage) );
310     newargpage->next = oneargpage;
311     oneargpage = newargpage;
312     oneargpage->used = 0;
313   }
314   newarg = &(oneargpage->args[oneargpage->used]);
315   oneargpage->used ++;
316
317   newarg->type = typarg ;
318   if (typarg == rec_argSub) newarg->val = subarg ;
319   else rec_gettext (&(newarg->val));
320
321 /*  if (currec->first == NULL) currec->first = newarg;
322   else currec->last->next = newarg;
323   currec->last = newarg;*/
324   if (currec->first == NULL) currec->first = newarg;
325   else {
326     struct unarg* nextarg = currec->first;
327     while(nextarg->next != NULL)
328       nextarg = nextarg->next;
329     nextarg->next = newarg;
330
331   }
332   newarg->next = NULL ;
333 /*                          rec_check(0) ;    */
334 }
335
336 /*   Ajouter une sous-liste
337
338      Une ouverture de parentheses A L'INTERIEUR d'une liste de parametres
339      signale une sous-liste : c'est une entite non identifiee, directement
340      utilisee comme argument de la liste contenante) d'un type reserve(SUB)
341
342      Elle est enregistree avec un identifieur special : '$' suivi d'un numero
343      de sous-liste dans l'entite en cours.
344
345      Son enregistrement consiste a definir un nouveau record courant, pour la
346      sous-liste, qui note comme suivant l'ancien courant, qui est son contenant
347      A la fin de la sous-liste, elle est enregistree comme toute entite (cf
348      rec_new) mais le suivant devient le nouveau courant dont l'enregistrement
349      des parametres continue
350
351      La premiere ouverture de parentheses dans l'entite est celle de la liste
352      principale de parametres et non d'une sous-liste
353 */
354
355 void rec_deblist()
356 {
357  if (numsub > 0) {            /* enregistrement d'une sous-liste */
358   /* int i ; */ struct rec* subrec ;
359     /* creation du nouvel enregistrement et chainage au precedent */
360   subrec = rec_newrec();
361   /*subrec = (struct rec*) malloc (sizeof (struct rec)) ;*/
362   switch (numsub) {
363   case 1: subrec->ident = sub1; break;
364   case 2: subrec->ident = sub2; break;
365   default: {
366     char bufsub[10];
367     if (numsub > 9) sprintf (bufsub,"$%d",numsub) ;
368     else {  bufsub[0] = '$'; bufsub[1] = (char)(numsub + 48); bufsub[2] = '\0';  }
369     subrec->ident = rec_newtext(bufsub) ;
370     }
371   }
372   subrec->type  = curtype ;
373   curtype = txt_sublist;      /* type reserve par defaut */
374   /*subrec->nbarg = 0 ;*/ subrec->next = currec ;
375   subrec->first = NULL ; /*subrec->last = NULL ;*/
376     /* les arguments de la sous-liste vont suivre ;
377        elle meme est argument de son contenant, ce qui est pris en compte
378        a la fermeture de la parenthese */
379   currec = subrec ;           /* substitution finale */
380  }
381  numsub ++ ;   /* numero de la prochaine sous-liste (la principale est en 0) */
382 /*                          rec_check(0) ;    */
383 }
384
385
386 /*   Affichage du contenu d'un record   */
387 void rec_print(struct rec* unrec)
388 {
389  int numa = 0;  int numl = 0;  int argl = 0;
390  if (unrec == NULL) {  printf ("Non defini\n") ; return;  }
391  printf ("Ident : %s  Type : %s  Nb.Arg.s : %s\n",
392           unrec->ident,unrec->type, (unrec->first ? unrec->first->val : "")) ;
393  if (modeprint < 2) return ;
394  curarg = unrec->first ;
395  while (curarg != NULL) {
396    numa ++;
397    argl = (int)strlen(curarg->val) + 18;
398    numl += argl;
399    if (numl > 132) {  printf("\n");  numl = argl;  }
400    printf ("  - Arg.%d[%c%c] : %s",
401            numa,argtype1[curarg->type],argtype2[curarg->type],curarg->val);
402    curarg = curarg->next ;
403  }
404  if (argl > 0) printf("\n");
405  return ;
406 }
407
408 /*   GESTION DES SCOPES   */
409
410 /*  Ouverture de scope :
411   un scope est un record particulier (pas de type ni d'argument)
412   d'une part il est enregistre, d'autre part il faut gerer le record en cours
413   En effet, une entite step etait en cours d'enregistrement (ident deja connu),
414   mais son type et ses arguments seront fournis apres fermeture du scope ...
415   Il faut donc la mettre de cote (c'est currec), pour la restaurer ensuite
416
417   Mais ATTENTION, il y a l'EXPORT : au ENDSCOPE, peut etre attachee une liste
418   d'Idents : ce sont les idents internes au SCOPE mais declares visibles de
419   l'exterieur du SCOPE (en plus de l''entite sur laquelle il porte)
420 */
421
422 void scope_debut()
423 {
424 /*   ouverture du scope et sauvegarde de l'entite en cours   */
425  struct scope* newscope; struct rec* unscope;
426  newscope = (struct scope*) malloc (sizeof (struct scope)) ;
427  newscope->rec  = currec ;
428  newscope->prev = curscope ;
429  curscope = newscope ;
430
431 /*   enregistrement de ce scope comme un record   */
432  unscope = rec_newrec();
433  /*unscope = (struct rec*) malloc (sizeof (struct rec)) ;*/
434  unscope->ident = txt_scope ;
435  unscope->type  = txt_nil ;
436  unscope->first = NULL;
437  /*unscope->nbarg = 0 ;*/
438  rec_new(unscope) ;
439 }
440
441 /*   Fermeture de scope :
442    La fin de scope est, comme son debut, un enregistrement special.
443    Il faut donc l'enregistrer.
444    Il faut aussi restaurer l'entite concernee par le scope, afin de terminer
445    son enregistrement (manquent ses arguments)  */
446
447 void scope_fin()
448 { struct scope* oldscope ; struct rec* unscope;
449  if (curscope == NULL) return ;   /* cela dit, c'est anormal ... */
450
451 /*   enregistrement de cette fin de scope comme un record   */
452  unscope = rec_newrec();
453 /* unscope = (struct rec*) malloc (sizeof (struct rec)) ;*/
454  unscope->ident = txt_endscope ;
455  unscope->type  = txt_nil ;
456  unscope->first = NULL;
457  /*unscope->nbarg = 0 ;*/
458
459 /*  Si on doit prendre en compte une Export List ...  */
460  if (subarg[0] == '$') {
461    if (modeprint > 0) {
462      printf("Export List : (List in Record n0 %d) -- ",nbrec);
463      rec_print(lastrec);
464    }
465    currec = unscope;
466    typarg = rec_argSub;
467    rec_newarg();
468  }
469  rec_new(unscope) ;
470
471 /*   fermeture effective du scope   */
472  currec   = curscope->rec ;      /* restaurer l'entite en cours d'enreg. */
473  yarec    = 1;
474  oldscope = curscope ;
475  curscope = oldscope->prev ;     /*  restauration de l'etat precedent  */
476  free (oldscope) ;               /*  suppression "physique"  */
477 }
478
479
480 /*   CONCLUSION  :  retour des valeurs pour constituer la liste des records,
481                     sous forme de directory / tableau
482
483      La liberation de la memoire est faite par lir_file_fin, en une fois
484 */
485
486 void lir_file_nbr(int* nbh, int* nbr, int* nbp)
487 /*  initialise le traitement et retourne la taille du directory et du header */
488 {
489  currec = firstrec ;
490 /*                       rec_check(0) ;    */
491  *nbh = nbhead;  *nbr = nbrec;  *nbp = nbpar;
492 }
493
494 void lir_file_fin(int mode)
495 /*  fin du traitement : regroupe les liberations de memoire en une phase  */
496 /*  mode = 1 : rec+arg. 2 : carpage; 3 : 1+2  */
497 {
498   if (mode & 1) {
499     while(onerecpage != NULL) {
500       struct recpage* newpage; newpage = onerecpage->next;
501       free(onerecpage);
502       onerecpage = newpage;
503     }
504
505
506 /*    struct rec* oldrec;
507     oldrec = NULL;
508     currec = firstrec;
509     while (currec != NULL) {
510       oldrec = currec;
511       currec = currec->next;*/
512 /* liberation memoire pour type & ident : si scope-endscope rien a liberer
513    si sous-liste : type pas a liberer, ident partage aussi par l'argument sera
514    libere par lui ... donc ici aussi, rien a liberer. CQFD  */
515 /*      free (oldrec) ;
516     }*/
517     while (oneargpage != NULL) {
518       struct argpage* newpage; newpage = oneargpage->next;
519       free (oneargpage);
520       oneargpage = newpage;
521     }
522   }
523   if (mode & 2) {
524     while (onecarpage != NULL) {
525       struct carpage* newpage; newpage = onecarpage->next;
526       free (onecarpage);
527       onecarpage = newpage;
528     }
529   }
530 }
531
532 int lir_file_rec(char* *ident, char* *type, int *nbarg)
533 /*   retourne les parametres du record courant
534      retour de fonction ; 1 si ok, 0 si liste epuisee   */
535 {
536  if (currec == NULL) return (0) ;
537 /*                                   rec_check(2) ;    */
538  *ident = currec->ident ;
539  *type  = currec->type ;
540  *nbarg = (currec->first != NULL);
541  curarg = currec->first ;    /* prepare lecture arg.s */
542  return (1) ;
543 }
544
545 void lir_file_finrec()
546 /*  fait le menage et passe au record suivant
547     ne pas appeler apres l'indication de fin mais apres chaque record ok !   */
548 {
549  currec = currec->next ;
550 /*                                   rec_check(2) ;   */
551 }
552
553 int lir_file_arg(int* type, char* *val)
554 /*  lit l'argument courant (au debut le 1er), fait le menage, prepare suivant
555     retourne 1 si ok, 0 si c'est fini
556     attention, suppose que nbarg > 0 ... (bref, pas de protection)   */
557 {
558  if (curarg == NULL) return (0) ;
559  *type = curarg->type ;
560  *val  = curarg->val ;
561  curarg = curarg->next ;
562  return (1) ;
563 }
564
565
566 /*   Verification de l'integrite des donnees   */
567
568 /*   Affiche ce qui ne va pas, mais aussi accede a tout : ainsi, les adresses
569      verolees aparaissent au grand jour du dbx   */
570
571 void rec_check(int mode)
572 /* mode=1 pas de controle nbrec (en cours d'enregistrement) */
573 {
574   struct rec* lerec ; struct unarg* larg ; int nr,na ;
575   lerec = firstrec ;
576   if (mode == 2) lerec = currec ;
577   nr = 0 ;
578   while (lerec != NULL) {
579     nr ++ ;
580     if (lerec->ident == NULL) printf("Record %d : ident null\n",nr) ;
581     if (lerec->type  == NULL) printf("Record %d : type  null\n",nr) ;
582     /*if (mode < 2 && (lerec->nbarg < 0 || lerec->nbarg > 10) ) printf
583       ("N.B.: Record %d : nbarg pas entre 0 & 10, vaut %d\n",nr,lerec->nbarg);
584     */
585     na = 0 ;
586     larg = lerec->first ;
587     while (larg != NULL) {
588       na ++ ;
589       if (larg->type < 0 || larg->type > 9) printf
590         ("Record %d , Arg. %d : type incorrect : %d\n",nr,na,larg->type) ;
591       if (larg->val == NULL) printf("Record %d , Arg %d : val null\n",nr,na) ;
592       larg = larg->next ;
593     }
594     /*if (na != lerec->nbarg) printf
595       ("Record %d : arglist pourrie, nb note %d relu %d\n",nr,lerec->nbarg,na) ;*/
596     lerec = lerec->next ;
597   }
598   if (mode == 0 && nr != nbrec) printf
599     ("Liste des records pourrie, nb note %d relu %d\n",nbrec,nr) ;
600 }
601
602 void steperror (char *mess);
603 int  steplex (void);
604