| #include <error.h> | 
 | #include <stdio.h> | 
 | #include <assert.h> | 
 | #include <atomic.h> | 
 |  | 
 | int readline(char *buf, size_t buf_l, const char *prompt, ...) | 
 | { | 
 | 	static spinlock_t readline_lock = SPINLOCK_INITIALIZER_IRQSAVE; | 
 | 	int i, c, echoing, retval; | 
 | 	va_list ap; | 
 |  | 
 | 	spin_lock_irqsave(&readline_lock); | 
 | 	va_start(ap, prompt); | 
 | 	if (prompt != NULL) | 
 | 		vcprintf(prompt, ap); | 
 | 	va_end(ap); | 
 |  | 
 | 	i = 0; | 
 | 	echoing = iscons(0); | 
 | 	while (1) { | 
 | 		c = getchar(); | 
 | 		if (c < 0) { | 
 | 			printk("read error: %e\n", c);	/* %e! */ | 
 | 			retval = i; | 
 | 			break; | 
 | 		} else if (c == '\b' || c == 0x7f) { | 
 | 			if (i > 0) { | 
 | 				if (echoing) | 
 | 					cputchar(c); | 
 | 				i--; | 
 | 			} | 
 | 			continue; | 
 | 		} else if (c == '\n' || c == '\r') { | 
 | 			/* sending a \n regardless, since the serial port gives us a \r for | 
 | 			 * carriage returns. (probably won't get a \r anymore) */ | 
 | 			if (echoing) | 
 | 				cputchar('\n'); | 
 | 			assert(i <= buf_l - 1);	/* never write to buf_l - 1 til the end */ | 
 | 			buf[i++] = c; | 
 | 			retval =  i; | 
 | 			break; | 
 | 		} else if (c >= ' ' && i < buf_l - 1) { | 
 | 			if (echoing) | 
 | 				cputchar(c); | 
 | 			buf[i++] = c; | 
 | 		} | 
 | 	} | 
 | 	spin_unlock_irqsave(&readline_lock); | 
 | 	return retval; | 
 | } | 
 |  |