Ruby  3.1.4p223 (2023-03-30 revision HEAD)
sprintf.c
1 /**********************************************************************
2 
3  sprintf.c -
4 
5  $Author$
6  created at: Fri Oct 15 10:39:26 JST 1993
7 
8  Copyright (C) 1993-2007 Yukihiro Matsumoto
9  Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10  Copyright (C) 2000 Information-technology Promotion Agency, Japan
11 
12 **********************************************************************/
13 
14 #include "ruby/internal/config.h"
15 
16 #include <math.h>
17 #include <stdarg.h>
18 
19 #ifdef HAVE_IEEEFP_H
20 # include <ieeefp.h>
21 #endif
22 
23 #include "id.h"
24 #include "internal.h"
25 #include "internal/error.h"
26 #include "internal/hash.h"
27 #include "internal/numeric.h"
28 #include "internal/object.h"
29 #include "internal/sanitizers.h"
30 #include "internal/symbol.h"
31 #include "ruby/encoding.h"
32 #include "ruby/re.h"
33 #include "ruby/util.h"
34 
35 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
36 
37 static char *fmt_setup(char*,size_t,int,int,int,int);
38 static char *ruby_ultoa(unsigned long val, char *endp, int base, int octzero);
39 
40 static char
41 sign_bits(int base, const char *p)
42 {
43  char c = '.';
44 
45  switch (base) {
46  case 16:
47  if (*p == 'X') c = 'F';
48  else c = 'f';
49  break;
50  case 8:
51  c = '7'; break;
52  case 2:
53  c = '1'; break;
54  }
55  return c;
56 }
57 
58 #define FNONE 0
59 #define FSHARP 1
60 #define FMINUS 2
61 #define FPLUS 4
62 #define FZERO 8
63 #define FSPACE 16
64 #define FWIDTH 32
65 #define FPREC 64
66 #define FPREC0 128
67 
68 #define CHECK(l) do {\
69  int cr = ENC_CODERANGE(result);\
70  while ((l) >= bsiz - blen) {\
71  bsiz*=2;\
72  if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\
73  }\
74  rb_str_resize(result, bsiz);\
75  ENC_CODERANGE_SET(result, cr);\
76  buf = RSTRING_PTR(result);\
77 } while (0)
78 
79 #define PUSH(s, l) do { \
80  CHECK(l);\
81  PUSH_(s, l);\
82 } while (0)
83 
84 #define PUSH_(s, l) do { \
85  memcpy(&buf[blen], (s), (l));\
86  blen += (l);\
87 } while (0)
88 
89 #define FILL(c, l) do { \
90  if ((l) <= 0) break;\
91  CHECK(l);\
92  FILL_(c, l);\
93 } while (0)
94 
95 #define FILL_(c, l) do { \
96  memset(&buf[blen], (c), (l));\
97  blen += (l);\
98 } while (0)
99 
100 #define GETARG() (nextvalue != Qundef ? nextvalue : \
101  GETNEXTARG())
102 
103 #define GETNEXTARG() ( \
104  check_next_arg(posarg, nextarg), \
105  (posarg = nextarg++, GETNTHARG(posarg)))
106 
107 #define GETPOSARG(n) ( \
108  check_pos_arg(posarg, (n)), \
109  (posarg = -1, GETNTHARG(n)))
110 
111 #define GETNTHARG(nth) \
112  (((nth) >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[(nth)])
113 
114 #define CHECKNAMEARG(name, len, enc) ( \
115  check_name_arg(posarg, name, len, enc), \
116  posarg = -2)
117 
118 #define GETNUM(n, val) \
119  (!(p = get_num(p, end, enc, &(n))) ? \
120  rb_raise(rb_eArgError, #val " too big") : (void)0)
121 
122 #define GETASTER(val) do { \
123  t = p++; \
124  n = 0; \
125  GETNUM(n, val); \
126  if (*p == '$') { \
127  tmp = GETPOSARG(n); \
128  } \
129  else { \
130  tmp = GETNEXTARG(); \
131  p = t; \
132  } \
133  (val) = NUM2INT(tmp); \
134 } while (0)
135 
136 static const char *
137 get_num(const char *p, const char *end, rb_encoding *enc, int *valp)
138 {
139  int next_n = *valp;
140  for (; p < end && rb_enc_isdigit(*p, enc); p++) {
141  if (MUL_OVERFLOW_INT_P(10, next_n))
142  return NULL;
143  next_n *= 10;
144  if (INT_MAX - (*p - '0') < next_n)
145  return NULL;
146  next_n += *p - '0';
147  }
148  if (p >= end) {
149  rb_raise(rb_eArgError, "malformed format string - %%*[0-9]");
150  }
151  *valp = next_n;
152  return p;
153 }
154 
155 static void
156 check_next_arg(int posarg, int nextarg)
157 {
158  switch (posarg) {
159  case -1:
160  rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg);
161  case -2:
162  rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg);
163  }
164 }
165 
166 static void
167 check_pos_arg(int posarg, int n)
168 {
169  if (posarg > 0) {
170  rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg);
171  }
172  if (posarg == -2) {
173  rb_raise(rb_eArgError, "numbered(%d) after named", n);
174  }
175  if (n < 1) {
176  rb_raise(rb_eArgError, "invalid index - %d$", n);
177  }
178 }
179 
180 static void
181 check_name_arg(int posarg, const char *name, int len, rb_encoding *enc)
182 {
183  if (posarg > 0) {
184  rb_enc_raise(enc, rb_eArgError, "named%.*s after unnumbered(%d)", len, name, posarg);
185  }
186  if (posarg == -1) {
187  rb_enc_raise(enc, rb_eArgError, "named%.*s after numbered", len, name);
188  }
189 }
190 
191 static VALUE
192 get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
193 {
194  VALUE tmp;
195 
196  if (*hash != Qundef) return *hash;
197  if (argc != 2) {
198  rb_raise(rb_eArgError, "one hash required");
199  }
200  tmp = rb_check_hash_type(argv[1]);
201  if (NIL_P(tmp)) {
202  rb_raise(rb_eArgError, "one hash required");
203  }
204  return (*hash = tmp);
205 }
206 
207 VALUE
208 rb_f_sprintf(int argc, const VALUE *argv)
209 {
210  return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
211 }
212 
213 VALUE
214 rb_str_format(int argc, const VALUE *argv, VALUE fmt)
215 {
216  enum {default_float_precision = 6};
217  rb_encoding *enc;
218  const char *p, *end;
219  char *buf;
220  long blen, bsiz;
221  VALUE result;
222 
223  long scanned = 0;
224  int coderange = ENC_CODERANGE_7BIT;
225  int width, prec, flags = FNONE;
226  int nextarg = 1;
227  int posarg = 0;
228  VALUE nextvalue;
229  VALUE tmp;
230  VALUE orig;
231  VALUE str;
232  volatile VALUE hash = Qundef;
233 
234 #define CHECK_FOR_WIDTH(f) \
235  if ((f) & FWIDTH) { \
236  rb_raise(rb_eArgError, "width given twice"); \
237  } \
238  if ((f) & FPREC0) { \
239  rb_raise(rb_eArgError, "width after precision"); \
240  }
241 #define CHECK_FOR_FLAGS(f) \
242  if ((f) & FWIDTH) { \
243  rb_raise(rb_eArgError, "flag after width"); \
244  } \
245  if ((f) & FPREC0) { \
246  rb_raise(rb_eArgError, "flag after precision"); \
247  }
248 
249  ++argc;
250  --argv;
251  StringValue(fmt);
252  enc = rb_enc_get(fmt);
253  orig = fmt;
254  fmt = rb_str_tmp_frozen_acquire(fmt);
255  p = RSTRING_PTR(fmt);
256  end = p + RSTRING_LEN(fmt);
257  blen = 0;
258  bsiz = 120;
259  result = rb_str_buf_new(bsiz);
260  rb_enc_associate(result, enc);
261  buf = RSTRING_PTR(result);
262  memset(buf, 0, bsiz);
263  ENC_CODERANGE_SET(result, coderange);
264 
265  for (; p < end; p++) {
266  const char *t;
267  int n;
268  VALUE sym = Qnil;
269 
270  for (t = p; t < end && *t != '%'; t++) ;
271  if (t + 1 == end) {
272  rb_raise(rb_eArgError, "incomplete format specifier; use %%%% (double %%) instead");
273  }
274  PUSH(p, t - p);
275  if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
276  scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &coderange);
277  ENC_CODERANGE_SET(result, coderange);
278  }
279  if (t >= end) {
280  /* end of fmt string */
281  goto sprint_exit;
282  }
283  p = t + 1; /* skip `%' */
284 
285  width = prec = -1;
286  nextvalue = Qundef;
287  retry:
288  switch (*p) {
289  default:
290  if (rb_enc_isprint(*p, enc))
291  rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
292  else
293  rb_raise(rb_eArgError, "malformed format string");
294  break;
295 
296  case ' ':
297  CHECK_FOR_FLAGS(flags);
298  flags |= FSPACE;
299  p++;
300  goto retry;
301 
302  case '#':
303  CHECK_FOR_FLAGS(flags);
304  flags |= FSHARP;
305  p++;
306  goto retry;
307 
308  case '+':
309  CHECK_FOR_FLAGS(flags);
310  flags |= FPLUS;
311  p++;
312  goto retry;
313 
314  case '-':
315  CHECK_FOR_FLAGS(flags);
316  flags |= FMINUS;
317  p++;
318  goto retry;
319 
320  case '0':
321  CHECK_FOR_FLAGS(flags);
322  flags |= FZERO;
323  p++;
324  goto retry;
325 
326  case '1': case '2': case '3': case '4':
327  case '5': case '6': case '7': case '8': case '9':
328  n = 0;
329  GETNUM(n, width);
330  if (*p == '$') {
331  if (nextvalue != Qundef) {
332  rb_raise(rb_eArgError, "value given twice - %d$", n);
333  }
334  nextvalue = GETPOSARG(n);
335  p++;
336  goto retry;
337  }
338  CHECK_FOR_WIDTH(flags);
339  width = n;
340  flags |= FWIDTH;
341  goto retry;
342 
343  case '<':
344  case '{':
345  {
346  const char *start = p;
347  char term = (*p == '<') ? '>' : '}';
348  int len;
349 
350  for (; p < end && *p != term; ) {
351  p += rb_enc_mbclen(p, end, enc);
352  }
353  if (p >= end) {
354  rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
355  }
356 #if SIZEOF_INT < SIZEOF_SIZE_T
357  if ((size_t)(p - start) >= INT_MAX) {
358  const int message_limit = 20;
359  len = (int)(rb_enc_right_char_head(start, start + message_limit, p, enc) - start);
361  "too long name (%"PRIuSIZE" bytes) - %.*s...%c",
362  (size_t)(p - start - 2), len, start, term);
363  }
364 #endif
365  len = (int)(p - start + 1); /* including parenthesis */
366  if (sym != Qnil) {
367  rb_enc_raise(enc, rb_eArgError, "named%.*s after <%"PRIsVALUE">",
368  len, start, rb_sym2str(sym));
369  }
370  CHECKNAMEARG(start, len, enc);
371  get_hash(&hash, argc, argv);
372  sym = rb_check_symbol_cstr(start + 1,
373  len - 2 /* without parenthesis */,
374  enc);
375  if (!NIL_P(sym)) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
376  if (nextvalue == Qundef) {
377  if (NIL_P(sym)) {
378  sym = rb_sym_intern(start + 1,
379  len - 2 /* without parenthesis */,
380  enc);
381  }
382  nextvalue = rb_hash_default_value(hash, sym);
383  if (NIL_P(nextvalue)) {
384  rb_key_err_raise(rb_enc_sprintf(enc, "key%.*s not found", len, start), hash, sym);
385  }
386  }
387  if (term == '}') goto format_s;
388  p++;
389  goto retry;
390  }
391 
392  case '*':
393  CHECK_FOR_WIDTH(flags);
394  flags |= FWIDTH;
395  GETASTER(width);
396  if (width < 0) {
397  flags |= FMINUS;
398  width = -width;
399  if (width < 0) rb_raise(rb_eArgError, "width too big");
400  }
401  p++;
402  goto retry;
403 
404  case '.':
405  if (flags & FPREC0) {
406  rb_raise(rb_eArgError, "precision given twice");
407  }
408  flags |= FPREC|FPREC0;
409 
410  prec = 0;
411  p++;
412  if (*p == '*') {
413  GETASTER(prec);
414  if (prec < 0) { /* ignore negative precision */
415  flags &= ~FPREC;
416  }
417  p++;
418  goto retry;
419  }
420 
421  GETNUM(prec, precision);
422  goto retry;
423 
424  case '\n':
425  case '\0':
426  p--;
427  /* fall through */
428  case '%':
429  if (flags != FNONE) {
430  rb_raise(rb_eArgError, "invalid format character - %%");
431  }
432  PUSH("%", 1);
433  break;
434 
435  case 'c':
436  {
437  VALUE val = GETARG();
438  VALUE tmp;
439  unsigned int c;
440  int n;
441 
442  tmp = rb_check_string_type(val);
443  if (!NIL_P(tmp)) {
444  if (rb_enc_strlen(RSTRING_PTR(tmp),RSTRING_END(tmp),enc) != 1) {
445  rb_raise(rb_eArgError, "%%c requires a character");
446  }
447  c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, enc);
448  RB_GC_GUARD(tmp);
449  }
450  else {
451  c = NUM2INT(val);
452  n = rb_enc_codelen(c, enc);
453  }
454  if (n <= 0) {
455  rb_raise(rb_eArgError, "invalid character");
456  }
457  if (!(flags & FWIDTH)) {
458  CHECK(n);
459  rb_enc_mbcput(c, &buf[blen], enc);
460  blen += n;
461  }
462  else if ((flags & FMINUS)) {
463  CHECK(n);
464  rb_enc_mbcput(c, &buf[blen], enc);
465  blen += n;
466  if (width > 1) FILL(' ', width-1);
467  }
468  else {
469  if (width > 1) FILL(' ', width-1);
470  CHECK(n);
471  rb_enc_mbcput(c, &buf[blen], enc);
472  blen += n;
473  }
474  }
475  break;
476 
477  case 's':
478  case 'p':
479  format_s:
480  {
481  VALUE arg = GETARG();
482  long len, slen;
483 
484  if (*p == 'p') {
485  str = rb_inspect(arg);
486  }
487  else {
488  str = rb_obj_as_string(arg);
489  }
490  len = RSTRING_LEN(str);
491  rb_str_set_len(result, blen);
492  if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
493  int cr = coderange;
494  scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr);
495  ENC_CODERANGE_SET(result,
496  (cr == ENC_CODERANGE_UNKNOWN ?
497  ENC_CODERANGE_BROKEN : (coderange = cr)));
498  }
499  enc = rb_enc_check(result, str);
500  if (flags&(FPREC|FWIDTH)) {
501  slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc);
502  if (slen < 0) {
503  rb_raise(rb_eArgError, "invalid mbstring sequence");
504  }
505  if ((flags&FPREC) && (prec < slen)) {
506  char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str),
507  prec, enc);
508  slen = prec;
509  len = p - RSTRING_PTR(str);
510  }
511  /* need to adjust multi-byte string pos */
512  if ((flags&FWIDTH) && (width > slen)) {
513  width -= (int)slen;
514  if (!(flags&FMINUS)) {
515  FILL(' ', width);
516  width = 0;
517  }
518  CHECK(len);
519  memcpy(&buf[blen], RSTRING_PTR(str), len);
520  RB_GC_GUARD(str);
521  blen += len;
522  if (flags&FMINUS) {
523  FILL(' ', width);
524  }
525  rb_enc_associate(result, enc);
526  break;
527  }
528  }
529  PUSH(RSTRING_PTR(str), len);
530  RB_GC_GUARD(str);
531  rb_enc_associate(result, enc);
532  }
533  break;
534 
535  case 'd':
536  case 'i':
537  case 'o':
538  case 'x':
539  case 'X':
540  case 'b':
541  case 'B':
542  case 'u':
543  {
544  volatile VALUE val = GETARG();
545  int valsign;
546  char nbuf[BIT_DIGITS(SIZEOF_LONG*CHAR_BIT)+2], *s;
547  const char *prefix = 0;
548  int sign = 0, dots = 0;
549  char sc = 0;
550  long v = 0;
551  int base, bignum = 0;
552  int len;
553 
554  switch (*p) {
555  case 'd':
556  case 'i':
557  case 'u':
558  sign = 1; break;
559  case 'o':
560  case 'x':
561  case 'X':
562  case 'b':
563  case 'B':
564  if (flags&(FPLUS|FSPACE)) sign = 1;
565  break;
566  }
567  if (flags & FSHARP) {
568  switch (*p) {
569  case 'o':
570  prefix = "0"; break;
571  case 'x':
572  prefix = "0x"; break;
573  case 'X':
574  prefix = "0X"; break;
575  case 'b':
576  prefix = "0b"; break;
577  case 'B':
578  prefix = "0B"; break;
579  }
580  }
581 
582  bin_retry:
583  switch (TYPE(val)) {
584  case T_FLOAT:
585  if (FIXABLE(RFLOAT_VALUE(val))) {
586  val = LONG2FIX((long)RFLOAT_VALUE(val));
587  goto bin_retry;
588  }
589  val = rb_dbl2big(RFLOAT_VALUE(val));
590  if (FIXNUM_P(val)) goto bin_retry;
591  bignum = 1;
592  break;
593  case T_STRING:
594  val = rb_str_to_inum(val, 0, TRUE);
595  goto bin_retry;
596  case T_BIGNUM:
597  bignum = 1;
598  break;
599  case T_FIXNUM:
600  v = FIX2LONG(val);
601  break;
602  default:
603  val = rb_Integer(val);
604  goto bin_retry;
605  }
606 
607  switch (*p) {
608  case 'o':
609  base = 8; break;
610  case 'x':
611  case 'X':
612  base = 16; break;
613  case 'b':
614  case 'B':
615  base = 2; break;
616  case 'u':
617  case 'd':
618  case 'i':
619  default:
620  base = 10; break;
621  }
622 
623  if (base != 10) {
624  int numbits = ffs(base)-1;
625  size_t abs_nlz_bits;
626  size_t numdigits = rb_absint_numwords(val, numbits, &abs_nlz_bits);
627  long i;
628  if (INT_MAX-1 < numdigits) /* INT_MAX is used because rb_long2int is used later. */
629  rb_raise(rb_eArgError, "size too big");
630  if (sign) {
631  if (numdigits == 0)
632  numdigits = 1;
633  tmp = rb_str_new(NULL, numdigits);
634  valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
635  1, CHAR_BIT-numbits, INTEGER_PACK_BIG_ENDIAN);
636  for (i = 0; i < RSTRING_LEN(tmp); i++)
637  RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
638  s = RSTRING_PTR(tmp);
639  if (valsign < 0) {
640  sc = '-';
641  width--;
642  }
643  else if (flags & FPLUS) {
644  sc = '+';
645  width--;
646  }
647  else if (flags & FSPACE) {
648  sc = ' ';
649  width--;
650  }
651  }
652  else {
653  /* Following conditional "numdigits++" guarantees the
654  * most significant digit as
655  * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
656  * - '0' for zero
657  * - not '0' for positive numbers.
658  *
659  * It also guarantees the most significant two
660  * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
661  * or '00'. */
662  if (numdigits == 0 ||
663  ((abs_nlz_bits != (size_t)(numbits-1) ||
664  !rb_absint_singlebit_p(val)) &&
665  (!bignum ? v < 0 : BIGNUM_NEGATIVE_P(val))))
666  numdigits++;
667  tmp = rb_str_new(NULL, numdigits);
668  valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
669  1, CHAR_BIT-numbits, INTEGER_PACK_2COMP | INTEGER_PACK_BIG_ENDIAN);
670  for (i = 0; i < RSTRING_LEN(tmp); i++)
671  RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
672  s = RSTRING_PTR(tmp);
673  dots = valsign < 0;
674  }
675  len = rb_long2int(RSTRING_END(tmp) - s);
676  }
677  else if (!bignum) {
678  valsign = 1;
679  if (v < 0) {
680  v = -v;
681  sc = '-';
682  width--;
683  valsign = -1;
684  }
685  else if (flags & FPLUS) {
686  sc = '+';
687  width--;
688  }
689  else if (flags & FSPACE) {
690  sc = ' ';
691  width--;
692  }
693  s = ruby_ultoa((unsigned long)v, nbuf + sizeof(nbuf), 10, 0);
694  len = (int)(nbuf + sizeof(nbuf) - s);
695  }
696  else {
697  tmp = rb_big2str(val, 10);
698  s = RSTRING_PTR(tmp);
699  valsign = 1;
700  if (s[0] == '-') {
701  s++;
702  sc = '-';
703  width--;
704  valsign = -1;
705  }
706  else if (flags & FPLUS) {
707  sc = '+';
708  width--;
709  }
710  else if (flags & FSPACE) {
711  sc = ' ';
712  width--;
713  }
714  len = rb_long2int(RSTRING_END(tmp) - s);
715  }
716 
717  if (dots) {
718  prec -= 2;
719  width -= 2;
720  }
721 
722  if (*p == 'X') {
723  char *pp = s;
724  int c;
725  while ((c = (int)(unsigned char)*pp) != 0) {
726  *pp = rb_enc_toupper(c, enc);
727  pp++;
728  }
729  }
730  if (prefix && !prefix[1]) { /* octal */
731  if (dots) {
732  prefix = 0;
733  }
734  else if (len == 1 && *s == '0') {
735  len = 0;
736  if (flags & FPREC) prec--;
737  }
738  else if ((flags & FPREC) && (prec > len)) {
739  prefix = 0;
740  }
741  }
742  else if (len == 1 && *s == '0') {
743  prefix = 0;
744  }
745  if (prefix) {
746  width -= (int)strlen(prefix);
747  }
748  if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
749  prec = width;
750  width = 0;
751  }
752  else {
753  if (prec < len) {
754  if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
755  prec = len;
756  }
757  width -= prec;
758  }
759  if (!(flags&FMINUS)) {
760  FILL(' ', width);
761  width = 0;
762  }
763  if (sc) PUSH(&sc, 1);
764  if (prefix) {
765  int plen = (int)strlen(prefix);
766  PUSH(prefix, plen);
767  }
768  if (dots) PUSH("..", 2);
769  if (prec > len) {
770  CHECK(prec - len);
771  if (!sign && valsign < 0) {
772  char c = sign_bits(base, p);
773  FILL_(c, prec - len);
774  }
775  else if ((flags & (FMINUS|FPREC)) != FMINUS) {
776  FILL_('0', prec - len);
777  }
778  }
779  PUSH(s, len);
780  RB_GC_GUARD(tmp);
781  FILL(' ', width);
782  }
783  break;
784 
785  case 'f':
786  {
787  VALUE val = GETARG(), num, den;
788  int sign = (flags&FPLUS) ? 1 : 0, zero = 0;
789  long len, fill;
790  if (RB_INTEGER_TYPE_P(val)) {
791  den = INT2FIX(1);
792  num = val;
793  }
794  else if (RB_TYPE_P(val, T_RATIONAL)) {
795  den = rb_rational_den(val);
796  num = rb_rational_num(val);
797  }
798  else {
799  nextvalue = val;
800  goto float_value;
801  }
802  if (!(flags&FPREC)) prec = default_float_precision;
803  if (FIXNUM_P(num)) {
804  if ((SIGNED_VALUE)num < 0) {
805  long n = -FIX2LONG(num);
806  num = LONG2FIX(n);
807  sign = -1;
808  }
809  }
810  else if (BIGNUM_NEGATIVE_P(num)) {
811  sign = -1;
812  num = rb_big_uminus(num);
813  }
814  if (den != INT2FIX(1)) {
815  num = rb_int_mul(num, rb_int_positive_pow(10, prec));
816  num = rb_int_plus(num, rb_int_idiv(den, INT2FIX(2)));
817  num = rb_int_idiv(num, den);
818  }
819  else if (prec >= 0) {
820  zero = prec;
821  }
822  val = rb_int2str(num, 10);
823  len = RSTRING_LEN(val) + zero;
824  if (prec >= len) len = prec + 1; /* integer part 0 */
825  if (sign || (flags&FSPACE)) ++len;
826  if (prec > 0) ++len; /* period */
827  fill = width > len ? width - len : 0;
828  CHECK(fill + len);
829  if (fill && !(flags&(FMINUS|FZERO))) {
830  FILL_(' ', fill);
831  }
832  if (sign || (flags&FSPACE)) {
833  buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' ';
834  }
835  if (fill && (flags&(FMINUS|FZERO)) == FZERO) {
836  FILL_('0', fill);
837  }
838  len = RSTRING_LEN(val) + zero;
839  t = RSTRING_PTR(val);
840  if (len > prec) {
841  PUSH_(t, len - prec);
842  }
843  else {
844  buf[blen++] = '0';
845  }
846  if (prec > 0) {
847  buf[blen++] = '.';
848  }
849  if (zero) {
850  FILL_('0', zero);
851  }
852  else if (prec > len) {
853  FILL_('0', prec - len);
854  PUSH_(t, len);
855  }
856  else if (prec > 0) {
857  PUSH_(t + len - prec, prec);
858  }
859  if (fill && (flags&FMINUS)) {
860  FILL_(' ', fill);
861  }
862  RB_GC_GUARD(val);
863  break;
864  }
865  case 'g':
866  case 'G':
867  case 'e':
868  case 'E':
869  /* TODO: rational support */
870  case 'a':
871  case 'A':
872  float_value:
873  {
874  VALUE val = GETARG();
875  double fval;
876 
877  fval = RFLOAT_VALUE(rb_Float(val));
878  if (!isfinite(fval)) {
879  const char *expr;
880  int need;
881  int elen;
882  char sign = '\0';
883 
884  if (isnan(fval)) {
885  expr = "NaN";
886  }
887  else {
888  expr = "Inf";
889  }
890  need = (int)strlen(expr);
891  elen = need;
892  if (!isnan(fval) && fval < 0.0)
893  sign = '-';
894  else if (flags & (FPLUS|FSPACE))
895  sign = (flags & FPLUS) ? '+' : ' ';
896  if (sign)
897  ++need;
898  if ((flags & FWIDTH) && need < width)
899  need = width;
900 
901  FILL(' ', need);
902  if (flags & FMINUS) {
903  if (sign)
904  buf[blen - need--] = sign;
905  memcpy(&buf[blen - need], expr, elen);
906  }
907  else {
908  if (sign)
909  buf[blen - elen - 1] = sign;
910  memcpy(&buf[blen - elen], expr, elen);
911  }
912  break;
913  }
914  else {
915  int cr = ENC_CODERANGE(result);
916  char fbuf[2*BIT_DIGITS(SIZEOF_INT*CHAR_BIT)+10];
917  char *fmt = fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
918  rb_str_set_len(result, blen);
919  rb_str_catf(result, fmt, fval);
920  ENC_CODERANGE_SET(result, cr);
921  bsiz = rb_str_capacity(result);
922  RSTRING_GETMEM(result, buf, blen);
923  }
924  }
925  break;
926  }
927  flags = FNONE;
928  }
929 
930  sprint_exit:
931  rb_str_tmp_frozen_release(orig, fmt);
932  /* XXX - We cannot validate the number of arguments if (digit)$ style used.
933  */
934  if (posarg >= 0 && nextarg < argc) {
935  const char *mesg = "too many arguments for format string";
936  if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg);
937  if (RTEST(ruby_verbose)) rb_warn("%s", mesg);
938  }
939  rb_str_resize(result, blen);
940 
941  return result;
942 }
943 
944 static char *
945 fmt_setup(char *buf, size_t size, int c, int flags, int width, int prec)
946 {
947  buf += size;
948  *--buf = '\0';
949  *--buf = c;
950 
951  if (flags & FPREC) {
952  buf = ruby_ultoa(prec, buf, 10, 0);
953  *--buf = '.';
954  }
955 
956  if (flags & FWIDTH) {
957  buf = ruby_ultoa(width, buf, 10, 0);
958  }
959 
960  if (flags & FSPACE) *--buf = ' ';
961  if (flags & FZERO) *--buf = '0';
962  if (flags & FMINUS) *--buf = '-';
963  if (flags & FPLUS) *--buf = '+';
964  if (flags & FSHARP) *--buf = '#';
965  *--buf = '%';
966  return buf;
967 }
968 
969 #undef FILE
970 #define FILE rb_printf_buffer
971 #define __sbuf rb_printf_sbuf
972 #define __sFILE rb_printf_sfile
973 #undef feof
974 #undef ferror
975 #undef clearerr
976 #undef fileno
977 #if SIZEOF_LONG < SIZEOF_LONG_LONG
978 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP
979 /* actually this doesn't mean a pointer is strictly 64bit, but just
980  * quad_t size */
981 # define _HAVE_LLP64_
982 # endif
983 # define _HAVE_SANE_QUAD_
984 # define quad_t LONG_LONG
985 # define u_quad_t unsigned LONG_LONG
986 #endif
987 #define FLOATING_POINT 1
988 #define BSD__dtoa ruby_dtoa
989 #define BSD__hdtoa ruby_hdtoa
990 #ifdef RUBY_PRI_VALUE_MARK
991 # define PRI_EXTRA_MARK RUBY_PRI_VALUE_MARK
992 #endif
993 #define lower_hexdigits (ruby_hexdigits+0)
994 #define upper_hexdigits (ruby_hexdigits+16)
995 #include "vsnprintf.c"
996 
997 static char *
998 ruby_ultoa(unsigned long val, char *endp, int base, int flags)
999 {
1000  const char *xdigs = lower_hexdigits;
1001  int octzero = flags & FSHARP;
1002  return BSD__ultoa(val, endp, base, octzero, xdigs);
1003 }
1004 
1005 static int ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
1006 
1007 int
1008 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1009 {
1010  if (str && (ssize_t)n < 1)
1011  return (EOF);
1012  return ruby_do_vsnprintf(str, n, fmt, ap);
1013 }
1014 
1015 static int
1016 ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1017 {
1018  ssize_t ret;
1019  rb_printf_buffer f;
1020 
1021  f._flags = __SWR | __SSTR;
1022  f._bf._base = f._p = (unsigned char *)str;
1023  f._bf._size = f._w = str ? (n - 1) : 0;
1024  f.vwrite = BSD__sfvwrite;
1025  f.vextra = 0;
1026  ret = BSD_vfprintf(&f, fmt, ap);
1027  if (str) *f._p = 0;
1028 #if SIZEOF_SIZE_T > SIZEOF_INT
1029  if (n > INT_MAX) return INT_MAX;
1030 #endif
1031  return (int)ret;
1032 }
1033 
1034 int
1035 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
1036 {
1037  int ret;
1038  va_list ap;
1039 
1040  if (str && (ssize_t)n < 1)
1041  return (EOF);
1042 
1043  va_start(ap, fmt);
1044  ret = ruby_do_vsnprintf(str, n, fmt, ap);
1045  va_end(ap);
1046  return ret;
1047 }
1048 
1049 typedef struct {
1050  rb_printf_buffer base;
1051  volatile VALUE value;
1053 
1054 static int
1055 ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio)
1056 {
1057  struct __siov *iov;
1058  VALUE result = (VALUE)fp->_bf._base;
1059  char *buf = (char*)fp->_p;
1060  long len, n;
1061  long blen = buf - RSTRING_PTR(result), bsiz = fp->_w;
1062 
1063  if (RBASIC(result)->klass) {
1064  rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1065  }
1066  if (uio->uio_resid == 0)
1067  return 0;
1068 #if SIZE_MAX > LONG_MAX
1069  if (uio->uio_resid >= LONG_MAX)
1070  rb_raise(rb_eRuntimeError, "too big string");
1071 #endif
1072  len = (long)uio->uio_resid;
1073  CHECK(len);
1074  buf += blen;
1075  fp->_w = bsiz;
1076  for (iov = uio->uio_iov; len > 0; ++iov) {
1077  MEMCPY(buf, iov->iov_base, char, n = iov->iov_len);
1078  buf += n;
1079  len -= n;
1080  }
1081  fp->_p = (unsigned char *)buf;
1082  rb_str_set_len(result, buf - RSTRING_PTR(result));
1083  return 0;
1084 }
1085 
1086 static const char *
1087 ruby__sfvextra(rb_printf_buffer *fp, size_t valsize, void *valp, long *sz, int sign)
1088 {
1089  VALUE value, result = (VALUE)fp->_bf._base;
1090  rb_encoding *enc;
1091  char *cp;
1092 
1093  if (valsize != sizeof(VALUE)) return 0;
1094  value = *(VALUE *)valp;
1095  if (RBASIC(result)->klass) {
1096  rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1097  }
1098  if (sign == '+') {
1099  if (RB_TYPE_P(value, T_CLASS)) {
1100 # define LITERAL(str) (*sz = rb_strlen_lit(str), str)
1101 
1102  if (value == rb_cNilClass) {
1103  return LITERAL("nil");
1104  }
1105  else if (value == rb_cInteger) {
1106  return LITERAL("Integer");
1107  }
1108  else if (value == rb_cSymbol) {
1109  return LITERAL("Symbol");
1110  }
1111  else if (value == rb_cTrueClass) {
1112  return LITERAL("true");
1113  }
1114  else if (value == rb_cFalseClass) {
1115  return LITERAL("false");
1116  }
1117 # undef LITERAL
1118  }
1119  value = rb_inspect(value);
1120  }
1121  else if (SYMBOL_P(value)) {
1122  value = rb_sym2str(value);
1123  if (sign == ' ' && !rb_str_symname_p(value)) {
1124  value = rb_str_escape(value);
1125  }
1126  }
1127  else {
1128  value = rb_obj_as_string(value);
1129  if (sign == ' ') value = QUOTE(value);
1130  }
1131  enc = rb_enc_compatible(result, value);
1132  if (enc) {
1133  rb_enc_associate(result, enc);
1134  }
1135  else {
1136  enc = rb_enc_get(result);
1137  value = rb_str_conv_enc_opts(value, rb_enc_get(value), enc,
1139  Qnil);
1140  *(volatile VALUE *)valp = value;
1141  }
1142  StringValueCStr(value);
1143  RSTRING_GETMEM(value, cp, *sz);
1144  ((rb_printf_buffer_extra *)fp)->value = value;
1145  return cp;
1146 }
1147 
1148 VALUE
1149 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
1150 {
1151  rb_printf_buffer_extra buffer;
1152 #define f buffer.base
1153  VALUE result;
1154 
1155  f._flags = __SWR | __SSTR;
1156  f._bf._size = 0;
1157  f._w = 120;
1158  result = rb_str_buf_new(f._w);
1159  if (enc) {
1160  if (rb_enc_mbminlen(enc) > 1) {
1161  /* the implementation deeply depends on plain char */
1162  rb_raise(rb_eArgError, "cannot construct wchar_t based encoding string: %s",
1163  rb_enc_name(enc));
1164  }
1165  rb_enc_associate(result, enc);
1166  }
1167  f._bf._base = (unsigned char *)result;
1168  f._p = (unsigned char *)RSTRING_PTR(result);
1169  RBASIC_CLEAR_CLASS(result);
1170  f.vwrite = ruby__sfvwrite;
1171  f.vextra = ruby__sfvextra;
1172  buffer.value = 0;
1173  BSD_vfprintf(&f, fmt, ap);
1174  RBASIC_SET_CLASS_RAW(result, rb_cString);
1175  rb_str_resize(result, (char *)f._p - RSTRING_PTR(result));
1176 #undef f
1177 
1178  return result;
1179 }
1180 
1181 VALUE
1182 rb_enc_sprintf(rb_encoding *enc, const char *format, ...)
1183 {
1184  VALUE result;
1185  va_list ap;
1186 
1187  va_start(ap, format);
1188  result = rb_enc_vsprintf(enc, format, ap);
1189  va_end(ap);
1190 
1191  return result;
1192 }
1193 
1194 VALUE
1195 rb_vsprintf(const char *fmt, va_list ap)
1196 {
1197  return rb_enc_vsprintf(NULL, fmt, ap);
1198 }
1199 
1200 VALUE
1201 rb_sprintf(const char *format, ...)
1202 {
1203  VALUE result;
1204  va_list ap;
1205 
1206  va_start(ap, format);
1207  result = rb_vsprintf(format, ap);
1208  va_end(ap);
1209 
1210  return result;
1211 }
1212 
1213 VALUE
1214 rb_str_vcatf(VALUE str, const char *fmt, va_list ap)
1215 {
1216  rb_printf_buffer_extra buffer;
1217 #define f buffer.base
1218  VALUE klass;
1219 
1220  StringValue(str);
1221  rb_str_modify(str);
1222  f._flags = __SWR | __SSTR;
1223  f._bf._size = 0;
1224  f._w = rb_str_capacity(str);
1225  f._bf._base = (unsigned char *)str;
1226  f._p = (unsigned char *)RSTRING_END(str);
1227  klass = RBASIC(str)->klass;
1228  RBASIC_CLEAR_CLASS(str);
1229  f.vwrite = ruby__sfvwrite;
1230  f.vextra = ruby__sfvextra;
1231  buffer.value = 0;
1232  BSD_vfprintf(&f, fmt, ap);
1233  RBASIC_SET_CLASS_RAW(str, klass);
1234  rb_str_resize(str, (char *)f._p - RSTRING_PTR(str));
1235 #undef f
1236 
1237  return str;
1238 }
1239 
1240 VALUE
1241 rb_str_catf(VALUE str, const char *format, ...)
1242 {
1243  va_list ap;
1244 
1245  va_start(ap, format);
1246  str = rb_str_vcatf(str, format, ap);
1247  va_end(ap);
1248 
1249  return str;
1250 }
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
Definition: ctype.h:166
int rb_enc_toupper(int c, rb_encoding *enc)
Identical to rb_toupper(), except it additionally takes an encoding.
Definition: encoding.c:1294
static bool rb_enc_isdigit(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isdigit(), except it additionally takes an encoding.
Definition: ctype.h:194
VALUE rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
Identical to rb_enc_sprintf(), except it takes a va_list instead of variadic arguments.
Definition: sprintf.c:1149
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
Definition: sprintf.c:1182
#define TYPE(_)
Old name of rb_type.
Definition: value_type.h:107
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition: value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition: coderange.h:180
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition: double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition: value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition: value_type.h:64
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition: value_type.h:57
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
Definition: transcode.h:523
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition: value_type.h:63
#define ENC_CODERANGE(obj)
Old name of RB_ENC_CODERANGE.
Definition: coderange.h:184
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
Definition: coderange.h:179
#define FIXABLE
Old name of RB_FIXABLE.
Definition: fixnum.h:25
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
Definition: transcode.h:521
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition: value_type.h:76
#define NUM2INT
Old name of RB_NUM2INT.
Definition: int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition: coderange.h:182
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition: value_type.h:58
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition: coderange.h:186
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition: value_type.h:88
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition: error.h:470
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3025
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition: error.h:459
VALUE rb_eRuntimeError
RuntimeError exception.
Definition: error.c:1097
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition: error.c:418
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1100
void rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt,...)
Identical to rb_raise(), except it additionally takes an encoding.
Definition: error.c:3006
VALUE rb_Float(VALUE val)
This is the logic behind Kernel#Float.
Definition: object.c:3441
VALUE rb_cInteger
Module class.
Definition: numeric.c:192
VALUE rb_cNilClass
NilClass class.
Definition: object.c:55
VALUE rb_Integer(VALUE val)
This is the logic behind Kernel#Integer.
Definition: object.c:3070
VALUE rb_cFalseClass
FalseClass class.
Definition: object.c:57
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition: object.c:564
VALUE rb_cSymbol
Sumbol class.
Definition: string.c:81
VALUE rb_cTrueClass
TrueClass class.
Definition: object.c:56
VALUE rb_cString
String class.
Definition: string.c:80
Encoding relates APIs.
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Identical to rb_enc_associate(), except it takes an encoding itself instead of its index.
Definition: encoding.c:1066
int rb_enc_codelen(int code, rb_encoding *enc)
Queries the number of bytes requested to represent the passed code point using the passed encoding.
Definition: encoding.c:1284
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Look for the "common" encoding between the two.
Definition: encoding.c:1176
unsigned int rb_enc_codepoint_len(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition: encoding.c:1270
static char * rb_enc_right_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the right boundary of a character.
Definition: encoding.h:718
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Identical to rb_enc_compatible(), except it raises an exception instead of returning NULL.
Definition: encoding.c:1097
static int rb_enc_mbcput(unsigned int c, void *buf, rb_encoding *enc)
Identical to rb_enc_uint_chr(), except it writes back to the passed buffer instead of allocating one.
Definition: encoding.h:657
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
Definition: encoding.c:1222
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
Definition: encoding.c:1072
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition: encoding.h:433
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
Definition: encoding.h:448
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
Definition: string.c:2735
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
Definition: string.c:1067
long rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
Definition: string.c:2071
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition: string.c:668
VALUE rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id_cstr(), except for the return type.
Definition: symbol.c:1151
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Exports an integer into a buffer.
Definition: bignum.c:3559
VALUE rb_str_to_inum(VALUE str, int base, int badcheck)
Identical to rb_cstr2inum(), except it takes Ruby's strings instead of C's.
Definition: bignum.c:4280
size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
Calculates the number of words needed represent the absolute value of the passed integer.
Definition: bignum.c:3393
int rb_absint_singlebit_p(VALUE val)
Tests abs(val) consists only of a bit or not.
Definition: bignum.c:3458
VALUE rb_big2str(VALUE x, int base)
Generates a place-value representation of the passed integer.
Definition: bignum.c:5096
#define INTEGER_PACK_BIG_ENDIAN
Big endian combination.
Definition: bignum.h:572
VALUE rb_dbl2big(double d)
Converts a C's double into a bignum.
Definition: bignum.c:5254
#define INTEGER_PACK_2COMP
Uses 2's complement representation.
Definition: bignum.h:549
VALUE rb_check_hash_type(VALUE obj)
Try converting an object to its hash representation using its to_hash method, if any.
Definition: hash.c:1896
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Identical to rb_hash_lookup(), except you can specify what to return on misshits.
Definition: hash.c:2095
VALUE rb_int_positive_pow(long x, unsigned long y)
Raises the passed x to the power of y.
Definition: numeric.c:4496
VALUE rb_rational_num(VALUE rat)
Queries the numerator of the passed Rational.
Definition: rational.c:1978
VALUE rb_rational_den(VALUE rat)
Queries the denominator of the passed Rational.
Definition: rational.c:1984
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition: string.c:828
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition: string.c:2459
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3039
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
Definition: string.c:918
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition: string.c:2659
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3056
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition: string.c:1506
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition: string.c:1657
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition: symbol.c:924
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
Definition: sprintf.c:214
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition: sprintf.c:208
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1201
VALUE rb_str_vcatf(VALUE dst, const char *fmt, va_list ap)
Identical to rb_str_catf(), except it takes a va_list.
Definition: sprintf.c:1214
VALUE rb_vsprintf(const char *fmt, va_list ap)
Identical to rb_sprintf(), except it takes a va_list.
Definition: sprintf.c:1195
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition: sprintf.c:1241
#define rb_long2int
Just another name of rb_long2int_inline.
Definition: long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:366
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:161
#define RBASIC(obj)
Convenient casting macro.
Definition: rbasic.h:40
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:72
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition: rstring.h:527
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition: rstring.h:573
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition: rstring.h:95
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
Identical to ruby_snprintf(), except it takes a va_list.
Definition: sprintf.c:1008
int ruby_snprintf(char *str, size_t n, char const *fmt,...)
Our own locale-insensitive version of snprintf(3).
Definition: sprintf.c:1035
#define RTEST
This is an old name of RB_TEST.
Defines old _.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:375