2 * ARexx functions for regina
3 * Copyright © 2002, Staf Verhaegen
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.
20 /* This files contains functions that are implemented in ARexx
21 * but that are not standard REXX functions. This file contains
22 * the functions that can be used on all platforms. amifuncs.c
23 * contains the ARexx functions that are only usable on the
24 * amiga platform or compatibles. (not implemented yet)
33 #if !defined(__WINS__) && !defined(__EPOC32__)
36 # define DBL_EPSILON 2.2204460492503131e-016
43 staticstreng(_fname
, "F");
44 staticstreng(_fstem
, "FI.F");
46 #if defined(_AMIGA) || defined(__AROS__)
47 # include <exec/memory.h>
48 # include <proto/exec.h>
51 typedef struct _arexx_tsd_t
{
56 unsigned long ah
,al
,Xnh
,Xnl
,c
;
60 #if !defined( HAVE_DIV )
67 typedef struct _ldiv_t
73 div_t div(int x
,int y
)
81 ldiv_t ldiv(long x
,long y
)
91 * Init thread data for arexx functions.
93 int init_arexxf( tsd_t
*TSD
)
97 if ( TSD
->arx_tsd
!= NULL
)
100 if ( ( TSD
->arx_tsd
= MallocTSD( sizeof( arexx_tsd_t
) ) ) == NULL
)
102 at
= (arexx_tsd_t
*)TSD
->arx_tsd
;
103 memset( at
, 0, sizeof( arexx_tsd_t
) );
105 /* glibc's starting value is 0 for the whole Xn, we use a seed of 0x1234ABCD */
107 at
->a
= rx_mk64u( 0x0005DEECE66D );
108 at
->Xn
= rx_mk64u( 0x1234ABCD330E );
112 at
->al
= 0xDEECE66Dul
;
114 at
->Xnl
= 0xABCD330Eul
;
121 * The implementation of srand48 and drand48 with fixed values in a thread safe
124 * We have to produce a value in the interval [0,1[ (zero until one but
125 * without one) from a 48 bit unsigned integer. This is done by a division by
126 * the maximum value corrected by small double. This small double is computed
127 * from the constant DBL_EPSILON.
129 * / a) 1+e > 1 and e > 0
130 * DBL_EPSILON = e with both
131 * \ b) there is no number e', e' < e
133 * We increase the divisor of 2**48-1 by (2**48-1)*DBL_EPSILON and have
134 * the wanted final divisor. That is with 2**48 - 1 = 281474976710655
136 #define twoE48m1 281474976710655.0
137 #define divisor ( twoE48m1 * ( 1.0 + DBL_EPSILON ) )
141 * srand48 sets the upper 32 bit of Xn. The lower 16 bit are set to 330E.
143 static void rx_srand48( const tsd_t
*TSD
, unsigned long ul
)
145 arexx_tsd_t
*at
= (arexx_tsd_t
*)TSD
->arx_tsd
;
148 ull
= ul
& 0xFFFFFFFF;
150 at
->Xn
= ull
| 0x330E;
154 * Compute X(n+1) = a * X(n) + c
156 static double rng( arexx_tsd_t
*at
)
160 Xn1
= at
->a
* at
->Xn
+ at
->c
;
161 at
->Xn
= Xn1
& rx_mk64u( 0xFFFFFFFFFFFF );
164 return (double) (signed __int64
) at
->Xn
;
166 return (double) at
->Xn
;
170 static void rx_srand48( const tsd_t
*TSD
, unsigned long ul
)
172 arexx_tsd_t
*at
= TSD
->arx_tsd
;
174 at
->Xnh
= ( ul
>> 16 ) & 0xFFFF;
175 at
->Xnl
= ( ( ul
& 0xFFFF ) << 16 ) | 0x330E;
178 static double rng( arexx_tsd_t
*at
)
181 unsigned long Xn1h
,Xn1l
;
182 unsigned long h
,al
,ah
,bl
,bh
;
184 * Doing 64 bit multiplication and addition by hand.
187 * be A = ah*H + al, with ah<H and al<H
188 * be B = bh*H + bl, with bh<H and bl<H
190 * then we can compute A*B as:
192 * (ah*H+al)*(bh*H+bl) = ah*bh*H*H +
197 * We have to add an additional term c, c small and we operate modulo
198 * 2**48-1. This keeps life simple because we may throw away the
199 * term ah*bh*H*H because the number is greater as 2**48 without rest.
201 * Furthermore we don't have to bother about carries in the multiplication
202 * and addition of ah*bl*H and al*bh*H. Finally the term c is so small that
203 * al*bl+c won't have any further carrying operation.
205 * Indeed, because we want the lower 16 bit part of ah*bl+bh*al, we can
206 * compute as usual, add the carry of al*bl+c and that's it.
208 * There is just one lack:
209 * We need everything of al*bl. So we have to compute as above but with
210 * 16 bit unsigneds to let the product be littler than 2**32.
212 * Perfrom this 16 bit operations first.
215 al
= at
->al
& 0xFFFF;
217 bl
= at
->Xnl
& 0xFFFF;
221 Xn1l
= h
& 0xFFFF; /* done lower 16 bit */
224 * Process the *H, H=16 part. Every overflow in addition will be in the
225 * 48 bit counted from 0, so the final modulo will cut it. Therefore
226 * we are allowed to ignore every overflow.
229 h
+= al
* bh
+ ah
* bl
;
230 Xn1l
|= (h
<< 16) & 0xFFFF0000; /* done middle 16 bit */
236 * Now do the ah*bl*H + bh*al+H for the outer 32 bit operation.
238 Xn1h
+= at
->ah
* at
->Xnl
+ at
->al
* at
->Xnh
;
239 at
->Xnh
= Xn1h
& 0xFFFF;
243 retval
*= 4294967296.0l;
251 * Map a random value computed by rng of the range [0,2**48[ to the
254 static double rx_drand48( const tsd_t
*TSD
)
256 arexx_tsd_t
*at
= (arexx_tsd_t
*)TSD
->arx_tsd
;
259 big
= (double) rng( at
);
261 return (double) big
/ divisor
;
265 * Support functions for the ARexx IO functions
267 /* setamilevel will change the environment to the variables used for open files */
268 static proclevel
setamilevel( tsd_t
*TSD
)
270 arexx_tsd_t
*atsd
= (arexx_tsd_t
*)TSD
->arx_tsd
;
271 proclevel oldlevel
= TSD
->currlevel
;
273 if (atsd
->amilevel
!=NULL
)
274 TSD
->currlevel
= atsd
->amilevel
;
279 atsd
->amilevel
= newlevel( TSD
, NULL
);
281 TSD
->currlevel
= atsd
->amilevel
;
283 setvalue( TSD
, _fname
, Str_cre_TSD( TSD
, "STDIN" ), -1 );
284 sprintf( txt
, "%p", stdin
);
285 setvalue( TSD
, _fstem
, Str_cre_TSD( TSD
, txt
), -1 );
287 setvalue( TSD
, _fname
, Str_cre_TSD( TSD
, "STDOUT" ), -1 );
288 sprintf( txt
, "%p", stdout
);
289 setvalue( TSD
, _fstem
, Str_cre_TSD( TSD
, txt
), -1 );
291 setvalue( TSD
, _fname
, Str_cre_TSD( TSD
, "STDERR" ), -1 );
292 sprintf( txt
, "%p", stderr
);
293 setvalue( TSD
, _fstem
, Str_cre_TSD( TSD
, txt
), -1 );
300 /* getfile will return the FILE pointer of given name */
301 static FILE *getfile( tsd_t
*TSD
, const streng
*name
)
303 proclevel oldlevel
= setamilevel( TSD
);
308 setvalue( TSD
, _fname
, Str_dup_TSD( TSD
, name
), -1 );
309 if ( isvariable( TSD
, _fstem
) )
311 s
= getvalue( TSD
, _fstem
, -1 );
312 txt
= str_of( TSD
, s
);
313 sscanf( txt
, "%p", &file
);
317 TSD
->currlevel
= oldlevel
;
323 /* getfilenames will return a list of all opened files */
324 static streng
*getfilenames( tsd_t
*TSD
, const streng
*sep
)
326 proclevel oldlevel
= setamilevel( TSD
);
327 streng
*retval
= NULL
, *tmpstr
;
331 get_next_variable( TSD
, 1 );
332 for ( var
= get_next_variable( TSD
, 0);
334 var
= get_next_variable( TSD
, 0) )
336 while ( var
!= NULL
&& var
->realbox
!= NULL
)
339 if ( var
!= NULL
&& ( (var
->flag
& (VFLAG_STR
| VFLAG_NUM
)) || var
->stem
) )
343 retval
= Str_dup_TSD( TSD
, var
->name
);
348 tmpstr
= Str_cat_TSD( TSD
, retval
, sep
);
349 if ( tmpstr
!= retval
)
351 Free_string_TSD( TSD
, retval
);
354 tmpstr
= Str_cat_TSD( TSD
, retval
, var
->name
);
355 if ( tmpstr
!= retval
)
357 Free_string_TSD( TSD
, retval
);
364 TSD
->currlevel
= oldlevel
;
366 /* If no variable present return NULL string */
368 retval
= nullstringptr();
373 /* addfile: store the FILE pointer in a given name */
374 static void addfile( tsd_t
*TSD
, const streng
*name
, FILE *file
)
376 proclevel oldlevel
= setamilevel( TSD
);
380 sprintf( txt
, "%p", (void *)file
);
381 s
= Str_cre_TSD( TSD
, txt
);
382 setvalue( TSD
, _fname
, Str_dup_TSD( TSD
, name
), -1 );
383 setvalue( TSD
, _fstem
, s
, -1 );
385 TSD
->currlevel
= oldlevel
;
389 /* rmfile: remove a given of open files list */
390 static void rmfile( tsd_t
*TSD
, const streng
*name
)
392 arexx_tsd_t
*atsd
= (arexx_tsd_t
*)TSD
->arx_tsd
;
393 proclevel oldlevel
= setamilevel( TSD
);
395 TSD
->currlevel
= atsd
->amilevel
;
397 drop_var( TSD
, name
);
399 TSD
->currlevel
= oldlevel
;
405 * Implementation of the ARexx IO functions
406 * See general documentation for more information
407 * Functions implemented: OPEN, CLOSE, READCH, READLN, WRITECH, WRITELN, EOF, SEEK
409 streng
*arexx_open( tsd_t
*TSD
, cparamboxptr parm1
)
411 cparamboxptr parm2
, parm3
;
415 static const char* modestrings
[] = {
421 checkparam( parm1
, 2, 3, "OPEN" );
425 file
= getfile( TSD
, parm1
->value
);
428 return int_to_streng( TSD
, 0 );
431 filename
= str_of( TSD
, parm2
->value
);
434 || parm3
->value
==NULL
435 || parm3
->value
->len
==0 )
437 else switch( getoptionchar( TSD
, parm3
->value
, "OPEN", 3, "", "WRA" ) )
457 file
= fopen( filename
, modestrings
[mode
] );
462 return int_to_streng( TSD
, 0 );
465 addfile( TSD
, parm1
->value
, file
);
466 return int_to_streng( TSD
, 1);
470 streng
*arexx_close( tsd_t
*TSD
, cparamboxptr parm1
)
474 checkparam( parm1
, 1, 1, "CLOSE" );
476 file
= getfile( TSD
, parm1
->value
);
478 return int_to_streng( TSD
, 0 );
481 rmfile( TSD
, parm1
->value
);
483 return int_to_streng( TSD
, 1 );
487 streng
*arexx_writech( tsd_t
*TSD
, cparamboxptr parm1
)
494 checkparam( parm1
, 2, 2, "WRITECH" );
497 file
= getfile( TSD
, parm1
->value
);
499 exiterror( ERR_INCORRECT_CALL
, 27, "WRITECH", tmpstr_of( TSD
, parm1
->value
));
501 txt
= str_of( TSD
, parm2
->value
);
502 count
= fprintf( file
, "%s", txt
);
505 return int_to_streng( TSD
, count
);
509 streng
*arexx_writeln( tsd_t
*TSD
, cparamboxptr parm1
)
516 checkparam( parm1
, 2, 2, "WRITELN" );
519 file
= getfile( TSD
, parm1
->value
);
521 exiterror( ERR_INCORRECT_CALL
, 27, "WRITELN", tmpstr_of( TSD
, parm1
->value
) );
523 txt
= str_of( TSD
, parm2
->value
);
524 count
= fprintf(file
, "%s\n", txt
);
527 return int_to_streng( TSD
, count
);
531 streng
*arexx_seek( tsd_t
*TSD
, cparamboxptr parm1
)
533 cparamboxptr parm2
, parm3
;
535 int pos
, error
, wench
;
538 checkparam( parm1
, 2, 3, "SEEK" );
542 file
= getfile( TSD
, parm1
->value
);
544 exiterror( ERR_INCORRECT_CALL
, 27, "SEEK", tmpstr_of( TSD
, parm1
->value
) );
546 offset
= streng_to_int( TSD
, parm2
->value
, &error
);
548 exiterror( ERR_INCORRECT_CALL
, 11, "SEEK", 2, tmpstr_of( TSD
, parm2
->value
) );
551 || parm3
->value
==NULL
552 || parm3
->value
->len
== 0 )
554 else switch( getoptionchar( TSD
, parm3
->value
, "SEEK", 3, "", "CBE" ) )
574 pos
= fseek( file
, offset
, wench
);
575 return int_to_streng( TSD
, pos
);
579 streng
*arexx_readch( tsd_t
*TSD
, cparamboxptr parm1
)
584 checkparam( parm1
, 1, 2, "READCH");
587 file
= getfile( TSD
, parm1
->value
);
589 exiterror( ERR_INCORRECT_CALL
, 27, "READCH", tmpstr_of( TSD
, parm1
->value
) );
593 char buffer
[2] = { 0, 0 };
595 buffer
[0] = (char)getc( file
);
597 return Str_cre_TSD( TSD
, buffer
);
604 count
= streng_to_int( TSD
, parm2
->value
, &error
);
607 exiterror( ERR_INCORRECT_CALL
, 11, "READCH", 2, tmpstr_of( TSD
, parm2
->value
) );
609 exiterror( ERR_INCORRECT_CALL
, 14, "READCH", 2, tmpstr_of( TSD
, parm2
->value
) );
611 ret
= Str_makeTSD( count
);
613 count
= fread( ret
->value
, 1, count
, file
);
617 * Fixme: What shall happen in this case?
618 * Setting count to 0 seems a little bit weak for me but better
619 * than doing more strange things. FGC
623 Str_len( ret
) = count
;
630 streng
*arexx_readln( tsd_t
*TSD
, cparamboxptr parm
)
635 checkparam( parm
, 1, 1, "READLN");
637 file
= getfile( TSD
, parm
->value
);
639 exiterror( ERR_INCORRECT_CALL
, 27, "READLN", tmpstr_of( TSD
, parm
->value
) );
641 fgets( buffer
, 1001, file
);
642 if ( buffer
[strlen(buffer
)-1]=='\n' )
643 buffer
[strlen(buffer
)-1]=0;
645 return Str_cre_TSD( TSD
, buffer
);
649 streng
*arexx_eof( tsd_t
*TSD
, cparamboxptr parm
)
653 checkparam( parm
, 1, 1, "EOF" );
655 file
= getfile( TSD
, parm
->value
);
657 exiterror( ERR_INCORRECT_CALL
, 27, "EOF", tmpstr_of( TSD
, parm
->value
) );
659 return int_to_streng( TSD
, feof( file
)!=0 );
664 * Implementation of the additional conversion functions from ARexx
665 * Functions: B2C, C2B
667 streng
*arexx_b2c( tsd_t
*TSD
, cparamboxptr parm
)
672 checkparam( parm
, 1, 1, "B2C" );
675 parm2
.value
= std_b2x( TSD
, parm
);
677 ret
= std_x2c( TSD
, &parm2
);
678 Free_string_TSD( TSD
, parm2
.value
);
684 streng
*arexx_c2b( tsd_t
*TSD
, cparamboxptr parm
)
689 checkparam( parm
, 1, 1, "B2C" );
692 parm2
.value
= std_c2x( TSD
, parm
);
694 ret
= std_x2b( TSD
, &parm2
);
695 Free_string_TSD( TSD
, parm2
.value
);
702 * Implementation of the bitwise function from ARexx
703 * Functions: BITCHG, BITCLR, BITSET, BITTST, BITCOMP
705 streng
*arexx_bitchg( tsd_t
*TSD
, cparamboxptr parm1
)
709 int bit
, error
, byte
;
712 checkparam( parm1
, 2, 2, "BITCHG" );
715 bit
= streng_to_int( TSD
, parm2
->value
, &error
);
717 exiterror( ERR_INCORRECT_CALL
, 11, "BITCHG", 2, tmpstr_of( TSD
, parm2
->value
) );
719 exiterror( ERR_INCORRECT_CALL
, 13, "BITCHG", 2, tmpstr_of( TSD
, parm2
->value
) );
723 byte
= parm1
->value
->len
-dt
.quot
-1;
725 exiterror( ERR_INCORRECT_CALL
, 0 );
727 ret
= Str_dup_TSD( TSD
, parm1
->value
);
728 ret
->value
[byte
]^=(char)(1<<dt
.rem
);
733 streng
*arexx_bitclr( tsd_t
*TSD
, cparamboxptr parm1
)
737 int bit
, error
, byte
;
740 checkparam( parm1
, 2, 2, "BITCLR" );
743 bit
= streng_to_int( TSD
, parm2
->value
, &error
);
745 exiterror( ERR_INCORRECT_CALL
, 11, "BITCLR", 2, tmpstr_of( TSD
, parm2
->value
) );
747 exiterror( ERR_INCORRECT_CALL
, 13, "BITCLR", 2, tmpstr_of( TSD
, parm2
->value
) );
751 byte
= parm1
->value
->len
-dt
.quot
-1;
753 exiterror( ERR_INCORRECT_CALL
, 0 );
755 ret
= Str_dup_TSD( TSD
, parm1
->value
);
756 ret
->value
[byte
]&=~(char)(1<<dt
.rem
);
761 streng
*arexx_bitset( tsd_t
*TSD
, cparamboxptr parm1
)
765 int bit
, error
, byte
;
768 checkparam( parm1
, 2, 2, "BITSET" );
771 bit
= streng_to_int( TSD
, parm2
->value
, &error
);
773 exiterror( ERR_INCORRECT_CALL
, 11, "BITSET", 2, tmpstr_of( TSD
, parm2
->value
) );
775 exiterror( ERR_INCORRECT_CALL
, 13, "BITSET", 2, tmpstr_of( TSD
, parm2
->value
) );
779 byte
= parm1
->value
->len
-dt
.quot
-1;
781 exiterror( ERR_INCORRECT_CALL
, 0 );
783 ret
= Str_dup_TSD( TSD
, parm1
->value
);
784 ret
->value
[byte
]|=(char)(1<<dt
.rem
);
789 streng
*arexx_bittst( tsd_t
*TSD
, cparamboxptr parm1
)
793 int bit
, error
, byte
;
796 checkparam( parm1
, 2, 2, "BITTST" );
799 bit
= streng_to_int( TSD
, parm2
->value
, &error
);
801 exiterror( ERR_INCORRECT_CALL
, 11, "BITTST", 2, tmpstr_of( TSD
, parm2
->value
) );
803 exiterror( ERR_INCORRECT_CALL
, 13, "BITTST", 2, tmpstr_of( TSD
, parm2
->value
) );
807 byte
= parm1
->value
->len
-dt
.quot
-1;
809 exiterror( ERR_INCORRECT_CALL
, 0 );
811 ret
= int_to_streng( TSD
, (parm1
->value
->value
[byte
] & (char)(1<<dt
.rem
))!=0 );
816 /* Help function for arexx_bitcomp */
817 static int firstbit(char c
)
833 /* This ARexx function has very weird usage of the pad byte,
834 * the shortest string is padded on the left with this byte
836 streng
*arexx_bitcomp( tsd_t
*TSD
, cparamboxptr parm1
)
838 cparamboxptr parm2
, parm3
;
839 const streng
*s1
, *s2
;
840 const char *cp1
, *cp2
;
844 checkparam( parm1
, 2, 3, "BITCOMP" );
847 /* Make s2 always shorter or equal to s1 */
848 if ( parm1
->value
->len
< parm2
->value
->len
)
857 for ( cp1
=s1
->value
+s1
->len
-1, cp2
=s2
->value
+s2
->len
-1, i
=0;
862 return int_to_streng( TSD
, i
*8 + firstbit( ( char ) ( *cp1
^ *cp2
) ) );
866 if ( parm3
==NULL
|| parm3
->value
==NULL
|| parm3
->value
->len
==0 )
869 pad
= parm3
->value
->value
[0];
876 return int_to_streng( TSD
, i
*8 + firstbit( ( char ) ( *cp1
^ pad
) ) );
879 return int_to_streng( TSD
, -1 );
884 * Some more misc. ARexx functions
885 * Functions: COMPRESS, HASH, RANDU, TRIM, UPPER
887 streng
*arexx_hash( tsd_t
*TSD
, cparamboxptr parm1
)
892 checkparam( parm1
, 1, 1, "HASH" );
894 uc
= (unsigned char *)parm1
->value
->value
;
895 for ( i
=0; i
<parm1
->value
->len
; i
++)
897 sum
= (sum
+ uc
[i
]) & 255;
900 return int_to_streng( TSD
, sum
);
904 streng
*arexx_compress( tsd_t
*TSD
, cparamboxptr parm1
)
910 checkparam( parm1
, 1, 2, "COMPRESS" );
912 match
= ( parm1
->next
!=NULL
) ? str_of( TSD
, parm1
->next
->value
) : " ";
914 ret
= Str_dup_TSD( TSD
, parm1
->value
);
915 for ( i
=start
=0; i
<ret
->len
; i
++ )
917 /* Copy char if not found */
918 if ( strchr( match
, ret
->value
[i
] )==NULL
)
920 ret
->value
[start
] = ret
->value
[i
];
926 if ( parm1
->next
!=NULL
)
927 FreeTSD( (char *)match
);
933 static const streng T_str
= { 1, 1, { .value
= "T" } };
934 static const parambox T_parm
= { NULL
, 0, (streng
*)&T_str
};
936 streng
*arexx_trim( tsd_t
*TSD
, cparamboxptr parm1
)
940 checkparam( parm1
, 1, 1, "TRIM" );
943 parm
.next
= (paramboxptr
)&T_parm
;
945 return std_strip( TSD
, &parm
);
949 streng
*arexx_upper( tsd_t
*TSD
, cparamboxptr parms
)
951 int rlength
=0, length
=0, start
=1, i
=0 ;
954 streng
*str
=NULL
, *ptr
=NULL
;
955 paramboxptr bptr
=NULL
;
958 * Check that we have between 1 and 4 args
959 * ( str [,start[,length[,pad]]] )
961 checkparam( parms
, 1, 4 , "UPPER" ) ;
963 rlength
= Str_len( str
) ;
965 * Get starting position, if supplied...
967 if ( parms
->next
!= NULL
968 && parms
->next
->value
)
969 start
= atopos( TSD
, parms
->next
->value
, "UPPER", 2 ) ;
971 * Get length, if supplied...
973 if ( parms
->next
!= NULL
974 && ( (bptr
= parms
->next
->next
) != NULL
)
975 && ( parms
->next
->next
->value
) )
976 length
= atozpos( TSD
, parms
->next
->next
->value
, "UPPER", 3 ) ;
978 length
= ( rlength
>= start
) ? rlength
- start
+ 1 : 0;
980 * Get pad character, if supplied...
984 && ( bptr
->next
->value
) )
985 padch
= getonechar( TSD
, parms
->next
->next
->next
->value
, "UPPER", 4) ;
987 * Create our new starting; duplicate of input string
989 ptr
= Str_makeTSD( length
);
990 memcpy( Str_val( ptr
), Str_val( str
), Str_len( str
) );
992 * Determine where to start changing case...
994 i
= ((rlength
>=start
)?start
-1:rlength
) ;
996 * Determine how many characters to change case...
998 changecount
= length
> rlength
? rlength
: length
;
1002 mem_upper( &ptr
->value
[i
], changecount
);
1004 * Append pad characters if required...
1006 if (changecount
< length
)
1007 memset(&ptr
->value
[changecount
], padch
, length
- changecount
);
1009 * Determine length of return string...
1011 ptr
->len
= (length
> rlength
) ? length
: rlength
;
1016 streng
*arexx_randu( tsd_t
*TSD
, cparamboxptr parm1
)
1022 checkparam( parm1
, 0, 1, "RANDU" );
1024 if ( ( parm1
!= NULL
) && ( parm1
->value
!= NULL
) )
1026 seed
= streng_to_int( TSD
, parm1
->value
, &error
);
1028 exiterror( ERR_INCORRECT_CALL
, 11, "RANDU", 1, tmpstr_of( TSD
, parm1
->value
) );
1030 rx_srand48( TSD
, seed
);
1033 sprintf( text
, "%.20f", rx_drand48( TSD
) );
1034 s
= Str_cre_TSD( TSD
, text
);
1035 retval
= str_format( TSD
, s
, -1, -1, -1, -1 );
1043 * Two memory allocation/deallocation functions: getspace and freespace
1045 streng
*arexx_getspace( tsd_t
*TSD
, cparamboxptr parm1
)
1050 checkparam( parm1
, 1, 1, "GETSPACE" );
1052 length
= streng_to_int( TSD
, parm1
->value
, &error
);
1054 exiterror( ERR_INCORRECT_CALL
, 11, "GETSPACE", 1, tmpstr_of( TSD
, parm1
->value
) );
1056 exiterror( ERR_INCORRECT_CALL
, 14, "GETSPACE", 1, tmpstr_of( TSD
, parm1
->value
) );
1058 ptr
= Malloc_TSD( TSD
, length
);
1059 memset( ptr
, 0, length
);
1061 exiterror( ERR_STORAGE_EXHAUSTED
, 0 );
1063 return Str_ncre_TSD( TSD
, (char *)&ptr
, sizeof(void *) );
1067 streng
*arexx_freespace( tsd_t
*TSD
, cparamboxptr parm1
)
1070 * For backwards compatibility there may be two arguments
1071 * But the second argument is ignored in regina
1073 checkparam( parm1
, 0, 2, "FREESPACE" );
1075 if ( parm1
== NULL
|| parm1
->value
== NULL
|| parm1
->value
->len
== 0 )
1076 #if defined(_AMIGA) || defined(__AROS__)
1077 return int_to_streng( TSD
, AvailMem( MEMF_ANY
) );
1079 return int_to_streng( TSD
, -1 );
1082 if ( parm1
->value
->len
!= sizeof(void *) )
1083 exiterror( ERR_INCORRECT_CALL
, 0 );
1085 Free_TSD( TSD
, *(parm1
->value
->ptr
) );
1087 return nullstringptr();
1094 * ARexx memory <-> string conversion routines: IMPORT, EXPORT, STORAGE
1096 streng
*arexx_import( tsd_t
*TSD
, cparamboxptr parm1
)
1102 checkparam( parm1
, 1, 2, "IMPORT" );
1104 if ( parm1
->value
->len
!= sizeof(void *) )
1105 exiterror( ERR_INCORRECT_CALL
, 0 );
1107 memptr
= *(parm1
->value
->ptr
);
1109 parm2
= parm1
->next
;
1110 if ( parm2
== NULL
|| parm2
->value
== NULL
|| parm2
->value
->len
== 0 )
1111 len
= strlen((char *)memptr
);
1114 len
= streng_to_int( TSD
, parm2
->value
, &error
);
1116 exiterror( ERR_INCORRECT_CALL
, 11, "IMPORT", 2, tmpstr_of( TSD
, parm2
->value
) );
1118 exiterror( ERR_INCORRECT_CALL
, 14, "IMPORT", 2, tmpstr_of( TSD
, parm2
->value
) );
1121 return Str_ncre_TSD( TSD
, (const char *)memptr
, len
);
1125 streng
*arexx_export( tsd_t
*TSD
, cparamboxptr parm1
)
1128 cparamboxptr parm2
= NULL
, parm3
= NULL
, parm4
= NULL
;
1133 checkparam( parm1
, 1, 4, "EXPORT" );
1135 if ( parm1
->value
== NULL
|| parm1
->value
->len
== 0 )
1136 exiterror( ERR_INCORRECT_CALL
, 21, "EXPORT", 1 );
1137 memptr
= *(parm1
->value
->ptr
);
1139 parm2
= parm1
->next
;
1140 if ( parm2
!= NULL
)
1141 parm3
= parm2
->next
;
1142 if ( parm3
!= NULL
)
1143 parm4
= parm3
->next
;
1145 if ( parm2
== NULL
|| parm2
->value
== NULL
|| parm2
->value
->len
== 0 )
1146 src
= nullstringptr();
1148 src
= Str_dup_TSD( TSD
, parm2
->value
);
1150 if ( parm3
== NULL
|| parm3
->value
== NULL
|| parm3
->value
->len
== 0 )
1154 len
= streng_to_int( TSD
, parm3
->value
, &error
);
1156 exiterror( ERR_INCORRECT_CALL
, 11, "EXPORT", 3, tmpstr_of( TSD
, parm3
->value
) );
1158 exiterror( ERR_INCORRECT_CALL
, 13, "EXPORT", 3, tmpstr_of( TSD
, parm3
->value
) );
1161 if ( parm4
== NULL
|| parm4
->value
== NULL
|| parm4
->value
->len
== 0 )
1164 fill
= parm4
->value
->value
[0];
1168 memcpy( memptr
, src
->value
, src
->len
);
1169 memset( ((char *)memptr
)+src
->len
, fill
, len
- src
->len
);
1172 memcpy( memptr
, src
->value
, len
);
1174 Free_string_TSD( TSD
, src
);
1176 return int_to_streng( TSD
, len
);
1180 streng
*arexx_storage( tsd_t
*TSD
, cparamboxptr parm1
)
1183 cparamboxptr parm2
= NULL
, parm3
= NULL
, parm4
= NULL
;
1186 streng
*src
, *retval
;
1188 checkparam( parm1
, 0, 4, "STORAGE" );
1190 if ( parm1
== NULL
|| parm1
->value
== NULL
)
1191 return arexx_freespace( TSD
, NULL
);
1193 if ( TSD
->restricted
)
1194 exiterror( ERR_RESTRICTED
, 1, "STORAGE" ) ;
1196 if ( parm1
->value
== NULL
|| parm1
->value
->len
== 0 )
1197 exiterror( ERR_INCORRECT_CALL
, 21, "STORAGE", 1 );
1198 memptr
= *(parm1
->value
->ptr
);
1200 parm2
= parm1
->next
;
1201 if ( parm2
!= NULL
)
1202 parm3
= parm2
->next
;
1203 if ( parm3
!= NULL
)
1204 parm4
= parm3
->next
;
1206 if ( parm2
== NULL
|| parm2
->value
== NULL
|| parm2
->value
->len
== 0 )
1207 src
= nullstringptr();
1209 src
= Str_dup_TSD( TSD
, parm2
->value
);
1211 if ( parm3
== NULL
|| parm3
->value
== NULL
|| parm3
->value
->len
== 0 )
1215 len
= streng_to_int( TSD
, parm3
->value
, &error
);
1217 exiterror( ERR_INCORRECT_CALL
, 11, "STORAGE", 3, tmpstr_of( TSD
, parm3
->value
) );
1219 exiterror( ERR_INCORRECT_CALL
, 13, "STORAGE", 3, tmpstr_of( TSD
, parm3
->value
) );
1222 if ( parm4
== NULL
|| parm4
->value
== NULL
|| parm4
->value
->len
== 0 )
1225 fill
= parm4
->value
->value
[0];
1227 retval
= Str_ncre_TSD( TSD
, (const char *)memptr
, len
);
1231 memcpy( memptr
, src
->value
, src
->len
);
1232 memset( ((char *)memptr
)+src
->len
, fill
, len
- src
->len
);
1235 memcpy( memptr
, src
->value
, len
);
1237 Free_string_TSD( TSD
, src
);
1245 * SHOW a function the names available in different resource lists
1247 streng
*arexx_show( tsd_t
*TSD
, cparamboxptr parm1
)
1249 cparamboxptr parm2
= NULL
, parm3
= NULL
;
1250 streng
*name
= NULL
, *sep
, *retval
;
1252 checkparam( parm1
, 1, 3, "SHOW" );
1253 parm2
= parm1
->next
;
1254 if ( parm2
!= NULL
)
1255 parm3
= parm2
->next
;
1257 if ( parm2
!= NULL
&& parm2
->value
!= NULL
&& parm2
->value
->len
!= 0 )
1258 name
= parm2
->value
;
1260 if ( parm3
== NULL
|| parm3
->value
== NULL
|| parm3
->value
->len
== 0 )
1261 sep
= Str_cre_TSD( TSD
, " " );
1263 sep
= Str_dup_TSD( TSD
, parm3
->value
);
1265 switch( getoptionchar( TSD
, parm1
->value
, "SHOW", 1, "", "F" ) )
1269 retval
= getfilenames( TSD
, sep
);
1272 FILE *f
= getfile( TSD
, name
);
1273 retval
= int_to_streng( TSD
, f
!= NULL
);
1277 default: /* We got an error in getoptionchar */
1281 Free_string_TSD( TSD
, sep
);