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