xref: /PHP-8.0/sapi/phpdbg/phpdbg_eol.c (revision 5d6e923d)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Anatol Belski <ab@php.net>                                  |
14    +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #	include "config.h"
19 #endif
20 
21 #include "phpdbg.h"
22 #include "phpdbg_eol.h"
23 
24 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
25 
26 #define EOL_LIST_LEN 4
27 struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = {
28 	{"CRLF", "\r\n", PHPDBG_EOL_CRLF},
29 /*	{"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/
30 	{"LF", "\n", PHPDBG_EOL_LF},
31 	{"CR", "\r", PHPDBG_EOL_CR},
32 };
33 
phpdbg_eol_global_update(char * name)34 int phpdbg_eol_global_update(char *name)
35 {
36 
37 	if (0 == strcmp(name, "CRLF") || 0 == strcmp(name, "crlf") || 0 == strcmp(name, "DOS") || 0 == strcmp(name, "dos")) {
38 		PHPDBG_G(eol) = PHPDBG_EOL_CRLF;
39 	} else if (0 == strcmp(name, "LF") || 0 == strcmp(name, "lf") || 0 == strcmp(name, "UNIX") || 0 == strcmp(name, "unix")) {
40 		PHPDBG_G(eol) = PHPDBG_EOL_LF;
41 	} else if (0 == strcmp(name, "CR") || 0 == strcmp(name, "cr") || 0 == strcmp(name, "MAC") || 0 == strcmp(name, "mac")) {
42 		PHPDBG_G(eol) = PHPDBG_EOL_CR;
43 	} else {
44 		return FAILURE;
45 	}
46 
47 	return SUCCESS;
48 }
49 
phpdbg_eol_name(int id)50 char *phpdbg_eol_name(int id)
51 {
52 	size_t i = 0;
53 
54 	while (i < EOL_LIST_LEN) {
55 
56 		if (id == phpdbg_eol_list[i].id) {
57 			return phpdbg_eol_list[i].name;
58 		}
59 
60 		i++;
61 	}
62 
63 	return NULL;
64 }
65 
phpdbg_eol_rep(int id)66 char *phpdbg_eol_rep(int id)
67 {
68 	size_t i = 0;
69 
70 	while (i < EOL_LIST_LEN) {
71 
72 		if (id == phpdbg_eol_list[i].id) {
73 			return phpdbg_eol_list[i].rep;
74 		}
75 
76 		i++;
77 	}
78 
79 	return NULL;
80 }
81 
82 /* Marked as never_inline to work around a -Walloc-size-larger-than bug in GCC. */
count_lf_and_cr(const char * in,int in_len)83 static zend_never_inline int count_lf_and_cr(const char *in, int in_len) {
84 	int i, count = 0;
85 	for (i = 0; i < in_len; i++) {
86 		if (0x0a == in[i] || 0x0d == in[i]) {
87 			count++;
88 		}
89 	}
90 	return count;
91 }
92 
93 /* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */
phpdbg_eol_convert(char ** str,int * len)94 void phpdbg_eol_convert(char **str, int *len)
95 {
96 	char *in = *str, *out;
97 	int in_len = *len, cursor, i;
98 	char last, cur;
99 
100 	if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) {
101 		return;
102 	}
103 
104 	if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */
105 		out = (char *)emalloc(in_len + count_lf_and_cr(in, in_len));
106 
107 		last = cur = in[0];
108 		i = cursor = 0;
109 		for (; i < in_len;) {
110 			if (0x0a == cur && last != 0x0d) {
111 				out[cursor] = 0x0d;
112 				cursor++;
113 				out[cursor] = cur;
114 			} else if(0x0d == cur) {
115 				if (i + 1 < in_len && 0x0a != in[i+1]) {
116 					out[cursor] = cur;
117 					cursor++;
118 					out[cursor] = 0x0a;
119 					last = 0x0a;
120 				} else {
121 					out[cursor] = 0x0d;
122 					last = 0x0d;
123 				}
124 			} else {
125 				out[cursor] = cur;
126 				last = cur;
127 			}
128 
129 			i++;
130 			cursor++;
131 			cur = in[i];
132 		}
133 
134 	} else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) {
135 		char want, kick;
136 
137 		if (PHPDBG_EOL_LF == PHPDBG_G(eol)) {
138 			want = 0x0a;
139 			kick = 0x0d;
140 		} else {
141 			want = 0x0d;
142 			kick = 0x0a;
143 		}
144 
145 		/* We gonna have a smaller or equally long string, estimation is almost neglecting */
146 		out = (char *)emalloc(in_len);
147 
148 		last = cur = in[0];
149 		i = cursor = 0;
150 		for (; cursor < in_len;) {
151 			if (kick == cur) {
152 				out[cursor] = want;
153 			} else if (want == cur) {
154 				if (kick != last) {
155 					out[cursor] = want;
156 				}
157 			} else {
158 				out[cursor] = cur;
159 			}
160 
161 			last = cur;
162 			cursor++;
163 			cur = in[cursor];
164 		}
165 	} else {
166 		return;
167 	}
168 
169 	efree(*str);
170 	*str = erealloc(out, cursor);
171 	*len = cursor;
172 	in = NULL;
173 }
174