194 Commits

Author SHA1 Message Date
Yukihiro "Matz" Matsumoto 478ada3bf4 fp_uscale.c: clamp precision in %g to avoid OOB in fixed_width
When sprintf is called with a precision larger than the double's
significand width (e.g. "%.51g"), fixed_width() indexed pow10 tables
out of bounds and produced a negative shift exponent. Cap the
internal digit count to 18 in the %g branch, matching the existing
%e and %f branches; downstream loops already zero-pad to the
caller's precision so visible output is unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-12 11:19:20 +09:00
Yukihiro "Matz" Matsumoto 1702b89c25 Merge pull request #6787 from dearblue/sprintf 2026-04-28 12:56:07 +09:00
Yukihiro "Matz" Matsumoto 416793db3d mruby-sprintf: use mrb_uint cast instead of uint64_t
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 19:25:35 +09:00
dearblue 9ad94a50e7 Supplement to #6781
`mrb_str_dup()` always duplicates string objects in an unfrozen state, and the class is also set.
Therefore, it can be observed and modified from the Ruby side using the `ObjectSpace.each_object` method.

By using `mrb_str_dup_frozen()`, unnecessary duplication can be avoided, and modifications to the string can also be prevented.
2026-04-13 21:49:59 +09:00
Yukihiro "Matz" Matsumoto 59552ecb8e mruby-sprintf: protect format string from mutation during callbacks
mrb_str_format captured raw C pointers (p, end) into the format
string's buffer before the main loop. The %s and %p specifiers call
to_s and inspect, which can invoke Ruby code that mutates the format
string via String#replace, freeing or reallocating its buffer. The
loop then continued iterating with dangling pointers, reading freed
memory and potentially leaking adjacent heap contents into the result.

Duplicate the format string with mrb_str_dup() before the loop. This
is O(1) because mrb_str_dup shares the underlying buffer; if the
original is later mutated via String#replace, str_replace decrements
the shared refcount, leaving our duplicate's buffer intact.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-10 14:51:59 +09:00
Yukihiro "Matz" Matsumoto 8956c5abb5 mruby.h: include mruby/presym.h for all source files
Since presym is now mandatory, mruby.h includes presym.h so that
MRB_SYM() macros are available everywhere without explicit include.
Remove redundant #include <mruby/presym.h> from all source files.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 16:50:58 +09:00
Yukihiro "Matz" Matsumoto a866a5b0e6 mruby-sprintf: improve initial buffer size estimation
Estimate initial buffer size based on format string to reduce
reallocations. The new formula uses format string length plus
120 bytes base, plus 24 bytes per format specifier, capped at 4096.

This reduces reallocations by ~60% in typical use cases and
improves performance by 2-21% depending on output size.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-29 11:56:58 +09:00
Yukihiro "Matz" Matsumoto e369bb3475 mruby-sprintf: rename get_format_info to get_fmt_spec
Avoid static function name collision with mruby-pack for future
amalgamation support.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-23 11:27:47 +09:00
Yukihiro "Matz" Matsumoto 7e28e68dca string.c: add mrb_utf8_to_buf() to consolidate UTF-8 encoding
Extract duplicated UTF-8 codepoint-to-bytes encoding into a shared
function in src/string.c. Update all gems to use it:

- mruby-sprintf: %c specifier
- mruby-io: putc
- mruby-string-ext: Integer#chr
- mruby-pack: pack("U")
- mruby-compiler: Unicode escapes in parser

Also use existing mrb_utf8len() in io.c for character length detection.

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:30:03 +09:00
Yukihiro "Matz" Matsumoto 53fce124e6 mruby-sprintf: optimize %c to avoid temporary string allocation
For integer arguments, encode UTF-8 directly into a stack buffer
instead of creating a temporary mrb_value string via mrb_str_new()
or calling Integer#chr.

- ~5% faster for single %c
- ~15% faster for multiple %c in one format string
- fixes UTF-8 characters (>= 0x80) which previously raised RangeError

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:27:27 +09:00
Yukihiro "Matz" Matsumoto e58c838c1d mruby-sprintf: combine variable declaration with initialization 2025-11-08 14:24:12 +09:00
Yukihiro "Matz" Matsumoto d4d2955c6b mruby-sprintf: combine variable declarations with initialization
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-23 13:35:44 +09:00
Yukihiro "Matz" Matsumoto dee72daf97 mruby-sprintf: prevent buffer overread in named format parsing; fix #6648
add bounds check at retry label to prevent reading past end of format string
when parsing unterminated named parameters like %<foo without closing >

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-22 15:25:47 +09:00
Yukihiro "Matz" Matsumoto 7de526b075 mruby-sprintf: use MRB_SYM() and mrb_define_module_function_id()
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-08 23:55:22 +09:00
Yukihiro "Matz" Matsumoto b97f7cb73f mruby-sprintf: replace designated initializers with switch statement
Replace designated initializer lookup table with a simple switch statement
for C++ compatibility. The switch approach is cleaner and works perfectly
in both C and C++ modes.

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-19 10:06:19 +09:00
Yukihiro "Matz" Matsumoto e149553db2 mruby-sprintf: improve code readability with comments and organization
Add clear section headers and explanatory comments to the format
handlers in mrb_str_format to improve code maintainability and
readability.

Changes:
- Add format type headers (CHARACTER, STRING, INTEGER, FLOAT)
- Add subsection comments explaining key logic steps
- Improve code organization within each format handler
- Better indentation and logical grouping

This makes the 450-line function much easier to navigate and understand
while maintaining identical functionality (all 1723 tests pass).

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-15 10:30:19 +09:00
Yukihiro "Matz" Matsumoto 0c99d9f20c mruby-sprintf: replace switch statement with lookup table dispatch
Replace the large 500+ line switch statement in mrb_str_format with a
clean lookup table dispatch system for better code organization and
maintainability.

Changes:
- Add format specifier lookup table (format_table[128])
- Define format types (FMT_FLAG, FMT_CHAR, FMT_INTEGER, etc.)
- Replace character-by-character dispatch with O(1) table lookup
- Maintain identical behavior (all 1723 tests pass)

This improves code readability by separating format specification
(data) from handling logic (code), making it easier to understand
and maintain the sprintf implementation.

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-15 10:05:20 +09:00
Yukihiro "Matz" Matsumoto 07b803e28a docs: replace xml-style markup with markdown in comments
Replace XML-style markup tags in comments with markdown equivalents:
- <code>...</code> to `...` (inline code)
- <tt>...</tt> to `...` (teletype/monospace)
- <i>...</i> to *...* (italics/emphasis)
- +...+ to `...` (parameter/variable references)

Updated 80+ files across core source, headers, mrbgems, and libraries
to use consistent markdown formatting in documentation comments.
Handled edge cases including special characters like <=> operators.

Co-authored-by: Atlassian Rovo Dev
2025-08-14 10:52:49 +09:00
Yukihiro "Matz" Matsumoto e15738ea74 mruby-sprintf: add comprehensive call-seq documentation for String#% method
- %: string formatting operator that uses the string as a format specification
  and applies it to the given argument(s), supports both single arguments and
  arrays for multiple substitutions, delegates to sprintf for actual formatting

The method now has comprehensive call-seq documentation with practical
examples demonstrating various sprintf formatting patterns including:

- Zero-padded integers: "%05d" % 123
- Multiple substitutions with arrays: "%-5s: %016x" % [name, id]
- Hash-based named substitutions: "foo = %{foo}" % { :foo => 'bar' }
- Named format specifiers: "%{foo}f" % { :foo => 1 }

Co-authored-by: Atlassian Rovo Dev
2025-08-14 10:52:47 +09:00
Yukihiro "Matz" Matsumoto 3e5129558b mruby-sprintf: remove misleading comment and dead code
The `XXX` comment in `sprintf.c` suggested that not validating
the number of arguments for positional format specifiers was a bug.
However, CRuby's `sprintf` also ignores extra arguments in this
case, making the existing behavior correct.

This commit removes the confusing comment and the disabled code
block that went with it, clarifying the intended behavior and
cleaning up the code.

Co-authored-by: Gemini <gemini@google.com>
2025-07-11 09:20:00 +09:00
Yukihiro "Matz" Matsumoto ac8d5c6ae6 mruby-sprintf: add README.md
The document is written by Google Jules.
2025-06-14 01:04:23 +09:00
Yukihiro "Matz" Matsumoto 4ca61298ac mruby-sprintf: add type cast to silence warning 2025-03-25 08:08:26 +09:00
dearblue e476d9a344 Need to restore the GC arena after some function calls
When calling `mrb_equal()` or `mrb_funcall()` family functions, the GC arena should be restored if the loop is repeated by a non-immediate return value.

In my opinion, restoring the GC arena is unnecessary when a non-immediate (true) value causes the function to return (e.g. the `mrb_ary_index_m()` function).

The patch does not take into account the case of recursive calls and may be incomplete.
2024-09-03 21:29:06 +09:00
Yukihiro "Matz" Matsumoto 3c5baac5c5 mruby-sprintf: fix a bug with negative octals
Leading octal digit may be 1, 3, 7 unlike binary or hexadecimal.
2024-07-30 11:33:18 +09:00
Yukihiro "Matz" Matsumoto 99c078bb6b mruby-bigint (mrb_bint_2comp): simplify using mpz_2comp() 2024-07-25 16:18:49 +09:00
Yukihiro "Matz" Matsumoto a77bc25a5f mruby-sprintf: support dots expression of negative integer format
For specifiers assume unsigned integers, negative numbers show dots (..)
to indicate virtual infinite 1s at the MSB side of 2's compliment.
2024-07-09 11:13:55 +09:00
Yukihiro "Matz" Matsumoto 80fec16cb6 mruby-sprintf: inline sign_bits() function 2024-07-09 10:48:07 +09:00
Yukihiro "Matz" Matsumoto d249c2e939 mruby-sprintf: separate filling high bits and converting negatives 2024-07-09 10:40:46 +09:00
Yukihiro "Matz" Matsumoto 0ea1549faa mruby-sprintf: reorder functions
In addition, internal function `mrb_str_format()` is made `static`.
2024-07-06 08:45:19 +09:00
Yukihiro "Matz" Matsumoto bd502f6d7b mruby-sprintf: support Big integers for %d etc. 2024-07-04 22:51:14 +09:00
Yukihiro "Matz" Matsumoto aea3e7aedd mruby-sprintf: raise ArgumentError for % at the bottom 2024-05-03 07:46:45 +09:00
Yukihiro "Matz" Matsumoto ca26f41b57 mruby-sprintf: remove unnecessary assignment 2024-04-18 15:48:45 +09:00
Yukihiro "Matz" Matsumoto 89f7bb1056 use more lightweight mrb_funcall_argv instead of mrb_funcall_id 2023-06-12 14:22:04 +09:00
Yukihiro "Matz" Matsumoto 2f7f797473 remove extra spaces before ; 2023-05-22 12:05:35 +09:00
Yukihiro "Matz" Matsumoto c32f7915fb reformat else clause indentation style 2023-05-20 00:21:01 +09:00
Yukihiro "Matz" Matsumoto a7232ecf8d mruby-sprintf (mrb_str_format): fixed integer size confusion
Declared as int, checked as mrb_int.
2022-12-06 08:31:30 +09:00
Yukihiro "Matz" Matsumoto 551d603d9c mruby-sprintf: remove unnecessary format specifier 2022-11-26 23:22:50 +09:00
Yukihiro "Matz" Matsumoto 9c5dc42e59 small cosmetic changes.
I prefer `i++` style unless absolutely necessary.
This commit is an addition to 41e4148.
2022-11-19 17:11:56 +09:00
Yukihiro "Matz" Matsumoto 71a1d0ad26 mruby-sprintf: fix a debug error message (remove additional "1"). 2022-11-15 13:27:31 +09:00
Yukihiro "Matz" Matsumoto 6bcbfed8bb mruby-sprintf/sprintf.c: check integer overflow before casting. 2022-11-11 08:08:07 +09:00
Yukihiro "Matz" Matsumoto 4e9773ae3d readint.c (mrb_int_read): new function.
We no longer use `mrb_read_int` which is kinda compatible with `strtol`.
2022-11-07 16:09:31 +09:00
Yukihiro "Matz" Matsumoto c6b7029cdc mruby-sprintf: fix int and mrb_int mixtures. 2022-11-04 13:11:36 +09:00
Yukihiro "Matz" Matsumoto b58094c881 mruby-sprintf/sprintf.c: call mrb_str_resize() less often. 2022-06-29 15:03:41 +09:00
Yukihiro "Matz" Matsumoto 61700dbb0a mruby-sprintf/sprintf.c: raise an error with MRB_NO_FLOAT. 2022-04-25 10:01:09 +09:00
Yukihiro "Matz" Matsumoto e5e7bd29ef sprintf.c: width may have been INT_MAX.
Now `width` is limited to `INT16_MIN..INT16_MAX`.
2021-09-14 14:12:56 +09:00
Yukihiro "Matz" Matsumoto 79bc8e2539 string.h: rename mrb_str_to_inum to mrb_str_to_integer.
Consistent naming: `integer` to represent integer packed in `mrb_value`
instead of `inum`.
2021-09-07 14:31:56 +09:00
Yukihiro "Matz" Matsumoto 2c41739b66 mruby.h: obsolete mrb_to_str().
Replace them by `mrb_ensure_string_type()`.
2021-09-01 07:00:55 +09:00
dearblue 5a57602860 Organize the include of header files
- `#include <math.h>` is done in `mruby.h`.
  Eliminate the need to worry about the `MRB_NO_FLOAT` macro.

- Include mruby header files before standard header files.
  If the standard header file is already placed before `mruby.h`, the standard header file added in the future tends to be placed before `mruby.h`.

This change should some reduce the chances of macros that must be defined becoming undefined in C++ or including problematic header files in a particular mruby build configuration.
2021-08-21 15:42:57 +09:00
Yukihiro "Matz" Matsumoto 5c804cf68f Remove redundant include headers.
- stdlib.h
- stddef.h
- stdint.h
- stdarg.h
- limits.h
- float.h
2021-07-25 13:07:10 +09:00
Yukihiro "Matz" Matsumoto 49af1fca03 readint.c: add new function mrb_int_read.
Difference from `strtoul(3)`:

* reads `mrb_int` based on configuration
* specifies the end of the string
* no sign interpretation
* base 10 only
2021-06-11 15:14:17 +09:00