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 implements the RxFuncDefine function. The direct useable
22 * function is placed in gci_rexxbridge.c or similar.
32 * A small enum type describing the parsed additional arguments to "CALLTYPE".
43 * checkname tries to interpret the first characters of a string and sets
44 * the symbolic name of it.
45 * The string is taken from *str with a length of *size.
47 * On success *str is set to the first character after the recognized word
48 * and *size is decremented by the length of the recognized word. Additionally
49 * *calltype and *infotype is set. Exactly one of them becomes "unknown".
51 * This function doesn't jump over leading whitespaces and the function
52 * doesn't check for any word delimiters. *str must have been uppercased.
54 static GCI_result
checkname( const char **str
,
56 GCI_calltype
*calltype
,
65 { GCI_ctCdecl
, InfoUnknown
, 5, "CDECL" },
66 { GCI_ctPascal
, InfoUnknown
, 6, "PASCAL" },
67 { GCI_ctStdcall
, InfoUnknown
, 7, "STDCALL" },
68 { GCI_ctUnknown
, InfoAs
, 2, "AS" },
69 { GCI_ctUnknown
, InfoFunction
, 8, "FUNCTION" },
70 { GCI_ctUnknown
, InfoWith
, 4, "WITH" },
71 { GCI_ctUnknown
, InfoParameters
, 10, "PARAMETERS" }
74 int i
, l
, len
= *size
;
76 for ( i
= 0; i
< (int) elements( list
); i
++ )
81 if ( memcmp( s
, list
[i
].name
, l
) == 0 )
85 *calltype
= list
[i
].ctype
;
86 *infotype
= list
[i
].itype
;
90 return GCI_UnsupportedType
;
94 * parseCallTree parses the string str and puts all fetched informations into
95 * *ci. The string str usually is the argument of stem.CALTYPE.
98 * GCI_OK: Everything is fine.
99 * GCI_UnsupportedType: The base calltype isn't cdecl, stdcall, etc or the
100 * modifiers (as function, etc) couldn't be recognized.
102 static GCI_result
parseCallType( void *hidden
,
108 const char *ptr
= GCI_ccontent( str
);
109 int size
= GCI_strlen( str
);
113 lastit
= InfoUnknown
;
114 memset( ci
, 0, sizeof( GCI_callinfo
) );
117 * Allow any order as far as double word arguments like "as function"
118 * appears together and in the right order.
123 * Chop off spaces. We stop if we reach EOS here.
125 while ( ( size
> 0 ) && GCI_isspace( *ptr
) )
133 if ( checkname( &ptr
, &size
, &ct
, &it
) != GCI_OK
)
134 return GCI_UnsupportedType
;
135 if ( lastit
== InfoAs
)
137 if ( it
!= InfoFunction
)
138 return GCI_UnsupportedType
;
142 lastit
= InfoUnknown
;
146 if ( lastit
== InfoWith
)
148 if ( it
!= InfoParameters
)
149 return GCI_UnsupportedType
;
152 ci
->with_parameters
= 1;
153 lastit
= InfoUnknown
;
158 if ( ci
->type
== GCI_ctUnknown
)
160 if ( ct
== GCI_ctUnknown
)
161 return GCI_UnsupportedType
;
170 if ( ct
!= GCI_ctUnknown
)
171 return GCI_UnsupportedType
;
184 return GCI_UnsupportedType
;
187 if ( ( ci
->type
== GCI_ctUnknown
) || ( lastit
!= InfoUnknown
) )
188 return GCI_UnsupportedType
;
194 * isempty returns 1 exactly if the passed string is either empty or consists
195 * of whitespaces only. 0 is returned otherwise.
197 static int isempty( void *hidden
,
200 const char *s
= GCI_ccontent( str
);
201 int len
= GCI_strlen( str
);
206 if ( !GCI_isspace( *s
) )
216 * parseTree parses a complete argument stem of RxFuncDefine.
217 * base must be the uppercased and otherwise prepared stem's name suitable
218 * for non-symbolic access. base must have some space left, e.g. 200 byte, for
219 * expanding all arguments. base's content isn't resetted on error which
220 * provides a simple way to determine the errorneous variable.
221 * *ti will be filled. *ti should be initialized. The caller must free the
222 * nodes element if it isn't NULL on return and the return value signals an
225 * prefixChar is the prefix that must be used in front of stem names.
228 * GCI_OK: Everything is fine.
229 * other: There are so many different errors, it doesn't make any sense
230 * to list them. Use the errorneous stem's name in base and the
231 * GCI_describe'd string of the return value.
233 static GCI_result
parseTree( void *hidden
,
236 const char *prefixChar
)
239 unsigned argc
, return_valid
= 0;
240 int origlen
= GCI_strlen( base
);
242 * All simple arguments must fit into a static buffer.
245 GCI_strOfCharBuffer( tmp
);
247 GCI_strcats( base
, "." );
248 GCI_strcats( base
, prefixChar
);
249 GCI_strcats( base
, "CALLTYPE" );
250 if ( ( rc
= GCI_readRexx( hidden
, base
, &str_tmp
, 0, 1, NULL
) ) != GCI_OK
)
252 if ( rc
== GCI_MissingValue
)
253 rc
= GCI_MissingName
;
256 GCI_uppercase( hidden
, &str_tmp
);
258 if ( ( rc
= parseCallType( hidden
, &str_tmp
, &ti
->callinfo
) ) != GCI_OK
)
261 GCI_strsetlen( base
, origlen
);
262 GCI_strcats( base
, ".0" );
263 if ( ( rc
= GCI_readRexx( hidden
, base
, &str_tmp
, 0, 1, NULL
) ) != GCI_OK
)
265 if ( rc
== GCI_MissingValue
)
266 rc
= GCI_MissingName
;
270 if ( GCI_string2bin( hidden
,
271 GCI_ccontent( &str_tmp
),
272 GCI_strlen( &str_tmp
),
275 GCI_unsigned
) != GCI_OK
)
276 return GCI_UnsupportedType
;
278 if ( argc
> GCI_REXX_ARGS
)
279 return GCI_NumberRange
;
282 * We still need to know whether to provide a return value.
284 GCI_strsetlen( base
, origlen
);
285 GCI_strcats( base
, "." );
286 GCI_strcats( base
, prefixChar
);
287 GCI_strcats( base
, "RETURN" );
288 GCI_strcats( base
, "." );
289 GCI_strcats( base
, prefixChar
);
290 GCI_strcats( base
, "TYPE" );
291 if ( ( rc
= GCI_readRexx( hidden
, base
, &str_tmp
, 0, 1, NULL
) ) != GCI_OK
)
293 if ( rc
== GCI_MissingValue
)
294 return GCI_MissingName
;
298 if ( !isempty( hidden
, &str_tmp
) )
301 * If we have to respect a return value, we have to pass back a
302 * return values in a stem, but this cannot be done if we have
303 * the with_parameters option in effect.
304 * Auto-enable as_function as mentioned in the proposal.
306 if ( ti
->callinfo
.with_parameters
)
307 ti
->callinfo
.as_function
= 1;
310 else if ( ti
->callinfo
.as_function
) /* senseless */
311 return GCI_NoBaseType
;
313 GCI_strsetlen( base
, origlen
);
318 return GCI_parsenodes( hidden
, base
, ti
, argc
, return_valid
, prefixChar
);
322 * GCI_ParseTree parses the stem of a function definition and checks its
325 * hidden is the usual parameter of the system; stem is the parameter of the
326 * (GCI_)RxFuncDefine call.
328 * The validated tree is returned in gci_info.
330 * error_disposition is a non-allocated string on entry. It will contain the
331 * error position in the stem in case of an error. It may be unset again to
332 * indicate a non specific error location.
334 * prefixChar is the prefix that must be used in front of stem names.
337 * GCI_OK: Everything is fine.
338 * other: There are so many different errors, it doesn't make any sense
339 * to list them. Use the errorneous stem's name in error_disposition
340 * (if available) and the GCI_describe'd string of the return value.
342 GCI_result
GCI_ParseTree( void *hidden
,
344 GCI_treeinfo
*gci_info
,
345 GCI_str
*error_disposition
,
346 const char *prefixChar
)
356 if ( ( rc
= GCI_readNewRexx( hidden
,
364 * Let the system show a proper error location.
366 if ( GCI_stralloc( hidden
,
368 GCI_strlen( stem
) ) == GCI_OK
)
369 GCI_strcpy( error_disposition
, stem
);
374 * An extra buffer for roughly 100 indentions, that's enough.
376 if ( ( rc
= GCI_stralloc( hidden
,
378 GCI_strlen( &stemval
) + STEMDEPTH
) ) != GCI_OK
)
380 GCI_strfree( hidden
, &stemval
);
384 * We do a non-symbolic access later. Make sure we don't loose!
386 GCI_uppercase( hidden
, &stemval
);
387 l
= GCI_strlen( &stemval
);
388 if ( ( l
> 0 ) & ( GCI_content( &stemval
)[l
- 1] == '.' ) )
389 GCI_strsetlen( &stemval
, l
- 1 );
390 GCI_strcpy( error_disposition
, &stemval
);
391 GCI_strfree( hidden
, &stemval
);
393 memset( &tree
, 0, sizeof( tree
) );
394 for ( l
= 0; l
< (int) elements( tree
.args
); l
++ )
398 if ( ( rc
= parseTree( hidden
,
401 prefixChar
) ) != GCI_OK
)
403 if ( tree
.nodes
!= NULL
)
404 GCI_free( hidden
, tree
.nodes
);
409 * We don't need the error disposition any longer.
411 GCI_strfree( hidden
, error_disposition
);
419 * GCI_RxFuncDefine is the main executor or the RxFuncDefine function.
420 * It checks the stem for validity. If successful it tries to register a new
421 * function to the generic call executor. That function will effectively call
422 * the desired function.
424 * hidden is the usual parameter of the system; internal, library, external
425 * and stem are the parameters of the RxFuncDefine call.
427 * error_disposition is a non-allocated string on entry. It will contain the
428 * error position in the stem in case of an error. It may be unset again to
429 * indicate a non specific error location.
431 * prefixChar is the prefix that must be used in front of stem names.
434 * GCI_OK: Everything is fine.
435 * other: There are so many different errors, it doesn't make any sense
436 * to list them. Use the errorneous stem's name in error_disposition
437 * (if available) and the GCI_describe'd string of the return value.
439 GCI_result
GCI_RxFuncDefine( void *hidden
,
440 const GCI_str
*internal
,
441 const GCI_str
*library
,
442 const GCI_str
*external
,
444 GCI_str
*error_disposition
,
445 const char *prefixChar
)
450 if ( ( rc
= GCI_ParseTree( hidden
,
454 prefixChar
) ) != GCI_OK
)
457 if ( ( rc
= GCI_RegisterDefinedFunction( hidden
,
461 &tree
) ) != GCI_OK
)
463 if ( tree
.nodes
!= NULL
)
464 GCI_free( hidden
, tree
.nodes
);