u 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. checksums.yaml +7 -0
  2. data/build/ext/u/data/attributes.rb +39 -0
  3. data/build/ext/u/data/bidi-mirroring.rb +27 -0
  4. data/build/ext/u/data/canonical-combining-class.rb +15 -0
  5. data/build/ext/u/data/case-folding.rb +39 -0
  6. data/build/ext/u/data/cased.rb +19 -0
  7. data/build/ext/u/data/compose.rb +304 -0
  8. data/build/ext/u/data/constants.rb +31 -0
  9. data/build/ext/u/data/decompose.rb +85 -0
  10. data/build/ext/u/data/general-category.rb +61 -0
  11. data/build/ext/u/data/grapheme-word-break.rb +15 -0
  12. data/build/ext/u/data/marshalled.rb +5 -0
  13. data/build/ext/u/data/script.rb +91 -0
  14. data/build/ext/u/data/soft-dotted.rb +17 -0
  15. data/build/ext/u/data/title-table.rb +30 -0
  16. data/build/ext/u/data/wide.rb +17 -0
  17. data/build/lib/u/build.rb +8 -0
  18. data/build/lib/u/build/data.rb +16 -0
  19. data/build/lib/u/build/data/bidimirroring.rb +26 -0
  20. data/build/lib/u/build/data/break.rb +14 -0
  21. data/build/lib/u/build/data/casefolding.rb +77 -0
  22. data/build/lib/u/build/data/compositionexclusions.rb +14 -0
  23. data/build/lib/u/build/data/derivedeastasianwidth.rb +15 -0
  24. data/build/lib/u/build/data/file.rb +88 -0
  25. data/build/lib/u/build/data/linebreak.rb +14 -0
  26. data/build/lib/u/build/data/proplist.rb +18 -0
  27. data/build/lib/u/build/data/scripts.rb +22 -0
  28. data/build/lib/u/build/data/specialcasing.rb +106 -0
  29. data/build/lib/u/build/data/unicode.rb +41 -0
  30. data/build/lib/u/build/data/unicode/entry.rb +27 -0
  31. data/build/lib/u/build/data/unicode/entry/decomposition.rb +29 -0
  32. data/build/lib/u/build/data/unicode/points.rb +32 -0
  33. data/build/lib/u/build/header.rb +11 -0
  34. data/build/lib/u/build/header/table.rb +19 -0
  35. data/build/lib/u/build/header/table/row.rb +64 -0
  36. data/build/lib/u/build/header/tables.rb +6 -0
  37. data/build/lib/u/build/header/tables/intervals.rb +50 -0
  38. data/build/lib/u/build/header/tables/split.rb +20 -0
  39. data/build/lib/u/build/header/tables/split/data.rb +29 -0
  40. data/build/lib/u/build/header/tables/split/part1.rb +28 -0
  41. data/build/lib/u/build/header/tables/split/part2.rb +13 -0
  42. data/build/lib/u/build/header/tables/split/row.rb +34 -0
  43. data/build/lib/u/build/header/tables/split/rows.rb +22 -0
  44. data/build/test/unit/break.rb +45 -0
  45. data/build/test/unit/case.rb +178 -0
  46. data/build/test/unit/foldcase.rb +44 -0
  47. data/build/test/unit/normalize.rb +81 -0
  48. data/ext/u/attributes.c +62 -0
  49. data/ext/u/attributes.h +5 -0
  50. data/ext/u/case.h +41 -0
  51. data/ext/u/data/attributes.h +3070 -0
  52. data/ext/u/data/bidi-mirroring.h +373 -0
  53. data/ext/u/data/canonical-combining-class.h +2157 -0
  54. data/ext/u/data/case-folding.h +171 -0
  55. data/ext/u/data/cased.h +42 -0
  56. data/ext/u/data/compose.h +1714 -0
  57. data/ext/u/data/constants.h +17 -0
  58. data/ext/u/data/decompose.h +9356 -0
  59. data/ext/u/data/general-category.h +28959 -0
  60. data/ext/u/data/grapheme-break.h +13201 -0
  61. data/ext/u/data/line-break.h +26501 -0
  62. data/ext/u/data/normalization-quick-check.h +3002 -0
  63. data/ext/u/data/script.h +2928 -0
  64. data/ext/u/data/soft-dotted.h +55 -0
  65. data/ext/u/data/title-table.h +41 -0
  66. data/ext/u/data/types.h +11117 -0
  67. data/ext/u/data/wide-cjk.h +197 -0
  68. data/ext/u/data/wide.h +59 -0
  69. data/ext/u/data/word-break.h +10001 -0
  70. data/ext/u/depend +281 -0
  71. data/ext/u/extconf.rb +158 -0
  72. data/ext/u/output.h +51 -0
  73. data/ext/{encoding/character/utf-8 → u}/private.c +11 -15
  74. data/ext/u/private.h +58 -0
  75. data/ext/u/rb_includes.h +10 -0
  76. data/ext/u/rb_private.c +98 -0
  77. data/ext/u/rb_private.h +67 -0
  78. data/ext/u/rb_u.c +251 -0
  79. data/ext/u/rb_u_buffer.c +443 -0
  80. data/ext/u/rb_u_buffer.h +24 -0
  81. data/ext/u/rb_u_re.c +43 -0
  82. data/ext/u/rb_u_re.h +15 -0
  83. data/ext/u/rb_u_string.c +478 -0
  84. data/ext/u/rb_u_string.h +173 -0
  85. data/ext/u/rb_u_string_alnum.c +10 -0
  86. data/ext/u/rb_u_string_alpha.c +10 -0
  87. data/ext/u/rb_u_string_aref.c +142 -0
  88. data/ext/u/rb_u_string_ascii_only.c +13 -0
  89. data/ext/u/rb_u_string_assigned.c +10 -0
  90. data/ext/u/rb_u_string_b.c +18 -0
  91. data/ext/u/rb_u_string_bytesize.c +10 -0
  92. data/ext/u/rb_u_string_byteslice.c +103 -0
  93. data/ext/u/rb_u_string_canonical_combining_class.c +33 -0
  94. data/ext/u/rb_u_string_case_ignorable.c +25 -0
  95. data/ext/u/rb_u_string_casecmp.c +61 -0
  96. data/ext/u/rb_u_string_cased.c +17 -0
  97. data/ext/u/rb_u_string_chomp.c +107 -0
  98. data/ext/u/rb_u_string_chop.c +33 -0
  99. data/ext/u/rb_u_string_chr.c +9 -0
  100. data/ext/u/rb_u_string_cntrl.c +10 -0
  101. data/ext/u/rb_u_string_collate.c +46 -0
  102. data/ext/u/rb_u_string_collation_key.c +18 -0
  103. data/ext/u/rb_u_string_count.c +38 -0
  104. data/ext/u/rb_u_string_defined.c +10 -0
  105. data/ext/u/rb_u_string_delete.c +62 -0
  106. data/ext/u/rb_u_string_digit.c +10 -0
  107. data/ext/u/rb_u_string_downcase.c +13 -0
  108. data/ext/u/rb_u_string_dump.c +153 -0
  109. data/ext/u/rb_u_string_each_byte.c +46 -0
  110. data/ext/u/rb_u_string_each_char.c +49 -0
  111. data/ext/u/rb_u_string_each_codepoint.c +45 -0
  112. data/ext/u/rb_u_string_each_grapheme_cluster.c +36 -0
  113. data/ext/u/rb_u_string_each_line.c +142 -0
  114. data/ext/u/rb_u_string_each_word.c +34 -0
  115. data/ext/u/rb_u_string_empty.c +11 -0
  116. data/ext/u/rb_u_string_end_with.c +31 -0
  117. data/ext/u/rb_u_string_eql.c +30 -0
  118. data/ext/u/rb_u_string_equal.c +33 -0
  119. data/ext/u/rb_u_string_foldcase.c +12 -0
  120. data/ext/u/rb_u_string_folded.c +13 -0
  121. data/ext/u/rb_u_string_format.c +1745 -0
  122. data/ext/u/rb_u_string_general_category.c +109 -0
  123. data/ext/u/rb_u_string_getbyte.c +21 -0
  124. data/ext/u/rb_u_string_graph.c +21 -0
  125. data/ext/u/rb_u_string_grapheme_break.c +61 -0
  126. data/ext/u/rb_u_string_gsub.c +164 -0
  127. data/ext/u/rb_u_string_hash.c +10 -0
  128. data/ext/u/rb_u_string_hex.c +9 -0
  129. data/ext/u/rb_u_string_include.c +10 -0
  130. data/ext/u/rb_u_string_index.c +110 -0
  131. data/ext/u/rb_u_string_inspect.c +189 -0
  132. data/ext/u/rb_u_string_internal_tr.c +148 -0
  133. data/ext/u/rb_u_string_internal_tr.h +29 -0
  134. data/ext/u/rb_u_string_justify.c +169 -0
  135. data/ext/u/rb_u_string_length.c +10 -0
  136. data/ext/u/rb_u_string_line_break.c +115 -0
  137. data/ext/u/rb_u_string_lower.c +13 -0
  138. data/ext/u/rb_u_string_lstrip.c +24 -0
  139. data/ext/u/rb_u_string_match.c +65 -0
  140. data/ext/u/rb_u_string_mirror.c +16 -0
  141. data/ext/u/rb_u_string_newline.c +21 -0
  142. data/ext/u/rb_u_string_normalize.c +70 -0
  143. data/ext/u/rb_u_string_normalized.c +28 -0
  144. data/ext/u/rb_u_string_oct.c +11 -0
  145. data/ext/u/rb_u_string_ord.c +14 -0
  146. data/ext/u/rb_u_string_partition.c +80 -0
  147. data/ext/u/rb_u_string_plus.c +33 -0
  148. data/ext/u/rb_u_string_print.c +10 -0
  149. data/ext/u/rb_u_string_punct.c +10 -0
  150. data/ext/u/rb_u_string_reverse.c +13 -0
  151. data/ext/u/rb_u_string_rindex.c +104 -0
  152. data/ext/u/rb_u_string_rpartition.c +81 -0
  153. data/ext/u/rb_u_string_rstrip.c +29 -0
  154. data/ext/u/rb_u_string_scan.c +109 -0
  155. data/ext/u/rb_u_string_script.c +253 -0
  156. data/ext/u/rb_u_string_soft_dotted.c +13 -0
  157. data/ext/u/rb_u_string_space.c +24 -0
  158. data/ext/u/rb_u_string_split.c +245 -0
  159. data/ext/u/rb_u_string_squeeze.c +75 -0
  160. data/ext/u/rb_u_string_start_with.c +31 -0
  161. data/ext/u/rb_u_string_strip.c +36 -0
  162. data/ext/u/rb_u_string_sub.c +147 -0
  163. data/ext/u/rb_u_string_times.c +35 -0
  164. data/ext/u/rb_u_string_title.c +10 -0
  165. data/ext/u/rb_u_string_titlecase.c +13 -0
  166. data/ext/u/rb_u_string_to_i.c +45 -0
  167. data/ext/u/rb_u_string_to_inum.c +364 -0
  168. data/ext/u/rb_u_string_to_inum.h +1 -0
  169. data/ext/u/rb_u_string_to_str.c +17 -0
  170. data/ext/u/rb_u_string_to_sym.c +12 -0
  171. data/ext/u/rb_u_string_tr.c +290 -0
  172. data/ext/u/rb_u_string_upcase.c +12 -0
  173. data/ext/u/rb_u_string_upper.c +13 -0
  174. data/ext/u/rb_u_string_valid.c +10 -0
  175. data/ext/u/rb_u_string_valid_encoding.c +12 -0
  176. data/ext/u/rb_u_string_wide.c +21 -0
  177. data/ext/u/rb_u_string_wide_cjk.c +21 -0
  178. data/ext/u/rb_u_string_width.c +19 -0
  179. data/ext/u/rb_u_string_word_break.c +63 -0
  180. data/ext/u/rb_u_string_xdigit.c +22 -0
  181. data/ext/u/rb_u_string_zero_width.c +16 -0
  182. data/ext/u/titled.c +55 -0
  183. data/ext/u/titled.h +1 -0
  184. data/ext/u/u.c +23 -0
  185. data/ext/u/u.h +458 -0
  186. data/ext/u/u_char_canonical_combining_class.c +31 -0
  187. data/ext/u/u_char_digit_value.c +21 -0
  188. data/ext/u/u_char_downcase.c +27 -0
  189. data/ext/u/u_char_general_category.c +31 -0
  190. data/ext/u/u_char_grapheme_break.c +28 -0
  191. data/ext/u/u_char_isalnum.c +24 -0
  192. data/ext/u/u_char_isalpha.c +21 -0
  193. data/ext/u/u_char_isassigned.c +16 -0
  194. data/ext/u/u_char_iscased.c +22 -0
  195. data/ext/u/u_char_iscaseignorable.c +29 -0
  196. data/ext/u/u_char_iscntrl.c +17 -0
  197. data/ext/u/u_char_isdefined.c +15 -0
  198. data/ext/u/u_char_isdigit.c +16 -0
  199. data/ext/u/u_char_isgraph.c +22 -0
  200. data/ext/u/u_char_islower.c +16 -0
  201. data/ext/u/u_char_isnewline.c +24 -0
  202. data/ext/u/u_char_isprint.c +21 -0
  203. data/ext/u/u_char_ispunct.c +27 -0
  204. data/ext/u/u_char_issoftdotted.c +18 -0
  205. data/ext/u/u_char_isspace.c +28 -0
  206. data/ext/u/u_char_isupper.c +16 -0
  207. data/ext/u/u_char_isvalid.c +18 -0
  208. data/ext/u/u_char_iswide.c +18 -0
  209. data/ext/u/u_char_iswide_cjk.c +22 -0
  210. data/ext/u/u_char_isxdigit.c +27 -0
  211. data/ext/u/u_char_iszerowidth.c +29 -0
  212. data/ext/u/u_char_line_break.c +29 -0
  213. data/ext/u/u_char_mirror.c +16 -0
  214. data/ext/u/u_char_normalized.c +23 -0
  215. data/ext/u/u_char_script.c +41 -0
  216. data/ext/u/u_char_to_u.c +48 -0
  217. data/ext/u/u_char_upcase.c +24 -0
  218. data/ext/u/u_char_width.c +12 -0
  219. data/ext/u/u_char_word_break.c +28 -0
  220. data/ext/u/u_char_xdigit_value.c +31 -0
  221. data/ext/u/u_collate.c +83 -0
  222. data/ext/u/u_collation_key.c +132 -0
  223. data/ext/u/u_decode.c +156 -0
  224. data/ext/u/u_downcase.c +201 -0
  225. data/ext/u/u_foldcase.c +68 -0
  226. data/ext/u/u_grapheme_clusters.c +57 -0
  227. data/ext/u/u_has_prefix.c +27 -0
  228. data/ext/u/u_index.c +93 -0
  229. data/ext/u/u_is_ascii_only.c +33 -0
  230. data/ext/u/u_locale.c +40 -0
  231. data/ext/u/u_locale.h +14 -0
  232. data/ext/u/u_mirror.c +20 -0
  233. data/ext/u/u_n_bytes.c +16 -0
  234. data/ext/u/u_n_chars.c +43 -0
  235. data/ext/u/u_normalize.c +232 -0
  236. data/ext/u/u_normalized.c +28 -0
  237. data/ext/u/u_offset_to_pointer.c +62 -0
  238. data/ext/u/u_pointer_to_offset.c +23 -0
  239. data/ext/u/u_recode.c +73 -0
  240. data/ext/u/u_reverse.c +21 -0
  241. data/ext/u/u_rindex.c +132 -0
  242. data/ext/u/u_titlecase.c +68 -0
  243. data/ext/u/u_upcase.c +89 -0
  244. data/ext/u/u_width.c +35 -0
  245. data/ext/u/u_words.c +82 -0
  246. data/ext/u/yield.h +27 -0
  247. data/lib/u-1.0.rb +20 -0
  248. data/lib/u-1.0/buffer.rb +10 -0
  249. data/lib/u-1.0/string.rb +9 -0
  250. data/lib/u-1.0/version.rb +287 -0
  251. data/test/unit/case.rb +2080 -0
  252. data/test/unit/foldcase.rb +1136 -0
  253. data/test/unit/graphemebreak.rb +407 -0
  254. data/test/unit/normalize.rb +367545 -0
  255. data/test/unit/u-1.0.rb +10 -0
  256. data/test/unit/u-1.0/buffer.rb +52 -0
  257. data/test/unit/u-1.0/string.rb +1439 -0
  258. data/test/unit/{u.rb → u-1.0/version.rb} +0 -1
  259. data/test/unit/wordbreak.rb +1083 -0
  260. metadata +603 -148
  261. data/README +0 -38
  262. data/Rakefile +0 -64
  263. data/ext/encoding/character/utf-8/break.c +0 -25
  264. data/ext/encoding/character/utf-8/data/break.h +0 -22931
  265. data/ext/encoding/character/utf-8/data/character-tables.h +0 -14358
  266. data/ext/encoding/character/utf-8/data/compose.h +0 -1607
  267. data/ext/encoding/character/utf-8/data/decompose.h +0 -10926
  268. data/ext/encoding/character/utf-8/data/generate-unicode-data.rb +0 -1070
  269. data/ext/encoding/character/utf-8/decompose.c +0 -444
  270. data/ext/encoding/character/utf-8/depend +0 -65
  271. data/ext/encoding/character/utf-8/extconf.rb +0 -67
  272. data/ext/encoding/character/utf-8/private.h +0 -51
  273. data/ext/encoding/character/utf-8/properties.c +0 -1056
  274. data/ext/encoding/character/utf-8/rb_includes.h +0 -19
  275. data/ext/encoding/character/utf-8/rb_methods.h +0 -49
  276. data/ext/encoding/character/utf-8/rb_private.h +0 -52
  277. data/ext/encoding/character/utf-8/rb_utf_aref.c +0 -111
  278. data/ext/encoding/character/utf-8/rb_utf_aset.c +0 -105
  279. data/ext/encoding/character/utf-8/rb_utf_casecmp.c +0 -24
  280. data/ext/encoding/character/utf-8/rb_utf_chomp.c +0 -114
  281. data/ext/encoding/character/utf-8/rb_utf_chop.c +0 -44
  282. data/ext/encoding/character/utf-8/rb_utf_collate.c +0 -13
  283. data/ext/encoding/character/utf-8/rb_utf_count.c +0 -30
  284. data/ext/encoding/character/utf-8/rb_utf_delete.c +0 -60
  285. data/ext/encoding/character/utf-8/rb_utf_downcase.c +0 -13
  286. data/ext/encoding/character/utf-8/rb_utf_each_char.c +0 -27
  287. data/ext/encoding/character/utf-8/rb_utf_foldcase.c +0 -13
  288. data/ext/encoding/character/utf-8/rb_utf_hex.c +0 -14
  289. data/ext/encoding/character/utf-8/rb_utf_index.c +0 -50
  290. data/ext/encoding/character/utf-8/rb_utf_insert.c +0 -48
  291. data/ext/encoding/character/utf-8/rb_utf_internal_bignum.c +0 -332
  292. data/ext/encoding/character/utf-8/rb_utf_internal_bignum.h +0 -12
  293. data/ext/encoding/character/utf-8/rb_utf_internal_tr.c +0 -142
  294. data/ext/encoding/character/utf-8/rb_utf_internal_tr.h +0 -41
  295. data/ext/encoding/character/utf-8/rb_utf_justify.c +0 -96
  296. data/ext/encoding/character/utf-8/rb_utf_length.c +0 -14
  297. data/ext/encoding/character/utf-8/rb_utf_lstrip.c +0 -41
  298. data/ext/encoding/character/utf-8/rb_utf_normalize.c +0 -51
  299. data/ext/encoding/character/utf-8/rb_utf_oct.c +0 -14
  300. data/ext/encoding/character/utf-8/rb_utf_reverse.c +0 -13
  301. data/ext/encoding/character/utf-8/rb_utf_rindex.c +0 -88
  302. data/ext/encoding/character/utf-8/rb_utf_rstrip.c +0 -51
  303. data/ext/encoding/character/utf-8/rb_utf_squeeze.c +0 -70
  304. data/ext/encoding/character/utf-8/rb_utf_strip.c +0 -27
  305. data/ext/encoding/character/utf-8/rb_utf_to_i.c +0 -25
  306. data/ext/encoding/character/utf-8/rb_utf_tr.c +0 -250
  307. data/ext/encoding/character/utf-8/rb_utf_upcase.c +0 -13
  308. data/ext/encoding/character/utf-8/tables.h +0 -38
  309. data/ext/encoding/character/utf-8/unicode.c +0 -319
  310. data/ext/encoding/character/utf-8/unicode.h +0 -216
  311. data/ext/encoding/character/utf-8/utf.c +0 -1334
  312. data/lib/encoding/character/utf-8.rb +0 -201
  313. data/lib/u.rb +0 -16
  314. data/lib/u/string.rb +0 -185
  315. data/lib/u/version.rb +0 -5
  316. data/test/unit/u/string.rb +0 -91
@@ -0,0 +1,34 @@
1
+ #include "rb_includes.h"
2
+
3
+ static void
4
+ each(const char *p, size_t n, VALUE *self)
5
+ {
6
+ rb_yield(rb_u_string_new_c(*self, p, n));
7
+ }
8
+
9
+ /* @overload each_word{ |word| … }
10
+ *
11
+ * Enumerates the words in the receiver, each inheriting any taint and
12
+ * untrust.
13
+ *
14
+ * @yieldparam [U::String] word
15
+ * @return [self]
16
+ * @see http://www.unicode.org/reports/tr29/
17
+ * Unicode Standard Annex #29: Unicode Text Segmentation
18
+ *
19
+ * @overload each_word
20
+ *
21
+ * @return [Enumerator] An Enumerator over the characters in the receiver
22
+ * @see http://www.unicode.org/reports/tr29/
23
+ * Unicode Standard Annex #29: Unicode Text Segmentation */
24
+ VALUE
25
+ rb_u_string_each_word(VALUE self)
26
+ {
27
+ RETURN_ENUMERATOR(self, 0, NULL);
28
+
29
+ const struct rb_u_string *string = RVAL2USTRING(self);
30
+ const char *p = USTRING_STR(string);
31
+ size_t length = USTRING_LENGTH(string);
32
+ u_words(p, length, (u_substring_fn)each, &self);
33
+ return self;
34
+ }
@@ -0,0 +1,11 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload empty?
4
+ * @return [Boolean] True if {#bytesize} = 0 */
5
+ VALUE
6
+ rb_u_string_empty(VALUE self)
7
+ {
8
+ const struct rb_u_string *string = RVAL2USTRING(self);
9
+
10
+ return (USTRING_LENGTH(string) == 0) ? Qtrue : Qfalse;
11
+ }
@@ -0,0 +1,31 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload end_with?(*suffixes)
4
+ * @param [Array] suffixes
5
+ * @return [Boolean] True if any element of SUFFIXES that responds to #to_str
6
+ * is a byte-level suffix of the receiver */
7
+ VALUE
8
+ rb_u_string_end_with(int argc, VALUE *argv, VALUE self)
9
+ {
10
+ const struct rb_u_string *string = RVAL2USTRING(self);
11
+ const char *end = USTRING_END(string);
12
+ long p_length = USTRING_LENGTH(string);
13
+
14
+ for (int i = 0; i < argc; i++) {
15
+ VALUE tmp = rb_u_string_check_type(argv[i]);
16
+ if (NIL_P(tmp))
17
+ continue;
18
+
19
+ const struct rb_u_string *other = RVAL2USTRING_ANY(tmp);
20
+ const char *q = USTRING_STR(other);
21
+ long q_length = USTRING_LENGTH(other);
22
+
23
+ if (p_length < q_length)
24
+ continue;
25
+
26
+ if (memcmp(end - q_length, q, q_length) == 0)
27
+ return Qtrue;
28
+ }
29
+
30
+ return Qfalse;
31
+ }
@@ -0,0 +1,30 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload eql?(other)
4
+ * @param [U::String] other
5
+ * @return [Boolean] True if the receiver’s bytes equal those of OTHER
6
+ * @see #<=>
7
+ * @see #== */
8
+ VALUE
9
+ rb_u_string_eql(VALUE self, VALUE rbother)
10
+ {
11
+ if (self == rbother)
12
+ return Qtrue;
13
+
14
+ if (!RTEST(rb_obj_is_kind_of(rbother, rb_cUString)))
15
+ return Qfalse;
16
+
17
+ const struct rb_u_string *string = RVAL2USTRING(self);
18
+ const struct rb_u_string *other = RVAL2USTRING(rbother);
19
+
20
+ const char *p = USTRING_STR(string);
21
+ const char *q = USTRING_STR(other);
22
+
23
+ if (p == q)
24
+ return Qtrue;
25
+
26
+ long p_length = USTRING_LENGTH(string);
27
+ long q_length = USTRING_LENGTH(other);
28
+
29
+ return p_length == q_length && memcmp(p, q, q_length) == 0 ? Qtrue : Qfalse;
30
+ }
@@ -0,0 +1,33 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload ==(other)
4
+ * @param [U::String, #to_str] other
5
+ * @return [Boolean] True if the receiver’s bytes equal those of OTHER
6
+ * @see #<=>
7
+ * @see #eql? */
8
+ VALUE
9
+ rb_u_string_equal(VALUE self, VALUE rbother)
10
+ {
11
+ if (self == rbother)
12
+ return Qtrue;
13
+
14
+ if (RTEST(rb_obj_is_kind_of(rbother, rb_cUString)))
15
+ return rb_u_string_eql(self, rbother);
16
+
17
+ if (!rb_respond_to(rbother, rb_intern("to_str")))
18
+ return Qfalse;
19
+
20
+ const struct rb_u_string *string = RVAL2USTRING(self);
21
+ const struct rb_u_string *other = RVAL2USTRING_ANY(rbother);
22
+
23
+ const char *p = USTRING_STR(string);
24
+ const char *q = USTRING_STR(other);
25
+
26
+ if (p == q)
27
+ return Qtrue;
28
+
29
+ long p_length = USTRING_LENGTH(string);
30
+ long q_length = USTRING_LENGTH(other);
31
+
32
+ return p_length == q_length && memcmp(p, q, q_length) == 0 ? Qtrue : Qfalse;
33
+ }
@@ -0,0 +1,12 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload foldcase(locale = ENV['LC_CTYPE'])
4
+ * @param [#to_str] locale
5
+ * @return [U::String] The case-folding of the receiver according to the
6
+ * rules of the language of LOCALE, which may be empty to specifically use
7
+ * the default rules, inheriting any taint and untrust */
8
+ VALUE
9
+ rb_u_string_foldcase(int argc, VALUE *argv, VALUE self)
10
+ {
11
+ return _rb_u_string_convert_locale(argc, argv, self, u_foldcase, NULL);
12
+ }
@@ -0,0 +1,13 @@
1
+ #include "rb_includes.h"
2
+
3
+ /* @overload folded?(locale = ENV[LC_CTYPE])
4
+ * @param [#to_str] locale
5
+ * @return [Boolean] True if the receiver has been case-folded according to
6
+ * the rules of the language of LOCALE, which may be empty to specifically
7
+ * use the default, language-independent, rules, that is, if _a_ =
8
+ * _a_{#foldcase}(LOCALE), where _a_ = {#normalize}(`:nfd`) */
9
+ VALUE
10
+ rb_u_string_folded(int argc, VALUE *argv, VALUE self)
11
+ {
12
+ return _rb_u_string_test_locale(argc, argv, self, u_foldcase);
13
+ }
@@ -0,0 +1,1745 @@
1
+ #include "rb_includes.h"
2
+ #include <limits.h>
3
+ #include <math.h>
4
+ #ifdef HAVE_RUBY_INTERN_H
5
+ # include <ruby/intern.h>
6
+ #else
7
+ # include <intern.h>
8
+ #endif
9
+ #ifdef HAVE_RUBY_ENCODING_H
10
+ # include <ruby/encoding.h>
11
+ #endif
12
+ #include "rb_u_buffer.h"
13
+ #include "rb_u_string_to_inum.h"
14
+
15
+ enum directive_flags {
16
+ DIRECTIVE_FLAGS_NONE = 0,
17
+ DIRECTIVE_FLAGS_SPACE = 1,
18
+ DIRECTIVE_FLAGS_SHARP = 2,
19
+ DIRECTIVE_FLAGS_PLUS = 4,
20
+ DIRECTIVE_FLAGS_MINUS = 8,
21
+ DIRECTIVE_FLAGS_ZERO = 16,
22
+ DIRECTIVE_FLAGS_DECIMAL =
23
+ DIRECTIVE_FLAGS_SPACE |
24
+ DIRECTIVE_FLAGS_PLUS |
25
+ DIRECTIVE_FLAGS_MINUS |
26
+ DIRECTIVE_FLAGS_ZERO,
27
+ DIRECTIVE_FLAGS_NUMBER =
28
+ DIRECTIVE_FLAGS_DECIMAL |
29
+ DIRECTIVE_FLAGS_SHARP
30
+ };
31
+
32
+ struct format_arguments {
33
+ int argc;
34
+ const VALUE *argv;
35
+ int i;
36
+ bool absolute;
37
+ VALUE names;
38
+ };
39
+
40
+ #if !(defined(HAVE_RB_LONG2INT) || defined(rb_long2int))
41
+ # if SIZEOF_INT < SIZEOF_LONG
42
+ static void
43
+ rb_out_of_int(long l)
44
+ {
45
+ rb_u_raise(rb_eRangeError,
46
+ l < 0 ?
47
+ "integer %ld too small to convert to C type int" :
48
+ "integer %ld too big to convert to C type int",
49
+ l);
50
+ }
51
+ # if defined(__GNUC__) && __GNUC__ > 2
52
+ # define rb_long2int(l) __extension__({ \
53
+ long _rb_long2int_l = (l); \
54
+ int _rb_long2int_i = (int)_rb_long2int_l; \
55
+ if ((long)_rb_long2int_i != _rb_long2int_l) \
56
+ rb_out_of_int(_rb_long2int_l); \
57
+ _rb_long2int_i; \
58
+ })
59
+ # else
60
+ static inline int
61
+ rb_long2int(long l)
62
+ {
63
+ int i = (int)l;
64
+
65
+ if ((long)i != l)
66
+ rb_out_of_int(l);
67
+
68
+ return i;
69
+ }
70
+ # endif
71
+ # else
72
+ # define rb_long2int(l) ((int)(l))
73
+ # endif
74
+ #endif
75
+
76
+ #ifndef RARRAY_LENINT
77
+ # define RARRAY_LENINT(ary) rb_long2int(RARRAY_LEN(ary))
78
+ #endif
79
+
80
+ #ifndef HAVE_RB_HASH_LOOKUP2
81
+ # include <st.h>
82
+
83
+ static VALUE
84
+ rb_hash_lookup2(VALUE hash, VALUE key, VALUE default_value)
85
+ {
86
+ VALUE value;
87
+
88
+ if (st_lookup(RHASH(hash)->tbl, key, &value))
89
+ return value;
90
+
91
+ return default_value;
92
+ }
93
+ #endif
94
+
95
+ #ifndef HAVE_RB_EKEYERROR
96
+ # define rb_eKeyError rb_eArgError
97
+ #endif
98
+
99
+ static int
100
+ directive_parse_int(const char **p, const char *end, const char *type)
101
+ {
102
+ const char *q = *p;
103
+
104
+ int n = 0;
105
+
106
+ while (q < end) {
107
+ const char *r;
108
+ uint32_t c = u_decode(&r, q, end);
109
+ if (!u_char_isdigit(c)) {
110
+ *p = q;
111
+ return n;
112
+ }
113
+ q = r;
114
+
115
+ int m = 10 * n + u_char_digit_value(c);
116
+ if (m / 10 != n) {
117
+ for ( ; q < end; q = r) {
118
+ if (!u_char_isdigit(u_decode(&r, q, end)))
119
+ break;
120
+ }
121
+ rb_u_raise(rb_eArgError,
122
+ "%s too large: %*s > %d",
123
+ type, (int)(q - *p), *p, INT_MAX);
124
+ }
125
+
126
+ n = m;
127
+ }
128
+
129
+ rb_u_raise(rb_eArgError, "directive missing after %s", type);
130
+ }
131
+
132
+ static bool
133
+ directive_argument_number(const char **p, const char *end, const char *type,
134
+ int *argument_number)
135
+ {
136
+ if (*argument_number != 0)
137
+ rb_u_raise(rb_eArgError, "%s already given", type);
138
+
139
+ const char *q = *p;
140
+ int n = directive_parse_int(&q, end, type);
141
+ if (*q != '$')
142
+ return false;
143
+ *p = q + 1;
144
+ *argument_number = n;
145
+
146
+ if (*p == end)
147
+ rb_u_raise(rb_eArgError, "directive missing after %s", type);
148
+
149
+ return true;
150
+ }
151
+
152
+ static void
153
+ directive_argument_name(const char **p, const char *end, char right,
154
+ ID *argument_id)
155
+ {
156
+ if (*argument_id != 0)
157
+ rb_u_raise(rb_eArgError, "argument name already given");
158
+
159
+ const char *q = *p;
160
+
161
+ const char *r = q;
162
+ while (r < end && u_decode(&r, q, end) != (uint32_t)right)
163
+ q = r;
164
+
165
+ if (q == end)
166
+ rb_u_raise(rb_eArgError,
167
+ "missing argument name end delimiter ‘%c’: %s",
168
+ right, *p);
169
+
170
+ const char *base = *p + 1;
171
+ long length = q - base;
172
+ #ifdef HAVE_RUBY_ENCODING_H
173
+ *argument_id = rb_intern3(base, length, rb_utf8_encoding());
174
+ #else
175
+ char name[length + 1];
176
+ memcpy(name, base, length);
177
+ name[length] = '\0';
178
+ *argument_id = rb_intern(name);
179
+ #endif
180
+
181
+ *p = r;
182
+
183
+ if (*p == end)
184
+ rb_u_raise(rb_eArgError, "directive missing after argument name");
185
+ }
186
+
187
+ static VALUE
188
+ format_arguments_absolute(struct format_arguments *arguments, int absolute)
189
+ {
190
+ if (arguments->i > 0)
191
+ rb_u_raise(rb_eArgError,
192
+ "cannot use absolute argument number %d: relative argument number already used",
193
+ absolute);
194
+
195
+ if (arguments->names != Qundef)
196
+ rb_u_raise(rb_eArgError,
197
+ "cannot use absolute argument number %d: named argument already used",
198
+ absolute);
199
+
200
+ arguments->absolute = true;
201
+
202
+ if (absolute > arguments->argc)
203
+ rb_u_raise(rb_eArgError,
204
+ "absolute argument number beyond end of argument list: %d > %d",
205
+ absolute, arguments->argc);
206
+
207
+ return arguments->argv[absolute - 1];
208
+ }
209
+
210
+ static VALUE
211
+ format_arguments_id(struct format_arguments *arguments, ID id)
212
+ {
213
+ if (arguments->i > 0)
214
+ rb_u_raise(rb_eArgError,
215
+ "cannot use named argument “%s”: relative argument number already used",
216
+ rb_id2name(id));
217
+
218
+ if (arguments->absolute)
219
+ rb_u_raise(rb_eArgError,
220
+ "cannot use named argument “%s”: absolute argument number already used",
221
+ rb_id2name(id));
222
+
223
+ if (arguments->names == Qundef) {
224
+ VALUE tmp;
225
+
226
+ if (arguments->argc != 1 ||
227
+ NIL_P(tmp = rb_check_convert_type(arguments->argv[0], T_HASH, "Hash", "to_hash")))
228
+ rb_u_raise(rb_eArgError,
229
+ "one Hash argument required when using named arguments in format");
230
+
231
+ arguments->names = tmp;
232
+ }
233
+
234
+ VALUE argument = rb_hash_lookup2(arguments->names, ID2SYM(id), Qundef);
235
+ if (argument == Qundef)
236
+ rb_u_raise(rb_eKeyError, "named argument not found: %s", rb_id2name(id));
237
+
238
+ return argument;
239
+ }
240
+
241
+ static VALUE
242
+ format_arguments_next(struct format_arguments *arguments)
243
+ {
244
+ if (arguments->absolute)
245
+ rb_u_raise(rb_eArgError,
246
+ "cannot use positional argument numbers after absolute argument numbers");
247
+
248
+ if (arguments->names != Qundef)
249
+ rb_u_raise(rb_eArgError,
250
+ "cannot use positional argument numbers after named arguments");
251
+
252
+ arguments->i++;
253
+
254
+ if (arguments->i > arguments->argc)
255
+ need_at_least_n_arguments(arguments->argc, arguments->i);
256
+
257
+ return arguments->argv[arguments->i - 1];
258
+ }
259
+
260
+ static int
261
+ directive_flags(const char **p, const char *end,
262
+ struct format_arguments *arguments,
263
+ VALUE *argument, bool *argument_to_s)
264
+ {
265
+ int flags = DIRECTIVE_FLAGS_NONE;
266
+ int argument_number = 0;
267
+ ID argument_id = 0;
268
+
269
+ while (*p < end) {
270
+ const char *q;
271
+ uint32_t c = u_decode(&q, *p, end);
272
+
273
+ int flag;
274
+
275
+ switch (c) {
276
+ case ' ':
277
+ flag = DIRECTIVE_FLAGS_SPACE;
278
+ break;
279
+ case '#':
280
+ flag = DIRECTIVE_FLAGS_SHARP;
281
+ break;
282
+ case '+':
283
+ flag = DIRECTIVE_FLAGS_PLUS;
284
+ break;
285
+ case '-':
286
+ flag = DIRECTIVE_FLAGS_MINUS;
287
+ break;
288
+ case '0':
289
+ flag = DIRECTIVE_FLAGS_ZERO;
290
+ break;
291
+ case '1':
292
+ case '2':
293
+ case '3':
294
+ case '4':
295
+ case '5':
296
+ case '6':
297
+ case '7':
298
+ case '8':
299
+ case '9':
300
+ if (!directive_argument_number(p, end, "absolute argument number", &argument_number))
301
+ goto setup_argument;
302
+ if (argument_id != 0)
303
+ rb_u_raise(rb_eArgError,
304
+ "cannot use absolute argument number: argument name already given");
305
+ continue;
306
+ case '<':
307
+ if (argument_number != 0)
308
+ rb_u_raise(rb_eArgError,
309
+ "cannot use argument name: absolute argument number already given");
310
+ directive_argument_name(p, end, '>', &argument_id);
311
+ *argument_to_s = false;
312
+ continue;
313
+ case '{':
314
+ if (argument_number != 0)
315
+ rb_u_raise(rb_eArgError,
316
+ "cannot use argument name: absolute argument number already given");
317
+ directive_argument_name(p, end, '}', &argument_id);
318
+ *argument_to_s = true;
319
+ goto setup_argument;
320
+ default:
321
+ goto setup_argument;
322
+ }
323
+
324
+ if (flags & flag)
325
+ rb_warning("repeated flag in format: ‘%c’", c);
326
+ flags |= flag;
327
+
328
+ *p = q;
329
+ }
330
+
331
+ if (flags != DIRECTIVE_FLAGS_NONE && *p == end)
332
+ rb_u_raise(rb_eArgError, "directive missing after flags");
333
+
334
+ setup_argument:
335
+ if (argument_number != 0)
336
+ *argument = format_arguments_absolute(arguments, argument_number);
337
+ else if (argument_id != 0)
338
+ *argument = format_arguments_id(arguments, argument_id);
339
+
340
+ return flags;
341
+ }
342
+
343
+ static int
344
+ directive_width(const char **p, const char *end,
345
+ struct format_arguments *arguments,
346
+ enum directive_flags *flags)
347
+ {
348
+ if (*p == end)
349
+ return 0;
350
+
351
+ const char *q;
352
+ if (u_decode(&q, *p, end) != '*')
353
+ return directive_parse_int(p, end, "field width");
354
+ *p = q;
355
+
356
+ int argument_number = 0;
357
+ VALUE argument = directive_argument_number(p, end,
358
+ "absolute field width argument number",
359
+ &argument_number) ?
360
+ format_arguments_absolute(arguments, argument_number) :
361
+ format_arguments_next(arguments);
362
+ int width = NUM2INT(argument);
363
+ if (width < 0) {
364
+ *flags |= DIRECTIVE_FLAGS_MINUS;
365
+ width = -width;
366
+ }
367
+
368
+ return width;
369
+ }
370
+
371
+ static int
372
+ directive_precision(const char **p, const char *end)
373
+ {
374
+ if (*p == end)
375
+ return -1;
376
+
377
+ const char *q;
378
+ if (u_decode(&q, *p, end) != '.')
379
+ return -1;
380
+ *p = q;
381
+
382
+ return directive_parse_int(p, end, "field precision");
383
+ }
384
+
385
+ static void
386
+ directive_validate_flags(uint32_t c, int flags, int valid)
387
+ {
388
+ char invalid[6];
389
+ int n = 0;
390
+
391
+ if ((flags & DIRECTIVE_FLAGS_SPACE) && !(valid & DIRECTIVE_FLAGS_SPACE))
392
+ invalid[n++] = ' ';
393
+ if ((flags & DIRECTIVE_FLAGS_SHARP) && !(valid & DIRECTIVE_FLAGS_SHARP))
394
+ invalid[n++] = '#';
395
+ if ((flags & DIRECTIVE_FLAGS_PLUS) && !(valid & DIRECTIVE_FLAGS_PLUS))
396
+ invalid[n++] = '+';
397
+ if ((flags & DIRECTIVE_FLAGS_MINUS) && !(valid & DIRECTIVE_FLAGS_MINUS))
398
+ invalid[n++] = '-';
399
+ if ((flags & DIRECTIVE_FLAGS_ZERO) && !(valid & DIRECTIVE_FLAGS_ZERO))
400
+ invalid[n++] = '0';
401
+ if (n == 0)
402
+ return;
403
+
404
+ invalid[n] = '\0';
405
+
406
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
407
+ int length = u_char_to_u(c, buf);
408
+ if (n == 1)
409
+ rb_u_raise(rb_eArgError,
410
+ "invalid flag ‘%s’ given to directive ‘%.*s’",
411
+ invalid, length, buf);
412
+
413
+ rb_u_raise(rb_eArgError,
414
+ "invalid flags “%s” given to directive ‘%.*s’",
415
+ invalid, length, buf);
416
+ }
417
+
418
+ NORETURN(static void
419
+ directive_simple_error(uint32_t c, const char *message))
420
+ {
421
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
422
+ int length = u_char_to_u(c, buf);
423
+ rb_u_raise(rb_eArgError, "%s: %.*s", message, length, buf);
424
+ }
425
+
426
+ static void
427
+ directive_validate_argument_not_given(uint32_t c, VALUE argument)
428
+ {
429
+ if (argument != Qundef)
430
+ directive_simple_error(c, "directive does not take an argument");
431
+ }
432
+
433
+ static void
434
+ directive_validate_width_not_given(uint32_t c, int width)
435
+ {
436
+ if (width != 0)
437
+ directive_simple_error(c, "directive does not allow specifying a width");
438
+ }
439
+
440
+ static void
441
+ directive_validate_precision_not_given(uint32_t c, int precision)
442
+ {
443
+ if (precision >= 0)
444
+ directive_simple_error(c, "directive does not allow specifying a precision");
445
+ }
446
+
447
+ static void
448
+ directive_escape(uint32_t c, VALUE result)
449
+ {
450
+ rb_u_buffer_append_char(result, c);
451
+ }
452
+
453
+ static void
454
+ directive_pad(int flags, int padding, const char *str, long length, VALUE result)
455
+ {
456
+ if (flags & DIRECTIVE_FLAGS_MINUS) {
457
+ rb_u_buffer_append(result, str, length);
458
+ rb_u_buffer_append_char_n(result, ' ', padding);
459
+ } else {
460
+ rb_u_buffer_append_char_n(result, ' ', padding);
461
+ rb_u_buffer_append(result, str, length);
462
+ }
463
+ }
464
+
465
+ static void
466
+ directive_character(UNUSED(uint32_t directive), int flags, int width, UNUSED(int precision), VALUE argument, VALUE result)
467
+ {
468
+ VALUE tmp = rb_u_string_check_type(argument);
469
+
470
+ uint32_t c;
471
+ const char *p;
472
+ int length;
473
+
474
+ if (!NIL_P(tmp)) {
475
+ const struct rb_u_string *string = RVAL2USTRING_ANY(tmp);
476
+ p = USTRING_STR(string);
477
+ const char *end = USTRING_END(string);
478
+ if (p == end)
479
+ rb_u_raise(rb_eArgError, "%%c requires a character");
480
+ const char *q;
481
+ c = u_decode(&q, p, end);
482
+ length = (int)(q - p);
483
+ } else {
484
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
485
+ p = buf;
486
+ c = NUM2INT(argument);
487
+ length = rb_u_char_to_u(c, buf);
488
+ }
489
+
490
+ int padding = width - (int)u_char_width(c);
491
+ if (padding < 0) {
492
+ rb_u_buffer_append_char(result, c);
493
+ return;
494
+ }
495
+
496
+ directive_pad(flags, padding, p, length, result);
497
+ }
498
+
499
+ static void
500
+ directive_string(UNUSED(uint32_t directive), int flags, int width, int precision, VALUE argument, VALUE result)
501
+ {
502
+ VALUE str = rb_u_string_object_as_string(argument);
503
+
504
+ if (OBJ_TAINTED(str))
505
+ OBJ_TAINT(result);
506
+
507
+ const struct rb_u_string *string = RVAL2USTRING_ANY(str);
508
+ const char *p = USTRING_STR(string);
509
+ long length = USTRING_LENGTH(string);
510
+
511
+ if (precision > 0) {
512
+ int i = 0;
513
+ const char *q = p, *end = p + length;
514
+ while (i < precision && q < end)
515
+ i += (int)u_char_width(u_decode(&q, q, end));
516
+ length = q - p;
517
+ }
518
+
519
+ long n_cells;
520
+ if (width == 0 || width < (n_cells = u_width_n(p, length))) {
521
+ rb_u_buffer_append(result, p, length);
522
+ return;
523
+ }
524
+
525
+ directive_pad(flags, width - (int)n_cells, p, length, result);
526
+ }
527
+
528
+ static void
529
+ directive_inspect(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
530
+ {
531
+ directive_string(directive, flags, width, precision, rb_inspect(argument), result);
532
+ }
533
+
534
+ static long
535
+ directive_integer_value_m(VALUE argument, VALUE *bignum)
536
+ {
537
+ switch (TYPE(argument)) {
538
+ case T_FLOAT: {
539
+ if (FIXABLE(RFLOAT_VALUE(argument)))
540
+ return (long)RFLOAT_VALUE(argument);
541
+ VALUE result = rb_dbl2big(RFLOAT_VALUE(argument));
542
+ if (FIXNUM_P(result))
543
+ return FIX2LONG(result);
544
+ *bignum = result;
545
+ return 0;
546
+ }
547
+ case T_STRING:
548
+ return directive_integer_value_m(rb_str_to_inum(argument, 0, true), bignum);
549
+ case T_BIGNUM:
550
+ *bignum = argument;
551
+ return 0;
552
+ case T_FIXNUM:
553
+ return FIX2LONG(argument);
554
+ default:
555
+ if (RTEST(rb_obj_is_kind_of(argument, rb_cUString)))
556
+ return directive_integer_value_m(rb_u_string_to_inum(argument, 0, true), bignum);
557
+ return directive_integer_value_m(rb_Integer(argument), bignum);
558
+ }
559
+ }
560
+
561
+ static long
562
+ directive_integer_value(VALUE argument, int base, VALUE *bignum)
563
+ {
564
+ long value = directive_integer_value_m(argument, bignum);
565
+ if (base == 2 && *bignum == Qundef)
566
+ return directive_integer_value_m(rb_int2big(value), bignum);
567
+ return value;
568
+ }
569
+
570
+ static void
571
+ directive_number_output(int flags, int width, int precision,
572
+ const char *prefix, uint32_t precision_filler, const char *digits, int length,
573
+ VALUE result)
574
+ {
575
+ int prefix_length = (int)strlen(prefix);
576
+ width -= prefix_length;
577
+
578
+ if (precision >= 0)
579
+ flags &= ~DIRECTIVE_FLAGS_ZERO;
580
+
581
+ if (precision < length)
582
+ precision = length;
583
+ width -= precision;
584
+
585
+ if (!(flags & DIRECTIVE_FLAGS_MINUS) && !(flags & DIRECTIVE_FLAGS_ZERO))
586
+ rb_u_buffer_append_char_n(result, ' ', width);
587
+
588
+ rb_u_buffer_append(result, prefix, prefix_length);
589
+
590
+ if (!(flags & DIRECTIVE_FLAGS_MINUS) && (flags & DIRECTIVE_FLAGS_ZERO))
591
+ rb_u_buffer_append_char_n(result, '0', width);
592
+
593
+ rb_u_buffer_append_char_n(result, precision_filler, precision - length);
594
+
595
+ rb_u_buffer_append(result, digits, length);
596
+
597
+ if (flags & DIRECTIVE_FLAGS_MINUS)
598
+ rb_u_buffer_append_char_n(result, ' ', width);
599
+ }
600
+
601
+ #define BITS2DECIMALDIGITS(n) (((long)(n) * 146) / 485 + 1) /* lg(10)⁻¹ ≈ 146/485 */
602
+ #define BITS2OCTALDIGITS(n) (((long)(n) * 1) / 3 + 1) /* lg(8)⁻¹ = 3 */
603
+
604
+ #define DIGITS_BUFFER_SIZE (BITS2OCTALDIGITS(sizeof(long) * CHAR_BIT) + 1)
605
+
606
+ #define BASE2FORMAT(base) \
607
+ ((base) == 10 ? "%ld" : ((base) == 16 ? "%lx" : "%lo"))
608
+
609
+ static void
610
+ directive_conflicting_flags_warning(uint32_t directive, int ignored, int when)
611
+ {
612
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
613
+ int length = u_char_to_u(directive, buf);
614
+ rb_warning("‘%.*s’ directive ignores ‘%c’ flag when ‘%c’ flag has been specified",
615
+ length, buf, ignored, when);
616
+ }
617
+
618
+ static bool
619
+ directive_number_sign(uint32_t directive, bool negative, int flags, char *sign)
620
+ {
621
+ if (flags & DIRECTIVE_FLAGS_PLUS && flags & DIRECTIVE_FLAGS_SPACE)
622
+ directive_conflicting_flags_warning(directive, ' ', '+');
623
+
624
+ if (negative) {
625
+ sign[0] = '-';
626
+ return true;
627
+ }
628
+
629
+ if (flags & DIRECTIVE_FLAGS_PLUS)
630
+ sign[0] = '+';
631
+ else if (flags & DIRECTIVE_FLAGS_SPACE)
632
+ sign[0] = ' ';
633
+ else
634
+ sign[0] = '\0';
635
+
636
+ return false;
637
+ }
638
+
639
+ static inline int
640
+ directive_number_long_signed(uint32_t directive, int flags, long argument,
641
+ int base, char *sign, const char **digits, char *buffer)
642
+ {
643
+ if (directive_number_sign(directive, argument < 0, flags, sign))
644
+ argument = -argument;
645
+
646
+ *digits = buffer;
647
+ return snprintf(buffer, DIGITS_BUFFER_SIZE, BASE2FORMAT(base), argument);
648
+ }
649
+
650
+ static inline int
651
+ directive_number_bignum_signed(uint32_t directive, int flags, VALUE argument,
652
+ int base, char *sign, const char **digits, VALUE *str)
653
+ {
654
+ *str = rb_big2str(argument, base);
655
+ *digits = RSTRING_PTR(*str);
656
+ if (directive_number_sign(directive, *digits[0] == '-', flags, sign))
657
+ (*digits)++;
658
+
659
+ return rb_long2int(RSTRING_END(*str) - *digits);
660
+ }
661
+
662
+ static void
663
+ directive_number_check_flags(uint32_t directive, int flags, int precision)
664
+ {
665
+ if ((flags & DIRECTIVE_FLAGS_MINUS) && (flags & DIRECTIVE_FLAGS_ZERO))
666
+ directive_conflicting_flags_warning(directive, '0', '-');
667
+
668
+ if (precision >= 0 && (flags & DIRECTIVE_FLAGS_ZERO)) {
669
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
670
+ int length = u_char_to_u(directive, buf);
671
+ rb_warning("‘%.*s’ directive ignores ‘0’ flag when precision (%d) has been specified",
672
+ length, buf, precision);
673
+ }
674
+ }
675
+
676
+ static int
677
+ directive_signed_number(uint32_t directive, int flags, int precision, VALUE argument,
678
+ int base, char *sign, const char **digits, char *buffer, VALUE *str)
679
+ {
680
+ directive_number_check_flags(directive, flags, precision);
681
+
682
+ VALUE bignum = Qundef;
683
+ long lvalue = directive_integer_value(argument, base, &bignum);
684
+
685
+ return (bignum == Qundef) ?
686
+ directive_number_long_signed(directive, flags, lvalue, base, sign, digits, buffer) :
687
+ directive_number_bignum_signed(directive, flags, bignum, base, sign, digits, str);
688
+ }
689
+
690
+ static U_PURE const char *
691
+ directive_number_skip_bits(const char *digits, int base)
692
+ {
693
+ const char *p = digits;
694
+
695
+ if (base == 16)
696
+ while (*p == 'f' || *p == 'F')
697
+ p++;
698
+ else if (base == 8) {
699
+ p++;
700
+ while (*p == '7')
701
+ p++;
702
+ } else if (base == 2)
703
+ while (*p == '1')
704
+ p++;
705
+
706
+ return p - 1;
707
+ }
708
+
709
+ static inline int
710
+ directive_number_long_unsigned(long argument,
711
+ int base, char *prefix, const char **digits, char *buffer)
712
+ {
713
+ *digits = buffer;
714
+ int length = snprintf(buffer, DIGITS_BUFFER_SIZE, BASE2FORMAT(base), (unsigned long)argument);
715
+
716
+ if (argument < 0) {
717
+ *digits = directive_number_skip_bits(buffer, base);
718
+ length -= (int)(*digits - buffer);
719
+ strcat(prefix, "..");
720
+ }
721
+
722
+ return length;
723
+ }
724
+
725
+ static inline int
726
+ directive_number_bignum_unsigned(VALUE argument,
727
+ int base, char *prefix, const char **digits, VALUE *str)
728
+ {
729
+ if (!RBIGNUM_SIGN(argument)) {
730
+ argument = rb_big_clone(argument);
731
+ rb_big_2comp(argument);
732
+ }
733
+
734
+ *str = rb_big2str0(argument, base, RBIGNUM_SIGN(argument));
735
+ *digits = RSTRING_PTR(*str);
736
+ if (*digits[0] == '-') {
737
+ *digits = directive_number_skip_bits(*digits + 1, base);
738
+ strcat(prefix, "..");
739
+ }
740
+
741
+ return rb_long2int(RSTRING_END(*str) - *digits);
742
+ }
743
+
744
+ static inline int
745
+ directive_unsigned_number(uint32_t directive, int flags, int precision, VALUE argument,
746
+ int base, char *prefix, const char **digits, char *buffer, VALUE *str)
747
+ {
748
+ directive_number_check_flags(directive, flags, precision);
749
+
750
+ VALUE bignum = Qundef;
751
+ long lvalue = directive_integer_value(argument, base, &bignum);
752
+
753
+ return (bignum == Qundef) ?
754
+ directive_number_long_unsigned(lvalue, base, prefix, digits, buffer) :
755
+ directive_number_bignum_unsigned(bignum, base, prefix, digits, str);
756
+ }
757
+
758
+ static int
759
+ directive_signed_or_unsigned_number(uint32_t directive, int flags, int precision, VALUE argument,
760
+ int base, char *prefix, const char **digits, char *buffer, VALUE *str)
761
+ {
762
+ if (!(flags & DIRECTIVE_FLAGS_SHARP))
763
+ for (char *p = prefix; *p != '\0'; p++)
764
+ *p = '\0';
765
+
766
+ if (!(flags & (DIRECTIVE_FLAGS_PLUS | DIRECTIVE_FLAGS_SPACE)))
767
+ return directive_unsigned_number(directive, flags, precision, argument, base, prefix, digits, buffer, str);
768
+
769
+ /* Move prefix forward one position to make room for sign. */
770
+ for (char *p = prefix + strlen(prefix); p > prefix; p--)
771
+ *p = *(p - 1);
772
+
773
+ return directive_signed_number(directive, flags, precision, argument, base, prefix, digits, buffer, str);
774
+ }
775
+
776
+ static void
777
+ directive_integer(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
778
+ {
779
+ char sign[] = "\0\0";
780
+ char buffer[DIGITS_BUFFER_SIZE];
781
+ VALUE str;
782
+ const char *digits;
783
+ int length = directive_signed_number(directive, flags, precision, argument, 10, sign, &digits, buffer, &str);
784
+
785
+ directive_number_output(flags, width, precision, sign, '0', digits, length, result);
786
+ }
787
+
788
+ static bool
789
+ directive_number_is_unsigned(char *prefix)
790
+ {
791
+ return strstr(prefix, "..") != NULL;
792
+ }
793
+
794
+ static void
795
+ directive_ignored_flag_on_negative_argument_warning(uint32_t directive, int ignored)
796
+ {
797
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
798
+ int length = u_char_to_u(directive, buf);
799
+ rb_warning("‘%.*s’ directive ignores ‘%c’ flag when given a negative argument",
800
+ length, buf, ignored);
801
+ }
802
+
803
+ static void
804
+ directive_unsigned_number_output(uint32_t directive, int flags, int width, int precision,
805
+ char *prefix, const char *digits, int length,
806
+ VALUE result)
807
+ {
808
+ if (directive_number_is_unsigned(prefix)) {
809
+ if (flags & DIRECTIVE_FLAGS_ZERO)
810
+ directive_ignored_flag_on_negative_argument_warning(directive, '0');
811
+
812
+ directive_number_output(flags & ~DIRECTIVE_FLAGS_ZERO,
813
+ width,
814
+ precision < 0 ? precision :
815
+ (precision - 2 >= 0 ? precision - 2 : 0),
816
+ prefix, digits[0], digits, length,
817
+ result);
818
+ } else
819
+ directive_number_output(flags, width, precision, prefix, '0', digits, length, result);
820
+
821
+ }
822
+
823
+ static void
824
+ directive_octal(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
825
+ {
826
+ char prefix[] = "0\0\0\0\0";
827
+ char buffer[DIGITS_BUFFER_SIZE];
828
+ VALUE str;
829
+ const char *digits;
830
+ int length = directive_signed_or_unsigned_number(directive, flags, precision, argument, 8, prefix, &digits, buffer, &str);
831
+
832
+ if ((flags & DIRECTIVE_FLAGS_SHARP) &&
833
+ (precision >= 0 ||
834
+ directive_number_is_unsigned(prefix) ||
835
+ (length == 1 && digits[0] == '0'))) {
836
+ if (directive_number_is_unsigned(prefix))
837
+ directive_ignored_flag_on_negative_argument_warning(directive, '#');
838
+
839
+ for (char *p = prefix; *p != '\0'; p++)
840
+ *p = *(p + 1);
841
+ }
842
+
843
+ directive_unsigned_number_output(directive, flags, width, precision, prefix, digits, length, result);
844
+ }
845
+
846
+ static void
847
+ directive_hexadecimal(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
848
+ {
849
+ char prefix[] = "0x\0\0\0\0";
850
+ if (directive == 'X')
851
+ prefix[1] = 'X';
852
+ char buffer[DIGITS_BUFFER_SIZE];
853
+ VALUE str;
854
+ const char *digits;
855
+ int length = directive_signed_or_unsigned_number(directive, flags, precision, argument, 16, prefix, &digits, buffer, &str);
856
+
857
+ if ((flags & DIRECTIVE_FLAGS_SHARP) && (length == 1 && digits[0] == '0'))
858
+ for (char *p = prefix; *p != '\0'; p++)
859
+ *p = '\0';
860
+
861
+ if (directive == 'X')
862
+ for (char *p = (char *)digits; *p != '\0'; p++)
863
+ *p = u_char_upcase(*p);
864
+
865
+ directive_unsigned_number_output(directive, flags, width, precision, prefix, digits, length, result);
866
+ }
867
+
868
+ static void
869
+ directive_binary(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
870
+ {
871
+ char prefix[] = "0b\0\0\0\0";
872
+ if (directive == 'B')
873
+ prefix[1] = 'B';
874
+ char buffer[DIGITS_BUFFER_SIZE];
875
+ VALUE str;
876
+ const char *digits;
877
+ int length = directive_signed_or_unsigned_number(directive, flags, precision, argument, 2, prefix, &digits, buffer, &str);
878
+
879
+ if ((flags & DIRECTIVE_FLAGS_SHARP) && (length == 1 && digits[0] == '0'))
880
+ for (char *p = prefix; *p != '\0'; p++)
881
+ *p = '\0';
882
+
883
+ directive_unsigned_number_output(directive, flags, width, precision, prefix, digits, length, result);
884
+ }
885
+
886
+ static inline void
887
+ directive_float_nan(uint32_t directive, int flags, int width, VALUE result)
888
+ {
889
+ /* sign? + NaN + \0 */
890
+ char buffer[1 + 3 + 1] = "\0";
891
+ int length = 3;
892
+
893
+ directive_number_sign(directive, false, flags, buffer);
894
+ if (buffer[0] != '\0')
895
+ length++;
896
+
897
+ strcat(buffer, "NaN");
898
+
899
+ directive_pad(flags, width - length, buffer, length, result);
900
+ }
901
+
902
+ static inline void
903
+ directive_float_inf(uint32_t directive, int flags, int width, double argument, VALUE result)
904
+ {
905
+ /* sign? + Inf + \0 */
906
+ char buffer[1 + 3 + 1] = "\0";
907
+ int length = 3;
908
+
909
+ directive_number_sign(directive, argument < 0.0, flags, buffer);
910
+ if (buffer[0] != '\0')
911
+ length++;
912
+
913
+ strcat(buffer, "Inf");
914
+
915
+ directive_pad(flags, width - length, buffer, length, result);
916
+ }
917
+
918
+ #pragma GCC diagnostic ignored "-Wformat-nonliteral"
919
+ static void
920
+ directive_float_format(uint32_t directive, int flags, int width, int precision, double argument, VALUE result)
921
+ {
922
+ char format[1 + /* '%' */
923
+ 5 + /* flags{0,5} */
924
+ BITS2DECIMALDIGITS(sizeof(width) * CHAR_BIT) + /* width_digits? */
925
+ 1 + /* ('.' */
926
+ BITS2DECIMALDIGITS(sizeof(precision) * CHAR_BIT) + /* precision_digits)? */
927
+ 1 + /* directive */
928
+ 1]; /* '\0' */
929
+ char *p = format;
930
+ const char *end = format + lengthof(format);
931
+
932
+ *p++ = '%';
933
+ if (flags & DIRECTIVE_FLAGS_SHARP)
934
+ *p++ = '#';
935
+ if (flags & DIRECTIVE_FLAGS_PLUS)
936
+ *p++ = '+';
937
+ if (flags & DIRECTIVE_FLAGS_MINUS)
938
+ *p++ = '-';
939
+ if (flags & DIRECTIVE_FLAGS_ZERO)
940
+ *p++ = '0';
941
+ if (flags & DIRECTIVE_FLAGS_SPACE)
942
+ *p++ = ' ';
943
+
944
+ if (width > 0)
945
+ p += snprintf(p, end - p, "%d", width);
946
+
947
+ if (precision >= 0)
948
+ p += snprintf(p, end - p, ".%d", precision);
949
+
950
+ *p++ = directive;
951
+ *p = '\0';
952
+
953
+ int exponent = 0;
954
+ frexp(argument, &exponent);
955
+ /* sign? +
956
+ * prefix? +
957
+ * character-before-separator? +
958
+ * (decimal_digits or characters after exponent) +
959
+ * separator? +
960
+ * precision? +
961
+ * exponent-char?
962
+ * exponent-±?
963
+ */
964
+ size_t needed = 1 +
965
+ 2 +
966
+ 1 +
967
+ abs((int)BITS2DECIMALDIGITS(exponent)) +
968
+ 1 +
969
+ (size_t)(precision >= 0 ? precision : 0) +
970
+ 1 +
971
+ 1;
972
+ if (needed < (size_t)width)
973
+ needed = width;
974
+ needed += 1;
975
+
976
+ rb_u_buffer_append_printf(result, needed, format, argument);
977
+ }
978
+ #pragma GCC diagnostic warning "-Wformat-nonliteral"
979
+
980
+ static void
981
+ directive_float(uint32_t directive, int flags, int width, int precision, VALUE argument, VALUE result)
982
+ {
983
+ double value = RFLOAT_VALUE(rb_Float(argument));
984
+
985
+ if (isnan(value))
986
+ directive_float_nan(directive, flags, width, result);
987
+ else if (isinf(value))
988
+ directive_float_inf(directive, flags, width, value, result);
989
+ else
990
+ directive_float_format(directive, flags, width, precision, value, result);
991
+ }
992
+
993
+ static void
994
+ directive(const char **p, const char *end, struct format_arguments *arguments, VALUE result)
995
+ {
996
+ VALUE argument = Qundef;
997
+ bool argument_to_s = false;
998
+ enum directive_flags flags = directive_flags(p, end, arguments, &argument, &argument_to_s);
999
+ if (argument_to_s) {
1000
+ directive_validate_flags('s', flags, DIRECTIVE_FLAGS_MINUS);
1001
+ directive_string('s', flags, 0, 0, argument, result);
1002
+ return;
1003
+ }
1004
+
1005
+ int width = directive_width(p, end, arguments, &flags);
1006
+
1007
+ int precision = directive_precision(p, end);
1008
+
1009
+ uint32_t c = '\0';
1010
+ if (*p < end)
1011
+ c = u_decode(p, *p, end);
1012
+ switch (c) {
1013
+ case '%':
1014
+ case '\0':
1015
+ case '\n':
1016
+ directive_validate_flags('%', flags, DIRECTIVE_FLAGS_NONE);
1017
+ directive_validate_argument_not_given('%', argument);
1018
+ directive_validate_width_not_given('%', width);
1019
+ directive_validate_precision_not_given('%', precision);
1020
+ directive_escape('%', result);
1021
+ if (c == '\n' || (c == '\0' && *p != end))
1022
+ directive_escape(c, result);
1023
+ return;
1024
+ default:
1025
+ break;
1026
+ }
1027
+
1028
+ static struct {
1029
+ uint32_t c;
1030
+ int flags;
1031
+ bool width;
1032
+ bool precision;
1033
+ void (*f)(uint32_t c, int, int, int, VALUE, VALUE);
1034
+ } directives[] = {
1035
+ { 'c', DIRECTIVE_FLAGS_MINUS, true, false, directive_character },
1036
+ { 's', DIRECTIVE_FLAGS_MINUS, true, true, directive_string },
1037
+ { 'p', DIRECTIVE_FLAGS_MINUS, true, true, directive_inspect },
1038
+ { 'd', DIRECTIVE_FLAGS_DECIMAL, true, true, directive_integer },
1039
+ { 'i', DIRECTIVE_FLAGS_DECIMAL, true, true, directive_integer },
1040
+ { 'u', DIRECTIVE_FLAGS_DECIMAL, true, true, directive_integer },
1041
+ { 'o', DIRECTIVE_FLAGS_NUMBER, true, true, directive_octal },
1042
+ { 'x', DIRECTIVE_FLAGS_NUMBER, true, true, directive_hexadecimal },
1043
+ { 'X', DIRECTIVE_FLAGS_NUMBER, true, true, directive_hexadecimal },
1044
+ { 'b', DIRECTIVE_FLAGS_NUMBER, true, true, directive_binary },
1045
+ { 'B', DIRECTIVE_FLAGS_NUMBER, true, true, directive_binary },
1046
+ { 'f', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1047
+ { 'g', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1048
+ { 'G', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1049
+ { 'e', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1050
+ { 'E', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1051
+ { 'a', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float },
1052
+ { 'A', DIRECTIVE_FLAGS_NUMBER, true, true, directive_float }
1053
+ };
1054
+
1055
+ for (size_t i = 0; i < lengthof(directives); i++)
1056
+ if (directives[i].c == c) {
1057
+ directive_validate_flags(c, flags, directives[i].flags);
1058
+ if (!directives[i].width)
1059
+ directive_validate_width_not_given(c, width);
1060
+ if (!directives[i].precision)
1061
+ directive_validate_precision_not_given(c, precision);
1062
+ directives[i].f(c,
1063
+ flags,
1064
+ width,
1065
+ precision,
1066
+ argument == Qundef ?
1067
+ format_arguments_next(arguments) :
1068
+ argument,
1069
+ result);
1070
+ return;
1071
+ }
1072
+
1073
+ char buf[U_CHAR_MAX_BYTE_LENGTH];
1074
+ int length = u_char_to_u(c, buf);
1075
+ rb_u_raise(rb_eArgError, "unknown directive: %.*s", length, buf);
1076
+ }
1077
+
1078
+ VALUE
1079
+ rb_u_buffer_append_format(int argc, const VALUE *argv, VALUE self, VALUE format)
1080
+ {
1081
+ const struct rb_u_string *string = RVAL2USTRING_ANY(format);
1082
+ const char *p = USTRING_STR(string);
1083
+ const char *end = USTRING_END(string);
1084
+
1085
+ struct format_arguments arguments = {
1086
+ .argc = argc,
1087
+ .argv = argv,
1088
+ .i = 0,
1089
+ .absolute = false,
1090
+ .names = Qundef
1091
+ };
1092
+
1093
+ while (p < end) {
1094
+ const char *q = p;
1095
+
1096
+ while (q < end && *q != '%')
1097
+ q++;
1098
+
1099
+ rb_u_buffer_append(self, p, q - p);
1100
+
1101
+ if (q == end)
1102
+ break;
1103
+
1104
+ p = q + 1;
1105
+
1106
+ directive(&p, end, &arguments, self);
1107
+ }
1108
+
1109
+ if (OBJ_TAINTED(format))
1110
+ OBJ_TAINT(self);
1111
+
1112
+ return self;
1113
+ }
1114
+
1115
+ /* @overload append_format(format, *values)
1116
+ *
1117
+ * Appends the result of FORMAT#%(values) to the receiver.
1118
+ *
1119
+ * @param [U::String, #to_str] format
1120
+ * @return [self] */
1121
+ VALUE
1122
+ rb_u_buffer_append_format_m(int argc, const VALUE *argv, VALUE self)
1123
+ {
1124
+ need_at_least_n_arguments(argc, 1);
1125
+
1126
+ return rb_u_buffer_append_format(argc - 1, argv + 1, self, argv[0]);
1127
+ }
1128
+
1129
+
1130
+ VALUE
1131
+ rb_u_string_format(int argc, const VALUE *argv, VALUE self)
1132
+ {
1133
+ return rb_u_buffer_to_u_bang(rb_u_buffer_append_format(argc,
1134
+ argv,
1135
+ rb_u_buffer_new_sized(127),
1136
+ self));
1137
+ }
1138
+
1139
+ /* @overload %(value)
1140
+ *
1141
+ * Returns a formatted string of the values in Array(VALUE) by treating the
1142
+ * receiver as a format specification of this formatted string.
1143
+ *
1144
+ * A format specification is a string consisting of sequences of normal
1145
+ * characters that are copied verbatim and field specifiers. A field
1146
+ * specifier consists of a `%`, followed by any optional flags, an optional
1147
+ * width, an optional precision, and a directive:
1148
+ *
1149
+ * %[flags][width][.[precision]]directive
1150
+ *
1151
+ * Note that this means that a lone `%` at the end of the string is simply
1152
+ * copied verbatim as it, by this definition, isn’t a field directive.
1153
+ *
1154
+ * The directive determines how this field should be formatted. The flags,
1155
+ * width, and precision modify this interpretation.
1156
+ *
1157
+ * The field often takes a value from VALUE and formats it according to a
1158
+ * given set of rules, which depend on the flags, width, and precision, but
1159
+ * can also output other, hardwired, values.
1160
+ *
1161
+ * The directives that don’t take a value are
1162
+ *
1163
+ * <table>
1164
+ * <thead>
1165
+ * <tr><th>Directive</th><th>Description</th></tr>
1166
+ * </thead>
1167
+ * <tbody>
1168
+ * <tr>
1169
+ * <td>%</td>
1170
+ * <td>Outputs ‘%’.</td>
1171
+ * </tr>
1172
+ * <tr>
1173
+ * <td>\n</td>
1174
+ * <td>Outputs “%\n”.</td>
1175
+ * </tr>
1176
+ * <tr>
1177
+ * <td>\0</td>
1178
+ * <td>Outputs “%\0”.</td>
1179
+ * </tr>
1180
+ * </tbody>
1181
+ * </table>
1182
+ *
1183
+ * None of these directives take any flags, width, or precision.
1184
+ *
1185
+ * All of the following directives allow you to specify a width. The width
1186
+ * only ever limits the minimum width of the field, that is, at least _width_
1187
+ * cells will be filled by the field, but perhaps more will actually be
1188
+ * required in the end.
1189
+ *
1190
+ * <dl>
1191
+ * <dt>c</dt>
1192
+ * <dd>
1193
+ * <p>Outputs</p>
1194
+ *
1195
+ * <pre><code>[left-padding]character[right-padding]</code></pre>
1196
+ *
1197
+ * <p>If a width <em>w</em> has been specified and the
1198
+ * ‘<code>-</code>’ flag hasn’t been given, <em>left-padding</em>
1199
+ * consists of enough spaces to make the whole field at least <em>w</em>
1200
+ * cells wide, otherwise it’s empty.</p>
1201
+ *
1202
+ * <p><em>Character</em> is the result of #to_str#chr on the
1203
+ * argument, if it responds to #to_str, otherwise it’s the result of
1204
+ * #to_int turned into a string containing the character at that code
1205
+ * point. A precision isn’t allowed. The {#width} of the character is
1206
+ * used in any width calculations.</p>
1207
+ *
1208
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1209
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1210
+ * to make the whole field at least <em>w</em> cells wide, otherwise it’s
1211
+ * empty.</p>
1212
+ * </dd>
1213
+ * <dt>s</dt>
1214
+ * <dd>
1215
+ * <p>Outputs</p>
1216
+ *
1217
+ * <pre><code>[left-padding]string[right-padding]</code></pre>
1218
+ *
1219
+ * <p><em>Left-padding</em> and <em>right-padding</em> are the same as
1220
+ * for the ‘c’ directive described above.</p>
1221
+ *
1222
+ * <p><em>String</em> is a substring of the result of #to_s on the
1223
+ * argument that is <em>w</em> cells wide, where <em>w</em> = precision,
1224
+ * if a precision has been specified, <em>w</em> = {#width}
1225
+ * otherwise.</p>
1226
+ * </dd>
1227
+ * <dt>p</dt>
1228
+ * <dd>
1229
+ * <p>Outputs</p>
1230
+ *
1231
+ * <pre><code>[left-padding]inspect[right-padding]</code></pre>
1232
+ *
1233
+ * <p><em>Left-padding</em> and <em>right-padding</em> are the same as
1234
+ * for the ‘c’ directive described above.</p>
1235
+ *
1236
+ * <p><em>String</em> is a substring of the result of #inspect on the
1237
+ * argument that is <em>w</em> cells wide, where <em>w</em> = precision,
1238
+ * if a precision has been specified, <em>w</em> = {#width}
1239
+ * otherwise.</p>
1240
+ * </dd>
1241
+ * <dt>d</dt>
1242
+ * <dt>i</dt>
1243
+ * <dt>u</dt>
1244
+ * <dd>
1245
+ * <p>Outputs</p>
1246
+ *
1247
+ * <pre><code>[left-padding][prefix/sign][zeroes]
1248
+ * [precision-filler]digits[right-padding]</code></pre>
1249
+ *
1250
+ * <p>If a width <em>w</em> has been specified and neither the
1251
+ * ‘<code>-</code>’ nor the ‘<code>0</code>’ flag has been given,
1252
+ * <em>left-padding</em> consists of enough spaces to make the whole
1253
+ * field at least <em>w</em> cells wide, otherwise it’s empty.</p>
1254
+ *
1255
+ * <p><em>Prefix/sign</em> is “-” if the argument is negative, “+” if the
1256
+ * ‘<code>+</code>’ flag was given, and “ ” if the ‘<code> </code>’ flag
1257
+ * was given, otherwise it’s empty.</p>
1258
+ *
1259
+ * <p>If a width <em>w</em> has been specified and the ‘<code>0</code>’
1260
+ * flag has been given and neither the ‘<code>-</code>’ flag has been
1261
+ * given nor a precision has been specified, <em>zeroes</em> consists of
1262
+ * enough zeroes to make the whole field at least <em>w</em> cells wide,
1263
+ * otherwise it’s empty.</p>
1264
+ *
1265
+ * <p>If a precision <em>p</em> has been specified,
1266
+ * <em>precision-filler</em> consists of enough zeroes to make for
1267
+ * <em>p</em> digits of output, otherwise it’s empty.</p>
1268
+ *
1269
+ * <p><em>Digits</em> consists of the digits in base 10 that represent
1270
+ * the result of calling Integer with the argument as its argument.</p>
1271
+ *
1272
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1273
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1274
+ * to make the whole field at least <em>w</em> cells wide, otherwise it’s
1275
+ * empty.</p>
1276
+ *
1277
+ * <table>
1278
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1279
+ * <tbody>
1280
+ * <tr>
1281
+ * <td>(Space)</td>
1282
+ * <td>Add a “ ” prefix to non-negative numbers</td>
1283
+ * </tr>
1284
+ * <tr>
1285
+ * <td><code>+</code></td>
1286
+ * <td>Add a “+” sign to non-negative numbers; overrides the
1287
+ * ‘<code> </code>’ flag</td>
1288
+ * </tr>
1289
+ * <tr>
1290
+ * <td><code>0</code></td>
1291
+ * <td>Use ‘0’ for any width padding; ignored when a precision has
1292
+ * been specified</td>
1293
+ * </tr>
1294
+ * <tr>
1295
+ * <td><code>-</code></td>
1296
+ * <td>Left justify the output with ‘ ’ as padding; overrides the
1297
+ * ‘<code>0</code>’ flag</td>
1298
+ * </tr>
1299
+ * </tbody>
1300
+ * </table>
1301
+ * </dd>
1302
+ * <dt>o</dt>
1303
+ * <dd>
1304
+ * <p>Outputs</p>
1305
+ *
1306
+ * <pre><code>[left-padding][prefix/sign][zeroes/sevens]
1307
+ * [precision-filler]octal-digits[right-padding]</code></pre>
1308
+ *
1309
+ * <p>If a width <em>w</em> has been specified and neither the
1310
+ * ‘<code>-</code>’ nor the ‘<code>0</code>’ flag has been given,
1311
+ * <em>left-padding</em> consists of enough spaces to make the whole
1312
+ * field at least <em>w</em> cells wide, otherwise it’s empty.</p>
1313
+ *
1314
+ * <p><em>Prefix/sign</em> is “-” if the argument is negative and the
1315
+ * ‘<code>+</code>’ or ‘<code> </code>’ flag was given, “..” if the
1316
+ * argument is negative, “+” if the ‘<code>+</code>’ flag was given, and
1317
+ * “ ” if the ‘<code> </code>’ flag was given, otherwise it’s empty.</p>
1318
+ *
1319
+ * <p>If a width <em>w</em> has been specified and the ‘<code>0</code>’
1320
+ * flag has been given and neither the ‘<code>-</code>’ flag has been
1321
+ * given nor a precision has been specified, <em>zeroes/sevens</em>
1322
+ * consists of enough zeroes, if the argument is non-negative or if the
1323
+ * ‘<code>+</code>’ or ‘<code> </code>’ flag has been specified, sevens
1324
+ * otherwise, to make the whole field at least <em>w</em> cells wide,
1325
+ * otherwise it’s empty.</p>
1326
+ *
1327
+ * <p>If a precision <em>p</em> has been specified,
1328
+ * <em>precision-filler</em> consists of enough zeroes, if the argument
1329
+ * is non-negative or if the ‘<code>+</code>’ or ‘<code> </code>’ flag
1330
+ * has been specified, sevens otherwise, to make for <em>p</em> digits of
1331
+ * output, otherwise it’s empty.</p>
1332
+ *
1333
+ * <p><em>Octal-digits</em> consists of the digits in base 8 that
1334
+ * represent the result of #to_int on the argument, using ‘0’ through
1335
+ * ‘7’. A negative value will be output as a two’s complement value.</p>
1336
+ *
1337
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1338
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1339
+ * to make the whole field at least <em>w</em> cells wide, otherwise it’s
1340
+ * empty.</p>
1341
+ *
1342
+ * <table>
1343
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1344
+ * <tbody>
1345
+ * <tr>
1346
+ * <td>(Space)</td>
1347
+ * <td>Add a “ ” prefix to non-negative numbers and don’t output
1348
+ * negative numbers as two’s complement values</td>
1349
+ * </tr>
1350
+ * <tr>
1351
+ * <td><code>+</code></td>
1352
+ * <td>Add a “+” sign to non-negative numbers and don’t output
1353
+ * negative numbers as two’s complement values; overrides the
1354
+ * ‘<code> </code>’ flag</td>
1355
+ * </tr>
1356
+ * <tr>
1357
+ * <td><code>0</code></td>
1358
+ * <td>Use ‘0’ for any width padding; ignored when a precision has
1359
+ * been specified</td>
1360
+ * </tr>
1361
+ * <tr>
1362
+ * <td><code>-</code></td>
1363
+ * <td>Left justify the output with ‘ ’ as padding; overrides the
1364
+ * ‘<code>0</code>’ flag</td>
1365
+ * </tr>
1366
+ * <tr>
1367
+ * <td><code>#</code></td>
1368
+ * <td>Increase precision to include as many digits as necessary to
1369
+ * make the first digit ‘0’, but don’t include the ‘0’ itself</td>
1370
+ * </tr>
1371
+ * </tbody>
1372
+ * </table>
1373
+ * </dd>
1374
+ * <dt>x</dt>
1375
+ * <dd>
1376
+ * <p>Outputs</p>
1377
+ *
1378
+ * <pre><code>[left-padding][sign][base-prefix][prefix][zeroes/fs]
1379
+ * [precision-filler]hexadecimal-digits[right-padding]</code></pre>
1380
+ *
1381
+ * <p><em>Left-padding</em> and <em>right-padding</em> are the same as
1382
+ * for the ‘o’ directive described above. <em>Zeroes/fs</em> is the same
1383
+ * as <em>zeroes/sevens</em> for the ‘o’ directive, except that it uses
1384
+ * ‘f’ characters instead of sevens. The same goes for
1385
+ * <em>precision-filler</em>.</p>
1386
+ *
1387
+ * <p><em>Sign</em> is “-” if the argument is negative and the
1388
+ * ‘<code>+</code>’ or ‘<code> </code>’ flag was given, “+” if the
1389
+ * argument is non-negative and the ‘<code>+</code>’ flag was given, and
1390
+ * “ ” if the argument is non-negative and the ‘<code> </code>’ flag was
1391
+ * given, otherwise it’s empty.</p>
1392
+ *
1393
+ * <p><em>Base-prefix</em> is “0x” if the ‘<code>#</code>’ flag was given
1394
+ * and the result of #to_int on the argument is non-zero.</p>
1395
+ *
1396
+ * <p><em>Prefix</em> is “..” if the argument is negative and neither the
1397
+ * ‘<code>+</code>’ nor the ‘<code> </code>’ flag was given.</p>
1398
+ *
1399
+ * <p><em>Hexadecimal-digits</em> consists of the digits in base 16 that
1400
+ * represent the result of #to_int on the argument, using ‘0’ through ‘9’
1401
+ * and ‘a’ through ‘f’. A negative value will be output as a two’s
1402
+ * complement value.</p>
1403
+ *
1404
+ * <table>
1405
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1406
+ * <tbody>
1407
+ * <tr><td>(Space)</td><td>Same as for ‘o’</td></tr>
1408
+ * <tr><td><code>+</code></td><td>Same as for ‘o’</td></tr>
1409
+ * <tr><td><code>0</code></td><td>Same as for ‘o’</td></tr>
1410
+ * <tr><td><code>-</code></td><td>Same as for ‘o’</td></tr>
1411
+ * <tr><td><code>#</code></td><td>Prefix non-zero values with “0x”</td></tr>
1412
+ * </tbody>
1413
+ * </table>
1414
+ * </dd>
1415
+ * <dt>X</dt>
1416
+ * <dd>
1417
+ * <p>Same as ‘x’, except that it uses uppercase letters instead.</p>
1418
+ * </dd>
1419
+ * <dt>b</dt>
1420
+ * <dd>
1421
+ * <p>Outputs</p>
1422
+ *
1423
+ * <pre><code>[left-padding][sign][base-prefix][prefix][zeroes/ones]
1424
+ * [precision-filler]binary-digits[right-padding]</code></pre>
1425
+ *
1426
+ * <p><em>Left-padding</em> and <em>right-padding</em> are the same as
1427
+ * for the ‘o’ directive described above. <em>Base-prefix</em> and
1428
+ * <em>prefix</em> are the same as for the ‘x’ directive, except that
1429
+ * <em>base-prefix</em> outputs “0b”. <em>Zeroes/ones</em> is the same
1430
+ * as <em>zeroes/fs</em> for the ‘x’ directive, except that it uses ones
1431
+ * instead of sevens. The same goes for <em>precision-filler</em>.</p>
1432
+ *
1433
+ * <p><em>Binary-digits</em> consists of the digits in base 2 that
1434
+ * represent the result of #to_int on the argument, using ‘0’ and ‘1’. A
1435
+ * negative value will be output as a two’s complement value.</p>
1436
+ *
1437
+ * <table>
1438
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1439
+ * <tbody>
1440
+ * <tr><td>(Space)</td><td>Same as for ‘o’</td></tr>
1441
+ * <tr><td><code>+</code></td><td>Same as for ‘o’</td></tr>
1442
+ * <tr><td><code>0</code></td><td>Same as for ‘o’</td></tr>
1443
+ * <tr><td><code>-</code></td><td>Same as for ‘o’</td></tr>
1444
+ * <tr><td><code>#</code></td><td>Prefix non-zero values with “0b”</td></tr>
1445
+ * </tbody>
1446
+ * </table>
1447
+ * </dd>
1448
+ * <dt>B</dt>
1449
+ * <dd>
1450
+ * <p>Same as ‘b’, except that it uses a “0B” prefix for the
1451
+ * ‘<code>#</code>’ flag.</p>
1452
+ * </dd>
1453
+ * <dt>f</dt>
1454
+ * <dd>
1455
+ * <p>Outputs</p>
1456
+ *
1457
+ * <pre><code>[left-padding][prefix/sign][zeroes]
1458
+ * integer-part[decimal-point][fractional-part][right-padding]</code></pre>
1459
+ *
1460
+ * <p>If a width <em>w</em> has been specified and neither the
1461
+ * ‘<code>-</code>’ nor the ‘<code>0</code>’ flag has been given,
1462
+ * <em>left-padding</em> consists of enough spaces to make the whole
1463
+ * field at least <em>w</em> cells wide, otherwise it’s empty.</p>
1464
+ *
1465
+ * <p><em>Prefix/sign</em> is “-” if the argument is negative, “+” if the
1466
+ * ‘<code>+</code>’ flag was given, and “ ” if the ‘<code> </code>’ flag
1467
+ * was given, otherwise it’s empty.</p>
1468
+ *
1469
+ * <p>If a width <em>w</em> has been specified and the ‘<code>0</code>’
1470
+ * flag has been given and the ‘<code>-</code>’ flag has not been given,
1471
+ * <em>zeroes</em> consists of enough zeroes to make the whole field
1472
+ * at least <em>w</em> cells wide, otherwise it’s empty.</p>
1473
+ *
1474
+ * <p><em>Integer-part</em> consists of the digits in base 10 that
1475
+ * represent the integer part of the result of calling Float with the
1476
+ * argument as its argument.</p>
1477
+ *
1478
+ * <p><em>Decimal-point</em> is “.” if the precision isn’t 0 or if the
1479
+ * ‘<code>#</code>’ flag has been given.</p>
1480
+ *
1481
+ * <p><em>Fractional-part</em> consists of <em>p</em> digits in base 10
1482
+ * that represent the fractional part of the result of calling Float with
1483
+ * the argument as its argument, where <em>p</em> = precision, if one has
1484
+ * been specified, <em>p</em> = 6 otherwise.</p>
1485
+ *
1486
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1487
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1488
+ * to make the whole field at least <em>w</em> cells wide, otherwise it’s
1489
+ * empty.</p>
1490
+ *
1491
+ * <table>
1492
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1493
+ * <tbody>
1494
+ * <tr>
1495
+ * <td>(Space)</td>
1496
+ * <td>Add a “ ” prefix to non-negative numbers</td>
1497
+ * </tr>
1498
+ * <tr>
1499
+ * <td><code>+</code></td>
1500
+ * <td>Add a “+” sign to non-negative numbers; overrides the
1501
+ * ‘<code> </code>’ flag</td>
1502
+ * </tr>
1503
+ * <tr>
1504
+ * <td><code>0</code></td>
1505
+ * <td>Use ‘0’ for any width padding; ignored when a precision has
1506
+ * been specified</td>
1507
+ * </tr>
1508
+ * <tr>
1509
+ * <td><code>-</code></td>
1510
+ * <td>Left justify the output with ‘ ’ as padding; overrides the
1511
+ * ‘<code>0</code>’ flag</td>
1512
+ * </tr>
1513
+ * <tr>
1514
+ * <td>#</td>
1515
+ * <td>Output a decimal point, even if no fractional part
1516
+ * follows</td>
1517
+ * </tr>
1518
+ * </tbody>
1519
+ * </table>
1520
+ * </dd>
1521
+ * <dt>e</dt>
1522
+ * <dd>
1523
+ * <p>Outputs</p>
1524
+ *
1525
+ * <pre><code>[left-padding][prefix/sign][zeroes]
1526
+ * digit[decimal-point][fractional-part]exponent[right-padding]</code></pre>
1527
+ *
1528
+ * <p>If a width <em>w</em> has been specified and neither the
1529
+ * ‘<code>-</code>’ nor the ‘<code>0</code>’ flag has been given,
1530
+ * <em>left-padding</em> consists of enough spaces to make the whole
1531
+ * field at least <em>w</em> + <em>e</em> cells wide, where <em>e</em> ≥
1532
+ * 4 is the width of the exponent, otherwise it’s empty.</p>
1533
+ *
1534
+ * <p><em>Prefix/sign</em> is “-” if the argument is negative, “+” if the
1535
+ * ‘<code>+</code>’ flag was given, and “ ” if the ‘<code> </code>’ flag
1536
+ * was given, otherwise it’s empty.</p>
1537
+ *
1538
+ * <p>If a width <em>w</em> has been specified and the ‘<code>0</code>’
1539
+ * flag has been given and the ‘<code>-</code>’ flag has not been given,
1540
+ * <em>zeroes</em> consists of enough zeroes to make the whole field
1541
+ * <em>w</em> + <em>e</em> cells wide, where <em>e</em> ≥ 4 is the width
1542
+ * of the exponent, otherwise it’s empty.</p>
1543
+ *
1544
+ * <p><em>Digit</em> consists of one digit in base 10 that represent the
1545
+ * most significant digit of the result of calling Float with the
1546
+ * argument as its argument.</p>
1547
+ *
1548
+ * <p><em>Decimal-point</em> is “.” if the precision isn’t 0 or if the
1549
+ * ‘<code>#</code>’ flag has been given.</p>
1550
+ *
1551
+ * <p><em>Fractional-part</em> consists of <em>p</em> digits in base 10
1552
+ * that represent all but the most significant digit of the result of
1553
+ * calling Float with the argument as its argument, where <em>p</em> =
1554
+ * precision, if one has been specified, <em>p</em> = 6 otherwise.</p>
1555
+ *
1556
+ * <p><em>Exponent</em> consists of “e” followed by the exponent in base
1557
+ * 10 required to turn the result of calling Float with the argument as
1558
+ * its argument into a decimal fraction with one non-zero digit in the
1559
+ * integer part. If the exponent is 0, “+00” will be output.</p>
1560
+ *
1561
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1562
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1563
+ * to make the whole field at least <em>w</em> + <em>e</em> cells wide,
1564
+ * where <em>e</em> ≥ 4 is the width of the exponent, otherwise it’s
1565
+ * empty.</p>
1566
+ *
1567
+ * <table>
1568
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1569
+ * <tbody>
1570
+ * <tr>
1571
+ * <td>(Space)</td>
1572
+ * <td>Add a “ ” prefix to non-negative numbers</td>
1573
+ * </tr>
1574
+ * <tr>
1575
+ * <td><code>+</code></td>
1576
+ * <td>Add a “+” sign to non-negative numbers; overrides the
1577
+ * ‘<code> </code>’ flag</td>
1578
+ * </tr>
1579
+ * <tr>
1580
+ * <td><code>0</code></td>
1581
+ * <td>Use ‘0’ for any width padding; ignored when a precision has
1582
+ * been specified</td>
1583
+ * </tr>
1584
+ * <tr>
1585
+ * <td><code>-</code></td>
1586
+ * <td>Left justify the output with ‘ ’ as padding; overrides the
1587
+ * ‘<code>0</code>’ flag</td>
1588
+ * </tr>
1589
+ * <tr>
1590
+ * <td>#</td>
1591
+ * <td>Output a decimal point, even if no fractional part
1592
+ * follows</td>
1593
+ * </tr>
1594
+ * </tbody>
1595
+ * </table>
1596
+ * </dd>
1597
+ * <dt>E</dt>
1598
+ * <dd>
1599
+ * <p>Same as ‘e’, except that it uses an uppercase ‘E’ for the exponent
1600
+ * separator.</p>
1601
+ * </dd>
1602
+ * <dt>g</dt>
1603
+ * <dd>
1604
+ * <p>Same as ‘e’ if the exponent is less than -4 or if the exponent is
1605
+ * greater than or equal to the precision, otherwise ‘f’ is used. The
1606
+ * precision defaults to 6 and a precision of 0 is treated as a precision
1607
+ * of 1. Trailing zeros are removed from the fractional part of the
1608
+ * result.</p>
1609
+ * </dd>
1610
+ * <dt>G</dt>
1611
+ * <dd>
1612
+ * <p>Same as ‘g’, except that it uses an uppercase ‘E’ for the exponent
1613
+ * separator.</p>
1614
+ * </dd>
1615
+ * <dt>a</dt>
1616
+ * <dd>
1617
+ * <p>Outputs</p>
1618
+ *
1619
+ * <pre><code>[left-padding][prefix/sign][zeroes]
1620
+ * digit[hexadecimal-point][fractional-part]exponent[right-padding]</code></pre>
1621
+ *
1622
+ * <p>If a width <em>w</em> has been specified and neither the
1623
+ * ‘<code>-</code>’ nor the ‘<code>0</code>’ flag has been given,
1624
+ * <em>left-padding</em> consists of enough spaces to make the whole
1625
+ * field at least <em>w</em> + <em>e</em> cells wide, where <em>e</em> ≥
1626
+ * 3 is the width of the exponent, otherwise it’s empty.</p>
1627
+ *
1628
+ * <p><em>Prefix/sign</em> is “-” if the argument is negative, “+” if the
1629
+ * ‘<code>+</code>’ flag was given, and “ ” if the ‘<code> </code>’ flag
1630
+ * was given, otherwise it’s empty.</p>
1631
+ *
1632
+ * <p>If a width <em>w</em> has been specified and the ‘<code>0</code>’
1633
+ * flag has been given and the ‘<code>-</code>’ flag has not been given,
1634
+ * <em>zeroes</em> consists of enough zeroes to make the whole field
1635
+ * <em>w</em> + <em>e</em> cells wide, where <em>e</em> ≥ 3 is the width
1636
+ * of the exponent, otherwise it’s empty.</p>
1637
+ *
1638
+ * <p><em>Digit</em> consists of one digit in base 16 that represent the
1639
+ * most significant digit of the result of calling Float with the
1640
+ * argument as its argument, using ‘0’ through ‘9’ and ‘a’ through ‘f’.</p>
1641
+ *
1642
+ * <p><em>Decimal-point</em> is “.” if the precision isn’t 0 or if the
1643
+ * ‘<code>#</code>’ flag has been given.</p>
1644
+ *
1645
+ * <p><em>Fractional-part</em> consists of <em>p</em> digits in base 16
1646
+ * that represent all but the most significant digit of the result of
1647
+ * calling Float with the argument as its argument, where <em>p</em> =
1648
+ * precision, if one has been specified, <em>p</em> = <em>q</em>, where
1649
+ * <em>q</em> is the number of digits required to represent the number
1650
+ * exactly, otherwise. Digits are output using ‘0’ through ‘9’ and ‘a’
1651
+ * through ‘f’.</p>
1652
+ *
1653
+ * <p><em>Exponent</em> consists of “p” followed by the exponent of 2 in
1654
+ * base 10 required to turn the result of calling Float with the argument
1655
+ * as its argument into a decimal fraction with one non-zero digit in the
1656
+ * integer part. If the exponent is 0, “+0” will be output.</p>
1657
+ *
1658
+ * <p>If a width <em>w</em> has been specified and the ‘<code>-</code>’
1659
+ * flag has been given, <em>right-padding</em> consists of enough spaces
1660
+ * to make the whole field at least <em>w</em> + <em>e</em> cells
1661
+ * wide, where <em>e</em> ≥ 3 is the width of the exponent, otherwise
1662
+ * it’s empty.</p>
1663
+ *
1664
+ * <table>
1665
+ * <thead><tr><th>Flag</th><th>Description</th></tr></thead>
1666
+ * <tbody>
1667
+ * <tr>
1668
+ * <td>(Space)</td>
1669
+ * <td>Add a “ ” prefix to non-negative numbers</td>
1670
+ * </tr>
1671
+ * <tr>
1672
+ * <td><code>+</code></td>
1673
+ * <td>Add a “+” sign to non-negative numbers; overrides the
1674
+ * ‘<code> </code>’ flag</td>
1675
+ * </tr>
1676
+ * <tr>
1677
+ * <td><code>0</code></td>
1678
+ * <td>Use ‘0’ for any width padding; ignored when a precision has
1679
+ * been specified</td>
1680
+ * </tr>
1681
+ * <tr>
1682
+ * <td><code>-</code></td>
1683
+ * <td>Left justify the output with ‘ ’ as padding; overrides the
1684
+ * ‘<code>0</code>’ flag</td>
1685
+ * </tr>
1686
+ * <tr>
1687
+ * <td>#</td>
1688
+ * <td>Output a decimal point, even if no fractional part
1689
+ * follows</td>
1690
+ * </tr>
1691
+ * </tbody>
1692
+ * </table>
1693
+ * </dd>
1694
+ * <dt>A</dt>
1695
+ * <dd>
1696
+ * <p>Same as ‘a’, except that it uses an uppercase letters instead.</p>
1697
+ * </dd>
1698
+ * </dl>
1699
+ *
1700
+ * A warning is issued if the ‘`0`’ flag is given when the ‘`-`’ flag has
1701
+ * also been given to the ‘d’, ‘i’, ‘u’, ‘o’, ‘x’, ‘X’, ‘b’, or ‘B’
1702
+ * directives.
1703
+ *
1704
+ * A warning is issued if the ‘`0`’ flag is given when a precision has been
1705
+ * specified for the ‘d’, ‘i’, ‘u’, ‘o’, ‘x’, ‘X’, ‘b’, or ‘B’ directives.
1706
+ *
1707
+ * A warning is issued if the ‘<code> </code>’ flag is given when the ‘`+`’
1708
+ * flag has also been given to the ‘d’, ‘i’, ‘u’, ‘o’, ‘x’, ‘X’, ‘b’, or ‘B’
1709
+ * directives.
1710
+ *
1711
+ * A warning is issued if the ‘`0`’ flag is given when the ‘o’, ‘x’, ‘X’,
1712
+ * ‘b’, or ‘B’ directives has been given a negative argument.
1713
+ *
1714
+ * A warning is issued if the ‘`#`’ flag is given when the ‘o’ directive has
1715
+ * been given a negative argument.
1716
+ *
1717
+ * Any taint on the receiver and any taint on arguments to any ‘s’ and ‘p’
1718
+ * directives is inherited by the result.
1719
+ *
1720
+ * @raise [ArgumentError] If the receiver isn’t a valid format specification
1721
+ * @raise [ArgumentError] If any flags are given to the ‘%’, ‘\n’, or ‘\0’
1722
+ * directives
1723
+ * @raise [ArgumentError] If an argument is given to the ‘%’, ‘\n’, or ‘\0’
1724
+ * directives
1725
+ * @raise [ArgumentError] If a width is specified for the ‘%’, ‘\n’, or ‘\0’
1726
+ * directives
1727
+ * @raise [ArgumentError] If a precision is specified for the ‘%’, ‘\n’, ‘\0’,
1728
+ * or ‘c’ directives
1729
+ * @raise [ArgumentError] If any of the flags ‘<code> </code>’, ‘`+`’, ’`0`’,
1730
+ * or ‘`#`’ are given to the ‘c’, ‘s’, or ‘p’ directives
1731
+ * @raise [ArgumentError] If the ‘`#`’ flag is given to the ‘d’, ‘i’, or ‘u’
1732
+ * directives
1733
+ * @raise [ArgumentError] If the argument to the ‘c’ directive doesn’t respond
1734
+ * to #to_str or #to_int
1735
+ * @return [U::String] */
1736
+ VALUE
1737
+ rb_u_string_format_m(VALUE self, VALUE argument)
1738
+ {
1739
+ volatile VALUE tmp = rb_check_array_type(argument);
1740
+
1741
+ if (!NIL_P(tmp))
1742
+ return rb_u_string_format(RARRAY_LENINT(tmp), RARRAY_PTR(tmp), self);
1743
+
1744
+ return rb_u_string_format(1, &argument, self);
1745
+ }