/*
|
/*
|
* iolib.c -- I/O library
|
* iolib.c -- I/O library
|
*/
|
*/
|
|
|
|
|
#include "types.h"
|
#include "types.h"
|
#include "stdarg.h"
|
#include "stdarg.h"
|
#include "iolib.h"
|
#include "iolib.h"
|
#include "biolib.h"
|
#include "biolib.h"
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* string functions */
|
/* string functions */
|
|
|
|
|
int strlen(char *str) {
|
int strlen(char *str) {
|
int i;
|
int i;
|
|
|
i = 0;
|
i = 0;
|
while (*str++ != '\0') {
|
while (*str++ != '\0') {
|
i++;
|
i++;
|
}
|
}
|
return i;
|
return i;
|
}
|
}
|
|
|
|
|
void strcpy(char *dst, char *src) {
|
void strcpy(char *dst, char *src) {
|
while ((*dst++ = *src++) != '\0') ;
|
while ((*dst++ = *src++) != '\0') ;
|
}
|
}
|
|
|
|
|
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt) {
|
void memcpy(unsigned char *dst, unsigned char *src, unsigned int cnt) {
|
while (cnt--) {
|
while (cnt--) {
|
*dst++ = *src++;
|
*dst++ = *src++;
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* terminal I/O */
|
/* terminal I/O */
|
|
|
|
|
char getchar(void) {
|
char getchar(void) {
|
return getc();
|
return getc();
|
}
|
}
|
|
|
|
|
void putchar(char c) {
|
void putchar(char c) {
|
if (c == '\n') {
|
if (c == '\n') {
|
putchar('\r');
|
putchar('\r');
|
}
|
}
|
putc(c);
|
putc(c);
|
}
|
}
|
|
|
|
|
void putString(char *s) {
|
void putString(char *s) {
|
while (*s != '\0') {
|
while (*s != '\0') {
|
putchar(*s++);
|
putchar(*s++);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* get a line from the terminal */
|
/* get a line from the terminal */
|
|
|
|
|
void getLine(char *prompt, char *line, int max) {
|
void getLine(char *prompt, char *line, int max) {
|
int index;
|
int index;
|
char c;
|
char c;
|
|
|
putString(prompt);
|
putString(prompt);
|
putString(line);
|
putString(line);
|
index = strlen(line);
|
index = strlen(line);
|
while (1) {
|
while (1) {
|
c = getchar();
|
c = getchar();
|
switch (c) {
|
switch (c) {
|
case '\r':
|
case '\r':
|
putchar('\n');
|
putchar('\n');
|
line[index] = '\0';
|
line[index] = '\0';
|
return;
|
return;
|
case '\b':
|
case '\b':
|
case 0x7F:
|
case 0x7F:
|
if (index == 0) {
|
if (index == 0) {
|
break;
|
break;
|
}
|
}
|
putchar('\b');
|
putchar('\b');
|
putchar(' ');
|
putchar(' ');
|
putchar('\b');
|
putchar('\b');
|
index--;
|
index--;
|
break;
|
break;
|
default:
|
default:
|
if (c == '\t') {
|
if (c == '\t') {
|
c = ' ';
|
c = ' ';
|
}
|
}
|
if (c < 0x20 || c > 0x7E) {
|
if (c < 0x20 || c > 0x7E) {
|
break;
|
break;
|
}
|
}
|
putchar(c);
|
putchar(c);
|
line[index++] = c;
|
line[index++] = c;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
/* scaled-down version of printf */
|
/* scaled-down version of printf */
|
|
|
|
|
/*
|
/*
|
* Count the number of characters needed to represent
|
* Count the number of characters needed to represent
|
* a given number in base 10.
|
* a given number in base 10.
|
*/
|
*/
|
int countPrintn(long n) {
|
int countPrintn(long n) {
|
long a;
|
long a;
|
int res;
|
int res;
|
|
|
res = 0;
|
res = 0;
|
if (n < 0) {
|
if (n < 0) {
|
res++;
|
res++;
|
n = -n;
|
n = -n;
|
}
|
}
|
a = n / 10;
|
a = n / 10;
|
if (a != 0) {
|
if (a != 0) {
|
res += countPrintn(a);
|
res += countPrintn(a);
|
}
|
}
|
return res + 1;
|
return res + 1;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Output a number in base 10.
|
* Output a number in base 10.
|
*/
|
*/
|
void printn(long n) {
|
void printn(long n) {
|
long a;
|
long a;
|
|
|
if (n < 0) {
|
if (n < 0) {
|
putchar('-');
|
putchar('-');
|
n = -n;
|
n = -n;
|
}
|
}
|
a = n / 10;
|
a = n / 10;
|
if (a != 0) {
|
if (a != 0) {
|
printn(a);
|
printn(a);
|
}
|
}
|
putchar(n % 10 + '0');
|
putchar(n % 10 + '0');
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Count the number of characters needed to represent
|
* Count the number of characters needed to represent
|
* a given number in a given base.
|
* a given number in a given base.
|
*/
|
*/
|
int countPrintu(unsigned long n, unsigned long b) {
|
int countPrintu(unsigned long n, unsigned long b) {
|
unsigned long a;
|
unsigned long a;
|
int res;
|
int res;
|
|
|
res = 0;
|
res = 0;
|
a = n / b;
|
a = n / b;
|
if (a != 0) {
|
if (a != 0) {
|
res += countPrintu(a, b);
|
res += countPrintu(a, b);
|
}
|
}
|
return res + 1;
|
return res + 1;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Output a number in a given base.
|
* Output a number in a given base.
|
*/
|
*/
|
void printu(unsigned long n, unsigned long b, Bool upperCase) {
|
void printu(unsigned long n, unsigned long b, Bool upperCase) {
|
unsigned long a;
|
unsigned long a;
|
|
|
a = n / b;
|
a = n / b;
|
if (a != 0) {
|
if (a != 0) {
|
printu(a, b, upperCase);
|
printu(a, b, upperCase);
|
}
|
}
|
if (upperCase) {
|
if (upperCase) {
|
putchar("0123456789ABCDEF"[n % b]);
|
putchar("0123456789ABCDEF"[n % b]);
|
} else {
|
} else {
|
putchar("0123456789abcdef"[n % b]);
|
putchar("0123456789abcdef"[n % b]);
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Output a number of filler characters.
|
* Output a number of filler characters.
|
*/
|
*/
|
void fill(int numFillers, char filler) {
|
void fill(int numFillers, char filler) {
|
while (numFillers-- > 0) {
|
while (numFillers-- > 0) {
|
putchar(filler);
|
putchar(filler);
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output with a variable argument list.
|
* Formatted output with a variable argument list.
|
*/
|
*/
|
void vprintf(char *fmt, va_list ap) {
|
void vprintf(char *fmt, va_list ap) {
|
char c;
|
char c;
|
int n;
|
int n;
|
long ln;
|
long ln;
|
unsigned int u;
|
unsigned int u;
|
unsigned long lu;
|
unsigned long lu;
|
char *s;
|
char *s;
|
Bool negFlag;
|
Bool negFlag;
|
char filler;
|
char filler;
|
int width, count;
|
int width, count;
|
|
|
while (1) {
|
while (1) {
|
while ((c = *fmt++) != '%') {
|
while ((c = *fmt++) != '%') {
|
if (c == '\0') {
|
if (c == '\0') {
|
return;
|
return;
|
}
|
}
|
putchar(c);
|
putchar(c);
|
}
|
}
|
c = *fmt++;
|
c = *fmt++;
|
if (c == '-') {
|
if (c == '-') {
|
negFlag = TRUE;
|
negFlag = TRUE;
|
c = *fmt++;
|
c = *fmt++;
|
} else {
|
} else {
|
negFlag = FALSE;
|
negFlag = FALSE;
|
}
|
}
|
if (c == '0') {
|
if (c == '0') {
|
filler = '0';
|
filler = '0';
|
c = *fmt++;
|
c = *fmt++;
|
} else {
|
} else {
|
filler = ' ';
|
filler = ' ';
|
}
|
}
|
width = 0;
|
width = 0;
|
while (c >= '0' && c <= '9') {
|
while (c >= '0' && c <= '9') {
|
width *= 10;
|
width *= 10;
|
width += c - '0';
|
width += c - '0';
|
c = *fmt++;
|
c = *fmt++;
|
}
|
}
|
if (c == 'd') {
|
if (c == 'd') {
|
n = va_arg(ap, int);
|
n = va_arg(ap, int);
|
count = countPrintn(n);
|
count = countPrintn(n);
|
if (width > 0 && !negFlag) {
|
if (width > 0 && !negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
printn(n);
|
printn(n);
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
} else
|
} else
|
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
|
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
|
u = va_arg(ap, int);
|
u = va_arg(ap, int);
|
count = countPrintu(u,
|
count = countPrintu(u,
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
|
if (width > 0 && !negFlag) {
|
if (width > 0 && !negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
printu(u,
|
printu(u,
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
|
c == 'X');
|
c == 'X');
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
} else
|
} else
|
if (c == 'l') {
|
if (c == 'l') {
|
c = *fmt++;
|
c = *fmt++;
|
if (c == 'd') {
|
if (c == 'd') {
|
ln = va_arg(ap, long);
|
ln = va_arg(ap, long);
|
count = countPrintn(ln);
|
count = countPrintn(ln);
|
if (width > 0 && !negFlag) {
|
if (width > 0 && !negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
printn(ln);
|
printn(ln);
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
} else
|
} else
|
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
|
if (c == 'u' || c == 'o' || c == 'x' || c == 'X') {
|
lu = va_arg(ap, long);
|
lu = va_arg(ap, long);
|
count = countPrintu(lu,
|
count = countPrintu(lu,
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10));
|
if (width > 0 && !negFlag) {
|
if (width > 0 && !negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
printu(lu,
|
printu(lu,
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
|
c == 'o' ? 8 : ((c == 'x' || c == 'X') ? 16 : 10),
|
c == 'X');
|
c == 'X');
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
} else {
|
} else {
|
putchar('l');
|
putchar('l');
|
putchar(c);
|
putchar(c);
|
}
|
}
|
} else
|
} else
|
if (c == 's') {
|
if (c == 's') {
|
s = va_arg(ap, char *);
|
s = va_arg(ap, char *);
|
count = strlen(s);
|
count = strlen(s);
|
if (width > 0 && !negFlag) {
|
if (width > 0 && !negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
while ((c = *s++) != '\0') {
|
while ((c = *s++) != '\0') {
|
putchar(c);
|
putchar(c);
|
}
|
}
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
fill(width - count, filler);
|
fill(width - count, filler);
|
}
|
}
|
} else
|
} else
|
if (c == 'c') {
|
if (c == 'c') {
|
c = va_arg(ap, char);
|
c = va_arg(ap, char);
|
putchar(c);
|
putchar(c);
|
} else {
|
} else {
|
putchar(c);
|
putchar(c);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output.
|
* Formatted output.
|
* This is a scaled-down version of the C library's
|
* This is a scaled-down version of the C library's
|
* printf. Used to print diagnostic information on
|
* printf. Used to print diagnostic information on
|
* the console (and optionally to a logfile).
|
* the console (and optionally to a logfile).
|
*/
|
*/
|
void printf(char *fmt, ...) {
|
void printf(char *fmt, ...) {
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
vprintf(fmt, ap);
|
vprintf(fmt, ap);
|
va_end(ap);
|
va_end(ap);
|
}
|
}
|
|
|