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

Diff of /lbbs/src/lml.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.48 by sysadm, Mon Nov 17 12:47:41 2025 UTC Revision 1.55 by sysadm, Sat Jan 3 10:27:14 2026 UTC
# Line 3  Line 3 
3   * lml   * lml
4   *   - LML render   *   - LML render
5   *   *
6   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>   * Copyright (C) 2004-2026  Leaflet <leaflet@leafok.com>
7   */   */
8    
9  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
# Line 14  Line 14 
14  #include "lml.h"  #include "lml.h"
15  #include "log.h"  #include "log.h"
16  #include "str_process.h"  #include "str_process.h"
17    #include "trie_dict.h"
18  #include <ctype.h>  #include <ctype.h>
19  #include <stdio.h>  #include <stdio.h>
20  #include <string.h>  #include <string.h>
# Line 21  Line 22 
22    
23  enum _lml_constant_t  enum _lml_constant_t
24  {  {
25            LML_TAG_NAME_BUF_LEN = 21,
26          LML_TAG_PARAM_BUF_LEN = 256,          LML_TAG_PARAM_BUF_LEN = 256,
27          LML_TAG_OUTPUT_BUF_LEN = 1024,          LML_TAG_OUTPUT_BUF_LEN = 1024,
28          LML_TAG_QUOTE_MAX_LEVEL = 10,          LML_TAG_QUOTE_MAX_LEVEL = 10,
# Line 162  const LML_TAG_DEF lml_tag_def[] = { Line 164  const LML_TAG_DEF lml_tag_def[] = {
164    
165  static const int lml_tag_count = sizeof(lml_tag_def) / sizeof(LML_TAG_DEF);  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)];  static int lml_tag_name_len[sizeof(lml_tag_def) / sizeof(LML_TAG_DEF)];
167    static TRIE_NODE *p_lml_tag_dict;
168  static int lml_ready = 0;  static int lml_ready = 0;
169    
170  inline static void lml_init(void)  int lml_init(void)
171  {  {
172            char tag_name_buf[LML_TAG_NAME_BUF_LEN];
173          int i;          int i;
174            int j;
175    
176          if (!lml_ready)          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          {          {
190                  for (i = 0; i < lml_tag_count; i++)                  for (j = 0; j < sizeof(tag_name_buf) - 1 && lml_tag_def[i].tag_name[j] != '\0'; j++)
191                  {                  {
192                          lml_tag_name_len[i] = (int)strlen(lml_tag_def[i].tag_name);                          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                    {
199                            log_error("trie_dict_set(lml_tag_dict, %s, %d) error", tag_name_buf, i);
200                            lml_cleanup();
201                            return -1;
202                    }
203            }
204    
205            lml_ready = 1;
206    
207            return 0;
208    }
209    
210                  lml_ready = 1;  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          }          }
217    
218            lml_ready = 0;
219  }  }
220    
221  #define CHECK_AND_APPEND_OUTPUT(out_buf, out_buf_len, out_buf_offset, tag_out, tag_out_len, line_width)                             \  #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                  if ((out_buf_offset) + (tag_out_len) >= (out_buf_len))                                                                      \          {                                                                                                                             \
224                  {                                                                                                                           \                  if ((out_buf_offset) + (tag_out_len) >= (out_buf_len))                                                                    \
225                          log_error("Buffer is not longer enough for output string %d >= %d\n", (out_buf_offset) + (tag_out_len), (out_buf_len)); \                  {                                                                                                                         \
226                          out_buf[out_buf_offset] = '\0';                                                                                         \                          log_error("Buffer is not longer enough for output string %d >= %d", (out_buf_offset) + (tag_out_len), (out_buf_len)); \
227                          return (out_buf_offset);                                                                                                \                          out_buf[out_buf_offset] = '\0';                                                                                       \
228                  }                                                                                                                           \                          return (out_buf_offset);                                                                                              \
229                  memcpy((out_buf) + (out_buf_offset), (tag_out), (size_t)(tag_out_len));                                                     \                  }                                                                                                                         \
230                  *((out_buf) + (out_buf_offset) + (size_t)(tag_out_len)) = '\0';                                                             \                  memcpy((out_buf) + (out_buf_offset), (tag_out), (size_t)(tag_out_len));                                                   \
231                  (line_width) += str_length((out_buf) + (out_buf_offset), 1);                                                                \                  *((out_buf) + (out_buf_offset) + (size_t)(tag_out_len)) = '\0';                                                           \
232                  (out_buf_offset) += (tag_out_len);                                                                                          \                  (line_width) += str_length((out_buf) + (out_buf_offset), 1);                                                              \
233                    (out_buf_offset) += (tag_out_len);                                                                                        \
234          }          }
235    
236  int lml_render(const char *str_in, char *str_out, int buf_len, int width, int quote_mode)  int lml_render(const char *str_in, char *str_out, int buf_len, int width, int quote_mode)
# Line 199  int lml_render(const char *str_in, char Line 239  int lml_render(const char *str_in, char
239          clock_t clock_end;          clock_t clock_end;
240    
241          char c;          char c;
242            char tag_name_buf[LML_TAG_NAME_BUF_LEN];
243          char tag_param_buf[LML_TAG_PARAM_BUF_LEN];          char tag_param_buf[LML_TAG_PARAM_BUF_LEN];
244          char tag_output_buf[LML_TAG_OUTPUT_BUF_LEN];          char tag_output_buf[LML_TAG_OUTPUT_BUF_LEN];
245          int i;          int i;
246          int j = 0;          int j = 0;
247          int k;          int k;
248            int last_i = -1;
249            int64_t tag_index;
250          int tag_start_pos = -1;          int tag_start_pos = -1;
251          int tag_name_pos = -1;          int tag_name_pos = -1;
252          int tag_end_pos = -1;          int tag_end_pos = -1;
# Line 211  int lml_render(const char *str_in, char Line 254  int lml_render(const char *str_in, char
254          int tag_output_len;          int tag_output_len;
255          int new_line = 1;          int new_line = 1;
256          int fb_quote_level = 0;          int fb_quote_level = 0;
         int tag_name_found;  
257          int line_width = 0;          int line_width = 0;
258          char tab_spaces[TAB_SIZE + 1];          char tab_spaces[TAB_SIZE + 1];
259          int tab_width = 0;          int tab_width = 0;
260    
261          clock_begin = clock();          clock_begin = clock();
262    
263          lml_init();  #ifdef _DEBUG
264            size_t str_in_len = strlen(str_in);
265    #endif
266    
267            if (!lml_ready)
268            {
269                    log_error("LML module is not initialized");
270                    return -1;
271            }
272    
273          lml_tag_disabled = 0;          lml_tag_disabled = 0;
274          lml_tag_quote_level = 0;          lml_tag_quote_level = 0;
# Line 230  int lml_render(const char *str_in, char Line 280  int lml_render(const char *str_in, char
280    
281          for (i = 0; str_in[i] != '\0'; i++)          for (i = 0; str_in[i] != '\0'; i++)
282          {          {
283    #ifdef _DEBUG
284                    if (i >= str_in_len)
285                    {
286                            log_error("Bug: i(%d) >= str_in_len(%d)", i, str_in_len);
287                            break;
288                    }
289    #endif
290    
291                  if (!lml_tag_disabled && new_line)                  if (!lml_tag_disabled && new_line)
292                  {                  {
293                          while (str_in[i] == ':' && str_in[i + 1] == ' ') // FB2000 quote leading str                          while (str_in[i] == ':' && str_in[i + 1] == ' ') // FB2000 quote leading str
# Line 256  int lml_render(const char *str_in, char Line 314  int lml_render(const char *str_in, char
314                          CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);                          CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
315    
316                          new_line = 0;                          new_line = 0;
317                            i--; // redo at current i
318                            continue;
319                  }                  }
320    
321                  if (lml_tag_disabled && new_line)                  if (lml_tag_disabled && new_line)
# Line 383  int lml_render(const char *str_in, char Line 443  int lml_render(const char *str_in, char
443                                  tag_name_pos++;                                  tag_name_pos++;
444                          }                          }
445    
446                          for (tag_name_found = 0, k = 0; k < lml_tag_count; k++)                          for (k = 0; k < sizeof(tag_name_buf) - 1 && tag_name_pos + k < tag_end_pos; k++)
447                          {                          {
448                                  if (strncasecmp(lml_tag_def[k].tag_name, str_in + tag_name_pos, (size_t)lml_tag_name_len[k]) == 0)                                  if (str_in[tag_name_pos + k] == ' ' || str_in[tag_name_pos + k] == ']')
449                                  {                                  {
450                                          tag_param_pos = -1;                                          break;
451                                          switch (str_in[tag_name_pos + lml_tag_name_len[k]])                                  }
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                            {
472                                    tag_param_pos = -1;
473                                    switch (str_in[tag_name_pos + lml_tag_name_len[k]])
474                                    {
475                                    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                                            {
486                                                    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                                                    {
494                                                            tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].tag_output, tag_param_buf);
495                                                    }
496                                                    else if (lml_tag_def[k].tag_filter_cb != NULL)
497                                                    {
498                                                            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                                                    }
501                                            }
502                                            else // if (quote_mode)
503                                          {                                          {
504                                          case ' ':                                                  if (lml_tag_def[k].quote_mode_output != NULL)
                                                 tag_name_found = 1;  
                                                 tag_param_pos = tag_name_pos + lml_tag_name_len[k] + 1;  
                                                 while (str_in[tag_param_pos] == ' ')  
505                                                  {                                                  {
506                                                          tag_param_pos++;                                                          tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].quote_mode_output, tag_param_buf);
507                                                  }                                                  }
508                                                  strncpy(tag_param_buf, str_in + tag_param_pos, (size_t)MIN(tag_end_pos - tag_param_pos, LML_TAG_PARAM_BUF_LEN));                                                  else if (lml_tag_def[k].tag_filter_cb != NULL)
                                                 tag_param_buf[MIN(tag_end_pos - tag_param_pos, LML_TAG_PARAM_BUF_LEN)] = '\0';  
                                         case ']':  
                                                 tag_name_found = 1;  
                                                 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  
509                                                  {                                                  {
510                                                          strncpy(tag_param_buf, lml_tag_def[k].default_param, LML_TAG_PARAM_BUF_LEN - 1);                                                          tag_output_len = lml_tag_def[k].tag_filter_cb(
511                                                          tag_param_buf[LML_TAG_PARAM_BUF_LEN - 1] = '\0';                                                                  lml_tag_def[k].tag_name, tag_param_buf, tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, 1);
512                                                  }                                                  }
513                                                  tag_output_len = 0;                                          }
514                                                  if (!quote_mode)  
515                                            if (line_width + tag_output_len > width)
516                                            {
517                                                    if (i > last_i)
518                                                  {                                                  {
519                                                          if (lml_tag_def[k].tag_output != NULL)                                                          last_i = i;
520                                                          {                                                          CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, "\n", 1, line_width);
521                                                                  tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].tag_output, tag_param_buf);                                                          new_line = 1;
522                                                          }                                                          line_width = 0;
523                                                          else if (lml_tag_def[k].tag_filter_cb != NULL)                                                          i--; // redo at current i
524                                                          {                                                          continue;
                                                                 tag_output_len = lml_tag_def[k].tag_filter_cb(  
                                                                         lml_tag_def[k].tag_name, tag_param_buf, tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, 0);  
                                                         }  
525                                                  }                                                  }
526                                                  else // if (quote_mode)                                                  else
527                                                  {                                                  {
528                                                          if (lml_tag_def[k].quote_mode_output != NULL)                                                          continue; // Output current tag in plain text if line width exceeded
                                                         {  
                                                                 tag_output_len = snprintf(tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, lml_tag_def[k].quote_mode_output, tag_param_buf);  
                                                         }  
                                                         else if (lml_tag_def[k].tag_filter_cb != NULL)  
                                                         {  
                                                                 tag_output_len = lml_tag_def[k].tag_filter_cb(  
                                                                         lml_tag_def[k].tag_name, tag_param_buf, tag_output_buf, LML_TAG_OUTPUT_BUF_LEN, 1);  
                                                         }  
529                                                  }                                                  }
                                                 CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);  
                                                 break;  
                                         default: // tag_name not match  
                                                 continue;  
530                                          }                                          }
531    
532                                            CHECK_AND_APPEND_OUTPUT(str_out, buf_len, j, tag_output_buf, tag_output_len, line_width);
533                                          break;                                          break;
534                                    default:
535                                            log_error("Bug: tag name not match");
536                                  }                                  }
537                          }                          }
538                            else // tag_name not found
                         if (!tag_name_found)  
539                          {                          {
540                                  if (line_width + 1 > width)                                  if (line_width + 1 > width)
541                                  {                                  {


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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