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 : utf8stringview_t remainder; 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-2024 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 : */