@@ -848,7 +848,8 @@ enum func_code {
848848 FN_ARG = 26 ,
849849 FN_INSTR = 27 ,
850850 FN_DEC = 28 ,
851- FN_HEX = 29
851+ FN_HEX = 29 ,
852+ FN_STRINGFN = 30
852853};
853854
854855/* Report an error and halt further execution.
@@ -1520,6 +1521,9 @@ static int function_lookup(const char *name, int len)
15201521 if ((len == 3 && name [0 ] == 'S' && name [1 ] == 'T' && name [2 ] == 'R' ) ||
15211522 (len == 4 && name [0 ] == 'S' && name [1 ] == 'T' && name [2 ] == 'R' && name [3 ] == '$' )) return FN_STR ;
15221523 if (len == 3 && name [0 ] == 'S' && name [1 ] == 'P' && name [2 ] == 'C' ) return FN_SPC ;
1524+ if ((len == 6 && name [0 ] == 'S' && name [1 ] == 'T' && name [2 ] == 'R' && name [3 ] == 'I' && name [4 ] == 'N' && name [5 ] == 'G' ) ||
1525+ (len == 7 && name [0 ] == 'S' && name [1 ] == 'T' && name [2 ] == 'R' && name [3 ] == 'I' && name [4 ] == 'N' && name [5 ] == 'G' && name [6 ] == '$' ))
1526+ return FN_STRINGFN ;
15231527 if (len == 6 && name [0 ] == 'S' && name [1 ] == 'Y' && name [2 ] == 'S' && name [3 ] == 'T' && name [4 ] == 'E' && name [5 ] == 'M' ) return FN_SYSTEM ;
15241528 return FN_NONE ;
15251529 case 'C' :
@@ -1868,7 +1872,7 @@ static struct value eval_function(const char *name, char **p)
18681872 * the closing ')'. For all other intrinsics we expect exactly one
18691873 * argument and consume ')' here so the caller resumes after it.
18701874 */
1871- if (code != FN_MID && code != FN_LEFT && code != FN_RIGHT && code != FN_INSTR ) {
1875+ if (code != FN_MID && code != FN_LEFT && code != FN_RIGHT && code != FN_INSTR && code != FN_STRINGFN ) {
18721876 if (* * p == ')' ) {
18731877 (* p )++ ;
18741878 } else {
@@ -2321,6 +2325,58 @@ static struct value eval_function(const char *name, char **p)
23212325 sprintf (outbuf , "%lX" , v );
23222326 return make_str (outbuf );
23232327 }
2328+ case FN_STRINGFN : {
2329+ /* STRING$(n, char$) or STRING$(n, code) */
2330+ struct value v_count = arg ;
2331+ struct value v_ch ;
2332+ int count ;
2333+ char ch ;
2334+
2335+ ensure_num (& v_count );
2336+ skip_spaces (p );
2337+ if (* * p != ',' ) {
2338+ runtime_error ("STRING$ requires 2 arguments" );
2339+ return make_str ("" );
2340+ }
2341+ (* p )++ ;
2342+ v_ch = eval_expr (p );
2343+ skip_spaces (p );
2344+ if (* * p == ')' ) {
2345+ (* p )++ ;
2346+ } else {
2347+ runtime_error ("Missing ')'" );
2348+ return make_str ("" );
2349+ }
2350+
2351+ count = (int )v_count .num ;
2352+ if (count <= 0 ) {
2353+ return make_str ("" );
2354+ }
2355+ if (count >= MAX_STR_LEN ) {
2356+ count = MAX_STR_LEN - 1 ;
2357+ }
2358+
2359+ if (v_ch .type == VAL_STR ) {
2360+ if (v_ch .str [0 ] == '\0' ) {
2361+ ch = ' ' ;
2362+ } else {
2363+ ch = v_ch .str [0 ];
2364+ }
2365+ } else {
2366+ /* Treat numeric second arg as character code. */
2367+ ch = (char )((int )v_ch .num & 0xff );
2368+ }
2369+
2370+ {
2371+ char out [MAX_STR_LEN ];
2372+ int i ;
2373+ for (i = 0 ; i < count ; i ++ ) {
2374+ out [i ] = ch ;
2375+ }
2376+ out [count ] = '\0' ;
2377+ return make_str (out );
2378+ }
2379+ }
23242380 case FN_UCASE : {
23252381 char out [MAX_STR_LEN ];
23262382 size_t i , n ;
@@ -2626,7 +2682,7 @@ static struct value eval_factor(char **p)
26262682 starts_with_kw (* p , "RND" ) || starts_with_kw (* p , "LEN" ) || starts_with_kw (* p , "VAL" ) ||
26272683 starts_with_kw (* p , "STR" ) || starts_with_kw (* p , "CHR" ) || starts_with_kw (* p , "ASC" ) ||
26282684 starts_with_kw (* p , "TAB" ) || starts_with_kw (* p , "SPC" ) || starts_with_kw (* p , "MID" ) ||
2629- starts_with_kw (* p , "LEFT" ) || starts_with_kw (* p , "RIGHT" ) ||
2685+ starts_with_kw (* p , "LEFT" ) || starts_with_kw (* p , "RIGHT" ) || starts_with_kw ( * p , "STRING" ) ||
26302686 starts_with_kw (* p , "UCASE" ) || starts_with_kw (* p , "LCASE" ) ||
26312687 starts_with_kw (* p , "INSTR" ) || starts_with_kw (* p , "DEC" ) || starts_with_kw (* p , "HEX" ) ||
26322688 starts_with_kw (* p , "ARGC" ) || starts_with_kw (* p , "ARG" ) ||
0 commit comments