move pic_printf family to port.c
This commit is contained in:
parent
8592802afc
commit
01c817799b
2
Makefile
2
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)
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
131
lib/ext/write.c
131
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)
|
||||
{
|
||||
|
|
|
@ -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__)
|
||||
|
|
85
lib/number.c
85
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);
|
||||
|
|
102
lib/port.c
102
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
|
||||
|
|
Loading…
Reference in New Issue