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