| /* | 
 |  * Copyright (C) 1996-2005 Paul Mackerras. | 
 |  * | 
 |  *      This program is free software; you can redistribute it and/or | 
 |  *      modify it under the terms of the GNU General Public License | 
 |  *      as published by the Free Software Foundation; either version | 
 |  *      2 of the License, or (at your option) any later version. | 
 |  */ | 
 | #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)); | 
 | } |