/[LeafOK_CVS]/lbbs/src/lml.c
ViewVC logotype

Annotation of /lbbs/src/lml.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.55 - (hide annotations)
Sat Jan 3 10:27:14 2026 UTC (2 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.54: +1 -1 lines
Content type: text/x-csrc
Update copyright info

1 sysadm 1.42 /* SPDX-License-Identifier: GPL-3.0-or-later */
2     /*
3     * lml
4     * - LML render
5     *
6 sysadm 1.55 * Copyright (C) 2004-2026 Leaflet <leaflet@leafok.com>
7 sysadm 1.42 */
8 sysadm 1.1
9 sysadm 1.47 #ifdef HAVE_CONFIG_H
10     #include "config.h"
11     #endif
12    
13 sysadm 1.12 #include "common.h"
14 sysadm 1.1 #include "lml.h"
15     #include "log.h"
16 sysadm 1.36 #include "str_process.h"
17 sysadm 1.53 #include "trie_dict.h"
18 sysadm 1.37 #include <ctype.h>
19 sysadm 1.1 #include <stdio.h>
20     #include <string.h>
21     #include <sys/param.h>
22    
23 sysadm 1.44 enum _lml_constant_t
24     {
25 sysadm 1.53 LML_TAG_NAME_BUF_LEN = 21,
26 sysadm 1.44 LML_TAG_PARAM_BUF_LEN = 256,
27     LML_TAG_OUTPUT_BUF_LEN = 1024,
28     LML_TAG_QUOTE_MAX_LEVEL = 10,
29     };
30 sysadm 1.1
31 sysadm 1.41 clock_t lml_total_exec_duration = 0;
32    
33 sysadm 1.20 typedef int (*lml_tag_filter_cb)(const char *tag_name, const char *tag_param_buf, char *tag_output_buf, size_t tag_output_buf_len, int quote_mode);
34 sysadm 1.3
35 sysadm 1.22 static int lml_tag_color_filter(const char *tag_name, const char *tag_param_buf, char *tag_output_buf, size_t tag_output_buf_len, int quote_mode)
36 sysadm 1.3 {
37     if (strcasecmp(tag_name, "color") == 0)
38     {
39     if (strcasecmp(tag_param_buf, "red") == 0)
40     {
41     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;31m");
42     }
43     else if (strcasecmp(tag_param_buf, "green") == 0)
44     {
45     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;32m");
46     }
47     else if (strcasecmp(tag_param_buf, "yellow") == 0)
48     {
49     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;33m");
50     }
51     else if (strcasecmp(tag_param_buf, "blue") == 0)
52     {
53     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;34m");
54     }
55     else if (strcasecmp(tag_param_buf, "magenta") == 0)
56     {
57     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;35m");
58     }
59     else if (strcasecmp(tag_param_buf, "cyan") == 0)
60     {
61     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;36m");
62     }
63     else if (strcasecmp(tag_param_buf, "black") == 0)
64     {
65     return snprintf(tag_output_buf, tag_output_buf_len, "\033[1;30;47m");
66     }
67     }
68     return 0;
69     }
70 sysadm 1.1
71 sysadm 1.4 static const char *lml_tag_quote_color[] = {
72 sysadm 1.5 "\033[33m", // yellow
73     "\033[32m", // green
74     "\033[35m", // magenta
75 sysadm 1.4 };
76    
77 sysadm 1.30 static const int LML_TAG_QUOTE_LEVEL_LOOP = (int)(sizeof(lml_tag_quote_color) / sizeof(const char *));
78    
79 sysadm 1.4 static int lml_tag_quote_level = 0;
80    
81 sysadm 1.20 static int lml_tag_quote_filter(const char *tag_name, const char *tag_param_buf, char *tag_output_buf, size_t tag_output_buf_len, int quote_mode)
82 sysadm 1.4 {
83     if (strcasecmp(tag_name, "quote") == 0)
84     {
85     if (lml_tag_quote_level <= LML_TAG_QUOTE_MAX_LEVEL)
86     {
87     lml_tag_quote_level++;
88     }
89 sysadm 1.14 return snprintf(tag_output_buf, tag_output_buf_len, "%s",
90     lml_tag_quote_color[lml_tag_quote_level % LML_TAG_QUOTE_LEVEL_LOOP]);
91 sysadm 1.4 }
92     else if (strcasecmp(tag_name, "/quote") == 0)
93     {
94     if (lml_tag_quote_level > 0)
95     {
96     lml_tag_quote_level--;
97     }
98 sysadm 1.14 return snprintf(tag_output_buf, tag_output_buf_len, "%s",
99 sysadm 1.5 (lml_tag_quote_level > 0 ? lml_tag_quote_color[lml_tag_quote_level % LML_TAG_QUOTE_LEVEL_LOOP] : "\033[m"));
100 sysadm 1.4 }
101    
102     return 0;
103     }
104    
105 sysadm 1.20 static int lml_tag_disabled = 0;
106    
107     static int lml_tag_disable_filter(const char *tag_name, const char *tag_param_buf, char *tag_output_buf, size_t tag_output_buf_len, int quote_mode)
108     {
109     lml_tag_disabled = 1;
110    
111 sysadm 1.23 return snprintf(tag_output_buf, tag_output_buf_len, "%s", (quote_mode ? "[plain]" : ""));
112 sysadm 1.20 }
113    
114 sysadm 1.22 typedef struct lml_tag_def_t
115     {
116 sysadm 1.26 const char *tag_name; // tag name
117     const char *tag_output; // output string
118     const char *default_param; // default param string
119     const char *quote_mode_output; // output string in quote mode
120 sysadm 1.22 lml_tag_filter_cb tag_filter_cb; // tag filter callback
121     } LML_TAG_DEF;
122    
123     const LML_TAG_DEF lml_tag_def[] = {
124     // Definition of tuple: {lml_tag, lml_output, default_param, quote_mode_output, lml_filter_cb}
125     {"plain", NULL, NULL, NULL, lml_tag_disable_filter},
126 sysadm 1.29 {"nolml", "", NULL, "", NULL}, // deprecated
127 sysadm 1.30 {"lml", "", NULL, "", NULL}, // deprecated
128     {"align", "", "", "", NULL}, // N/A
129     {"/align", "", "", "", NULL}, // N/A
130     {"size", "", "", "", NULL}, // N/A
131     {"/size", "", "", "", NULL}, // N/A
132 sysadm 1.22 {"left", "[", "", "[left]", NULL},
133     {"right", "]", "", "[right]", NULL},
134     {"bold", "\033[1m", "", "", NULL}, // does not work in Fterm
135     {"/bold", "\033[22m", NULL, "", NULL},
136     {"b", "\033[1m", "", "", NULL},
137     {"/b", "\033[22m", NULL, "", NULL},
138 sysadm 1.26 {"italic", "\033[5m", "", "", NULL}, // use blink instead
139 sysadm 1.22 {"/italic", "\033[m", NULL, "", NULL}, // \033[25m does not work in Fterm
140     {"i", "\033[5m", "", "", NULL},
141     {"/i", "\033[m", NULL, "", NULL},
142     {"underline", "\033[4m", "", "", NULL},
143     {"/underline", "\033[m", NULL, "", NULL}, // \033[24m does not work in Fterm
144     {"u", "\033[4m", "", "", NULL},
145     {"/u", "\033[m", NULL, "", NULL},
146     {"color", NULL, NULL, "", lml_tag_color_filter},
147     {"/color", "\033[m", NULL, "", NULL},
148     {"quote", NULL, NULL, "", lml_tag_quote_filter},
149     {"/quote", NULL, NULL, "", lml_tag_quote_filter},
150     {"url", "", "", "", NULL},
151     {"/url", "(链接: %s)", NULL, "", NULL},
152     {"link", "", "", "", NULL},
153     {"/link", "(链接: %s)", NULL, "", NULL},
154     {"email", "", "", "", NULL},
155     {"/email", "(Email: %s)", NULL, "", NULL},
156     {"user", "", "", "", NULL},
157     {"/user", "(用户: %s)", NULL, "", NULL},
158     {"article", "", "", "", NULL},
159     {"/article", "(文章: %s)", NULL, "", NULL},
160     {"image", "(图片: %s)", "", "%s", NULL},
161     {"flash", "(Flash: %s)", "", "", NULL},
162     {"bwf", "\033[1;31m****\033[m", "", "****", NULL},
163 sysadm 1.1 };
164    
165 sysadm 1.44 static const int lml_tag_count = sizeof(lml_tag_def) / sizeof(LML_TAG_DEF);
166     static int lml_tag_name_len[sizeof(lml_tag_def) / sizeof(LML_TAG_DEF)];
167 sysadm 1.53 static TRIE_NODE *p_lml_tag_dict;
168 sysadm 1.19 static int lml_ready = 0;
169 sysadm 1.1
170 sysadm 1.53 int lml_init(void)
171 sysadm 1.1 {
172 sysadm 1.53 char tag_name_buf[LML_TAG_NAME_BUF_LEN];
173 sysadm 1.1 int i;
174 sysadm 1.53 int j;
175 sysadm 1.1
176 sysadm 1.53 if (lml_ready)
177     {
178     lml_cleanup();
179     }
180    
181     p_lml_tag_dict = trie_dict_create();
182     if (p_lml_tag_dict == NULL)
183     {
184     log_error("trie_dict_create(lml_tag_dict) error");
185     return -1;
186     }
187    
188     for (i = 0; i < lml_tag_count; i++)
189 sysadm 1.1 {
190 sysadm 1.54 for (j = 0; j < sizeof(tag_name_buf) - 1 && lml_tag_def[i].tag_name[j] != '\0'; j++)
191 sysadm 1.53 {
192     tag_name_buf[j] = (char)tolower(lml_tag_def[i].tag_name[j]);
193     }
194     tag_name_buf[j] = '\0';
195     lml_tag_name_len[i] = j;
196    
197     if (trie_dict_set(p_lml_tag_dict, tag_name_buf, (int64_t)i) != 1)
198 sysadm 1.1 {
199 sysadm 1.53 log_error("trie_dict_set(lml_tag_dict, %s, %d) error", tag_name_buf, i);
200     lml_cleanup();
201     return -1;
202 sysadm 1.1 }
203 sysadm 1.53 }
204    
205     lml_ready = 1;
206 sysadm 1.1
207 sysadm 1.53 return 0;
208     }
209    
210     void lml_cleanup(void)
211     {
212     if (p_lml_tag_dict != NULL)
213     {
214     trie_dict_destroy(p_lml_tag_dict);
215     p_lml_tag_dict = NULL;
216 sysadm 1.1 }
217 sysadm 1.53
218     lml_ready = 0;
219 sysadm 1.1 }
220    
221 sysadm 1.53 #define CHECK_AND_APPEND_OUTPUT(out_buf, out_buf_len, out_buf_offset, tag_out, tag_out_len, line_width) \
222     if ((tag_out_len) > 0) \
223     { \
224     if ((out_buf_offset) + (tag_out_len) >= (out_buf_len)) \
225     { \
226 sysadm 1.52 log_error("Buffer is not longer enough for output string %d >= %d", (out_buf_offset) + (tag_out_len), (out_buf_len)); \
227 sysadm 1.53 out_buf[out_buf_offset] = '\0'; \
228     return (out_buf_offset); \
229     } \
230     memcpy((out_buf) + (out_buf_offset), (tag_out), (size_t)(tag_out_len)); \
231     *((out_buf) + (out_buf_offset) + (size_t)(tag_out_len)) = '\0'; \
232     (line_width) += str_length((out_buf) + (out_buf_offset), 1); \
233     (out_buf_offset) += (tag_out_len); \
234 sysadm 1.35 }
235 sysadm 1.34
236 sysadm 1.36 int lml_render(const char *str_in, char *str_out, int buf_len, int width, int quote_mode)
237 sysadm 1.1 {
238 sysadm 1.41 clock_t clock_begin;
239     clock_t clock_end;
240    
241 sysadm 1.13 char c;
242 sysadm 1.53 char tag_name_buf[LML_TAG_NAME_BUF_LEN];
243 sysadm 1.2 char tag_param_buf[LML_TAG_PARAM_BUF_LEN];
244 sysadm 1.1 char tag_output_buf[LML_TAG_OUTPUT_BUF_LEN];
245     int i;
246     int j = 0;
247     int k;
248 sysadm 1.53 int last_i = -1;
249     int64_t tag_index;
250 sysadm 1.1 int tag_start_pos = -1;
251 sysadm 1.26 int tag_name_pos = -1;
252 sysadm 1.1 int tag_end_pos = -1;
253 sysadm 1.2 int tag_param_pos = -1;
254 sysadm 1.1 int tag_output_len;
255 sysadm 1.5 int new_line = 1;
256     int fb_quote_level = 0;
257 sysadm 1.36 int line_width = 0;
258 sysadm 1.46 char tab_spaces[TAB_SIZE + 1];
259     int tab_width = 0;
260 sysadm 1.1
261 sysadm 1.51 clock_begin = clock();
262    
263 sysadm 1.49 #ifdef _DEBUG
264     size_t str_in_len = strlen(str_in);
265     #endif
266    
267 sysadm 1.53 if (!lml_ready)
268     {
269     log_error("LML module is not initialized");
270     return -1;
271     }
272 sysadm 1.1
273 sysadm 1.20 lml_tag_disabled = 0;
274 sysadm 1.4 lml_tag_quote_level = 0;
275    
276 sysadm 1.36 if (width <= 0)
277     {
278     width = INT_MAX;
279     }
280    
281 sysadm 1.1 for (i = 0; str_in[i] != '\0'; i++)
282     {
283 sysadm 1.49 #ifdef _DEBUG
284     if (i >= str_in_len)
285     {
286 sysadm 1.52 log_error("Bug: i(%d) >= str_in_len(%d)", i, str_in_len);
287 sysadm 1.49 break;
288     }
289     #endif
290    
291 sysadm 1.36 if (!lml_tag_disabled && new_line)
292 sysadm 1.5 {
293 sysadm 1.36 while (str_in[i] == ':' && str_in[i + 1] == ' ') // FB2000 quote leading str
294 sysadm 1.5 {
295     fb_quote_level++;
296 sysadm 1.36 lml_tag_quote_level++;
297     i += 2;
298 sysadm 1.5 }
299    
300 sysadm 1.36 if (!quote_mode && lml_tag_quote_level > 0)
301 sysadm 1.5 {
302 sysadm 1.14 tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, "%s",
303 sysadm 1.31 lml_tag_quote_color[lml_tag_quote_level % LML_TAG_QUOTE_LEVEL_LOOP]);
304 sysadm 1.36 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
305 sysadm 1.5 }
306    
307 sysadm 1.36 for (k = 0; k < fb_quote_level; k++)
308     {
309     tag_output_buf[k * 2] = ':';
310     tag_output_buf[k * 2 + 1] = ' ';
311     }
312     tag_output_buf[fb_quote_level * 2] = '\0';
313     tag_output_len = fb_quote_level * 2;
314     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
315    
316 sysadm 1.5 new_line = 0;
317 sysadm 1.50 i--; // redo at current i
318     continue;
319 sysadm 1.5 }
320    
321 sysadm 1.39 if (lml_tag_disabled && new_line)
322     {
323     new_line = 0;
324     }
325    
326 sysadm 1.41 if (!quote_mode && !lml_tag_disabled && str_in[i] == '\033' && str_in[i + 1] == '[') // Escape sequence
327 sysadm 1.8 {
328 sysadm 1.48 for (k = i + 2; isdigit((int)str_in[k]) || str_in[k] == ';' || str_in[k] == '?'; k++)
329 sysadm 1.8 ;
330    
331 sysadm 1.37 if (str_in[k] == 'm') // valid -- copy directly
332     {
333     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, str_in + i, k - i + 1, line_width);
334     }
335 sysadm 1.48 else if (isalpha((int)str_in[k]))
336 sysadm 1.37 {
337     // unsupported ANSI CSI command
338     }
339     else
340 sysadm 1.8 {
341 sysadm 1.35 k--;
342 sysadm 1.8 }
343 sysadm 1.35
344     i = k;
345     continue;
346 sysadm 1.8 }
347    
348 sysadm 1.28 if (str_in[i] == '\n') // jump out of tag at end of line
349 sysadm 1.5 {
350 sysadm 1.41 if (!lml_tag_disabled && tag_start_pos != -1) // tag is not closed
351 sysadm 1.28 {
352 sysadm 1.45 if (line_width + 1 > width)
353 sysadm 1.38 {
354     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
355     new_line = 1;
356     line_width = 0;
357 sysadm 1.40 i--; // redo at current i
358 sysadm 1.45 continue;
359 sysadm 1.38 }
360 sysadm 1.45
361     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "[", 1, line_width);
362     i = tag_start_pos; // restart from tag_start_pos + 1
363     tag_start_pos = -1;
364     tag_name_pos = -1;
365     continue;
366 sysadm 1.28 }
367    
368 sysadm 1.41 if (!lml_tag_disabled && fb_quote_level > 0)
369 sysadm 1.33 {
370     lml_tag_quote_level -= fb_quote_level;
371    
372 sysadm 1.36 tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, (quote_mode ? "" : "\033[m"));
373     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
374    
375     fb_quote_level = 0;
376 sysadm 1.33 }
377    
378 sysadm 1.38 if (new_line)
379     {
380     continue;
381     }
382    
383 sysadm 1.28 tag_start_pos = -1;
384     tag_name_pos = -1;
385 sysadm 1.5 new_line = 1;
386 sysadm 1.38 line_width = -1;
387 sysadm 1.5 }
388 sysadm 1.36 else if (str_in[i] == '\r' || str_in[i] == '\7')
389 sysadm 1.5 {
390 sysadm 1.36 continue; // Skip special characters
391 sysadm 1.5 }
392 sysadm 1.46 else if (str_in[i] == '\t')
393     {
394     tab_width = TAB_SIZE - (line_width % TAB_SIZE);
395     if (line_width + tab_width > width)
396     {
397     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
398     new_line = 1;
399     line_width = 0;
400     // skip current Tab
401     continue;
402     }
403    
404     for (k = 0; k < tab_width; k++)
405     {
406     tab_spaces[k] = ' ';
407     }
408     tab_spaces[tab_width] = '\0';
409     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tab_spaces, tab_width, line_width);
410     continue;
411     }
412 sysadm 1.5
413 sysadm 1.20 if (!lml_tag_disabled && str_in[i] == '[')
414 sysadm 1.1 {
415 sysadm 1.33 if (tag_start_pos != -1) // tag is not closed
416     {
417 sysadm 1.45 if (line_width + 1 > width)
418     {
419     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
420     new_line = 1;
421     line_width = 0;
422     i--; // redo at current i
423     continue;
424     }
425    
426     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "[", 1, line_width);
427     i = tag_start_pos; // restart from tag_start_pos + 1
428     tag_start_pos = -1;
429     tag_name_pos = -1;
430     continue;
431 sysadm 1.33 }
432    
433 sysadm 1.26 tag_start_pos = i;
434     tag_name_pos = i + 1;
435 sysadm 1.1 }
436 sysadm 1.32 else if (!lml_tag_disabled && str_in[i] == ']' && tag_name_pos >= 0)
437 sysadm 1.1 {
438 sysadm 1.32 tag_end_pos = i;
439    
440     // Skip space characters
441     while (str_in[tag_name_pos] == ' ')
442 sysadm 1.1 {
443 sysadm 1.32 tag_name_pos++;
444     }
445 sysadm 1.1
446 sysadm 1.54 for (k = 0; k < sizeof(tag_name_buf) - 1 && tag_name_pos + k < tag_end_pos; k++)
447 sysadm 1.53 {
448     if (str_in[tag_name_pos + k] == ' ' || str_in[tag_name_pos + k] == ']')
449     {
450     break;
451     }
452     tag_name_buf[k] = (char)tolower(str_in[tag_name_pos + k]);
453     }
454     tag_name_buf[k] = '\0';
455    
456     k = -1;
457     if (tag_name_buf[0] != '\0')
458     {
459     tag_index = -1;
460     if (trie_dict_get(p_lml_tag_dict, tag_name_buf, (int64_t *)&tag_index) < 0)
461     {
462     log_error("trie_dict_get(lml_tag_dict, %s) error", tag_name_buf);
463     }
464     else
465     {
466     k = (int)tag_index;
467     }
468     }
469    
470     if (k != -1)
471 sysadm 1.32 {
472 sysadm 1.53 tag_param_pos = -1;
473     switch (str_in[tag_name_pos + lml_tag_name_len[k]])
474 sysadm 1.1 {
475 sysadm 1.53 case ' ':
476     tag_param_pos = tag_name_pos + lml_tag_name_len[k] + 1;
477     while (str_in[tag_param_pos] == ' ')
478     {
479     tag_param_pos++;
480     }
481     strncpy(tag_param_buf, str_in + tag_param_pos, (size_t)MIN(tag_end_pos - tag_param_pos, LML_TAG_PARAM_BUF_LEN));
482     tag_param_buf[MIN(tag_end_pos - tag_param_pos, LML_TAG_PARAM_BUF_LEN)] = '\0';
483     case ']':
484     if (tag_param_pos == -1 && lml_tag_def[k].tag_output != NULL && lml_tag_def[k].default_param != NULL) // Apply default param if not defined
485 sysadm 1.1 {
486 sysadm 1.53 strncpy(tag_param_buf, lml_tag_def[k].default_param, LML_TAG_PARAM_BUF_LEN - 1);
487     tag_param_buf[LML_TAG_PARAM_BUF_LEN - 1] = '\0';
488     }
489     tag_output_len = 0;
490     if (!quote_mode)
491     {
492     if (lml_tag_def[k].tag_output != NULL)
493 sysadm 1.32 {
494 sysadm 1.53 tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].tag_output, tag_param_buf);
495 sysadm 1.32 }
496 sysadm 1.53 else if (lml_tag_def[k].tag_filter_cb != NULL)
497 sysadm 1.32 {
498 sysadm 1.53 tag_output_len = lml_tag_def[k].tag_filter_cb(
499     lml_tag_def[k].tag_name, tag_param_buf, tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, 0);
500 sysadm 1.32 }
501 sysadm 1.53 }
502     else // if (quote_mode)
503     {
504     if (lml_tag_def[k].quote_mode_output != NULL)
505 sysadm 1.32 {
506 sysadm 1.53 tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].quote_mode_output, tag_param_buf);
507 sysadm 1.32 }
508 sysadm 1.53 else if (lml_tag_def[k].tag_filter_cb != NULL)
509 sysadm 1.1 {
510 sysadm 1.53 tag_output_len = lml_tag_def[k].tag_filter_cb(
511     lml_tag_def[k].tag_name, tag_param_buf, tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, 1);
512 sysadm 1.1 }
513 sysadm 1.53 }
514 sysadm 1.50
515 sysadm 1.53 if (line_width + tag_output_len > width)
516     {
517     if (i > last_i)
518 sysadm 1.50 {
519 sysadm 1.53 last_i = i;
520 sysadm 1.50 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
521     new_line = 1;
522     line_width = 0;
523     i--; // redo at current i
524     continue;
525     }
526 sysadm 1.53 else
527     {
528     continue; // Output current tag in plain text if line width exceeded
529     }
530     }
531 sysadm 1.50
532 sysadm 1.53 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
533 sysadm 1.32 break;
534 sysadm 1.53 default:
535     log_error("Bug: tag name not match");
536 sysadm 1.1 }
537 sysadm 1.32 }
538 sysadm 1.53 else // tag_name not found
539 sysadm 1.32 {
540 sysadm 1.40 if (line_width + 1 > width)
541 sysadm 1.38 {
542     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
543     new_line = 1;
544     line_width = 0;
545 sysadm 1.40 i--; // redo at current i
546 sysadm 1.38 continue;
547     }
548    
549 sysadm 1.40 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "[", 1, line_width);
550     i = tag_start_pos; // restart from tag_start_pos + 1
551     tag_start_pos = -1;
552     tag_name_pos = -1;
553     continue;
554 sysadm 1.1 }
555 sysadm 1.32
556     tag_start_pos = -1;
557     tag_name_pos = -1;
558 sysadm 1.1 }
559 sysadm 1.26 else if (lml_tag_disabled || tag_name_pos == -1) // not in LML tag
560 sysadm 1.1 {
561 sysadm 1.36 if (line_width + (str_in[i] & 0x80 ? 2 : 1) > width)
562     {
563     CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
564     new_line = 1;
565     line_width = 0;
566 sysadm 1.40 i--; // redo at current i
567 sysadm 1.36 continue;
568     }
569    
570     tag_output_len = 1;
571 sysadm 1.22 if (str_in[i] & 0x80) // head of multi-byte character
572 sysadm 1.1 {
573 sysadm 1.22 c = (str_in[i] & 0x70) << 1;
574     while (c & 0x80)
575 sysadm 1.1 {
576 sysadm 1.36 if (str_in[i + tag_output_len] == '\0')
577 sysadm 1.13 {
578 sysadm 1.36 break;
579 sysadm 1.13 }
580 sysadm 1.36 tag_output_len++;
581 sysadm 1.22 c = (c & 0x7f) << 1;
582 sysadm 1.1 }
583     }
584    
585 sysadm 1.36 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, str_in + i, tag_output_len, line_width);
586     i += (tag_output_len - 1);
587 sysadm 1.1 }
588     else // in LML tag
589     {
590     // Do nothing
591     }
592     }
593    
594 sysadm 1.41 if (!lml_tag_disabled && tag_start_pos != -1) // tag is not closed
595 sysadm 1.26 {
596     tag_end_pos = i - 1;
597     tag_output_len = tag_end_pos - tag_start_pos + 1;
598 sysadm 1.36 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, str_in + tag_start_pos, tag_output_len, line_width);
599 sysadm 1.26 }
600    
601 sysadm 1.23 if (!quote_mode && !lml_tag_disabled && lml_tag_quote_level > 0)
602 sysadm 1.5 {
603     tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, "\033[m");
604 sysadm 1.36 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
605 sysadm 1.5 }
606    
607 sysadm 1.1 str_out[j] = '\0';
608    
609 sysadm 1.41 clock_end = clock();
610     lml_total_exec_duration += (clock_end - clock_begin);
611    
612 sysadm 1.1 return j;
613 sysadm 1.5 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1