1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Felipe Pena <felipe@php.net>                                |
16    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
17    | Authors: Bob Weinand <bwoebi@php.net>                                |
18    +----------------------------------------------------------------------+
19 */
20 
21 #include "phpdbg.h"
22 #include "phpdbg_cmd.h"
23 #include "phpdbg_set.h"
24 #include "phpdbg_utils.h"
25 #include "phpdbg_bp.h"
26 #include "phpdbg_prompt.h"
27 
28 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
29 
30 #define PHPDBG_SET_COMMAND_D(f, h, a, m, l, s, flags) \
31 	PHPDBG_COMMAND_D_EXP(f, h, a, m, l, s, &phpdbg_prompt_commands[17], flags)
32 
33 const phpdbg_command_t phpdbg_set_commands[] = {
34 	PHPDBG_SET_COMMAND_D(prompt,       "usage: set prompt [<string>]",            'p', set_prompt,       NULL, "|s", 0),
35 	PHPDBG_SET_COMMAND_D(pagination,   "usage: set pagination [<on|off>]",        'P', set_pagination,   NULL, "|b", PHPDBG_ASYNC_SAFE),
36 #ifndef _WIN32
37 	PHPDBG_SET_COMMAND_D(color,        "usage: set color  <element> <color>",     'c', set_color,        NULL, "ss", PHPDBG_ASYNC_SAFE),
38 	PHPDBG_SET_COMMAND_D(colors,       "usage: set colors [<on|off>]",            'C', set_colors,       NULL, "|b", PHPDBG_ASYNC_SAFE),
39 #endif
40 	PHPDBG_SET_COMMAND_D(oplog,        "usage: set oplog  [<output>]",            'O', set_oplog,        NULL, "|s", 0),
41 	PHPDBG_SET_COMMAND_D(break,        "usage: set break id [<on|off>]",          'b', set_break,        NULL, "l|b", PHPDBG_ASYNC_SAFE),
42 	PHPDBG_SET_COMMAND_D(breaks,       "usage: set breaks [<on|off>]",            'B', set_breaks,       NULL, "|b", PHPDBG_ASYNC_SAFE),
43 	PHPDBG_SET_COMMAND_D(quiet,        "usage: set quiet [<on|off>]",             'q', set_quiet,        NULL, "|b", PHPDBG_ASYNC_SAFE),
44 	PHPDBG_SET_COMMAND_D(stepping,     "usage: set stepping [<line|op>]",         's', set_stepping,     NULL, "|s", PHPDBG_ASYNC_SAFE),
45 	PHPDBG_SET_COMMAND_D(refcount,     "usage: set refcount [<on|off>]",          'r', set_refcount,     NULL, "|b", PHPDBG_ASYNC_SAFE),
46 	PHPDBG_SET_COMMAND_D(lines,        "usage: set lines [<number>]",             'l', set_lines,        NULL, "|l", PHPDBG_ASYNC_SAFE),
47 	PHPDBG_END_COMMAND
48 };
49 
PHPDBG_SET(prompt)50 PHPDBG_SET(prompt) /* {{{ */
51 {
52 	if (!param || param->type == EMPTY_PARAM) {
53 		phpdbg_writeln("setprompt", "str=\"%s\"", "Current prompt: %s", phpdbg_get_prompt());
54 	} else {
55 		phpdbg_set_prompt(param->str);
56 	}
57 
58 	return SUCCESS;
59 } /* }}} */
60 
PHPDBG_SET(pagination)61 PHPDBG_SET(pagination) /* {{{ */
62 {
63 	if (!param || param->type == EMPTY_PARAM) {
64 		phpdbg_writeln("setpagination", "active=\"%s\"", "Pagination %s", PHPDBG_G(flags) & PHPDBG_HAS_PAGINATION ? "on" : "off");
65 	} else switch (param->type) {
66 		case NUMERIC_PARAM: {
67 			if (param->num) {
68 				PHPDBG_G(flags) |= PHPDBG_HAS_PAGINATION;
69 			} else {
70 				PHPDBG_G(flags) &= ~PHPDBG_HAS_PAGINATION;
71 			}
72 		} break;
73 
74 		default:
75 			phpdbg_error("setpagination", "type=\"wrongargs\"", "set pagination used incorrectly: set pagination <on|off>");
76 	}
77 
78 	return SUCCESS;
79 } /* }}} */
80 
PHPDBG_SET(lines)81 PHPDBG_SET(lines) /* {{{ */
82 {
83 	if (!param || param->type == EMPTY_PARAM) {
84 		phpdbg_writeln("setlines", "active=\"%s\"", "Lines %ld", PHPDBG_G(lines));
85 	} else switch (param->type) {
86 		case NUMERIC_PARAM: {
87 			PHPDBG_G(lines) = param->num;
88 		} break;
89 
90 		default:
91 			phpdbg_error("setlines", "type=\"wrongargs\"", "set lines used incorrectly: set lines <number>");
92 	}
93 
94 	return SUCCESS;
95 } /* }}} */
96 
PHPDBG_SET(break)97 PHPDBG_SET(break) /* {{{ */
98 {
99 	switch (param->type) {
100 		case NUMERIC_PARAM: {
101 			if (param->next) {
102 				if (param->next->num) {
103 					phpdbg_enable_breakpoint(param->num);
104 				} else {
105 					phpdbg_disable_breakpoint(param->num);
106 				}
107 			} else {
108 				phpdbg_breakbase_t *brake = phpdbg_find_breakbase(param->num);
109 				if (brake) {
110 					phpdbg_writeln("setbreak", "id=\"%ld\" active=\"%s\"", "Breakpoint #%ld %s", param->num, brake->disabled ? "off" : "on");
111 				} else {
112 					phpdbg_error("setbreak", "type=\"nobreak\" id=\"%ld\"", "Failed to find breakpoint #%ld", param->num);
113 				}
114 			}
115 		} break;
116 
117 		default:
118 			phpdbg_error("setbreak", "type=\"wrongargs\"", "set break used incorrectly: set break [id] <on|off>");
119 	}
120 
121 	return SUCCESS;
122 } /* }}} */
123 
PHPDBG_SET(breaks)124 PHPDBG_SET(breaks) /* {{{ */
125 {
126 	if (!param || param->type == EMPTY_PARAM) {
127 		phpdbg_writeln("setbreaks", "active=\"%s\"", "Breakpoints %s",PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED ? "on" : "off");
128 	} else switch (param->type) {
129 		case NUMERIC_PARAM: {
130 			if (param->num) {
131 				phpdbg_enable_breakpoints();
132 			} else {
133 				phpdbg_disable_breakpoints();
134 			}
135 		} break;
136 
137 		default:
138 			phpdbg_error("setbreaks", "type=\"wrongargs\"", "set breaks used incorrectly: set breaks <on|off>");
139 	}
140 
141 	return SUCCESS;
142 } /* }}} */
143 
144 #ifndef _WIN32
PHPDBG_SET(color)145 PHPDBG_SET(color) /* {{{ */
146 {
147 	const phpdbg_color_t *color = phpdbg_get_color(param->next->str, param->next->len);
148 
149 	if (!color) {
150 		phpdbg_error("setcolor", "type=\"nocolor\"", "Failed to find the requested color (%s)", param->next->str);
151 		return SUCCESS;
152 	}
153 
154 	switch (phpdbg_get_element(param->str, param->len)) {
155 		case PHPDBG_COLOR_PROMPT:
156 			phpdbg_notice("setcolor", "type=\"prompt\" color=\"%s\" code=\"%s\"", "setting prompt color to %s (%s)", color->name, color->code);
157 			if (PHPDBG_G(prompt)[1]) {
158 				free(PHPDBG_G(prompt)[1]);
159 				PHPDBG_G(prompt)[1]=NULL;
160 			}
161 			phpdbg_set_color(PHPDBG_COLOR_PROMPT, color);
162 		break;
163 
164 		case PHPDBG_COLOR_ERROR:
165 			phpdbg_notice("setcolor", "type=\"error\" color=\"%s\" code=\"%s\"", "setting error color to %s (%s)", color->name, color->code);
166 			phpdbg_set_color(PHPDBG_COLOR_ERROR, color);
167 		break;
168 
169 		case PHPDBG_COLOR_NOTICE:
170 			phpdbg_notice("setcolor", "type=\"notice\" color=\"%s\" code=\"%s\"", "setting notice color to %s (%s)", color->name, color->code);
171 			phpdbg_set_color(PHPDBG_COLOR_NOTICE, color);
172 		break;
173 
174 		default:
175 			phpdbg_error("setcolor", "type=\"invalidtype\"", "Failed to find the requested element (%s)", param->str);
176 	}
177 
178 	return SUCCESS;
179 } /* }}} */
180 
PHPDBG_SET(colors)181 PHPDBG_SET(colors) /* {{{ */
182 {
183 	if (!param || param->type == EMPTY_PARAM) {
184 		phpdbg_writeln("setcolors", "active=\"%s\"", "Colors %s", PHPDBG_G(flags) & PHPDBG_IS_COLOURED ? "on" : "off");
185 	} else switch (param->type) {
186 		case NUMERIC_PARAM: {
187 			if (param->num) {
188 				PHPDBG_G(flags) |= PHPDBG_IS_COLOURED;
189 			} else {
190 				PHPDBG_G(flags) &= ~PHPDBG_IS_COLOURED;
191 			}
192 		} break;
193 
194 		default:
195 			phpdbg_error("setcolors", "type=\"wrongargs\"", "set colors used incorrectly: set colors <on|off>");
196 	}
197 
198 	return SUCCESS;
199 } /* }}} */
200 #endif
201 
PHPDBG_SET(oplog)202 PHPDBG_SET(oplog) /* {{{ */
203 {
204 	if (!param || param->type == EMPTY_PARAM) {
205 		phpdbg_notice("setoplog", "active=\"%s\"", "Oplog %s", PHPDBG_G(oplog) ? "on" : "off");
206 	} else switch (param->type) {
207 		case STR_PARAM: {
208 			/* open oplog */
209 			FILE *old = PHPDBG_G(oplog);
210 
211 			PHPDBG_G(oplog) = fopen(param->str, "w+");
212 			if (!PHPDBG_G(oplog)) {
213 				phpdbg_error("setoplog", "type=\"openfailure\" file=\"%s\"", "Failed to open %s for oplog", param->str);
214 				PHPDBG_G(oplog) = old;
215 			} else {
216 				if (old) {
217 					phpdbg_notice("setoplog", "type=\"closingold\"", "Closing previously open oplog");
218 					fclose(old);
219 				}
220 
221 				phpdbg_notice("setoplog", "file=\"%s\"", "Successfully opened oplog %s", param->str);
222 			}
223 		} break;
224 
225 		phpdbg_default_switch_case();
226 	}
227 
228 	return SUCCESS;
229 } /* }}} */
230 
PHPDBG_SET(quiet)231 PHPDBG_SET(quiet) /* {{{ */
232 {
233 	if (!param || param->type == EMPTY_PARAM) {
234 		phpdbg_writeln("setquiet", "active=\"%s\"", "Quietness %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
235 	} else switch (param->type) {
236 		case NUMERIC_PARAM: {
237 			if (param->num) {
238 				PHPDBG_G(flags) |= PHPDBG_IS_QUIET;
239 			} else {
240 				PHPDBG_G(flags) &= ~PHPDBG_IS_QUIET;
241 			}
242 		} break;
243 
244 		phpdbg_default_switch_case();
245 	}
246 
247 	return SUCCESS;
248 } /* }}} */
249 
PHPDBG_SET(stepping)250 PHPDBG_SET(stepping) /* {{{ */
251 {
252 	if (!param || param->type == EMPTY_PARAM) {
253 		phpdbg_writeln("setstepping", "type=\"%s\"", "Stepping %s", PHPDBG_G(flags) & PHPDBG_STEP_OPCODE ? "opcode" : "line");
254 	} else switch (param->type) {
255 		case STR_PARAM: {
256 			if (param->len == sizeof("opcode") - 1 && !memcmp(param->str, "opcode", sizeof("opcode"))) {
257 				PHPDBG_G(flags) |= PHPDBG_STEP_OPCODE;
258 			} else if (param->len == sizeof("line") - 1 && !memcmp(param->str, "line", sizeof("line"))) {
259 				PHPDBG_G(flags) &= ~PHPDBG_STEP_OPCODE;
260 			} else {
261 				phpdbg_error("setstepping", "type=\"wrongargs\"", "usage set stepping [<opcode|line>]");
262 			}
263 		} break;
264 
265 		phpdbg_default_switch_case();
266 	}
267 
268 	return SUCCESS;
269 } /* }}} */
270 
PHPDBG_SET(refcount)271 PHPDBG_SET(refcount) /* {{{ */
272 {
273 	if (!param || param->type == EMPTY_PARAM) {
274 		phpdbg_writeln("setrefcount", "active=\"%s\"", "Showing refcounts %s", PHPDBG_G(flags) & PHPDBG_IS_QUIET ? "on" : "off");
275 	} else switch (param->type) {
276 		case NUMERIC_PARAM: {
277 			if (param->num) {
278 				PHPDBG_G(flags) |= PHPDBG_SHOW_REFCOUNTS;
279 			} else {
280 				PHPDBG_G(flags) &= ~PHPDBG_SHOW_REFCOUNTS;
281 			}
282 		} break;
283 
284 		phpdbg_default_switch_case();
285 	}
286 
287 	return SUCCESS;
288 } /* }}} */
289