1 #include "iwxstr.h"
2 #include "iwlog.h"
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <stdarg.h>
8
9 // Default IWXSTR initial size
10 #ifndef IWXSTR_AUNIT
11 #define IWXSTR_AUNIT 16
12 #endif
13
14 struct _IWXSTR {
15 char *ptr; /**< Data buffer */
16 size_t size; /**< Actual data size */
17 size_t asize; /**< Allocated buffer size */
18 };
19
iwxstr_new2(size_t siz)20 IWXSTR *iwxstr_new2(size_t siz) {
21 if (!siz) siz = IWXSTR_AUNIT;
22 IWXSTR *xstr = malloc(sizeof(*xstr));
23 if (!xstr) return 0;
24 xstr->ptr = malloc(siz);
25 if (!xstr->ptr) {
26 free(xstr);
27 return 0;
28 }
29 xstr->size = 0;
30 xstr->asize = siz;
31 xstr->ptr[0] = '\0';
32 return xstr;
33 }
34
iwxstr_new(void)35 IWXSTR *iwxstr_new(void) {
36 return iwxstr_new2(IWXSTR_AUNIT);
37 }
38
iwxstr_destroy(IWXSTR * xstr)39 void iwxstr_destroy(IWXSTR *xstr) {
40 if (!xstr) return;
41 free(xstr->ptr);
42 free(xstr);
43 }
44
iwxstr_clear(IWXSTR * xstr)45 void iwxstr_clear(IWXSTR *xstr) {
46 assert(xstr);
47 xstr->size = 0;
48 }
49
iwxstr_cat(IWXSTR * xstr,const void * buf,size_t size)50 iwrc iwxstr_cat(IWXSTR *xstr, const void *buf, size_t size) {
51 size_t nsize = xstr->size + size + 1;
52 if (xstr->asize < nsize) {
53 while (xstr->asize < nsize) {
54 xstr->asize <<= 1;
55 if (xstr->asize < nsize) {
56 xstr->asize = nsize;
57 }
58 }
59 char *ptr = realloc(xstr->ptr, xstr->asize);
60 if (!ptr) {
61 return IW_ERROR_ERRNO;
62 }
63 xstr->ptr = ptr;
64 }
65 memcpy(xstr->ptr + xstr->size, buf, size);
66 xstr->size += size;
67 xstr->ptr[xstr->size] = '\0';
68 return IW_OK;
69 }
70
iwxstr_cat2(IWXSTR * xstr,const char * buf)71 iwrc iwxstr_cat2(IWXSTR *xstr, const char *buf) {
72 return buf ? iwxstr_cat(xstr, buf, strlen(buf)) : 0;
73 }
74
iwxstr_unshift(IWXSTR * xstr,const void * buf,size_t size)75 iwrc iwxstr_unshift(IWXSTR *xstr, const void *buf, size_t size) {
76 size_t nsize = xstr->size + size + 1;
77 if (xstr->asize < nsize) {
78 while (xstr->asize < nsize) {
79 xstr->asize <<= 1;
80 if (xstr->asize < nsize) {
81 xstr->asize = nsize;
82 }
83 }
84 char *ptr = realloc(xstr->ptr, xstr->asize);
85 if (!ptr) {
86 return IW_ERROR_ERRNO;
87 }
88 xstr->ptr = ptr;
89 }
90 if (xstr->size) {
91 // shift to right
92 memmove(xstr->ptr + size, xstr->ptr, xstr->size);
93 }
94 memcpy(xstr->ptr, buf, size);
95 xstr->size += size;
96 xstr->ptr[xstr->size] = '\0';
97 return IW_OK;
98 }
99
iwxstr_shift(IWXSTR * xstr,size_t shift_size)100 void iwxstr_shift(IWXSTR *xstr, size_t shift_size) {
101 if (shift_size == 0) {
102 return;
103 }
104 if (shift_size > xstr->size) {
105 shift_size = xstr->size;
106 }
107 if (xstr->size > shift_size) {
108 memmove(xstr->ptr, xstr->ptr + shift_size, xstr->size - shift_size);
109 }
110 xstr->size -= shift_size;
111 xstr->ptr[xstr->size] = '\0';
112 }
113
iwxstr_vaprintf(IWXSTR * xstr,const char * format,va_list ap)114 static iwrc iwxstr_vaprintf(IWXSTR *xstr, const char *format, va_list ap) {
115 iwrc rc = 0;
116 while (*format) {
117 if (*format == '%') {
118 char cbuf[32];
119 cbuf[0] = '%';
120 size_t cblen = 1;
121 int lnum = 0;
122 ++format;
123 while (strchr("0123456789 .+-hlLzI", *format) && *format && cblen < sizeof(cbuf) - 1) {
124 if (*format == 'l' || *format == 'L') {
125 lnum++;
126 }
127 cbuf[cblen++] = *(format++);
128 }
129 cbuf[cblen++] = *format;
130 cbuf[cblen] = '\0';
131 int tlen;
132 char *tmp, tbuf[128];
133 switch (*format) {
134 case 's':
135 tmp = va_arg(ap, char *);
136 if (!tmp) tmp = "(null)";
137 rc = iwxstr_cat(xstr, tmp, strlen(tmp));
138 break;
139 case 'd':
140 if (lnum >= 2) { // -V1037
141 tlen = sprintf(tbuf, cbuf, va_arg(ap, long long));
142 } else if (lnum >= 1) {
143 tlen = sprintf(tbuf, cbuf, va_arg(ap, long));
144 } else {
145 tlen = sprintf(tbuf, cbuf, va_arg(ap, int));
146 }
147 rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
148 break;
149 case 'o':
150 case 'u':
151 case 'x':
152 case 'X':
153 case 'c':
154 if (lnum >= 2) {
155 tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long long));
156 } else if (lnum >= 1) {
157 tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned long));
158 } else {
159 tlen = sprintf(tbuf, cbuf, va_arg(ap, unsigned int));
160 }
161 rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
162 break;
163 case 'e':
164 case 'E':
165 case 'f':
166 case 'g':
167 case 'G':
168 if (lnum > 1) {
169 tlen = snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, long double));
170 } else {
171 tlen = snprintf(tbuf, sizeof(tbuf), cbuf, va_arg(ap, double));
172 }
173 if (tlen < 0 || tlen >= sizeof(tbuf)) {
174 tbuf[sizeof(tbuf) - 1] = '*';
175 tlen = sizeof(tbuf);
176 }
177 rc = iwxstr_cat(xstr, tbuf, (size_t) tlen);
178 break;
179 case '%':
180 rc = iwxstr_cat(xstr, "%", 1);
181 break;
182 }
183 RCBREAK(rc);
184 } else {
185 rc = iwxstr_cat(xstr, format, 1);
186 RCRET(rc);
187 }
188 format++;
189 }
190 return rc;
191 }
192
iwxstr_printf(IWXSTR * xstr,const char * format,...)193 iwrc iwxstr_printf(IWXSTR *xstr, const char *format, ...) {
194 va_list ap;
195 va_start(ap, format);
196 iwrc rc = iwxstr_vaprintf(xstr, format, ap);
197 va_end(ap);
198 return rc;
199 }
200
iwxstr_ptr(IWXSTR * xstr)201 char *iwxstr_ptr(IWXSTR *xstr) {
202 return xstr->ptr;
203 }
204
iwxstr_size(IWXSTR * xstr)205 size_t iwxstr_size(IWXSTR *xstr) {
206 return xstr->size;
207 }
208
209