xref: /php-src/sapi/phpdbg/phpdbg_io.c (revision c8955c07)
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    | https://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_io.h"
22 
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)23 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
24 
25 /* is easy to generalize ... but not needed for now */
26 PHPDBG_API int phpdbg_consume_stdin_line(char *buf) {
27 	int bytes = PHPDBG_G(input_buflen), len = 0;
28 
29 	if (PHPDBG_G(input_buflen)) {
30 		memcpy(buf, PHPDBG_G(input_buffer), bytes);
31 	}
32 
33 	PHPDBG_G(last_was_newline) = 1;
34 
35 	do {
36 		int i;
37 		if (bytes <= 0) {
38 			continue;
39 		}
40 
41 		for (i = len; i < len + bytes; i++) {
42 			if (buf[i] == '\x03') {
43 				if (i != len + bytes - 1) {
44 					memmove(buf + i, buf + i + 1, len + bytes - i - 1);
45 				}
46 				len--;
47 				i--;
48 				continue;
49 			}
50 			if (buf[i] == '\n') {
51 				PHPDBG_G(input_buflen) = len + bytes - 1 - i;
52 				if (PHPDBG_G(input_buflen)) {
53 					memcpy(PHPDBG_G(input_buffer), buf + i + 1, PHPDBG_G(input_buflen));
54 				}
55 				if (i != PHPDBG_MAX_CMD - 1) {
56 					buf[i + 1] = 0;
57 				}
58 				return i;
59 			}
60 		}
61 
62 		len += bytes;
63 	} while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, buf + len, PHPDBG_MAX_CMD - len, -1)) > 0);
64 
65 	if (bytes <= 0) {
66 		PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
67 		zend_bailout();
68 	}
69 
70 	return bytes;
71 }
72 
phpdbg_mixed_read(int fd,char * ptr,int len,int tmo)73 PHPDBG_API int phpdbg_mixed_read(int fd, char *ptr, int len, int tmo) {
74 	int ret;
75 
76 	do {
77 		ret = read(fd, ptr, len);
78 	} while (ret == -1 && errno == EINTR);
79 
80 	return ret;
81 }
82 
phpdbg_output_pager(int fd,const char * ptr,int len)83 static int phpdbg_output_pager(int fd, const char *ptr, int len) {
84 	int count = 0, bytes = 0;
85 	const char *p = ptr, *endp = ptr + len;
86 
87 	while ((p = memchr(p, '\n', endp - p))) {
88 		count++;
89 		p++;
90 
91 		if (count % PHPDBG_G(lines) == 0) {
92 			bytes += write(fd, ptr + bytes, (p - ptr) - bytes);
93 
94 			if (memchr(p, '\n', endp - p)) {
95 				char buf[PHPDBG_MAX_CMD];
96 				zend_quiet_write(fd, ZEND_STRL("\r---Type <return> to continue or q <return> to quit---"));
97 				phpdbg_consume_stdin_line(buf);
98 				if (*buf == 'q') {
99 					break;
100 				}
101 				zend_quiet_write(fd, "\r", 1);
102 			} else break;
103 		}
104 	}
105 	if (bytes && count % PHPDBG_G(lines) != 0) {
106 		bytes += write(fd, ptr + bytes, len - bytes);
107 	} else if (!bytes) {
108 		bytes += write(fd, ptr, len);
109 	}
110 	return bytes;
111 }
112 
phpdbg_mixed_write(int fd,const char * ptr,int len)113 PHPDBG_API int phpdbg_mixed_write(int fd, const char *ptr, int len) {
114 	if ((PHPDBG_G(flags) & PHPDBG_HAS_PAGINATION)
115 	 && PHPDBG_G(io)[PHPDBG_STDOUT].fd == fd
116 	 && PHPDBG_G(lines) > 0) {
117 		return phpdbg_output_pager(fd, ptr, len);
118 	}
119 
120 	return write(fd, ptr, len);
121 }
122