(root)/
gettext-0.22.4/
libtextstyle/
lib/
term-styled-ostream.c
       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