2 static char *RCSid
= "$Id$";
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 # define MIN(a,b) (((a)>(b))?(b):(a))
35 streng
*Str_ndup( const streng
*name
, int length
)
37 return Str_ndup_TSD(__regina_get_tsd(), name
, length
) ;
40 streng
*Str_ndup_TSD( const tsd_t
*TSD
, const streng
*name
, int length
)
44 assert( Str_len(name
) >= length
) ;
45 ptr
= Str_makeTSD( length
) ;
48 memcpy( ptr
->value
, name
->value
, length
) ;
52 streng
*Str_nodup( const streng
*name
, int offset
, int length
)
54 return Str_nodup_TSD(__regina_get_tsd(), name
, offset
, length
) ;
57 streng
*Str_nodup_TSD( const tsd_t
*TSD
, const streng
*name
, int offset
, int length
)
61 assert( Str_len(name
) >= (offset
+length
) ) ;
62 ptr
= Str_makeTSD( length
) ;
63 memcpy( ptr
->value
, name
->value
+offset
, length
) ;
68 streng
*Str_dup( const streng
*name
)
70 return Str_dup_TSD(__regina_get_tsd(), name
) ;
73 streng
*Str_dup_TSD( const tsd_t
*TSD
, const streng
*input
)
77 output
= Str_makeTSD( input
->len
) ;
78 output
->len
= input
->len
;
79 memcpy( output
->value
, input
->value
, input
->len
) ;
84 streng
*Str_dupstr( const streng
*name
)
86 return Str_dupstr_TSD(__regina_get_tsd(), name
) ;
89 /* Str_dupstr works like Str_dup but appends a hidden '\0' at the end. The
90 * terminator will be deleted by further Str_... operations.
92 streng
*Str_dupstr_TSD( const tsd_t
*TSD
, const streng
*input
)
96 output
= Str_makeTSD( input
->len
+ 1 ) ;
97 output
->len
= input
->len
;
98 memcpy( output
->value
, input
->value
, input
->len
) ;
99 output
->value
[input
->len
] = '\0';
104 streng
*Str_ncpy( streng
*to
, const streng
*from
, int length
)
106 return Str_ncpy_TSD( __regina_get_tsd(), to
, from
, length
) ;
109 streng
*Str_ncpy_TSD( const tsd_t
*TSD
, streng
*to
, const streng
*from
, int length
)
113 assert( Str_len(from
) >= length
) ;
114 if ((new=to
)->max
<(to
->len
+ length
))
116 new = Str_makeTSD( to
->len
+ length
) ;
117 memcpy(new->value
, to
->value
, to
->len
) ;
119 /* FreeTSD( to ) ; */
122 length
= (length
>Str_len(from
)) ? Str_len(from
) : length
;
123 memcpy(new->value
, from
->value
, length
) ;
129 streng
*Str_ncre( const char *from
, int length
)
131 return Str_ncre_TSD( __regina_get_tsd(), from
, length
) ;
134 streng
*Str_ncre_TSD( const tsd_t
*TSD
, const char *from
, int length
)
136 streng
*result
=NULL
;
138 assert( length
>= 0 ) ;
140 result
= Str_makeTSD( length
) ;
141 memcpy( result
->value
, from
, length
) ;
143 result
->len
= length
;
148 int Str_ncmp( const streng
*first
, const streng
*second
, int limit
)
152 rlim
= MIN( limit
, MIN( first
->len
, second
->len
) ) ;
153 for (i
=0 ; i
<rlim
; i
++)
154 if (first
->value
[i
] != second
->value
[i
])
155 return (first
->value
[i
] - second
->value
[i
]) ;
158 return (first
->len
!= second
->len
) ;
164 streng
*Str_cre( const char *input
)
166 return Str_cre_TSD( __regina_get_tsd(), input
) ;
169 streng
*Str_cre_TSD( const tsd_t
*TSD
, const char *input
)
171 streng
*result
=NULL
;
172 register int len
=strlen(input
);
174 result
= Str_makeTSD( len
) ;
175 memcpy( result
->value
, input
, result
->len
=len
) ;
179 streng
*Str_crestr( const char *input
)
181 return Str_crestr_TSD( __regina_get_tsd(), input
) ;
184 streng
*Str_crestr_TSD( const tsd_t
*TSD
, const char *input
)
187 register int len
=1+strlen(input
);
189 result
= Str_makeTSD( len
) ;
190 memcpy( result
->value
, input
, result
->len
=len
-1 ) ;
195 #if !defined(FLISTS) || defined(TRACEMEM)
196 streng
*__regina_Str_make( int size
)
198 return Str_make_TSD( __regina_get_tsd(), size
) ;
202 streng
*__regina_Str_make_TSD( const tsd_t
*TSD
, int size
)
206 retval
= MallocTSD(sizeof(streng
));
212 size
= 1; /* Don't allow malloc(0), Checker doesn't like it */
213 if ((retval
->value
= MallocTSD(size
)) == NULL
)
217 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
221 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
225 streng
*__regina_Str_make_TSD( const tsd_t
*TSD
, int size
)
227 streng
*result
=NULL
;
229 result
= MallocTSD( size
+ STRHEAD
) ;
235 # endif /* CHECK_MEMORY */
236 #endif /* !defined(FLISTS) || defined(TRACEMEM) */
239 static streng
*assure( const tsd_t
*TSD
, const streng
*str
, int length
)
243 if (length
<= str
->max
)
244 return (streng
*) str
;
246 ptr
= Str_makeTSD( length
) ;
247 memcpy( ptr
->value
, str
->value
, str
->len
) ;
248 ptr
->len
= str
->len
;
250 /* We don't free str. */
255 streng
*Str_catstr( streng
*base
, const char *append
)
257 return Str_catstr_TSD( __regina_get_tsd(), base
, append
) ;
260 streng
*Str_catstr_TSD( const tsd_t
*TSD
, streng
*base
, const char *append
)
265 ptr
= assure( TSD
, base
, (tmp
=strlen(append
)) + base
->len
) ;
266 memcpy( &ptr
->value
[ptr
->len
], append
, tmp
) ;
272 streng
*Str_nocat( streng
*first
, const streng
*second
, int length
, int offset
)
274 return Str_nocat_TSD( __regina_get_tsd(), first
, second
, length
, offset
) ;
277 streng
*Str_nocat_TSD( const tsd_t
*TSD
, streng
*first
, const streng
*second
, int length
, int offset
)
282 assert( second
->len
+ 1 >= offset
+ length
) ;
284 tmp
= second
->len
- offset
;
285 if (tmp
<0 || tmp
>length
)
288 ptr
= assure( TSD
, first
, first
->len
+ tmp
);
289 memcpy( &first
->value
[first
->len
], &second
->value
[offset
], tmp
) ;
296 streng
*Str_cat( streng
*first
, const streng
*second
)
298 return Str_cat_TSD( __regina_get_tsd(), first
, second
) ;
301 streng
*Str_cat_TSD( const tsd_t
*TSD
, streng
*first
, const streng
*second
)
306 ptr
= assure( TSD
, first
, (tmp
=Str_len(first
)+Str_len(second
)) ) ;
307 memcpy( &ptr
->value
[Str_len(first
)], second
->value
, Str_len(second
) ) ;
314 streng
*Str_ncat( streng
*first
, const streng
*second
, int length
)
316 return Str_ncat_TSD( __regina_get_tsd(), first
, second
, length
) ;
319 streng
*Str_ncat_TSD( const tsd_t
*TSD
, streng
*first
, const streng
*second
, int length
)
324 ptr
= assure( TSD
, first
, Str_len(first
) + (tmp
=MIN(length
,Str_len(second
))) ) ;
325 memcpy( &ptr
->value
[Str_len(first
)], second
->value
, tmp
) ;
333 int Str_cmp( const streng
*first
, const streng
*second
)
338 if (lim
!= second
->len
)
341 return memcmp( first
->value
, second
->value
, lim
) ;
346 int Str_ccmp( const streng
*first
, const streng
*second
)
350 if (Str_len(first
) != Str_len(second
))
353 for (tmp
=0; tmp
<Str_len(first
); tmp
++ )
354 if (RXTOLOW(first
->value
[tmp
]) != RXTOLOW(second
->value
[tmp
]))
361 int Str_cncmp( const streng
*first
, const streng
*second
, int length
)
363 int tmp
=0, top
=0, shorter
=0 ;
365 shorter
= MIN( Str_len(first
), Str_len(second
) ) ;
366 if ( ( shorter
<length
) && (Str_len(first
) != Str_len(second
)) )
369 top
= MIN( shorter
, length
) ;
370 for (tmp
=0; tmp
<top
; tmp
++ )
371 if (RXTOLOW(first
->value
[tmp
]) != RXTOLOW(second
->value
[tmp
]))
378 int Str_cnocmp( const streng
*first
, const streng
*second
, int length
, int offset
)
380 int tmp
=0, top
=0, shorter
=0 ;
382 shorter
= MIN( Str_len(first
), Str_len(second
)-offset
) ;
383 if ( ( shorter
<length
) && (Str_len(first
) != Str_len(second
)-offset
) )
386 top
= MIN( shorter
, length
) ;
387 for (tmp
=0; tmp
<top
; tmp
++ )
388 if (RXTOLOW(first
->value
[tmp
]) != RXTOLOW(second
->value
[offset
+tmp
]))
395 char *str_of( const tsd_t
*TSD
, const streng
*input
)
396 /* returns a 0-terminated copy of the string-value of input. Free it with
400 char *retval
= MallocTSD( Str_len(input
) + 1 ) ;
402 memcpy( retval
, input
->value
, Str_len(input
) ) ;
403 retval
[Str_len(input
)] = '\0' ;
407 volatile char *tmpstr_of( tsd_t
*TSD
, const streng
*input
)
408 /* returns a temporarily allocated 0-terminated copy of the string-value of
409 * input. Never free it explicitely. There is storage for 7 parallel living
410 * strings. The oldest will be deleted first. The main purpose of this function
411 * is to get a 0-terminated string of a streng for a very short time,
412 * e.g. exiterror. Since exiterror longjmp's back to another place, you
413 * don't have any chance to free up the allocated string. This is done now
415 * Call this function with NULL as the argument to free all temporary strings.
416 * WARNING: This function insn't thread-safe and won't ever be! Move the
417 * variable strs to the thread-specific memory to be thread-safe.
424 for (i
= 0; i
< sizeof(TSD
->tmp_strs
) / sizeof(TSD
->tmp_strs
[0]); i
++)
426 if (TSD
->tmp_strs
[i
] != NULL
)
428 FreeTSD( (char *) TSD
->tmp_strs
[i
] ) ;
429 TSD
->tmp_strs
[i
] = NULL
;
432 TSD
->next_tmp_str
= 0;
436 /* allocate a new one */
437 if (TSD
->tmp_strs
[TSD
->next_tmp_str
] != NULL
)
438 FreeTSD( (char *) TSD
->tmp_strs
[TSD
->next_tmp_str
] ) ;
439 /* keep exiterror within Malloc in mind */
440 TSD
->tmp_strs
[TSD
->next_tmp_str
] = NULL
;
441 TSD
->tmp_strs
[TSD
->next_tmp_str
] = str_of( TSD
, input
) ;
442 i
= TSD
->next_tmp_str
;
444 if (++TSD
->next_tmp_str
>= sizeof(TSD
->tmp_strs
) / sizeof(TSD
->tmp_strs
[0]))
445 TSD
->next_tmp_str
= 0 ;
447 return TSD
->tmp_strs
[i
] ;
450 streng
*Str_ncatstr( streng
*base
, const char *input
, int length
)
452 return Str_ncatstr_TSD( __regina_get_tsd(), base
, input
, length
) ;
455 streng
*Str_ncatstr_TSD( const tsd_t
*TSD
, streng
*base
, const char *input
, int length
)
460 top
= MIN( (int) strlen(input
), length
) ;
461 ptr
= assure( TSD
, base
, Str_len(base
) + top
) ;
462 memcpy( &ptr
->value
[Str_len(ptr
)], input
, top
) ;
468 streng
*Str_upper( streng
*input
)
470 register int len
= Str_len(input
);
471 char *val
= input
->value
;
475 /* I think we don't need to check for islower before the toupper, FGC */
476 *val
= (char) toupper(*val
);
482 streng
*Str_strp( streng
*input
, char chr
, char opt
)
484 register int i
=0,j
=0;
489 if (opt
& STRIP_TRAILING
)
491 for (i
=(input
->len
)-1;i
>-1;i
--)
493 if (input
->value
[i
] != chr
)
498 if (opt
& STRIP_LEADING
)
500 for (j
=0;j
<input
->len
;j
++)
501 if (input
->value
[j
] != chr
)
503 for (i
=0;j
<input
->len
;i
++,j
++)
504 input
->value
[i
] = input
->value
[j
];
510 char *str_trans(char *str
,char oldch
,char newch
)
512 * Function : Translate all occurrences of oldch to newch in str
513 * Parameters: *str - string to be amended
514 * oldch - character to be replaced
515 * newch - character to replace oldch
516 * Return : same string but with characters translated
525 if (*(str
+i
) == oldch
)
531 int mem_cmpic( const char *buf1
, const char *buf2
, int len
)
533 * Function : Compares two memory buffers for equality;
534 * case insensitive. Same as memicmp() Microsoft C.
535 * Parameters: buf1 - first buffer
536 * buf2 - second buffer
537 * len - number of characters to compare.
538 * Return : <0 if buf1 < buf2
544 unsigned char c1
,c2
; /* allow 8-bit characters to order correctly */
546 for( i
= 0; i
< len
; i
++ )
548 c1
= (unsigned char) ((isupper(*buf1
)) ? tolower(*buf1
) : *buf1
);
549 c2
= (unsigned char) ((isupper(*buf2
)) ? tolower(*buf2
) : *buf2
);