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