xref: /PHP-7.4/Zend/zend_highlight.c (revision 7f72d771)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "zend.h"
21 #include <zend_language_parser.h>
22 #include "zend_compile.h"
23 #include "zend_highlight.h"
24 #include "zend_ptr_stack.h"
25 #include "zend_globals.h"
26 #include "zend_exceptions.h"
27 
zend_html_putc(char c)28 ZEND_API void zend_html_putc(char c)
29 {
30 	switch (c) {
31 		case '\n':
32 			ZEND_PUTS("<br />");
33 			break;
34 		case '<':
35 			ZEND_PUTS("&lt;");
36 			break;
37 		case '>':
38 			ZEND_PUTS("&gt;");
39 			break;
40 		case '&':
41 			ZEND_PUTS("&amp;");
42 			break;
43 		case ' ':
44 			ZEND_PUTS("&nbsp;");
45 			break;
46 		case '\t':
47 			ZEND_PUTS("&nbsp;&nbsp;&nbsp;&nbsp;");
48 			break;
49 		default:
50 			ZEND_PUTC(c);
51 			break;
52 	}
53 }
54 
55 
zend_html_puts(const char * s,size_t len)56 ZEND_API void zend_html_puts(const char *s, size_t len)
57 {
58 	const unsigned char *ptr = (const unsigned char*)s, *end = ptr + len;
59 	unsigned char *filtered = NULL;
60 	size_t filtered_len;
61 
62 	if (LANG_SCNG(output_filter)) {
63 		LANG_SCNG(output_filter)(&filtered, &filtered_len, ptr, len);
64 		ptr = filtered;
65 		end = filtered + filtered_len;
66 	}
67 
68 	while (ptr<end) {
69 		if (*ptr==' ') {
70 			do {
71 				zend_html_putc(*ptr);
72 			} while ((++ptr < end) && (*ptr==' '));
73 		} else {
74 			zend_html_putc(*ptr++);
75 		}
76 	}
77 
78 	if (LANG_SCNG(output_filter)) {
79 		efree(filtered);
80 	}
81 }
82 
83 
zend_highlight(zend_syntax_highlighter_ini * syntax_highlighter_ini)84 ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini)
85 {
86 	zval token;
87 	int token_type;
88 	char *last_color = syntax_highlighter_ini->highlight_html;
89 	char *next_color;
90 
91 	zend_printf("<code>");
92 	zend_printf("<span style=\"color: %s\">\n", last_color);
93 	/* highlight stuff coming back from zendlex() */
94 	while ((token_type=lex_scan(&token, NULL))) {
95 		switch (token_type) {
96 			case T_INLINE_HTML:
97 				next_color = syntax_highlighter_ini->highlight_html;
98 				break;
99 			case T_COMMENT:
100 			case T_DOC_COMMENT:
101 				next_color = syntax_highlighter_ini->highlight_comment;
102 				break;
103 			case T_OPEN_TAG:
104 			case T_OPEN_TAG_WITH_ECHO:
105 			case T_CLOSE_TAG:
106 			case T_LINE:
107 			case T_FILE:
108 			case T_DIR:
109 			case T_TRAIT_C:
110 			case T_METHOD_C:
111 			case T_FUNC_C:
112 			case T_NS_C:
113 			case T_CLASS_C:
114 				next_color = syntax_highlighter_ini->highlight_default;
115 				break;
116 			case '"':
117 			case T_ENCAPSED_AND_WHITESPACE:
118 			case T_CONSTANT_ENCAPSED_STRING:
119 				next_color = syntax_highlighter_ini->highlight_string;
120 				break;
121 			case T_WHITESPACE:
122 				zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));  /* no color needed */
123 				ZVAL_UNDEF(&token);
124 				continue;
125 				break;
126 			default:
127 				if (Z_TYPE(token) == IS_UNDEF) {
128 					next_color = syntax_highlighter_ini->highlight_keyword;
129 				} else {
130 					next_color = syntax_highlighter_ini->highlight_default;
131 				}
132 				break;
133 		}
134 
135 		if (last_color != next_color) {
136 			if (last_color != syntax_highlighter_ini->highlight_html) {
137 				zend_printf("</span>");
138 			}
139 			last_color = next_color;
140 			if (last_color != syntax_highlighter_ini->highlight_html) {
141 				zend_printf("<span style=\"color: %s\">", last_color);
142 			}
143 		}
144 
145 		zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
146 
147 		if (Z_TYPE(token) == IS_STRING) {
148 			switch (token_type) {
149 				case T_OPEN_TAG:
150 				case T_OPEN_TAG_WITH_ECHO:
151 				case T_CLOSE_TAG:
152 				case T_WHITESPACE:
153 				case T_COMMENT:
154 				case T_DOC_COMMENT:
155 					break;
156 				default:
157 					zval_ptr_dtor_str(&token);
158 					break;
159 			}
160 		}
161 		ZVAL_UNDEF(&token);
162 	}
163 
164 	if (last_color != syntax_highlighter_ini->highlight_html) {
165 		zend_printf("</span>\n");
166 	}
167 	zend_printf("</span>\n");
168 	zend_printf("</code>");
169 
170 	/* Discard parse errors thrown during tokenization */
171 	zend_clear_exception();
172 }
173 
zend_strip(void)174 ZEND_API void zend_strip(void)
175 {
176 	zval token;
177 	int token_type;
178 	int prev_space = 0;
179 
180 	while ((token_type=lex_scan(&token, NULL))) {
181 		switch (token_type) {
182 			case T_WHITESPACE:
183 				if (!prev_space) {
184 					zend_write(" ", sizeof(" ") - 1);
185 					prev_space = 1;
186 				}
187 						/* lack of break; is intentional */
188 			case T_COMMENT:
189 			case T_DOC_COMMENT:
190 				ZVAL_UNDEF(&token);
191 				continue;
192 
193 			case T_END_HEREDOC:
194 				zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
195 				/* read the following character, either newline or ; */
196 				if (lex_scan(&token, NULL) != T_WHITESPACE) {
197 					zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
198 				}
199 				zend_write("\n", sizeof("\n") - 1);
200 				prev_space = 1;
201 				ZVAL_UNDEF(&token);
202 				continue;
203 
204 			default:
205 				zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
206 				break;
207 		}
208 
209 		if (Z_TYPE(token) == IS_STRING) {
210 			switch (token_type) {
211 				case T_OPEN_TAG:
212 				case T_OPEN_TAG_WITH_ECHO:
213 				case T_CLOSE_TAG:
214 				case T_WHITESPACE:
215 				case T_COMMENT:
216 				case T_DOC_COMMENT:
217 					break;
218 
219 				default:
220 					zval_ptr_dtor_str(&token);
221 					break;
222 			}
223 		}
224 		prev_space = 0;
225 		ZVAL_UNDEF(&token);
226 	}
227 
228 	/* Discard parse errors thrown during tokenization */
229 	zend_clear_exception();
230 }
231