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