| 1 | /* | 
|---|
| 2 | * This Source Code Form is subject to the terms of the Mozilla Public | 
|---|
| 3 | * License, v. 2.0.  If a copy of the MPL was not distributed with this | 
|---|
| 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
|---|
| 5 | * | 
|---|
| 6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. | 
|---|
| 7 | */ | 
|---|
| 8 |  | 
|---|
| 9 | /* | 
|---|
| 10 | * @a M. L. Kersten, P. Boncz | 
|---|
| 11 | * @* Atomic types | 
|---|
| 12 | * The Binary Association Table library assumes efficient | 
|---|
| 13 | * implementation of the atoms making up the binary association.  This | 
|---|
| 14 | * section describes the preliminaries for handling both built-in and | 
|---|
| 15 | * user-defined atomic types. | 
|---|
| 16 | * New types, such as point and polygons, can be readily added to this | 
|---|
| 17 | * collection. | 
|---|
| 18 | */ | 
|---|
| 19 | /* | 
|---|
| 20 | * @- inline comparison routines | 
|---|
| 21 | * Return 0 on l==r, < 0 iff l < r, >0 iff l > r | 
|---|
| 22 | */ | 
|---|
| 23 | #include "monetdb_config.h" | 
|---|
| 24 | #include "gdk.h" | 
|---|
| 25 | #include "gdk_private.h" | 
|---|
| 26 | #include <math.h> | 
|---|
| 27 |  | 
|---|
| 28 | /* the *Cmp functions return a value less than zero if the first | 
|---|
| 29 | * argument is less than the second; they return zero if the two | 
|---|
| 30 | * values are equal; and they return a value greater than zero if the | 
|---|
| 31 | * first argument is greater than the second.  Remember that in all | 
|---|
| 32 | * cases, nil is considered smaller than any other value and nil is | 
|---|
| 33 | * equal to itself (this has repercussions for the floating point | 
|---|
| 34 | * implementation if and when its NIL value is the floating point | 
|---|
| 35 | * NaN). */ | 
|---|
| 36 |  | 
|---|
| 37 | static int | 
|---|
| 38 | bteCmp(const bte *l, const bte *r) | 
|---|
| 39 | { | 
|---|
| 40 | return (*l > *r) - (*l < *r); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | static int | 
|---|
| 44 | shtCmp(const sht *l, const sht *r) | 
|---|
| 45 | { | 
|---|
| 46 | return (*l > *r) - (*l < *r); | 
|---|
| 47 | } | 
|---|
| 48 |  | 
|---|
| 49 | static int | 
|---|
| 50 | intCmp(const int *l, const int *r) | 
|---|
| 51 | { | 
|---|
| 52 | return (*l > *r) - (*l < *r); | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | static int | 
|---|
| 56 | fltCmp(const flt *l, const flt *r) | 
|---|
| 57 | { | 
|---|
| 58 | return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r); | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | static int | 
|---|
| 62 | lngCmp(const lng *l, const lng *r) | 
|---|
| 63 | { | 
|---|
| 64 | return (*l > *r) - (*l < *r); | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | #ifdef HAVE_HGE | 
|---|
| 68 | static int | 
|---|
| 69 | hgeCmp(const hge *l, const hge *r) | 
|---|
| 70 | { | 
|---|
| 71 | return (*l > *r) - (*l < *r); | 
|---|
| 72 | } | 
|---|
| 73 | #endif | 
|---|
| 74 |  | 
|---|
| 75 | static int | 
|---|
| 76 | dblCmp(const dbl *l, const dbl *r) | 
|---|
| 77 | { | 
|---|
| 78 | return is_dbl_nil(*l) ? -!is_dbl_nil(*r) : is_dbl_nil(*r) ? 1 : (*l > *r) - (*l < *r); | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | /* | 
|---|
| 82 | * @- inline hash routines | 
|---|
| 83 | * Return some positive integer derived from one atom value. | 
|---|
| 84 | */ | 
|---|
| 85 | static BUN | 
|---|
| 86 | bteHash(const bte *v) | 
|---|
| 87 | { | 
|---|
| 88 | return (BUN) mix_bte(*(const unsigned char *) v); | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | static BUN | 
|---|
| 92 | shtHash(const sht *v) | 
|---|
| 93 | { | 
|---|
| 94 | return (BUN) mix_sht(*(const unsigned short *) v); | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | static BUN | 
|---|
| 98 | intHash(const int *v) | 
|---|
| 99 | { | 
|---|
| 100 | return (BUN) mix_int(*(const unsigned int *) v); | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 | static BUN | 
|---|
| 104 | lngHash(const lng *v) | 
|---|
| 105 | { | 
|---|
| 106 | return (BUN) mix_lng(*(const ulng *) v); | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | #ifdef HAVE_HGE | 
|---|
| 110 | static BUN | 
|---|
| 111 | hgeHash(const hge *v) | 
|---|
| 112 | { | 
|---|
| 113 | return (BUN) mix_hge(*(const uhge *) v); | 
|---|
| 114 | } | 
|---|
| 115 | #endif | 
|---|
| 116 |  | 
|---|
| 117 | /* | 
|---|
| 118 | * @+ Standard Atoms | 
|---|
| 119 | */ | 
|---|
| 120 | static int | 
|---|
| 121 | batFix(const bat *b) | 
|---|
| 122 | { | 
|---|
| 123 | return BBPretain(*b); | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | static int | 
|---|
| 127 | batUnfix(const bat *b) | 
|---|
| 128 | { | 
|---|
| 129 | return BBPrelease(*b); | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | /* | 
|---|
| 133 | * @+ Atomic Type Interface | 
|---|
| 134 | * The collection of built-in types supported for BATs can be extended | 
|---|
| 135 | * easily.  In essence, the user should specify conversion routines | 
|---|
| 136 | * from values stored anywhere in memory to its equivalent in the BAT, | 
|---|
| 137 | * and vice verse.  Some routines are required for coercion and to | 
|---|
| 138 | * support the BAT administration. | 
|---|
| 139 | * | 
|---|
| 140 | * A new type is incrementally build using the routine | 
|---|
| 141 | * ATOMallocate(id).  The parameter id denotes the type name; an entry | 
|---|
| 142 | * is created if the type is so far unknown. | 
|---|
| 143 | * | 
|---|
| 144 | * The size describes the amount of space to be reserved in the BUN. | 
|---|
| 145 | * | 
|---|
| 146 | * The routine put takes a pointer to a memory resident copy and | 
|---|
| 147 | * prepares a persistent copy in the BAT passed.  The inverse | 
|---|
| 148 | * operation is get.  A new value can be directly included into the | 
|---|
| 149 | * BAT using new, which should prepare a null-value representation.  A | 
|---|
| 150 | * value is removed from the BAT store using del, which can take care | 
|---|
| 151 | * of garbage collection and BAT administration. | 
|---|
| 152 | * | 
|---|
| 153 | * The pair tostr and fromstr should convert a reference to a | 
|---|
| 154 | * persistent value to a memory resident string equivalent. FromStr | 
|---|
| 155 | * takes a string and applies a put to store it within a BAT.  They | 
|---|
| 156 | * are used to prepare for readable output/input and to support | 
|---|
| 157 | * coercion. | 
|---|
| 158 | * | 
|---|
| 159 | * The routines cmp and eq are comparison routines used to build | 
|---|
| 160 | * access structures. The null returns a reference to a null value | 
|---|
| 161 | * representation. | 
|---|
| 162 | * | 
|---|
| 163 | * The incremental atom construction uses hardwired properties.  This | 
|---|
| 164 | * should be improved later on. | 
|---|
| 165 | */ | 
|---|
| 166 | int | 
|---|
| 167 | ATOMallocate(const char *id) | 
|---|
| 168 | { | 
|---|
| 169 | int t; | 
|---|
| 170 |  | 
|---|
| 171 | if (strlen(id) >= IDLENGTH) { | 
|---|
| 172 | GDKerror( "ATOMallocate: name too long"); | 
|---|
| 173 | return int_nil; | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | MT_lock_set(&GDKthreadLock); | 
|---|
| 177 | t = ATOMindex(id); | 
|---|
| 178 | if (t < 0) { | 
|---|
| 179 | t = -t; | 
|---|
| 180 | if (t == GDKatomcnt) { | 
|---|
| 181 | if (GDKatomcnt == MAXATOMS) { | 
|---|
| 182 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 183 | GDKerror( "ATOMallocate: too many types"); | 
|---|
| 184 | return int_nil; | 
|---|
| 185 | } | 
|---|
| 186 | GDKatomcnt++; | 
|---|
| 187 | } | 
|---|
| 188 | BATatoms[t] = (atomDesc) { | 
|---|
| 189 | .size = sizeof(int),	/* default */ | 
|---|
| 190 | .linear = true,		/* default */ | 
|---|
| 191 | .storage = t,		/* default */ | 
|---|
| 192 | }; | 
|---|
| 193 | strcpy(BATatoms[t].name, id); | 
|---|
| 194 | } | 
|---|
| 195 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 196 | return t; | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | int | 
|---|
| 200 | ATOMindex(const char *nme) | 
|---|
| 201 | { | 
|---|
| 202 | int t, j = GDKatomcnt; | 
|---|
| 203 |  | 
|---|
| 204 | for (t = 0; t < GDKatomcnt; t++) { | 
|---|
| 205 | if (!BATatoms[t].name[0]) { | 
|---|
| 206 | if (j == GDKatomcnt) | 
|---|
| 207 | j = t; | 
|---|
| 208 | } else if (strcmp(nme, BATatoms[t].name) == 0) { | 
|---|
| 209 | return t; | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|
| 212 | } | 
|---|
| 213 | if (strcmp(nme, "bat") == 0) { | 
|---|
| 214 | return TYPE_bat; | 
|---|
| 215 | } | 
|---|
| 216 | return -j; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | char * | 
|---|
| 220 | ATOMname(int t) | 
|---|
| 221 | { | 
|---|
| 222 | return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null"; | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 | bool | 
|---|
| 226 | ATOMisdescendant(int tpe, int parent) | 
|---|
| 227 | { | 
|---|
| 228 | int cur = -1; | 
|---|
| 229 |  | 
|---|
| 230 | while (cur != tpe) { | 
|---|
| 231 | cur = tpe; | 
|---|
| 232 | if (cur == parent) | 
|---|
| 233 | return true; | 
|---|
| 234 | tpe = ATOMstorage(tpe); | 
|---|
| 235 | } | 
|---|
| 236 | return false; | 
|---|
| 237 | } | 
|---|
| 238 |  | 
|---|
| 239 |  | 
|---|
| 240 | const bte bte_nil = GDK_bte_min-1; | 
|---|
| 241 | const sht sht_nil = GDK_sht_min-1; | 
|---|
| 242 | const int int_nil = GDK_int_min-1; | 
|---|
| 243 | #ifdef NAN_CANNOT_BE_USED_AS_INITIALIZER | 
|---|
| 244 | /* Definition of NAN is seriously broken on Intel compiler (at least | 
|---|
| 245 | * in some versions), so we work around it. */ | 
|---|
| 246 | const union _flt_nil_t _flt_nil_ = { | 
|---|
| 247 | .l = UINT32_C(0x7FC00000) | 
|---|
| 248 | }; | 
|---|
| 249 | const union _dbl_nil_t _dbl_nil_ = { | 
|---|
| 250 | .l = UINT64_C(0x7FF8000000000000) | 
|---|
| 251 | }; | 
|---|
| 252 | #else | 
|---|
| 253 | const flt flt_nil = NAN; | 
|---|
| 254 | const dbl dbl_nil = NAN; | 
|---|
| 255 | #endif | 
|---|
| 256 | const lng lng_nil = GDK_lng_min-1; | 
|---|
| 257 | #ifdef HAVE_HGE | 
|---|
| 258 | const hge hge_nil = GDK_hge_min-1; | 
|---|
| 259 | #endif | 
|---|
| 260 | const oid oid_nil = (oid) 1 << (sizeof(oid) * 8 - 1); | 
|---|
| 261 | const ptr ptr_nil = NULL; | 
|---|
| 262 |  | 
|---|
| 263 | ptr | 
|---|
| 264 | ATOMnil(int t) | 
|---|
| 265 | { | 
|---|
| 266 | const void *src = ATOMnilptr(t); | 
|---|
| 267 | size_t len = ATOMlen(ATOMtype(t), src); | 
|---|
| 268 | ptr dst = GDKmalloc(len); | 
|---|
| 269 |  | 
|---|
| 270 | if (dst) | 
|---|
| 271 | memcpy(dst, src, len); | 
|---|
| 272 | return dst; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | /* | 
|---|
| 276 | * @- Atomic ADT functions | 
|---|
| 277 | */ | 
|---|
| 278 | size_t | 
|---|
| 279 | ATOMlen(int t, const void *src) | 
|---|
| 280 | { | 
|---|
| 281 | size_t (*l)(const void *) = BATatoms[t].atomLen; | 
|---|
| 282 |  | 
|---|
| 283 | return l ? (*l) (src) : ATOMsize(t); | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 | gdk_return | 
|---|
| 287 | ATOMheap(int t, Heap *hp, size_t cap) | 
|---|
| 288 | { | 
|---|
| 289 | void (*h) (Heap *, size_t) = BATatoms[t].atomHeap; | 
|---|
| 290 |  | 
|---|
| 291 | if (h) { | 
|---|
| 292 | (*h) (hp, cap); | 
|---|
| 293 | if (hp->base == NULL) | 
|---|
| 294 | return GDK_FAIL; | 
|---|
| 295 | } | 
|---|
| 296 | return GDK_SUCCEED; | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | /* | 
|---|
| 300 | * Atom print avoids coercion to strings for built-in types. | 
|---|
| 301 | * The comparison against the NULL value is hard coded for speed. | 
|---|
| 302 | */ | 
|---|
| 303 | #define LINE_LEN	60 | 
|---|
| 304 |  | 
|---|
| 305 | int | 
|---|
| 306 | ATOMprint(int t, const void *p, stream *s) | 
|---|
| 307 | { | 
|---|
| 308 | ssize_t (*tostr) (char **, size_t *, const void *, bool); | 
|---|
| 309 | ssize_t res; | 
|---|
| 310 |  | 
|---|
| 311 | if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) { | 
|---|
| 312 | size_t sz; | 
|---|
| 313 |  | 
|---|
| 314 | if (t != TYPE_bat && t < TYPE_str) { | 
|---|
| 315 | char buf[dblStrlen], *addr = buf;	/* use memory from stack */ | 
|---|
| 316 |  | 
|---|
| 317 | sz = dblStrlen; | 
|---|
| 318 | res = (*tostr) (&addr, &sz, p, true); | 
|---|
| 319 | if (res > 0) | 
|---|
| 320 | res = mnstr_write(s, buf, (size_t) res, 1); | 
|---|
| 321 | } else { | 
|---|
| 322 | str buf = NULL; | 
|---|
| 323 |  | 
|---|
| 324 | sz = 0; | 
|---|
| 325 | res = (*tostr) (&buf, &sz, p, true); | 
|---|
| 326 | if (res > 0) | 
|---|
| 327 | res = mnstr_write(s, buf, (size_t) res, 1); | 
|---|
| 328 | GDKfree(buf); | 
|---|
| 329 | } | 
|---|
| 330 | } else { | 
|---|
| 331 | res = mnstr_write(s, "nil", 1, 3); | 
|---|
| 332 | } | 
|---|
| 333 | if (res < 0) | 
|---|
| 334 | GDKsyserror( "ATOMprint: write failure\n"); | 
|---|
| 335 | return (int) res; | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 |  | 
|---|
| 339 | char * | 
|---|
| 340 | ATOMformat(int t, const void *p) | 
|---|
| 341 | { | 
|---|
| 342 | ssize_t (*tostr) (char **, size_t *, const void *, bool); | 
|---|
| 343 |  | 
|---|
| 344 | if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) { | 
|---|
| 345 | size_t sz = 0; | 
|---|
| 346 | char *buf = NULL; | 
|---|
| 347 | ssize_t res = (*tostr) (&buf, &sz, p, true); | 
|---|
| 348 | if (res < 0 && buf) { | 
|---|
| 349 | GDKfree(buf); | 
|---|
| 350 | buf = NULL; | 
|---|
| 351 | } | 
|---|
| 352 | return buf; | 
|---|
| 353 | } | 
|---|
| 354 | return GDKstrdup( "nil"); | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | ptr | 
|---|
| 358 | ATOMdup(int t, const void *p) | 
|---|
| 359 | { | 
|---|
| 360 | size_t len = ATOMlen(t, p); | 
|---|
| 361 | ptr n = GDKmalloc(len); | 
|---|
| 362 |  | 
|---|
| 363 | if (n) | 
|---|
| 364 | memcpy(n, p, len); | 
|---|
| 365 | return n; | 
|---|
| 366 | } | 
|---|
| 367 |  | 
|---|
| 368 | /* | 
|---|
| 369 | * @* Builtin Atomic Operator Implementations | 
|---|
| 370 | * | 
|---|
| 371 | * @+ Atom-from-String Conversions | 
|---|
| 372 | * These routines convert from string to atom. They are used during | 
|---|
| 373 | * conversion and BAT import. In order to avoid unnecessary | 
|---|
| 374 | * malloc()/free() sequences, the conversion functions have a meta | 
|---|
| 375 | * 'dst' pointer to a destination region, and an integer* 'len' | 
|---|
| 376 | * parameter, that denotes the length of that region (a char region | 
|---|
| 377 | * for ToStr functions, an atom region from FromStr conversions). Only | 
|---|
| 378 | * if necessary will the conversion routine do a GDKfree()/GDKmalloc() | 
|---|
| 379 | * sequence, and increment the 'len'.  Passing a pointer to a nil-ptr | 
|---|
| 380 | * as 'dst' and/or a *len==0 is valid; the conversion function will | 
|---|
| 381 | * then alloc some region for you. | 
|---|
| 382 | */ | 
|---|
| 383 | #define atommem(size)					\ | 
|---|
| 384 | do {						\ | 
|---|
| 385 | if (*dst == NULL || *len < (size)) {	\ | 
|---|
| 386 | GDKfree(*dst);			\ | 
|---|
| 387 | *len = (size);			\ | 
|---|
| 388 | *dst = GDKmalloc(*len);		\ | 
|---|
| 389 | if (*dst == NULL) {		\ | 
|---|
| 390 | *len = 0;		\ | 
|---|
| 391 | return -1;		\ | 
|---|
| 392 | }				\ | 
|---|
| 393 | }					\ | 
|---|
| 394 | } while (0) | 
|---|
| 395 |  | 
|---|
| 396 | #define is_ptr_nil(val)		((val) == ptr_nil) | 
|---|
| 397 |  | 
|---|
| 398 | #define atomtostr(TYPE, FMT, FMTCAST)					\ | 
|---|
| 399 | ssize_t									\ | 
|---|
| 400 | TYPE##ToStr(char **dst, size_t *len, const TYPE *src, bool external)	\ | 
|---|
| 401 | {									\ | 
|---|
| 402 | atommem(TYPE##Strlen);						\ | 
|---|
| 403 | if (is_##TYPE##_nil(*src)) {					\ | 
|---|
| 404 | if (external) {						\ | 
|---|
| 405 | strcpy(*dst, "nil");				\ | 
|---|
| 406 | return 3;					\ | 
|---|
| 407 | }							\ | 
|---|
| 408 | strcpy(*dst, str_nil);					\ | 
|---|
| 409 | return 1;						\ | 
|---|
| 410 | }								\ | 
|---|
| 411 | return snprintf(*dst, *len, FMT, FMTCAST *src);			\ | 
|---|
| 412 | } | 
|---|
| 413 |  | 
|---|
| 414 | #define num10(x)	GDKisdigit(x) | 
|---|
| 415 | #define base10(x)	((x) - '0') | 
|---|
| 416 |  | 
|---|
| 417 | #define num16(x)	isxdigit((unsigned char) (x)) | 
|---|
| 418 | #define base16(x)	(((x) >= 'a' && (x) <= 'f') ? ((x) - 'a' + 10) : ((x) >= 'A' && (x) <= 'F') ? ((x) - 'A' + 10) : (x) - '0') | 
|---|
| 419 | #define mult16(x)	((x) << 4) | 
|---|
| 420 |  | 
|---|
| 421 | static void * | 
|---|
| 422 | voidRead(void *a, stream *s, size_t cnt) | 
|---|
| 423 | { | 
|---|
| 424 | (void) s; | 
|---|
| 425 | (void) cnt; | 
|---|
| 426 | return a; | 
|---|
| 427 | } | 
|---|
| 428 |  | 
|---|
| 429 | static gdk_return | 
|---|
| 430 | voidWrite(const void *a, stream *s, size_t cnt) | 
|---|
| 431 | { | 
|---|
| 432 | (void) a; | 
|---|
| 433 | (void) s; | 
|---|
| 434 | (void) cnt; | 
|---|
| 435 | return GDK_SUCCEED; | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | /* | 
|---|
| 439 | * Converts string values such as TRUE/FALSE/true/false etc to 1/0/NULL. | 
|---|
| 440 | * Switched from byte-to-byte compare to library function strncasecmp, | 
|---|
| 441 | * experiments showed that library function is even slightly faster and we | 
|---|
| 442 | * now also support True/False (and trUe/FAlSE should this become a thing). | 
|---|
| 443 | */ | 
|---|
| 444 | ssize_t | 
|---|
| 445 | bitFromStr(const char *src, size_t *len, bit **dst, bool external) | 
|---|
| 446 | { | 
|---|
| 447 | const char *p = src; | 
|---|
| 448 |  | 
|---|
| 449 | atommem(sizeof(bit)); | 
|---|
| 450 |  | 
|---|
| 451 | **dst = bit_nil; | 
|---|
| 452 |  | 
|---|
| 453 | if (GDK_STRNIL(src)) | 
|---|
| 454 | return 1; | 
|---|
| 455 |  | 
|---|
| 456 | while (GDKisspace(*p)) | 
|---|
| 457 | p++; | 
|---|
| 458 | if (*p == '0') { | 
|---|
| 459 | **dst = FALSE; | 
|---|
| 460 | p++; | 
|---|
| 461 | } else if (*p == '1') { | 
|---|
| 462 | **dst = TRUE; | 
|---|
| 463 | p++; | 
|---|
| 464 | } else if (strncasecmp(p, "true",  4) == 0) { | 
|---|
| 465 | **dst = TRUE; | 
|---|
| 466 | p += 4; | 
|---|
| 467 | } else if (strncasecmp(p, "false", 5) == 0) { | 
|---|
| 468 | **dst = FALSE; | 
|---|
| 469 | p += 5; | 
|---|
| 470 | } else if (external && strncasecmp(p, "nil",   3) == 0) { | 
|---|
| 471 | p += 3; | 
|---|
| 472 | } else { | 
|---|
| 473 | return -1; | 
|---|
| 474 | } | 
|---|
| 475 | while (GDKisspace(*p)) | 
|---|
| 476 | p++; | 
|---|
| 477 | return (ssize_t) (p - src); | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 | ssize_t | 
|---|
| 481 | bitToStr(char **dst, size_t *len, const bit *src, bool external) | 
|---|
| 482 | { | 
|---|
| 483 | atommem(6); | 
|---|
| 484 |  | 
|---|
| 485 | if (is_bit_nil(*src)) { | 
|---|
| 486 | if (external) { | 
|---|
| 487 | strcpy(*dst, "nil"); | 
|---|
| 488 | return 3; | 
|---|
| 489 | } | 
|---|
| 490 | strcpy(*dst, str_nil); | 
|---|
| 491 | return 1; | 
|---|
| 492 | } | 
|---|
| 493 | if (*src) { | 
|---|
| 494 | strcpy(*dst, "true"); | 
|---|
| 495 | return 4; | 
|---|
| 496 | } | 
|---|
| 497 | strcpy(*dst, "false"); | 
|---|
| 498 | return 5; | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 | ssize_t | 
|---|
| 502 | batFromStr(const char *src, size_t *len, bat **dst, bool external) | 
|---|
| 503 | { | 
|---|
| 504 | char *s; | 
|---|
| 505 | const char *t, *r = src; | 
|---|
| 506 | int c; | 
|---|
| 507 | bat bid = 0; | 
|---|
| 508 |  | 
|---|
| 509 | atommem(sizeof(bat)); | 
|---|
| 510 |  | 
|---|
| 511 | if (GDK_STRNIL(src)) { | 
|---|
| 512 | **dst = bat_nil; | 
|---|
| 513 | return 1; | 
|---|
| 514 | } | 
|---|
| 515 |  | 
|---|
| 516 | while (GDKisspace(*r)) | 
|---|
| 517 | r++; | 
|---|
| 518 |  | 
|---|
| 519 | if (external && strcmp(r, "nil") == 0) { | 
|---|
| 520 | **dst = bat_nil; | 
|---|
| 521 | return (ssize_t) (r - src) + 3; | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|
| 524 | if (*r == '<') | 
|---|
| 525 | r++; | 
|---|
| 526 | t = r; | 
|---|
| 527 | while ((c = *t) && (c == '_' || GDKisalnum(c))) | 
|---|
| 528 | t++; | 
|---|
| 529 |  | 
|---|
| 530 | s = GDKstrndup(r, t - r); | 
|---|
| 531 | if (s == NULL) | 
|---|
| 532 | return -1; | 
|---|
| 533 | bid = BBPindex(s); | 
|---|
| 534 | GDKfree(s); | 
|---|
| 535 | **dst = bid == 0 ? bat_nil : bid; | 
|---|
| 536 | return (ssize_t) (t + (c == '>') - src); | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 | ssize_t | 
|---|
| 540 | batToStr(char **dst, size_t *len, const bat *src, bool external) | 
|---|
| 541 | { | 
|---|
| 542 | bat b = *src; | 
|---|
| 543 | size_t i; | 
|---|
| 544 | str s; | 
|---|
| 545 |  | 
|---|
| 546 | if (is_bat_nil(b) || (s = BBPname(b)) == NULL || *s == 0) { | 
|---|
| 547 | atommem(4); | 
|---|
| 548 | if (external) { | 
|---|
| 549 | strcpy(*dst, "nil"); | 
|---|
| 550 | return 3; | 
|---|
| 551 | } | 
|---|
| 552 | strcpy(*dst, str_nil); | 
|---|
| 553 | return 1; | 
|---|
| 554 | } | 
|---|
| 555 | i = strlen(s) + 3; | 
|---|
| 556 | atommem(i); | 
|---|
| 557 | return (ssize_t) strconcat_len(*dst, *len, "<", s, ">", NULL); | 
|---|
| 558 | } | 
|---|
| 559 |  | 
|---|
| 560 |  | 
|---|
| 561 | /* | 
|---|
| 562 | * numFromStr parses the head of the string for a number, accepting an | 
|---|
| 563 | * optional sign. The code has been prepared to continue parsing by | 
|---|
| 564 | * returning the number of characters read.  Both overflow and | 
|---|
| 565 | * incorrect syntax (not a number) result in the function returning 0 | 
|---|
| 566 | * and setting the destination to nil. | 
|---|
| 567 | */ | 
|---|
| 568 | struct maxdiv { | 
|---|
| 569 | /* if we want to multiply a value with scale, the value must | 
|---|
| 570 | * be no larger than maxval for there to not be overflow */ | 
|---|
| 571 | #ifdef HAVE_HGE | 
|---|
| 572 | hge scale, maxval; | 
|---|
| 573 | #else | 
|---|
| 574 | lng scale, maxval; | 
|---|
| 575 | #endif | 
|---|
| 576 | }; | 
|---|
| 577 | static const struct maxdiv maxdiv[] = { | 
|---|
| 578 | #ifdef HAVE_HGE | 
|---|
| 579 | /* maximum hge value: 170141183460469231731687303715884105727 (2**127-1) | 
|---|
| 580 | * GCC doesn't currently support integer constants that don't | 
|---|
| 581 | * fit in 8 bytes, so we split large values up*/ | 
|---|
| 582 | {(hge) LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000000U)+ (hge) LL_CONSTANT(1687303715884105727)}, | 
|---|
| 583 | {(hge) LL_CONSTANT(10), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000000) + (hge) LL_CONSTANT(168730371588410572)}, | 
|---|
| 584 | {(hge) LL_CONSTANT(100), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000000) + (hge) LL_CONSTANT(16873037158841057)}, | 
|---|
| 585 | {(hge) LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000) + (hge) LL_CONSTANT(1687303715884105)}, | 
|---|
| 586 | {(hge) LL_CONSTANT(10000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000) + (hge) LL_CONSTANT(168730371588410)}, | 
|---|
| 587 | {(hge) LL_CONSTANT(100000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000) + (hge) LL_CONSTANT(16873037158841)}, | 
|---|
| 588 | {(hge) LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000) + (hge) LL_CONSTANT(1687303715884)}, | 
|---|
| 589 | {(hge) LL_CONSTANT(10000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000) + (hge) LL_CONSTANT(168730371588)}, | 
|---|
| 590 | {(hge) LL_CONSTANT(100000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000) + (hge) LL_CONSTANT(16873037158)}, | 
|---|
| 591 | {(hge) LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000) + (hge) LL_CONSTANT(1687303715)}, | 
|---|
| 592 | {(hge) LL_CONSTANT(10000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000) + (hge) LL_CONSTANT(168730371)}, | 
|---|
| 593 | {(hge) LL_CONSTANT(100000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000) + (hge) LL_CONSTANT(16873037)}, | 
|---|
| 594 | {(hge) LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000) + (hge) LL_CONSTANT(1687303)}, | 
|---|
| 595 | {(hge) LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000) + (hge) LL_CONSTANT(168730)}, | 
|---|
| 596 | {(hge) LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000) + (hge) LL_CONSTANT(16873)}, | 
|---|
| 597 | {(hge) LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000) + (hge) LL_CONSTANT(1687)}, | 
|---|
| 598 | {(hge) LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000) + (hge) LL_CONSTANT(168)}, | 
|---|
| 599 | {(hge) LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100) + (hge) LL_CONSTANT(16)}, | 
|---|
| 600 | {(hge) LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10) + (hge) LL_CONSTANT(1)}, | 
|---|
| 601 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U)}, | 
|---|
| 602 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10), (hge) LL_CONSTANT(1701411834604692317)}, | 
|---|
| 603 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100), (hge) LL_CONSTANT(170141183460469231)}, | 
|---|
| 604 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923)}, | 
|---|
| 605 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000), (hge) LL_CONSTANT(1701411834604692)}, | 
|---|
| 606 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000), (hge) LL_CONSTANT(170141183460469)}, | 
|---|
| 607 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046)}, | 
|---|
| 608 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000), (hge) LL_CONSTANT(1701411834604)}, | 
|---|
| 609 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000), (hge) LL_CONSTANT(170141183460)}, | 
|---|
| 610 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346)}, | 
|---|
| 611 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000), (hge) LL_CONSTANT(1701411834)}, | 
|---|
| 612 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000), (hge) LL_CONSTANT(170141183)}, | 
|---|
| 613 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118)}, | 
|---|
| 614 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(1701411)}, | 
|---|
| 615 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(170141)}, | 
|---|
| 616 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014)}, | 
|---|
| 617 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(1701)}, | 
|---|
| 618 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(170)}, | 
|---|
| 619 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17)}, | 
|---|
| 620 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000000U),(hge) LL_CONSTANT(1)}, | 
|---|
| 621 | #else | 
|---|
| 622 | /* maximum lng value: 9223372036854775807 (2**63-1) */ | 
|---|
| 623 | {LL_CONSTANT(1), LL_CONSTANT(9223372036854775807)}, | 
|---|
| 624 | {LL_CONSTANT(10), LL_CONSTANT(922337203685477580)}, | 
|---|
| 625 | {LL_CONSTANT(100), LL_CONSTANT(92233720368547758)}, | 
|---|
| 626 | {LL_CONSTANT(1000), LL_CONSTANT(9223372036854775)}, | 
|---|
| 627 | {LL_CONSTANT(10000), LL_CONSTANT(922337203685477)}, | 
|---|
| 628 | {LL_CONSTANT(100000), LL_CONSTANT(92233720368547)}, | 
|---|
| 629 | {LL_CONSTANT(1000000), LL_CONSTANT(9223372036854)}, | 
|---|
| 630 | {LL_CONSTANT(10000000), LL_CONSTANT(922337203685)}, | 
|---|
| 631 | {LL_CONSTANT(100000000), LL_CONSTANT(92233720368)}, | 
|---|
| 632 | {LL_CONSTANT(1000000000), LL_CONSTANT(9223372036)}, | 
|---|
| 633 | {LL_CONSTANT(10000000000), LL_CONSTANT(922337203)}, | 
|---|
| 634 | {LL_CONSTANT(100000000000), LL_CONSTANT(92233720)}, | 
|---|
| 635 | {LL_CONSTANT(1000000000000), LL_CONSTANT(9223372)}, | 
|---|
| 636 | {LL_CONSTANT(10000000000000), LL_CONSTANT(922337)}, | 
|---|
| 637 | {LL_CONSTANT(100000000000000), LL_CONSTANT(92233)}, | 
|---|
| 638 | {LL_CONSTANT(1000000000000000), LL_CONSTANT(9223)}, | 
|---|
| 639 | {LL_CONSTANT(10000000000000000), LL_CONSTANT(922)}, | 
|---|
| 640 | {LL_CONSTANT(100000000000000000), LL_CONSTANT(92)}, | 
|---|
| 641 | {LL_CONSTANT(1000000000000000000), LL_CONSTANT(9)}, | 
|---|
| 642 | #endif | 
|---|
| 643 | }; | 
|---|
| 644 | static const int maxmod10 = 7;	/* (int) (maxdiv[0].maxval % 10) */ | 
|---|
| 645 |  | 
|---|
| 646 | static ssize_t | 
|---|
| 647 | numFromStr(const char *src, size_t *len, void **dst, int tp, bool external) | 
|---|
| 648 | { | 
|---|
| 649 | const char *p = src; | 
|---|
| 650 | size_t sz = ATOMsize(tp); | 
|---|
| 651 | #ifdef HAVE_HGE | 
|---|
| 652 | hge base = 0; | 
|---|
| 653 | #else | 
|---|
| 654 | lng base = 0; | 
|---|
| 655 | #endif | 
|---|
| 656 | int sign = 1; | 
|---|
| 657 |  | 
|---|
| 658 | /* a valid number has the following syntax: | 
|---|
| 659 | * [-+]?[0-9]+([eE][0-9]+)?(LL)? -- PCRE syntax, or in other words | 
|---|
| 660 | * optional sign, one or more digits, optional exponent, optional LL | 
|---|
| 661 | * the exponent has the following syntax: | 
|---|
| 662 | * lower or upper case letter E, one or more digits | 
|---|
| 663 | * embedded spaces are not allowed | 
|---|
| 664 | * the optional LL at the end are only allowed for lng and hge | 
|---|
| 665 | * values */ | 
|---|
| 666 | atommem(sz); | 
|---|
| 667 |  | 
|---|
| 668 | if (GDK_STRNIL(src)) { | 
|---|
| 669 | memcpy(*dst, ATOMnilptr(tp), sz); | 
|---|
| 670 | return 1; | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 | while (GDKisspace(*p)) | 
|---|
| 674 | p++; | 
|---|
| 675 | if (!num10(*p)) { | 
|---|
| 676 | switch (*p) { | 
|---|
| 677 | case 'n': | 
|---|
| 678 | if (external) { | 
|---|
| 679 | memcpy(*dst, ATOMnilptr(tp), sz); | 
|---|
| 680 | if (p[1] == 'i' && p[2] == 'l') { | 
|---|
| 681 | p += 3; | 
|---|
| 682 | return (ssize_t) (p - src); | 
|---|
| 683 | } | 
|---|
| 684 | } | 
|---|
| 685 | GDKerror( "not a number"); | 
|---|
| 686 | goto bailout; | 
|---|
| 687 | case '-': | 
|---|
| 688 | sign = -1; | 
|---|
| 689 | p++; | 
|---|
| 690 | break; | 
|---|
| 691 | case '+': | 
|---|
| 692 | p++; | 
|---|
| 693 | break; | 
|---|
| 694 | } | 
|---|
| 695 | if (!num10(*p)) { | 
|---|
| 696 | GDKerror( "not a number"); | 
|---|
| 697 | goto bailout; | 
|---|
| 698 | } | 
|---|
| 699 | } | 
|---|
| 700 | do { | 
|---|
| 701 | int dig = base10(*p); | 
|---|
| 702 | if (base > maxdiv[1].maxval || | 
|---|
| 703 | (base == maxdiv[1].maxval && dig > maxmod10)) { | 
|---|
| 704 | /* overflow */ | 
|---|
| 705 | goto overflow; | 
|---|
| 706 | } | 
|---|
| 707 | base = 10 * base + dig; | 
|---|
| 708 | p++; | 
|---|
| 709 | } while (num10(*p)); | 
|---|
| 710 | if ((*p == 'e' || *p == 'E') && num10(p[1])) { | 
|---|
| 711 | p++; | 
|---|
| 712 | if (base == 0) { | 
|---|
| 713 | /* if base is 0, any exponent will do, the | 
|---|
| 714 | * result is still 0 */ | 
|---|
| 715 | while (num10(*p)) | 
|---|
| 716 | p++; | 
|---|
| 717 | } else { | 
|---|
| 718 | int exp = 0; | 
|---|
| 719 | do { | 
|---|
| 720 | /* this calculation cannot overflow */ | 
|---|
| 721 | exp = exp * 10 + base10(*p); | 
|---|
| 722 | if (exp >= (int) (sizeof(maxdiv) / sizeof(maxdiv[0]))) { | 
|---|
| 723 | /* overflow */ | 
|---|
| 724 | goto overflow; | 
|---|
| 725 | } | 
|---|
| 726 | p++; | 
|---|
| 727 | } while (num10(*p)); | 
|---|
| 728 | if (base > maxdiv[exp].maxval) { | 
|---|
| 729 | /* overflow */ | 
|---|
| 730 | goto overflow; | 
|---|
| 731 | } | 
|---|
| 732 | base *= maxdiv[exp].scale; | 
|---|
| 733 | } | 
|---|
| 734 | } | 
|---|
| 735 | base *= sign; | 
|---|
| 736 | switch (sz) { | 
|---|
| 737 | case 1: { | 
|---|
| 738 | bte **dstbte = (bte **) dst; | 
|---|
| 739 | if (base < GDK_bte_min || base > GDK_bte_max) { | 
|---|
| 740 | goto overflow; | 
|---|
| 741 | } | 
|---|
| 742 | **dstbte = (bte) base; | 
|---|
| 743 | break; | 
|---|
| 744 | } | 
|---|
| 745 | case 2: { | 
|---|
| 746 | sht **dstsht = (sht **) dst; | 
|---|
| 747 | if (base < GDK_sht_min || base > GDK_sht_max) { | 
|---|
| 748 | goto overflow; | 
|---|
| 749 | } | 
|---|
| 750 | **dstsht = (sht) base; | 
|---|
| 751 | break; | 
|---|
| 752 | } | 
|---|
| 753 | case 4: { | 
|---|
| 754 | int **dstint = (int **) dst; | 
|---|
| 755 | if (base < GDK_int_min || base > GDK_int_max) { | 
|---|
| 756 | goto overflow; | 
|---|
| 757 | } | 
|---|
| 758 | **dstint = (int) base; | 
|---|
| 759 | break; | 
|---|
| 760 | } | 
|---|
| 761 | case 8: { | 
|---|
| 762 | lng **dstlng = (lng **) dst; | 
|---|
| 763 | #ifdef HAVE_HGE | 
|---|
| 764 | if (base < GDK_lng_min || base > GDK_lng_max) { | 
|---|
| 765 | goto overflow; | 
|---|
| 766 | } | 
|---|
| 767 | #endif | 
|---|
| 768 | **dstlng = (lng) base; | 
|---|
| 769 | if (p[0] == 'L' && p[1] == 'L') | 
|---|
| 770 | p += 2; | 
|---|
| 771 | break; | 
|---|
| 772 | } | 
|---|
| 773 | #ifdef HAVE_HGE | 
|---|
| 774 | case 16: { | 
|---|
| 775 | hge **dsthge = (hge **) dst; | 
|---|
| 776 | **dsthge = (hge) base; | 
|---|
| 777 | if (p[0] == 'L' && p[1] == 'L') | 
|---|
| 778 | p += 2; | 
|---|
| 779 | break; | 
|---|
| 780 | } | 
|---|
| 781 | #endif | 
|---|
| 782 | } | 
|---|
| 783 | while (GDKisspace(*p)) | 
|---|
| 784 | p++; | 
|---|
| 785 | return (ssize_t) (p - src); | 
|---|
| 786 |  | 
|---|
| 787 | overflow: | 
|---|
| 788 | while (num10(*p)) | 
|---|
| 789 | p++; | 
|---|
| 790 | GDKerror( "overflow: \"%.*s\" does not fit in %s\n", | 
|---|
| 791 | (int) (p - src), src, ATOMname(tp)); | 
|---|
| 792 | bailout: | 
|---|
| 793 | memcpy(*dst, ATOMnilptr(tp), sz); | 
|---|
| 794 | return -1; | 
|---|
| 795 | } | 
|---|
| 796 |  | 
|---|
| 797 | ssize_t | 
|---|
| 798 | bteFromStr(const char *src, size_t *len, bte **dst, bool external) | 
|---|
| 799 | { | 
|---|
| 800 | return numFromStr(src, len, (void **) dst, TYPE_bte, external); | 
|---|
| 801 | } | 
|---|
| 802 |  | 
|---|
| 803 | ssize_t | 
|---|
| 804 | shtFromStr(const char *src, size_t *len, sht **dst, bool external) | 
|---|
| 805 | { | 
|---|
| 806 | return numFromStr(src, len, (void **) dst, TYPE_sht, external); | 
|---|
| 807 | } | 
|---|
| 808 |  | 
|---|
| 809 | ssize_t | 
|---|
| 810 | intFromStr(const char *src, size_t *len, int **dst, bool external) | 
|---|
| 811 | { | 
|---|
| 812 | return numFromStr(src, len, (void **) dst, TYPE_int, external); | 
|---|
| 813 | } | 
|---|
| 814 |  | 
|---|
| 815 | ssize_t | 
|---|
| 816 | lngFromStr(const char *src, size_t *len, lng **dst, bool external) | 
|---|
| 817 | { | 
|---|
| 818 | return numFromStr(src, len, (void **) dst, TYPE_lng, external); | 
|---|
| 819 | } | 
|---|
| 820 |  | 
|---|
| 821 | #ifdef HAVE_HGE | 
|---|
| 822 | ssize_t | 
|---|
| 823 | hgeFromStr(const char *src, size_t *len, hge **dst, bool external) | 
|---|
| 824 | { | 
|---|
| 825 | return numFromStr(src, len, (void **) dst, TYPE_hge, external); | 
|---|
| 826 | } | 
|---|
| 827 | #endif | 
|---|
| 828 |  | 
|---|
| 829 | #define atom_io(TYPE, NAME, CAST)					\ | 
|---|
| 830 | static TYPE *								\ | 
|---|
| 831 | TYPE##Read(TYPE *A, stream *s, size_t cnt)				\ | 
|---|
| 832 | {									\ | 
|---|
| 833 | TYPE *a = A;							\ | 
|---|
| 834 | if (a == NULL && (a = GDKmalloc(cnt * sizeof(TYPE))) == NULL)	\ | 
|---|
| 835 | return NULL;						\ | 
|---|
| 836 | if (mnstr_read##NAME##Array(s, (CAST *) a, cnt) == 0 ||		\ | 
|---|
| 837 | mnstr_errnr(s)) {						\ | 
|---|
| 838 | if (a != A)						\ | 
|---|
| 839 | GDKfree(a);					\ | 
|---|
| 840 | return NULL;						\ | 
|---|
| 841 | }								\ | 
|---|
| 842 | return a;							\ | 
|---|
| 843 | }									\ | 
|---|
| 844 | static gdk_return							\ | 
|---|
| 845 | TYPE##Write(const TYPE *a, stream *s, size_t cnt)			\ | 
|---|
| 846 | {									\ | 
|---|
| 847 | return mnstr_write##NAME##Array(s, (const CAST *) a, cnt) ?	\ | 
|---|
| 848 | GDK_SUCCEED : GDK_FAIL;					\ | 
|---|
| 849 | } | 
|---|
| 850 |  | 
|---|
| 851 | atom_io(bat, Int, int) | 
|---|
| 852 | atom_io(bit, Bte, bte) | 
|---|
| 853 |  | 
|---|
| 854 | atomtostr(bte, "%hhd", ) | 
|---|
| 855 | atom_io(bte, Bte, bte) | 
|---|
| 856 |  | 
|---|
| 857 | atomtostr(sht, "%hd", ) | 
|---|
| 858 | atom_io(sht, Sht, sht) | 
|---|
| 859 |  | 
|---|
| 860 | atomtostr(int, "%d", ) | 
|---|
| 861 | atom_io(int, Int, int) | 
|---|
| 862 |  | 
|---|
| 863 | atomtostr(lng, LLFMT, ) | 
|---|
| 864 | atom_io(lng, Lng, lng) | 
|---|
| 865 |  | 
|---|
| 866 | #ifdef HAVE_HGE | 
|---|
| 867 | #define HGE_LL018FMT "%018" PRId64 | 
|---|
| 868 | #define HGE_LL18DIGITS LL_CONSTANT(1000000000000000000) | 
|---|
| 869 | #define HGE_ABS(a) (((a) < 0) ? -(a) : (a)) | 
|---|
| 870 | ssize_t | 
|---|
| 871 | hgeToStr(char **dst, size_t *len, const hge *src, bool external) | 
|---|
| 872 | { | 
|---|
| 873 | atommem(hgeStrlen); | 
|---|
| 874 | if (is_hge_nil(*src)) { | 
|---|
| 875 | if (external) { | 
|---|
| 876 | return (ssize_t) strcpy_len(*dst, "nil", 4); | 
|---|
| 877 | } | 
|---|
| 878 | strcpy(*dst, str_nil); | 
|---|
| 879 | return 1; | 
|---|
| 880 | } | 
|---|
| 881 | if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) { | 
|---|
| 882 | lng s = (lng) *src; | 
|---|
| 883 | return lngToStr(dst, len, &s, external); | 
|---|
| 884 | } else { | 
|---|
| 885 | hge s = *src / HGE_LL18DIGITS; | 
|---|
| 886 | ssize_t llen = hgeToStr(dst, len, &s, external); | 
|---|
| 887 | if (llen < 0) | 
|---|
| 888 | return llen; | 
|---|
| 889 | snprintf(*dst + llen, *len - llen, HGE_LL018FMT, | 
|---|
| 890 | (lng) HGE_ABS(*src % HGE_LL18DIGITS)); | 
|---|
| 891 | return strlen(*dst); | 
|---|
| 892 | } | 
|---|
| 893 | } | 
|---|
| 894 | atom_io(hge, Hge, hge) | 
|---|
| 895 | #endif | 
|---|
| 896 |  | 
|---|
| 897 | ssize_t | 
|---|
| 898 | ptrFromStr(const char *src, size_t *len, ptr **dst, bool external) | 
|---|
| 899 | { | 
|---|
| 900 | size_t base = 0; | 
|---|
| 901 | const char *p = src; | 
|---|
| 902 |  | 
|---|
| 903 | atommem(sizeof(ptr)); | 
|---|
| 904 |  | 
|---|
| 905 | **dst = ptr_nil; | 
|---|
| 906 | if (GDK_STRNIL(src)) | 
|---|
| 907 | return 1; | 
|---|
| 908 |  | 
|---|
| 909 | while (GDKisspace(*p)) | 
|---|
| 910 | p++; | 
|---|
| 911 | if (external && strncmp(p, "nil", 3) == 0) { | 
|---|
| 912 | p += 3; | 
|---|
| 913 | } else { | 
|---|
| 914 | if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { | 
|---|
| 915 | p += 2; | 
|---|
| 916 | } | 
|---|
| 917 | if (!num16(*p)) { | 
|---|
| 918 | GDKerror( "not a number\n"); | 
|---|
| 919 | return -1; | 
|---|
| 920 | } | 
|---|
| 921 | while (num16(*p)) { | 
|---|
| 922 | if (base >= ((size_t) 1 << (8 * sizeof(size_t) - 4))) { | 
|---|
| 923 | GDKerror( "overflow\n"); | 
|---|
| 924 | return -1; | 
|---|
| 925 | } | 
|---|
| 926 | base = mult16(base) + base16(*p); | 
|---|
| 927 | p++; | 
|---|
| 928 | } | 
|---|
| 929 | **dst = (ptr) base; | 
|---|
| 930 | } | 
|---|
| 931 | while (GDKisspace(*p)) | 
|---|
| 932 | p++; | 
|---|
| 933 | return (ssize_t) (p - src); | 
|---|
| 934 | } | 
|---|
| 935 |  | 
|---|
| 936 | atomtostr(ptr, "%p", ) | 
|---|
| 937 |  | 
|---|
| 938 | #if SIZEOF_VOID_P == SIZEOF_INT | 
|---|
| 939 | atom_io(ptr, Int, int) | 
|---|
| 940 | #else /* SIZEOF_VOID_P == SIZEOF_LNG */ | 
|---|
| 941 | atom_io(ptr, Lng, lng) | 
|---|
| 942 | #endif | 
|---|
| 943 |  | 
|---|
| 944 | ssize_t | 
|---|
| 945 | dblFromStr(const char *src, size_t *len, dbl **dst, bool external) | 
|---|
| 946 | { | 
|---|
| 947 | const char *p = src; | 
|---|
| 948 | ssize_t n = 0; | 
|---|
| 949 | double d; | 
|---|
| 950 |  | 
|---|
| 951 | /* alloc memory */ | 
|---|
| 952 | atommem(sizeof(dbl)); | 
|---|
| 953 |  | 
|---|
| 954 | if (GDK_STRNIL(src)) { | 
|---|
| 955 | **dst = dbl_nil; | 
|---|
| 956 | return 1; | 
|---|
| 957 | } | 
|---|
| 958 |  | 
|---|
| 959 | while (GDKisspace(*p)) | 
|---|
| 960 | p++; | 
|---|
| 961 | if (external && strncmp(p, "nil", 3) == 0) { | 
|---|
| 962 | **dst = dbl_nil; | 
|---|
| 963 | p += 3; | 
|---|
| 964 | n = (ssize_t) (p - src); | 
|---|
| 965 | } else { | 
|---|
| 966 | /* on overflow, strtod returns HUGE_VAL and sets | 
|---|
| 967 | * errno to ERANGE; on underflow, it returns a value | 
|---|
| 968 | * whose magnitude is no greater than the smallest | 
|---|
| 969 | * normalized double, and may or may not set errno to | 
|---|
| 970 | * ERANGE.  We accept underflow, but not overflow. */ | 
|---|
| 971 | char *pe; | 
|---|
| 972 | errno = 0; | 
|---|
| 973 | d = strtod(p, &pe); | 
|---|
| 974 | if (p == pe) | 
|---|
| 975 | p = src; /* nothing converted */ | 
|---|
| 976 | else | 
|---|
| 977 | p = pe; | 
|---|
| 978 | n = (ssize_t) (p - src); | 
|---|
| 979 | if (n == 0 || (errno == ERANGE && (d < -1 || d > 1)) | 
|---|
| 980 | || !isfinite(d) /* no NaN or Infinte */ | 
|---|
| 981 | ) { | 
|---|
| 982 | GDKerror( "overflow or not a number\n"); | 
|---|
| 983 | return -1; | 
|---|
| 984 | } else { | 
|---|
| 985 | while (src[n] && GDKisspace(src[n])) | 
|---|
| 986 | n++; | 
|---|
| 987 | **dst = (dbl) d; | 
|---|
| 988 | } | 
|---|
| 989 | } | 
|---|
| 990 | return n; | 
|---|
| 991 | } | 
|---|
| 992 |  | 
|---|
| 993 | ssize_t | 
|---|
| 994 | dblToStr(char **dst, size_t *len, const dbl *src, bool external) | 
|---|
| 995 | { | 
|---|
| 996 | int i; | 
|---|
| 997 |  | 
|---|
| 998 | atommem(dblStrlen); | 
|---|
| 999 | if (is_dbl_nil(*src)) { | 
|---|
| 1000 | if (external) { | 
|---|
| 1001 | strcpy(*dst, "nil"); | 
|---|
| 1002 | return 3; | 
|---|
| 1003 | } | 
|---|
| 1004 | strcpy(*dst, str_nil); | 
|---|
| 1005 | return 1; | 
|---|
| 1006 | } | 
|---|
| 1007 | for (i = 4; i < 18; i++) { | 
|---|
| 1008 | snprintf(*dst, *len, "%.*g", i, *src); | 
|---|
| 1009 | if (strtod(*dst, NULL) == *src) | 
|---|
| 1010 | break; | 
|---|
| 1011 | } | 
|---|
| 1012 | return (ssize_t) strlen(*dst); | 
|---|
| 1013 | } | 
|---|
| 1014 |  | 
|---|
| 1015 | atom_io(dbl, Lng, lng) | 
|---|
| 1016 |  | 
|---|
| 1017 | ssize_t | 
|---|
| 1018 | fltFromStr(const char *src, size_t *len, flt **dst, bool external) | 
|---|
| 1019 | { | 
|---|
| 1020 | const char *p = src; | 
|---|
| 1021 | ssize_t n = 0; | 
|---|
| 1022 | float f; | 
|---|
| 1023 |  | 
|---|
| 1024 | /* alloc memory */ | 
|---|
| 1025 | atommem(sizeof(flt)); | 
|---|
| 1026 |  | 
|---|
| 1027 | if (GDK_STRNIL(src)) { | 
|---|
| 1028 | **dst = flt_nil; | 
|---|
| 1029 | return 1; | 
|---|
| 1030 | } | 
|---|
| 1031 |  | 
|---|
| 1032 | while (GDKisspace(*p)) | 
|---|
| 1033 | p++; | 
|---|
| 1034 | if (external && strncmp(p, "nil", 3) == 0) { | 
|---|
| 1035 | **dst = flt_nil; | 
|---|
| 1036 | p += 3; | 
|---|
| 1037 | n = (ssize_t) (p - src); | 
|---|
| 1038 | } else { | 
|---|
| 1039 | /* on overflow, strtof returns HUGE_VALF and sets | 
|---|
| 1040 | * errno to ERANGE; on underflow, it returns a value | 
|---|
| 1041 | * whose magnitude is no greater than the smallest | 
|---|
| 1042 | * normalized float, and may or may not set errno to | 
|---|
| 1043 | * ERANGE.  We accept underflow, but not overflow. */ | 
|---|
| 1044 | char *pe; | 
|---|
| 1045 | errno = 0; | 
|---|
| 1046 | f = strtof(p, &pe); | 
|---|
| 1047 | if (p == pe) | 
|---|
| 1048 | p = src; /* nothing converted */ | 
|---|
| 1049 | else | 
|---|
| 1050 | p = pe; | 
|---|
| 1051 | n = (ssize_t) (p - src); | 
|---|
| 1052 | if (n == 0 || (errno == ERANGE && (f < -1 || f > 1)) | 
|---|
| 1053 | || !isfinite(f) /* no NaN or infinite */) { | 
|---|
| 1054 | GDKerror( "overflow or not a number\n"); | 
|---|
| 1055 | return -1; | 
|---|
| 1056 | } else { | 
|---|
| 1057 | while (src[n] && GDKisspace(src[n])) | 
|---|
| 1058 | n++; | 
|---|
| 1059 | **dst = (flt) f; | 
|---|
| 1060 | } | 
|---|
| 1061 | } | 
|---|
| 1062 | return n; | 
|---|
| 1063 | } | 
|---|
| 1064 |  | 
|---|
| 1065 | ssize_t | 
|---|
| 1066 | fltToStr(char **dst, size_t *len, const flt *src, bool external) | 
|---|
| 1067 | { | 
|---|
| 1068 | int i; | 
|---|
| 1069 |  | 
|---|
| 1070 | atommem(fltStrlen); | 
|---|
| 1071 | if (is_flt_nil(*src)) { | 
|---|
| 1072 | if (external) { | 
|---|
| 1073 | strcpy(*dst, "nil"); | 
|---|
| 1074 | return 3; | 
|---|
| 1075 | } | 
|---|
| 1076 | strcpy(*dst, str_nil); | 
|---|
| 1077 | return 1; | 
|---|
| 1078 | } | 
|---|
| 1079 | for (i = 4; i < 10; i++) { | 
|---|
| 1080 | snprintf(*dst, *len, "%.*g", i, *src); | 
|---|
| 1081 | if (strtof(*dst, NULL) == *src) | 
|---|
| 1082 | break; | 
|---|
| 1083 | } | 
|---|
| 1084 | return (ssize_t) strlen(*dst); | 
|---|
| 1085 | } | 
|---|
| 1086 |  | 
|---|
| 1087 | atom_io(flt, Int, int) | 
|---|
| 1088 |  | 
|---|
| 1089 |  | 
|---|
| 1090 | /* | 
|---|
| 1091 | * String conversion routines. | 
|---|
| 1092 | */ | 
|---|
| 1093 | ssize_t | 
|---|
| 1094 | OIDfromStr(const char *src, size_t *len, oid **dst, bool external) | 
|---|
| 1095 | { | 
|---|
| 1096 | #if SIZEOF_OID == SIZEOF_INT | 
|---|
| 1097 | int ui = 0, *uip = &ui; | 
|---|
| 1098 | #else | 
|---|
| 1099 | lng ui = 0, *uip = &ui; | 
|---|
| 1100 | #endif | 
|---|
| 1101 | size_t l = sizeof(ui); | 
|---|
| 1102 | ssize_t pos = 0; | 
|---|
| 1103 | const char *p = src; | 
|---|
| 1104 |  | 
|---|
| 1105 | atommem(sizeof(oid)); | 
|---|
| 1106 |  | 
|---|
| 1107 | **dst = oid_nil; | 
|---|
| 1108 | if (GDK_STRNIL(src)) | 
|---|
| 1109 | return 1; | 
|---|
| 1110 |  | 
|---|
| 1111 | while (GDKisspace(*p)) | 
|---|
| 1112 | p++; | 
|---|
| 1113 |  | 
|---|
| 1114 | if (external && strncmp(p, "nil", 3) == 0) | 
|---|
| 1115 | return (ssize_t) (p - src) + 3; | 
|---|
| 1116 |  | 
|---|
| 1117 | if (GDKisdigit(*p)) { | 
|---|
| 1118 | #if SIZEOF_OID == SIZEOF_INT | 
|---|
| 1119 | pos = intFromStr(p, &l, &uip, external); | 
|---|
| 1120 | #else | 
|---|
| 1121 | pos = lngFromStr(p, &l, &uip, external); | 
|---|
| 1122 | #endif | 
|---|
| 1123 | if (pos < 0) | 
|---|
| 1124 | return pos; | 
|---|
| 1125 | if (p[pos] == '@') { | 
|---|
| 1126 | pos++; | 
|---|
| 1127 | while (GDKisdigit(p[pos])) | 
|---|
| 1128 | pos++; | 
|---|
| 1129 | } | 
|---|
| 1130 | if (ui >= 0) { | 
|---|
| 1131 | **dst = ui; | 
|---|
| 1132 | } | 
|---|
| 1133 | p += pos; | 
|---|
| 1134 | } else { | 
|---|
| 1135 | GDKerror( "not an OID\n"); | 
|---|
| 1136 | return -1; | 
|---|
| 1137 | } | 
|---|
| 1138 | while (GDKisspace(*p)) | 
|---|
| 1139 | p++; | 
|---|
| 1140 | return (ssize_t) (p - src); | 
|---|
| 1141 | } | 
|---|
| 1142 |  | 
|---|
| 1143 | ssize_t | 
|---|
| 1144 | OIDtoStr(char **dst, size_t *len, const oid *src, bool external) | 
|---|
| 1145 | { | 
|---|
| 1146 | atommem(oidStrlen); | 
|---|
| 1147 |  | 
|---|
| 1148 | if (is_oid_nil(*src)) { | 
|---|
| 1149 | if (external) { | 
|---|
| 1150 | strcpy(*dst, "nil"); | 
|---|
| 1151 | return 3; | 
|---|
| 1152 | } | 
|---|
| 1153 | strcpy(*dst, str_nil); | 
|---|
| 1154 | return 1; | 
|---|
| 1155 | } | 
|---|
| 1156 | return snprintf(*dst, *len, OIDFMT "@0", *src); | 
|---|
| 1157 | } | 
|---|
| 1158 |  | 
|---|
| 1159 | atomDesc BATatoms[MAXATOMS] = { | 
|---|
| 1160 | [TYPE_void] = { | 
|---|
| 1161 | .name = "void", | 
|---|
| 1162 | .storage = TYPE_void, | 
|---|
| 1163 | .linear = true, | 
|---|
| 1164 | #if SIZEOF_OID == SIZEOF_INT | 
|---|
| 1165 | .atomNull = (void *) &int_nil, | 
|---|
| 1166 | .atomCmp = (int (*)(const void *, const void *)) intCmp, | 
|---|
| 1167 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1168 | #else | 
|---|
| 1169 | .atomNull = (void *) &lng_nil, | 
|---|
| 1170 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, | 
|---|
| 1171 | .atomHash = (BUN (*)(const void *)) lngHash, | 
|---|
| 1172 | #endif | 
|---|
| 1173 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr, | 
|---|
| 1174 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr, | 
|---|
| 1175 | .atomRead = (void *(*)(void *, stream *, size_t)) voidRead, | 
|---|
| 1176 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite, | 
|---|
| 1177 | }, | 
|---|
| 1178 | [TYPE_bit] = { | 
|---|
| 1179 | .name = "bit", | 
|---|
| 1180 | .storage = TYPE_bte, | 
|---|
| 1181 | .linear = true, | 
|---|
| 1182 | .size = sizeof(bit), | 
|---|
| 1183 | .atomNull = (void *) &bte_nil, | 
|---|
| 1184 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr, | 
|---|
| 1185 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr, | 
|---|
| 1186 | .atomRead = (void *(*)(void *, stream *, size_t)) bitRead, | 
|---|
| 1187 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite, | 
|---|
| 1188 | .atomCmp = (int (*)(const void *, const void *)) bteCmp, | 
|---|
| 1189 | .atomHash = (BUN (*)(const void *)) bteHash, | 
|---|
| 1190 | }, | 
|---|
| 1191 | [TYPE_bte] = { | 
|---|
| 1192 | .name = "bte", | 
|---|
| 1193 | .storage = TYPE_bte, | 
|---|
| 1194 | .linear = true, | 
|---|
| 1195 | .size = sizeof(bte), | 
|---|
| 1196 | .atomNull = (void *) &bte_nil, | 
|---|
| 1197 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr, | 
|---|
| 1198 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr, | 
|---|
| 1199 | .atomRead = (void *(*)(void *, stream *, size_t)) bteRead, | 
|---|
| 1200 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite, | 
|---|
| 1201 | .atomCmp = (int (*)(const void *, const void *)) bteCmp, | 
|---|
| 1202 | .atomHash = (BUN (*)(const void *)) bteHash, | 
|---|
| 1203 | }, | 
|---|
| 1204 | [TYPE_sht] = { | 
|---|
| 1205 | .name = "sht", | 
|---|
| 1206 | .storage = TYPE_sht, | 
|---|
| 1207 | .linear = true, | 
|---|
| 1208 | .size = sizeof(sht), | 
|---|
| 1209 | .atomNull = (void *) &sht_nil, | 
|---|
| 1210 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr, | 
|---|
| 1211 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr, | 
|---|
| 1212 | .atomRead = (void *(*)(void *, stream *, size_t)) shtRead, | 
|---|
| 1213 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite, | 
|---|
| 1214 | .atomCmp = (int (*)(const void *, const void *)) shtCmp, | 
|---|
| 1215 | .atomHash = (BUN (*)(const void *)) shtHash, | 
|---|
| 1216 | }, | 
|---|
| 1217 | [TYPE_bat] = { | 
|---|
| 1218 | .name = "BAT", | 
|---|
| 1219 | .storage = TYPE_int, | 
|---|
| 1220 | .linear = true, | 
|---|
| 1221 | .size = sizeof(bat), | 
|---|
| 1222 | .atomNull = (void *) &int_nil, | 
|---|
| 1223 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) batFromStr, | 
|---|
| 1224 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) batToStr, | 
|---|
| 1225 | .atomRead = (void *(*)(void *, stream *, size_t)) batRead, | 
|---|
| 1226 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) batWrite, | 
|---|
| 1227 | .atomCmp = (int (*)(const void *, const void *)) intCmp, | 
|---|
| 1228 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1229 | .atomFix = (int (*)(const void *)) batFix, | 
|---|
| 1230 | .atomUnfix = (int (*)(const void *)) batUnfix, | 
|---|
| 1231 | }, | 
|---|
| 1232 | [TYPE_int] = { | 
|---|
| 1233 | .name = "int", | 
|---|
| 1234 | .storage = TYPE_int, | 
|---|
| 1235 | .linear = true, | 
|---|
| 1236 | .size = sizeof(int), | 
|---|
| 1237 | .atomNull = (void *) &int_nil, | 
|---|
| 1238 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr, | 
|---|
| 1239 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr, | 
|---|
| 1240 | .atomRead = (void *(*)(void *, stream *, size_t)) intRead, | 
|---|
| 1241 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite, | 
|---|
| 1242 | .atomCmp = (int (*)(const void *, const void *)) intCmp, | 
|---|
| 1243 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1244 | }, | 
|---|
| 1245 | [TYPE_oid] = { | 
|---|
| 1246 | .name = "oid", | 
|---|
| 1247 | .linear = true, | 
|---|
| 1248 | .size = sizeof(oid), | 
|---|
| 1249 | #if SIZEOF_OID == SIZEOF_INT | 
|---|
| 1250 | .storage = TYPE_int, | 
|---|
| 1251 | .atomNull = (void *) &int_nil, | 
|---|
| 1252 | .atomRead = (void *(*)(void *, stream *, size_t)) intRead, | 
|---|
| 1253 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite, | 
|---|
| 1254 | .atomCmp = (int (*)(const void *, const void *)) intCmp, | 
|---|
| 1255 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1256 | #else | 
|---|
| 1257 | .storage = TYPE_lng, | 
|---|
| 1258 | .atomNull = (void *) &lng_nil, | 
|---|
| 1259 | .atomRead = (void *(*)(void *, stream *, size_t)) lngRead, | 
|---|
| 1260 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite, | 
|---|
| 1261 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, | 
|---|
| 1262 | .atomHash = (BUN (*)(const void *)) lngHash, | 
|---|
| 1263 | #endif | 
|---|
| 1264 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr, | 
|---|
| 1265 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr, | 
|---|
| 1266 | }, | 
|---|
| 1267 | [TYPE_ptr] = { | 
|---|
| 1268 | .name = "ptr", | 
|---|
| 1269 | .storage = TYPE_ptr, | 
|---|
| 1270 | .linear = true, | 
|---|
| 1271 | .size = sizeof(void *), | 
|---|
| 1272 | .atomNull = (void *) &ptr_nil, | 
|---|
| 1273 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr, | 
|---|
| 1274 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr, | 
|---|
| 1275 | .atomRead = (void *(*)(void *, stream *, size_t)) ptrRead, | 
|---|
| 1276 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite, | 
|---|
| 1277 | #if SIZEOF_VOID_P == SIZEOF_INT | 
|---|
| 1278 | .atomCmp = (int (*)(const void *, const void *)) intCmp, | 
|---|
| 1279 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1280 | #else /* SIZEOF_VOID_P == SIZEOF_LNG */ | 
|---|
| 1281 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, | 
|---|
| 1282 | .atomHash = (BUN (*)(const void *)) lngHash, | 
|---|
| 1283 | #endif | 
|---|
| 1284 | }, | 
|---|
| 1285 | [TYPE_flt] = { | 
|---|
| 1286 | .name = "flt", | 
|---|
| 1287 | .storage = TYPE_flt, | 
|---|
| 1288 | .linear = true, | 
|---|
| 1289 | .size = sizeof(flt), | 
|---|
| 1290 | .atomNull = (void *) &flt_nil, | 
|---|
| 1291 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr, | 
|---|
| 1292 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr, | 
|---|
| 1293 | .atomRead = (void *(*)(void *, stream *, size_t)) fltRead, | 
|---|
| 1294 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite, | 
|---|
| 1295 | .atomCmp = (int (*)(const void *, const void *)) fltCmp, | 
|---|
| 1296 | .atomHash = (BUN (*)(const void *)) intHash, | 
|---|
| 1297 | }, | 
|---|
| 1298 | [TYPE_dbl] = { | 
|---|
| 1299 | .name = "dbl", | 
|---|
| 1300 | .storage = TYPE_dbl, | 
|---|
| 1301 | .linear = true, | 
|---|
| 1302 | .size = sizeof(dbl), | 
|---|
| 1303 | .atomNull = (void *) &dbl_nil, | 
|---|
| 1304 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr, | 
|---|
| 1305 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr, | 
|---|
| 1306 | .atomRead = (void *(*)(void *, stream *, size_t)) dblRead, | 
|---|
| 1307 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite, | 
|---|
| 1308 | .atomCmp = (int (*)(const void *, const void *)) dblCmp, | 
|---|
| 1309 | .atomHash = (BUN (*)(const void *)) lngHash, | 
|---|
| 1310 | }, | 
|---|
| 1311 | [TYPE_lng] = { | 
|---|
| 1312 | .name = "lng", | 
|---|
| 1313 | .storage = TYPE_lng, | 
|---|
| 1314 | .linear = true, | 
|---|
| 1315 | .size = sizeof(lng), | 
|---|
| 1316 | .atomNull = (void *) &lng_nil, | 
|---|
| 1317 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr, | 
|---|
| 1318 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr, | 
|---|
| 1319 | .atomRead = (void *(*)(void *, stream *, size_t)) lngRead, | 
|---|
| 1320 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite, | 
|---|
| 1321 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, | 
|---|
| 1322 | .atomHash = (BUN (*)(const void *)) lngHash, | 
|---|
| 1323 | }, | 
|---|
| 1324 | #ifdef HAVE_HGE | 
|---|
| 1325 | [TYPE_hge] = { | 
|---|
| 1326 | .name = "hge", | 
|---|
| 1327 | .storage = TYPE_hge, | 
|---|
| 1328 | .linear = true, | 
|---|
| 1329 | .size = sizeof(hge), | 
|---|
| 1330 | .atomNull = (void *) &hge_nil, | 
|---|
| 1331 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr, | 
|---|
| 1332 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr, | 
|---|
| 1333 | .atomRead = (void *(*)(void *, stream *, size_t)) hgeRead, | 
|---|
| 1334 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite, | 
|---|
| 1335 | .atomCmp = (int (*)(const void *, const void *)) hgeCmp, | 
|---|
| 1336 | .atomHash = (BUN (*)(const void *)) hgeHash, | 
|---|
| 1337 | }, | 
|---|
| 1338 | #endif | 
|---|
| 1339 | [TYPE_str] = { | 
|---|
| 1340 | .name = "str", | 
|---|
| 1341 | .storage = TYPE_str, | 
|---|
| 1342 | .linear = true, | 
|---|
| 1343 | .size = sizeof(var_t), | 
|---|
| 1344 | .atomNull = (void *) str_nil, | 
|---|
| 1345 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr, | 
|---|
| 1346 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr, | 
|---|
| 1347 | .atomRead = (void *(*)(void *, stream *, size_t)) strRead, | 
|---|
| 1348 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite, | 
|---|
| 1349 | .atomCmp = (int (*)(const void *, const void *)) strCmp, | 
|---|
| 1350 | .atomHash = (BUN (*)(const void *)) strHash, | 
|---|
| 1351 | .atomPut = (var_t (*)(Heap *, var_t *, const void *)) strPut, | 
|---|
| 1352 | .atomLen = (size_t (*)(const void *)) strLen, | 
|---|
| 1353 | .atomHeap = strHeap, | 
|---|
| 1354 | }, | 
|---|
| 1355 | }; | 
|---|
| 1356 |  | 
|---|
| 1357 | int GDKatomcnt = TYPE_str + 1; | 
|---|
| 1358 |  | 
|---|
| 1359 | /* | 
|---|
| 1360 | * Sometimes a bat descriptor is loaded before the dynamic module | 
|---|
| 1361 | * defining the atom is loaded. To support this an extra set of | 
|---|
| 1362 | * unknown atoms is kept.  These can be accessed via the ATOMunknown | 
|---|
| 1363 | * interface. Finding an (negative) atom index can be done via | 
|---|
| 1364 | * ATOMunknown_find, which simply adds the atom if it's not in the | 
|---|
| 1365 | * unknown set. The index can be used to find the name of an unknown | 
|---|
| 1366 | * ATOM via ATOMunknown_name. | 
|---|
| 1367 | */ | 
|---|
| 1368 | static str unknown[MAXATOMS] = { NULL }; | 
|---|
| 1369 |  | 
|---|
| 1370 | int | 
|---|
| 1371 | ATOMunknown_find(const char *nme) | 
|---|
| 1372 | { | 
|---|
| 1373 | int i, j = 0; | 
|---|
| 1374 |  | 
|---|
| 1375 | /* first try to find the atom */ | 
|---|
| 1376 | MT_lock_set(&GDKthreadLock); | 
|---|
| 1377 | for (i = 1; i < MAXATOMS; i++) { | 
|---|
| 1378 | if (unknown[i]) { | 
|---|
| 1379 | if (strcmp(unknown[i], nme) == 0) { | 
|---|
| 1380 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 1381 | return -i; | 
|---|
| 1382 | } | 
|---|
| 1383 | } else if (j == 0) | 
|---|
| 1384 | j = i; | 
|---|
| 1385 | } | 
|---|
| 1386 | if (j == 0) { | 
|---|
| 1387 | /* no space for new atom (shouldn't happen) */ | 
|---|
| 1388 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 1389 | return 0; | 
|---|
| 1390 | } | 
|---|
| 1391 | if ((unknown[j] = GDKstrdup(nme)) == NULL) { | 
|---|
| 1392 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 1393 | return 0; | 
|---|
| 1394 | } | 
|---|
| 1395 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 1396 | return -j; | 
|---|
| 1397 | } | 
|---|
| 1398 |  | 
|---|
| 1399 | str | 
|---|
| 1400 | ATOMunknown_name(int i) | 
|---|
| 1401 | { | 
|---|
| 1402 | assert(i < 0); | 
|---|
| 1403 | assert(unknown[-i]); | 
|---|
| 1404 | return unknown[-i]; | 
|---|
| 1405 | } | 
|---|
| 1406 |  | 
|---|
| 1407 | void | 
|---|
| 1408 | ATOMunknown_clean(void) | 
|---|
| 1409 | { | 
|---|
| 1410 | int i; | 
|---|
| 1411 |  | 
|---|
| 1412 | MT_lock_set(&GDKthreadLock); | 
|---|
| 1413 | for (i = 1; i < MAXATOMS; i++) { | 
|---|
| 1414 | if(unknown[i]) { | 
|---|
| 1415 | GDKfree(unknown[i]); | 
|---|
| 1416 | unknown[i] = NULL; | 
|---|
| 1417 | } else { | 
|---|
| 1418 | break; | 
|---|
| 1419 | } | 
|---|
| 1420 | } | 
|---|
| 1421 | MT_lock_unset(&GDKthreadLock); | 
|---|
| 1422 | } | 
|---|
| 1423 |  | 
|---|