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.
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.
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
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.
56 * GCI_OK: Everything's fine.
57 * GCI_InternalError: Attempt to shorten the array so far that elements get
59 * GCI_NoMemory: Not enough free memory. Note that the old w->ti->nodes
62 static GCI_result
resizeNodes( WalkerInfo
*w
,
66 GCI_treeinfo
*ti
= w
->ti
;
68 if ( ti
->max
== new_nodemax
)
70 if ( ti
->used
> new_nodemax
)
71 return GCI_InternalError
;
73 buf
= GCI_malloc( w
->hidden
, sizeof( GCI_nodeinfo
) * new_nodemax
);
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
;
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.
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
105 static GCI_result
walker( int depth
,
108 const GCI_parseinfo
*info
)
111 WalkerInfo
*w
= (WalkerInfo
*) arg
;
112 GCI_treeinfo
*ti
= w
->ti
;
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 );
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
138 * v -> v -> v -> v ->...
139 * a->b->c->d->-1 -1<-a|>b->c->d a<-b|>c->d a<-b<-c|>d
154 assert( n
->child
!= -1 );
157 h
= ti
->nodes
+ n
->child
;
161 n
->direct_size
+= h
->direct_size
;
162 n
->indirect_size
+= h
->indirect_size
;
168 h
= ti
->nodes
+ next
;
172 n
->direct_size
+= h
->direct_size
;
173 n
->indirect_size
+= h
->indirect_size
;
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 * );
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
)
207 n
->parent
= w
->parent
;
211 n
->indirect_size
= 0;
214 if ( n
->parent
== -1 )
216 assert( depth
== 0 );
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
)
234 n
->direct_size
= info
->size
;
238 n
->direct_size
= info
->size
+ 1;
242 n
->direct_size
= info
->size
;
254 return GCI_InternalError
;
257 if ( info
->indirect
)
259 n
->indirect_size
= n
->direct_size
;
260 n
->direct_size
= sizeof( void * );
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
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.
293 * which is equivalent to (assuming a pointer size of 4)
295 * INTEGER8 1 byte, pos 0
296 * INDIRECTION 4 byte, pos 1 ---+
297 * INTEGER16 2 byte, pos 5 |
299 * +------------------------------+
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 |
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
,
322 GCI_treeinfo
*ti
= w
->ti
;
326 n
= ti
->nodes
+ start
;
334 n
->direct_pos
= w
->runner
;
336 if ( info
->indirect
)
338 w
->runner
+= sizeof( void * );
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.
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
);
357 for ( child
= n
->child
;
359 child
= ti
->nodes
[child
].sibling
)
360 computePosition( w
, child
, 1 );
361 assert( n
->direct_size
== w
->runner
- h
);
365 w
->runner
+= n
->direct_size
;
372 * Now handle the indirect case. We either may have a direct or an indirect
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
)
387 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
391 computePosition( w
, n
->child
, 0 );
393 if ( h
== w
->runner
)
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
);
405 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
409 for ( child
= n
->child
;
411 child
= ti
->nodes
[child
].sibling
)
412 computePosition( w
, child
, 0 );
414 if ( h
== w
->runner
)
418 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
419 n
->indirect_size
= w
->runner
- h
+ s
;
425 assert( ( info
->type
!= GCI_array
) &&
426 ( info
->type
!= GCI_container
) );
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
)
440 w
->runner
+= SPARE( w
->runner
, GCI_ALIGNMENT
);
441 n
->indirect_pos
= w
->runner
;
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
;
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.
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
);
472 n
->indirect_size
= w
->runner
- h
;
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
483 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
485 if ( info
->type
== GCI_array
)
487 n
->indirect_size
+= info
->size
* ( w
->runner
- h
);
488 w
->runner
+= ( info
->size
- 1 ) * ( w
->runner
- h
);
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
,
508 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
511 computePosition( w
, start
, 1 );
512 if ( hrun
== w
->runner
)
515 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
518 computePosition( w
, start
, 0 );
519 if ( hrun
== w
->runner
)
523 w
->ti
->nodes
[start
].indirect_size
= w
->runner
- hrun
;
525 * Let the next argument be aligned properly and note it in the indirect
528 s
= SPARE( w
->runner
, GCI_ALIGNMENT
);
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
539 static void dumpNode( const GCI_treeinfo
*ti
,
548 n
= ti
->nodes
+ start
;
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
);
571 ( n
->type
.generated
) ? " (generated)" : "" );
574 if ( n
->child
!= -1 )
575 dumpNode( ti
, n
->child
, indent
+ 1 );
576 } while ( start
!= -1 );
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
)
588 if ( getenv("_GCI_DUMP") == NULL
)
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 )
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 )
609 "Return value starts on index %d:\n",
611 dumpNode( ti
, ti
->retval
, 0 );
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
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
658 * GCI_IllegalName: The variables name in cb->buffer is illegal in terms of
659 * Rexx. In general, the basename of GCI_paretree is
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
,
681 unsigned return_valid
,
682 const char *prefixChar
)
684 GCI_result rc
= GCI_OK
;
686 int origlen
= GCI_strlen( base
);
694 for ( i
= 0; i
< argc
; i
++ )
696 GCI_strsetlen( base
, origlen
);
697 sprintf( iter
, ".%u", i
+1 );
698 GCI_strcats( base
, iter
);
700 ti
->args
[i
] = ti
->used
;
701 if ( ( rc
= GCI_parsetree( hidden
,
705 prefixChar
) ) != GCI_OK
)
707 if ( ti
->callinfo
.with_parameters
&&
708 ( ti
->nodes
[ti
->args
[i
]].child
!= -1 ) )
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
);
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" );
727 ti
->retval
= ti
->used
;
728 rc
= GCI_parsetree( hidden
, base
, walker
, &w
, prefixChar
);
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
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;
758 * Minimize the used memory.
760 resizeNodes( &w
, ti
->used
);