xref: /php-src/ext/dom/lexbor/lexbor/core/print.c (revision f0934090)
1 /*
2  * Copyright (C) 2021 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/core/str.h"
8 #include "lexbor/core/print.h"
9 
10 
11 #define lexbor_sprintf_append(dst, end, src, length)                          \
12     do {                                                                      \
13         if ((size_t) ((end) - (dst)) < (length)) {                            \
14             return (end) - (dst);                                             \
15         }                                                                     \
16                                                                               \
17         memcpy((dst), (src), (length));                                       \
18         (dst) += (length);                                                    \
19     }                                                                         \
20     while (false)
21 
22 
23 size_t
lexbor_printf_size(const char * format,...)24 lexbor_printf_size(const char *format, ...)
25 {
26     size_t ret;
27     va_list va;
28 
29     va_start(va, format);
30     ret = lexbor_vprintf_size(format, va);
31     va_end(va);
32 
33     return ret;
34 }
35 
36 size_t
lexbor_vprintf_size(const char * format,va_list va)37 lexbor_vprintf_size(const char *format, va_list va)
38 {
39     char c;
40     const char *begin, *cdata;
41     size_t size;
42     lexbor_str_t *str;
43 
44     begin = format;
45     size = 0;
46 
47     while (true) {
48         c = *format;
49 
50         if (c == '%') {
51             c = format[1];
52 
53             switch (c) {
54                 case '\0':
55                     return size + (format - begin) + 1;
56 
57                 case 's':
58                     cdata = va_arg(va, const char *);
59                     size += (format - begin) + strlen(cdata);
60                     break;
61 
62                 case 'S':
63                     str = va_arg(va, lexbor_str_t *);
64                     size += (format - begin) + str->length;
65                     break;
66 
67                 case '%':
68                     size += (format - begin) + 1;
69                     break;
70 
71                 default:
72                     return LXB_PRINT_ERROR;
73             }
74 
75             format++;
76             begin = format + 1;
77         }
78         else if (c == '\0') {
79             return size + (format - begin);
80         }
81 
82         format++;
83     }
84 }
85 
86 size_t
lexbor_sprintf(lxb_char_t * dst,size_t size,const char * format,...)87 lexbor_sprintf(lxb_char_t *dst, size_t size, const char *format, ...)
88 {
89     size_t ret;
90     va_list va;
91 
92     va_start(va, format);
93     ret = lexbor_vsprintf(dst, size, format, va);
94     va_end(va);
95 
96     return ret;
97 }
98 
99 size_t
lexbor_vsprintf(lxb_char_t * dst,size_t size,const char * format,va_list va)100 lexbor_vsprintf(lxb_char_t *dst, size_t size, const char *format, va_list va)
101 {
102     char c;
103     const char *begin, *cdata;
104     lxb_char_t *end, *start;
105     lexbor_str_t *str;
106 
107     begin = format;
108     start = dst;
109     end = dst + size;
110 
111     while (true) {
112         c = *format;
113 
114         if (c == '%') {
115             c = format[1];
116 
117             switch (c) {
118                 case '\0':
119                     size = (format - begin) + 1;
120                     lexbor_sprintf_append(dst, end, begin, size);
121                     goto done;
122 
123                 case 's':
124                     size = format - begin;
125                     lexbor_sprintf_append(dst, end, begin, size);
126 
127                     cdata = va_arg(va, const char *);
128                     size = strlen(cdata);
129                     lexbor_sprintf_append(dst, end, cdata, size);
130                     break;
131 
132                 case 'S':
133                     size = format - begin;
134                     lexbor_sprintf_append(dst, end, begin, size);
135 
136                     str = va_arg(va, lexbor_str_t *);
137                     lexbor_sprintf_append(dst, end, str->data, str->length);
138                     break;
139 
140                 case '%':
141                     size = (format - begin) + 1;
142                     lexbor_sprintf_append(dst, end, begin, size);
143                     break;
144 
145                 default:
146                     return LXB_PRINT_ERROR;
147             }
148 
149             format++;
150             begin = format + 1;
151         }
152         else if (c == '\0') {
153             size = format - begin;
154             lexbor_sprintf_append(dst, end, begin, size);
155             goto done;
156         }
157 
158         format++;
159     }
160 
161 done:
162 
163     if (end - dst > 0) {
164         *dst = '\0';
165     }
166 
167     return dst - start;
168 }
169