1 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2 
3 #if !IS_CPLUSPLUS
4 #define term_styled_ostream_representation any_ostream_representation
5 #endif
6 #line 1 "term-styled-ostream.oo.c"
7 /* Output stream for CSS styled text, producing ANSI escape sequences.
8    Copyright (C) 2006-2007, 2019-2020 Free Software Foundation, Inc.
9    Written by Bruno Haible <bruno@clisp.org>, 2006.
10 
11    This program is free software: you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
23 
24 #include <config.h>
25 
26 /* Specification.  */
27 #include "term-styled-ostream.h"
28 
29 #include <stdlib.h>
30 
31 #include <cr-om-parser.h>
32 #include <cr-sel-eng.h>
33 #include <cr-style.h>
34 #include <cr-rgb.h>
35 /* <cr-fonts.h> has a broken double-inclusion guard in libcroco-0.6.1.  */
36 #ifndef __CR_FONTS_H__
37 # include <cr-fonts.h>
38 #endif
39 #include <cr-string.h>
40 
41 #include "term-ostream.h"
42 #include "mem-hash-map.h"
43 #include "xalloc.h"
44 
45 
46 /* CSS matching works as follows:
47    Suppose we have an element inside class "header" inside class "table".
48    We pretend to have an XML tree that looks like this:
49 
50      (root)
51        +----table
52               +----header
53 
54    For each of these XML nodes, the CSS matching engine can report the
55    matching CSS declarations.  We extract the CSS property values that
56    matter for terminal styling and cache them.  */
57 
58 /* Attributes that can be set on a character.  */
59 typedef struct
60 {
61   term_color_t     color;
62   term_color_t     bgcolor;
63   term_weight_t    weight;
64   term_posture_t   posture;
65   term_underline_t underline;
66 } attributes_t;
67 
68 #line 69 "term-styled-ostream.c"
69 #include "term_styled_ostream.priv.h"
70 
71 const typeinfo_t term_styled_ostream_typeinfo = { "term_styled_ostream" };
72 
73 static const typeinfo_t * const term_styled_ostream_superclasses[] =
74   { term_styled_ostream_SUPERCLASSES };
75 
76 #define super styled_ostream_vtable
77 
78 #line 82 "term-styled-ostream.oo.c"
79 
80 /* Implementation of ostream_t methods.  */
81 
82 static void
term_styled_ostream__write_mem(term_styled_ostream_t stream,const void * data,size_t len)83 term_styled_ostream__write_mem (term_styled_ostream_t stream,
84                                 const void *data, size_t len)
85 {
86   term_ostream_set_color (stream->destination, stream->curr_attr->color);
87   term_ostream_set_bgcolor (stream->destination, stream->curr_attr->bgcolor);
88   term_ostream_set_weight (stream->destination, stream->curr_attr->weight);
89   term_ostream_set_posture (stream->destination, stream->curr_attr->posture);
90   term_ostream_set_underline (stream->destination, stream->curr_attr->underline);
91 
92   term_ostream_write_mem (stream->destination, data, len);
93 }
94 
95 static void
term_styled_ostream__flush(term_styled_ostream_t stream,ostream_flush_scope_t scope)96 term_styled_ostream__flush (term_styled_ostream_t stream, ostream_flush_scope_t scope)
97 {
98   term_ostream_flush (stream->destination, scope);
99 }
100 
101 static void
term_styled_ostream__free(term_styled_ostream_t stream)102 term_styled_ostream__free (term_styled_ostream_t stream)
103 {
104   term_ostream_free (stream->destination);
105   cr_cascade_destroy (stream->css_document);
106   cr_sel_eng_destroy (stream->css_engine);
107   free (stream->curr_classes);
108   {
109     void *ptr = NULL;
110     const void *key;
111     size_t keylen;
112     void *data;
113 
114     while (hash_iterate (&stream->cache, &ptr, &key, &keylen, &data) == 0)
115       {
116         free (data);
117       }
118   }
119   hash_destroy (&stream->cache);
120   free (stream);
121 }
122 
123 /* Implementation of styled_ostream_t methods.  */
124 
125 /* CRStyle doesn't contain a value for the 'text-decoration' property.
126    So we have to extend it.  */
127 
128 enum CRXTextDecorationType
129 {
130   TEXT_DECORATION_NONE,
131   TEXT_DECORATION_UNDERLINE,
132   TEXT_DECORATION_OVERLINE,
133   TEXT_DECORATION_LINE_THROUGH,
134   TEXT_DECORATION_BLINK,
135   TEXT_DECORATION_INHERIT
136 };
137 
138 typedef struct _CRXStyle
139 {
140   struct _CRXStyle *parent_style;
141   CRStyle *base;
142   enum CRXTextDecorationType text_decoration;
143 } CRXStyle;
144 
145 /* An extended version of cr_style_new.  */
146 static CRXStyle *
crx_style_new(gboolean a_set_props_to_initial_values)147 crx_style_new (gboolean a_set_props_to_initial_values)
148 {
149   CRStyle *base;
150   CRXStyle *result;
151 
152   base = cr_style_new (a_set_props_to_initial_values);
153   if (base == NULL)
154     return NULL;
155 
156   result = XMALLOC (CRXStyle);
157   result->base = base;
158   if (a_set_props_to_initial_values)
159     result->text_decoration = TEXT_DECORATION_NONE;
160   else
161     result->text_decoration = TEXT_DECORATION_INHERIT;
162 
163   return result;
164 }
165 
166 /* An extended version of cr_style_destroy.  */
167 static void
crx_style_destroy(CRXStyle * a_style)168 crx_style_destroy (CRXStyle *a_style)
169 {
170   cr_style_destroy (a_style->base);
171   free (a_style);
172 }
173 
174 /* An extended version of cr_sel_eng_get_matched_style.  */
175 static enum CRStatus
crx_sel_eng_get_matched_style(CRSelEng * a_this,CRCascade * a_cascade,xmlNode * a_node,CRXStyle * a_parent_style,CRXStyle ** a_style,gboolean a_set_props_to_initial_values)176 crx_sel_eng_get_matched_style (CRSelEng * a_this, CRCascade * a_cascade,
177                                xmlNode * a_node,
178                                CRXStyle * a_parent_style, CRXStyle ** a_style,
179                                gboolean a_set_props_to_initial_values)
180 {
181   enum CRStatus status;
182   CRPropList *props = NULL;
183 
184   if (!(a_this && a_cascade && a_node && a_style))
185     return CR_BAD_PARAM_ERROR;
186 
187   status = cr_sel_eng_get_matched_properties_from_cascade (a_this, a_cascade,
188                                                            a_node, &props);
189   if (!(status == CR_OK))
190     return status;
191 
192   if (props)
193     {
194       CRXStyle *style;
195 
196       if (!*a_style)
197         {
198           *a_style = crx_style_new (a_set_props_to_initial_values);
199           if (!*a_style)
200             return CR_ERROR;
201         }
202       else
203         {
204           if (a_set_props_to_initial_values)
205             {
206               cr_style_set_props_to_initial_values ((*a_style)->base);
207               (*a_style)->text_decoration = TEXT_DECORATION_NONE;
208             }
209           else
210             {
211               cr_style_set_props_to_default_values ((*a_style)->base);
212               (*a_style)->text_decoration = TEXT_DECORATION_INHERIT;
213             }
214         }
215       style = *a_style;
216       style->parent_style = a_parent_style;
217       style->base->parent_style =
218         (a_parent_style != NULL ? a_parent_style->base : NULL);
219 
220       {
221         CRPropList *cur;
222 
223         for (cur = props; cur != NULL; cur = cr_prop_list_get_next (cur))
224           {
225             CRDeclaration *decl = NULL;
226 
227             cr_prop_list_get_decl (cur, &decl);
228             cr_style_set_style_from_decl (style->base, decl);
229             if (decl != NULL
230                 && decl->property != NULL
231                 && decl->property->stryng != NULL
232                 && decl->property->stryng->str != NULL)
233               {
234                 if (strcmp (decl->property->stryng->str, "text-decoration") == 0
235                     && decl->value != NULL
236                     && decl->value->type == TERM_IDENT
237                     && decl->value->content.str != NULL)
238                   {
239                     const char *value =
240                       cr_string_peek_raw_str (decl->value->content.str);
241 
242                     if (value != NULL)
243                       {
244                         if (strcmp (value, "none") == 0)
245                           style->text_decoration = TEXT_DECORATION_NONE;
246                         else if (strcmp (value, "underline") == 0)
247                           style->text_decoration = TEXT_DECORATION_UNDERLINE;
248                         else if (strcmp (value, "overline") == 0)
249                           style->text_decoration = TEXT_DECORATION_OVERLINE;
250                         else if (strcmp (value, "line-through") == 0)
251                           style->text_decoration = TEXT_DECORATION_LINE_THROUGH;
252                         else if (strcmp (value, "blink") == 0)
253                           style->text_decoration = TEXT_DECORATION_BLINK;
254                         else if (strcmp (value, "inherit") == 0)
255                           style->text_decoration = TEXT_DECORATION_INHERIT;
256                       }
257                   }
258               }
259           }
260       }
261 
262       cr_prop_list_destroy (props);
263     }
264 
265   return CR_OK;
266 }
267 
268 /* According to the CSS2 spec, sections 6.1 and 6.2, we need to do a
269    propagation: specified values -> computed values -> actual values.
270    The computed values are necessary.  libcroco does not compute them for us.
271    The function cr_style_resolve_inherited_properties is also not sufficient:
272    it handles only the case of inheritance, not the case of non-inheritance.
273    So we write style accessors that fetch the computed value, doing the
274    inheritance on the fly.
275    We then compute the actual values from the computed values; for colors,
276    this is done through the rgb_to_color method.  */
277 
278 static term_color_t
style_compute_color_value(CRStyle * style,enum CRRgbProp which,term_ostream_t stream)279 style_compute_color_value (CRStyle *style, enum CRRgbProp which,
280                            term_ostream_t stream)
281 {
282   for (;;)
283     {
284       if (style == NULL)
285         return COLOR_DEFAULT;
286       if (cr_rgb_is_set_to_inherit (&style->rgb_props[which].sv))
287         style = style->parent_style;
288       else if (cr_rgb_is_set_to_transparent (&style->rgb_props[which].sv))
289         /* A transparent color occurs as default background color, set by
290            cr_style_set_props_to_default_values.  */
291         return COLOR_DEFAULT;
292       else
293         {
294           CRRgb rgb;
295           int r;
296           int g;
297           int b;
298 
299           cr_rgb_copy (&rgb, &style->rgb_props[which].sv);
300           if (cr_rgb_compute_from_percentage (&rgb) != CR_OK)
301             abort ();
302           r = rgb.red & 0xff;
303           g = rgb.green & 0xff;
304           b = rgb.blue & 0xff;
305           return term_ostream_rgb_to_color (stream, r, g, b);
306         }
307     }
308 }
309 
310 static term_weight_t
style_compute_font_weight_value(const CRStyle * style)311 style_compute_font_weight_value (const CRStyle *style)
312 {
313   int value = 0;
314   for (;;)
315     {
316       if (style == NULL)
317         value += 4;
318       else
319         switch (style->font_weight)
320           {
321           case FONT_WEIGHT_INHERIT:
322             style = style->parent_style;
323             continue;
324           case FONT_WEIGHT_BOLDER:
325             value += 1;
326             style = style->parent_style;
327             continue;
328           case FONT_WEIGHT_LIGHTER:
329             value -= 1;
330             style = style->parent_style;
331             continue;
332           case FONT_WEIGHT_100:
333             value += 1;
334             break;
335           case FONT_WEIGHT_200:
336             value += 2;
337             break;
338           case FONT_WEIGHT_300:
339             value += 3;
340             break;
341           case FONT_WEIGHT_400: case FONT_WEIGHT_NORMAL:
342             value += 4;
343             break;
344           case FONT_WEIGHT_500:
345             value += 5;
346             break;
347           case FONT_WEIGHT_600:
348             value += 6;
349             break;
350           case FONT_WEIGHT_700: case FONT_WEIGHT_BOLD:
351             value += 7;
352             break;
353           case FONT_WEIGHT_800:
354             value += 8;
355             break;
356           case FONT_WEIGHT_900:
357             value += 9;
358             break;
359           default:
360             abort ();
361           }
362       /* Value >= 600 -> WEIGHT_BOLD.  Value <= 500 -> WEIGHT_NORMAL.  */
363       return (value >= 6 ? WEIGHT_BOLD : WEIGHT_NORMAL);
364     }
365 }
366 
367 static term_posture_t
style_compute_font_posture_value(const CRStyle * style)368 style_compute_font_posture_value (const CRStyle *style)
369 {
370   for (;;)
371     {
372       if (style == NULL)
373         return POSTURE_DEFAULT;
374       switch (style->font_style)
375         {
376         case FONT_STYLE_INHERIT:
377           style = style->parent_style;
378           break;
379         case FONT_STYLE_NORMAL:
380           return POSTURE_NORMAL;
381         case FONT_STYLE_ITALIC:
382         case FONT_STYLE_OBLIQUE:
383           return POSTURE_ITALIC;
384         default:
385           abort ();
386         }
387     }
388 }
389 
390 static term_underline_t
style_compute_text_underline_value(const CRXStyle * style)391 style_compute_text_underline_value (const CRXStyle *style)
392 {
393   for (;;)
394     {
395       if (style == NULL)
396         return UNDERLINE_DEFAULT;
397       switch (style->text_decoration)
398         {
399         case TEXT_DECORATION_INHERIT:
400           style = style->parent_style;
401           break;
402         case TEXT_DECORATION_NONE:
403         case TEXT_DECORATION_OVERLINE:
404         case TEXT_DECORATION_LINE_THROUGH:
405         case TEXT_DECORATION_BLINK:
406           return UNDERLINE_OFF;
407         case TEXT_DECORATION_UNDERLINE:
408           return UNDERLINE_ON;
409         default:
410           abort ();
411         }
412     }
413 }
414 
415 /* Match the current list of CSS classes to the CSS and return the result.  */
416 static attributes_t *
match(term_styled_ostream_t stream)417 match (term_styled_ostream_t stream)
418 {
419   xmlNodePtr root;
420   xmlNodePtr curr;
421   char *p_end;
422   char *p_start;
423   CRXStyle *curr_style;
424   CRStyle *curr_style_base;
425   attributes_t *attr;
426 
427   /* Create a hierarchy of XML nodes.  */
428   root = xmlNewNode (NULL, (const xmlChar *) "__root__");
429   root->type = XML_ELEMENT_NODE;
430   curr = root;
431   p_end = &stream->curr_classes[stream->curr_classes_length];
432   p_start = stream->curr_classes;
433   while (p_start < p_end)
434     {
435       char *p;
436       xmlNodePtr child;
437 
438       if (!(*p_start == ' '))
439         abort ();
440       p_start++;
441       for (p = p_start; p < p_end && *p != ' '; p++)
442         ;
443 
444       /* Temporarily replace the ' ' by '\0'.  */
445       *p = '\0';
446       child = xmlNewNode (NULL, (const xmlChar *) p_start);
447       child->type = XML_ELEMENT_NODE;
448       xmlSetProp (child, (const xmlChar *) "class", (const xmlChar *) p_start);
449       *p = ' ';
450 
451       if (xmlAddChild (curr, child) == NULL)
452         /* Error! Shouldn't happen.  */
453         abort ();
454 
455       curr = child;
456       p_start = p;
457     }
458 
459   /* Retrieve the matching CSS declarations.  */
460   /* Not curr_style = crx_style_new (TRUE); because that assumes that the
461      default foreground color is black and that the default background color
462      is white, which is not necessarily true in a terminal context.  */
463   curr_style = NULL;
464   for (curr = root; curr != NULL; curr = curr->children)
465     {
466       CRXStyle *parent_style = curr_style;
467       curr_style = NULL;
468 
469       if (crx_sel_eng_get_matched_style (stream->css_engine,
470                                          stream->css_document,
471                                          curr,
472                                          parent_style, &curr_style,
473                                          FALSE) != CR_OK)
474         abort ();
475       if (curr_style == NULL)
476         /* No declarations matched this node.  Inherit all values.  */
477         curr_style = parent_style;
478       else
479         /* curr_style is a new style, inheriting from parent_style.  */
480         ;
481     }
482   curr_style_base = (curr_style != NULL ? curr_style->base : NULL);
483 
484   /* Extract the CSS declarations that we can use.  */
485   attr = XMALLOC (attributes_t);
486   attr->color =
487     style_compute_color_value (curr_style_base, RGB_PROP_COLOR,
488                                stream->destination);
489   attr->bgcolor =
490     style_compute_color_value (curr_style_base, RGB_PROP_BACKGROUND_COLOR,
491                                stream->destination);
492   attr->weight = style_compute_font_weight_value (curr_style_base);
493   attr->posture = style_compute_font_posture_value (curr_style_base);
494   attr->underline = style_compute_text_underline_value (curr_style);
495 
496   /* Free the style chain.  */
497   while (curr_style != NULL)
498     {
499       CRXStyle *parent_style = curr_style->parent_style;
500 
501       crx_style_destroy (curr_style);
502       curr_style = parent_style;
503     }
504 
505   /* Free the XML nodes.  */
506   xmlFreeNodeList (root);
507 
508   return attr;
509 }
510 
511 /* Match the current list of CSS classes to the CSS and store the result in
512    stream->curr_attr and in the cache.  */
513 static void
match_and_cache(term_styled_ostream_t stream)514 match_and_cache (term_styled_ostream_t stream)
515 {
516   attributes_t *attr = match (stream);
517   if (hash_insert_entry (&stream->cache,
518                          stream->curr_classes, stream->curr_classes_length,
519                          attr) == NULL)
520     abort ();
521   stream->curr_attr = attr;
522 }
523 
524 static void
term_styled_ostream__begin_use_class(term_styled_ostream_t stream,const char * classname)525 term_styled_ostream__begin_use_class (term_styled_ostream_t stream,
526                                       const char *classname)
527 {
528   size_t classname_len;
529   char *p;
530   void *found;
531 
532   if (classname[0] == '\0' || strchr (classname, ' ') != NULL)
533     /* Invalid classname argument.  */
534     abort ();
535 
536   /* Push the classname onto the classname list.  */
537   classname_len = strlen (classname);
538   if (stream->curr_classes_length + 1 + classname_len + 1
539       > stream->curr_classes_allocated)
540     {
541       size_t new_allocated = stream->curr_classes_length + 1 + classname_len + 1;
542       if (new_allocated < 2 * stream->curr_classes_allocated)
543         new_allocated = 2 * stream->curr_classes_allocated;
544 
545       stream->curr_classes = xrealloc (stream->curr_classes, new_allocated);
546       stream->curr_classes_allocated = new_allocated;
547     }
548   p = &stream->curr_classes[stream->curr_classes_length];
549   *p++ = ' ';
550   memcpy (p, classname, classname_len);
551   stream->curr_classes_length += 1 + classname_len;
552 
553   /* Uodate stream->curr_attr.  */
554   if (hash_find_entry (&stream->cache,
555                        stream->curr_classes, stream->curr_classes_length,
556                        &found) < 0)
557     match_and_cache (stream);
558   else
559     stream->curr_attr = (attributes_t *) found;
560 }
561 
562 static void
term_styled_ostream__end_use_class(term_styled_ostream_t stream,const char * classname)563 term_styled_ostream__end_use_class (term_styled_ostream_t stream,
564                                     const char *classname)
565 {
566   char *p_end;
567   char *p_start;
568   char *p;
569   void *found;
570 
571   if (stream->curr_classes_length == 0)
572     /* No matching call to begin_use_class.  */
573     abort ();
574 
575   /* Remove the trailing classname.  */
576   p_end = &stream->curr_classes[stream->curr_classes_length];
577   p = p_end;
578   while (*--p != ' ')
579     ;
580   p_start = p + 1;
581   if (!(p_end - p_start == strlen (classname)
582         && memcmp (p_start, classname, p_end - p_start) == 0))
583     /* The match ing call to begin_use_class used a different classname.  */
584     abort ();
585   stream->curr_classes_length = p - stream->curr_classes;
586 
587   /* Update stream->curr_attr.  */
588   if (hash_find_entry (&stream->cache,
589                        stream->curr_classes, stream->curr_classes_length,
590                        &found) < 0)
591     abort ();
592   stream->curr_attr = (attributes_t *) found;
593 }
594 
595 static const char *
term_styled_ostream__get_hyperlink_ref(term_styled_ostream_t stream)596 term_styled_ostream__get_hyperlink_ref (term_styled_ostream_t stream)
597 {
598   return term_ostream_get_hyperlink_ref (stream->destination);
599 }
600 
601 static const char *
term_styled_ostream__get_hyperlink_id(term_styled_ostream_t stream)602 term_styled_ostream__get_hyperlink_id (term_styled_ostream_t stream)
603 {
604   return term_ostream_get_hyperlink_id (stream->destination);
605 }
606 
607 static void
term_styled_ostream__set_hyperlink(term_styled_ostream_t stream,const char * ref,const char * id)608 term_styled_ostream__set_hyperlink (term_styled_ostream_t stream,
609                                     const char *ref, const char *id)
610 {
611   term_ostream_set_hyperlink (stream->destination, ref, id);
612 }
613 
614 static void
term_styled_ostream__flush_to_current_style(term_styled_ostream_t stream)615 term_styled_ostream__flush_to_current_style (term_styled_ostream_t stream)
616 {
617   term_ostream_set_color (stream->destination, stream->curr_attr->color);
618   term_ostream_set_bgcolor (stream->destination, stream->curr_attr->bgcolor);
619   term_ostream_set_weight (stream->destination, stream->curr_attr->weight);
620   term_ostream_set_posture (stream->destination, stream->curr_attr->posture);
621   term_ostream_set_underline (stream->destination, stream->curr_attr->underline);
622 
623   term_ostream_flush_to_current_style (stream->destination);
624 }
625 
626 /* Constructor.  */
627 
628 term_styled_ostream_t
term_styled_ostream_create(int fd,const char * filename,ttyctl_t tty_control,const char * css_filename)629 term_styled_ostream_create (int fd, const char *filename, ttyctl_t tty_control,
630                             const char *css_filename)
631 {
632   term_styled_ostream_t stream;
633   CRStyleSheet *css_file_contents;
634 
635   /* If css_filename is NULL, no styling is desired.  The code below would end
636      up returning NULL anyway.  But it's better to not rely on such details of
637      libcroco behaviour.  */
638   if (css_filename == NULL)
639     return NULL;
640 
641   stream = XMALLOC (struct term_styled_ostream_representation);
642 
643   stream->base.base.vtable = &term_styled_ostream_vtable;
644   stream->destination = term_ostream_create (fd, filename, tty_control);
645 
646   if (cr_om_parser_simply_parse_file ((const guchar *) css_filename,
647                                       CR_UTF_8, /* CR_AUTO is not supported */
648                                       &css_file_contents) != CR_OK)
649     {
650       term_ostream_free (stream->destination);
651       free (stream);
652       return NULL;
653     }
654   stream->css_document = cr_cascade_new (NULL, css_file_contents, NULL);
655   stream->css_engine = cr_sel_eng_new ();
656 
657   stream->curr_classes_allocated = 60;
658   stream->curr_classes = XNMALLOC (stream->curr_classes_allocated, char);
659   stream->curr_classes_length = 0;
660 
661   hash_init (&stream->cache, 10);
662 
663   match_and_cache (stream);
664 
665   return stream;
666 }
667 
668 #line 669 "term-styled-ostream.c"
669 
670 const struct term_styled_ostream_implementation term_styled_ostream_vtable =
671 {
672   term_styled_ostream_superclasses,
673   sizeof (term_styled_ostream_superclasses) / sizeof (term_styled_ostream_superclasses[0]),
674   sizeof (struct term_styled_ostream_representation),
675   term_styled_ostream__write_mem,
676   term_styled_ostream__flush,
677   term_styled_ostream__free,
678   term_styled_ostream__begin_use_class,
679   term_styled_ostream__end_use_class,
680   term_styled_ostream__get_hyperlink_ref,
681   term_styled_ostream__get_hyperlink_id,
682   term_styled_ostream__set_hyperlink,
683   term_styled_ostream__flush_to_current_style,
684 };
685 
686 #if !HAVE_INLINE
687 
688 /* Define the functions that invoke the methods.  */
689 
690 void
term_styled_ostream_write_mem(term_styled_ostream_t first_arg,const void * data,size_t len)691 term_styled_ostream_write_mem (term_styled_ostream_t first_arg, const void *data, size_t len)
692 {
693   const struct term_styled_ostream_implementation *vtable =
694     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
695   vtable->write_mem (first_arg,data,len);
696 }
697 
698 void
term_styled_ostream_flush(term_styled_ostream_t first_arg,ostream_flush_scope_t scope)699 term_styled_ostream_flush (term_styled_ostream_t first_arg, ostream_flush_scope_t scope)
700 {
701   const struct term_styled_ostream_implementation *vtable =
702     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
703   vtable->flush (first_arg,scope);
704 }
705 
706 void
term_styled_ostream_free(term_styled_ostream_t first_arg)707 term_styled_ostream_free (term_styled_ostream_t first_arg)
708 {
709   const struct term_styled_ostream_implementation *vtable =
710     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
711   vtable->free (first_arg);
712 }
713 
714 void
term_styled_ostream_begin_use_class(term_styled_ostream_t first_arg,const char * classname)715 term_styled_ostream_begin_use_class (term_styled_ostream_t first_arg, const char *classname)
716 {
717   const struct term_styled_ostream_implementation *vtable =
718     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
719   vtable->begin_use_class (first_arg,classname);
720 }
721 
722 void
term_styled_ostream_end_use_class(term_styled_ostream_t first_arg,const char * classname)723 term_styled_ostream_end_use_class (term_styled_ostream_t first_arg, const char *classname)
724 {
725   const struct term_styled_ostream_implementation *vtable =
726     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
727   vtable->end_use_class (first_arg,classname);
728 }
729 
730 const char *
term_styled_ostream_get_hyperlink_ref(term_styled_ostream_t first_arg)731 term_styled_ostream_get_hyperlink_ref (term_styled_ostream_t first_arg)
732 {
733   const struct term_styled_ostream_implementation *vtable =
734     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
735   return vtable->get_hyperlink_ref (first_arg);
736 }
737 
738 const char *
term_styled_ostream_get_hyperlink_id(term_styled_ostream_t first_arg)739 term_styled_ostream_get_hyperlink_id (term_styled_ostream_t first_arg)
740 {
741   const struct term_styled_ostream_implementation *vtable =
742     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
743   return vtable->get_hyperlink_id (first_arg);
744 }
745 
746 void
term_styled_ostream_set_hyperlink(term_styled_ostream_t first_arg,const char * ref,const char * id)747 term_styled_ostream_set_hyperlink (term_styled_ostream_t first_arg,                               const char *ref, const char *id)
748 {
749   const struct term_styled_ostream_implementation *vtable =
750     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
751   vtable->set_hyperlink (first_arg,ref,id);
752 }
753 
754 void
term_styled_ostream_flush_to_current_style(term_styled_ostream_t first_arg)755 term_styled_ostream_flush_to_current_style (term_styled_ostream_t first_arg)
756 {
757   const struct term_styled_ostream_implementation *vtable =
758     ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
759   vtable->flush_to_current_style (first_arg);
760 }
761 
762 #endif
763