@@ -3049,6 +3049,85 @@ static node_idx_t native_prn_str(env_ptr_t env, list_ptr_t args) {
3049
3049
return new_node_string (s);
3050
3050
}
3051
3051
3052
+ static node_idx_t native_printf (env_ptr_t env, list_ptr_t args) {
3053
+ list_t ::iterator it (args);
3054
+ if (!it) {
3055
+ warnf (" printf requires at least a format string argument\n " );
3056
+ return NIL_NODE;
3057
+ }
3058
+
3059
+ // Get format string
3060
+ node_t * format_node = get_node (*it);
3061
+ if (format_node->type != NODE_STRING) {
3062
+ warnf (" printf first argument must be a string\n " );
3063
+ return NIL_NODE;
3064
+ }
3065
+
3066
+ jo_string format_str = format_node->t_string ;
3067
+ ++it;
3068
+
3069
+ // Collect all arguments into a vector
3070
+ std::vector<node_idx_t > arg_values;
3071
+ for (; it; ++it) {
3072
+ arg_values.push_back (*it);
3073
+ }
3074
+
3075
+ // Process format string
3076
+ size_t pos = 0 ;
3077
+ size_t arg_index = 0 ;
3078
+
3079
+ while (pos < format_str.length ()) {
3080
+ if (format_str[pos] == ' %' && pos + 1 < format_str.length ()) {
3081
+ if (format_str[pos + 1 ] == ' %' ) {
3082
+ // Escaped % character
3083
+ printf (" %%" );
3084
+ pos += 2 ;
3085
+ } else {
3086
+ // The next character is the format specifier (simplified approach)
3087
+ char format_char = format_str[pos + 1 ];
3088
+
3089
+ if (arg_index >= arg_values.size ()) {
3090
+ warnf (" printf: not enough arguments for format string\n " );
3091
+ return NIL_NODE;
3092
+ }
3093
+
3094
+ node_idx_t arg = arg_values[arg_index++];
3095
+
3096
+ switch (format_char) {
3097
+ case ' d' :
3098
+ case ' i' :
3099
+ printf (" %lld" , get_node_int (arg));
3100
+ break ;
3101
+ case ' f' :
3102
+ case ' g' :
3103
+ printf (" %g" , get_node_float (arg));
3104
+ break ;
3105
+ case ' s' :
3106
+ {
3107
+ node_t * str_node = get_node (arg);
3108
+ if (str_node->type == NODE_STRING) {
3109
+ printf (" %s" , str_node->t_string .c_str ());
3110
+ } else {
3111
+ printf (" %s" , get_node_string (arg).c_str ());
3112
+ }
3113
+ }
3114
+ break ;
3115
+ default :
3116
+ // Just add the argument's string representation
3117
+ printf (" %s" , get_node_string (arg).c_str ());
3118
+ break ;
3119
+ }
3120
+ pos += 2 ; // Move past the % and the format specifier
3121
+ }
3122
+ } else {
3123
+ // Regular character - print directly
3124
+ printf (" %c" , format_str[pos++]);
3125
+ }
3126
+ }
3127
+
3128
+ fflush (stdout);
3129
+ return NIL_NODE;
3130
+ }
3052
3131
static node_idx_t native_do (env_ptr_t env, list_ptr_t args) {
3053
3132
return eval_node_list (env, args);
3054
3133
}
@@ -6038,7 +6117,6 @@ static node_idx_t native_set_q(env_ptr_t env, list_ptr_t args) {
6038
6117
// Returns the first logical true value of (pred x) for any x in coll,
6039
6118
// else nil. One common idiom is to use a set as pred, for example
6040
6119
// this will return :fred if :fred is in the sequence, otherwise nil:
6041
- // (some #{:fred} coll)
6042
6120
static node_idx_t native_some (env_ptr_t env, list_ptr_t args) {
6043
6121
node_idx_t pred_idx = args->first_value ();
6044
6122
node_idx_t coll_idx = args->second_value ();
@@ -6541,6 +6619,7 @@ int main(int argc, char **argv) {
6541
6619
env->set (" prn" , new_node_native_function (" prn" , &native_prn, false , NODE_FLAG_PRERESOLVE));
6542
6620
env->set (" pr-str" , new_node_native_function (" pr-str" , &native_pr_str, false , NODE_FLAG_PRERESOLVE));
6543
6621
env->set (" prn-str" , new_node_native_function (" prn-str" , &native_prn_str, false , NODE_FLAG_PRERESOLVE));
6622
+ env->set (" printf" , new_node_native_function (" printf" , &native_printf, false , NODE_FLAG_PRERESOLVE));
6544
6623
env->set (" =" , new_node_native_function (" =" , &native_eq, false , NODE_FLAG_PRERESOLVE));
6545
6624
env->set (" ==" , new_node_native_function (" ==" , &native_eq, false , NODE_FLAG_PRERESOLVE));
6546
6625
env->set (" not=" , new_node_native_function (" not=" , &native_neq, false , NODE_FLAG_PRERESOLVE));
0 commit comments