1 /*
2  *  Generic Call Interface for Rexx
3  *  Copyright � 2003-2004, Florian Gro�e-Coosmann
4  *
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.
9  *
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.
14  *
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.
18  *
19  * ----------------------------------------------------------------------------
20  *
21  * This file contains little helper routines.
22  */
23 
24 #include "gci.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 
30 /*****************************************************************************
31  *****************************************************************************
32  ** GLOBAL FUNCTIONS *********************************************************
33  *****************************************************************************
34  *****************************************************************************/
35 
36 /*
37  * GCI_strlen returns the current length of the string.
38  */
GCI_strlen(const GCI_str * str)39 int GCI_strlen( const GCI_str *str )
40 {
41    return str->used;
42 }
43 
44 /*
45  * GCI_strmax returns the maximum length of the string including any
46  * terminators.
47  */
GCI_strmax(const GCI_str * str)48 int GCI_strmax( const GCI_str *str )
49 {
50    return str->max;
51 }
52 
53 /*
54  * GCI_content returns a pointer to the content of str. The content may not be
55  * 0-terminated.
56  */
GCI_content(GCI_str * str)57 char * GCI_content( GCI_str *str )
58 {
59    return str->val;
60 }
61 
62 /*
63  * GCI_content returns a pointer to the content of str. The content may not be
64  * 0-terminated.
65  */
GCI_ccontent(const GCI_str * str)66 const char * GCI_ccontent( const GCI_str *str )
67 {
68    return str->val;
69 }
70 
71 /*
72  * GCI_streq returns 1 if two string have an equal content, 0 otherwise.
73  */
GCI_streq(const GCI_str * s1,const GCI_str * s2)74 int GCI_streq( const GCI_str *s1,
75                const GCI_str *s2 )
76 {
77    int l = s1->used;
78 
79    if ( l != s2->used )
80       return 0;
81    return ( memcmp( s1->val, s2->val, l ) == 0 ) ? 1 : 0;
82 }
83 
84 /*
85  * concat appends the content of second to first. second_len contains the
86  * length of second. second may not be 0-terminated.
87  * The return value is either GCI_OK or GCI_BufferTooSmall.
88  */
concat(GCI_str * first,const char * second,int size)89 static GCI_result concat( GCI_str *first,
90                           const char *second,
91                           int size )
92 {
93    if ( first->used + size > first->max )
94       return GCI_BufferTooSmall;
95 
96    memcpy( first->val + first->used, second, size );
97    first->used += size;
98    return GCI_OK;
99 }
100 
101 /*
102  * GCI_strcat appends the content of second to first.
103  * The return value is either GCI_OK or GCI_BufferTooSmall.
104  */
GCI_strcat(GCI_str * first,const GCI_str * second)105 GCI_result GCI_strcat( GCI_str *first,
106                        const GCI_str *second )
107 {
108    return concat( first, second->val, second->used );
109 }
110 
111 /*
112  * GCI_strcats appends the content of the 0-terminated string second to first.
113  * The return value is either GCI_OK or GCI_BufferTooSmall.
114  */
GCI_strcats(GCI_str * first,const char * second)115 GCI_result GCI_strcats( GCI_str *first,
116                         const char *second )
117 {
118    return concat( first, second, strlen( second ) );
119 }
120 
121 /*
122  * GCI_strsetlen sets the length of str to max. If max if bigger than the
123  * string's internal maximum it is set to the string's internal maximum.
124  */
GCI_strsetlen(GCI_str * str,int max)125 void GCI_strsetlen( GCI_str *str,
126                     int max )
127 {
128    if ( str->max < max )
129       str->used = str->max;
130    else
131       str->used = max;
132 }
133 
134 /*
135  * GCI_strcpy sets the content of first to the content of second.
136  * The return value is either GCI_OK or GCI_BufferTooSmall.
137  */
GCI_strcpy(GCI_str * first,const GCI_str * second)138 GCI_result GCI_strcpy( GCI_str *first,
139                        const GCI_str *second )
140 {
141    if ( first->max < second->used )
142       return GCI_BufferTooSmall;
143 
144    memcpy( first->val, second->val, second->used );
145    first->used = second->used;
146    return GCI_OK;
147 }
148 
149 /*
150  * GCI_strfromascii creates a GCI_str from a character pointer. The content's
151  * maximum is set to max, the content itself is taken from ptr.
152  * The used length is set to 0.
153  * THE FILLED GCI_str MUST NEVER BE PASSED TO GCI_strfree!
154  * The passed string is returned.
155  */
GCI_strfromascii(GCI_str * str,char * ptr,int max)156 GCI_str *GCI_strfromascii( GCI_str *str,
157                            char *ptr,
158                            int max )
159 {
160    str->val = ptr;
161    str->used = 0;
162    str->max = max;
163 
164    return str;
165 }
166 
167 /*
168  * GCI_migratefromascii creates a GCI_str from a character pointer.
169  * The content's maximum and its length is set to length of the zero-terminated
170  * string in ptr, the content itself is taken from ptr.
171  * THE FILLED GCI_str MUST NEVER BE PASSED TO GCI_strfree!
172  * The passed string is returned.
173  */
GCI_migratefromascii(GCI_str * str,const char * ptr)174 const GCI_str *GCI_migratefromascii( GCI_str *str,
175                                      const char *ptr )
176 {
177    str->val = (char *) ptr;
178    str->used = strlen( ptr );
179    str->max = str->used;
180 
181    return str;
182 }
183 
184 /*
185  * GCI_stralloc allocates the content of a string. The content will have
186  * size bytes. The former content won't be freed if there is something
187  * allocated.
188  * The return value is either GCI_OK or GCI_NoMemory.
189  */
GCI_stralloc(void * hidden,GCI_str * str,unsigned size)190 GCI_result GCI_stralloc( void *hidden,
191                          GCI_str *str,
192                          unsigned size )
193 {
194    if ( size == 0 )
195       size = 1;
196    if ( ( str->val = (char *) GCI_malloc( hidden, size ) ) == NULL )
197       return GCI_NoMemory;
198 
199    str->used = 0;
200    str->max = size;
201    return GCI_OK;
202 }
203 
204 /*
205  * GCI_strfree deallocates the content of a string. The string itself isn't
206  * freed. The content is set to NULL.
207  */
GCI_strfree(void * hidden,GCI_str * str)208 void GCI_strfree( void *hidden,
209                   GCI_str *str )
210 {
211    if ( str->val != NULL )
212       GCI_free( hidden, str->val );
213 
214    str->val = NULL;
215    str->max = str->used = 0;
216 }
217 
218 /*
219  * GCI_strdup duplicates the content of a string second and assigns it to
220  * first. The content of first will be overwritten without any cleanup.
221  * This function allocates the needed bytes only.
222  * The return value is either GCI_OK or GCI_NoMemory.
223  */
GCI_strdup(void * hidden,GCI_str * first,const GCI_str * second)224 GCI_result GCI_strdup( void *hidden,
225                        GCI_str *first,
226                        const GCI_str *second )
227 {
228    if ( ( first->val = (char *) GCI_malloc( hidden, second->used ) ) == NULL )
229       return GCI_NoMemory;
230 
231    memcpy( first->val, second->val, second->used );
232    first->used = first->max = second->used;
233    return GCI_OK;
234 }
235 
236 /*
237  * GCI_strtoascii duplicates the content of the string str to a newly created
238  * ASCIIZ string which is returned. NULL is returned in case of an error or
239  * if str describes a NULL string (in opposite to an empty string).
240  */
GCI_strtoascii(void * hidden,const GCI_str * str)241 char *GCI_strtoascii( void *hidden,
242                       const GCI_str *str )
243 {
244    char *retval;
245 
246    if ( ( str == NULL ) || ( str->val == NULL ) )
247       return NULL;
248    if ( ( retval = (char *) GCI_malloc( hidden, str->used + 1 ) ) == NULL )
249       return NULL;
250 
251    memcpy( retval, str->val, str->used );
252    retval[str->used] = '\0';
253    return retval;
254 }
255 
256 /*
257  * GCI_uppercase transforms the content of str to its uppercased value.
258  * We may or may not convert foreign characters. It depends on the runtime
259  * system and on the environment settings of codepage/language.
260  */
GCI_uppercase(void * hidden,GCI_str * str)261 void GCI_uppercase( void *hidden,
262                     GCI_str *str )
263 {
264    int i, len = str->used;
265    char *ptr = str->val;
266 
267    for ( i = 0; i < len; i++, ptr++ )
268       *ptr = (char) GCI_toupper( *ptr );
269 }
270 
271 /*
272  * GCI_describe converts a GCI_result to a more or less human readable
273  * string. The caller shall provide a string with at least 80 byte.
274  * THIS FUNCTION IS NOT THREAD SAFE.
275  */
GCI_describe(GCI_str * description,GCI_result rc)276 void GCI_describe( GCI_str *description,
277                    GCI_result rc )
278 {
279    char *ptr = NULL;
280    static char buf[40];
281 
282    switch ( rc )
283    {  /* oversized lines! */                                                 /* here is the limit for the text: -->blahblah" */
284       case GCI_OK:                   ptr = "GCI completed successfully";                                                      break;
285       case GCI_NoMemory:             ptr = "Out of memory while processing a GCI request";                                    break;
286       case GCI_WrongInput:           ptr = "Unexpected input, either unknown type or illegal data";                           break;
287       case GCI_NumberRange:          ptr = "Number out of the allowed range";                                                 break;
288       case GCI_StringRange:          ptr = "String too big for the defined buffer";                                           break;
289       case GCI_UnsupportedType:      ptr = "Illegal combination of type/size";                                                break;
290       case GCI_UnsupportedNumber:    ptr = "Unsupported number like NAN, +INF, -INF";                                         break;
291       case GCI_BufferTooSmall:       ptr = "Structure too complex for static internal buffer";                                break;
292       case GCI_MissingName:          ptr = "An element of the structure is missing";                                          break;
293       case GCI_MissingValue:         ptr = "A value of the structure is missing";                                             break;
294       case GCI_IllegalName:          ptr = "The name or part of the name is illegal for the interpreter";                     break;
295       case GCI_RexxError:            ptr = "A problem raises when communicating with the interpreter";                        break;
296       case GCI_NoBaseType:           ptr = "The type won't fit the requirements for basic types (arguments/return value)";    break;
297       case GCI_InternalError:        ptr = "An unknown internal GCI error occured";                                           break;
298       case GCI_FunctionAlreadyKnown: ptr = "New REXX function already registered to the interpreter";                         break;
299       case GCI_LibraryNotFound:      ptr = "The external library was not found or can't be loaded";                           break;
300       case GCI_NoLibraryFunction:    ptr = "The external function can't be found in the external library";                    break;
301       case GCI_FunctionNotFound:     ptr = "The REXX function was not or no longer registered by the interpreter";            break;
302       case GCI_SyntaxError:          ptr = "The number of arguments is wrong or an argument is missing";                      break;
303       case GCI_CoreConfused:         ptr = "The core of GCI can't determine how to invoke generic functions";                 break;
304       case GCI_ArgStackOverflow:     ptr = "GCI's internal stack for arguments got an overflow";                              break;
305       case GCI_NestingOverflow:      ptr = "GCI counted too many nested LIKE containers";                                     break;
306       default:
307          break;
308    }
309 
310    if ( ptr == NULL )
311    {
312       ptr = buf;
313       sprintf( buf, "Unknown GCI error %d", rc );
314    }
315    description->val = ptr;
316    description->used = strlen(ptr);
317    description->max = description->used;
318 }
319 
320 /*
321  * GCI_strswap exchanges two strings' content completely.
322  */
GCI_strswap(GCI_str * first,GCI_str * second)323 void GCI_strswap( GCI_str *first,
324                   GCI_str *second )
325 {
326    GCI_str h;
327 
328    h = *first;
329    *first = *second;
330    *second = h;
331 }
332