# [patch] highlight_[file|string] and line numbers

- Thread: https://externals.io/message/15407
- Original archive: https://news-web.php.net/php.internals/15407
- Started by Johannes Schlueter on 2005-03-12T23:16:14+00:00
- Messages: 5
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #15407 — Johannes Schlueter — 2005-03-12T23:16:14+00:00

URL: https://externals.io/message/15407#15407

Hi,

some days (or even weeks?) ago Lukas asked on IRC wether there is a way to get 
PHP code highlighted with linenumbers. The first reaction of most people 
(including me) was "no" since you can't copy&paste the code but after 
thinking I found out that <ol> works really fine. So I've implemented it that 
way and added an optional bool parameter to the highlight functions. 
Additionally I've added two other parameters to these functions: The first 
one is a bool that adds jump targets (<a id="[line]"/>), second one is a 
prefix to this number (<a id="[prefix][line]"/>) which is needed to make sure 
the jump target is unique even if more than one snippet is added to the 
output.

This doesn't work with .phps yet since we would a new php.ini setting which I 
didn't want to add or numbered output would need to become default.

My patch is attached and, if it doesn't come through, available on 
http://www.schlueters.de/zend_highlight_20050312_1.diff a sample output is at 
http://www.schlueters.de/highlight_pma.html

johannes
-- 
Johannes Schlüter                           Mayflower GmbH / ThinkPHP
http://thinkphp.de                            http://blog.thinkphp.de

---

## #15408 — Jeffery Fernandez — 2005-03-12T23:47:19+00:00

URL: https://externals.io/message/15407#15408 · In reply to: #15407

Johannes Schlueter wrote:

>Hi,
>
>some days (or even weeks?) ago Lukas asked on IRC wether there is a way to get 
>PHP code highlighted with linenumbers. The first reaction of most people 
>(including me) was "no" since you can't copy&paste the code but after 
>thinking I found out that <ol> works really fine. So I've implemented it that 
>way and added an optional bool parameter to the highlight functions. 
>Additionally I've added two other parameters to these functions: The first 
>one is a bool that adds jump targets (<a id="[line]"/>), second one is a 
>prefix to this number (<a id="[prefix][line]"/>) which is needed to make sure 
>the jump target is unique even if more than one snippet is added to the 
>output.
>
>This doesn't work with .phps yet since we would a new php.ini setting which I 
>didn't want to add or numbered output would need to become default.
>
>My patch is attached and, if it doesn't come through, available on 
>http://www.schlueters.de/zend_highlight_20050312_1.diff a sample output is at 
>http://www.schlueters.de/highlight_pma.html
>
>johannes
>  
>
>  
>
That looks very good but there seems to be serious html issues when I 
validated that page... Total 1789 erros when I validated that page at 
w3c. If you can fix that it would be awesome.

my 2c

>------------------------------------------------------------------------
>
>Index: Zend/zend_highlight.h
>===================================================================
>RCS file: /repository/ZendEngine2/zend_highlight.h,v
>retrieving revision 1.24
>diff -u -r1.24 zend_highlight.h
>--- Zend/zend_highlight.h	8 Jan 2004 17:31:47 -0000	1.24
>+++ Zend/zend_highlight.h	12 Mar 2005 14:40:12 -0000
>@@ -41,11 +41,16 @@
> 
> BEGIN_EXTERN_C()
> ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC);
>+ZEND_API void zend_highlight_numbered(zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool mark_lines, char *line_prefix TSRMLS_DC);
> ZEND_API void zend_strip(TSRMLS_D);
> ZEND_API int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC);
>+ZEND_API int highlight_file_ex(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC);
> ZEND_API int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC);
>+ZEND_API int highlight_string_ex(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC);
> ZEND_API void zend_html_putc(char c);
>+ZEND_API void zend_html_putc_ex(char c, char *last_color, int *line, char *line_prefix);
> ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC);
>+ZEND_API void zend_html_puts_ex(const char *s, uint len, char *last_color, int *line, char *line_prefix TSRMLS_DC);
> END_EXTERN_C()
> 
> extern zend_syntax_highlighter_ini syntax_highlighter_ini;
>Index: Zend/zend_highlight.c
>===================================================================
>RCS file: /repository/ZendEngine2/zend_highlight.c,v
>retrieving revision 1.47
>diff -u -r1.47 zend_highlight.c
>--- Zend/zend_highlight.c	2 Jan 2005 23:53:43 -0000	1.47
>+++ Zend/zend_highlight.c	12 Mar 2005 14:40:12 -0000
>@@ -53,9 +53,35 @@
> 	}
> }
> 
>+ZEND_API void zend_html_putc_ex(char c, char *last_color, int *line, char *line_prefix)
>+{
>+	if (c == '\n') {
>+		/* the &nbsp; is needed to work around https://bugzilla.mozilla.org/show_bug.cgi?id=194831 */
>+		zend_printf("&nbsp;</span></code></li>\n<li>");
>+		if (last_color != NULL) {
>+			if (line && *line) {
>+				if (line_prefix) {
>+					zend_printf("<a id=\"%s%d\"/>", line_prefix, ++*line);
>+				} else {
>+					zend_printf("<a id=\"%d\"/>", ++*line);
>+				}
>+			}
>+			zend_printf("<code><span style=\"color: %s\">", last_color);
>+		} else {
>+			zend_printf("<code><span>");
>+		}
>+	} else {
>+		zend_html_putc(c);
>+	}
>+}
> 
> ZEND_API void zend_html_puts(const char *s, uint len TSRMLS_DC)
> {
>+	zend_html_puts_ex(s, len, NULL, NULL, `NULL` TSRMLS_CC);
>+}
>+
>+ZEND_API void zend_html_puts_ex(const char *s, uint len, char *last_color, int *line, char *line_prefix TSRMLS_DC)
>+{
> 	const char *ptr=s, *end=s+len;
> 
> #ifdef ZEND_MULTIBYTE
>@@ -83,7 +109,11 @@
> 				ptr++;
> 			}
> 		} else {
>-			zend_html_putc(*ptr++);
>+			if (last_color == NULL) {
>+				zend_html_putc(*ptr++);
>+			} else {
>+				zend_html_putc_ex(*ptr++, last_color, line, line_prefix);
>+			}
> 		}
> 	}
> 
>@@ -196,6 +226,108 @@
> }
> 
> 
>+ZEND_API void zend_highlight_numbered(zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool mark_lines, char *line_prefix TSRMLS_DC)
>+{
>+	zval token;
>+	int token_type;
>+	char *last_color = syntax_highlighter_ini->highlight_html;
>+	char *next_color;
>+	int in_string=0, post_heredoc = 0;
>+	int line = 0;
>+
>+	if (mark_lines) {
>+		line = 1;
>+		if (line_prefix) {
>+			zend_printf("<ol><li><a id=\"%s%d\"/><code><span style=\"color: %s\">", line_prefix, line, last_color);
>+		} else {
>+			zend_printf("<ol><li><a id=\"%d\"/><code><span style=\"color: %s\">", line, last_color);
>+		}
>+	} else {
>+		zend_printf("<ol><li><code><span style=\"color: %s\">", last_color);
>+	}
>+	/* highlight stuff coming back from zendlex() */
>+	token.type = 0;
>+	while ((token_type=lex_scan(&token TSRMLS_CC))) {
>+		switch (token_type) {
>+			case T_INLINE_HTML:
>+				next_color = syntax_highlighter_ini->highlight_html;
>+				break;
>+			case T_COMMENT:
>+			case T_DOC_COMMENT:
>+				next_color = syntax_highlighter_ini->highlight_comment;
>+				break;
>+			case T_OPEN_TAG:
>+			case T_OPEN_TAG_WITH_ECHO:
>+				next_color = syntax_highlighter_ini->highlight_default;
>+				break;
>+			case T_CLOSE_TAG:
>+				next_color = syntax_highlighter_ini->highlight_default;
>+				break;
>+			case T_CONSTANT_ENCAPSED_STRING:
>+				next_color = syntax_highlighter_ini->highlight_string;
>+				break;
>+			case '"':
>+				next_color = syntax_highlighter_ini->highlight_string;
>+				in_string = !in_string;
>+				break;				
>+			case T_WHITESPACE:
>+				zend_html_puts_ex(LANG_SCNG(yy_text), LANG_SCNG(yy_leng), last_color, &line, line_prefix TSRMLS_CC);  /* no color needed */
>+				token.type = 0;
>+				continue;
>+				break;
>+			default:
>+				if (in_string) {
>+					next_color = syntax_highlighter_ini->highlight_string;
>+				} else if (token.type == 0) {
>+					next_color = syntax_highlighter_ini->highlight_keyword;
>+				} else {
>+					next_color = syntax_highlighter_ini->highlight_default;
>+				}
>+				break;
>+		}
>+
>+		if (last_color != next_color) {
>+			last_color = next_color;
>+			zend_printf("</span><span style=\"color: %s\">", last_color);
>+			  
>+		}
>+		switch (token_type) {
>+			case T_END_HEREDOC:
>+				zend_html_puts_ex(token.value.str.val, token.value.str.len, last_color, &line, line_prefix TSRMLS_CC);
>+				post_heredoc = 1;
>+				break;
>+			default:
>+				zend_html_puts_ex(LANG_SCNG(yy_text), LANG_SCNG(yy_leng), last_color, &line, line_prefix TSRMLS_CC);
>+				if (post_heredoc) {
>+					 zend_html_putc_ex('\n', last_color, &line, line_prefix);
>+					 post_heredoc = 0;
>+				}
>+				break;
>+		}
>+
>+		if (token.type == IS_STRING) {
>+			switch (token_type) {
>+				case T_OPEN_TAG:
>+				case T_OPEN_TAG_WITH_ECHO:
>+				case T_CLOSE_TAG:
>+				case T_WHITESPACE:
>+				case T_COMMENT:
>+				case T_DOC_COMMENT:
>+					break;
>+				default:
>+					efree(token.value.str.val);
>+					break;
>+			}
>+		} else if (token_type == T_END_HEREDOC) {
>+			efree(token.value.str.val);
>+		}
>+		token.type = 0;
>+	}
>+	zend_printf("</span>");
>+	zend_printf("</code></li></ol>");
>+}
>+
>+
> 
> ZEND_API void zend_strip(TSRMLS_D)
> {
>Index: Zend/zend_language_scanner.l
>===================================================================
>RCS file: /repository/ZendEngine2/zend_language_scanner.l,v
>retrieving revision 1.124
>diff -u -r1.124 zend_language_scanner.l
>--- Zend/zend_language_scanner.l	7 Mar 2005 16:48:49 -0000	1.124
>+++ Zend/zend_language_scanner.l	12 Mar 2005 14:40:13 -0000
>@@ -557,11 +557,11 @@
> 
> 
> BEGIN_EXTERN_C()
>-int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC)
>+int highlight_file_ex(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC)
> {
> 	zend_lex_state original_lex_state;
> 	zend_file_handle file_handle;
>-
>+	
> 	file_handle.type = ZEND_HANDLE_FILENAME;
> 	file_handle.filename = filename;
> 	file_handle.free_filename = 0;
>@@ -571,7 +571,11 @@
> 		zend_message_dispatcher(ZMSG_FAILED_HIGHLIGHT_FOPEN, filename);
> 		return FAILURE;
> 	}
>-	zend_highlight(syntax_highlighter_ini TSRMLS_CC);
>+	if (numbered) {
>+	    zend_highlight_numbered(syntax_highlighter_ini, mark_lines, line_prefix TSRMLS_CC);
>+	} else {
>+	    zend_highlight(syntax_highlighter_ini TSRMLS_CC);
>+	}
> #ifdef ZEND_MULTIBYTE
> 	if (SCNG(script_org)) {
> 		efree(SCNG(script_org));
>@@ -587,7 +591,12 @@
> 	return SUCCESS;
> }
> 
>-int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC)
>+int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC)
>+{
>+    return highlight_file_ex(filename, syntax_highlighter_ini, 0, 0, `NULL` TSRMLS_CC);
>+}
>+
>+int highlight_string_ex(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name, zend_bool numbered, zend_bool mark_lines, char *line_prefix TSRMLS_DC)
> {
> 	zend_lex_state original_lex_state;
> 	zval tmp = *str;
>@@ -598,7 +607,11 @@
> 	if (zend_prepare_string_for_scanning(str, str_name TSRMLS_CC)==FAILURE) {
> 		return FAILURE;
> 	}
>-	zend_highlight(syntax_highlighter_ini TSRMLS_CC);
>+	if (numbered) {
>+	    zend_highlight_numbered(syntax_highlighter_ini, mark_lines, line_prefix TSRMLS_CC);
>+	} else {
>+	    zend_highlight(syntax_highlighter_ini TSRMLS_CC);
>+	}
> #ifdef ZEND_MULTIBYTE
> 	if (SCNG(script_org)) {
> 		efree(SCNG(script_org));
>@@ -613,6 +626,11 @@
> 	zval_dtor(str);
> 	return SUCCESS;
> }
>+
>+int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC)
>+{
>+    return highlight_string_ex(str, syntax_highlighter_ini, str_name, 0, 0, `NULL` TSRMLS_CC);
>+}
> END_EXTERN_C()
> 
> #ifdef ZEND_MULTIBYTE
>Index: ext/standard/basic_functions.c
>===================================================================
>RCS file: /repository/php-src/ext/standard/basic_functions.c,v
>retrieving revision 1.705
>diff -u -r1.705 basic_functions.c
>--- ext/standard/basic_functions.c	7 Mar 2005 19:37:26 -0000	1.705
>+++ ext/standard/basic_functions.c	12 Mar 2005 14:40:14 -0000
>@@ -2353,15 +2353,19 @@
> 	syntax_highlighter_ini->highlight_string  = INI_STR("highlight.string");
> }
> 
>-/* {{{ proto bool highlight_file(string file_name [, bool return] )
>+/* {{{ proto bool highlight_file(string file_name [, bool return [, bool numbered [, bool mark_lines [, string mark_prefix]]]] )
>    Syntax highlight a source file */
> PHP_FUNCTION(highlight_file)
> {
> 	zval *filename;
> 	zend_syntax_highlighter_ini syntax_highlighter_ini;
> 	zend_bool i = 0;
>+	zend_bool numbered = 0;
>+	zend_bool mark_lines = 0;
>+	char *line_prefix = NULL;
>+	int line_prefix_len = 0;
> 
>-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &filename, &i) == FAILURE) {
>+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bbbs", &filename, &i, &numbered, &mark_lines, &line_prefix, &line_prefix_len) == FAILURE) {
> 		RETURN_FALSE;
> 	}
> 	convert_to_string(filename);
>@@ -2380,7 +2384,7 @@
> 
> 	php_get_highlight_struct(&syntax_highlighter_ini);
> 
>-	if (highlight_file(Z_STRVAL_P(filename), &syntax_highlighter_ini TSRMLS_CC) == FAILURE) {
>+	if (highlight_file_ex(Z_STRVAL_P(filename), &syntax_highlighter_ini, numbered, mark_lines, line_prefix TSRMLS_CC) == FAILURE) {
> 		RETURN_FALSE;
> 	}
> 
>@@ -2472,7 +2476,7 @@
> }
> /* }}} */
> 
>-/* {{{ proto bool highlight_string(string string [, bool return] )
>+/* {{{ proto bool highlight_string(string string [, bool return [, bool mark_lines [, string mark_prefix]]] )
>    Syntax highlight a string or optionally return it */
> PHP_FUNCTION(highlight_string)
> {
>@@ -2480,9 +2484,13 @@
> 	zend_syntax_highlighter_ini syntax_highlighter_ini;
> 	char *hicompiled_string_description;
> 	zend_bool  i = 0;
>+	zend_bool numbered = 0;
>+	zend_bool mark_lines = 0;
>+	char *line_prefix = NULL;
>+	int line_prefix_len = 0;
> 	int old_error_reporting = EG(error_reporting);
> 
>-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &expr, &i) == FAILURE) {
>+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bbbs", &expr, &i, &numbered, &mark_lines, &line_prefix, &line_prefix_len) == FAILURE) {
> 		RETURN_FALSE;
> 	}
> 	convert_to_string(expr);
>@@ -2497,7 +2505,7 @@
> 
> 	hicompiled_string_description = zend_make_compiled_string_description("highlighted code" TSRMLS_CC);
> 
>-	if (highlight_string(expr, &syntax_highlighter_ini, hicompiled_string_description TSRMLS_CC) == FAILURE) {
>+	if (highlight_string_ex(expr, &syntax_highlighter_ini, hicompiled_string_description, numbered, mark_lines, line_prefix TSRMLS_CC) == FAILURE) {
> 		efree(hicompiled_string_description);
> 		RETURN_FALSE;
> 	}

---

## #15411 — Gordon P. Hemsley — 2005-03-13T00:22:54+00:00

URL: https://externals.io/message/15407#15411 · In reply to: #15408

Instead of using <a id="[line]" /> (which I'm not sure is even valid),
you can simply just embed the id into the <li> tag: <li id="[line]">.

And that's just _my_ 2 cents.


On Sun, 13 Mar 2005 10:47:19 +1100, Jeffery Fernandez
<forums@jefferyfernandez.id.au> wrote:
> Johannes Schlueter wrote:
> 
> > […]
> That looks very good but there seems to be serious html issues when I
> validated that page... Total 1789 erros when I validated that page at
> w3c. If you can fix that it would be awesome.
> 
> my 2c
> 
> > […]
> 
> --
> 
> 
> 
> 


-- 
Gordon P. Hemsley
gphemsley@gmail.com
http://www.lttp.net/ • http://cmsforme.sourceforge.net/

---

## #15409 — Johannes Schlueter — 2005-03-13T01:12:53+00:00

URL: https://externals.io/message/15407#15409 · In reply to: #15408

Hi Jeffery,


> That looks very good but there seems to be serious html issues when I
> validated that page... Total 1789 erros when I validated that page at
> w3c. If you can fix that it would be awesome.

Try to validate it as XHTML1.0 and, since the function is for embedding into 
other documents, keep in mind that the output is missing the doctype header 
and <html> tag and so on, it's only the <ol>...</ol> part.

johannes

---

## #15410 — Jeffery Fernandez — 2005-03-13T01:18:58+00:00

URL: https://externals.io/message/15407#15410 · In reply to: #15409

Johannes Schlueter wrote:

>Hi Jeffery,
>
>
>  
>
> > […]
>
>Try to validate it as XHTML1.0 and, since the function is for embedding into 
>other documents, keep in mind that the output is missing the doctype header 
>and <html> tag and so on, it's only the <ol>...</ol> part.
>
>johannes
>
>  
>
You could be right.. I haven't tested the output within a valid doc type 
page
