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