fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / regina / gci / gci_rxfuncdefine.c
blob01a1f40e0ffd0373045cce607acfba8c5ab4aae3
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 implements the RxFuncDefine function. The direct useable
22 * function is placed in gci_rexxbridge.c or similar.
25 #include "gci.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
32 * A small enum type describing the parsed additional arguments to "CALLTYPE".
34 typedef enum {
35 InfoUnknown = 0,
36 InfoAs,
37 InfoFunction,
38 InfoWith,
39 InfoParameters
40 } InfoType;
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,
55 int *size,
56 GCI_calltype *calltype,
57 InfoType *infotype )
59 static const struct {
60 GCI_calltype ctype;
61 InfoType itype;
62 int length;
63 const char *name;
64 } list[] = {
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" }
73 const char *s = *str;
74 int i, l, len = *size;
76 for ( i = 0; i < (int) elements( list ); i++ )
78 l = list[i].length;
79 if ( len < l )
80 continue;
81 if ( memcmp( s, list[i].name, l ) == 0 )
83 *str = s + l;
84 *size -= l;
85 *calltype = list[i].ctype;
86 *infotype = list[i].itype;
87 return GCI_OK;
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.
97 * Return values:
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,
103 const GCI_str *str,
104 GCI_callinfo *ci )
106 GCI_calltype ct;
107 InfoType it, lastit;
108 const char *ptr = GCI_ccontent( str );
109 int size = GCI_strlen( str );
111 (hidden = hidden);
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.
120 for ( ; ; )
123 * Chop off spaces. We stop if we reach EOS here.
125 while ( ( size > 0 ) && GCI_isspace( *ptr ) )
127 ptr++;
128 size--;
130 if ( size == 0 )
131 break;
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;
139 else
141 ci->as_function = 1;
142 lastit = InfoUnknown;
143 continue;
146 if ( lastit == InfoWith )
148 if ( it != InfoParameters )
149 return GCI_UnsupportedType;
150 else
152 ci->with_parameters = 1;
153 lastit = InfoUnknown;
154 continue;
158 if ( ci->type == GCI_ctUnknown )
160 if ( ct == GCI_ctUnknown )
161 return GCI_UnsupportedType;
162 else
164 ci->type = ct;
165 continue;
168 else
170 if ( ct != GCI_ctUnknown )
171 return GCI_UnsupportedType;
174 switch ( it )
176 case InfoAs:
177 case InfoWith:
178 lastit = it;
179 continue;
181 default:
182 break;
184 return GCI_UnsupportedType;
187 if ( ( ci->type == GCI_ctUnknown ) || ( lastit != InfoUnknown ) )
188 return GCI_UnsupportedType;
190 return GCI_OK;
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,
198 const GCI_str *str )
200 const char *s = GCI_ccontent( str );
201 int len = GCI_strlen( str );
203 (hidden = hidden);
205 while ( len > 0 ) {
206 if ( !GCI_isspace( *s ) )
207 return 0;
208 len--;
209 s++;
212 return 1;
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
223 * error.
225 * prefixChar is the prefix that must be used in front of stem names.
227 * Return values:
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,
234 GCI_str *base,
235 GCI_treeinfo *ti,
236 const char *prefixChar )
238 GCI_result rc;
239 unsigned argc, return_valid = 0;
240 int origlen = GCI_strlen( base );
242 * All simple arguments must fit into a static buffer.
244 char tmp[256];
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;
254 return rc;
256 GCI_uppercase( hidden, &str_tmp );
258 if ( ( rc = parseCallType( hidden, &str_tmp, &ti->callinfo ) ) != GCI_OK )
259 return rc;
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;
267 return rc;
270 if ( GCI_string2bin( hidden,
271 GCI_ccontent( &str_tmp ),
272 GCI_strlen( &str_tmp ),
273 &argc,
274 sizeof( argc ),
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;
296 else
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;
308 return_valid = 1;
310 else if ( ti->callinfo.as_function ) /* senseless */
311 return GCI_NoBaseType;
313 GCI_strsetlen( base, origlen );
315 if ( rc != GCI_OK )
316 return rc;
318 return GCI_parsenodes( hidden, base, ti, argc, return_valid, prefixChar );
322 * GCI_ParseTree parses the stem of a function definition and checks its
323 * validity.
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.
336 * Return values:
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,
343 const GCI_str *stem,
344 GCI_treeinfo *gci_info,
345 GCI_str *error_disposition,
346 const char *prefixChar )
348 GCI_result rc;
349 GCI_str stemval;
350 GCI_treeinfo tree;
351 int l;
354 * Allow novalue.
356 if ( ( rc = GCI_readNewRexx( hidden,
357 stem,
358 &stemval,
361 NULL ) ) != GCI_OK )
364 * Let the system show a proper error location.
366 if ( GCI_stralloc( hidden,
367 error_disposition,
368 GCI_strlen( stem ) ) == GCI_OK )
369 GCI_strcpy( error_disposition, stem );
370 return rc;
374 * An extra buffer for roughly 100 indentions, that's enough.
376 if ( ( rc = GCI_stralloc( hidden,
377 error_disposition,
378 GCI_strlen( &stemval ) + STEMDEPTH ) ) != GCI_OK )
380 GCI_strfree( hidden, &stemval );
381 return rc;
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++ )
395 tree.args[l] = -1;
396 tree.retval = -1;
398 if ( ( rc = parseTree( hidden,
399 error_disposition,
400 &tree,
401 prefixChar ) ) != GCI_OK )
403 if ( tree.nodes != NULL )
404 GCI_free( hidden, tree.nodes );
405 return rc;
409 * We don't need the error disposition any longer.
411 GCI_strfree( hidden, error_disposition );
413 *gci_info = tree;
415 return GCI_OK;
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.
433 * Return values:
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,
443 const GCI_str *stem,
444 GCI_str *error_disposition,
445 const char *prefixChar )
447 GCI_result rc;
448 GCI_treeinfo tree;
450 if ( ( rc = GCI_ParseTree( hidden,
451 stem,
452 &tree,
453 error_disposition,
454 prefixChar ) ) != GCI_OK )
455 return rc;
457 if ( ( rc = GCI_RegisterDefinedFunction( hidden,
458 internal,
459 library,
460 external,
461 &tree ) ) != GCI_OK )
463 if ( tree.nodes != NULL )
464 GCI_free( hidden, tree.nodes );
467 return rc;