18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 1996-2005 Paul Mackerras.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <linux/string.h>
68c2ecf20Sopenharmony_ci#include <asm/udbg.h>
78c2ecf20Sopenharmony_ci#include <asm/time.h>
88c2ecf20Sopenharmony_ci#include "nonstdio.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistatic bool paginating, paginate_skipping;
118c2ecf20Sopenharmony_cistatic unsigned long paginate_lpp; /* Lines Per Page */
128c2ecf20Sopenharmony_cistatic unsigned long paginate_pos;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_civoid xmon_start_pagination(void)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	paginating = true;
178c2ecf20Sopenharmony_ci	paginate_skipping = false;
188c2ecf20Sopenharmony_ci	paginate_pos = 0;
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_civoid xmon_end_pagination(void)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	paginating = false;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid xmon_set_pagination_lpp(unsigned long lpp)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	paginate_lpp = lpp;
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic int xmon_readchar(void)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	if (udbg_getc)
348c2ecf20Sopenharmony_ci		return udbg_getc();
358c2ecf20Sopenharmony_ci	return -1;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic int xmon_write(const char *ptr, int nb)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	int rv = 0;
418c2ecf20Sopenharmony_ci	const char *p = ptr, *q;
428c2ecf20Sopenharmony_ci	const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]";
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (nb <= 0)
458c2ecf20Sopenharmony_ci		return rv;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (paginating && paginate_skipping)
488c2ecf20Sopenharmony_ci		return nb;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (paginate_lpp) {
518c2ecf20Sopenharmony_ci		while (paginating && (q = strchr(p, '\n'))) {
528c2ecf20Sopenharmony_ci			rv += udbg_write(p, q - p + 1);
538c2ecf20Sopenharmony_ci			p = q + 1;
548c2ecf20Sopenharmony_ci			paginate_pos++;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci			if (paginate_pos >= paginate_lpp) {
578c2ecf20Sopenharmony_ci				udbg_write(msg, strlen(msg));
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci				switch (xmon_readchar()) {
608c2ecf20Sopenharmony_ci				case 'a':
618c2ecf20Sopenharmony_ci					paginating = false;
628c2ecf20Sopenharmony_ci					break;
638c2ecf20Sopenharmony_ci				case 'q':
648c2ecf20Sopenharmony_ci					paginate_skipping = true;
658c2ecf20Sopenharmony_ci					break;
668c2ecf20Sopenharmony_ci				default:
678c2ecf20Sopenharmony_ci					/* nothing */
688c2ecf20Sopenharmony_ci					break;
698c2ecf20Sopenharmony_ci				}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci				paginate_pos = 0;
728c2ecf20Sopenharmony_ci				udbg_write("\r\n", 2);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci				if (paginate_skipping)
758c2ecf20Sopenharmony_ci					return nb;
768c2ecf20Sopenharmony_ci			}
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return rv + udbg_write(p, nb - (p - ptr));
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ciint xmon_putchar(int c)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	char ch = c;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (c == '\n')
888c2ecf20Sopenharmony_ci		xmon_putchar('\r');
898c2ecf20Sopenharmony_ci	return xmon_write(&ch, 1) == 1? c: -1;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic char line[256];
938c2ecf20Sopenharmony_cistatic char *lineptr;
948c2ecf20Sopenharmony_cistatic int lineleft;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int xmon_getchar(void)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	int c;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (lineleft == 0) {
1018c2ecf20Sopenharmony_ci		lineptr = line;
1028c2ecf20Sopenharmony_ci		for (;;) {
1038c2ecf20Sopenharmony_ci			c = xmon_readchar();
1048c2ecf20Sopenharmony_ci			if (c == -1 || c == 4)
1058c2ecf20Sopenharmony_ci				break;
1068c2ecf20Sopenharmony_ci			if (c == '\r' || c == '\n') {
1078c2ecf20Sopenharmony_ci				*lineptr++ = '\n';
1088c2ecf20Sopenharmony_ci				xmon_putchar('\n');
1098c2ecf20Sopenharmony_ci				break;
1108c2ecf20Sopenharmony_ci			}
1118c2ecf20Sopenharmony_ci			switch (c) {
1128c2ecf20Sopenharmony_ci			case 0177:
1138c2ecf20Sopenharmony_ci			case '\b':
1148c2ecf20Sopenharmony_ci				if (lineptr > line) {
1158c2ecf20Sopenharmony_ci					xmon_putchar('\b');
1168c2ecf20Sopenharmony_ci					xmon_putchar(' ');
1178c2ecf20Sopenharmony_ci					xmon_putchar('\b');
1188c2ecf20Sopenharmony_ci					--lineptr;
1198c2ecf20Sopenharmony_ci				}
1208c2ecf20Sopenharmony_ci				break;
1218c2ecf20Sopenharmony_ci			case 'U' & 0x1F:
1228c2ecf20Sopenharmony_ci				while (lineptr > line) {
1238c2ecf20Sopenharmony_ci					xmon_putchar('\b');
1248c2ecf20Sopenharmony_ci					xmon_putchar(' ');
1258c2ecf20Sopenharmony_ci					xmon_putchar('\b');
1268c2ecf20Sopenharmony_ci					--lineptr;
1278c2ecf20Sopenharmony_ci				}
1288c2ecf20Sopenharmony_ci				break;
1298c2ecf20Sopenharmony_ci			default:
1308c2ecf20Sopenharmony_ci				if (lineptr >= &line[sizeof(line) - 1])
1318c2ecf20Sopenharmony_ci					xmon_putchar('\a');
1328c2ecf20Sopenharmony_ci				else {
1338c2ecf20Sopenharmony_ci					xmon_putchar(c);
1348c2ecf20Sopenharmony_ci					*lineptr++ = c;
1358c2ecf20Sopenharmony_ci				}
1368c2ecf20Sopenharmony_ci			}
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		lineleft = lineptr - line;
1398c2ecf20Sopenharmony_ci		lineptr = line;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	if (lineleft == 0)
1428c2ecf20Sopenharmony_ci		return -1;
1438c2ecf20Sopenharmony_ci	--lineleft;
1448c2ecf20Sopenharmony_ci	return *lineptr++;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cichar *xmon_gets(char *str, int nb)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	char *p;
1508c2ecf20Sopenharmony_ci	int c;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	for (p = str; p < str + nb - 1; ) {
1538c2ecf20Sopenharmony_ci		c = xmon_getchar();
1548c2ecf20Sopenharmony_ci		if (c == -1) {
1558c2ecf20Sopenharmony_ci			if (p == str)
1568c2ecf20Sopenharmony_ci				return NULL;
1578c2ecf20Sopenharmony_ci			break;
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci		*p++ = c;
1608c2ecf20Sopenharmony_ci		if (c == '\n')
1618c2ecf20Sopenharmony_ci			break;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	*p = 0;
1648c2ecf20Sopenharmony_ci	return str;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_civoid xmon_printf(const char *format, ...)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	va_list args;
1708c2ecf20Sopenharmony_ci	static char xmon_outbuf[1024];
1718c2ecf20Sopenharmony_ci	int rc, n;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	va_start(args, format);
1748c2ecf20Sopenharmony_ci	n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
1758c2ecf20Sopenharmony_ci	va_end(args);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	rc = xmon_write(xmon_outbuf, n);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (n && rc == 0) {
1808c2ecf20Sopenharmony_ci		/* No udbg hooks, fallback to printk() - dangerous */
1818c2ecf20Sopenharmony_ci		pr_cont("%s", xmon_outbuf);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_civoid xmon_puts(const char *str)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	xmon_write(str, strlen(str));
1888c2ecf20Sopenharmony_ci}
189