|  | #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: %d\n", c); | 
|  | 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; | 
|  | } | 
|  |  |