Snippets

Takehiko NOZAKI gdtoa usage (printf %a conversion like)

Updated by Takehiko NOZAKI

File acvt.c Modified

  • Ignore whitespace
  • Hide word diff
 			fclose(fp);
 			printf("testcase:[%s], expect:[%s], result[%s]\n",
 				t[i].svalue, expect, result);
+			/* FIXME */
 			if (strcmp(result, expect))
 				abort();
 			free(expect);
Created by Takehiko NOZAKI

File acvt.c Added

  • Ignore whitespace
  • Hide word diff
+/*-
+ * Copyright (c) 2021 Takehiko NOZAKI
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+
+#if defined(__NetBSD__)
+extern char *__hdtoa(double, const char *, int, int *, int *, char **);
+extern void __freedtoa(char *);
+#define hdtoa		__hdtoa
+#define freedtoa	__freedtoa
+#include <sys/cdefs.h>
+#define arraycount(array)	__arraycount(array)
+#else
+#include "gdtoa.h"
+#define arraycount(array)       (sizeof(array)/sizeof(array[0]))
+#endif
+
+struct dtoatestcase {
+	double dvalue;
+	const char *svalue;
+};
+
+#define DTOATEST(value) { .dvalue = value, .svalue = #value }
+#define debug	printf
+
+#define DEFAULTPREC	6
+#define MAXEXPSIZ	3
+
+#define NEGATIVE	0x1
+#define SQUOTE		0x2
+#define MINUS		0x4
+#define PLUS		0x8
+#define SPACE		0x10
+#define SHARP		0x20
+#define ZERO		0x40
+#define HEX		0x80
+
+#define PADSIZ	20
+static const char zeros[PADSIZ] = "00000000000000000000";
+static const char spaces[PADSIZ] = "                    ";
+
+static inline int
+pad(const char *filler, int len, FILE *fp)
+{
+	while (len > PADSIZ) {
+		if (fwrite(filler, 1, PADSIZ, fp) != PADSIZ)
+			return 1;
+		len -= PADSIZ;
+	}
+	if (fwrite(filler, 1, len, fp) != len)
+		return 1;
+	return 0;
+}
+
+static inline int
+lpad(int sign, int width, int siz, int flags, FILE *fp)
+{
+	if (width > siz && (flags & (MINUS|ZERO)) == 0 &&
+	    pad(spaces, width - siz, fp))
+		return 1;
+	if (sign && putc(sign, fp) == EOF)
+		return 1;
+	if ((flags & HEX) && fwrite("0x", 1, 2, fp) != 2)
+		return 1;
+	if (width > siz && (flags & (MINUS|ZERO)) == ZERO &&
+	    pad(zeros, width - siz, fp))
+		return 1;
+	return 0;
+}
+
+static inline int
+rpad(int width, int siz, int flags, FILE *fp)
+{
+	if (width > siz && (flags & MINUS) &&
+	    pad(spaces, width - siz, fp))
+		return 1;
+	return 0;
+}
+
+static inline int
+cvt_sign(int flags)
+{
+	if (flags & NEGATIVE)
+		return '-';
+	else if (flags & PLUS)
+		return '+';
+	else if (flags & SPACE)
+		return ' ';
+	return '\0';
+}
+
+static inline int
+cvt_inf(int width, int flags, FILE *fp)
+{
+	int sign, siz;
+
+	sign = cvt_sign(flags);
+	siz = (sign) ? 4 : 3;
+	if (lpad(sign, width, siz, flags & ~ZERO, fp))
+		return 1;
+	if (fwrite("inf", 1, 3, fp) != 3)
+		return 1;
+	if (rpad(width, siz, flags, fp))
+		return 1;
+	return 0;
+}
+
+static inline int
+cvt_nan(int width, int flags, FILE *fp)
+{
+	if (lpad('\0', width, 3, flags & ~ZERO, fp))
+		return 1;
+	if (fwrite("nan", 1, 3, fp) != 3)
+		return 1;
+	if (rpad(width, 3, flags, fp))
+		return 1;
+	return 0;
+}
+
+static inline int
+to_char(int digit)
+{
+	return '0' + digit;
+}
+
+static inline int
+cvt_exp(int exp, FILE *fp)
+{
+	char buf[MAXEXPSIZ + 2], *expstr;
+	int sign;
+	size_t len;
+
+	if (exp >= 0) {
+		sign = '+';
+	} else {
+		sign = '-';
+		exp = -exp;
+	}
+	expstr = &buf[sizeof(buf)];
+	while (exp > 9) {
+		*--expstr = to_char(exp % 10);
+		exp /= 10;
+	}
+	*--expstr = to_char(exp);
+	*--expstr = sign;
+	*--expstr = 'p';
+	len = &buf[sizeof(buf)] - expstr;
+	if (fwrite(expstr, 1, len, fp) != len)
+		return 1;
+	return 0;
+}
+
+static inline int
+cvt_asize(int sign, int len, int prec, int exp, int flags)
+{
+	int x, s, i, f, d, p;
+
+	x = 2;
+	s = (sign) ? 1 : 0;
+	i = 1;
+	f = len - 1;
+	if (f < prec)
+		f = prec;
+	d = (f > 0 || flags & SHARP) ? 1 : 0;
+	p = 2;
+	while (exp > 9) {
+		++p;
+		exp /= 9;
+	}
+	++p;
+	return x + s + i + f + d + p;
+}
+
+static inline int
+cvt_afmt(char *head, int len, int width, int prec, int exp, int flags, FILE *fp)
+{
+	int sign, size;
+
+	sign = cvt_sign(flags);
+	size = cvt_asize(sign, len, prec, exp, flags);
+	if (lpad(sign, width, size, flags|HEX, fp))
+		return 1;
+	if (putc(*head, fp) == EOF)
+		return 1;
+	if (((flags & SHARP) || prec > 0) && putc('.', fp) == EOF)
+		return 1;
+	if (--len > 0 && fwrite(&head[1], 1, len, fp) != len)
+		return 1;
+	if (prec > len && pad(zeros, prec - len, fp))
+		return 1;
+	if (cvt_exp(exp, fp))
+		return 1;
+	if (rpad(width, size, flags, fp))
+		return 1;
+	return 0;
+}
+
+int
+acvt(double dvalue, int width, int prec, FILE *fp)
+{
+	static const char *xdigit = "0123456789abcdef";
+	int flags, exp, neg, len, ret;
+	char *head, *tail;
+
+	flags = 0;
+	if (prec >= 0)
+		++prec;
+	head = hdtoa(dvalue, xdigit, prec, &exp, &neg, &tail);
+	if (head == NULL)
+		return 1;
+	len = tail - head;
+	if (neg)
+		flags |= NEGATIVE;
+	if (exp == INT_MAX) {
+		switch (*head) {
+		case 'I':
+			ret = cvt_inf(width, flags, fp);
+			break;
+		case 'N':
+			ret = cvt_nan(width, flags, fp);
+			break;
+		default:
+			ret = 1;
+		}
+	} else {
+		if (prec < 0)
+			prec = len;
+		ret = cvt_afmt(head, len, width, prec - 1, exp - 1, flags, fp);
+	}
+	freedtoa(head);
+	return ret;
+}
+
+int
+main(int argc, char *argv[])
+{
+	static const struct dtoatestcase t[] = {
+#if defined(HAVE_MATH_H) && !defined(__vax__)
+		DTOATEST(INF),
+		DTOATEST(NAN),
+#else
+		DTOATEST(1.0/0.0),
+		DTOATEST(0.0/0.0),
+#endif
+		DTOATEST(0.0),
+		DTOATEST(1.0),
+		DTOATEST(10.0),
+		DTOATEST(100.0),
+		DTOATEST(1.1),
+		DTOATEST(1.123456789),
+		DTOATEST(11.23456789),
+		DTOATEST(112.3456789),
+		DTOATEST(1123.456789),
+		DTOATEST(11234.56789),
+		DTOATEST(112345.6789),
+		DTOATEST(1123456.789),
+		DTOATEST(11234567.89),
+		DTOATEST(112345678.9),
+		DTOATEST(1123456789.0),
+		DTOATEST(11234567890123.0),
+	};
+	size_t i, n;
+	int prec;
+	FILE *fp;
+	char *expect, *result;
+
+	for (i = 0; i < arraycount(t); ++i) {
+		for (prec = -1; prec <= 20; ++prec) {
+			expect = NULL;
+			if (asprintf(&expect, "%30.*a", prec, t[i].dvalue) < 0)
+				abort();
+			result = NULL;
+			fp = open_memstream(&result, &n);
+			if (fp == NULL)
+				abort();
+			if (acvt(t[i].dvalue, 30, prec, fp))
+				abort();
+			fclose(fp);
+			printf("testcase:[%s], expect:[%s], result[%s]\n",
+				t[i].svalue, expect, result);
+			if (strcmp(result, expect))
+				abort();
+			free(expect);
+			free(result);
+		}
+	}
+	exit(EXIT_SUCCESS);
+}
  1. 1
  2. 2
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.