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 : */