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: Anatol Belski <ab@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "phpdbg.h"
24 #include "phpdbg_eol.h"
25
26 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
27
28 #define EOL_LIST_LEN 4
29 struct phpdbg_eol_rep phpdbg_eol_list[EOL_LIST_LEN] = {
30 {"CRLF", "\r\n", PHPDBG_EOL_CRLF},
31 /* {"LFCR", "\n\r", PHPDBG_EOL_LFCR},*/
32 {"LF", "\n", PHPDBG_EOL_LF},
33 {"CR", "\r", PHPDBG_EOL_CR},
34 };
35
phpdbg_eol_global_update(char * name)36 int phpdbg_eol_global_update(char *name)
37 {
38
39 if (0 == strcmp(name, "CRLF") || 0 == strcmp(name, "crlf") || 0 == strcmp(name, "DOS") || 0 == strcmp(name, "dos")) {
40 PHPDBG_G(eol) = PHPDBG_EOL_CRLF;
41 } else if (0 == strcmp(name, "LF") || 0 == strcmp(name, "lf") || 0 == strcmp(name, "UNIX") || 0 == strcmp(name, "unix")) {
42 PHPDBG_G(eol) = PHPDBG_EOL_LF;
43 } else if (0 == strcmp(name, "CR") || 0 == strcmp(name, "cr") || 0 == strcmp(name, "MAC") || 0 == strcmp(name, "mac")) {
44 PHPDBG_G(eol) = PHPDBG_EOL_CR;
45 } else {
46 return FAILURE;
47 }
48
49 return SUCCESS;
50 }
51
phpdbg_eol_name(int id)52 char *phpdbg_eol_name(int id)
53 {
54 size_t i = 0;
55
56 while (i < EOL_LIST_LEN) {
57
58 if (id == phpdbg_eol_list[i].id) {
59 return phpdbg_eol_list[i].name;
60 }
61
62 i++;
63 }
64
65 return NULL;
66 }
67
phpdbg_eol_rep(int id)68 char *phpdbg_eol_rep(int id)
69 {
70 size_t i = 0;
71
72 while (i < EOL_LIST_LEN) {
73
74 if (id == phpdbg_eol_list[i].id) {
75 return phpdbg_eol_list[i].rep;
76 }
77
78 i++;
79 }
80
81 return NULL;
82 }
83
84 /* 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)85 static zend_never_inline int count_lf_and_cr(const char *in, int in_len) {
86 int i, count = 0;
87 for (i = 0; i < in_len; i++) {
88 if (0x0a == in[i] || 0x0d == in[i]) {
89 count++;
90 }
91 }
92 return count;
93 }
94
95 /* Inspired by https://ccrma.stanford.edu/~craig/utility/flip/flip.cpp */
phpdbg_eol_convert(char ** str,int * len)96 void phpdbg_eol_convert(char **str, int *len)
97 {
98 char *in = *str, *out;
99 int in_len = *len, cursor, i;
100 char last, cur;
101
102 if ((PHPDBG_G(flags) & PHPDBG_IS_REMOTE) != PHPDBG_IS_REMOTE) {
103 return;
104 }
105
106 if (PHPDBG_EOL_CRLF == PHPDBG_G(eol)) { /* XXX add LFCR case if it's gonna be needed */
107 out = (char *)emalloc(in_len + count_lf_and_cr(in, in_len));
108
109 last = cur = in[0];
110 i = cursor = 0;
111 for (; i < in_len;) {
112 if (0x0a == cur && last != 0x0d) {
113 out[cursor] = 0x0d;
114 cursor++;
115 out[cursor] = cur;
116 } else if(0x0d == cur) {
117 if (i + 1 < in_len && 0x0a != in[i+1]) {
118 out[cursor] = cur;
119 cursor++;
120 out[cursor] = 0x0a;
121 last = 0x0a;
122 } else {
123 out[cursor] = 0x0d;
124 last = 0x0d;
125 }
126 } else {
127 out[cursor] = cur;
128 last = cur;
129 }
130
131 i++;
132 cursor++;
133 cur = in[i];
134 }
135
136 } else if (PHPDBG_EOL_LF == PHPDBG_G(eol) || PHPDBG_EOL_CR == PHPDBG_G(eol)) {
137 char want, kick;
138
139 if (PHPDBG_EOL_LF == PHPDBG_G(eol)) {
140 want = 0x0a;
141 kick = 0x0d;
142 } else {
143 want = 0x0d;
144 kick = 0x0a;
145 }
146
147 /* We gonna have a smaller or equally long string, estimation is almost neglecting */
148 out = (char *)emalloc(in_len);
149
150 last = cur = in[0];
151 i = cursor = 0;
152 for (; cursor < in_len;) {
153 if (kick == cur) {
154 out[cursor] = want;
155 } else if (want == cur) {
156 if (kick != last) {
157 out[cursor] = want;
158 }
159 } else {
160 out[cursor] = cur;
161 }
162
163 last = cur;
164 cursor++;
165 cur = in[cursor];
166 }
167 } else {
168 return;
169 }
170
171 efree(*str);
172 *str = erealloc(out, cursor);
173 *len = cursor;
174 in = NULL;
175 }
176