u 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }