ruby-oci8 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +80 -0
- data/NEWS +56 -1
- data/VERSION +1 -1
- data/dist-files +3 -0
- data/ext/oci8/.document +1 -0
- data/ext/oci8/apiwrap.yml +17 -0
- data/ext/oci8/attr.c +1 -1
- data/ext/oci8/bind.c +1 -1
- data/ext/oci8/error.c +91 -2
- data/ext/oci8/extconf.rb +3 -2
- data/ext/oci8/object.c +20 -13
- data/ext/oci8/oci8.c +25 -0
- data/ext/oci8/oci8.h +12 -0
- data/ext/oci8/oci8lib.c +6 -72
- data/ext/oci8/ocidatetime.c +1 -1
- data/ext/oci8/ocihandle.c +702 -0
- data/ext/oci8/ocinumber.c +67 -71
- data/ext/oci8/oradate.c +1 -1
- data/ext/oci8/oranumber_util.c +315 -0
- data/ext/oci8/oranumber_util.h +24 -0
- data/ext/oci8/stmt.c +11 -9
- data/lib/oci8/datetime.rb +5 -1
- data/test/test_oranumber.rb +144 -1
- metadata +23 -7
data/ext/oci8/ocinumber.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "oci8.h"
|
9
9
|
#include <orl.h>
|
10
10
|
#include <errno.h>
|
11
|
+
#include "oranumber_util.h"
|
11
12
|
|
12
13
|
#ifndef RUBY_VM
|
13
14
|
/* ruby 1.8 */
|
@@ -36,26 +37,6 @@ static OCINumber const_m1; /* -1 */
|
|
36
37
|
static OCINumber const_PI2; /* +PI/2 */
|
37
38
|
static OCINumber const_mPI2; /* -PI/2 */
|
38
39
|
|
39
|
-
#define SHRESHOLD_FMT_STR "00000000000000000000000000"
|
40
|
-
#define SHRESHOLD_FMT (OraText*)SHRESHOLD_FMT_STR
|
41
|
-
#define SHRESHOLD_FMT_LEN (sizeof(SHRESHOLD_FMT_STR) - 1)
|
42
|
-
#define SHRESHOLD_VAL_STR "10000000000000000000000000"
|
43
|
-
#define SHRESHOLD_VAL (OraText*)SHRESHOLD_VAL_STR
|
44
|
-
#define SHRESHOLD_VAL_LEN (sizeof(SHRESHOLD_VAL_STR) - 1)
|
45
|
-
static OCINumber const_shreshold;
|
46
|
-
|
47
|
-
/* TODO: scale: -84 - 127 */
|
48
|
-
#define NUMBER_FORMAT1_STR "FM9999999999999999999999990.9999999999999999999999999999999999999"
|
49
|
-
#define NUMBER_FORMAT1 (OraText*)NUMBER_FORMAT1_STR
|
50
|
-
#define NUMBER_FORMAT1_LEN (sizeof(NUMBER_FORMAT1_STR) - 1)
|
51
|
-
#define NUMBER_FORMAT2_STR "FM99999999999999999999999999999999999990.999999999999999999999999"
|
52
|
-
#define NUMBER_FORMAT2 (OraText*)NUMBER_FORMAT2_STR
|
53
|
-
#define NUMBER_FORMAT2_LEN (sizeof(NUMBER_FORMAT2_STR) - 1)
|
54
|
-
#define NUMBER_FORMAT2_DECIMAL (sizeof("999999999999999999999999") - 1)
|
55
|
-
#define NUMBER_FORMAT_INT_STR "FM99999999999999999999999999999999999990"
|
56
|
-
#define NUMBER_FORMAT_INT (OraText*)NUMBER_FORMAT_INT_STR
|
57
|
-
#define NUMBER_FORMAT_INT_LEN (sizeof(NUMBER_FORMAT_INT_STR) - 1)
|
58
|
-
|
59
40
|
#define _NUMBER(val) ((OCINumber *)DATA_PTR(val)) /* dangerous macro */
|
60
41
|
|
61
42
|
#define RBOCI8_T_ORANUMBER (T_MASK + 1)
|
@@ -109,6 +90,7 @@ static int rboci8_type(VALUE obj)
|
|
109
90
|
static VALUE onum_to_f(VALUE self);
|
110
91
|
static VALUE onum_to_r(VALUE self);
|
111
92
|
static VALUE onum_to_d(VALUE self);
|
93
|
+
static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp);
|
112
94
|
|
113
95
|
static VALUE onum_s_alloc(VALUE klass)
|
114
96
|
{
|
@@ -135,14 +117,18 @@ VALUE oci8_make_integer(OCINumber *s, OCIError *errhp)
|
|
135
117
|
{
|
136
118
|
signed long sl;
|
137
119
|
char buf[512];
|
138
|
-
|
120
|
+
sword rv;
|
139
121
|
|
140
122
|
if (OCINumberToInt(errhp, s, sizeof(sl), OCI_NUMBER_SIGNED, &sl) == OCI_SUCCESS) {
|
141
123
|
return LONG2NUM(sl);
|
142
124
|
}
|
143
|
-
|
144
|
-
|
145
|
-
|
125
|
+
/* convert to Integer via String */
|
126
|
+
rv = oranumber_to_str(s, buf, sizeof(buf));
|
127
|
+
if (rv > 0) {
|
128
|
+
return rb_cstr2inum(buf, 10);
|
129
|
+
}
|
130
|
+
oranumber_dump(s, buf);
|
131
|
+
rb_raise(eOCIException, "Invalid internal number format: %s", buf);
|
146
132
|
}
|
147
133
|
|
148
134
|
VALUE oci8_make_float(OCINumber *s, OCIError *errhp)
|
@@ -164,29 +150,25 @@ static void set_oci_number_from_str(OCINumber *result, VALUE str, VALUE fmt, VAL
|
|
164
150
|
StringValue(str);
|
165
151
|
/* set from string. */
|
166
152
|
if (NIL_P(fmt)) {
|
167
|
-
int
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
153
|
+
int rv = oranumber_from_str(result, RSTRING_PTR(str), RSTRING_LEN(str));
|
154
|
+
if (rv == ORANUMBER_SUCCESS) {
|
155
|
+
return; /* success */
|
156
|
+
} else {
|
157
|
+
const char *default_msg = NULL;
|
158
|
+
switch (rv) {
|
159
|
+
case ORANUMBER_INVALID_NUMBER:
|
160
|
+
default_msg = "invalid number";
|
161
|
+
break;
|
162
|
+
case ORANUMBER_NUMERIC_OVERFLOW:
|
163
|
+
default_msg = "numeric overflow";
|
173
164
|
break;
|
174
165
|
}
|
166
|
+
oci8_raise_by_msgno(rv, default_msg);
|
175
167
|
}
|
176
|
-
if (i == -1)
|
177
|
-
cnt = 0;
|
178
|
-
if (cnt <= NUMBER_FORMAT2_DECIMAL) {
|
179
|
-
fmt_ptr = NUMBER_FORMAT2;
|
180
|
-
fmt_len = NUMBER_FORMAT2_LEN;
|
181
|
-
} else {
|
182
|
-
fmt_ptr = NUMBER_FORMAT1;
|
183
|
-
fmt_len = NUMBER_FORMAT1_LEN;
|
184
|
-
}
|
185
|
-
} else {
|
186
|
-
StringValue(fmt);
|
187
|
-
fmt_ptr = RSTRING_ORATEXT(fmt);
|
188
|
-
fmt_len = RSTRING_LEN(fmt);
|
189
168
|
}
|
169
|
+
StringValue(fmt);
|
170
|
+
fmt_ptr = RSTRING_ORATEXT(fmt);
|
171
|
+
fmt_len = RSTRING_LEN(fmt);
|
190
172
|
if (NIL_P(nls_params)) {
|
191
173
|
nls_params_ptr = NULL;
|
192
174
|
nls_params_len = 0;
|
@@ -1053,30 +1035,16 @@ static VALUE onum_to_char(int argc, VALUE *argv, VALUE self)
|
|
1053
1035
|
|
1054
1036
|
rb_scan_args(argc, argv, "02", &fmt /* nil */, &nls_params /* nil */);
|
1055
1037
|
if (NIL_P(fmt)) {
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
oci_lc(OCINumberIsInt(errhp, _NUMBER(self), &is_int));
|
1061
|
-
if (is_int) {
|
1062
|
-
fmt_ptr = NUMBER_FORMAT_INT;
|
1063
|
-
fmt_len = NUMBER_FORMAT_INT_LEN;
|
1064
|
-
} else {
|
1065
|
-
oci_lc(OCINumberAbs(errhp, _NUMBER(self), &absval));
|
1066
|
-
oci_lc(OCINumberCmp(errhp, &absval, &const_shreshold, &sign));
|
1067
|
-
if (sign >= 0) {
|
1068
|
-
fmt_ptr = NUMBER_FORMAT2;
|
1069
|
-
fmt_len = NUMBER_FORMAT2_LEN;
|
1070
|
-
} else {
|
1071
|
-
fmt_ptr = NUMBER_FORMAT1;
|
1072
|
-
fmt_len = NUMBER_FORMAT1_LEN;
|
1073
|
-
}
|
1038
|
+
rv = oranumber_to_str(_NUMBER(self), buf, sizeof(buf));
|
1039
|
+
if (rv > 0) {
|
1040
|
+
return rb_usascii_str_new(buf, rv);
|
1074
1041
|
}
|
1075
|
-
|
1076
|
-
|
1077
|
-
fmt_ptr = RSTRING_ORATEXT(fmt);
|
1078
|
-
fmt_len = RSTRING_LEN(fmt);
|
1042
|
+
oranumber_dump(_NUMBER(self), buf);
|
1043
|
+
rb_raise(eOCIException, "Invalid internal number format: %s", buf);
|
1079
1044
|
}
|
1045
|
+
StringValue(fmt);
|
1046
|
+
fmt_ptr = RSTRING_ORATEXT(fmt);
|
1047
|
+
fmt_len = RSTRING_LEN(fmt);
|
1080
1048
|
if (NIL_P(nls_params)) {
|
1081
1049
|
nls_params_ptr = NULL;
|
1082
1050
|
nls_params_len = 0;
|
@@ -1195,11 +1163,23 @@ static VALUE onum_to_r(VALUE self)
|
|
1195
1163
|
*/
|
1196
1164
|
static VALUE onum_to_d(VALUE self)
|
1197
1165
|
{
|
1166
|
+
return onum_to_d_real(_NUMBER(self), oci8_errhp);
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
/* Converts to BigDecimal via number in scientific notation */
|
1170
|
+
static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp)
|
1171
|
+
{
|
1172
|
+
char buf[64];
|
1173
|
+
ub4 buf_size = sizeof(buf);
|
1174
|
+
const const char *fmt = "FM9.99999999999999999999999999999999999999EEEE";
|
1175
|
+
|
1198
1176
|
if (!cBigDecimal) {
|
1199
1177
|
rb_require("bigdecimal");
|
1200
1178
|
cBigDecimal = rb_const_get(rb_cObject, id_BigDecimal);
|
1201
1179
|
}
|
1202
|
-
|
1180
|
+
oci_lc(OCINumberToText(errhp, num, (const oratext *)fmt, strlen(fmt),
|
1181
|
+
NULL, 0, &buf_size, TO_ORATEXT(buf)));
|
1182
|
+
return rb_funcall(rb_cObject, id_BigDecimal, 1, rb_usascii_str_new(buf, buf_size));
|
1203
1183
|
}
|
1204
1184
|
|
1205
1185
|
/*
|
@@ -1262,6 +1242,24 @@ static VALUE onum_shift(VALUE self, VALUE exp)
|
|
1262
1242
|
return oci8_make_ocinumber(&result, errhp);
|
1263
1243
|
}
|
1264
1244
|
|
1245
|
+
/*
|
1246
|
+
* call-seq:
|
1247
|
+
* onum.dump -> string
|
1248
|
+
*
|
1249
|
+
* Returns internal representation whose format is same with
|
1250
|
+
* the return value of Oracle SQL function DUMP().
|
1251
|
+
*
|
1252
|
+
* OraNumber.new(100).dump #=> "Typ=2 Len=2: 194,2"
|
1253
|
+
* OraNumber.new(123).dump #=> "Typ=2 Len=3: 194,2,24"
|
1254
|
+
* OraNumber.new(0.1).dump #=> "Typ=2 Len=2: 192,11"
|
1255
|
+
*/
|
1256
|
+
static VALUE onum_dump(VALUE self)
|
1257
|
+
{
|
1258
|
+
char buf[ORANUMBER_DUMP_BUF_SIZ];
|
1259
|
+
int rv = oranumber_dump(_NUMBER(self), buf);
|
1260
|
+
return rb_usascii_str_new(buf, rv);
|
1261
|
+
}
|
1262
|
+
|
1265
1263
|
static VALUE onum_hash(VALUE self)
|
1266
1264
|
{
|
1267
1265
|
char *c = DATA_PTR(self);
|
@@ -1297,7 +1295,7 @@ static VALUE onum_inspect(VALUE self)
|
|
1297
1295
|
*
|
1298
1296
|
* Dump <i>onum</i> for marshaling.
|
1299
1297
|
*/
|
1300
|
-
static VALUE
|
1298
|
+
static VALUE onum__dump(int argc, VALUE *argv, VALUE self)
|
1301
1299
|
{
|
1302
1300
|
char *c = DATA_PTR(self);
|
1303
1301
|
int size = c[0] + 1;
|
@@ -1443,9 +1441,6 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
|
|
1443
1441
|
OCINumberDiv(errhp, &num1 /* PI */, &num2 /* 2 */, &const_PI2);
|
1444
1442
|
/* set const_mPI2 */
|
1445
1443
|
OCINumberNeg(errhp, &const_PI2 /* PI/2 */, &const_mPI2);
|
1446
|
-
/* set const_shreshold */
|
1447
|
-
OCINumberFromText(errhp, SHRESHOLD_VAL, SHRESHOLD_VAL_LEN, SHRESHOLD_FMT, SHRESHOLD_FMT_LEN,
|
1448
|
-
NULL, 0, &const_shreshold);
|
1449
1444
|
|
1450
1445
|
/* PI */
|
1451
1446
|
OCINumberSetPi(errhp, &num1);
|
@@ -1516,12 +1511,13 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
|
|
1516
1511
|
if (have_OCINumberShift) {
|
1517
1512
|
rb_define_method(cOCINumber, "shift", onum_shift, 1);
|
1518
1513
|
}
|
1514
|
+
rb_define_method(cOCINumber, "dump", onum_dump, 0);
|
1519
1515
|
|
1520
1516
|
rb_define_method_nodoc(cOCINumber, "hash", onum_hash, 0);
|
1521
1517
|
rb_define_method_nodoc(cOCINumber, "inspect", onum_inspect, 0);
|
1522
1518
|
|
1523
1519
|
/* methods for marshaling */
|
1524
|
-
rb_define_method(cOCINumber, "_dump",
|
1520
|
+
rb_define_method(cOCINumber, "_dump", onum__dump, -1);
|
1525
1521
|
rb_define_singleton_method(cOCINumber, "_load", onum_s_load, 1);
|
1526
1522
|
|
1527
1523
|
oci8_define_bind_class("OraNumber", &bind_ocinumber_class);
|
data/ext/oci8/oradate.c
CHANGED
@@ -0,0 +1,315 @@
|
|
1
|
+
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include "oranumber_util.h"
|
5
|
+
|
6
|
+
int oranumber_to_str(const OCINumber *on, char *buf, int buflen)
|
7
|
+
{
|
8
|
+
signed char exponent;
|
9
|
+
signed char mantissa[21]; /* terminated by a negative number */
|
10
|
+
int datalen = on->OCINumberPart[0];
|
11
|
+
int len = 0;
|
12
|
+
int idx;
|
13
|
+
int n;
|
14
|
+
#define PUTC(chr) do { \
|
15
|
+
if (len < buflen) { \
|
16
|
+
buf[len++] = (chr); \
|
17
|
+
} else { \
|
18
|
+
return ORANUMBER_TOO_SHORT_BUFFER; \
|
19
|
+
} \
|
20
|
+
} while(0)
|
21
|
+
#define PUTEND() do { \
|
22
|
+
if (len < buflen) { \
|
23
|
+
buf[len] = '\0'; \
|
24
|
+
} else { \
|
25
|
+
return ORANUMBER_TOO_SHORT_BUFFER; \
|
26
|
+
} \
|
27
|
+
} while(0)
|
28
|
+
|
29
|
+
if (datalen == 0) {
|
30
|
+
/* too short */
|
31
|
+
return -1;
|
32
|
+
}
|
33
|
+
if (datalen == 1) {
|
34
|
+
if (on->OCINumberPart[1] == 0x80) {
|
35
|
+
/* zero */
|
36
|
+
PUTC('0');
|
37
|
+
PUTEND();
|
38
|
+
return 1;
|
39
|
+
}
|
40
|
+
/* unexpected format */
|
41
|
+
return -1;
|
42
|
+
}
|
43
|
+
if (datalen > 21) {
|
44
|
+
/* too long */
|
45
|
+
return -1;
|
46
|
+
}
|
47
|
+
/* normalize exponent and mantissa */
|
48
|
+
if (on->OCINumberPart[1] >= 128) {
|
49
|
+
/* positive number */
|
50
|
+
exponent = on->OCINumberPart[1] - 193;
|
51
|
+
for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
|
52
|
+
mantissa[idx] = on->OCINumberPart[idx + 2] - 1;
|
53
|
+
}
|
54
|
+
mantissa[idx] = -1;
|
55
|
+
} else {
|
56
|
+
/* negative number */
|
57
|
+
exponent = 62 - on->OCINumberPart[1];
|
58
|
+
for (idx = 0; idx < on->OCINumberPart[0] - 1; idx++) {
|
59
|
+
mantissa[idx] = 101 - on->OCINumberPart[idx + 2];
|
60
|
+
}
|
61
|
+
mantissa[idx] = -1;
|
62
|
+
PUTC('-');
|
63
|
+
}
|
64
|
+
/* convert exponent and mantissa to human readable number */
|
65
|
+
idx = 0;
|
66
|
+
if (exponent-- >= 0) {
|
67
|
+
/* integer part */
|
68
|
+
n = mantissa[idx++];
|
69
|
+
if (n / 10 != 0) {
|
70
|
+
PUTC(n / 10 + '0');
|
71
|
+
}
|
72
|
+
PUTC(n % 10 + '0');
|
73
|
+
while (exponent-- >= 0) {
|
74
|
+
n = mantissa[idx++];
|
75
|
+
if (n < 0) {
|
76
|
+
do {
|
77
|
+
PUTC('0');
|
78
|
+
PUTC('0');
|
79
|
+
} while (exponent-- >= 0);
|
80
|
+
PUTEND();
|
81
|
+
return len;
|
82
|
+
}
|
83
|
+
PUTC(n / 10 + '0');
|
84
|
+
PUTC(n % 10 + '0');
|
85
|
+
}
|
86
|
+
if (mantissa[idx] < 0) {
|
87
|
+
PUTEND();
|
88
|
+
return len;
|
89
|
+
}
|
90
|
+
} else {
|
91
|
+
PUTC('0');
|
92
|
+
}
|
93
|
+
PUTC('.');
|
94
|
+
/* fractional number part */
|
95
|
+
while (++exponent < -1) {
|
96
|
+
PUTC('0');
|
97
|
+
PUTC('0');
|
98
|
+
}
|
99
|
+
while ((n = mantissa[idx++]) >= 0) {
|
100
|
+
PUTC(n / 10 + '0');
|
101
|
+
PUTC(n % 10 + '0');
|
102
|
+
}
|
103
|
+
if (buf[len - 1] == '0') {
|
104
|
+
len--;
|
105
|
+
}
|
106
|
+
PUTEND();
|
107
|
+
return len;
|
108
|
+
}
|
109
|
+
|
110
|
+
int oranumber_from_str(OCINumber *on, const char *buf, int buflen)
|
111
|
+
{
|
112
|
+
const char *end;
|
113
|
+
int is_positive = 1;
|
114
|
+
char mantissa[41];
|
115
|
+
int dec_point;
|
116
|
+
long exponent = 0;
|
117
|
+
int idx = 0;
|
118
|
+
int i;
|
119
|
+
|
120
|
+
if (buflen < 0) {
|
121
|
+
end = buf + strlen(buf);
|
122
|
+
} else {
|
123
|
+
end = buf + buflen;
|
124
|
+
}
|
125
|
+
|
126
|
+
/* skip leading spaces */
|
127
|
+
while (buf < end && *buf == ' ') {
|
128
|
+
buf++;
|
129
|
+
}
|
130
|
+
if (buf == end) {
|
131
|
+
return ORANUMBER_INVALID_NUMBER;
|
132
|
+
}
|
133
|
+
/* read a sign mark */
|
134
|
+
if (*buf == '+') {
|
135
|
+
buf++;
|
136
|
+
} else if (*buf == '-') {
|
137
|
+
buf++;
|
138
|
+
is_positive = 0;
|
139
|
+
}
|
140
|
+
/* next should be number or a dot */
|
141
|
+
if ((*buf < '0' || '9' < *buf) && *buf != '.') {
|
142
|
+
return ORANUMBER_INVALID_NUMBER;
|
143
|
+
}
|
144
|
+
/* skip leading zeros */
|
145
|
+
while (buf < end) {
|
146
|
+
if (*buf == '0') {
|
147
|
+
buf++;
|
148
|
+
} else {
|
149
|
+
break;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
/* read integer part */
|
153
|
+
while (buf < end) {
|
154
|
+
if ('0' <= *buf && *buf <= '9') {
|
155
|
+
if (idx < 41) {
|
156
|
+
mantissa[idx] = *buf - '0';
|
157
|
+
}
|
158
|
+
idx++;
|
159
|
+
} else if (*buf == '.' || *buf == 'E' || *buf == 'e' || *buf == ' ') {
|
160
|
+
break;
|
161
|
+
} else {
|
162
|
+
return ORANUMBER_INVALID_NUMBER;
|
163
|
+
}
|
164
|
+
buf++;
|
165
|
+
}
|
166
|
+
dec_point = idx;
|
167
|
+
/* read fractional part */
|
168
|
+
if (buf < end && *buf == '.') {
|
169
|
+
buf++;
|
170
|
+
if (idx == 0) {
|
171
|
+
/* skip leading zeros */
|
172
|
+
while (buf < end) {
|
173
|
+
if (*buf == '0') {
|
174
|
+
dec_point--;
|
175
|
+
buf++;
|
176
|
+
} else {
|
177
|
+
break;
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
while (buf < end) {
|
182
|
+
if ('0' <= *buf && *buf <= '9') {
|
183
|
+
if (idx < 41) {
|
184
|
+
mantissa[idx++] = *buf - '0';
|
185
|
+
}
|
186
|
+
} else if (*buf == 'E' || *buf == 'e' || *buf == ' ') {
|
187
|
+
break;
|
188
|
+
} else {
|
189
|
+
return ORANUMBER_INVALID_NUMBER;
|
190
|
+
}
|
191
|
+
buf++;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
/* read exponent part */
|
195
|
+
if (buf < end && (*buf == 'E' || *buf == 'e')) {
|
196
|
+
int negate = 0;
|
197
|
+
buf++;
|
198
|
+
if (buf < end) {
|
199
|
+
if (*buf == '+') {
|
200
|
+
buf++;
|
201
|
+
} else if (*buf == '-') {
|
202
|
+
buf++;
|
203
|
+
negate = 1;
|
204
|
+
}
|
205
|
+
}
|
206
|
+
while (buf < end) {
|
207
|
+
if ('0' <= *buf && *buf <= '9') {
|
208
|
+
exponent *= 10;
|
209
|
+
exponent += *buf - '0';
|
210
|
+
} else if (*buf == ' ') {
|
211
|
+
break;
|
212
|
+
} else {
|
213
|
+
return ORANUMBER_INVALID_NUMBER;
|
214
|
+
}
|
215
|
+
buf++;
|
216
|
+
}
|
217
|
+
if (negate) {
|
218
|
+
exponent = -exponent;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
/* skip trailing spaces */
|
222
|
+
while (buf < end && *buf == ' ') {
|
223
|
+
buf++;
|
224
|
+
}
|
225
|
+
/* final format check */
|
226
|
+
if (buf != end) {
|
227
|
+
return ORANUMBER_INVALID_NUMBER;
|
228
|
+
}
|
229
|
+
/* determine exponent */
|
230
|
+
exponent += dec_point - 1;
|
231
|
+
if (exponent % 2 == 0) {
|
232
|
+
memmove(mantissa + 1, mantissa, 40);
|
233
|
+
mantissa[0] = 0;
|
234
|
+
idx++;
|
235
|
+
}
|
236
|
+
/* round if needed */
|
237
|
+
if (idx > 40) {
|
238
|
+
idx = 40;
|
239
|
+
if (mantissa[40] >= 5) {
|
240
|
+
/* round up */
|
241
|
+
for (i = 39; i >= 0; i--) {
|
242
|
+
mantissa[i]++;
|
243
|
+
if (mantissa[i] == 10) {
|
244
|
+
mantissa[i] = 0;
|
245
|
+
} else {
|
246
|
+
break;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
if (i == -1) {
|
250
|
+
/* all figures are rounded up. */
|
251
|
+
mantissa[0] = 0;
|
252
|
+
mantissa[1] = 1;
|
253
|
+
idx = 2;
|
254
|
+
exponent++;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
}
|
258
|
+
/* shrink mantissa scale */
|
259
|
+
while (idx > 0 && mantissa[idx - 1] == 0) {
|
260
|
+
idx--;
|
261
|
+
}
|
262
|
+
/* check zero or underflow */
|
263
|
+
if (idx == 0 || exponent < -130) {
|
264
|
+
on->OCINumberPart[0] = 1;
|
265
|
+
on->OCINumberPart[1] = 0x80;
|
266
|
+
return ORANUMBER_SUCCESS;
|
267
|
+
}
|
268
|
+
/* check overflow */
|
269
|
+
if (exponent > 125) {
|
270
|
+
return ORANUMBER_NUMERIC_OVERFLOW;
|
271
|
+
}
|
272
|
+
/* change the base number from 10 to 100 */
|
273
|
+
if (idx % 2 == 1) {
|
274
|
+
mantissa[idx++] = 0;
|
275
|
+
}
|
276
|
+
idx /= 2;
|
277
|
+
for (i = 0; i < idx; i++) {
|
278
|
+
mantissa[i] = mantissa[i * 2] * 10 + mantissa[i * 2 + 1];
|
279
|
+
}
|
280
|
+
/* add negative value's terminator */
|
281
|
+
if (!is_positive && idx < 20) {
|
282
|
+
mantissa[idx++] = -1;
|
283
|
+
}
|
284
|
+
/* construct OCINumber */
|
285
|
+
on->OCINumberPart[0] = 1 + idx;
|
286
|
+
if (is_positive) {
|
287
|
+
on->OCINumberPart[1] = (exponent >> 1) + 193;
|
288
|
+
for (i = 0; i < idx; i++) {
|
289
|
+
on->OCINumberPart[i + 2] = mantissa[i] + 1;
|
290
|
+
}
|
291
|
+
} else {
|
292
|
+
on->OCINumberPart[1] = 62 - (exponent >> 1);
|
293
|
+
for (i = 0; i < idx; i++) {
|
294
|
+
on->OCINumberPart[i + 2] = 101 - mantissa[i];
|
295
|
+
}
|
296
|
+
}
|
297
|
+
return ORANUMBER_SUCCESS;
|
298
|
+
}
|
299
|
+
|
300
|
+
int oranumber_dump(const OCINumber *on, char *buf)
|
301
|
+
{
|
302
|
+
int idx;
|
303
|
+
int len = on->OCINumberPart[0];
|
304
|
+
int offset;
|
305
|
+
|
306
|
+
offset = sprintf(buf, "Typ=2 Len=%u: ", len);
|
307
|
+
if (len > 21) {
|
308
|
+
len = 21;
|
309
|
+
}
|
310
|
+
for (idx = 1; idx <= len; idx++) {
|
311
|
+
offset += sprintf(buf + offset, "%hhu,", on->OCINumberPart[idx]);
|
312
|
+
}
|
313
|
+
buf[--offset] = '\0';
|
314
|
+
return offset;
|
315
|
+
}
|