From 01c817799b5f46f22e4306967d93298738f21039 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Sun, 9 Apr 2017 23:39:24 +0900 Subject: [PATCH] move pic_printf family to port.c --- Makefile | 2 - contrib/10.roundtrip/emyg.c | 150 ++++++++++++++++++++++++++++++++++ contrib/10.roundtrip/nitro.mk | 5 +- lib/ext/write.c | 131 +---------------------------- lib/include/picrin/setup.h | 16 ++-- lib/number.c | 85 +++++++------------ lib/port.c | 102 +++++++++++++++++++++++ 7 files changed, 294 insertions(+), 197 deletions(-) create mode 100644 contrib/10.roundtrip/emyg.c diff --git a/Makefile b/Makefile index 61c5bd60..66e12e3c 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/contrib/10.roundtrip/emyg.c b/contrib/10.roundtrip/emyg.c new file mode 100644 index 00000000..ad5ebc26 --- /dev/null +++ b/contrib/10.roundtrip/emyg.c @@ -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)); +} diff --git a/contrib/10.roundtrip/nitro.mk b/contrib/10.roundtrip/nitro.mk index 942adf7c..e984dba5 100644 --- a/contrib/10.roundtrip/nitro.mk +++ b/contrib/10.roundtrip/nitro.mk @@ -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 diff --git a/lib/ext/write.c b/lib/ext/write.c index d6588f31..d5d086d1 100644 --- a/lib/ext/write.c +++ b/lib/ext/write.c @@ -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) { diff --git a/lib/include/picrin/setup.h b/lib/include/picrin/setup.h index 298f58b5..af4efa49 100644 --- a/lib/include/picrin/setup.h +++ b/lib/include/picrin/setup.h @@ -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 @@ -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__) diff --git a/lib/number.c b/lib/number.c index 3578d9ea..e7328fc0 100644 --- a/lib/number.c +++ b/lib/number.c @@ -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); diff --git a/lib/port.c b/lib/port.c index 0a7a84f3..dbb52d51 100644 --- a/lib/port.c +++ b/lib/port.c @@ -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