LCOV - code coverage report
Current view: top level - io/source/format - io_md_writer.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 100.0 % 94 94
Test Date: 2025-05-01 10:10:14 Functions: 100.0 % 3 3

            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          144 :         const char peeknext = text[text_current_byte+1];  /* note: only in case current<=0x7f this is a valid code point, 0 at string end */
      67          144 :         if ( current == IO_MD_WRITER_LINEBREAK )
      68              :         {
      69           12 :             if (( peeknext == IO_MD_WRITER_LINEBREAK )
      70            9 :                 || ( peeknext == '+' )  /* list */
      71            9 :                 || ( peeknext == '*' )  /* list */
      72            9 :                 || ( peeknext == '-' )  /* list or heading */
      73            8 :                 || ( peeknext == '=' )  /* heading */
      74            8 :                 || ( peeknext == '#' )  /* heading */
      75            8 :                 || ( peeknext == '0' )  /* ordered list */
      76            8 :                 || ( peeknext == '1' )  /* ordered list */
      77            8 :                 || ( peeknext == '2' )  /* ordered list */
      78            8 :                 || ( peeknext == '3' )  /* ordered list */
      79            8 :                 || ( peeknext == '4' )  /* ordered list */
      80            7 :                 || ( peeknext == '5' )  /* ordered list */
      81            6 :                 || ( peeknext == '6' )  /* ordered list */
      82            6 :                 || ( peeknext == '7' )  /* ordered list */
      83            6 :                 || ( peeknext == '8' )  /* ordered list */
      84            6 :                 || ( peeknext == '9' )  /* ordered list */
      85            6 :                 || ( peeknext == '>' )  /* citation */
      86              :                 /*|| ( peeknext == ' ' )*/  /* list continuation */
      87            5 :                 || ( peeknext == '|' ))  /* table */
      88              : 
      89              :             {
      90            7 :                 const utf8stringview_t str_view = UTF8STRINGVIEW( &(text[text_start_byte]), text_current_byte-text_start_byte );
      91            7 :                 write_err |= io_xml_writer_write_xml_enc_view( (*this_).sink, &str_view );
      92            7 :                 write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_linebreak );
      93            7 :                 text_start_byte = text_current_byte+1;
      94              :             }
      95              :         }
      96          132 :         else if ( current == DATA_TABLE_ALPHANUM_DIAGRAM /* = 'D' */)
      97              :         {
      98              :             /* try to parse an id */
      99           12 :             data_id_t probe_id = DATA_ID_VOID;
     100              :             utf8stringview_t string_to_parse;
     101           12 :             utf8stringview_t remainder = UTF8STRINGVIEW_EMPTY;
     102              :             const utf8error_t region_err
     103           12 :                 = utf8stringview_init_region( &string_to_parse, text, text_current_byte, text_byte_length - text_current_byte );
     104           12 :             if ( region_err == UTF8ERROR_SUCCESS )
     105              :             {
     106           12 :                 data_id_init_by_stringview( &probe_id, &string_to_parse, &remainder );
     107              :             }
     108           12 :             const unsigned int id_length = utf8stringview_get_length( &string_to_parse ) - utf8stringview_get_length( &remainder );
     109              : 
     110           12 :             if ( data_id_is_valid( &probe_id ) )
     111              :             {
     112            5 :                 const bool show_id = utf8stringview_starts_with_str( &remainder, IO_MD_WRITER_LINK_AS_ID );
     113            5 :                 const bool show_name
     114              :                     = show_id
     115              :                     ? false
     116            5 :                     : utf8stringview_starts_with_str( &remainder, IO_MD_WRITER_LINK_AS_NAME );
     117              : 
     118            5 :                 if ( show_id || show_name )
     119            3 :                 {
     120              :                     u8_error_t d_err;
     121            3 :                     d_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, data_id_get_row_id( &probe_id ), &((*this_).temp_diagram) );
     122            3 :                     if ( d_err == U8_ERROR_NONE )
     123              :                     {
     124              :                         /* write previously parsed characters */
     125            2 :                         const utf8stringview_t str_view = UTF8STRINGVIEW( &(text[text_start_byte]), text_current_byte-text_start_byte );
     126            2 :                         write_err |= io_xml_writer_write_xml_enc_view( (*this_).sink, &str_view );
     127            2 :                         text_start_byte = text_current_byte;
     128              : 
     129              :                         /* write id */
     130            2 :                         char probe_id_str_buf[DATA_ID_MAX_UTF8STRING_SIZE] = "";
     131            2 :                         utf8stringbuf_t probe_id_str = UTF8STRINGBUF( probe_id_str_buf );
     132            2 :                         write_err |= data_id_to_utf8stringbuf ( &probe_id, probe_id_str );
     133            2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_start );
     134            2 :                         write_err |= io_xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( &probe_id_str ) );
     135            2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_middle );
     136            2 :                         if ( show_id )
     137              :                         {
     138            1 :                             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( &probe_id_str ) );
     139            1 :                             text_current_byte += id_length + sizeof(IO_MD_WRITER_LINK_AS_ID)-1 - 1;
     140              :                         }
     141              :                         else /* show_name */
     142              :                         {
     143            1 :                             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, data_diagram_get_name_const( &((*this_).temp_diagram) ) );
     144            1 :                             text_current_byte += id_length + sizeof(IO_MD_WRITER_LINK_AS_NAME)-1 - 1;
     145              :                         }
     146            2 :                         write_err |= io_xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_end );
     147            2 :                         text_start_byte = text_current_byte+1;
     148              : 
     149              :                         /* destroy the diagram */
     150            2 :                         data_diagram_destroy( &((*this_).temp_diagram) );
     151              :                     }
     152              :                     else
     153              :                     {
     154            1 :                         U8_TRACE_INFO_INT("id found but diagram does not exist: D", data_id_get_row_id( &probe_id ) );
     155              :                     }
     156              :                 }
     157              :                 else
     158              :                 {
     159            2 :                     U8_TRACE_INFO_INT("id found but #id or #name fragment missing: D", data_id_get_row_id( &probe_id ) );
     160              :                 }
     161              :             }
     162              :         }
     163              : 
     164          144 :         if ( text_current_byte+1 == text_byte_length )
     165              :         {
     166            4 :             write_err |= io_xml_writer_write_xml_enc( (*this_).sink, &(text[text_start_byte]) );
     167              :         }
     168              :     }
     169              : 
     170            4 :     U8_TRACE_END_ERR( write_err );
     171            4 :     return write_err;
     172              : }
     173              : 
     174              : 
     175              : /*
     176              : Copyright 2019-2025 Andreas Warnke
     177              : 
     178              : Licensed under the Apache License, Version 2.0 (the "License");
     179              : you may not use this file except in compliance with the License.
     180              : You may obtain a copy of the License at
     181              : 
     182              :     http://www.apache.org/licenses/LICENSE-2.0
     183              : 
     184              : Unless required by applicable law or agreed to in writing, software
     185              : distributed under the License is distributed on an "AS IS" BASIS,
     186              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     187              : See the License for the specific language governing permissions and
     188              : limitations under the License.
     189              : */
        

Generated by: LCOV version 2.0-1