1 /* Jitter: custom contextual printing.
2
3 Copyright (C) 2020 Luca Saiu
4 Written by Luca Saiu
5
6 This file is part of Jitter.
7
8 Jitter is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Jitter is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
20
21
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <jitter/jitter.h>
29 #include <jitter/jitter-dynamic-buffer.h>
30 #include <jitter/jitter-fatal.h>
31 #include <jitter/jitter-malloc.h>
32 #include <jitter/jitter-string.h>
33
34 #include <jitter/jitter-print.h>
35
36
37
38
39 /* Internal functionality.
40 * ************************************************************************** */
41
42 /* What a context consists of in memory. This type should be treated as
43 opaque by the final user, and even by users defining new context kinds. */
44 struct jitter_print_context_private
45 {
46 /* The stack of currently active decorations, the most current on the top.
47 The stack is empty at initialisation. Items are all of type
48 struct jitter_print_decoration. */
49 struct jitter_dynamic_buffer stack;
50
51 /* The context kind. This is a pointer. */
52 jitter_print_context_kind kind;
53
54 /* The context data, as appropriate for its kind. This is a pointer. */
55 jitter_print_context_data data;
56 };
57
58 /* A decoration <name, type, value> tuple. This is what the stack within
59 each context structs contains. */
60 struct jitter_print_decoration
61 {
62 /* The name for this decoration. This is a malloc-allocated copy, not
63 shared with data provided by the user. */
64 char *name;
65
66 /* The decoration type, whose value indicates which of the value fields is
67 significant. */
68 enum jitter_print_decoration_type type;
69
70 /* The value associated to the decoration. */
71 union jitter_print_decoration_value value;
72 };
73
74 /* Free the resources associated to the pointed decoration. */
75 static void
jitter_print_decoration_finalize(struct jitter_print_decoration * d)76 jitter_print_decoration_finalize (struct jitter_print_decoration *d)
77 {
78 /* Free the local copy of the name. */
79 free (d->name);
80
81 /* Free the local copy of the string value, if that is the union significant
82 field. */
83 if (d->type == jitter_print_decoration_type_string)
84 free (d->value.string);
85 }
86
87 /* Initialise the pointed decoration stack, meant to be the field stack of
88 a struct jitter_print_context_private object. */
89 static void
jitter_print_decoration_stack_initialize(struct jitter_dynamic_buffer * s)90 jitter_print_decoration_stack_initialize (struct jitter_dynamic_buffer *s)
91 {
92 jitter_dynamic_buffer_initialize (s);
93 }
94
95 /* Free the resources associated to the pointed decoration stack, meant to be
96 the field stack of a struct jitter_print_context_private object. */
97 static void
jitter_print_decoration_stack_finalize(struct jitter_dynamic_buffer * s)98 jitter_print_decoration_stack_finalize (struct jitter_dynamic_buffer *s)
99 {
100 struct jitter_print_decoration *elements
101 = ((struct jitter_print_decoration *)
102 JITTER_DYNAMIC_BUFFER_TO_CONST_POINTER (s));
103 struct jitter_print_decoration *limit
104 = ((struct jitter_print_decoration *)
105 JITTER_DYNAMIC_BUFFER_FIRST_UNUSED_CHAR_CONST (s));
106 struct jitter_print_decoration *element;
107 for (element = elements; element < limit; element ++)
108 jitter_print_decoration_finalize (element);
109 jitter_dynamic_buffer_finalize (s);
110 }
111
112 /* Return a pointer to the bottom of the decoration stack in the pointed
113 context. The bottom may contain a valid decoration, or not. */
114 static struct jitter_print_decoration *
jitter_print_decoration_stack_bottom(struct jitter_print_context_private * ct)115 jitter_print_decoration_stack_bottom (struct jitter_print_context_private *ct)
116 {
117 return ((struct jitter_print_decoration *)
118 JITTER_DYNAMIC_BUFFER_TO_CONST_POINTER (& ct->stack));
119 }
120
121 /* Return a pointer to the top decoration of the pointed context, or NULL
122 if the stack is currently empty. */
123 static struct jitter_print_decoration *
jitter_print_decoration_stack_top(struct jitter_print_context_private * ct)124 jitter_print_decoration_stack_top (struct jitter_print_context_private *ct)
125 {
126 struct jitter_print_decoration *bottom
127 = jitter_print_decoration_stack_bottom (ct);
128 struct jitter_print_decoration *top
129 = ((struct jitter_print_decoration *)
130 JITTER_DYNAMIC_BUFFER_FIRST_UNUSED_CHAR_CONST (& ct->stack)) - 1;
131 if (top < bottom)
132 return NULL;
133 else
134 return top;
135 }
136
137
138
139
140 /* Decorations.
141 * ************************************************************************** */
142
143 /* Common code factoring the logic in jitter_print_begin_decoration_integer ,
144 jitter_print_begin_decoration_floating_point ,
145 jitter_print_begin_decoration_string , jitter_print_begin_decoration_pointer
146 . Strings, both in the decoration name and in the decoration value, if
147 applicable, are cloned here: the caller should not make clones out of this
148 function. */
149 static int
jitter_print_begin_decoration(jitter_print_context ct,jitter_print_decoration_name name_orig,enum jitter_print_decoration_type type,union jitter_print_decoration_value value_orig)150 jitter_print_begin_decoration (jitter_print_context ct,
151 jitter_print_decoration_name name_orig,
152 enum jitter_print_decoration_type type,
153 union jitter_print_decoration_value value_orig)
154 {
155 /* Make a new decoration for the context decoration stack, cloning the fields
156 that need to be cloned. Do not push it to the stack yet, so that user code
157 has access to the previously active decorations. */
158 struct jitter_print_decoration d;
159 d.name = jitter_clone_string (name_orig);
160 d.type = type;
161 if (type == jitter_print_decoration_type_string)
162 d.value.string = jitter_clone_string (value_orig.string);
163 else
164 d.value = value_orig;
165
166 /* Perform the user action, with the declration ready but not yet active
167 on the stack. */
168 int res = 0;
169 if (ct->kind->begin_decoration != NULL)
170 res = ct->kind->begin_decoration (ct->data, d.name, d.type, & d.value);
171
172 /* Make the new decoration active. */
173 JITTER_DYNAMIC_BUFFER_PUSH (& ct->stack, struct jitter_print_decoration, & d);
174
175 return res;
176 }
177
178 int
jitter_print_begin_decoration_integer(jitter_print_context ct,jitter_print_decoration_name name,jitter_int value)179 jitter_print_begin_decoration_integer (jitter_print_context ct,
180 jitter_print_decoration_name name,
181 jitter_int value)
182 {
183 union jitter_print_decoration_value v;
184 v.integer = value;
185 return jitter_print_begin_decoration (ct, name,
186 jitter_print_decoration_type_integer,
187 v);
188 }
189
190 int
jitter_print_begin_decoration_floating_point(jitter_print_context ct,jitter_print_decoration_name name,double value)191 jitter_print_begin_decoration_floating_point (jitter_print_context ct,
192 jitter_print_decoration_name name,
193 double value)
194 {
195 union jitter_print_decoration_value v;
196 v.floating_point = value;
197 return jitter_print_begin_decoration
198 (ct, name, jitter_print_decoration_type_floating_point, v);
199 }
200
201 int
jitter_print_begin_decoration_string(jitter_print_context ct,jitter_print_decoration_name name,char * value)202 jitter_print_begin_decoration_string (jitter_print_context ct,
203 jitter_print_decoration_name name,
204 char *value)
205 {
206 union jitter_print_decoration_value v;
207 v.string = value;
208 return jitter_print_begin_decoration (ct, name,
209 jitter_print_decoration_type_string,
210 v);
211 }
212
213 int
jitter_print_begin_decoration_pointer(jitter_print_context ct,jitter_print_decoration_name name,void * value)214 jitter_print_begin_decoration_pointer (jitter_print_context ct,
215 jitter_print_decoration_name name,
216 void *value)
217 {
218 union jitter_print_decoration_value v;
219 v.pointer = value;
220 return jitter_print_begin_decoration (ct, name,
221 jitter_print_decoration_type_pointer,
222 v);
223 }
224
225 int
jitter_print_end_decoration(jitter_print_context ct,jitter_print_decoration_name name)226 jitter_print_end_decoration (jitter_print_context ct,
227 jitter_print_decoration_name name)
228 {
229 /* Check what the topmost decoration is; fail fatally if it is not what
230 it is supposed to be in LIFO order. */
231 struct jitter_print_decoration *d = jitter_print_decoration_stack_top (ct);
232 if (d == NULL)
233 jitter_fatal ("jitter_print_end_decoration: no current decoration "
234 "(expecting \"%s\")", name);
235 else if (strcmp (d->name, name))
236 jitter_fatal ("jitter_print_end_decoration: current decoration is \"%s\" "
237 "instead of \"%s\"", d->name, name);
238
239 /* Pop the deoration from the stack, but do not finalise it yet: the
240 user function still needs it. */
241 jitter_dynamic_buffer_pop (& ct->stack,
242 sizeof (struct jitter_print_decoration));
243
244 /* Perform the user action. The decoration is no longer active while the
245 user function runs, but the user still receives its data. */
246 int res = 0;
247 if (ct->kind->end_decoration != NULL)
248 res = ct->kind->end_decoration (ct->data, d->name, d->type, & d->value);
249
250 /* Now we can destroy the decoration. */
251 jitter_print_decoration_finalize (d);
252
253 return res;
254 }
255
256 /* End every decoration which has been begun and not ended yet, following the
257 correct LIFO order. Return 0 iff every close operation succeeds. This is
258 intended for context finalisation, in cases where the stream is closed early
259 before some decorations are explicitly ended. */
260 static int
jitter_print_end_all_decorations(jitter_print_context ct)261 jitter_print_end_all_decorations (jitter_print_context ct)
262 {
263 int res = 0;
264 struct jitter_print_decoration *top;
265 while ((top = jitter_print_decoration_stack_top (ct)) != NULL)
266 res = res || jitter_print_end_decoration (ct, top->name);
267 return res;
268 }
269
270
271 /* Decoration introspection.
272 * ************************************************************************** */
273
274 /* Factor the common code of jitter_print_get_decoration and
275 jitter_print_get_decoration_named , behaving like
276 jitter_print_get_decoration_named iff name is not NULL. */
277 static void
jitter_print_get_decoration_possibly_named(jitter_print_context ct,jitter_print_decoration_name name,jitter_print_decoration_name * name_pp,enum jitter_print_decoration_type ** type_pp,union jitter_print_decoration_value ** value_pp)278 jitter_print_get_decoration_possibly_named
279 (jitter_print_context ct,
280 jitter_print_decoration_name name,
281 jitter_print_decoration_name *name_pp,
282 enum jitter_print_decoration_type **type_pp,
283 union jitter_print_decoration_value **value_pp)
284 {
285 struct jitter_print_decoration *bottom
286 = jitter_print_decoration_stack_bottom (ct);
287 struct jitter_print_decoration *top
288 = jitter_print_decoration_stack_top (ct);
289
290 /* Scan the stack top-to-bottom, and stop at the first match. */
291 struct jitter_print_decoration *d;
292 if (top != NULL)
293 for (d = top; d >= bottom; d --)
294 if (name == NULL || ! strcmp (d->name, name))
295 {
296 * name_pp = d->name;
297 * type_pp = & d->type;
298 * value_pp = & d->value;
299 return;
300 }
301
302 /* If we arrived here no match exists. */
303 * name_pp = NULL;
304 * type_pp = NULL;
305 * value_pp = NULL;
306 }
307
308 void
jitter_print_get_decoration(jitter_print_context ct,jitter_print_decoration_name * name_pp,enum jitter_print_decoration_type ** type_pp,union jitter_print_decoration_value ** value_pp)309 jitter_print_get_decoration (jitter_print_context ct,
310 jitter_print_decoration_name *name_pp,
311 enum jitter_print_decoration_type **type_pp,
312 union jitter_print_decoration_value **value_pp)
313 {
314 jitter_print_get_decoration_possibly_named (ct, NULL, name_pp,
315 type_pp, value_pp);
316 }
317
318 void
jitter_print_get_decoration_named(jitter_print_context ct,jitter_print_decoration_name name,enum jitter_print_decoration_type ** type_pp,union jitter_print_decoration_value ** value_pp)319 jitter_print_get_decoration_named
320 (jitter_print_context ct,
321 jitter_print_decoration_name name,
322 enum jitter_print_decoration_type **type_pp,
323 union jitter_print_decoration_value **value_pp)
324 {
325 char *found_name_p;
326 jitter_print_get_decoration_possibly_named (ct, name, & found_name_p,
327 type_pp, value_pp);
328 }
329
330
331
332
333 /* Convenience functions for known decorations.
334 * ************************************************************************** */
335
336 int
jitter_print_begin_class(jitter_print_context ct,jitter_print_class c)337 jitter_print_begin_class (jitter_print_context ct, jitter_print_class c)
338 {
339 return jitter_print_begin_decoration_string
340 (ct,
341 JITTER_PRINT_DECORATION_NAME_CLASS,
342 c);
343 }
344
345 int
jitter_print_end_class(jitter_print_context ct)346 jitter_print_end_class (jitter_print_context ct)
347 {
348 return jitter_print_end_decoration (ct,
349 JITTER_PRINT_DECORATION_NAME_CLASS);
350 }
351
352 int
jitter_print_begin_hyperlink(jitter_print_context ct,jitter_print_url url)353 jitter_print_begin_hyperlink (jitter_print_context ct, jitter_print_url url)
354 {
355 /* Prevent nesting. */
356 char *active_hyperlink = jitter_print_get_hyperlink (ct);
357 if (active_hyperlink != NULL)
358 jitter_fatal ("jitter_print_begin_hyperlink: hyperlink already active "
359 "(\"%s\")", active_hyperlink);
360
361 return jitter_print_begin_decoration_string
362 (ct,
363 JITTER_PRINT_DECORATION_NAME_HYPERLINK,
364 url);
365 }
366
367 int
jitter_print_end_hyperlink(jitter_print_context ct)368 jitter_print_end_hyperlink (jitter_print_context ct)
369 {
370 return jitter_print_end_decoration (ct,
371 JITTER_PRINT_DECORATION_NAME_HYPERLINK);
372 }
373
374 /* Common code factoring jitter_print_get_class and jitter_print_get_hyperlink
375 . */
376 static char *
jitter_print_get_string_decoration(jitter_print_context ct,jitter_print_decoration_name name)377 jitter_print_get_string_decoration (jitter_print_context ct,
378 jitter_print_decoration_name name)
379 {
380 enum jitter_print_decoration_type *type_p;
381 union jitter_print_decoration_value *value_p;
382 jitter_print_get_decoration_named (ct, name, & type_p, & value_p);
383 if (type_p == NULL)
384 return NULL;
385 else if (* type_p != jitter_print_decoration_type_string)
386 jitter_fatal ("jitter_print_get_string_decoration: non-string value for "
387 "decoration %s", name);
388 else
389 return value_p->string;
390 }
391
392 char *
jitter_print_get_class(jitter_print_context ct)393 jitter_print_get_class (jitter_print_context ct)
394 {
395 return jitter_print_get_string_decoration
396 (ct, JITTER_PRINT_DECORATION_NAME_CLASS);
397 }
398 char *
jitter_print_get_hyperlink(jitter_print_context ct)399 jitter_print_get_hyperlink (jitter_print_context ct)
400 {
401 return jitter_print_get_string_decoration
402 (ct, JITTER_PRINT_DECORATION_NAME_HYPERLINK);
403 }
404
405
406
407 /* Functionality available in every context.
408 * ************************************************************************** */
409
410 int
jitter_print_flush(jitter_print_context ct)411 jitter_print_flush (jitter_print_context ct)
412 {
413 if (ct->kind->flush != NULL)
414 return ct->kind->flush (ct->data);
415 else
416 return 0;
417 }
418
419 int
jitter_print_context_destroy(jitter_print_context ct)420 jitter_print_context_destroy (jitter_print_context ct)
421 {
422 int res_end_decorations = jitter_print_end_all_decorations (ct);
423 int res_flush = jitter_print_flush (ct);
424 int res_destroy = 0;
425 if (ct->kind->destroy_without_flushing)
426 res_destroy = ct->kind->destroy_without_flushing (ct->data);
427 jitter_print_decoration_stack_finalize (& ct->stack);
428 free (ct);
429 return res_end_decorations || res_flush || res_destroy;
430 }
431
432
433
434
435 /* Printing with contexts.
436 * ************************************************************************** */
437
438 /* The size of a buffer large enough to hold the printed representation of
439 any numeric or pointer type, in chars. */
440 #define JITTER_PRINT_MEMORY_BUFFER_SIZE \
441 /* The radix associated to the least economical space representation is 2. \
442 In binary a 64-bit word takes up to 64 digits, plus one for the '\0' \
443 terminator. No sane configuration will print pointers in binary, so \
444 pointers will be more compact even if printed with a prefix. */ \
445 65
446
447 /* Internal emulation of the print_char behaviour within struct
448 jitter_print_context_kind_struct , to be used when print_char is NULL but
449 print_chars is not. */
450 static int
jitter_print_char_as_a_size_1_chars(jitter_print_context ct,char c)451 jitter_print_char_as_a_size_1_chars (jitter_print_context ct, char c)
452 {
453 return ct->kind->print_chars (ct->data, & c, 1);
454 }
455
456 /* Internal emulation of the print_chars behaviour within struct
457 jitter_print_context_kind_struct , to be used when print_chars is NULL but
458 print_char is not. */
459 static int
jitter_print_chars_in_a_loop(jitter_print_context ct,const char * p,size_t char_no)460 jitter_print_chars_in_a_loop (jitter_print_context ct, const char *p,
461 size_t char_no)
462 {
463 int res = 0;
464 int i;
465 for (i = 0; i < char_no; i ++)
466 {
467 res = ct->kind->print_char (ct->data, p [i]);
468 if (res != 0)
469 break;
470 }
471 return res;
472 }
473
474 int
jitter_print_char(jitter_print_context ct,char c)475 jitter_print_char (jitter_print_context ct, char c)
476 {
477 if (ct->kind->print_char != NULL)
478 return ct->kind->print_char (ct->data, c);
479 else if (ct->kind->print_chars != NULL)
480 return jitter_print_char_as_a_size_1_chars (ct, c);
481 else
482 /* Neither user function is defined. Print nothing. */
483 return 0;
484 }
485
486 int
jitter_print_chars(jitter_print_context ct,const char * p,size_t char_no)487 jitter_print_chars (jitter_print_context ct, const char *p, size_t char_no)
488 {
489 if (ct->kind->print_chars != NULL)
490 return ct->kind->print_chars (ct->data, p, char_no);
491 else if (ct->kind->print_char != NULL)
492 return jitter_print_chars_in_a_loop (ct, p, char_no);
493 else
494 /* Neither user function is defined. Print nothing. */
495 return 0;
496 }
497
498 int
jitter_print_char_star(jitter_print_context ct,const char * s)499 jitter_print_char_star (jitter_print_context ct, const char *s)
500 {
501 return jitter_print_chars (ct, s, strlen (s));
502 }
503
504 /* The only function we need to print signed data. */
505 int
jitter_print_long_long(jitter_print_context ct,int radix,jitter_long_long x)506 jitter_print_long_long (jitter_print_context ct, int radix, jitter_long_long x)
507 {
508 if (x < 0)
509 {
510 int minus_error = jitter_print_char (ct, '-');
511 if (minus_error != 0)
512 return minus_error;
513 jitter_ulong_long absolute_value = (jitter_ulong_long) (- x);
514 return jitter_print_ulong_long (ct, radix, absolute_value);
515 }
516 else
517 return jitter_print_ulong_long (ct, radix, x);
518 }
519
520 /* This is the core of every integer printing function. */
521 int
jitter_print_ulong_long(jitter_print_context ct,int radix,jitter_ulong_long x)522 jitter_print_ulong_long (jitter_print_context ct, int radix, jitter_ulong_long x)
523 {
524 /* This is the only place where we need to validate the radix. Every other
525 integer printing function, even when printing zero, ends up calling
526 this function. */
527 if (radix < 2 || radix > 36)
528 jitter_fatal ("jitter printing: invalid radix %i", radix);
529
530 if (x == 0)
531 return jitter_print_char (ct, '0');
532 else
533 {
534 /* Build a string containing the *reversed* digits in memory; we
535 do not know how long it will be yet. */
536 char reversed_digits [JITTER_PRINT_MEMORY_BUFFER_SIZE];
537 int i = 0;
538 while (x != 0)
539 {
540 const char *all_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
541 reversed_digits [i] = all_digits [x % radix];
542 x /= radix;
543 i ++;
544 }
545 /* Print the characters from the string, read backwards. Notice that at
546 the beginning i is the index of the leftmost element *out* of the
547 string. */
548 int res;
549 for (i --; i >= 0; i --)
550 {
551 res = jitter_print_char (ct, reversed_digits [i]);
552 if (res != 0)
553 break;
554 }
555 return res;
556 }
557 }
558
559 /* The functions for printing out every other integer type are based on the two
560 functions above. */
561 int
jitter_print_short(jitter_print_context ct,int radix,short x)562 jitter_print_short (jitter_print_context ct, int radix, short x)
563 {
564 return jitter_print_long_long (ct, radix, x);
565 }
566 int
jitter_print_int(jitter_print_context ct,int radix,int x)567 jitter_print_int (jitter_print_context ct, int radix, int x)
568 {
569 return jitter_print_long_long (ct, radix, x);
570 }
571 int
jitter_print_long(jitter_print_context ct,int radix,long x)572 jitter_print_long (jitter_print_context ct, int radix, long x)
573 {
574 return jitter_print_long_long (ct, radix, x);
575 }
576 int
jitter_print_ushort(jitter_print_context ct,int radix,unsigned short x)577 jitter_print_ushort (jitter_print_context ct, int radix, unsigned short x)
578 {
579 return jitter_print_ulong_long (ct, radix, x);
580 }
581 int
jitter_print_uint(jitter_print_context ct,int radix,unsigned int x)582 jitter_print_uint (jitter_print_context ct, int radix, unsigned int x)
583 {
584 return jitter_print_ulong_long (ct, radix, x);
585 }
586 int
jitter_print_ulong(jitter_print_context ct,int radix,unsigned long x)587 jitter_print_ulong (jitter_print_context ct, int radix, unsigned long x)
588 {
589 return jitter_print_ulong_long (ct, radix, x);
590 }
591
592 /* For pointer and floating-point types we rely on sprintf. Float values are
593 printed just like double values anyway. */
594 int
jitter_print_pointer(jitter_print_context ct,void * p)595 jitter_print_pointer (jitter_print_context ct, void *p)
596 {
597 char buffer [JITTER_PRINT_MEMORY_BUFFER_SIZE];
598 sprintf (buffer, "%p", p);
599 return jitter_print_char_star (ct, buffer);
600 }
601 int
jitter_print_float(jitter_print_context ct,float x)602 jitter_print_float (jitter_print_context ct, float x)
603 {
604 return jitter_print_double (ct, x);
605 }
606 int
jitter_print_double(jitter_print_context ct,double x)607 jitter_print_double (jitter_print_context ct, double x)
608 {
609 char buffer [JITTER_PRINT_MEMORY_BUFFER_SIZE];
610 sprintf (buffer, "%f", x);
611 return jitter_print_char_star (ct, buffer);
612 }
613 #if defined (JITTER_HAVE_LONG_DOUBLE)
614 int
jitter_print_long_double(jitter_print_context ct,long double x)615 jitter_print_long_double (jitter_print_context ct, long double x)
616 {
617 char buffer [JITTER_PRINT_MEMORY_BUFFER_SIZE];
618 sprintf (buffer, "%Lf", x);
619 return jitter_print_char_star (ct, buffer);
620 }
621 #endif // #if defined (JITTER_HAVE_LONG_DOUBLE)
622
623
624
625
626 /* Defining new print context kinds.
627 * ************************************************************************** */
628
629 /* Initialize the pointed context kind like
630 jitter_print_context_kind_make_trivial would, without allocating a new
631 buffer. The user is not supposed to use this, as she should treat the the
632 context kind as an opaque data type; however this is convenient for keeping
633 predefined context kinds in global variables, which can be initialised and
634 never finalized, without getting distracting warnings from valgrind. */
635 static void
jitter_print_context_kind_initialize_trivial(jitter_print_context_kind k)636 jitter_print_context_kind_initialize_trivial (jitter_print_context_kind k)
637 {
638 k->print_char = NULL;
639 k->print_chars = NULL;
640 k->begin_decoration = NULL;
641 k->end_decoration = NULL;
642 k->flush = NULL;
643 k->destroy_without_flushing = NULL;
644 }
645
646 jitter_print_context_kind
jitter_print_context_kind_make_trivial(void)647 jitter_print_context_kind_make_trivial (void)
648 {
649 jitter_print_context_kind res
650 = jitter_xmalloc (sizeof (struct jitter_print_context_kind_struct));
651 jitter_print_context_kind_initialize_trivial (res);
652 return res;
653 }
654
655 void
jitter_print_context_kind_destroy(jitter_print_context_kind k)656 jitter_print_context_kind_destroy (jitter_print_context_kind k)
657 {
658 free (k);
659 }
660
661 jitter_print_context
jitter_print_context_make(jitter_print_context_kind k,jitter_print_context_data d)662 jitter_print_context_make (jitter_print_context_kind k, jitter_print_context_data d)
663 {
664 jitter_print_context res
665 = jitter_xmalloc (sizeof (struct jitter_print_context_private));
666
667 jitter_print_decoration_stack_initialize (& res->stack);
668 res->kind = k;
669 res->data = d;
670
671 return res;
672 }
673
674
675
676
677 /* Predefined print context kinds: file_star print context.
678 * ************************************************************************** */
679
680 /* The one file_star context kind global, allocated statically rather than
681 with malloc. */
682 static struct jitter_print_context_kind_struct
683 jitter_print_context_kind_file_star_struct;
684 static jitter_print_context_kind
685 jitter_print_context_kind_file_star
686 = & jitter_print_context_kind_file_star_struct;
687
688 /* Non-trivial context kind operations. */
689 static int
jitter_print_context_file_star_print_char(jitter_print_context_data d,char c)690 jitter_print_context_file_star_print_char (jitter_print_context_data d,
691 char c)
692 {
693 return fputc (c, (FILE *) d) == EOF;
694 }
695 static int
jitter_print_context_file_star_flush(jitter_print_context_data d)696 jitter_print_context_file_star_flush (jitter_print_context_data d)
697 {
698 return fflush ((FILE *) d);
699 }
700 /* There is no need for a function
701 jitter_print_context_file_star_destroy_without_flushing . There is nothing
702 to destroy, since the FILE * object was given by the user, and the file is
703 not to be closed here. */
704
705 /* Global initialisation for this context kind. */
706 static void
jitter_print_context_kind_file_star_initialize(void)707 jitter_print_context_kind_file_star_initialize (void)
708 {
709 jitter_print_context_kind_initialize_trivial
710 (jitter_print_context_kind_file_star);
711 jitter_print_context_kind_file_star->print_char
712 = jitter_print_context_file_star_print_char;
713 jitter_print_context_kind_file_star->flush
714 = jitter_print_context_file_star_flush;
715 }
716
717 /* The user-visible function. */
718 jitter_print_context
jitter_print_context_make_file_star(FILE * f)719 jitter_print_context_make_file_star (FILE *f)
720 {
721 return jitter_print_context_make (jitter_print_context_kind_file_star, f);
722 }
723
724
725
726
727 /* Predefined print context kinds: file-descriptor print context.
728 * ************************************************************************** */
729
730 /* A file descriptor in memory, as the datum pointed within a file-descriptor
731 print context. This struct serves to make the code simple and clean, but
732 it would also be possible to cast between pointer and int and store the
733 descriptor directly in place of the pointer. */
734 struct jitter_print_context_fd
735 {
736 /* The underlying file descriptor. */
737 int fd;
738 };
739
740 /* The one fd context kind global, allocated statically rather than
741 with malloc. */
742 static struct jitter_print_context_kind_struct
743 jitter_print_context_kind_fd_struct;
744 static jitter_print_context_kind
745 jitter_print_context_kind_fd
746 = & jitter_print_context_kind_fd_struct;
747
748 /* Non-trivial context kind operations. */
749 static int
jitter_print_context_fd_print_chars(jitter_print_context_data d,const char * p,size_t char_no)750 jitter_print_context_fd_print_chars (jitter_print_context_data d,
751 const char *p, size_t char_no)
752 {
753 int fd = ((struct jitter_print_context_fd *)d)->fd;
754 const char *remaining_part = p;
755 int remaining_part_length = char_no;
756 int res = 0;
757 while (remaining_part_length > 0)
758 {
759 res = write (fd, remaining_part, remaining_part_length);
760 if (res == -1)
761 {
762 /* Break from the loop if the error is not recoverable here. If the
763 problem can be fixed by simply trying again then do nothing without
764 updating remaining_part or remaining_part_length, and remain in the
765 loop. */
766 if (errno != EAGAIN && errno != EINTR)
767 break;
768 }
769 else
770 {
771 /* The entire string may or may not have been printed at this point.
772 Advance to the remaining_part pointer and keep track of how many
773 characters have not been printed yet; this may or may not end the
774 loop. */
775 remaining_part += res;
776 remaining_part_length -= res;
777 }
778 };
779
780 /* Return 0 iff res does not currently contain an error result. */
781 return res == -1 ? res : 0;
782 }
783 static int
jitter_print_context_fd_destroy_without_flushing(jitter_print_context_data d)784 jitter_print_context_fd_destroy_without_flushing
785 (jitter_print_context_data d)
786 {
787 free (d);
788
789 /* Do *not* call close here. The descriptor is for the user to close. */
790 return 0;
791 }
792
793 /* Global initialisation for this context kind. */
794 static void
jitter_print_context_kind_fd_initialize(void)795 jitter_print_context_kind_fd_initialize (void)
796 {
797 jitter_print_context_kind_initialize_trivial (jitter_print_context_kind_fd);
798 jitter_print_context_kind_fd->print_chars
799 = jitter_print_context_fd_print_chars;
800 jitter_print_context_kind_fd->destroy_without_flushing
801 = jitter_print_context_fd_destroy_without_flushing;
802 }
803
804 /* The user-visible function. */
805 jitter_print_context
jitter_print_context_make_fd(int fd)806 jitter_print_context_make_fd (int fd)
807 {
808 struct jitter_print_context_fd *data
809 = jitter_xmalloc (sizeof (struct jitter_print_context_fd));
810 data->fd = fd;
811 return jitter_print_context_make (jitter_print_context_kind_fd, data);
812 }
813
814
815
816
817 /* Predefined print context kinds: memory print context.
818 * ************************************************************************** */
819
820 /* The "channel" for a memory print context is in fact a dynamically
821 allocated buffer. */
822 struct jitter_print_context_memory
823 {
824 /* A dynamic buffer containing char elements. */
825 struct jitter_dynamic_buffer db;
826 };
827
828 /* The one memory context kind global, allocated statically rather than
829 with malloc. */
830 static struct jitter_print_context_kind_struct
831 jitter_print_context_kind_memory_struct;
832 static jitter_print_context_kind
833 jitter_print_context_kind_memory
834 = & jitter_print_context_kind_memory_struct;
835
836 /* Non-trivial context kind operations. */
837 static int
jitter_print_context_memory_print_chars(jitter_print_context_data d,const char * p,size_t char_no)838 jitter_print_context_memory_print_chars (jitter_print_context_data d,
839 const char *p, size_t char_no)
840 {
841 struct jitter_dynamic_buffer *db
842 = & ((struct jitter_print_context_memory *) d)->db;
843 jitter_dynamic_buffer_push (db, p, char_no);
844 return 0;
845 }
846 static int
jitter_print_context_memory_destroy_without_flushing(jitter_print_context_data d)847 jitter_print_context_memory_destroy_without_flushing
848 (jitter_print_context_data d)
849 {
850 /* Destroy the dynamic buffer content holding printed data, and the memory
851 held by the dyanmic buffer struct itself. */
852 jitter_dynamic_buffer_finalize (& ((struct jitter_print_context_memory *)
853 d)->db);
854 free (d);
855 return 0;
856 }
857
858 /* Global initialisation for this context kind. */
859 static void
jitter_print_context_kind_memory_initialize(void)860 jitter_print_context_kind_memory_initialize (void)
861 {
862 jitter_print_context_kind_initialize_trivial
863 (jitter_print_context_kind_memory);
864 jitter_print_context_kind_memory->print_chars
865 = jitter_print_context_memory_print_chars;
866 jitter_print_context_kind_memory->destroy_without_flushing
867 = jitter_print_context_memory_destroy_without_flushing;
868 }
869
870 /* Return a fresh memory context. */
871 jitter_print_context
jitter_print_context_make_memory(void)872 jitter_print_context_make_memory (void)
873 {
874 struct jitter_print_context_memory *data
875 = jitter_xmalloc (sizeof (struct jitter_print_context_memory));
876 jitter_dynamic_buffer_initialize (& data->db);
877 return jitter_print_context_make (jitter_print_context_kind_memory, data);
878 }
879
880 char *
jitter_print_context_get_memory(jitter_print_context c,size_t * length_p)881 jitter_print_context_get_memory (jitter_print_context c,
882 size_t *length_p)
883 {
884 /* Fail if c is not in fact a string print context. */
885 if (c->kind != jitter_print_context_kind_memory)
886 jitter_fatal ("jitter_print_context_get_memory: not a memory print context");
887
888 /* Copy any chars which have been printed including chars beyond the first
889 '\0', if any -- this is why this does not use strncpy; unconditionally add
890 a final '\0' at the end. */
891 struct jitter_dynamic_buffer *db
892 = & ((struct jitter_print_context_memory *) c->data)->db;
893 size_t length = JITTER_DYNAMIC_BUFFER_USED_SIZE (db);
894 char *res = jitter_xmalloc (length + 1);
895 memcpy (res, JITTER_DYNAMIC_BUFFER_TO_CONST_POINTER (db), length);
896 res [length] = '\0';
897
898 /* The length is important in case of binary output, when the user printed
899 '\0' chars. */
900 if (length_p != NULL)
901 * length_p = length;
902 return res;
903 }
904
905
906
907
908 /* Global initialisation.
909 * ************************************************************************** */
910
911 void
jitter_print_initialize(void)912 jitter_print_initialize (void)
913 {
914 static /*jitter_bool*/bool jitter_print_already_initialized = false;
915
916 if (jitter_print_already_initialized)
917 return;
918
919 /* Initialise predefined context types. */
920 jitter_print_context_kind_file_star_initialize ();
921 jitter_print_context_kind_fd_initialize ();
922 jitter_print_context_kind_memory_initialize ();
923
924 jitter_print_already_initialized = true;
925 }
926