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