move pic_printf family to port.c

This commit is contained in:
Yuichi Nishiwaki 2017-04-09 23:39:24 +09:00
parent 8592802afc
commit 01c817799b
7 changed files with 294 additions and 197 deletions

View File

@ -37,7 +37,6 @@ PICRIN_OBJS = \
CONTRIB_SRCS =
CONTRIB_OBJS = $(CONTRIB_SRCS:.c=.o)
CONTRIB_LIBS =
CONTRIB_DEFS =
CONTRIB_INITS =
CONTRIB_TESTS =
CONTRIB_DOCS = $(wildcard contrib/*/docs/*.rst)
@ -63,7 +62,6 @@ tiny-picrin: $(LIBPICRIN_OBJS) src/tiny-main.o
include $(sort $(wildcard contrib/*/nitro.mk))
picrin: CFLAGS += $(CONTRIB_DEFS)
picrin: $(PICRIN_OBJS) $(CONTRIB_OBJS) $(LIBPICRIN_OBJS)
$(CC) $(CFLAGS) -o $@ $(PICRIN_OBJS) $(CONTRIB_OBJS) $(LIBPICRIN_OBJS) $(LDFLAGS)

150
contrib/10.roundtrip/emyg.c Normal file
View File

@ -0,0 +1,150 @@
#include "picrin.h"
#include "emyg_dtoa.h"
#include "emyg_atod.h"
static int
int2str(long x, int base, char *buf)
{
static const char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
int i, neg, len;
neg = 0;
if (x < 0) {
neg = 1;
x = -x;
}
i = 0;
do {
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg) {
buf[i++] = '-';
}
buf[i] = '\0';
len = i;
for (i = 0; i < len / 2; ++i) {
char tmp = buf[i];
buf[i] = buf[len - i - 1];
buf[len - i - 1] = tmp;
}
return len;
}
static pic_value
emyg_number_to_string(pic_state *pic)
{
double f;
bool e;
int radix = 10;
pic_get_args(pic, "F|i", &f, &e, &radix);
if (radix < 2 || radix > 36) {
pic_error(pic, "invalid radix (between 2 and 36, inclusive)", 1, pic_int_value(pic, radix));
}
if (e) {
char buf[sizeof(int) * CHAR_BIT + 3];
int len = int2str((int) f, radix, buf);
return pic_str_value(pic, buf, len);
}
else {
char buf[64];
emyg_dtoa(f, buf);
return pic_cstr_value(pic, buf);
}
}
static bool
strcaseeq(const char *s1, const char *s2)
{
char a, b;
while ((a = *s1++) * (b = *s2++)) {
if (tolower(a) != tolower(b))
return false;
}
return a == b;
}
static pic_value
string_to_number(pic_state *pic, const char *str)
{
double flt;
const char *c = str;
bool isint = 1;
if (*c == '+' || *c == '-')
c++;
if (! isdigit(*c++)) {
return pic_false_value(pic);
}
while (isdigit(*c)) c++;
if (*c == '.') {
isint = false;
c++;
while (isdigit(*c)) c++;
}
if (*c == 'e' || *c == 'E') {
isint = false;
c++;
if (*c == '+' || *c == '-')
c++;
if (! isdigit(*c++)) {
return pic_false_value(pic);
}
while (isdigit(*c)) c++;
}
if (*c != '\0') {
return pic_false_value(pic);
}
flt = emyg_atod(str);
if (isint && INT_MIN <= flt && flt <= INT_MAX) {
return pic_int_value(pic, flt);
} else {
return pic_float_value(pic, flt);
}
}
static pic_value
emyg_string_to_number(pic_state *pic)
{
const char *str;
int radix = 10;
long num;
char *eptr;
pic_get_args(pic, "z|i", &str, &radix);
if (strcaseeq(str, "+inf.0"))
return pic_float_value(pic, 1.0 / 0.0);
if (strcaseeq(str, "-inf.0"))
return pic_float_value(pic, -1.0 / 0.0);
if (strcaseeq(str, "+nan.0"))
return pic_float_value(pic, 0.0 / 0.0);
if (strcaseeq(str, "-nan.0"))
return pic_float_value(pic, -0.0 / 0.0);
num = strtol(str, &eptr, radix);
if (*eptr == '\0') {
return INT_MIN <= num && num <= INT_MAX ? pic_int_value(pic, num) : pic_float_value(pic, num);
}
return string_to_number(pic, str);
}
void
pic_nitro_init_roundtrip(pic_state *PIC_UNUSED(pic))
{
pic_set(pic, "number->string", pic_lambda(pic, emyg_number_to_string, 0));
pic_set(pic, "string->number", pic_lambda(pic, emyg_string_to_number, 0));
}

View File

@ -1,7 +1,8 @@
CONTRIB_DEFS += -DPIC_CSTRING_TO_DOUBLE=emyg_atod -DPIC_DOUBLE_TO_CSTRING=emyg_dtoa
CONTRIB_INITS += roundtrip
CONTRIB_SRCS += contrib/10.roundtrip/emyg_dtoa.c \
contrib/10.roundtrip/emyg_atod.c
contrib/10.roundtrip/emyg_atod.c \
contrib/10.roundtrip/emyg.c
CONTRIB_TESTS += test-roundtrip

View File

@ -6,6 +6,8 @@
#include "picrin/extra.h"
#include "../object.h"
#if PIC_USE_WRITE
struct writer_control {
int mode;
int op;
@ -21,135 +23,6 @@ struct writer_control {
#define OP_WRITE_SHARED 2
#define OP_WRITE_SIMPLE 3
#if PIC_USE_WRITE
static void write_value(pic_state *pic, pic_value obj, pic_value port, int mode, int op);
#endif
static void
print_int(pic_state *pic, pic_value port, long x, int base)
{
static const char digits[] = "0123456789abcdef";
char buf[20];
int i, neg;
neg = 0;
if (x < 0) {
neg = 1;
x = -x;
}
i = 0;
do {
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg) {
buf[i++] = '-';
}
while (i-- > 0) {
pic_fputc(pic, buf[i], port);
}
}
int
pic_vfprintf(pic_state *pic, pic_value port, const char *fmt, va_list ap)
{
const char *p;
char *sval;
int ival;
void *vp;
long start = pic_fseek(pic, port, 0, PIC_SEEK_CUR);
for (p = fmt; *p; p++) {
#if PIC_USE_WRITE
if (*p == '~') {
switch (*++p) {
default:
pic_fputc(pic, *(p-1), port);
break;
case '%':
pic_fputc(pic, '\n', port);
break;
case 'a':
write_value(pic, va_arg(ap, pic_value), port, DISPLAY_MODE, OP_WRITE);
break;
case 's':
write_value(pic, va_arg(ap, pic_value), port, WRITE_MODE, OP_WRITE);
break;
}
continue;
}
#endif
if (*p != '%') {
pic_fputc(pic, *p, port);
continue;
}
switch (*++p) {
case 'd':
case 'i':
ival = va_arg(ap, int);
print_int(pic, port, ival, 10);
break;
case 'f': {
char buf[64];
PIC_DOUBLE_TO_CSTRING(va_arg(ap, double), buf);
pic_fputs(pic, buf, port);
break;
}
case 'c':
ival = va_arg(ap, int);
pic_fputc(pic, ival, port);
break;
case 's':
sval = va_arg(ap, char*);
pic_fputs(pic, sval, port);
break;
case 'p':
vp = va_arg(ap, void*);
pic_fputs(pic, "0x", port);
print_int(pic, port, (long)vp, 16);
break;
case '%':
pic_fputc(pic, *(p-1), port);
break;
default:
pic_fputc(pic, '%', port);
pic_fputc(pic, *(p-1), port);
break;
}
}
return pic_fseek(pic, port, 0, PIC_SEEK_CUR) - start;
}
int
pic_fprintf(pic_state *pic, pic_value port, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = pic_vfprintf(pic, port, fmt, ap);
va_end(ap);
return n;
}
int
pic_printf(pic_state *pic, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = pic_vfprintf(pic, pic_stdout(pic), fmt, ap);
va_end(ap);
return n;
}
#if PIC_USE_WRITE
static void
writer_control_init(pic_state *pic, struct writer_control *p, int mode, int op)
{

View File

@ -409,6 +409,12 @@ atof(const char *nptr)
#endif
PIC_STATIC_INLINE double
pic_atod(const char *str)
{
return atof(str);
}
#if PIC_USE_STDIO
# include <stdio.h>
@ -469,16 +475,6 @@ pic_dtoa(double dval, char *buf)
#endif
#ifndef PIC_DOUBLE_TO_CSTRING
#define PIC_DOUBLE_TO_CSTRING pic_dtoa
#endif
void PIC_DOUBLE_TO_CSTRING(double, char *);
#ifndef PIC_CSTRING_TO_DOUBLE
#define PIC_CSTRING_TO_DOUBLE atof
#endif
double PIC_CSTRING_TO_DOUBLE(const char *);
/* optional features available? */
#if (defined(__GNUC__) || defined(__clang__)) && ! defined(__STRICT_ANSI__)

View File

@ -170,45 +170,34 @@ DEFINE_AOP(div, pic_div(pic, pic_int_value(pic, 1), argv[0]), do {
} while (0))
static int
number_string_length(int val, int radix)
int2str(long x, int base, char *buf)
{
unsigned long v = val; /* in case val == INT_MIN */
int count = 0;
if (val == 0) {
return 1;
}
if (val < 0) {
v = -val;
count = 1;
}
while (v > 0) {
++count;
v /= radix;
}
return count;
}
static const char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
int i, neg, len;
static void
number_string(int val, int radix, int length, char *buffer) {
const char digits[37] = "0123456789abcdefghijklmnopqrstuvwxyz";
unsigned long v = val;
int i;
if (val == 0) {
buffer[0] = '0';
buffer[1] = '\0';
return;
}
if (val < 0) {
buffer[0] = '-';
v = -val;
neg = 0;
if (x < 0) {
neg = 1;
x = -x;
}
for(i = length - 1; v > 0; --i) {
buffer[i] = digits[v % radix];
v /= radix;
i = 0;
do {
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg) {
buf[i++] = '-';
}
buffer[length] = '\0';
return;
buf[i] = '\0';
len = i;
for (i = 0; i < len / 2; ++i) {
char tmp = buf[i];
buf[i] = buf[len - i - 1];
buf[len - i - 1] = tmp;
}
return len;
}
static pic_value
@ -217,35 +206,23 @@ pic_number_number_to_string(pic_state *pic)
double f;
bool e;
int radix = 10;
pic_value str;
pic_get_args(pic, "F|i", &f, &e, &radix);
if (radix < 2 || radix > 36) {
pic_error(pic, "number->string: invalid radix (between 2 and 36, inclusive)", 1, pic_int_value(pic, radix));
pic_error(pic, "invalid radix (between 2 and 36, inclusive)", 1, pic_int_value(pic, radix));
}
if (e) {
int ival = (int) f;
int ilen = number_string_length(ival, radix);
char *buf = pic_alloca(pic, ilen + 1);
number_string(ival, radix, ilen, buf);
str = pic_str_value(pic, buf, ilen);
char buf[sizeof(int) * CHAR_BIT + 3];
int len = int2str((int) f, radix, buf);
return pic_str_value(pic, buf, len);
}
else {
pic_value port = pic_fmemopen(pic, NULL, 0, "w");
const char *buf;
int len;
pic_fprintf(pic, port, "%f", f);
pic_fgetbuf(pic, port, &buf, &len);
str = pic_str_value(pic, buf, len);
pic_fclose(pic, port);
char buf[64];
pic_dtoa(f, buf);
return pic_cstr_value(pic, buf);
}
return str;
}
static bool
@ -295,7 +272,7 @@ string_to_number(pic_state *pic, const char *str)
return pic_false_value(pic);
}
flt = PIC_CSTRING_TO_DOUBLE(str);
flt = pic_atod(str);
if (isint && INT_MIN <= flt && flt <= INT_MAX) {
return pic_int_value(pic, flt);

View File

@ -307,6 +307,108 @@ pic_fseek(pic_state *pic, pic_value port, long offset, int whence)
return 0;
}
int
pic_vfprintf(pic_state *pic, pic_value port, const char *fmt, va_list ap)
{
const char *p;
long start = pic_fseek(pic, port, 0, PIC_SEEK_CUR);
for (p = fmt; *p; p++) {
if (*p == '~') {
switch (*++p) {
default:
pic_fputc(pic, *(p-1), port);
break;
case '%':
pic_fputc(pic, '\n', port);
break;
case 'a':
pic_void(pic, pic_funcall(pic, "display", 2, va_arg(ap, pic_value), port));
break;
case 's':
pic_void(pic, pic_funcall(pic, "write", 2, va_arg(ap, pic_value), port));
break;
}
continue;
}
if (*p == '%') {
switch (*++p) {
case 'd':
case 'i': {
int ival = va_arg(ap, int);
pic_value str = pic_funcall(pic, "number->string", 1, pic_int_value(pic, ival));
pic_fputs(pic, pic_str(pic, str, 0), port);
break;
}
case 'f': {
double f = va_arg(ap, double);
pic_value str = pic_funcall(pic, "number->string", 1, pic_float_value(pic, f));
pic_fputs(pic, pic_str(pic, str, 0), port);
break;
}
case 'c': {
int ival = va_arg(ap, int);
pic_fputc(pic, ival, port);
break;
}
case 's': {
char *sval = va_arg(ap, char*);
pic_fputs(pic, sval, port);
break;
}
case 'p': {
static const char digits[] = "0123456789abcdef";
unsigned long vp = (unsigned long) va_arg(ap, void*);
char buf[sizeof vp * CHAR_BIT / 4 + 1];
size_t i;
for (i = 0; i < sizeof buf; ++i) {
buf[sizeof buf - i - 1] = digits[vp % 16];
vp /= 16;
}
buf[i] = '\0';
pic_fputs(pic, "0x", port);
pic_fputs(pic, buf, port);
break;
}
case '%':
pic_fputc(pic, *(p-1), port);
break;
default:
pic_fputc(pic, '%', port);
pic_fputc(pic, *(p-1), port);
break;
}
continue;
}
pic_fputc(pic, *p, port);
}
return pic_fseek(pic, port, 0, PIC_SEEK_CUR) - start;
}
int
pic_fprintf(pic_state *pic, pic_value port, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = pic_vfprintf(pic, port, fmt, ap);
va_end(ap);
return n;
}
int
pic_printf(pic_state *pic, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = pic_vfprintf(pic, pic_stdout(pic), fmt, ap);
va_end(ap);
return n;
}
typedef struct { char *buf; long pos, end, capa; } xbuf_t;
static int