1 /*
2 +----------------------------------------------------------------------+
3 | Xdebug |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2002-2020 Derick Rethans |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 1.01 of the Xdebug license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available at through the world-wide-web at |
10 | https://xdebug.org/license.php |
11 | If you did not receive a copy of the Xdebug license and are unable |
12 | to obtain it through the world-wide-web, please send a note to |
13 | derick@xdebug.org so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 */
16
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <locale.h>
22
23 #include "php.h"
24 #include "ext/standard/php_string.h"
25
26 #include "mm.h"
27 #include "str.h"
28
realloc_if_needed(xdebug_str * xs,int size_to_fit)29 inline static void realloc_if_needed(xdebug_str *xs, int size_to_fit)
30 {
31 if (!xs->a || !xs->l || xs->l + size_to_fit > xs->a - 1) {
32 xs->d = xdrealloc(xs->d, xs->a + size_to_fit + XDEBUG_STR_PREALLOC);
33 xs->a = xs->a + size_to_fit + XDEBUG_STR_PREALLOC;
34 }
35 if (!xs->l) {
36 xs->d[0] = '\0';
37 }
38 }
39
xdebug_str_internal_addl(xdebug_str * xs,const char * str,int le,int f)40 inline static void xdebug_str_internal_addl(xdebug_str *xs, const char *str, int le, int f)
41 {
42 realloc_if_needed(xs, le);
43
44 memcpy(xs->d + xs->l, str, le);
45 xs->d[xs->l + le] = '\0';
46 xs->l = xs->l + le;
47
48 if (f) {
49 xdfree((char*) str);
50 }
51 }
52
xdebug_str_add(xdebug_str * xs,const char * str,int f)53 void xdebug_str_add(xdebug_str *xs, const char *str, int f)
54 {
55 xdebug_str_internal_addl(xs, str, strlen(str), f);
56 }
57
xdebug_str_addl(xdebug_str * xs,const char * str,int le,int f)58 void xdebug_str_addl(xdebug_str *xs, const char *str, int le, int f)
59 {
60 xdebug_str_internal_addl(xs, str, le, f);
61 }
62
xdebug_str_add_str(xdebug_str * xs,const xdebug_str * str)63 void xdebug_str_add_str(xdebug_str *xs, const xdebug_str *str)
64 {
65 xdebug_str_internal_addl(xs, str->d, str->l, 0);
66 }
67
xdebug_str_add_zstr(xdebug_str * xs,const zend_string * str)68 void xdebug_str_add_zstr(xdebug_str *xs, const zend_string *str)
69 {
70 xdebug_str_internal_addl(xs, ZSTR_VAL(str), ZSTR_LEN(str), 0);
71 }
72
xdebug_str_addc(xdebug_str * xs,char letter)73 void xdebug_str_addc(xdebug_str *xs, char letter)
74 {
75 realloc_if_needed(xs, 1);
76
77 xs->d[xs->l] = letter;
78 xs->d[xs->l + 1] = '\0';
79 xs->l = xs->l + 1;
80 }
81
xdebug_str_add_uint64(xdebug_str * xs,uint64_t num)82 void xdebug_str_add_uint64(xdebug_str *xs, uint64_t num)
83 {
84 char buffer[21];
85 char *pos;
86 int digit;
87
88 pos = &buffer[20];
89 *pos = '\0';
90
91 do {
92 digit = num % 10;
93 num = num / 10;
94 if (digit < 10) {
95 *--pos = '0' + digit;
96 } else {
97 *--pos = 'a' + digit - 10;
98 }
99 } while (num != 0L);
100
101 xdebug_str_internal_addl(xs, pos, &buffer[20] - pos, 0);
102 }
103
xdebug_str_add_va_fmt(xdebug_str * xs,const char * fmt,va_list argv)104 void xdebug_str_add_va_fmt(xdebug_str *xs, const char *fmt, va_list argv)
105 {
106 int size;
107 int n;
108 va_list argv_size, argv_copy;
109
110 realloc_if_needed(xs, 1);
111 size = xs->a - xs->l;
112
113 va_copy(argv_size, argv);
114 n = vsnprintf(xs->d + xs->l, size, fmt, argv_size);
115 va_end(argv_size);
116 if (n > -1 && n < size) {
117 xs->l += n;
118 return;
119 }
120
121 realloc_if_needed(xs, n + 1);
122 size = xs->a - xs->l;
123
124 va_copy(argv_copy, argv);
125 n = vsnprintf(xs->d + xs->l, size, fmt, argv_copy);
126 va_end(argv_copy);
127
128 if (n > -1 && n < size) {
129 xs->l += n;
130 return;
131 }
132
133 assert(0);
134 }
135
xdebug_str_add_fmt(xdebug_str * xs,const char * fmt,...)136 void xdebug_str_add_fmt(xdebug_str *xs, const char *fmt, ...)
137 {
138 va_list args;
139
140 va_start(args, fmt);
141 xdebug_str_add_va_fmt(xs, fmt, args);
142 va_end(args);
143 }
144
xdebug_str_chop(xdebug_str * xs,size_t c)145 void xdebug_str_chop(xdebug_str *xs, size_t c)
146 {
147 if (c > xs->l) {
148 /* Do nothing if the chop amount is larger than the buffer size */
149 } else {
150 xs->l -= c;
151 xs->d[xs->l] = '\0';
152 }
153 }
154
xdebug_str_new(void)155 xdebug_str *xdebug_str_new(void)
156 {
157 xdebug_str *tmp = xdmalloc(sizeof(xdebug_str));
158
159 tmp->l = 0;
160 tmp->a = 0;
161 tmp->d = NULL;
162
163 return tmp;
164 }
165
xdebug_str_create(const char * c,size_t len)166 xdebug_str *xdebug_str_create(const char *c, size_t len)
167 {
168 xdebug_str *tmp = xdebug_str_new();
169
170 tmp->l = tmp->a = len;
171 tmp->a++;
172 tmp->d = xdmalloc(tmp->a);
173 memcpy(tmp->d, c, tmp->l);
174 tmp->d[tmp->l] = '\0';
175
176 return tmp;
177 }
178
xdebug_str_create_from_char(char * c)179 xdebug_str *xdebug_str_create_from_char(char *c)
180 {
181 return xdebug_str_create(c, strlen(c));
182 }
183
xdebug_str_copy(xdebug_str * orig)184 xdebug_str *xdebug_str_copy(xdebug_str *orig)
185 {
186 xdebug_str *tmp = xdebug_str_new();
187
188 tmp->l = tmp->a = orig->l;
189 tmp->a++;
190 tmp->d = xdmalloc(tmp->a);
191 memcpy(tmp->d, orig->d, tmp->l);
192 tmp->d[orig->l] = '\0';
193
194 return tmp;
195 }
196
xdebug_str_destroy(xdebug_str * s)197 void xdebug_str_destroy(xdebug_str *s)
198 {
199 if (s->d) {
200 xdfree(s->d);
201 }
202 }
203
xdebug_str_free(xdebug_str * s)204 void xdebug_str_free(xdebug_str *s)
205 {
206 xdebug_str_destroy(s);
207 xdfree(s);
208 }
209
xdebug_sprintf(const char * fmt,...)210 char *xdebug_sprintf(const char* fmt, ...)
211 {
212 char *new_str;
213 int size = 32;
214 va_list args;
215
216 new_str = (char *) xdmalloc(size);
217
218 for (;;) {
219 int n;
220
221 va_start(args, fmt);
222 n = vsnprintf(new_str, size, fmt, args);
223 va_end(args);
224
225 if (n > -1 && n < size) {
226 break;
227 }
228 if (n < 0) {
229 size *= 2;
230 } else {
231 size = n + 1;
232 }
233 new_str = (char *) xdrealloc(new_str, size);
234 }
235
236 return new_str;
237 }
238
239 /**
240 * Duplicate zend_strndup in core to avoid mismatches
241 * in C-runtime libraries when xdebug and core are built
242 * with different run-time libraries.
243 */
xdebug_strndup(const char * s,int length)244 char *xdebug_strndup(const char *s, int length)
245 {
246 char *p;
247
248 p = (char *) xdmalloc(length + 1);
249 if (p == NULL) {
250 return p;
251 }
252 if (length) {
253 memcpy(p, s, length);
254 }
255 p[length] = 0;
256 return p;
257 }
258