/*
|
/*
|
* lib.c -- the library
|
* lib.c -- the library
|
*/
|
*/
|
|
|
|
|
#include "common.h"
|
#include "common.h"
|
#include "lib.h"
|
#include "lib.h"
|
#include "stdarg.h"
|
#include "stdarg.h"
|
#include "start.h"
|
#include "start.h"
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* This is only for debugging.
|
* This is only for debugging.
|
* Place a breakpoint at the very beginning of this routine
|
* Place a breakpoint at the very beginning of this routine
|
* and call it wherever you want to break execution.
|
* and call it wherever you want to break execution.
|
*/
|
*/
|
void debugBreak(void) {
|
void debugBreak(void) {
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* Count the length of a string (without terminating null character).
|
* Count the length of a string (without terminating null character).
|
*/
|
*/
|
int strlen(const char *s) {
|
int strlen(const char *s) {
|
const char *p;
|
const char *p;
|
|
|
p = s;
|
p = s;
|
while (*p != '\0') {
|
while (*p != '\0') {
|
p++;
|
p++;
|
}
|
}
|
return p - s;
|
return p - s;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Compare two strings.
|
* Compare two strings.
|
* Return a number < 0, = 0, or > 0 iff the first string is less
|
* Return a number < 0, = 0, or > 0 iff the first string is less
|
* than, equal to, or greater than the second one, respectively.
|
* than, equal to, or greater than the second one, respectively.
|
*/
|
*/
|
int strcmp(const char *s, const char *t) {
|
int strcmp(const char *s, const char *t) {
|
while (*s == *t) {
|
while (*s == *t) {
|
if (*s == '\0') {
|
if (*s == '\0') {
|
return 0;
|
return 0;
|
}
|
}
|
s++;
|
s++;
|
t++;
|
t++;
|
}
|
}
|
return *s - *t;
|
return *s - *t;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Copy string t to string s (includes terminating null character).
|
* Copy string t to string s (includes terminating null character).
|
*/
|
*/
|
char *strcpy(char *s, const char *t) {
|
char *strcpy(char *s, const char *t) {
|
char *p;
|
char *p;
|
|
|
p = s;
|
p = s;
|
while ((*p = *t) != '\0') {
|
while ((*p = *t) != '\0') {
|
p++;
|
p++;
|
t++;
|
t++;
|
}
|
}
|
return s;
|
return s;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Append string t to string s.
|
* Append string t to string s.
|
*/
|
*/
|
char *strcat(char *s, const char *t) {
|
char *strcat(char *s, const char *t) {
|
char *p;
|
char *p;
|
|
|
p = s;
|
p = s;
|
while (*p != '\0') {
|
while (*p != '\0') {
|
p++;
|
p++;
|
}
|
}
|
while ((*p = *t) != '\0') {
|
while ((*p = *t) != '\0') {
|
p++;
|
p++;
|
t++;
|
t++;
|
}
|
}
|
return s;
|
return s;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Locate character c in string s.
|
* Locate character c in string s.
|
*/
|
*/
|
char *strchr(const char *s, char c) {
|
char *strchr(const char *s, char c) {
|
while (*s != c) {
|
while (*s != c) {
|
if (*s == '\0') {
|
if (*s == '\0') {
|
return NULL;
|
return NULL;
|
}
|
}
|
s++;
|
s++;
|
}
|
}
|
return (char *) s;
|
return (char *) s;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Extract the next token from the string s, delimited
|
* Extract the next token from the string s, delimited
|
* by any character from the delimiter string t.
|
* by any character from the delimiter string t.
|
*/
|
*/
|
char *strtok(char *s, const char *t) {
|
char *strtok(char *s, const char *t) {
|
static char *p;
|
static char *p;
|
char *q;
|
char *q;
|
|
|
if (s != NULL) {
|
if (s != NULL) {
|
p = s;
|
p = s;
|
} else {
|
} else {
|
p++;
|
p++;
|
}
|
}
|
while (*p != '\0' && strchr(t, *p) != NULL) {
|
while (*p != '\0' && strchr(t, *p) != NULL) {
|
p++;
|
p++;
|
}
|
}
|
if (*p == '\0') {
|
if (*p == '\0') {
|
return NULL;
|
return NULL;
|
}
|
}
|
q = p++;
|
q = p++;
|
while (*p != '\0' && strchr(t, *p) == NULL) {
|
while (*p != '\0' && strchr(t, *p) == NULL) {
|
p++;
|
p++;
|
}
|
}
|
if (*p != '\0') {
|
if (*p != '\0') {
|
*p = '\0';
|
*p = '\0';
|
} else {
|
} else {
|
p--;
|
p--;
|
}
|
}
|
return q;
|
return q;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* Determine if a character is 'white space'.
|
* Determine if a character is 'white space'.
|
*/
|
*/
|
static Bool isspace(char c) {
|
static Bool isspace(char c) {
|
Bool res;
|
Bool res;
|
|
|
switch (c) {
|
switch (c) {
|
case ' ':
|
case ' ':
|
case '\f':
|
case '\f':
|
case '\n':
|
case '\n':
|
case '\r':
|
case '\r':
|
case '\t':
|
case '\t':
|
case '\v':
|
case '\v':
|
res = true;
|
res = true;
|
break;
|
break;
|
default:
|
default:
|
res = false;
|
res = false;
|
break;
|
break;
|
}
|
}
|
return res;
|
return res;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Check for valid digit, and convert to value.
|
* Check for valid digit, and convert to value.
|
*/
|
*/
|
static Bool checkDigit(char c, int base, int *value) {
|
static Bool checkDigit(char c, int base, int *value) {
|
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
*value = c - '0';
|
*value = c - '0';
|
} else
|
} else
|
if (c >= 'A' && c <= 'Z') {
|
if (c >= 'A' && c <= 'Z') {
|
*value = c - 'A' + 10;
|
*value = c - 'A' + 10;
|
} else
|
} else
|
if (c >= 'a' && c <= 'z') {
|
if (c >= 'a' && c <= 'z') {
|
*value = c - 'a' + 10;
|
*value = c - 'a' + 10;
|
} else {
|
} else {
|
return false;
|
return false;
|
}
|
}
|
return *value < base;
|
return *value < base;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Convert initial part of string to unsigned long integer.
|
* Convert initial part of string to unsigned long integer.
|
*/
|
*/
|
unsigned long strtoul(const char *s, char **endp, int base) {
|
unsigned long strtoul(const char *s, char **endp, int base) {
|
unsigned long res;
|
unsigned long res;
|
int sign;
|
int sign;
|
int digit;
|
int digit;
|
|
|
res = 0;
|
res = 0;
|
while (isspace(*s)) {
|
while (isspace(*s)) {
|
s++;
|
s++;
|
}
|
}
|
if (*s == '+') {
|
if (*s == '+') {
|
sign = 1;
|
sign = 1;
|
s++;
|
s++;
|
} else
|
} else
|
if (*s == '-') {
|
if (*s == '-') {
|
sign = -1;
|
sign = -1;
|
s++;
|
s++;
|
} else {
|
} else {
|
sign = 1;
|
sign = 1;
|
}
|
}
|
if (base == 0 || base == 16) {
|
if (base == 0 || base == 16) {
|
if (*s == '0' &&
|
if (*s == '0' &&
|
(*(s + 1) == 'x' || *(s + 1) == 'X')) {
|
(*(s + 1) == 'x' || *(s + 1) == 'X')) {
|
/* base is 16 */
|
/* base is 16 */
|
s += 2;
|
s += 2;
|
base = 16;
|
base = 16;
|
} else {
|
} else {
|
/* base is 0 or 16, but number does not start with "0x" */
|
/* base is 0 or 16, but number does not start with "0x" */
|
if (base == 0) {
|
if (base == 0) {
|
if (*s == '0') {
|
if (*s == '0') {
|
s++;
|
s++;
|
base = 8;
|
base = 8;
|
} else {
|
} else {
|
base = 10;
|
base = 10;
|
}
|
}
|
} else {
|
} else {
|
/* take base as is */
|
/* take base as is */
|
}
|
}
|
}
|
}
|
} else {
|
} else {
|
/* take base as is */
|
/* take base as is */
|
}
|
}
|
while (checkDigit(*s, base, &digit)) {
|
while (checkDigit(*s, base, &digit)) {
|
res *= base;
|
res *= base;
|
res += digit;
|
res += digit;
|
s++;
|
s++;
|
}
|
}
|
if (endp != NULL) {
|
if (endp != NULL) {
|
*endp = (char *) s;
|
*endp = (char *) s;
|
}
|
}
|
return sign * res;
|
return sign * res;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* Exchange two array items of a given size.
|
* Exchange two array items of a given size.
|
*/
|
*/
|
static void xchg(char *p, char *q, int size) {
|
static void xchg(char *p, char *q, int size) {
|
char t;
|
char t;
|
|
|
while (size--) {
|
while (size--) {
|
t = *p;
|
t = *p;
|
*p++ = *q;
|
*p++ = *q;
|
*q++ = t;
|
*q++ = t;
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* This is a recursive version of quicksort.
|
* This is a recursive version of quicksort.
|
*/
|
*/
|
static void sort(char *l, char *r, int size,
|
static void sort(char *l, char *r, int size,
|
int (*cmp)(const void *, const void *)) {
|
int (*cmp)(const void *, const void *)) {
|
char *i;
|
char *i;
|
char *j;
|
char *j;
|
char *x;
|
char *x;
|
|
|
i = l;
|
i = l;
|
j = r;
|
j = r;
|
x = l + (((r - l) / size) / 2) * size;
|
x = l + (((r - l) / size) / 2) * size;
|
do {
|
do {
|
while (cmp(i, x) < 0) {
|
while (cmp(i, x) < 0) {
|
i += size;
|
i += size;
|
}
|
}
|
while (cmp(x, j) < 0) {
|
while (cmp(x, j) < 0) {
|
j -= size;
|
j -= size;
|
}
|
}
|
if (i <= j) {
|
if (i <= j) {
|
/* exchange array elements i and j */
|
/* exchange array elements i and j */
|
/* attention: update x if it is one of these */
|
/* attention: update x if it is one of these */
|
if (x == i) {
|
if (x == i) {
|
x = j;
|
x = j;
|
} else
|
} else
|
if (x == j) {
|
if (x == j) {
|
x = i;
|
x = i;
|
}
|
}
|
xchg(i, j, size);
|
xchg(i, j, size);
|
i += size;
|
i += size;
|
j -= size;
|
j -= size;
|
}
|
}
|
} while (i <= j);
|
} while (i <= j);
|
if (l < j) {
|
if (l < j) {
|
sort(l, j, size, cmp);
|
sort(l, j, size, cmp);
|
}
|
}
|
if (i < r) {
|
if (i < r) {
|
sort(i, r, size, cmp);
|
sort(i, r, size, cmp);
|
}
|
}
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* External interface for the quicksort algorithm.
|
* External interface for the quicksort algorithm.
|
*/
|
*/
|
void qsort(void *base, int n, int size,
|
void qsort(void *base, int n, int size,
|
int (*cmp)(const void *, const void*)) {
|
int (*cmp)(const void *, const void*)) {
|
sort((char *) base, (char *) base + (n - 1) * size, size, cmp);
|
sort((char *) base, (char *) base + (n - 1) * size, size, cmp);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* Input a character from the console.
|
* Input a character from the console.
|
*/
|
*/
|
char getchar(void) {
|
char getchar(void) {
|
return cin();
|
return cin();
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Output a character on the console.
|
* Output a character on the console.
|
* Replace LF by CR/LF.
|
* Replace LF by CR/LF.
|
*/
|
*/
|
void putchar(char c) {
|
void putchar(char c) {
|
if (c == '\n') {
|
if (c == '\n') {
|
cout('\r');
|
cout('\r');
|
}
|
}
|
cout(c);
|
cout(c);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
/*
|
/*
|
* 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.
|
*/
|
*/
|
static int countPrintn(long n) {
|
static 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.
|
*/
|
*/
|
static void *printn(void *(*emit)(void *, char), void *arg,
|
static void *printn(void *(*emit)(void *, char), void *arg,
|
int *nchar, long n) {
|
int *nchar, long n) {
|
long a;
|
long a;
|
|
|
if (n < 0) {
|
if (n < 0) {
|
arg = emit(arg, '-');
|
arg = emit(arg, '-');
|
(*nchar)++;
|
(*nchar)++;
|
n = -n;
|
n = -n;
|
}
|
}
|
a = n / 10;
|
a = n / 10;
|
if (a != 0) {
|
if (a != 0) {
|
arg = printn(emit, arg, nchar, a);
|
arg = printn(emit, arg, nchar, a);
|
}
|
}
|
arg = emit(arg, n % 10 + '0');
|
arg = emit(arg, n % 10 + '0');
|
(*nchar)++;
|
(*nchar)++;
|
return arg;
|
return arg;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* 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.
|
*/
|
*/
|
static int countPrintu(unsigned long n, unsigned long b) {
|
static 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.
|
*/
|
*/
|
static void *printu(void *(*emit)(void *, char), void *arg,
|
static void *printu(void *(*emit)(void *, char), void *arg,
|
int *nchar, unsigned long n, unsigned long b,
|
int *nchar, unsigned long n, unsigned long b,
|
Bool upperCase) {
|
Bool upperCase) {
|
unsigned long a;
|
unsigned long a;
|
|
|
a = n / b;
|
a = n / b;
|
if (a != 0) {
|
if (a != 0) {
|
arg = printu(emit, arg, nchar, a, b, upperCase);
|
arg = printu(emit, arg, nchar, a, b, upperCase);
|
}
|
}
|
if (upperCase) {
|
if (upperCase) {
|
arg = emit(arg, "0123456789ABCDEF"[n % b]);
|
arg = emit(arg, "0123456789ABCDEF"[n % b]);
|
(*nchar)++;
|
(*nchar)++;
|
} else {
|
} else {
|
arg = emit(arg, "0123456789abcdef"[n % b]);
|
arg = emit(arg, "0123456789abcdef"[n % b]);
|
(*nchar)++;
|
(*nchar)++;
|
}
|
}
|
return arg;
|
return arg;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Output a number of filler characters.
|
* Output a number of filler characters.
|
*/
|
*/
|
static void *fill(void *(*emit)(void *, char), void *arg,
|
static void *fill(void *(*emit)(void *, char), void *arg,
|
int *nchar, int numFillers, char filler) {
|
int *nchar, int numFillers, char filler) {
|
while (numFillers-- > 0) {
|
while (numFillers-- > 0) {
|
arg = emit(arg, filler);
|
arg = emit(arg, filler);
|
(*nchar)++;
|
(*nchar)++;
|
}
|
}
|
return arg;
|
return arg;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* This function does the real work of formatted printing.
|
* This function does the real work of formatted printing.
|
*/
|
*/
|
static int doPrintf(void *(*emit)(void *, char), void *arg,
|
static int doPrintf(void *(*emit)(void *, char), void *arg,
|
const char *fmt, va_list ap) {
|
const char *fmt, va_list ap) {
|
int nchar;
|
int nchar;
|
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;
|
|
|
nchar = 0;
|
nchar = 0;
|
while (1) {
|
while (1) {
|
while ((c = *fmt++) != '%') {
|
while ((c = *fmt++) != '%') {
|
if (c == '\0') {
|
if (c == '\0') {
|
return nchar;
|
return nchar;
|
}
|
}
|
arg = emit(arg, c);
|
arg = emit(arg, c);
|
nchar++;
|
nchar++;
|
}
|
}
|
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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
arg = printn(emit, arg, &nchar, n);
|
arg = printn(emit, arg, &nchar, n);
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
arg = printu(emit, arg, &nchar, u,
|
arg = printu(emit, arg, &nchar, 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
arg = printn(emit, arg, &nchar, ln);
|
arg = printn(emit, arg, &nchar, ln);
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
arg = printu(emit, arg, &nchar, lu,
|
arg = printu(emit, arg, &nchar, 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
} else {
|
} else {
|
arg = emit(arg, 'l');
|
arg = emit(arg, 'l');
|
nchar++;
|
nchar++;
|
arg = emit(arg, c);
|
arg = emit(arg, c);
|
nchar++;
|
nchar++;
|
}
|
}
|
} 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) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
while ((c = *s++) != '\0') {
|
while ((c = *s++) != '\0') {
|
arg = emit(arg, c);
|
arg = emit(arg, c);
|
nchar++;
|
nchar++;
|
}
|
}
|
if (width > 0 && negFlag) {
|
if (width > 0 && negFlag) {
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
arg = fill(emit, arg, &nchar, width - count, filler);
|
}
|
}
|
} else
|
} else
|
if (c == 'c') {
|
if (c == 'c') {
|
c = va_arg(ap, char);
|
c = va_arg(ap, char);
|
arg = emit(arg, c);
|
arg = emit(arg, c);
|
nchar++;
|
nchar++;
|
} else {
|
} else {
|
arg = emit(arg, c);
|
arg = emit(arg, c);
|
nchar++;
|
nchar++;
|
}
|
}
|
}
|
}
|
/* never reached */
|
/* never reached */
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Emit a character to the console.
|
* Emit a character to the console.
|
*/
|
*/
|
static void *emitToConsole(void *dummy, char c) {
|
static void *emitToConsole(void *dummy, char c) {
|
putchar(c);
|
putchar(c);
|
return dummy;
|
return dummy;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output with a variable argument list.
|
* Formatted output with a variable argument list.
|
*/
|
*/
|
static int vprintf(const char *fmt, va_list ap) {
|
static int vprintf(const char *fmt, va_list ap) {
|
int n;
|
int n;
|
|
|
n = doPrintf(emitToConsole, NULL, fmt, ap);
|
n = doPrintf(emitToConsole, NULL, fmt, ap);
|
return n;
|
return n;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output.
|
* Formatted output.
|
*/
|
*/
|
int printf(const char *fmt, ...) {
|
int printf(const char *fmt, ...) {
|
int n;
|
int n;
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
n = vprintf(fmt, ap);
|
n = vprintf(fmt, ap);
|
va_end(ap);
|
va_end(ap);
|
return n;
|
return n;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Emit a character to a buffer.
|
* Emit a character to a buffer.
|
*/
|
*/
|
static void *emitToBuffer(void *bufptr, char c) {
|
static void *emitToBuffer(void *bufptr, char c) {
|
*(char *)bufptr = c;
|
*(char *)bufptr = c;
|
return (char *) bufptr + 1;
|
return (char *) bufptr + 1;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output into a buffer with a variable argument list.
|
* Formatted output into a buffer with a variable argument list.
|
*/
|
*/
|
static int vsprintf(char *s, const char *fmt, va_list ap) {
|
static int vsprintf(char *s, const char *fmt, va_list ap) {
|
int n;
|
int n;
|
|
|
n = doPrintf(emitToBuffer, s, fmt, ap);
|
n = doPrintf(emitToBuffer, s, fmt, ap);
|
s[n] = '\0';
|
s[n] = '\0';
|
return n;
|
return n;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* Formatted output into a buffer.
|
* Formatted output into a buffer.
|
*/
|
*/
|
int sprintf(char *s, const char *fmt, ...) {
|
int sprintf(char *s, const char *fmt, ...) {
|
int n;
|
int n;
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
n = vsprintf(s, fmt, ap);
|
n = vsprintf(s, fmt, ap);
|
va_end(ap);
|
va_end(ap);
|
return n;
|
return n;
|
}
|
}
|
|
|