189 lines
3.1 KiB
C
189 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 1996-2005 Paul Mackerras.
|
|
*/
|
|
#include <linux/string.h>
|
|
#include <asm/udbg.h>
|
|
#include <asm/time.h>
|
|
#include "nonstdio.h"
|
|
|
|
static bool paginating, paginate_skipping;
|
|
static unsigned long paginate_lpp; /* Lines Per Page */
|
|
static unsigned long paginate_pos;
|
|
|
|
void xmon_start_pagination(void)
|
|
{
|
|
paginating = true;
|
|
paginate_skipping = false;
|
|
paginate_pos = 0;
|
|
}
|
|
|
|
void xmon_end_pagination(void)
|
|
{
|
|
paginating = false;
|
|
}
|
|
|
|
void xmon_set_pagination_lpp(unsigned long lpp)
|
|
{
|
|
paginate_lpp = lpp;
|
|
}
|
|
|
|
static int xmon_readchar(void)
|
|
{
|
|
if (udbg_getc)
|
|
return udbg_getc();
|
|
return -1;
|
|
}
|
|
|
|
static int xmon_write(const char *ptr, int nb)
|
|
{
|
|
int rv = 0;
|
|
const char *p = ptr, *q;
|
|
const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]";
|
|
|
|
if (nb <= 0)
|
|
return rv;
|
|
|
|
if (paginating && paginate_skipping)
|
|
return nb;
|
|
|
|
if (paginate_lpp) {
|
|
while (paginating && (q = strchr(p, '\n'))) {
|
|
rv += udbg_write(p, q - p + 1);
|
|
p = q + 1;
|
|
paginate_pos++;
|
|
|
|
if (paginate_pos >= paginate_lpp) {
|
|
udbg_write(msg, strlen(msg));
|
|
|
|
switch (xmon_readchar()) {
|
|
case 'a':
|
|
paginating = false;
|
|
break;
|
|
case 'q':
|
|
paginate_skipping = true;
|
|
break;
|
|
default:
|
|
/* nothing */
|
|
break;
|
|
}
|
|
|
|
paginate_pos = 0;
|
|
udbg_write("\r\n", 2);
|
|
|
|
if (paginate_skipping)
|
|
return nb;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv + udbg_write(p, nb - (p - ptr));
|
|
}
|
|
|
|
int xmon_putchar(int c)
|
|
{
|
|
char ch = c;
|
|
|
|
if (c == '\n')
|
|
xmon_putchar('\r');
|
|
return xmon_write(&ch, 1) == 1? c: -1;
|
|
}
|
|
|
|
static char line[256];
|
|
static char *lineptr;
|
|
static int lineleft;
|
|
|
|
static int xmon_getchar(void)
|
|
{
|
|
int c;
|
|
|
|
if (lineleft == 0) {
|
|
lineptr = line;
|
|
for (;;) {
|
|
c = xmon_readchar();
|
|
if (c == -1 || c == 4)
|
|
break;
|
|
if (c == '\r' || c == '\n') {
|
|
*lineptr++ = '\n';
|
|
xmon_putchar('\n');
|
|
break;
|
|
}
|
|
switch (c) {
|
|
case 0177:
|
|
case '\b':
|
|
if (lineptr > line) {
|
|
xmon_putchar('\b');
|
|
xmon_putchar(' ');
|
|
xmon_putchar('\b');
|
|
--lineptr;
|
|
}
|
|
break;
|
|
case 'U' & 0x1F:
|
|
while (lineptr > line) {
|
|
xmon_putchar('\b');
|
|
xmon_putchar(' ');
|
|
xmon_putchar('\b');
|
|
--lineptr;
|
|
}
|
|
break;
|
|
default:
|
|
if (lineptr >= &line[sizeof(line) - 1])
|
|
xmon_putchar('\a');
|
|
else {
|
|
xmon_putchar(c);
|
|
*lineptr++ = c;
|
|
}
|
|
}
|
|
}
|
|
lineleft = lineptr - line;
|
|
lineptr = line;
|
|
}
|
|
if (lineleft == 0)
|
|
return -1;
|
|
--lineleft;
|
|
return *lineptr++;
|
|
}
|
|
|
|
char *xmon_gets(char *str, int nb)
|
|
{
|
|
char *p;
|
|
int c;
|
|
|
|
for (p = str; p < str + nb - 1; ) {
|
|
c = xmon_getchar();
|
|
if (c == -1) {
|
|
if (p == str)
|
|
return NULL;
|
|
break;
|
|
}
|
|
*p++ = c;
|
|
if (c == '\n')
|
|
break;
|
|
}
|
|
*p = 0;
|
|
return str;
|
|
}
|
|
|
|
void xmon_printf(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
static char xmon_outbuf[1024];
|
|
int rc, n;
|
|
|
|
va_start(args, format);
|
|
n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
|
|
va_end(args);
|
|
|
|
rc = xmon_write(xmon_outbuf, n);
|
|
|
|
if (n && rc == 0) {
|
|
/* No udbg hooks, fallback to printk() - dangerous */
|
|
printk("%s", xmon_outbuf);
|
|
}
|
|
}
|
|
|
|
void xmon_puts(const char *str)
|
|
{
|
|
xmon_write(str, strlen(str));
|
|
}
|