1 /* This files solves the problems with instore macros.
2 * While parsing a special tree of type tnode is created
3 * and fold together with containing strings to one big
4 * beast (called a tinned tree, american: canned heat :-) ).
5 * Then we have two objects: a special tree and the tinned tree.
6 * There is a one to one releationship between them.
7 * The tinned tree may be expanded to a tree by ExpandTinnedTree().
8 * The tree is tinned by TinTree() which should only be called from
9 * the lexical analyser.
10 * We are protected against multithreading while normal parsing.
11 * Destroying the tree and tinning/expanding is done in
12 * multithreaded mode.
13 */
14
15 #include "rexx.h"
16 #include "rxiface.h"
17 #include <assert.h>
18
19 /* We begin with some odd tricks. We want a fast but memory
20 * saving routine to build the tree. We don't want to copy
21 * tree leaves more than one. Thus we pack them into buckets.
22 * This allows a very fast kind of searching. Keep in mind
23 * that we must create a pointerless list which is included
24 * in the tinned tree.
25 *
26 * This structure is called ttree, have a look at regina_t.h.
27 *
28 * DEFAULT_TTREE_ELEMS defines the normal number of elements in the ttree.
29 * The more elements the better is the performance in searching. The less
30 * elements the better is the memory waste overhead. We want some more space
31 * than MAX_INTERNAL_SIZE in memory.c. This leads to "normal" memory
32 * allocation and can be freed without problems if we parse a nested
33 * Rexx program. This is currently 2048. We allocate nearly 8K. This
34 * will give a reasonable performance and a slight overhead for
35 * external(!) functions, 4K in the middle.
36 */
37 #define DEFAULT_TTREE_ELEMS (8192 / sizeof(treenode))
38
39 /* Same as before but for offsrclines: */
40 #define DEFAULT_OTREE_ELEMS (4096 / sizeof(offsrcline))
41
42 static ttree *CurrentT = NULL;
43 static otree *CurrentO = NULL;
44 static nodeptr Reused = NULL;
45 static const char MagicHeader[] = MAGIC;
46
47 /* NewProg indicates the start of a new parsing sequence. We don't allow
48 * a nesting call. In case of an error is is the job of fetch_... to do the
49 * cleanup.
50 */
NewProg(void)51 void NewProg(void)
52 {
53 CurrentT = NULL; /* Trivial */
54 CurrentO = NULL; /* Trivial */
55 Reused = NULL; /* Can't reuse stuff of another parsing process */
56 }
57
58 /* EndProg is called at the end of the parsing process. Start is the
59 * starting element of the later interpreter tree.
60 * parser_data.root is assigned.
61 */
EndProg(nodeptr Start)62 void EndProg(nodeptr Start)
63 {
64 parser_data.root = Start; /* trivial, too */
65 CurrentT = NULL;
66 CurrentO = NULL;
67 Reused = NULL; /* Can't reuse stuff of another parsing process */
68 }
69
70 /* FreshNode returns a new ttree element. Call only within a NewProg/EndProg
71 * calling sequence.
72 * If you don't want the returned node WHILE PARSING because you want to do
73 * some tricks the the node at a later time, you are allowed to call
74 * RejectNode(). Rejected nodes are tried to be passed back to the used
75 * nodes.
76 */
FreshNode(void)77 nodeptr FreshNode(void)
78 {
79 nodeptr h;
80
81 if (Reused != NULL) /* This should be put back first */
82 {
83 h = Reused;
84 Reused = Reused->next;
85 h->next = NULL; /* Everything except nodeindex is 0 now */
86 return(h);
87 }
88
89 if (CurrentT && (CurrentT->num < CurrentT->max)) /* bucket not full */
90 {
91 memset(CurrentT->elems + CurrentT->num, 0, sizeof(treenode));
92 CurrentT->elems[CurrentT->num].nodeindex = CurrentT->sum + CurrentT->num;
93 return(CurrentT->elems + CurrentT->num++);
94 }
95
96 if (CurrentT == NULL) /* First call */
97 {
98 parser_data.nodes = (ttree *)Malloc_TSD(parser_data.TSD, sizeof(ttree));
99 CurrentT = parser_data.nodes;
100 CurrentT->sum = 0;
101 }
102 else /* current bucket is full */
103 {
104 CurrentT->next = (ttree *)Malloc_TSD(parser_data.TSD, sizeof(ttree));
105 CurrentT->next->sum = CurrentT->sum + CurrentT->num;
106 CurrentT = CurrentT->next;
107 }
108
109 /* always */
110 CurrentT->next = NULL;
111 CurrentT->max = DEFAULT_TTREE_ELEMS;
112 CurrentT->num = 1;
113 CurrentT->elems = (treenode *)Malloc_TSD(parser_data.TSD,
114 CurrentT->max * sizeof(treenode));
115
116 memset(CurrentT->elems, 0, sizeof(treenode));
117 CurrentT->elems[0].nodeindex = CurrentT->sum;
118 return(CurrentT->elems);
119 }
120
121 /* RejectNode gives the argument back to the pool of unused treenode entries
122 * which are managed and passed back by FreshNode().
123 * You should use the function ONLY IF YOU ARE WITHING THE PARSING PROCESS!
124 * It is not guaranteed that the memory of the entry is freed. It can only
125 * be reused.
126 * Note that the content of the entry is NOT FREED in any kind.
127 */
RejectNode(nodeptr NoLongerUsed)128 void RejectNode(nodeptr NoLongerUsed)
129 {
130 unsigned long idx;
131
132 assert(CurrentT != NULL);
133 /* CurrentT == NULL can't happen, since CurrentT is only set within the
134 * parsing process while at least one treenode has been returned.
135 */
136 if (CurrentT == NULL) /* In case of no assertion we return simply */
137 return;
138
139 /* Save exactly the nodeindex and destroy everything else */
140 idx = NoLongerUsed->nodeindex;
141 memset(NoLongerUsed, 0, sizeof(treenode)); /* Clean it up */
142 NoLongerUsed->nodeindex = idx;
143
144 NoLongerUsed->next = Reused;
145 Reused = NoLongerUsed;
146 }
147
148 /* FreshLine returns a new otree element. Call only within a NewProg/EndProg
149 * calling sequence.
150 */
FreshLine(void)151 offsrcline *FreshLine(void)
152 {
153 if (CurrentO && (CurrentO->num < CurrentO->max)) /* bucket not full */
154 {
155 memset(CurrentO->elems + CurrentO->num, 0, sizeof(offsrcline));
156 return(CurrentO->elems + CurrentO->num++);
157 }
158
159 if (CurrentO == NULL) /* First call */
160 {
161 parser_data.srclines = (otree *)Malloc_TSD(parser_data.TSD, sizeof(otree));
162 CurrentO = parser_data.srclines;
163 CurrentO->sum = 0;
164 }
165 else /* current bucket is full */
166 {
167 CurrentO->next = (otree *)Malloc_TSD(parser_data.TSD, sizeof(otree));
168 CurrentO->next->sum = CurrentO->sum + CurrentO->num;
169 CurrentO = CurrentO->next;
170 }
171
172 /* always */
173 CurrentO->next = NULL;
174 CurrentO->max = DEFAULT_OTREE_ELEMS;
175 CurrentO->num = 1;
176 CurrentO->elems = (offsrcline *)Malloc_TSD(parser_data.TSD,
177 CurrentO->max * sizeof(offsrcline));
178
179 memset(CurrentO->elems, 0, sizeof(offsrcline));
180 return(CurrentO->elems);
181 }
182
183 /*****************************************************************************
184 *****************************************************************************
185 * start of the multithreaded part *******************************************
186 *****************************************************************************
187 *****************************************************************************/
188
189
190 /* DestroyNode kills all allocated elements within a nodeptr
191 * without freeing the node itself.
192 */
DestroyNode(const tsd_t * TSD,nodeptr p)193 static void DestroyNode(const tsd_t *TSD, nodeptr p)
194 {
195 int type ;
196
197 if (p->name)
198 Free_stringTSD( p->name ) ;
199
200 if (p->now)
201 FreeTSD( p->now ) ;
202
203 type = p->type ;
204 if (type == X_CON_SYMBOL || type == X_STRING)
205 {
206 if (p->u.number)
207 {
208 FreeTSD( p->u.number->num ) ;
209 FreeTSD( p->u.number ) ;
210 }
211 }
212 if (type==X_SIM_SYMBOL || type==X_STEM_SYMBOL || type==X_HEAD_SYMBOL ||
213 type==X_CTAIL_SYMBOL || type==X_VTAIL_SYMBOL )
214 {
215 if (p->u.varbx)
216 {
217 detach( TSD, p->u.varbx ) ;
218 }
219 }
220
221 if (type == X_CEXPRLIST)
222 {
223 if (p->u.strng)
224 Free_stringTSD( p->u.strng ) ;
225 }
226 }
227
228 /* DestroyInternalParsingTree frees all allocated memory used by a parsing
229 * tree. The structure itself is not freed.
230 */
DestroyInternalParsingTree(const tsd_t * TSD,internal_parser_type * ipt)231 void DestroyInternalParsingTree(const tsd_t *TSD, internal_parser_type *ipt)
232 {
233 ttree *tr, *th;
234 otree *otr, *oh;
235 lineboxptr lr, lh;
236 labelboxptr ar, ah;
237 unsigned long i;
238
239 if (!ipt)
240 return;
241
242 /* Cleanup all the nodes */
243 if (ipt->nodes != NULL)
244 {
245 tr = ipt->nodes;
246
247 while (tr)
248 {
249 for (i = 0; i < tr->num; i++)
250 DestroyNode(TSD, tr->elems + i);
251 th = tr->next;
252 FreeTSD(tr->elems);
253 FreeTSD(tr);
254 tr = th;
255 }
256
257 ipt->nodes = NULL;
258 }
259 ipt->root = NULL; /* not really needed */
260
261 /* Cleanup all the lineboxes */
262 if (ipt->first_source_line != NULL)
263 {
264 lr = ipt->first_source_line;
265
266 while (lr)
267 {
268 lh = lr->next;
269 Free_stringTSD(lr->line);
270 FreeTSD(lr);
271 lr = lh;
272 }
273
274 ipt->first_source_line = ipt->last_source_line = NULL;
275 }
276
277 /* Cleanup all the labelboxes */
278 if (ipt->first_label != NULL)
279 {
280 ar = ipt->first_label;
281
282 while (ar)
283 {
284 ah = ar->next;
285 FreeTSD(ar);
286 ar = ah;
287 }
288
289 ipt->first_label = ipt->last_label = NULL;
290 }
291
292 if (ipt->sort_labels != NULL)
293 {
294 FreeTSD(ipt->sort_labels);
295
296 ipt->sort_labels = NULL;
297 }
298
299 /* Cleanup the incore sourceline informations */
300 /* Cleanup all the nodes */
301 if (ipt->srclines != NULL)
302 {
303 otr = ipt->srclines;
304
305 while (otr)
306 {
307 oh = otr->next;
308 FreeTSD(otr->elems);
309 FreeTSD(otr);
310 otr = oh;
311 }
312
313 ipt->srclines = NULL;
314 }
315 if (ipt->kill)
316 Free_stringTSD(ipt->kill);
317 ipt->kill = NULL;
318 }
319
320 /* ExpandTinnedTree expands the external tree from a former parsing operation
321 * to a fully usable tree. All allocations and relacations are done to fake
322 * a normal parsing operation.
323 * The external tree won't be used any longer after this operation but the
324 * external tree must have been checked before this operation.
325 * The freshly allocated tree is returned.
326 */
ExpandTinnedTree(const tsd_t * TSD,const external_parser_type * ept,unsigned long size,const char * incore_source,unsigned long incore_source_length)327 internal_parser_type ExpandTinnedTree(const tsd_t *TSD,
328 const external_parser_type *ept,
329 unsigned long size,
330 const char *incore_source,
331 unsigned long incore_source_length)
332 {
333 internal_parser_type ipt;
334 unsigned long i,j;
335 const extstring *es;
336 const offsrcline *lastsrcline;
337 nodeptr thisptr;
338
339 memset(&ipt, 0, sizeof(ipt));
340
341 /* We build the sourcelines first *****************************************/
342 if (incore_source_length == 0)
343 incore_source = NULL;
344 if (ept->NumberOfSourceLines == 0)
345 incore_source = NULL;
346 if (incore_source) /* Its worth to check exactly */
347 {
348 lastsrcline = (const offsrcline *) ((char *) ept + ept->source);
349 lastsrcline += ept->NumberOfSourceLines - 1;
350 j = lastsrcline->length + lastsrcline->offset;
351 /* j shall be very close to the end of the source string. It may
352 * follow a linefeed (or carriage return/linefeed) and probably a
353 * ^Z for CP/M descendents which includes Microsoft products. It's
354 * fais to assume the following check:
355 */
356 if ((j > incore_source_length) ||
357 (j + 3 < incore_source_length))
358 incore_source = NULL;
359 }
360 if (incore_source) /* We are sure enough to use the source string */
361 {
362 ipt.incore_source = incore_source;
363 ipt.srclines = (otree *)MallocTSD(sizeof(otree));
364 ipt.srclines->sum = 0;
365 ipt.srclines->next = NULL;
366 ipt.srclines->max = ept->NumberOfSourceLines;
367 ipt.srclines->num = ipt.srclines->max;
368 ipt.srclines->elems = (offsrcline *)MallocTSD(ipt.srclines->num * sizeof(offsrcline));
369 memcpy(ipt.srclines->elems,
370 (char *) ept + ept->source,
371 ipt.srclines->num * sizeof(offsrcline));
372 }
373 /**************************************************************************/
374
375 ipt.tline = -1; /* unused */
376 ipt.tstart = -1; /* unused */
377 ipt.result = 0; /* unused */
378 ipt.first_label = ipt.last_label = NULL; /* initialize it for newlabel() */
379 ipt.numlabels = 0; /* initialize it for newlabel() */
380 ipt.sort_labels = NULL; /* initialize it for newlabel() */
381
382 ipt.nodes = (ttree *)MallocTSD(sizeof(ttree));
383 ipt.nodes->sum = 0;
384 ipt.nodes->next = NULL;
385 ipt.nodes->max = ept->NumberOfTreeElements;
386 ipt.nodes->num = ipt.nodes->max;
387 ipt.nodes->elems = (treenode *)MallocTSD(ipt.nodes->num * sizeof(treenode));
388
389 memcpy(ipt.nodes->elems,
390 (char *) ept + ept->tree,
391 ipt.nodes->num * sizeof(treenode));
392 ipt.root = ipt.nodes->elems + ept->TreeStart;
393
394 /* Everything is ready for a relocation step. Don't forget to *************
395 * create the labelboxes as necessary.
396 */
397 for (i = 0;i < ept->NumberOfTreeElements;i++)
398 {
399 thisptr = ipt.nodes->elems + i;
400 if (thisptr->name)
401 {
402 es = (extstring *) ((char *) ept + (unsigned long) thisptr->name);
403 thisptr->name = Str_makeTSD(es->length);
404 thisptr->name->len = es->length;
405 memcpy(thisptr->name->value,
406 es + 1 /* position of string content */,
407 es->length);
408 }
409
410 /*
411 * Do things the parsing step would have do. Simple values in thisptr->u
412 * are copied already.
413 */
414
415 /*
416 * See also several places in this file and in debug.c where this
417 * switch list must be changed. Seek for X_CEXPRLIST.
418 */
419 switch ( thisptr->type )
420 {
421 case X_CEXPRLIST:
422 if ( thisptr->u.strng )
423 {
424 es = (extstring *) ((char *) ept + (unsigned long) thisptr->u.strng);
425 thisptr->u.strng = Str_makeTSD( es->length );
426 thisptr->u.strng->len = es->length;
427 memcpy( thisptr->u.strng->value,
428 es + 1 /* position of string content */,
429 es->length);
430 }
431 break;
432
433 case X_LABEL:
434 newlabel(TSD, &ipt, thisptr);
435 break;
436
437 default:
438 break;
439 }
440
441 if (thisptr->next == (nodeptr) (unsigned long) -1)
442 thisptr->next = NULL;
443 else
444 thisptr->next = ipt.nodes->elems + (unsigned long) thisptr->next;
445 for (j = 0;j < sizeof(thisptr->p) / sizeof(thisptr->p[0]);j++)
446 {
447 if (thisptr->p[j] == (nodeptr) (unsigned long) -1)
448 thisptr->p[j] = NULL;
449 else
450 thisptr->p[j] = ipt.nodes->elems + (unsigned long) thisptr->p[j];
451 }
452 }
453 return(ipt);
454 }
455
456 /* We must take care of the alignment of structure. We may get a SIGBUS in
457 * the following if we don't do it. We assume that an alignment for an
458 * unsigned long is sufficient for all types including structures. We also
459 * assume a power of two for an unsigned's size.
460 */
461 #define USIZ sizeof(unsigned long)
462 #define USIZ_1 (USIZ-1)
463 /* Wastes one byte in average but is much faster */
464 #define StringSize(s) (((sizeof(extstring)+s->len)|USIZ_1)+1)
465
ComputeExternalSize(const internal_parser_type * ipt,unsigned long * SourceLines,unsigned long * Nodes)466 static unsigned long ComputeExternalSize(const internal_parser_type *ipt,
467 unsigned long *SourceLines,
468 unsigned long *Nodes)
469 {
470 otree *otp;
471 ttree *ttp;
472 nodeptr np;
473 unsigned long size = sizeof(external_parser_type);
474 unsigned long i, elems, bufchars;
475
476 /* sourceline table */
477 elems = 0;
478 if ((otp = ipt->srclines) == NULL)
479 {
480 if (ipt->last_source_line)
481 {
482 elems = ipt->last_source_line->lineno;
483 }
484 }
485 else
486 {
487 while (otp->next)
488 otp = otp->next;
489 elems = otp->sum + otp->num;
490 }
491 *SourceLines = elems;
492 size += elems * sizeof(offsrcline); /* the table */
493
494 /* nodetable */
495 elems = bufchars = 0;
496 ttp = ipt->nodes;
497 while (ttp)
498 {
499 for (i = 0;i < ttp->num;i++)
500 {
501 elems++;
502 np = ttp->elems + i;
503 if (np->name)
504 bufchars += StringSize(np->name);
505
506 /*
507 * Add all sizes of strings that have been generated at the parsing
508 * step.
509 */
510
511 /*
512 * See also several places in this file and in debug.c where this
513 * switch list must be changed. Seek for X_CEXPRLIST.
514 */
515 switch ( np->type )
516 {
517 case X_CEXPRLIST:
518 if ( np->u.strng )
519 bufchars += StringSize( np->u.strng );
520 break;
521
522 default:
523 break;
524 }
525 }
526 ttp = ttp->next;
527 }
528 *Nodes = elems;
529 size += elems * sizeof(treenode);
530 size += bufchars;
531
532 size += sizeof(((external_parser_type *)0)->Magic);
533 return(size);
534 }
535
536 /* FillStrings copies all offsrclines from the otree to base+start
537 * consecutively.
538 * The index just beyond the last copied byte is returned.
539 */
FillStrings(char * base,unsigned long start,const otree * otp)540 static unsigned long FillStrings(char *base, unsigned long start,
541 const otree *otp)
542 {
543 if (otp != NULL)
544 {
545 while (otp != NULL)
546 {
547 memcpy(base + start, otp->elems, otp->num * sizeof(offsrcline));
548 start += otp->num * sizeof(offsrcline);
549 otp = otp->next;
550 }
551 }
552 return(start);
553 }
554
555 /* FillTree copies all treenodes of the ttree to base+buf in a relocatable
556 * manner. Look at ExpandTinnedTree() or regina_t.h for a description.
557 * Each treenode is copied to the table and the containing strings are copied
558 * as extstrings to base+start which is incremented.
559 * The table must be large enough.
560 * The index just beyond the last copied character is returned.
561 */
FillTree(treenode * table,char * base,unsigned long start,const ttree * ttp)562 static unsigned long FillTree(treenode *table, char *base, unsigned long start,
563 const ttree *ttp)
564 {
565 cnodeptr np;
566 unsigned long i,j;
567 extstring *e;
568
569 while (ttp)
570 {
571 for (i = 0;i < ttp->num;i++)
572 {
573 np = (cnodeptr) (ttp->elems + i);
574 *table = *np; /* Full copy includes unnecessary stuff but is fast */
575
576 if (np->name)
577 {
578 table->name = (streng *) start;
579 e = (extstring *) (base + start);
580 e->length = np->name->len;
581 memcpy(e + 1 /* just beyond the head */, np->name->value, e->length);
582 start += StringSize(np->name);
583 }
584
585 /*
586 * Remove all "flags" from the target and copy only approved values
587 * the parser computes already.
588 */
589 memset( &table->u, 0, sizeof( table->u ) );
590
591 /*
592 * See also several places in this file and in debug.c where this
593 * switch list must be changed. Seek for X_CEXPRLIST.
594 */
595 switch ( np->type )
596 {
597 case X_EQUAL:
598 case X_DIFF:
599 case X_GT:
600 case X_GTE:
601 case X_LT:
602 case X_LTE:
603 table->u.flags = np->u.flags;
604 break;
605
606 case X_PARSE:
607 /*
608 * fixes 972850
609 */
610 table->u.parseflags = np->u.parseflags;
611 break;
612
613 case X_ADDR_V:
614 table->u.nonansi = np->u.nonansi;
615 break;
616
617 case X_CEXPRLIST:
618 if ( np->u.strng )
619 {
620 table->u.strng = (streng *) start;
621 e = (extstring *) (base + start);
622 e->length = np->u.strng->len;
623 memcpy(e + 1, np->u.strng->value, e->length);
624 start += StringSize(np->u.strng);
625 }
626 break;
627
628 case X_LABEL:
629 table->u.trace_only = np->u.trace_only;
630 break;
631
632 case X_ADDR_WITH:
633 if ( !np->p[0] && !np->p[1] && !np->p[2] )
634 table->u.of = np->u.of;
635 break;
636
637 default:
638 break;
639 }
640
641 if (table->next == NULL)
642 table->next = (nodeptr) (unsigned long) -1;
643 else
644 table->next = (nodeptr) np->next->nodeindex;
645 for (j = 0;j < sizeof(np->p) / sizeof(np->p[0]);j++)
646 {
647 if (table->p[j] == NULL)
648 table->p[j] = (nodeptr) (unsigned long) -1;
649 else
650 table->p[j] = (nodeptr) np->p[j]->nodeindex;
651 }
652 table++;
653 }
654 ttp = ttp->next;
655 }
656
657 return(start);
658 }
659
660 /* TinTree "tins" a tree into an external structure. The complete structure
661 * is allocated by one call to IfcAllocateMemory. The returned value shall
662 * be used as an instore macro for RexxStart.
663 * *length is set to the allocated size of the memory block on return.
664 * ExpandedTinnedTree can expand the returned value and IsValidTin checks it.
665 */
TinTree(const tsd_t * TSD,const internal_parser_type * ipt,unsigned long * length)666 external_parser_type *TinTree(const tsd_t *TSD,
667 const internal_parser_type *ipt,
668 unsigned long *length)
669 {
670 external_parser_type *retval;
671 unsigned long srclines, nodecount, len;
672
673 *length = ComputeExternalSize(ipt, &srclines, &nodecount);
674
675 retval = (external_parser_type *)IfcAllocateMemory(*length);
676 if (retval == NULL)
677 return(NULL);
678 memset(retval, 0, sizeof(external_parser_type));
679
680 /* Build the envelope */
681 len = sizeof(MagicHeader); /* includes a terminating 0 */
682 if (len > sizeof(retval->Magic))
683 len = sizeof(retval->Magic);
684 memcpy(retval->Magic, MagicHeader, len);
685 len = sizeof(PARSE_VERSION_STRING);
686 if (len > sizeof(retval->ReginaVersion))
687 len = sizeof(retval->ReginaVersion);
688 memcpy(retval->ReginaVersion, PARSE_VERSION_STRING, len);
689
690 retval->arch_detector.s.one = 1;
691 retval->arch_detector.s.two = 2;
692 retval->arch_detector.s.ptr3 = (void *)3;
693 retval->arch_detector.s.ptr4 = (void *)4;
694 retval->OverallSize = (unsigned long) *length;
695 retval->NumberOfSourceLines = srclines;
696 retval->version = INSTORE_VERSION;
697 retval->NumberOfTreeElements = nodecount;
698
699 retval->source = sizeof(external_parser_type);
700 len = FillStrings((char *) retval,
701 sizeof(external_parser_type),
702 ipt->srclines);
703
704 retval->tree = len;
705 retval->TreeStart = ipt->root->nodeindex;
706 len = FillTree((treenode *) ((char *) retval + len),
707 (char *) retval,
708 len + nodecount*sizeof(treenode),
709 ipt->nodes);
710
711 memcpy((char *) retval + len, retval->Magic, sizeof(retval->Magic));
712
713 assert((unsigned long) len + sizeof(retval->Magic) == *length);
714
715 /* DEBUGGING: return NULL if you don't want tinned trees */
716 return(retval);
717 }
718
719 /* IsValidTin returns 1 if the structure ept if of length eptlen and seems
720 * to contain a valid parsing tree. 0 is returned if this is not the case.
721 */
IsValidTin(const external_parser_type * ept,unsigned long eptlen)722 int IsValidTin(const external_parser_type *ept, unsigned long eptlen)
723 {
724 char Magic[sizeof(((external_parser_type *)0)->Magic)];
725 unsigned long len;
726
727 /* Some paranoia tests first: */
728 if ((ept == NULL) || (eptlen < sizeof(external_parser_type)))
729 return(0);
730
731 /* Be sure to fill Magic as described */
732 memset(Magic, 0, sizeof(Magic));
733 len = sizeof(MagicHeader); /* includes a terminating 0 */
734 if (len > sizeof(ept->Magic))
735 len = sizeof(ept->Magic);
736 memcpy(Magic, MagicHeader, len);
737
738 if (memcmp(Magic, ept->Magic, sizeof(Magic)) != 0)
739 return(0);
740
741 if ((ept->arch_detector.s.one != 1) ||
742 (ept->arch_detector.s.two != 2) ||
743 (ept->arch_detector.s.ptr3 != (void *)3) ||
744 (ept->arch_detector.s.ptr4 != (void *)4))
745 return(0);
746
747 if (ept->OverallSize != eptlen)
748 return(0);
749
750 if (ept->version != INSTORE_VERSION)
751 return(0);
752
753 if (memcmp(Magic,
754 (char *) ept + eptlen - sizeof(Magic),
755 sizeof(Magic)) != 0)
756 return(0);
757
758 return(1);
759 }
760