2828
2929#include <ctype.h>
3030#include <inttypes.h>
31+ #include <stdarg.h>
32+ #include <stddef.h>
3133#include <stdio.h>
3234
35+ //TODO use macro from utils
36+ #ifndef CONTAINER_OF
37+ #define CONTAINER_OF (ptr , type , member ) \
38+ ((type *) (((char *) (ptr)) - offsetof(type, member)))
39+ #endif
40+
41+ struct FprintfFun
42+ {
43+ PrinterFun base ;
44+ FILE * stream ;
45+ };
46+
3347const term empty_tuple = 0 ;
3448
49+ int fprintf_printer (PrinterFun * fun , const char * fmt , ...)
50+ {
51+ int ret ;
52+
53+ va_list args ;
54+ va_start (args , fmt );
55+
56+ FILE * stream = CONTAINER_OF (fun , struct FprintfFun , base )-> stream ;
57+ ret = vfprintf (stream , fmt , args );
58+
59+ va_end (args );
60+
61+ return ret ;
62+ }
63+
3564void term_display (FILE * fd , term t , const Context * ctx )
3665{
3766 term_fprint (fd , t , ctx -> global );
3867}
3968
40- void term_fprint (FILE * fd , term t , const GlobalContext * global )
69+ int term_fprint (FILE * stream , term t , const GlobalContext * global )
70+ {
71+ struct FprintfFun fprintf_fun = {
72+ .base = {
73+ .print = fprintf_printer
74+ },
75+ .stream = stream
76+ };
77+
78+ return term_funprint (& fprintf_fun .base , t , global );
79+ }
80+
81+ int term_funprint (PrinterFun * fun , term t , const GlobalContext * global )
4182{
4283 if (term_is_atom (t )) {
4384 int atom_index = term_to_atom_index (t );
4485 AtomString atom_string = (AtomString ) valueshashtable_get_value (
4586 global -> atoms_ids_table , atom_index , (unsigned long ) NULL );
46- fprintf (fd , "%.*s" , (int ) atom_string_len (atom_string ), (char * ) atom_string_data (atom_string ));
87+ return fun -> print (fun , "%.*s" , (int ) atom_string_len (atom_string ),
88+ (char * ) atom_string_data (atom_string ));
4789
4890 } else if (term_is_integer (t )) {
4991 avm_int_t iv = term_to_int (t );
50- fprintf ( fd , AVM_INT_FMT , iv );
92+ return fun -> print ( fun , AVM_INT_FMT , iv );
5193
5294 } else if (term_is_nil (t )) {
53- fprintf ( fd , "[]" );
95+ return fun -> print ( fun , "[]" );
5496
5597 } else if (term_is_nonempty_list (t )) {
5698 int is_printable = 1 ;
@@ -69,33 +111,55 @@ void term_fprint(FILE *fd, term t, const GlobalContext *global)
69111 int ok ;
70112 char * printable = interop_list_to_string (t , & ok );
71113 if (LIKELY (ok )) {
72- fprintf ( fd , "\"%s\"" , printable );
114+ int ret = fun -> print ( fun , "\"%s\"" , printable );
73115 free (printable );
116+ return ret ;
74117 } else {
75- fprintf ( fd , "???" );
118+ return fun -> print ( fun , "???" );
76119 }
77120
78121 } else {
79- fputc ('[' , fd );
122+ int ret = fun -> print (fun , "[" );
123+ if (UNLIKELY (ret < 0 )) {
124+ return ret ;
125+ }
80126 int display_separator = 0 ;
81127 while (term_is_nonempty_list (t )) {
82128 if (display_separator ) {
83- fputc ( ',' , fd );
129+ ret += fun -> print ( fun , "," );
84130 } else {
85131 display_separator = 1 ;
86132 }
87133
88- term_fprint (fd , term_get_list_head (t ), global );
134+ int printed = term_funprint (fun , term_get_list_head (t ), global );
135+ if (UNLIKELY (printed < 0 )) {
136+ return printed ;
137+ }
138+ ret += printed ;
89139 t = term_get_list_tail (t );
90140 }
91141 if (!term_is_nil (t )) {
92- fputc ('|' , fd );
93- term_fprint (fd , t , global );
142+ int printed = fun -> print (fun , "|" );
143+ if (UNLIKELY (printed < 0 )) {
144+ return printed ;
145+ }
146+ ret += printed ;
147+
148+ printed = term_funprint (fun , t , global );
149+ if (UNLIKELY (printed < 0 )) {
150+ return printed ;
151+ }
152+ ret += printed ;
153+ }
154+ int printed = fun -> print (fun , "]" );
155+ if (UNLIKELY (printed < 0 )) {
156+ return printed ;
94157 }
95- fputc (']' , fd );
158+ ret += printed ;
159+ return ret ;
96160 }
97161 } else if (term_is_pid (t )) {
98- fprintf ( fd , "<0.%i.0>" , term_to_local_process_id (t ));
162+ return fun -> print ( fun , "<0.%i.0>" , term_to_local_process_id (t ));
99163
100164 } else if (term_is_function (t )) {
101165 const term * boxed_value = term_to_const_term_ptr (t );
@@ -107,35 +171,77 @@ void term_fprint(FILE *fd, term t, const GlobalContext *global)
107171 #else
108172 "#Fun<erl_eval.%lu.%llu>" ;
109173 #endif
110- fprintf ( fd , format , fun_index , (unsigned long ) fun_module );
174+ return fun -> print ( fun , format , fun_index , (unsigned long ) fun_module );
111175
112176 } else if (term_is_tuple (t )) {
113- fputc ('{' , fd );
177+ int ret = fun -> print (fun , "{" );
178+ if (UNLIKELY (ret < 0 )) {
179+ return ret ;
180+ }
114181
115182 int tuple_size = term_get_tuple_arity (t );
116183 for (int i = 0 ; i < tuple_size ; i ++ ) {
117184 if (i != 0 ) {
118- fputc (',' , fd );
185+ int printed = fun -> print (fun , "," );
186+ if (UNLIKELY (printed < 0 )) {
187+ return printed ;
188+ }
189+ ret += printed ;
190+ }
191+ int printed = term_funprint (fun , term_get_tuple_element (t , i ), global );
192+ if (UNLIKELY (printed < 0 )) {
193+ return printed ;
119194 }
120- term_fprint ( fd , term_get_tuple_element ( t , i ), global ) ;
195+ ret += printed ;
121196 }
122197
123- fputc ('}' , fd );
198+ int printed = fun -> print (fun , "}" );
199+ if (UNLIKELY (printed < 0 )) {
200+ return printed ;
201+ }
202+ ret += printed ;
203+ return ret ;
124204
125205 } else if (term_is_map (t )) {
126- fprintf (fd , "#{" );
206+ int ret = fun -> print (fun , "#{" );
207+ if (UNLIKELY (ret < 0 )) {
208+ return ret ;
209+ }
127210
128211 int map_size = term_get_map_size (t );
129212 for (int i = 0 ; i < map_size ; i ++ ) {
130213 if (i != 0 ) {
131- fputc (',' , fd );
214+ int printed = fun -> print (fun , "," );
215+ if (UNLIKELY (printed < 0 )) {
216+ return printed ;
217+ }
218+ ret += printed ;
219+ }
220+ int printed = term_funprint (fun , term_get_map_key (t , i ), global );
221+ if (UNLIKELY (printed < 0 )) {
222+ return printed ;
223+ }
224+ ret += printed ;
225+
226+ printed = fun -> print (fun , "=>" );
227+ if (UNLIKELY (printed < 0 )) {
228+ return printed ;
229+ }
230+ ret += printed ;
231+
232+ printed = term_funprint (fun , term_get_map_value (t , i ), global );
233+ if (UNLIKELY (printed < 0 )) {
234+ return printed ;
132235 }
133- term_fprint (fd , term_get_map_key (t , i ), global );
134- fprintf (fd , "=>" );
135- term_fprint (fd , term_get_map_value (t , i ), global );
236+ ret += printed ;
136237 }
137238
138- fputc ('}' , fd );
239+ int printed = fun -> print (fun , "}" );
240+ if (UNLIKELY (printed < 0 )) {
241+ return printed ;
242+ }
243+ ret += printed ;
244+ return ret ;
139245
140246 } else if (term_is_binary (t )) {
141247 int len = term_binary_size (t );
@@ -149,24 +255,45 @@ void term_fprint(FILE *fd, term t, const GlobalContext *global)
149255 }
150256 }
151257
152- fprintf (fd , "<<" );
258+ int ret = fun -> print (fun , "<<" );
259+ if (UNLIKELY (ret < 0 )) {
260+ return ret ;
261+ }
262+
153263 if (is_printable ) {
154- fprintf (fd , "\"%.*s\"" , len , binary_data );
264+ int printed = fun -> print (fun , "\"%.*s\"" , len , binary_data );
265+ if (UNLIKELY (printed < 0 )) {
266+ return printed ;
267+ }
268+ ret += printed ;
155269
156270 } else {
157271 int display_separator = 0 ;
158272 for (int i = 0 ; i < len ; i ++ ) {
159273 if (display_separator ) {
160- fputc (',' , fd );
274+ int printed = fun -> print (fun , "," );
275+ if (UNLIKELY (printed < 0 )) {
276+ return printed ;
277+ }
278+ ret += printed ;
161279 } else {
162280 display_separator = 1 ;
163281 }
164282
165283 uint8_t c = (uint8_t ) binary_data [i ];
166- fprintf (fd , "%i" , (int ) c );
284+ int printed = fun -> print (fun , "%i" , (int ) c );
285+ if (UNLIKELY (printed < 0 )) {
286+ return printed ;
287+ }
288+ ret += printed ;
167289 }
168290 }
169- fprintf (fd , ">>" );
291+ int printed = fun -> print (fun , ">>" );
292+ if (UNLIKELY (printed < 0 )) {
293+ return printed ;
294+ }
295+ ret += printed ;
296+ return ret ;
170297
171298 } else if (term_is_reference (t )) {
172299 const char * format =
@@ -175,30 +302,28 @@ void term_fprint(FILE *fd, term t, const GlobalContext *global)
175302#else
176303 "#Ref<0.0.0.%lu>" ;
177304#endif
178- fprintf ( fd , format , term_to_ref_ticks (t ));
305+ return fun -> print ( fun , format , term_to_ref_ticks (t ));
179306
180307 } else if (term_is_boxed_integer (t )) {
181308 int size = term_boxed_size (t );
182309 switch (size ) {
183310 case 1 :
184- fprintf (fd , AVM_INT_FMT , term_unbox_int (t ));
185- break ;
311+ return fun -> print (fun , AVM_INT_FMT , term_unbox_int (t ));
186312
187313#if BOXED_TERMS_REQUIRED_FOR_INT64 == 2
188314 case 2 :
189- fprintf (fd , AVM_INT64_FMT , term_unbox_int64 (t ));
190- break ;
315+ return fun -> print (fun , AVM_INT64_FMT , term_unbox_int64 (t ));
191316#endif
192-
193317 default :
194318 AVM_ABORT ();
195319 }
196320
197321 } else if (term_is_float (t )) {
198322 avm_float_t f = term_to_float (t );
199- fprintf (fd , AVM_FLOAT_FMT , f );
323+ return fun -> print (fun , AVM_FLOAT_FMT , f );
324+
200325 } else {
201- fprintf ( fd , "Unknown term type: %" TERM_U_FMT , t );
326+ return fun -> print ( fun , "Unknown term type: %" TERM_U_FMT , t );
202327 }
203328}
204329
0 commit comments