blind-to-portable.c (4415B)
1 /* See LICENSE file for copyright and license details. */ 2 #define INCLUDE_UINT16 3 #include "common.h" 4 5 /* Disable warnings in <math.h> */ 6 #if defined(__clang__) 7 # pragma clang diagnostic ignored "-Wdouble-promotion" 8 # pragma clang diagnostic ignored "-Wconversion" 9 #endif 10 11 USAGE("[-s]") 12 13 static int strict = 1; 14 15 #define CONV(ITYPE, OTYPE, SOTYPE, EXPONENT, HA2EXPONENT, FRACTION)\ 16 do {\ 17 static int cache_i = 0;\ 18 static ITYPE cache_in[] = {0, 0, 0, 0};\ 19 static OTYPE cache_out[] = {0, 0, 0, 0};\ 20 OTYPE signb, fraction, ret;\ 21 SOTYPE exponent;\ 22 ITYPE u, dexponent;\ 23 if (host == cache_in[cache_i]) {\ 24 ret = cache_out[cache_i++];\ 25 cache_i &= 3;\ 26 return ret;\ 27 }\ 28 cache_in[cache_i] = host;\ 29 signb = (OTYPE)signbit(host);\ 30 u = signb ? -host : host;\ 31 if (g_isnan(host) || g_isinf(host)) {\ 32 ret = ((((OTYPE)1 << EXPONENT) - (OTYPE)1) << FRACTION) | (OTYPE)!g_isinf(host);\ 33 } else if (u == (ITYPE)0.0) {\ 34 ret = 0;\ 35 } else {\ 36 dexponent = log2(u);\ 37 exponent = (SOTYPE)dexponent;\ 38 if (u == pow((ITYPE)2.0, (ITYPE)exponent)) {\ 39 exponent += HA2EXPONENT;\ 40 fraction = 0;\ 41 } else {\ 42 /* TODO subnormals are a bit rounded off */\ 43 u *= pow((ITYPE)2.0, (ITYPE)(FRACTION + 1 - exponent));\ 44 fraction = (OTYPE)u;\ 45 while (fraction >= (OTYPE)2 << FRACTION) {\ 46 fraction >>= 1;\ 47 exponent += 1;\ 48 }\ 49 fraction &= ((OTYPE)1 << FRACTION) - 1;\ 50 exponent += HA2EXPONENT - 1;\ 51 }\ 52 if (exponent < 1) {\ 53 /* TODO subnormal result */\ 54 exponent = 0;\ 55 fraction = 0;\ 56 } else if (exponent >= ((SOTYPE)1 << EXPONENT) - 1) { \ 57 exponent = ((SOTYPE)1 << EXPONENT) - 1;\ 58 fraction = 0;\ 59 }\ 60 ret = ((OTYPE)exponent << FRACTION) + fraction;\ 61 }\ 62 ret |= signb << (FRACTION + EXPONENT);\ 63 cache_out[cache_i++] = ret;\ 64 cache_i &= 3;\ 65 return ret;\ 66 } while (0) 67 68 #define PROCESS_FLOAT(ITYPE, OTYPE, BITS)\ 69 do {\ 70 size_t i, n;\ 71 ITYPE *ibuf = (ITYPE *)(stream->buf);\ 72 OTYPE *obuf = sizeof(ITYPE) == sizeof(OTYPE) ? (OTYPE *)(stream->buf)\ 73 : alloca(sizeof(stream->buf) / sizeof(ITYPE) * sizeof(OTYPE));\ 74 strict *= !USING_BINARY##BITS;\ 75 if (!strict && sizeof(ITYPE) != sizeof(OTYPE))\ 76 eprintf("-s is supported not on this machine\n");\ 77 if (stream->endian == LITTLE && !strict) {\ 78 esend_stream(stream, STDOUT_FILENO, "<stdout>");\ 79 break;\ 80 }\ 81 do {\ 82 n = stream->ptr / sizeof(ITYPE);\ 83 if (strict) {\ 84 for (i = 0; i < n; i++)\ 85 obuf[i] = htole(conv_##ITYPE(ibuf[i]));\ 86 } else {\ 87 for (i = 0; i < n; i++)\ 88 obuf[i] = htole(*(OTYPE *)&ibuf[i]);\ 89 }\ 90 ewriteall(STDOUT_FILENO, obuf, n * sizeof(OTYPE), "<stdout>");\ 91 n *= sizeof(ITYPE);\ 92 memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ 93 } while (eread_stream(stream, SIZE_MAX));\ 94 if (stream->ptr)\ 95 eprintf("%s: incomplete frame\n", stream->file);\ 96 } while (0) 97 98 #define PROCESS_INTEGER(TYPE)\ 99 do {\ 100 size_t i, n;\ 101 TYPE *buf = (TYPE *)(stream->buf);\ 102 if (stream->endian == LITTLE) {\ 103 esend_stream(stream, STDOUT_FILENO, "<stdout>");\ 104 break;\ 105 }\ 106 do {\ 107 n = stream->ptr / sizeof(TYPE);\ 108 for (i = 0; i < n; i++)\ 109 buf[i] = htole(buf[i]);\ 110 n *= sizeof(TYPE);\ 111 ewriteall(STDOUT_FILENO, buf, n, "<stdout>");\ 112 memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ 113 } while (eread_stream(stream, SIZE_MAX));\ 114 if (stream->ptr)\ 115 eprintf("%s: incomplete frame\n", stream->file);\ 116 } while (0) 117 118 static uint64_t conv_double(double host) {CONV(double, uint64_t, int64_t, 11, 1023, 52);} 119 static uint32_t conv_float (float host) {CONV(float, uint32_t, int32_t, 8, 127, 23);} 120 121 static void process_lf (struct stream *stream) {PROCESS_FLOAT(double, uint64_t, 64);} 122 static void process_f (struct stream *stream) {PROCESS_FLOAT(float, uint32_t, 32);} 123 static void process_u16(struct stream *stream) {PROCESS_INTEGER(uint16_t);} 124 125 int 126 main(int argc, char *argv[]) 127 { 128 struct stream stream; 129 void (*process)(struct stream *stream); 130 131 ARGBEGIN { 132 case 's': 133 strict = 0; 134 break; 135 default: 136 usage(); 137 } ARGEND; 138 139 if (argc) 140 usage(); 141 142 eopen_stream(&stream, NULL); 143 #if defined(HOST_ENDIAN_IS_LITTLE_ENDIAN) 144 if (stream.endian == HOST) 145 stream.endian = LITTLE; 146 #elif defined(HOST_ENDIAN_IS_BIG_ENDIAN) 147 if (stream.endian == HOST) 148 stream.endian = BIG; 149 #endif 150 151 SELECT_PROCESS_FUNCTION(&stream); 152 fprint_stream_head(stdout, &stream); 153 efflush(stdout, "<stdout>"); 154 process(&stream); 155 return 0; 156 }