LCOV - code coverage report
Current view: top level - io/source/format - io_md_writer.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.65.6_covts Lines: 75 75 100.0 %
Date: 2025-09-25 21:07:53 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* File: io_md_writer.c; Copyright and License: see below */
       2             : 
       3             : #include "format/io_md_writer.h"
       4             : #include "utf8stringbuf/utf8stringview.h"
       5             : #include "u8/u8_trace.h"
       6             : #include "u8/u8_log.h"
       7             : #include <stdio.h>
       8             : #include <stdbool.h>
       9             : #include <assert.h>
      10             : 
      11             : /* Note, this is no full markdown syntax support - but it helps keeping markdown in shape */
      12             : static const char IO_MD_WRITER_LINEBREAK = '\n';
      13             : static const char IO_MD_WRITER_LINK_AS_ID[] = "#id";
      14             : static const char IO_MD_WRITER_LINK_AS_NAME[] = "#name";
      15             : 
      16           3 : void io_md_writer_init ( io_md_writer_t *this_,
      17             :                          data_database_reader_t *db_reader,
      18             :                          const char * tag_linebreak,
      19             :                          const char * tag_xref_start,
      20             :                          const char * tag_xref_middle,
      21             :                          const char * tag_xref_end,
      22             :                          io_xml_writer_t *sink )
      23             : {
      24           3 :     U8_TRACE_BEGIN();
      25           3 :     assert( NULL != db_reader );
      26           3 :     assert( NULL != tag_linebreak );
      27           3 :     assert( NULL != tag_xref_start );
      28           3 :     assert( NULL != tag_xref_middle );
      29           3 :     assert( NULL != tag_xref_end );
      30           3 :     assert( NULL != sink );
      31             : 
      32           3 :     (*this_).db_reader = db_reader;
      33           3 :     (*this_).tag_linebreak = tag_linebreak;
      34           3 :     (*this_).tag_xref_start = tag_xref_start;
      35           3 :     (*this_).tag_xref_middle = tag_xref_middle;
      36           3 :     (*this_).tag_xref_end = tag_xref_end;
      37           3 :     (*this_).sink = sink;
      38             : 
      39           3 :     U8_TRACE_END();
      40           3 : }
      41             : 
      42           3 : void io_md_writer_destroy( io_md_writer_t *this_ )
      43             : {
      44           3 :     U8_TRACE_BEGIN();
      45             : 
      46           3 :     (*this_).sink = NULL;
      47           3 :     (*this_).db_reader = NULL;
      48             : 
      49           3 :     U8_TRACE_END();
      50           3 : }
      51             : 
      52           4 : u8_error_t io_md_writer_transform ( io_md_writer_t *this_, const char *text )
      53             : {
      54           4 :     U8_TRACE_BEGIN();
      55           4 :     assert ( NULL != text );
      56           4 :     assert ( NULL != (*this_).db_reader );
      57           4 :     assert ( NULL != (*this_).sink );
      58             : 
      59           4 :     unsigned int text_start_byte = 0;
      60           4 :     const unsigned int text_byte_length = utf8string_get_length( text );
      61           4 :     u8_error_t write_err = U8_ERROR_NONE;
      62             : 
      63         148 :     for ( unsigned int text_current_byte = 0; text_current_byte < text_byte_length; text_current_byte ++ )
      64             :     {
      65         144 :         const char current = text[text_current_byte];  /* note: only in case current<=0x7f this is a valid code point */
      66             : #if 0
      67             :         const char peeknext = text[text_current_byte+1];  /* note: only in case current<=0x7f this is a valid code point, 0 at string end */
      68             : #endif
      69         144 :         if ( current == IO_MD_WRITER_LINEBREAK )
      70             :         {
      71             : #if 0
      72             :             if (( peeknext == IO_MD_WRITER_LINEBREAK )
      73             :                 || ( peeknext == '+' )  /* list */
      74             :                 || ( peeknext == '*' )  /* list */
      75             :                 || ( peeknext == '-' )  /* list or heading */
      76             :                 || ( peeknext == '=' )  /* heading */
      77             :                 || ( peeknext == '#' )  /* heading */
      78             :                 || ( peeknext == '0' )  /* ordered list */
      79             :                 || ( peeknext == '1' )  /* ordered list */
      80             :                 || ( peeknext == '2' )  /* ordered list */
      81             :                 || ( peeknext == '3' )  /* ordered list */
      82             :                 || ( peeknext == '4' )  /* ordered list */
      83             :                 || ( peeknext == '5' )  /* ordered list */
      84             :                 || ( peeknext == '6' )  /* ordered list */
      85             :                 || ( peeknext == '7' )  /* ordered list */
      86             :                 || ( peeknext == '8' )  /* ordered list */
      87             :                 || ( peeknext == '9' )  /* ordered list */
      88             :                 || ( peeknext == '>' )  /* citation */
      89             :                 /*|| ( peeknext == ' ' )*/  /* list continuation */
      90             :                 || ( peeknext == '|' ))  /* table */
      91             : #endif
      92             :             {
      93          12 :                 const utf8stringview_t str_view = UTF8STRINGVIEW( &(text[text_start_byte]), text_current_byte-text_start_byte );
      94          12 :                 write_err |= io_xml_writer_write_xml_enc_view( (*this_).sink, &str_view );
      95          12 :                 write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_linebreak );
      96          12 :                 text_start_byte = text_current_byte+1;
      97             :             }
      98             :         }
      99         132 :         else if ( current == DATA_TABLE_ALPHANUM_DIAGRAM /* = 'D' */)
     100             :         {
     101             :             /* try to parse an id */
     102          12 :             data_id_t probe_id = DATA_ID_VOID;
     103             :             utf8stringview_t string_to_parse;
     104          12 :             utf8stringview_t remainder = UTF8STRINGVIEW_EMPTY;
     105             :             const utf8error_t region_err
     106          12 :                 = utf8stringview_init_region( &string_to_parse, text, text_current_byte, text_byte_length - text_current_byte );
     107          12 :             if ( region_err == UTF8ERROR_SUCCESS )
     108             :             {
     109          12 :                 data_id_init_by_stringview( &probe_id, &string_to_parse, &remainder );
     110             :             }
     111          12 :             const unsigned int id_length = utf8stringview_get_length( &string_to_parse ) - utf8stringview_get_length( &remainder );
     112             : 
     113          12 :             if ( data_id_is_valid( &probe_id ) )
     114             :             {
     115           5 :                 const bool show_id = utf8stringview_starts_with_str( &remainder, IO_MD_WRITER_LINK_AS_ID );
     116           5 :                 const bool show_name
     117             :                     = show_id
     118             :                     ? false
     119           5 :                     : utf8stringview_starts_with_str( &remainder, IO_MD_WRITER_LINK_AS_NAME );
     120             : 
     121           5 :                 if ( show_id || show_name )
     122           3 :                 {
     123             :                     u8_error_t d_err;
     124           3 :                     d_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, data_id_get_row_id( &probe_id ), &((*this_).temp_diagram) );
     125           3 :                     if ( d_err == U8_ERROR_NONE )
     126             :                     {
     127             :                         /* write previously parsed characters */
     128           2 :                         const utf8stringview_t str_view = UTF8STRINGVIEW( &(text[text_start_byte]), text_current_byte-text_start_byte );
     129           2 :                         write_err |= io_xml_writer_write_xml_enc_view( (*this_).sink, &str_view );
     130           2 :                         text_start_byte = text_current_byte;
     131             : 
     132             :                         /* write id */
     133           2 :                         char probe_id_str_buf[DATA_ID_MAX_UTF8STRING_SIZE] = "";
     134           2 :                         utf8stringbuf_t probe_id_str = UTF8STRINGBUF( probe_id_str_buf );
     135           2 :                         write_err |= data_id_to_utf8stringbuf ( &probe_id, probe_id_str );
     136           2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_start );
     137           2 :                         write_err |= io_xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( &probe_id_str ) );
     138           2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_middle );
     139           2 :                         if ( show_id )
     140             :                         {
     141           1 :                             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( &probe_id_str ) );
     142           1 :                             text_current_byte += id_length + sizeof(IO_MD_WRITER_LINK_AS_ID)-1 - 1;
     143             :                         }
     144             :                         else /* show_name */
     145             :                         {
     146           1 :                             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, data_diagram_get_name_const( &((*this_).temp_diagram) ) );
     147           1 :                             text_current_byte += id_length + sizeof(IO_MD_WRITER_LINK_AS_NAME)-1 - 1;
     148             :                         }
     149           2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_end );
     150           2 :                         text_start_byte = text_current_byte+1;
     151             : 
     152             :                         /* destroy the diagram */
     153           2 :                         data_diagram_destroy( &((*this_).temp_diagram) );
     154             :                     }
     155             :                     else
     156             :                     {
     157           1 :                         U8_TRACE_INFO_INT("id found but diagram does not exist: D", data_id_get_row_id( &probe_id ) );
     158             :                     }
     159             :                 }
     160             :                 else
     161             :                 {
     162           2 :                     U8_TRACE_INFO_INT("id found but #id or #name fragment missing: D", data_id_get_row_id( &probe_id ) );
     163             :                 }
     164             :             }
     165             :         }
     166             : 
     167         144 :         if ( text_current_byte+1 == text_byte_length )
     168             :         {
     169           4 :             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, &(text[text_start_byte]) );
     170             :         }
     171             :     }
     172             : 
     173           4 :     U8_TRACE_END_ERR( write_err );
     174           4 :     return write_err;
     175             : }
     176             : 
     177             : 
     178             : /*
     179             : Copyright 2019-2025 Andreas Warnke
     180             : 
     181             : Licensed under the Apache License, Version 2.0 (the "License");
     182             : you may not use this file except in compliance with the License.
     183             : You may obtain a copy of the License at
     184             : 
     185             :     http://www.apache.org/licenses/LICENSE-2.0
     186             : 
     187             : Unless required by applicable law or agreed to in writing, software
     188             : distributed under the License is distributed on an "AS IS" BASIS,
     189             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     190             : See the License for the specific language governing permissions and
     191             : limitations under the License.
     192             : */

Generated by: LCOV version 1.16