disable the unrecognized nls flag
[AROS-Contrib.git] / regina / gci / gci_prepare.c
bloba784b0361f2f9b68c2cb70f0338d9bfa9afeb1b5
1 /*
2 * Generic Call Interface for Rexx
3 * Copyright © 2003-2004, Florian Große-Coosmann
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * ----------------------------------------------------------------------------
21 * This file prepares an input tree for later use.
24 #include "gci.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
31 * While iterating over the tree we need a structure of needed informations
32 * we can pass as one single pointer to the tree enumerator.
34 typedef struct {
35 void *hidden;
36 GCI_treeinfo *ti; /* current tree */
37 int parent; /* current parent, used in the first pass */
38 unsigned runner; /* current memory location, used while computing
39 * positions.
41 } WalkerInfo;
44 * We don't know where the items will be placed in advance. But we can compute
45 * it afterwards. The main information we need is the amount of spare space
46 * which depends on the alignment.
47 * We currently use a fixed alignment of GCI_ALIGNMENT but it can depend on
48 * individual alignment factors.
50 #define SPARE(pos,align) (((pos)%(align)) ? ((align) - (pos)%(align)) : 0)
53 * resizeNodes resizes the w->ti->nodes array to the new_nodemax maximum.
55 * Return values:
56 * GCI_OK: Everything's fine.
57 * GCI_InternalError: Attempt to shorten the array so far that elements get
58 * lost.
59 * GCI_NoMemory: Not enough free memory. Note that the old w->ti->nodes
60 * persists.
62 static GCI_result resizeNodes( WalkerInfo *w,
63 int new_nodemax )
65 void *buf;
66 GCI_treeinfo *ti = w->ti;
68 if ( ti->max == new_nodemax )
69 return GCI_OK;
70 if ( ti->used > new_nodemax )
71 return GCI_InternalError;
73 buf = GCI_malloc( w->hidden, sizeof( GCI_nodeinfo ) * new_nodemax );
74 if ( buf == NULL )
75 return GCI_NoMemory;
77 if ( ti->nodes != NULL )
79 memcpy( buf, ti->nodes, sizeof( GCI_nodeinfo ) * ti->used );
80 GCI_free( w->hidden, ti->nodes );
82 ti->max = new_nodemax;
83 ti->nodes = (GCI_nodeinfo *) buf;
85 return GCI_OK;
89 * walker is a callback-routine for the tree enumerator GCI_parsetree.
90 * Look there for the arguments.
92 * Its purpose is the building of a tree structure in ((WalkerInfo *)arg)->ti,
93 * which may grow during the iteration.
94 * We compute the direct and indirect sizes of each element. At the end of
95 * the last iteration step we have the memory count we need to allocate for a
96 * call to the function.
98 * Return values:
99 * GCI_OK: Everything's fine.
100 * GCI_InternalError: Attempt to shorten the array so far that elements get
101 * lost or illegal values used internally.
102 * GCI_NoMemory: Not enough free memory. Note that the old w->ti->nodes
103 * persists.
105 static GCI_result walker( int depth,
106 int itemnumber,
107 void *arg,
108 const GCI_parseinfo *info )
110 GCI_result rc;
111 WalkerInfo *w = (WalkerInfo *) arg;
112 GCI_treeinfo *ti = w->ti;
113 GCI_nodeinfo *n, *h;
114 int idx, prev, next;
116 if ( itemnumber == -1 )
119 * We either have a container or an array.
120 * In case of an array: multiply the sizes by the array count
121 * In case of a container: Reverse the siblings
122 * In both cases we have to adjust other sizes and counts and we have
123 * to reinstall the parent's parent.
125 assert( w->parent >= 0 );
126 if ( w->parent < 0 )
127 return GCI_InternalError;
129 n = ti->nodes + w->parent;
130 w->parent = n->parent;
132 if ( info->type == GCI_container )
135 * reverse the siblings. We do
136 * n n n--+ n-----+
137 * | | | |
138 * v -> v -> v -> v ->...
139 * a->b->c->d->-1 -1<-a|>b->c->d a<-b|>c->d a<-b<-c|>d
140 * p n p n p n
141 * r e r e r e
142 * e x e x e x
143 * v t v t v t
147 * ...-> v
148 * a<-b<-c<-d|>-1
149 * p n
150 * r e
151 * e x
152 * v t
154 assert( n->child != -1 );
156 prev = -1;
157 h = ti->nodes + n->child;
158 next = h->sibling;
159 h->sibling = prev;
161 n->direct_size += h->direct_size;
162 n->indirect_size += h->indirect_size;
164 while ( next != -1 )
166 prev = n->child;
167 n->child = next;
168 h = ti->nodes + next;
169 next = h->sibling;
170 h->sibling = prev;
172 n->direct_size += h->direct_size;
173 n->indirect_size += h->indirect_size;
176 else
178 assert( info->type == GCI_array );
180 h = ti->nodes + n->child;
181 n->direct_size = info->size * h->direct_size;
182 n->indirect_size = info->size * h->indirect_size;
185 if ( info->indirect )
187 n->indirect_size += n->direct_size;
188 n->direct_size = sizeof( void * );
190 return GCI_OK;
194 * Normal call (itemnumber >= 0)
195 * Create an entry and set the values for base types. Composite types'
196 * sizes must wait until the finalization of the subelements (see above).
198 if ( ti->used + 1 >= ti->max )
200 if ( ( rc = resizeNodes( w, ti->max + 64 ) ) != GCI_OK )
201 return rc;
203 idx = ti->used++;
204 n = ti->nodes + idx;
206 n->type = *info;
207 n->parent = w->parent;
208 n->child = -1;
209 n->sibling = -1;
210 n->direct_size = 0;
211 n->indirect_size = 0;
212 n->direct_pos = 0;
213 n->indirect_pos = 0;
214 if ( n->parent == -1 )
216 assert( depth == 0 );
218 else
221 * We concatenate the sibling in reversed order; it must be rearranged
222 * at the end of the current depth.
224 n->sibling = ti->nodes[n->parent].child;
225 ti->nodes[n->parent].child = idx;
228 switch ( info->type )
230 case GCI_integer:
231 case GCI_unsigned:
232 case GCI_float:
233 case GCI_char:
234 n->direct_size = info->size;
235 break;
237 case GCI_string:
238 n->direct_size = info->size + 1;
239 break;
241 case GCI_raw:
242 n->direct_size = info->size;
243 break;
245 case GCI_container:
246 case GCI_array:
248 * computed later
250 w->parent = idx;
251 return GCI_OK;
253 default:
254 return GCI_InternalError;
257 if ( info->indirect )
259 n->indirect_size = n->direct_size;
260 n->direct_size = sizeof( void * );
262 return GCI_OK;
266 * computePosition recursively iterates over the tree w->ti computing the
267 * relative positions of each element within an imaginary buffer.
269 * The iteration starts at the element start. direct is a flag indicating
270 * whether or not the direct size shall be computed. This includes all child
271 * sizes up to their end or a branch to an INDIRECT element, in which case
272 * the pointer itself is counted and the iteration is stopped.
273 * In case of !direct the indirect size of an element is added. This is 1 for
274 * an INDIRECT INTEGER8 for example. In case of composite type like array
275 * and container we start a new cycle of direct/!direct computation of the
276 * sub-elements.
278 * This technique shall ensure the "width-first" logic of memory allocation
279 * needed for a buffer. Since we double-buffer all values, we have to add
280 * every value to an indirect after the direct buffer.
282 * Another thing this routine has to do is the computation of alignment.
283 * This will increase the size of the used buffer.
285 * One(!) example is
286 * CONTAINER
287 * INTEGER8
288 * INDIRECT CONTAINER
289 * CHAR
290 * INDIRECT STRING255
291 * INTEGER32
292 * INTEGER16
293 * which is equivalent to (assuming a pointer size of 4)
294 * CONTAINER
295 * INTEGER8 1 byte, pos 0
296 * INDIRECTION 4 byte, pos 1 ---+
297 * INTEGER16 2 byte, pos 5 |
298 * pos 7 |
299 * +------------------------------+
300 * | .
301 * v . ( spare space to the next boundary, )
302 * CONTAINER . ( e.g. with an alignment of 16 )
303 * CHAR 1 byte, pos 16
304 * INDIRECTION 4 byte, pos 17 --+
305 * INTEGER32 4 byte, pos 21 |
306 * 25 |
307 * +------------------------------+
308 * | . ( spare space to the next boundary, )
309 * v . ( e.g. with an alignment of 16 )
310 * STRING255 256 byte, pos 32
312 * whith makes a sum of 288 byte used
314 * The used size is added to w->runner.
316 static void computePosition( WalkerInfo *w,
317 int start,
318 int direct )
320 GCI_nodeinfo *n;
321 GCI_parseinfo *info;
322 GCI_treeinfo *ti = w->ti;
323 int child;
324 unsigned h, s;
326 n = ti->nodes + start;
327 info = &n->type;
329 if ( direct )
332 * The simpler case.
334 n->direct_pos = w->runner;
336 if ( info->indirect )
338 w->runner += sizeof( void * );
339 return;
342 switch ( info->type )
345 * In case of container or array we have to add direct sizes of the
346 * children, too. They will not be aligned, that's user's stuff.
348 case GCI_array:
349 h = w->runner;
350 computePosition( w, n->child, 1 );
351 assert( n->direct_size / info->size == w->runner - h );
352 w->runner += ( info->size - 1 ) * ( w->runner - h );
353 break;
355 case GCI_container:
356 h = w->runner;
357 for ( child = n->child;
358 child != -1;
359 child = ti->nodes[child].sibling )
360 computePosition( w, child, 1 );
361 assert( n->direct_size == w->runner - h );
362 break;
364 default:
365 w->runner += n->direct_size;
366 break;
368 return;
372 * Now handle the indirect case. We either may have a direct or an indirect
373 * node.
375 if ( !info->indirect )
378 * In case of direct nodes, counted for the indirect case, we can have
379 * containers or array only. These type may be direct but may have
380 * indirected elements which have to be counted, too.
381 * You can think of this case as a forwarder. Nothing really special
382 * happens here, despite the fact we have to realign indirect values.
384 switch ( info->type )
386 case GCI_array:
387 s = SPARE( w->runner, GCI_ALIGNMENT );
388 w->runner += s;
389 h = w->runner;
391 computePosition( w, n->child, 0 );
393 if ( h == w->runner )
394 w->runner -= s;
395 else
397 s = SPARE( w->runner, GCI_ALIGNMENT );
398 n->indirect_size = info->size * ( w->runner - h + s );
399 w->runner += ( info->size - 1 ) * ( w->runner - h + s );
400 w->runner += s;
402 break;
404 case GCI_container:
405 s = SPARE( w->runner, GCI_ALIGNMENT );
406 w->runner += s;
407 h = w->runner;
409 for ( child = n->child;
410 child != -1;
411 child = ti->nodes[child].sibling )
412 computePosition( w, child, 0 );
414 if ( h == w->runner )
415 w->runner -= s;
416 else
418 s = SPARE( w->runner, GCI_ALIGNMENT );
419 n->indirect_size = w->runner - h + s;
420 w->runner += s;
422 break;
424 default:
425 assert( ( info->type != GCI_array ) &&
426 ( info->type != GCI_container ) );
427 break;
429 return;
433 * The indirect case where the node is also indirect. Simple types are
434 * trivial, but the array or container case is not.
436 switch ( info->type )
438 case GCI_array:
439 case GCI_container:
440 w->runner += SPARE( w->runner, GCI_ALIGNMENT );
441 n->indirect_pos = w->runner;
442 break;
444 default:
445 h = SPARE( w->runner, GCI_ALIGNMENT );
446 n->indirect_pos = w->runner + h;
447 w->runner += n->indirect_size + h;
448 h = SPARE( w->runner, GCI_ALIGNMENT );
449 n->indirect_size += h;
450 w->runner += h;
451 return;
455 * Treating an array as a container, we only have to support the container
456 * here for indirect cases. But a container may have both direct and
457 * indirect fields. We always have to recompute both types separately to
458 * let adjacent fields keep connected (width-first order).
460 * We do an alignment after the direct computation. If we have an indirect
461 * case we always have a direct case. And if we don't have an indirect case
462 * we have to align one level higher, therefore we may do an alignment.
464 h = w->runner;
465 for ( child = n->child; child != -1; child = ti->nodes[child].sibling )
466 computePosition( w, child, 1 );
467 if ( info->type == GCI_array )
468 w->runner += (info->size - 1) * ( w->runner - h );
470 s = SPARE( w->runner, GCI_ALIGNMENT );
471 w->runner += s;
472 n->indirect_size = w->runner - h;
474 h = w->runner;
475 for ( child = n->child; child != -1; child = ti->nodes[child].sibling )
476 computePosition( w, child, 0 );
477 if ( h != w->runner )
480 * Let the next argument be aligned properly and note it in the indirect
481 * size.
483 s = SPARE( w->runner, GCI_ALIGNMENT );
484 w->runner += s;
485 if ( info->type == GCI_array )
487 n->indirect_size += info->size * ( w->runner - h );
488 w->runner += ( info->size - 1 ) * ( w->runner - h );
490 else
492 n->indirect_size += w->runner - h;
498 * computePositions recursively iterates over the tree w->ti computing the
499 * relative positions of each element within an imaginary buffer.
501 * See computePosition above for a description.
503 static void computePositions( WalkerInfo *w,
504 int start )
506 unsigned s, hrun;
508 s = SPARE( w->runner, GCI_ALIGNMENT );
509 w->runner += s;
510 hrun = w->runner;
511 computePosition( w, start, 1 );
512 if ( hrun == w->runner )
513 w->runner -= s;
515 s = SPARE( w->runner, GCI_ALIGNMENT );
516 w->runner += s;
517 hrun = w->runner;
518 computePosition( w, start, 0 );
519 if ( hrun == w->runner )
520 w->runner -= s;
521 else
523 w->ti->nodes[start].indirect_size = w->runner - hrun;
525 * Let the next argument be aligned properly and note it in the indirect
526 * size.
528 s = SPARE( w->runner, GCI_ALIGNMENT );
529 w->runner += s;
530 w->ti->nodes[start].indirect_size += s;
535 * dumpNode dumps a node and all its childs and siblings to stdout.
536 * start is the starting node withing the tree, indent is the current indention
537 * level.
539 static void dumpNode( const GCI_treeinfo *ti,
540 int start,
541 int indent )
543 char buf[80], *p;
544 GCI_nodeinfo *n;
545 GCI_parseinfo *info;
547 do {
548 n = ti->nodes + start;
549 info = &n->type;
550 strcpy( buf, (info->indirect) ? "INDIRECT " : "" );
551 p = buf + strlen(buf);
552 switch ( info->type )
554 case GCI_integer: sprintf(p, "INTEGER%u", info->size*8 ); break;
555 case GCI_unsigned: sprintf(p, "UNSIGNED%u", info->size*8 ); break;
556 case GCI_float: sprintf(p, "FLOAT%u", info->size*8 ); break;
557 case GCI_char: sprintf(p, "CHAR%u", info->size*8 ); break;
558 case GCI_string: sprintf(p, "STRING%u", info->size ); break;
559 case GCI_raw: sprintf(p, "RAW%u", info->size ); break;
560 case GCI_container: sprintf(p, "CONTAINER" ); break;
561 case GCI_array: sprintf(p, "ARRAY[%u]", info->size ); break;
562 default: sprintf(p, "???[%u]", info->size ); break;
564 printf( "%3d %3d %3d %3d, %5u %5u %5u %5u ",
565 start, n->parent, n->child, n->sibling,
566 n->direct_size, n->indirect_size,
567 n->direct_pos, n->indirect_pos );
568 printf( "%*s%s%s\n",
569 indent * 3, "",
570 buf,
571 ( n->type.generated ) ? " (generated)" : "" );
572 start = n->sibling;
574 if ( n->child != -1 )
575 dumpNode( ti, n->child, indent + 1 );
576 } while ( start != -1 );
579 #ifdef DEBUG
581 * dump dumps every argument and the return value including every child to
582 * stdout if the environment variable "_GCI_DUMP" is set.
584 static void dump( const GCI_treeinfo *ti )
586 int i;
588 if ( getenv("_GCI_DUMP") == NULL )
589 return;
590 printf( "TreeInfo:\n"
591 "%d (%d) nodes used\n"
592 "%u bytes used for the buffer\n",
593 ti->used, ti->max, ti->size );
594 printf( "idx par chl sib, dsi isi dpo ipo\n");
596 for ( i = 0; i < (int) elements( ti->args ); i++ )
598 if ( ti->args[i] == -1 )
599 break;
600 printf( "\n"
601 "Argument %d starts on index %d:\n",
602 i + 1, ti->args[i] );
603 dumpNode( ti, ti->args[i], 0 );
606 if ( ti->retval != -1 )
608 printf( "\n"
609 "Return value starts on index %d:\n",
610 ti->retval );
611 dumpNode( ti, ti->retval, 0 );
614 #else
615 # define dump(x)
616 #endif
618 /*****************************************************************************
619 *****************************************************************************
620 ** GLOBAL FUNCTIONS *********************************************************
621 *****************************************************************************
622 *****************************************************************************/
625 * GCI_parsenodes parses a type definition stem (that thing you provide in a
626 * call to RxFuncDefine) and assigns the values to a structure.
628 * The stem's name will come from base, which must be readable in a
629 * non-symbolic manner (uppercased, etc). The string must have some spare
630 * space for the additional fields of the names all over the structure. I
631 * think 200 byte will be sufficient.
632 * The structure *ti is filled, ti->nodes shall be NULL initially and may or
633 * may not contain valid entries on return even in case of an error.
634 * ti->callinfo is used to determine if more restriction have to be applied to
635 * the arguments or to the return value.
636 * argc contains the number of arguments this function shall parse.
637 * return_valid shall be set to 1 if the "stem.RETURN.TYPE" is not the
638 * empty string. In this case we parse the corresponding tree, too.
640 * prefixChar is the prefix that must be used in front of stem names.
642 * The string base may contain the error location within the stem in case of
643 * an error.
645 * Return values:
646 * GCI_OK: Everything is fine.
648 * In case of an error cb->buffer will contain the
649 * variable's name where the problem raises first.
651 * GCI_MissingName: A variable's name isn't set. This is the equivalence
652 * for GCI_MissingValue in the type parsing step. The
653 * system may or may not raise a NOVALUE condition instead
654 * depending on the implementation.
655 * GCI_BufferTooSmall: The variable's name buffer cb->buffer can't hold the
656 * complete variable's name or the type string exceeds
657 * 256 byte.
658 * GCI_IllegalName: The variables name in cb->buffer is illegal in terms of
659 * Rexx. In general, the basename of GCI_paretree is
660 * wrong.
661 * GCI_RexxError: An unexpected error is returned by the interpreter
662 * while trying to access Rexx variables.
663 * GCI_UnsupportedType: Wrong type of input, e.g. FLOAT31 or the empty string
664 * in a type description string. Another reason is an
665 * internal error since the default sizes for "unsigned"
666 * and "integer" are not supported.
667 * GCI_WrongInput: Strange characters occur in the input string as the
668 * bit size of the type.
669 * GCI_NumberRange: Number to small or big to fit into the desired type
670 * with the desired destbyte-size. This applies to the
671 * element count of an "ARRAY" or "CONTAINER" type size
672 * or the bit size of the plain type.
673 * GCI_NoBaseType: The type won't fit the requirements for basic types.
674 * GCI_InternalError: Attempt to shorten the array so far that elements get
675 * lost or illegal values used internally.
677 GCI_result GCI_parsenodes( void *hidden,
678 GCI_str *base,
679 GCI_treeinfo *ti,
680 unsigned argc,
681 unsigned return_valid,
682 const char *prefixChar )
684 GCI_result rc = GCI_OK;
685 unsigned i;
686 int origlen = GCI_strlen( base );
687 char iter[4];
688 WalkerInfo w;
690 w.hidden = hidden;
691 w.ti = ti;
692 w.runner = 0;
694 for ( i = 0; i < argc; i++ )
696 GCI_strsetlen( base, origlen );
697 sprintf( iter, ".%u", i+1 );
698 GCI_strcats( base, iter );
699 w.parent = -1;
700 ti->args[i] = ti->used;
701 if ( ( rc = GCI_parsetree( hidden,
702 base,
703 walker,
705 prefixChar ) ) != GCI_OK )
706 break;
707 if ( ti->callinfo.with_parameters &&
708 ( ti->nodes[ti->args[i]].child != -1 ) )
710 rc = GCI_NoBaseType;
711 break;
713 ti->size += ti->nodes[ti->args[i]].direct_size;
714 ti->size += ti->nodes[ti->args[i]].indirect_size;
715 computePositions( &w, ti->args[i] );
716 assert( w.runner >= ti->size );
717 ti->size = w.runner;
720 if ( ( rc == GCI_OK ) && return_valid )
722 GCI_strsetlen( base, origlen );
723 GCI_strcats( base, "." );
724 GCI_strcats( base, prefixChar );
725 GCI_strcats( base, "RETURN" );
726 w.parent = -1;
727 ti->retval = ti->used;
728 rc = GCI_parsetree( hidden, base, walker, &w, prefixChar );
729 if ( rc == GCI_OK )
731 if ( ti->callinfo.as_function &&
732 ( ti->nodes[ti->retval].child != -1 ) )
733 return GCI_NoBaseType;
734 GCI_strsetlen( base, origlen );
737 * It doesn't make any sense to add the return value's sizes, but it
738 * makes sense to buffer at least the first direct return value for
739 * later use.
741 if ( w.runner != 0 )
743 ti->size += SPARE( ti->size, GCI_ALIGNMENT );
744 ti->size += ti->nodes[ti->retval].direct_size;
746 computePositions( &w, ti->retval );
751 * Don't let malloc throw an error if no parameters are addressed.
753 ti->size = ( w.runner ) ? w.runner : 1;
755 if ( rc == GCI_OK )
758 * Minimize the used memory.
760 resizeNodes( &w, ti->used );
761 dump( ti );
764 return rc;