Ruby 3.2.4p170 (2024-04-23 revision af471c0e0127eea0cafa6f308c0425bbfab0acf5)
util.c
1/**********************************************************************
2
3 util.c -
4
5 $Author$
6 created at: Fri Mar 10 17:22:34 JST 1995
7
8 Copyright (C) 1993-2008 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#if defined __MINGW32__ || defined __MINGW64__
13# define MINGW_HAS_SECURE_API 1
14#endif
15
16#include "ruby/internal/config.h"
17
18#include <ctype.h>
19#include <errno.h>
20#include <float.h>
21#include <math.h>
22#include <stdio.h>
23
24#ifdef _WIN32
25# include "missing/file.h"
26#endif
27
28#include "internal.h"
29#include "internal/sanitizers.h"
30#include "internal/util.h"
31#include "ruby/util.h"
32#include "ruby_atomic.h"
33
34const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF";
35#define hexdigit ruby_hexdigits
36
37unsigned long
38ruby_scan_oct(const char *start, size_t len, size_t *retlen)
39{
40 register const char *s = start;
41 register unsigned long retval = 0;
42 size_t i;
43
44 for (i = 0; i < len; i++) {
45 if ((s[0] < '0') || ('7' < s[0])) {
46 break;
47 }
48 retval <<= 3;
49 retval |= *s++ - '0';
50 }
51 *retlen = (size_t)(s - start);
52 return retval;
53}
54
55unsigned long
56ruby_scan_hex(const char *start, size_t len, size_t *retlen)
57{
58 register const char *s = start;
59 register unsigned long retval = 0;
60 signed char d;
61 size_t i = 0;
62
63 for (i = 0; i < len; i++) {
64 d = ruby_digit36_to_number_table[(unsigned char)*s];
65 if (d < 0 || 15 < d) {
66 break;
67 }
68 retval <<= 4;
69 retval |= d;
70 s++;
71 }
72 *retlen = (size_t)(s - start);
73 return retval;
74}
75
76const signed char ruby_digit36_to_number_table[] = {
77 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
78 /*0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
79 /*1*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
80 /*2*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
81 /*3*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
82 /*4*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
83 /*5*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
84 /*6*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
85 /*7*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
86 /*8*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
87 /*9*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
88 /*a*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
89 /*b*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
90 /*c*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
91 /*d*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
92 /*e*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
93 /*f*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
94};
95
96NO_SANITIZE("unsigned-integer-overflow", extern unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow));
97unsigned long
98ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow)
99{
100 RBIMPL_ASSERT_OR_ASSUME(base >= 2);
101 RBIMPL_ASSERT_OR_ASSUME(base <= 36);
102
103 const char *start = str;
104 unsigned long ret = 0, x;
105 unsigned long mul_overflow = (~(unsigned long)0) / base;
106
107 *overflow = 0;
108
109 if (!len) {
110 *retlen = 0;
111 return 0;
112 }
113
114 do {
115 int d = ruby_digit36_to_number_table[(unsigned char)*str++];
116 if (d == -1 || base <= d) {
117 --str;
118 break;
119 }
120 if (mul_overflow < ret)
121 *overflow = 1;
122 ret *= base;
123 x = ret;
124 ret += d;
125 if (ret < x)
126 *overflow = 1;
127 } while (len < 0 || --len);
128 *retlen = str - start;
129 return ret;
130}
131
132unsigned long
133ruby_strtoul(const char *str, char **endptr, int base)
134{
135 int c, b, overflow;
136 int sign = 0;
137 size_t len;
138 unsigned long ret;
139 const char *subject_found = str;
140
141 if (base < 0) {
142 errno = EINVAL;
143 return 0;
144 }
145
146 if (base == 1 || 36 < base) {
147 errno = EINVAL;
148 return 0;
149 }
150
151 while ((c = *str) && ISSPACE(c))
152 str++;
153
154 if (c == '+') {
155 sign = 1;
156 str++;
157 }
158 else if (c == '-') {
159 sign = -1;
160 str++;
161 }
162
163 if (str[0] == '0') {
164 subject_found = str+1;
165 if (base == 0 || base == 16) {
166 if (str[1] == 'x' || str[1] == 'X') {
167 b = 16;
168 str += 2;
169 }
170 else {
171 b = base == 0 ? 8 : 16;
172 str++;
173 }
174 }
175 else {
176 b = base;
177 str++;
178 }
179 }
180 else {
181 b = base == 0 ? 10 : base;
182 }
183
184 ret = ruby_scan_digits(str, -1, b, &len, &overflow);
185
186 if (0 < len)
187 subject_found = str+len;
188
189 if (endptr)
190 *endptr = (char*)subject_found;
191
192 if (overflow) {
193 errno = ERANGE;
194 return ULONG_MAX;
195 }
196
197 if (sign < 0) {
198 ret = (unsigned long)(-(long)ret);
199 return ret;
200 }
201 else {
202 return ret;
203 }
204}
205
206#include <sys/types.h>
207#include <sys/stat.h>
208#ifdef HAVE_UNISTD_H
209#include <unistd.h>
210#endif
211#if defined(HAVE_FCNTL_H)
212#include <fcntl.h>
213#endif
214
215#ifndef S_ISDIR
216# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
217#endif
218
219typedef int (cmpfunc_t)(const void*, const void*, void*);
220
221#if !defined HAVE_GNU_QSORT_R
222#if defined HAVE_QSORT_S && defined RUBY_MSVCRT_VERSION
223/* In contrast to its name, Visual Studio qsort_s is incompatible with
224 * C11 in the order of the comparison function's arguments, and same
225 * as BSD qsort_r rather. */
226# define qsort_r(base, nel, size, arg, cmp) qsort_s(base, nel, size, cmp, arg)
227# define cmp_bsd_qsort cmp_ms_qsort
228# define HAVE_BSD_QSORT_R 1
229#endif
230
231#if defined HAVE_BSD_QSORT_R
232struct bsd_qsort_r_args {
233 cmpfunc_t *cmp;
234 void *arg;
235};
236
237static int
238cmp_bsd_qsort(void *d, const void *a, const void *b)
239{
240 const struct bsd_qsort_r_args *args = d;
241 return (*args->cmp)(a, b, args->arg);
242}
243
244void
245ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d)
246{
247 struct bsd_qsort_r_args args;
248 args.cmp = cmp;
249 args.arg = d;
250 qsort_r(base, nel, size, &args, cmp_bsd_qsort);
251}
252#elif defined HAVE_QSORT_S
253/* C11 qsort_s has the same arguments as GNU's, but uses
254 * runtime-constraints handler. */
255void
256ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d)
257{
258 if (!nel || !size) return; /* nothing to sort */
259
260 /* get rid of runtime-constraints handler for MT-safeness */
261 if (!base || !cmp) return;
262 if (nel > RSIZE_MAX || size > RSIZE_MAX) return;
263
264 qsort_s(base, nel, size, cmp, d);
265}
266# define HAVE_GNU_QSORT_R 1
267#else
268/* mm.c */
269
270#define mmtype long
271#define mmcount (16 / SIZEOF_LONG)
272#define A ((mmtype*)a)
273#define B ((mmtype*)b)
274#define C ((mmtype*)c)
275#define D ((mmtype*)d)
276
277#define mmstep (sizeof(mmtype) * mmcount)
278#define mmprepare(base, size) do {\
279 if (((VALUE)(base) % sizeof(mmtype)) == 0 && ((size) % sizeof(mmtype)) == 0) \
280 if ((size) >= mmstep) mmkind = 1;\
281 else mmkind = 0;\
282 else mmkind = -1;\
283 high = ((size) / mmstep) * mmstep;\
284 low = ((size) % mmstep);\
285} while (0)\
286
287#define mmarg mmkind, size, high, low
288#define mmargdecl int mmkind, size_t size, size_t high, size_t low
289
290static void mmswap_(register char *a, register char *b, mmargdecl)
291{
292 if (a == b) return;
293 if (mmkind >= 0) {
294 register mmtype s;
295#if mmcount > 1
296 if (mmkind > 0) {
297 register char *t = a + high;
298 do {
299 s = A[0]; A[0] = B[0]; B[0] = s;
300 s = A[1]; A[1] = B[1]; B[1] = s;
301#if mmcount > 2
302 s = A[2]; A[2] = B[2]; B[2] = s;
303#if mmcount > 3
304 s = A[3]; A[3] = B[3]; B[3] = s;
305#endif
306#endif
307 a += mmstep; b += mmstep;
308 } while (a < t);
309 }
310#endif
311 if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s;
312#if mmcount > 2
313 if (low >= 2 * sizeof(mmtype)) { s = A[1]; A[1] = B[1]; B[1] = s;
314#if mmcount > 3
315 if (low >= 3 * sizeof(mmtype)) {s = A[2]; A[2] = B[2]; B[2] = s;}
316#endif
317 }
318#endif
319 }
320 }
321 else {
322 register char *t = a + size, s;
323 do {s = *a; *a++ = *b; *b++ = s;} while (a < t);
324 }
325}
326#define mmswap(a,b) mmswap_((a),(b),mmarg)
327
328/* a, b, c = b, c, a */
329static void mmrot3_(register char *a, register char *b, register char *c, mmargdecl)
330{
331 if (mmkind >= 0) {
332 register mmtype s;
333#if mmcount > 1
334 if (mmkind > 0) {
335 register char *t = a + high;
336 do {
337 s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
338 s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
339#if mmcount > 2
340 s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;
341#if mmcount > 3
342 s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s;
343#endif
344#endif
345 a += mmstep; b += mmstep; c += mmstep;
346 } while (a < t);
347 }
348#endif
349 if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
350#if mmcount > 2
351 if (low >= 2 * sizeof(mmtype)) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
352#if mmcount > 3
353 if (low == 3 * sizeof(mmtype)) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}
354#endif
355 }
356#endif
357 }
358 }
359 else {
360 register char *t = a + size, s;
361 do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t);
362 }
363}
364#define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg)
365
366/* qs6.c */
367/*****************************************************/
368/* */
369/* qs6 (Quick sort function) */
370/* */
371/* by Tomoyuki Kawamura 1995.4.21 */
372/* kawamura@tokuyama.ac.jp */
373/*****************************************************/
374
375typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */
376#define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0) /* Push L,l,R,r */
377#define POP(ll,rr) do { --top; (ll) = top->LL; (rr) = top->RR; } while (0) /* Pop L,l,R,r */
378
379#define med3(a,b,c) ((*cmp)((a),(b),d)<0 ? \
380 ((*cmp)((b),(c),d)<0 ? (b) : ((*cmp)((a),(c),d)<0 ? (c) : (a))) : \
381 ((*cmp)((b),(c),d)>0 ? (b) : ((*cmp)((a),(c),d)<0 ? (a) : (c))))
382
383void
384ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d)
385{
386 register char *l, *r, *m; /* l,r:left,right group m:median point */
387 register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */
388 char *L = base; /* left end of current region */
389 char *R = (char*)base + size*(nel-1); /* right end of current region */
390 size_t chklim = 63; /* threshold of ordering element check */
391 enum {size_bits = sizeof(size) * CHAR_BIT};
392 stack_node stack[size_bits]; /* enough for size_t size */
393 stack_node *top = stack;
394 int mmkind;
395 size_t high, low, n;
396
397 if (nel <= 1) return; /* need not to sort */
398 mmprepare(base, size);
399 goto start;
400
401 nxt:
402 if (stack == top) return; /* return if stack is empty */
403 POP(L,R);
404
405 for (;;) {
406 start:
407 if (L + size == R) { /* 2 elements */
408 if ((*cmp)(L,R,d) > 0) mmswap(L,R);
409 goto nxt;
410 }
411
412 l = L; r = R;
413 n = (r - l + size) / size; /* number of elements */
414 m = l + size * (n >> 1); /* calculate median value */
415
416 if (n >= 60) {
417 register char *m1;
418 register char *m3;
419 if (n >= 200) {
420 n = size*(n>>3); /* number of bytes in splitting 8 */
421 {
422 register char *p1 = l + n;
423 register char *p2 = p1 + n;
424 register char *p3 = p2 + n;
425 m1 = med3(p1, p2, p3);
426 p1 = m + n;
427 p2 = p1 + n;
428 p3 = p2 + n;
429 m3 = med3(p1, p2, p3);
430 }
431 }
432 else {
433 n = size*(n>>2); /* number of bytes in splitting 4 */
434 m1 = l + n;
435 m3 = m + n;
436 }
437 m = med3(m1, m, m3);
438 }
439
440 if ((t = (*cmp)(l,m,d)) < 0) { /*3-5-?*/
441 if ((t = (*cmp)(m,r,d)) < 0) { /*3-5-7*/
442 if (chklim && nel >= chklim) { /* check if already ascending order */
443 char *p;
444 chklim = 0;
445 for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail;
446 goto nxt;
447 }
448 fail: goto loopA; /*3-5-7*/
449 }
450 if (t > 0) {
451 if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/
452 mmrot3(r,m,l); goto loopA; /*3-5-2*/
453 }
454 goto loopB; /*3-5-5*/
455 }
456
457 if (t > 0) { /*7-5-?*/
458 if ((t = (*cmp)(m,r,d)) > 0) { /*7-5-3*/
459 if (chklim && nel >= chklim) { /* check if already ascending order */
460 char *p;
461 chklim = 0;
462 for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2;
463 while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */
464 goto nxt;
465 }
466 fail2: mmswap(l,r); goto loopA; /*7-5-3*/
467 }
468 if (t < 0) {
469 if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/
470 mmrot3(l,m,r); goto loopA; /*7-5-6*/
471 }
472 mmswap(l,r); goto loopA; /*7-5-5*/
473 }
474
475 if ((t = (*cmp)(m,r,d)) < 0) {goto loopA;} /*5-5-7*/
476 if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/
477
478 /* determining splitting type in case 5-5-5 */ /*5-5-5*/
479 for (;;) {
480 if ((l += size) == r) goto nxt; /*5-5-5*/
481 if (l == m) continue;
482 if ((t = (*cmp)(l,m,d)) > 0) {mmswap(l,r); l = L; goto loopA;}/*575-5*/
483 if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/
484 }
485
486 loopA: eq_l = 1; eq_r = 1; /* splitting type A */ /* left <= median < right */
487 for (;;) {
488 for (;;) {
489 if ((l += size) == r)
490 {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
491 if (l == m) continue;
492 if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
493 if (t < 0) eq_l = 0;
494 }
495 for (;;) {
496 if (l == (r -= size))
497 {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
498 if (r == m) {m = l; break;}
499 if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
500 if (t == 0) break;
501 }
502 mmswap(l,r); /* swap left and right */
503 }
504
505 loopB: eq_l = 1; eq_r = 1; /* splitting type B */ /* left < median <= right */
506 for (;;) {
507 for (;;) {
508 if (l == (r -= size))
509 {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
510 if (r == m) continue;
511 if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
512 if (t > 0) eq_r = 0;
513 }
514 for (;;) {
515 if ((l += size) == r)
516 {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
517 if (l == m) {m = r; break;}
518 if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
519 if (t == 0) break;
520 }
521 mmswap(l,r); /* swap left and right */
522 }
523
524 fin:
525 if (eq_l == 0) /* need to sort left side */
526 if (eq_r == 0) /* need to sort right side */
527 if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */
528 else {PUSH(L,l); L = r;} /* sort right side first */
529 else R = l; /* need to sort left side only */
530 else if (eq_r == 0) L = r; /* need to sort right side only */
531 else goto nxt; /* need not to sort both sides */
532 }
533}
534#endif
535#endif /* !HAVE_GNU_QSORT_R */
536
537char *
538ruby_strdup(const char *str)
539{
540 char *tmp;
541 size_t len = strlen(str) + 1;
542
543 tmp = xmalloc(len);
544 memcpy(tmp, str, len);
545
546 return tmp;
547}
548
549char *
551{
552#if defined HAVE_GETCWD
553# undef RUBY_UNTYPED_DATA_WARNING
554# define RUBY_UNTYPED_DATA_WARNING 0
555# if defined NO_GETCWD_MALLOC
556 VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL);
557 int size = 200;
558 char *buf = xmalloc(size);
559
560 while (!getcwd(buf, size)) {
561 int e = errno;
562 if (e != ERANGE) {
563 xfree(buf);
564 DATA_PTR(guard) = NULL;
565 rb_syserr_fail(e, "getcwd");
566 }
567 size *= 2;
568 DATA_PTR(guard) = buf;
569 buf = xrealloc(buf, size);
570 }
571# else
572 VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, free, NULL);
573 char *buf, *cwd = getcwd(NULL, 0);
574 DATA_PTR(guard) = cwd;
575 if (!cwd) rb_sys_fail("getcwd");
576 buf = ruby_strdup(cwd); /* allocate by xmalloc */
577 free(cwd);
578# endif
579 DATA_PTR(RB_GC_GUARD(guard)) = NULL;
580#else
581# ifndef PATH_MAX
582# define PATH_MAX 8192
583# endif
584 char *buf = xmalloc(PATH_MAX+1);
585
586 if (!getwd(buf)) {
587 int e = errno;
588 xfree(buf);
589 rb_syserr_fail(e, "getwd");
590 }
591#endif
592 return buf;
593}
594
595void
596ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg)
597{
598 const char *end;
599 int len;
600
601 if (!str) return;
602 for (; *str; str = end) {
603 while (ISSPACE(*str) || *str == ',') str++;
604 if (!*str) break;
605 end = str;
606 while (*end && !ISSPACE(*end) && *end != ',') end++;
607 len = (int)(end - str); /* assume no string exceeds INT_MAX */
608 (*func)(str, len, arg);
609 }
610}
611
612#undef strtod
613#define strtod ruby_strtod
614#undef dtoa
615#define dtoa ruby_dtoa
616#undef hdtoa
617#define hdtoa ruby_hdtoa
618#include "missing/dtoa.c"
#define RBIMPL_ASSERT_OR_ASSUME(expr)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:229
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:133
#define ISSPACE
Old name of rb_isspace.
Definition ctype.h:88
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xrealloc
Old name of ruby_xrealloc.
Definition xmalloc.h:56
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3262
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3274
unsigned long ruby_scan_hex(const char *str, size_t len, size_t *ret)
Interprets the passed string a hexadecimal unsigned integer.
Definition util.c:56
const signed char ruby_digit36_to_number_table[]
Character to number mapping like ‘'a’->10,'b'->11etc.
Definition util.c:76
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition util.c:538
void ruby_each_words(const char *str, void(*func)(const char *word, int len, void *argv), void *argv)
Scans the passed string, with calling the callback function every time it encounters a "word".
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
char * ruby_getcwd(void)
This is our own version of getcwd(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition util.c:550
const char ruby_hexdigits[]
Characters that Ruby accepts as hexadecimal digits.
Definition util.c:34
unsigned long ruby_scan_oct(const char *str, size_t len, size_t *consumed)
Interprets the passed string as an octal unsigned integer.
Definition util.c:38
unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow)
Scans the passed string, assuming the string is a textual representation of an integer.
Definition util.c:98
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define Data_Wrap_Struct(klass, mark, free, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rdata.h:202
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:71
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:82
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40