sbase/printf.c

157 lines
3.2 KiB
C
Raw Normal View History

/* See LICENSE file for copyright and license details. */
2014-09-28 14:10:27 +00:00
#include <ctype.h>
#include <limits.h>
2014-09-28 14:10:27 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utf.h"
#include "util.h"
2014-09-28 14:10:27 +00:00
2015-02-15 16:00:32 +00:00
static void
usage(void)
{
eprintf("%s format [arg ...]\n", argv0);
2014-09-28 14:10:27 +00:00
}
2015-02-15 16:00:32 +00:00
int
main(int argc, char *argv[])
2014-09-28 14:10:27 +00:00
{
Rune *rarg;
size_t i, j, argi, lastargi, formatlen, arglen;
long long num;
double dou;
int cooldown = 0, width, precision;
char *format, *tmp, *arg, *fmt;
argv0 = argv[0];
if (argc < 2)
2014-09-28 14:10:27 +00:00
usage();
format = argv[1];
if ((tmp = strstr(format, "\\c"))) {
*tmp = 0;
cooldown = 1;
}
formatlen = unescape(format);
if (formatlen == 0)
return 0;
lastargi = 0;
for (i = 0, argi = 2; !cooldown || i < formatlen; i++, i = cooldown ? i : (i % formatlen)) {
if (i == 0) {
if (lastargi == argi)
2014-09-28 14:10:27 +00:00
break;
lastargi = argi;
}
if (format[i] != '%') {
putchar(format[i]);
continue;
}
2014-09-28 14:10:27 +00:00
/* field width */
width = -1;
for (i++; strchr("#-+ 0", format[i]); i++);
if (format[i] == '*') {
if (argi < argc)
width = estrtonum(argv[argi++], 0, INT_MAX);
else
cooldown = 1;
i++;
} else {
j = i;
for (; strchr("+-0123456789", format[i]); i++);
if (j != i) {
tmp = estrndup(format + j, i - j);
width = estrtonum(tmp, 0, INT_MAX);
free(tmp);
} else {
width = 0;
2014-09-28 14:10:27 +00:00
}
}
/* field precision */
precision = -1;
if (format[i] == '.') {
if (format[++i] == '*') {
if (argi < argc)
precision = estrtonum(argv[argi++], 0, INT_MAX);
else
cooldown = 1;
i++;
2014-09-28 14:10:27 +00:00
} else {
j = i;
for (; strchr("+-0123456789", format[i]); i++);
if (j != i) {
tmp = estrndup(format + j, i - j);
precision = estrtonum(tmp, 0, INT_MAX);
free(tmp);
} else {
precision = 0;
}
2014-09-28 14:10:27 +00:00
}
}
if (format[i] != '%') {
if (argi < argc)
arg = argv[argi++];
else {
arg = "";
cooldown = 1;
}
} else
putchar('%');
switch (format[i]) {
case 'b':
if ((tmp = strstr(arg, "\\c"))) {
*tmp = 0;
unescape(arg);
fputs(arg, stdout);
return 0;
}
unescape(arg);
fputs(arg, stdout);
break;
case 'c':
unescape(arg);
rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
utftorunestr(arg, rarg);
efputrune(rarg, stdout, "<stdout>");
free(rarg);
break;
case 's':
printf("%*.*s", width, precision, arg);
break;
case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
arglen = strlen(arg);
for (j = 0; j < arglen && isspace(arg[j]); j++);
if (arg[j] == '\'' || arg[j] == '\"') {
arg += j + 1;
unescape(arg);
rarg = ereallocarray(NULL, utflen(arg) + 1, sizeof(*rarg));
utftorunestr(arg, rarg);
num = rarg[0];
} else
num = (strlen(arg) > 0) ? estrtonum(arg, LLONG_MIN, LLONG_MAX) : 0;
fmt = estrdup("%*ll#");
fmt[4] = format[i];
printf(fmt, width, num);
free(fmt);
break;
case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
fmt = estrdup("%*.*#");
fmt[4] = format[i];
dou = (strlen(arg) > 0) ? estrtod(arg) : 0;
printf(fmt, width, precision, dou);
free(fmt);
break;
default:
eprintf("Invalid format specifier '%c'.\n", format[i]);
2014-09-28 14:10:27 +00:00
}
if (argi >= argc)
cooldown = 1;
2014-09-28 14:10:27 +00:00
}
2014-09-28 14:10:27 +00:00
return 0;
}