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