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+
47+ struct SnprintfFun
48+ {
49+ PrinterFun base ;
50+ int size ;
51+ char * buf ;
52+ };
53+
3354const term empty_tuple = 0 ;
3455
56+ int fprintf_printer (PrinterFun * fun , const char * fmt , ...)
57+ {
58+ int ret ;
59+
60+ va_list args ;
61+ va_start (args , fmt );
62+
63+ FILE * stream = CONTAINER_OF (fun , struct FprintfFun , base )-> stream ;
64+ ret = vfprintf (stream , fmt , args );
65+
66+ va_end (args );
67+
68+ return ret ;
69+ }
70+
71+ int snprintf_printer (PrinterFun * fun , const char * fmt , ...)
72+ {
73+ int ret ;
74+
75+ va_list args ;
76+ va_start (args , fmt );
77+
78+ struct SnprintfFun * snpf = CONTAINER_OF (fun , struct SnprintfFun , base );
79+ ret = vsnprintf (snpf -> buf , snpf -> size , fmt , args );
80+ snpf -> buf += ret ;
81+ snpf -> size -= ret ;
82+
83+ va_end (args );
84+
85+ return ret ;
86+ }
87+
3588void term_display (FILE * fd , term t , const Context * ctx )
89+ {
90+ term_fprint (fd , t , ctx -> global );
91+ }
92+
93+ int term_fprint (FILE * stream , term t , const GlobalContext * global )
94+ {
95+ struct FprintfFun fprintf_fun = {
96+ .base = {
97+ .print = fprintf_printer
98+ },
99+ .stream = stream
100+ };
101+
102+ return term_funprint (& fprintf_fun .base , t , global );
103+ }
104+
105+ int term_snprint (char * buf , size_t size , term t , const GlobalContext * global )
106+ {
107+ struct SnprintfFun snprintf_fun = {
108+ .base = {
109+ .print = snprintf_printer
110+ },
111+ .buf = buf ,
112+ .size = size
113+ };
114+
115+ return term_funprint (& snprintf_fun .base , t , global );
116+ }
117+
118+ int term_funprint (PrinterFun * fun , term t , const GlobalContext * global )
36119{
37120 if (term_is_atom (t )) {
38121 int atom_index = term_to_atom_index (t );
39- AtomString atom_string = (AtomString ) valueshashtable_get_value (ctx -> global -> atoms_ids_table , atom_index , (unsigned long ) NULL );
40- fprintf (fd , "%.*s" , (int ) atom_string_len (atom_string ), (char * ) atom_string_data (atom_string ));
122+ AtomString atom_string = (AtomString ) valueshashtable_get_value (
123+ global -> atoms_ids_table , atom_index , (unsigned long ) NULL );
124+ return fun -> print (fun , "%.*s" , (int ) atom_string_len (atom_string ),
125+ (char * ) atom_string_data (atom_string ));
41126
42127 } else if (term_is_integer (t )) {
43128 avm_int_t iv = term_to_int (t );
44- fprintf ( fd , AVM_INT_FMT , iv );
129+ return fun -> print ( fun , AVM_INT_FMT , iv );
45130
46131 } else if (term_is_nil (t )) {
47- fprintf ( fd , "[]" );
132+ return fun -> print ( fun , "[]" );
48133
49134 } else if (term_is_nonempty_list (t )) {
50135 int is_printable = 1 ;
@@ -63,33 +148,55 @@ void term_display(FILE *fd, term t, const Context *ctx)
63148 int ok ;
64149 char * printable = interop_list_to_string (t , & ok );
65150 if (LIKELY (ok )) {
66- fprintf ( fd , "\"%s\"" , printable );
151+ int ret = fun -> print ( fun , "\"%s\"" , printable );
67152 free (printable );
153+ return ret ;
68154 } else {
69- fprintf ( fd , "???" );
155+ return fun -> print ( fun , "???" );
70156 }
71157
72158 } else {
73- fputc ('[' , fd );
159+ int ret = fun -> print (fun , "[" );
160+ if (UNLIKELY (ret < 0 )) {
161+ return ret ;
162+ }
74163 int display_separator = 0 ;
75164 while (term_is_nonempty_list (t )) {
76165 if (display_separator ) {
77- fputc ( ',' , fd );
166+ ret += fun -> print ( fun , "," );
78167 } else {
79168 display_separator = 1 ;
80169 }
81170
82- term_display (fd , term_get_list_head (t ), ctx );
171+ int printed = term_funprint (fun , term_get_list_head (t ), global );
172+ if (UNLIKELY (printed < 0 )) {
173+ return printed ;
174+ }
175+ ret += printed ;
83176 t = term_get_list_tail (t );
84177 }
85178 if (!term_is_nil (t )) {
86- fputc ('|' , fd );
87- term_display (fd , t , ctx );
179+ int printed = fun -> print (fun , "|" );
180+ if (UNLIKELY (printed < 0 )) {
181+ return printed ;
182+ }
183+ ret += printed ;
184+
185+ printed = term_funprint (fun , t , global );
186+ if (UNLIKELY (printed < 0 )) {
187+ return printed ;
188+ }
189+ ret += printed ;
190+ }
191+ int printed = fun -> print (fun , "]" );
192+ if (UNLIKELY (printed < 0 )) {
193+ return printed ;
88194 }
89- fputc (']' , fd );
195+ ret += printed ;
196+ return ret ;
90197 }
91198 } else if (term_is_pid (t )) {
92- fprintf ( fd , "<0.%i.0>" , term_to_local_process_id (t ));
199+ return fun -> print ( fun , "<0.%i.0>" , term_to_local_process_id (t ));
93200
94201 } else if (term_is_function (t )) {
95202 const term * boxed_value = term_to_const_term_ptr (t );
@@ -101,35 +208,77 @@ void term_display(FILE *fd, term t, const Context *ctx)
101208 #else
102209 "#Fun<erl_eval.%lu.%llu>" ;
103210 #endif
104- fprintf ( fd , format , fun_index , (unsigned long ) fun_module );
211+ return fun -> print ( fun , format , fun_index , (unsigned long ) fun_module );
105212
106213 } else if (term_is_tuple (t )) {
107- fputc ('{' , fd );
214+ int ret = fun -> print (fun , "{" );
215+ if (UNLIKELY (ret < 0 )) {
216+ return ret ;
217+ }
108218
109219 int tuple_size = term_get_tuple_arity (t );
110220 for (int i = 0 ; i < tuple_size ; i ++ ) {
111221 if (i != 0 ) {
112- fputc (',' , fd );
222+ int printed = fun -> print (fun , "," );
223+ if (UNLIKELY (printed < 0 )) {
224+ return printed ;
225+ }
226+ ret += printed ;
113227 }
114- term_display (fd , term_get_tuple_element (t , i ), ctx );
228+ int printed = term_funprint (fun , term_get_tuple_element (t , i ), global );
229+ if (UNLIKELY (printed < 0 )) {
230+ return printed ;
231+ }
232+ ret += printed ;
115233 }
116234
117- fputc ('}' , fd );
235+ int printed = fun -> print (fun , "}" );
236+ if (UNLIKELY (printed < 0 )) {
237+ return printed ;
238+ }
239+ ret += printed ;
240+ return ret ;
118241
119242 } else if (term_is_map (t )) {
120- fprintf (fd , "#{" );
243+ int ret = fun -> print (fun , "#{" );
244+ if (UNLIKELY (ret < 0 )) {
245+ return ret ;
246+ }
121247
122248 int map_size = term_get_map_size (t );
123249 for (int i = 0 ; i < map_size ; i ++ ) {
124250 if (i != 0 ) {
125- fputc (',' , fd );
251+ int printed = fun -> print (fun , "," );
252+ if (UNLIKELY (printed < 0 )) {
253+ return printed ;
254+ }
255+ ret += printed ;
256+ }
257+ int printed = term_funprint (fun , term_get_map_key (t , i ), global );
258+ if (UNLIKELY (printed < 0 )) {
259+ return printed ;
126260 }
127- term_display (fd , term_get_map_key (t , i ), ctx );
128- fprintf (fd , "=>" );
129- term_display (fd , term_get_map_value (t , i ), ctx );
261+ ret += printed ;
262+
263+ printed = fun -> print (fun , "=>" );
264+ if (UNLIKELY (printed < 0 )) {
265+ return printed ;
266+ }
267+ ret += printed ;
268+
269+ printed = term_funprint (fun , term_get_map_value (t , i ), global );
270+ if (UNLIKELY (printed < 0 )) {
271+ return printed ;
272+ }
273+ ret += printed ;
130274 }
131275
132- fputc ('}' , fd );
276+ int printed = fun -> print (fun , "}" );
277+ if (UNLIKELY (printed < 0 )) {
278+ return printed ;
279+ }
280+ ret += printed ;
281+ return ret ;
133282
134283 } else if (term_is_binary (t )) {
135284 int len = term_binary_size (t );
@@ -143,24 +292,45 @@ void term_display(FILE *fd, term t, const Context *ctx)
143292 }
144293 }
145294
146- fprintf (fd , "<<" );
295+ int ret = fun -> print (fun , "<<" );
296+ if (UNLIKELY (ret < 0 )) {
297+ return ret ;
298+ }
299+
147300 if (is_printable ) {
148- fprintf (fd , "\"%.*s\"" , len , binary_data );
301+ int printed = fun -> print (fun , "\"%.*s\"" , len , binary_data );
302+ if (UNLIKELY (printed < 0 )) {
303+ return printed ;
304+ }
305+ ret += printed ;
149306
150307 } else {
151308 int display_separator = 0 ;
152309 for (int i = 0 ; i < len ; i ++ ) {
153310 if (display_separator ) {
154- fputc (',' , fd );
311+ int printed = fun -> print (fun , "," );
312+ if (UNLIKELY (printed < 0 )) {
313+ return printed ;
314+ }
315+ ret += printed ;
155316 } else {
156317 display_separator = 1 ;
157318 }
158319
159320 uint8_t c = (uint8_t ) binary_data [i ];
160- fprintf (fd , "%i" , (int ) c );
321+ int printed = fun -> print (fun , "%i" , (int ) c );
322+ if (UNLIKELY (printed < 0 )) {
323+ return printed ;
324+ }
325+ ret += printed ;
161326 }
162327 }
163- fprintf (fd , ">>" );
328+ int printed = fun -> print (fun , ">>" );
329+ if (UNLIKELY (printed < 0 )) {
330+ return printed ;
331+ }
332+ ret += printed ;
333+ return ret ;
164334
165335 } else if (term_is_reference (t )) {
166336 const char * format =
@@ -169,30 +339,28 @@ void term_display(FILE *fd, term t, const Context *ctx)
169339#else
170340 "#Ref<0.0.0.%lu>" ;
171341#endif
172- fprintf ( fd , format , term_to_ref_ticks (t ));
342+ return fun -> print ( fun , format , term_to_ref_ticks (t ));
173343
174344 } else if (term_is_boxed_integer (t )) {
175345 int size = term_boxed_size (t );
176346 switch (size ) {
177347 case 1 :
178- fprintf (fd , AVM_INT_FMT , term_unbox_int (t ));
179- break ;
348+ return fun -> print (fun , AVM_INT_FMT , term_unbox_int (t ));
180349
181350#if BOXED_TERMS_REQUIRED_FOR_INT64 == 2
182351 case 2 :
183- fprintf (fd , AVM_INT64_FMT , term_unbox_int64 (t ));
184- break ;
352+ return fun -> print (fun , AVM_INT64_FMT , term_unbox_int64 (t ));
185353#endif
186-
187354 default :
188355 AVM_ABORT ();
189356 }
190357
191358 } else if (term_is_float (t )) {
192359 avm_float_t f = term_to_float (t );
193- fprintf (fd , AVM_FLOAT_FMT , f );
360+ return fun -> print (fun , AVM_FLOAT_FMT , f );
361+
194362 } else {
195- fprintf ( fd , "Unknown term type: %" TERM_U_FMT , t );
363+ return fun -> print ( fun , "Unknown term type: %" TERM_U_FMT , t );
196364 }
197365}
198366
0 commit comments