mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
src/string.c@0:158c61bb030f, 2015-03-25 (annotated)
- Committer:
- mzta
- Date:
- Wed Mar 25 17:36:16 2015 +0000
- Revision:
- 0:158c61bb030f
mirb_mbed initial commit;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzta | 0:158c61bb030f | 1 | /* |
mzta | 0:158c61bb030f | 2 | ** string.c - String class |
mzta | 0:158c61bb030f | 3 | ** |
mzta | 0:158c61bb030f | 4 | ** See Copyright Notice in mruby.h |
mzta | 0:158c61bb030f | 5 | */ |
mzta | 0:158c61bb030f | 6 | |
mzta | 0:158c61bb030f | 7 | #include <ctype.h> |
mzta | 0:158c61bb030f | 8 | #include <float.h> |
mzta | 0:158c61bb030f | 9 | #include <limits.h> |
mzta | 0:158c61bb030f | 10 | #include <stddef.h> |
mzta | 0:158c61bb030f | 11 | #include <stdlib.h> |
mzta | 0:158c61bb030f | 12 | #include <string.h> |
mzta | 0:158c61bb030f | 13 | #include "mruby.h" |
mzta | 0:158c61bb030f | 14 | #include "mruby/array.h" |
mzta | 0:158c61bb030f | 15 | #include "mruby/class.h" |
mzta | 0:158c61bb030f | 16 | #include "mruby/range.h" |
mzta | 0:158c61bb030f | 17 | #include "mruby/string.h" |
mzta | 0:158c61bb030f | 18 | #include "mruby/re.h" |
mzta | 0:158c61bb030f | 19 | |
mzta | 0:158c61bb030f | 20 | const char mrb_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
mzta | 0:158c61bb030f | 21 | |
mzta | 0:158c61bb030f | 22 | typedef struct mrb_shared_string { |
mzta | 0:158c61bb030f | 23 | mrb_bool nofree : 1; |
mzta | 0:158c61bb030f | 24 | int refcnt; |
mzta | 0:158c61bb030f | 25 | char *ptr; |
mzta | 0:158c61bb030f | 26 | mrb_int len; |
mzta | 0:158c61bb030f | 27 | } mrb_shared_string; |
mzta | 0:158c61bb030f | 28 | |
mzta | 0:158c61bb030f | 29 | static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2); |
mzta | 0:158c61bb030f | 30 | static mrb_value mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); |
mzta | 0:158c61bb030f | 31 | |
mzta | 0:158c61bb030f | 32 | MRB_API mrb_int |
mzta | 0:158c61bb030f | 33 | mrb_str_strlen(mrb_state *mrb, struct RString *s) |
mzta | 0:158c61bb030f | 34 | { |
mzta | 0:158c61bb030f | 35 | mrb_int i, max = RSTR_LEN(s); |
mzta | 0:158c61bb030f | 36 | char *p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 37 | |
mzta | 0:158c61bb030f | 38 | if (!p) return 0; |
mzta | 0:158c61bb030f | 39 | for (i=0; i<max; i++) { |
mzta | 0:158c61bb030f | 40 | if (p[i] == '\0') { |
mzta | 0:158c61bb030f | 41 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); |
mzta | 0:158c61bb030f | 42 | } |
mzta | 0:158c61bb030f | 43 | } |
mzta | 0:158c61bb030f | 44 | return max; |
mzta | 0:158c61bb030f | 45 | } |
mzta | 0:158c61bb030f | 46 | |
mzta | 0:158c61bb030f | 47 | static inline void |
mzta | 0:158c61bb030f | 48 | resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) |
mzta | 0:158c61bb030f | 49 | { |
mzta | 0:158c61bb030f | 50 | if (RSTR_EMBED_P(s)) { |
mzta | 0:158c61bb030f | 51 | if (RSTRING_EMBED_LEN_MAX < capacity) { |
mzta | 0:158c61bb030f | 52 | char *const tmp = (char *)mrb_malloc(mrb, capacity+1); |
mzta | 0:158c61bb030f | 53 | const mrb_int len = RSTR_EMBED_LEN(s); |
mzta | 0:158c61bb030f | 54 | memcpy(tmp, s->as.ary, len); |
mzta | 0:158c61bb030f | 55 | RSTR_UNSET_EMBED_FLAG(s); |
mzta | 0:158c61bb030f | 56 | s->as.heap.ptr = tmp; |
mzta | 0:158c61bb030f | 57 | s->as.heap.len = len; |
mzta | 0:158c61bb030f | 58 | s->as.heap.aux.capa = capacity; |
mzta | 0:158c61bb030f | 59 | } |
mzta | 0:158c61bb030f | 60 | } |
mzta | 0:158c61bb030f | 61 | else { |
mzta | 0:158c61bb030f | 62 | s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); |
mzta | 0:158c61bb030f | 63 | s->as.heap.aux.capa = capacity; |
mzta | 0:158c61bb030f | 64 | } |
mzta | 0:158c61bb030f | 65 | } |
mzta | 0:158c61bb030f | 66 | |
mzta | 0:158c61bb030f | 67 | static void |
mzta | 0:158c61bb030f | 68 | str_decref(mrb_state *mrb, mrb_shared_string *shared) |
mzta | 0:158c61bb030f | 69 | { |
mzta | 0:158c61bb030f | 70 | shared->refcnt--; |
mzta | 0:158c61bb030f | 71 | if (shared->refcnt == 0) { |
mzta | 0:158c61bb030f | 72 | if (!shared->nofree) { |
mzta | 0:158c61bb030f | 73 | mrb_free(mrb, shared->ptr); |
mzta | 0:158c61bb030f | 74 | } |
mzta | 0:158c61bb030f | 75 | mrb_free(mrb, shared); |
mzta | 0:158c61bb030f | 76 | } |
mzta | 0:158c61bb030f | 77 | } |
mzta | 0:158c61bb030f | 78 | |
mzta | 0:158c61bb030f | 79 | MRB_API void |
mzta | 0:158c61bb030f | 80 | mrb_str_modify(mrb_state *mrb, struct RString *s) |
mzta | 0:158c61bb030f | 81 | { |
mzta | 0:158c61bb030f | 82 | if (RSTR_SHARED_P(s)) { |
mzta | 0:158c61bb030f | 83 | mrb_shared_string *shared = s->as.heap.aux.shared; |
mzta | 0:158c61bb030f | 84 | |
mzta | 0:158c61bb030f | 85 | if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { |
mzta | 0:158c61bb030f | 86 | s->as.heap.ptr = shared->ptr; |
mzta | 0:158c61bb030f | 87 | s->as.heap.aux.capa = shared->len; |
mzta | 0:158c61bb030f | 88 | RSTR_PTR(s)[s->as.heap.len] = '\0'; |
mzta | 0:158c61bb030f | 89 | mrb_free(mrb, shared); |
mzta | 0:158c61bb030f | 90 | } |
mzta | 0:158c61bb030f | 91 | else { |
mzta | 0:158c61bb030f | 92 | char *ptr, *p; |
mzta | 0:158c61bb030f | 93 | mrb_int len; |
mzta | 0:158c61bb030f | 94 | |
mzta | 0:158c61bb030f | 95 | p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 96 | len = s->as.heap.len; |
mzta | 0:158c61bb030f | 97 | ptr = (char *)mrb_malloc(mrb, (size_t)len + 1); |
mzta | 0:158c61bb030f | 98 | if (p) { |
mzta | 0:158c61bb030f | 99 | memcpy(ptr, p, len); |
mzta | 0:158c61bb030f | 100 | } |
mzta | 0:158c61bb030f | 101 | ptr[len] = '\0'; |
mzta | 0:158c61bb030f | 102 | s->as.heap.ptr = ptr; |
mzta | 0:158c61bb030f | 103 | s->as.heap.aux.capa = len; |
mzta | 0:158c61bb030f | 104 | str_decref(mrb, shared); |
mzta | 0:158c61bb030f | 105 | } |
mzta | 0:158c61bb030f | 106 | RSTR_UNSET_SHARED_FLAG(s); |
mzta | 0:158c61bb030f | 107 | return; |
mzta | 0:158c61bb030f | 108 | } |
mzta | 0:158c61bb030f | 109 | if (RSTR_NOFREE_P(s)) { |
mzta | 0:158c61bb030f | 110 | char *p = s->as.heap.ptr; |
mzta | 0:158c61bb030f | 111 | |
mzta | 0:158c61bb030f | 112 | s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1); |
mzta | 0:158c61bb030f | 113 | if (p) { |
mzta | 0:158c61bb030f | 114 | memcpy(RSTR_PTR(s), p, s->as.heap.len); |
mzta | 0:158c61bb030f | 115 | } |
mzta | 0:158c61bb030f | 116 | RSTR_PTR(s)[s->as.heap.len] = '\0'; |
mzta | 0:158c61bb030f | 117 | s->as.heap.aux.capa = s->as.heap.len; |
mzta | 0:158c61bb030f | 118 | RSTR_UNSET_NOFREE_FLAG(s); |
mzta | 0:158c61bb030f | 119 | return; |
mzta | 0:158c61bb030f | 120 | } |
mzta | 0:158c61bb030f | 121 | } |
mzta | 0:158c61bb030f | 122 | |
mzta | 0:158c61bb030f | 123 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 124 | mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) |
mzta | 0:158c61bb030f | 125 | { |
mzta | 0:158c61bb030f | 126 | mrb_int slen; |
mzta | 0:158c61bb030f | 127 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 128 | |
mzta | 0:158c61bb030f | 129 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 130 | slen = RSTR_LEN(s); |
mzta | 0:158c61bb030f | 131 | if (len != slen) { |
mzta | 0:158c61bb030f | 132 | if (slen < len || slen - len > 256) { |
mzta | 0:158c61bb030f | 133 | resize_capa(mrb, s, len); |
mzta | 0:158c61bb030f | 134 | } |
mzta | 0:158c61bb030f | 135 | RSTR_SET_LEN(s, len); |
mzta | 0:158c61bb030f | 136 | RSTR_PTR(s)[len] = '\0'; /* sentinel */ |
mzta | 0:158c61bb030f | 137 | } |
mzta | 0:158c61bb030f | 138 | return str; |
mzta | 0:158c61bb030f | 139 | } |
mzta | 0:158c61bb030f | 140 | |
mzta | 0:158c61bb030f | 141 | #define mrb_obj_alloc_string(mrb) ((struct RString*)mrb_obj_alloc((mrb), MRB_TT_STRING, (mrb)->string_class)) |
mzta | 0:158c61bb030f | 142 | |
mzta | 0:158c61bb030f | 143 | static struct RString* |
mzta | 0:158c61bb030f | 144 | str_new_static(mrb_state *mrb, const char *p, size_t len) |
mzta | 0:158c61bb030f | 145 | { |
mzta | 0:158c61bb030f | 146 | struct RString *s; |
mzta | 0:158c61bb030f | 147 | |
mzta | 0:158c61bb030f | 148 | if (len >= MRB_INT_MAX) { |
mzta | 0:158c61bb030f | 149 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); |
mzta | 0:158c61bb030f | 150 | } |
mzta | 0:158c61bb030f | 151 | s = mrb_obj_alloc_string(mrb); |
mzta | 0:158c61bb030f | 152 | s->as.heap.len = len; |
mzta | 0:158c61bb030f | 153 | s->as.heap.aux.capa = 0; /* nofree */ |
mzta | 0:158c61bb030f | 154 | s->as.heap.ptr = (char *)p; |
mzta | 0:158c61bb030f | 155 | s->flags = MRB_STR_NOFREE; |
mzta | 0:158c61bb030f | 156 | |
mzta | 0:158c61bb030f | 157 | return s; |
mzta | 0:158c61bb030f | 158 | } |
mzta | 0:158c61bb030f | 159 | |
mzta | 0:158c61bb030f | 160 | static struct RString* |
mzta | 0:158c61bb030f | 161 | str_new(mrb_state *mrb, const char *p, size_t len) |
mzta | 0:158c61bb030f | 162 | { |
mzta | 0:158c61bb030f | 163 | struct RString *s; |
mzta | 0:158c61bb030f | 164 | |
mzta | 0:158c61bb030f | 165 | if (mrb_ro_data_p(p)) { |
mzta | 0:158c61bb030f | 166 | return str_new_static(mrb, p, len); |
mzta | 0:158c61bb030f | 167 | } |
mzta | 0:158c61bb030f | 168 | s = mrb_obj_alloc_string(mrb); |
mzta | 0:158c61bb030f | 169 | if (len < RSTRING_EMBED_LEN_MAX) { |
mzta | 0:158c61bb030f | 170 | RSTR_SET_EMBED_FLAG(s); |
mzta | 0:158c61bb030f | 171 | RSTR_SET_EMBED_LEN(s, len); |
mzta | 0:158c61bb030f | 172 | if (p) { |
mzta | 0:158c61bb030f | 173 | memcpy(s->as.ary, p, len); |
mzta | 0:158c61bb030f | 174 | } |
mzta | 0:158c61bb030f | 175 | } else { |
mzta | 0:158c61bb030f | 176 | if (len >= MRB_INT_MAX) { |
mzta | 0:158c61bb030f | 177 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); |
mzta | 0:158c61bb030f | 178 | } |
mzta | 0:158c61bb030f | 179 | s->as.heap.len = len; |
mzta | 0:158c61bb030f | 180 | s->as.heap.aux.capa = len; |
mzta | 0:158c61bb030f | 181 | s->as.heap.ptr = (char *)mrb_malloc(mrb, len+1); |
mzta | 0:158c61bb030f | 182 | if (p) { |
mzta | 0:158c61bb030f | 183 | memcpy(s->as.heap.ptr, p, len); |
mzta | 0:158c61bb030f | 184 | } |
mzta | 0:158c61bb030f | 185 | } |
mzta | 0:158c61bb030f | 186 | RSTR_PTR(s)[len] = '\0'; |
mzta | 0:158c61bb030f | 187 | return s; |
mzta | 0:158c61bb030f | 188 | } |
mzta | 0:158c61bb030f | 189 | |
mzta | 0:158c61bb030f | 190 | static inline void |
mzta | 0:158c61bb030f | 191 | str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) |
mzta | 0:158c61bb030f | 192 | { |
mzta | 0:158c61bb030f | 193 | s->c = mrb_str_ptr(obj)->c; |
mzta | 0:158c61bb030f | 194 | } |
mzta | 0:158c61bb030f | 195 | |
mzta | 0:158c61bb030f | 196 | static mrb_value |
mzta | 0:158c61bb030f | 197 | mrb_str_new_empty(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 198 | { |
mzta | 0:158c61bb030f | 199 | struct RString *s = str_new(mrb, 0, 0); |
mzta | 0:158c61bb030f | 200 | |
mzta | 0:158c61bb030f | 201 | str_with_class(mrb, s, str); |
mzta | 0:158c61bb030f | 202 | return mrb_obj_value(s); |
mzta | 0:158c61bb030f | 203 | } |
mzta | 0:158c61bb030f | 204 | |
mzta | 0:158c61bb030f | 205 | #ifndef MRB_STR_BUF_MIN_SIZE |
mzta | 0:158c61bb030f | 206 | # define MRB_STR_BUF_MIN_SIZE 128 |
mzta | 0:158c61bb030f | 207 | #endif |
mzta | 0:158c61bb030f | 208 | |
mzta | 0:158c61bb030f | 209 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 210 | mrb_str_buf_new(mrb_state *mrb, size_t capa) |
mzta | 0:158c61bb030f | 211 | { |
mzta | 0:158c61bb030f | 212 | struct RString *s; |
mzta | 0:158c61bb030f | 213 | |
mzta | 0:158c61bb030f | 214 | s = mrb_obj_alloc_string(mrb); |
mzta | 0:158c61bb030f | 215 | |
mzta | 0:158c61bb030f | 216 | if (capa >= MRB_INT_MAX) { |
mzta | 0:158c61bb030f | 217 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string capacity size too big"); |
mzta | 0:158c61bb030f | 218 | } |
mzta | 0:158c61bb030f | 219 | if (capa < MRB_STR_BUF_MIN_SIZE) { |
mzta | 0:158c61bb030f | 220 | capa = MRB_STR_BUF_MIN_SIZE; |
mzta | 0:158c61bb030f | 221 | } |
mzta | 0:158c61bb030f | 222 | s->as.heap.len = 0; |
mzta | 0:158c61bb030f | 223 | s->as.heap.aux.capa = capa; |
mzta | 0:158c61bb030f | 224 | s->as.heap.ptr = (char *)mrb_malloc(mrb, capa+1); |
mzta | 0:158c61bb030f | 225 | RSTR_PTR(s)[0] = '\0'; |
mzta | 0:158c61bb030f | 226 | |
mzta | 0:158c61bb030f | 227 | return mrb_obj_value(s); |
mzta | 0:158c61bb030f | 228 | } |
mzta | 0:158c61bb030f | 229 | |
mzta | 0:158c61bb030f | 230 | static void |
mzta | 0:158c61bb030f | 231 | str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) |
mzta | 0:158c61bb030f | 232 | { |
mzta | 0:158c61bb030f | 233 | size_t capa; |
mzta | 0:158c61bb030f | 234 | size_t total; |
mzta | 0:158c61bb030f | 235 | ptrdiff_t off = -1; |
mzta | 0:158c61bb030f | 236 | |
mzta | 0:158c61bb030f | 237 | if (len == 0) return; |
mzta | 0:158c61bb030f | 238 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 239 | if (ptr >= RSTR_PTR(s) && ptr <= RSTR_PTR(s) + (size_t)RSTR_LEN(s)) { |
mzta | 0:158c61bb030f | 240 | off = ptr - RSTR_PTR(s); |
mzta | 0:158c61bb030f | 241 | } |
mzta | 0:158c61bb030f | 242 | |
mzta | 0:158c61bb030f | 243 | if (RSTR_EMBED_P(s)) |
mzta | 0:158c61bb030f | 244 | capa = RSTRING_EMBED_LEN_MAX; |
mzta | 0:158c61bb030f | 245 | else |
mzta | 0:158c61bb030f | 246 | capa = s->as.heap.aux.capa; |
mzta | 0:158c61bb030f | 247 | |
mzta | 0:158c61bb030f | 248 | if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) { |
mzta | 0:158c61bb030f | 249 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); |
mzta | 0:158c61bb030f | 250 | } |
mzta | 0:158c61bb030f | 251 | total = RSTR_LEN(s)+len; |
mzta | 0:158c61bb030f | 252 | if (capa <= total) { |
mzta | 0:158c61bb030f | 253 | while (total > capa) { |
mzta | 0:158c61bb030f | 254 | if (capa + 1 >= MRB_INT_MAX / 2) { |
mzta | 0:158c61bb030f | 255 | capa = (total + 4095) / 4096; |
mzta | 0:158c61bb030f | 256 | break; |
mzta | 0:158c61bb030f | 257 | } |
mzta | 0:158c61bb030f | 258 | capa = (capa + 1) * 2; |
mzta | 0:158c61bb030f | 259 | } |
mzta | 0:158c61bb030f | 260 | resize_capa(mrb, s, capa); |
mzta | 0:158c61bb030f | 261 | } |
mzta | 0:158c61bb030f | 262 | if (off != -1) { |
mzta | 0:158c61bb030f | 263 | ptr = RSTR_PTR(s) + off; |
mzta | 0:158c61bb030f | 264 | } |
mzta | 0:158c61bb030f | 265 | memcpy(RSTR_PTR(s) + RSTR_LEN(s), ptr, len); |
mzta | 0:158c61bb030f | 266 | mrb_assert_int_fit(size_t, total, mrb_int, MRB_INT_MAX); |
mzta | 0:158c61bb030f | 267 | RSTR_SET_LEN(s, total); |
mzta | 0:158c61bb030f | 268 | RSTR_PTR(s)[total] = '\0'; /* sentinel */ |
mzta | 0:158c61bb030f | 269 | } |
mzta | 0:158c61bb030f | 270 | |
mzta | 0:158c61bb030f | 271 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 272 | mrb_str_new(mrb_state *mrb, const char *p, size_t len) |
mzta | 0:158c61bb030f | 273 | { |
mzta | 0:158c61bb030f | 274 | return mrb_obj_value(str_new(mrb, p, len)); |
mzta | 0:158c61bb030f | 275 | } |
mzta | 0:158c61bb030f | 276 | |
mzta | 0:158c61bb030f | 277 | /* |
mzta | 0:158c61bb030f | 278 | * call-seq: (Caution! NULL string) |
mzta | 0:158c61bb030f | 279 | * String.new(str="") => new_str |
mzta | 0:158c61bb030f | 280 | * |
mzta | 0:158c61bb030f | 281 | * Returns a new string object containing a copy of <i>str</i>. |
mzta | 0:158c61bb030f | 282 | */ |
mzta | 0:158c61bb030f | 283 | |
mzta | 0:158c61bb030f | 284 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 285 | mrb_str_new_cstr(mrb_state *mrb, const char *p) |
mzta | 0:158c61bb030f | 286 | { |
mzta | 0:158c61bb030f | 287 | struct RString *s; |
mzta | 0:158c61bb030f | 288 | size_t len; |
mzta | 0:158c61bb030f | 289 | |
mzta | 0:158c61bb030f | 290 | if (p) { |
mzta | 0:158c61bb030f | 291 | len = strlen(p); |
mzta | 0:158c61bb030f | 292 | } |
mzta | 0:158c61bb030f | 293 | else { |
mzta | 0:158c61bb030f | 294 | len = 0; |
mzta | 0:158c61bb030f | 295 | } |
mzta | 0:158c61bb030f | 296 | |
mzta | 0:158c61bb030f | 297 | s = str_new(mrb, p, len); |
mzta | 0:158c61bb030f | 298 | |
mzta | 0:158c61bb030f | 299 | return mrb_obj_value(s); |
mzta | 0:158c61bb030f | 300 | } |
mzta | 0:158c61bb030f | 301 | |
mzta | 0:158c61bb030f | 302 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 303 | mrb_str_new_static(mrb_state *mrb, const char *p, size_t len) |
mzta | 0:158c61bb030f | 304 | { |
mzta | 0:158c61bb030f | 305 | struct RString *s = str_new_static(mrb, p, len); |
mzta | 0:158c61bb030f | 306 | return mrb_obj_value(s); |
mzta | 0:158c61bb030f | 307 | } |
mzta | 0:158c61bb030f | 308 | |
mzta | 0:158c61bb030f | 309 | void |
mzta | 0:158c61bb030f | 310 | mrb_gc_free_str(mrb_state *mrb, struct RString *str) |
mzta | 0:158c61bb030f | 311 | { |
mzta | 0:158c61bb030f | 312 | if (RSTR_EMBED_P(str)) |
mzta | 0:158c61bb030f | 313 | /* no code */; |
mzta | 0:158c61bb030f | 314 | else if (RSTR_SHARED_P(str)) |
mzta | 0:158c61bb030f | 315 | str_decref(mrb, str->as.heap.aux.shared); |
mzta | 0:158c61bb030f | 316 | else if (!RSTR_NOFREE_P(str)) |
mzta | 0:158c61bb030f | 317 | mrb_free(mrb, str->as.heap.ptr); |
mzta | 0:158c61bb030f | 318 | } |
mzta | 0:158c61bb030f | 319 | |
mzta | 0:158c61bb030f | 320 | MRB_API char* |
mzta | 0:158c61bb030f | 321 | mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) |
mzta | 0:158c61bb030f | 322 | { |
mzta | 0:158c61bb030f | 323 | struct RString *s; |
mzta | 0:158c61bb030f | 324 | |
mzta | 0:158c61bb030f | 325 | if (!mrb_string_p(str0)) { |
mzta | 0:158c61bb030f | 326 | mrb_raise(mrb, E_TYPE_ERROR, "expected String"); |
mzta | 0:158c61bb030f | 327 | } |
mzta | 0:158c61bb030f | 328 | |
mzta | 0:158c61bb030f | 329 | s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); |
mzta | 0:158c61bb030f | 330 | if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { |
mzta | 0:158c61bb030f | 331 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); |
mzta | 0:158c61bb030f | 332 | } |
mzta | 0:158c61bb030f | 333 | return RSTR_PTR(s); |
mzta | 0:158c61bb030f | 334 | } |
mzta | 0:158c61bb030f | 335 | |
mzta | 0:158c61bb030f | 336 | static void |
mzta | 0:158c61bb030f | 337 | str_make_shared(mrb_state *mrb, struct RString *s) |
mzta | 0:158c61bb030f | 338 | { |
mzta | 0:158c61bb030f | 339 | if (!RSTR_SHARED_P(s)) { |
mzta | 0:158c61bb030f | 340 | mrb_shared_string *shared = (mrb_shared_string *)mrb_malloc(mrb, sizeof(mrb_shared_string)); |
mzta | 0:158c61bb030f | 341 | |
mzta | 0:158c61bb030f | 342 | shared->refcnt = 1; |
mzta | 0:158c61bb030f | 343 | if (RSTR_EMBED_P(s)) { |
mzta | 0:158c61bb030f | 344 | const mrb_int len = RSTR_EMBED_LEN(s); |
mzta | 0:158c61bb030f | 345 | char *const tmp = (char *)mrb_malloc(mrb, len+1); |
mzta | 0:158c61bb030f | 346 | memcpy(tmp, s->as.ary, len); |
mzta | 0:158c61bb030f | 347 | tmp[len] = '\0'; |
mzta | 0:158c61bb030f | 348 | RSTR_UNSET_EMBED_FLAG(s); |
mzta | 0:158c61bb030f | 349 | s->as.heap.ptr = tmp; |
mzta | 0:158c61bb030f | 350 | s->as.heap.len = len; |
mzta | 0:158c61bb030f | 351 | shared->nofree = FALSE; |
mzta | 0:158c61bb030f | 352 | shared->ptr = s->as.heap.ptr; |
mzta | 0:158c61bb030f | 353 | } |
mzta | 0:158c61bb030f | 354 | else if (RSTR_NOFREE_P(s)) { |
mzta | 0:158c61bb030f | 355 | shared->nofree = TRUE; |
mzta | 0:158c61bb030f | 356 | shared->ptr = s->as.heap.ptr; |
mzta | 0:158c61bb030f | 357 | RSTR_UNSET_NOFREE_FLAG(s); |
mzta | 0:158c61bb030f | 358 | } |
mzta | 0:158c61bb030f | 359 | else { |
mzta | 0:158c61bb030f | 360 | shared->nofree = FALSE; |
mzta | 0:158c61bb030f | 361 | if (s->as.heap.aux.capa > s->as.heap.len) { |
mzta | 0:158c61bb030f | 362 | s->as.heap.ptr = shared->ptr = (char *)mrb_realloc(mrb, s->as.heap.ptr, s->as.heap.len+1); |
mzta | 0:158c61bb030f | 363 | } |
mzta | 0:158c61bb030f | 364 | else { |
mzta | 0:158c61bb030f | 365 | shared->ptr = s->as.heap.ptr; |
mzta | 0:158c61bb030f | 366 | } |
mzta | 0:158c61bb030f | 367 | } |
mzta | 0:158c61bb030f | 368 | shared->len = s->as.heap.len; |
mzta | 0:158c61bb030f | 369 | s->as.heap.aux.shared = shared; |
mzta | 0:158c61bb030f | 370 | RSTR_SET_SHARED_FLAG(s); |
mzta | 0:158c61bb030f | 371 | } |
mzta | 0:158c61bb030f | 372 | } |
mzta | 0:158c61bb030f | 373 | |
mzta | 0:158c61bb030f | 374 | /* |
mzta | 0:158c61bb030f | 375 | * call-seq: (Caution! String("abcd") change) |
mzta | 0:158c61bb030f | 376 | * String("abcdefg") = String("abcd") + String("efg") |
mzta | 0:158c61bb030f | 377 | * |
mzta | 0:158c61bb030f | 378 | * Returns a new string object containing a copy of <i>str</i>. |
mzta | 0:158c61bb030f | 379 | */ |
mzta | 0:158c61bb030f | 380 | MRB_API void |
mzta | 0:158c61bb030f | 381 | mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) |
mzta | 0:158c61bb030f | 382 | { |
mzta | 0:158c61bb030f | 383 | struct RString *s1 = mrb_str_ptr(self), *s2; |
mzta | 0:158c61bb030f | 384 | mrb_int len; |
mzta | 0:158c61bb030f | 385 | |
mzta | 0:158c61bb030f | 386 | mrb_str_modify(mrb, s1); |
mzta | 0:158c61bb030f | 387 | if (!mrb_string_p(other)) { |
mzta | 0:158c61bb030f | 388 | other = mrb_str_to_str(mrb, other); |
mzta | 0:158c61bb030f | 389 | } |
mzta | 0:158c61bb030f | 390 | s2 = mrb_str_ptr(other); |
mzta | 0:158c61bb030f | 391 | len = RSTR_LEN(s1) + RSTR_LEN(s2); |
mzta | 0:158c61bb030f | 392 | |
mzta | 0:158c61bb030f | 393 | if (RSTRING_CAPA(self) < len) { |
mzta | 0:158c61bb030f | 394 | resize_capa(mrb, s1, len); |
mzta | 0:158c61bb030f | 395 | } |
mzta | 0:158c61bb030f | 396 | memcpy(RSTR_PTR(s1)+RSTR_LEN(s1), RSTR_PTR(s2), RSTR_LEN(s2)); |
mzta | 0:158c61bb030f | 397 | RSTR_SET_LEN(s1, len); |
mzta | 0:158c61bb030f | 398 | RSTR_PTR(s1)[len] = '\0'; |
mzta | 0:158c61bb030f | 399 | } |
mzta | 0:158c61bb030f | 400 | |
mzta | 0:158c61bb030f | 401 | /* |
mzta | 0:158c61bb030f | 402 | * call-seq: (Caution! String("abcd") remain) |
mzta | 0:158c61bb030f | 403 | * String("abcdefg") = String("abcd") + String("efg") |
mzta | 0:158c61bb030f | 404 | * |
mzta | 0:158c61bb030f | 405 | * Returns a new string object containing a copy of <i>str</i>. |
mzta | 0:158c61bb030f | 406 | */ |
mzta | 0:158c61bb030f | 407 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 408 | mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) |
mzta | 0:158c61bb030f | 409 | { |
mzta | 0:158c61bb030f | 410 | struct RString *s = mrb_str_ptr(a); |
mzta | 0:158c61bb030f | 411 | struct RString *s2 = mrb_str_ptr(b); |
mzta | 0:158c61bb030f | 412 | struct RString *t; |
mzta | 0:158c61bb030f | 413 | |
mzta | 0:158c61bb030f | 414 | t = str_new(mrb, 0, RSTR_LEN(s) + RSTR_LEN(s2)); |
mzta | 0:158c61bb030f | 415 | memcpy(RSTR_PTR(t), RSTR_PTR(s), RSTR_LEN(s)); |
mzta | 0:158c61bb030f | 416 | memcpy(RSTR_PTR(t) + RSTR_LEN(s), RSTR_PTR(s2), RSTR_LEN(s2)); |
mzta | 0:158c61bb030f | 417 | |
mzta | 0:158c61bb030f | 418 | return mrb_obj_value(t); |
mzta | 0:158c61bb030f | 419 | } |
mzta | 0:158c61bb030f | 420 | |
mzta | 0:158c61bb030f | 421 | /* 15.2.10.5.2 */ |
mzta | 0:158c61bb030f | 422 | |
mzta | 0:158c61bb030f | 423 | /* |
mzta | 0:158c61bb030f | 424 | * call-seq: (Caution! String("abcd") remain) for stack_argument |
mzta | 0:158c61bb030f | 425 | * String("abcdefg") = String("abcd") + String("efg") |
mzta | 0:158c61bb030f | 426 | * |
mzta | 0:158c61bb030f | 427 | * Returns a new string object containing a copy of <i>str</i>. |
mzta | 0:158c61bb030f | 428 | */ |
mzta | 0:158c61bb030f | 429 | static mrb_value |
mzta | 0:158c61bb030f | 430 | mrb_str_plus_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 431 | { |
mzta | 0:158c61bb030f | 432 | mrb_value str; |
mzta | 0:158c61bb030f | 433 | |
mzta | 0:158c61bb030f | 434 | mrb_get_args(mrb, "S", &str); |
mzta | 0:158c61bb030f | 435 | return mrb_str_plus(mrb, self, str); |
mzta | 0:158c61bb030f | 436 | } |
mzta | 0:158c61bb030f | 437 | |
mzta | 0:158c61bb030f | 438 | /* 15.2.10.5.26 */ |
mzta | 0:158c61bb030f | 439 | /* 15.2.10.5.33 */ |
mzta | 0:158c61bb030f | 440 | /* |
mzta | 0:158c61bb030f | 441 | * call-seq: |
mzta | 0:158c61bb030f | 442 | * len = strlen(String("abcd")) |
mzta | 0:158c61bb030f | 443 | * |
mzta | 0:158c61bb030f | 444 | * Returns the length of string. |
mzta | 0:158c61bb030f | 445 | */ |
mzta | 0:158c61bb030f | 446 | static mrb_value |
mzta | 0:158c61bb030f | 447 | mrb_str_size(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 448 | { |
mzta | 0:158c61bb030f | 449 | struct RString *s = mrb_str_ptr(self); |
mzta | 0:158c61bb030f | 450 | return mrb_fixnum_value(RSTR_LEN(s)); |
mzta | 0:158c61bb030f | 451 | } |
mzta | 0:158c61bb030f | 452 | |
mzta | 0:158c61bb030f | 453 | /* 15.2.10.5.1 */ |
mzta | 0:158c61bb030f | 454 | /* |
mzta | 0:158c61bb030f | 455 | * call-seq: |
mzta | 0:158c61bb030f | 456 | * str * integer => new_str |
mzta | 0:158c61bb030f | 457 | * |
mzta | 0:158c61bb030f | 458 | * Copy---Returns a new <code>String</code> containing <i>integer</i> copies of |
mzta | 0:158c61bb030f | 459 | * the receiver. |
mzta | 0:158c61bb030f | 460 | * |
mzta | 0:158c61bb030f | 461 | * "Ho! " * 3 #=> "Ho! Ho! Ho! " |
mzta | 0:158c61bb030f | 462 | */ |
mzta | 0:158c61bb030f | 463 | static mrb_value |
mzta | 0:158c61bb030f | 464 | mrb_str_times(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 465 | { |
mzta | 0:158c61bb030f | 466 | mrb_int n,len,times; |
mzta | 0:158c61bb030f | 467 | struct RString *str2; |
mzta | 0:158c61bb030f | 468 | char *p; |
mzta | 0:158c61bb030f | 469 | |
mzta | 0:158c61bb030f | 470 | mrb_get_args(mrb, "i", ×); |
mzta | 0:158c61bb030f | 471 | if (times < 0) { |
mzta | 0:158c61bb030f | 472 | mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); |
mzta | 0:158c61bb030f | 473 | } |
mzta | 0:158c61bb030f | 474 | if (times && MRB_INT_MAX / times < RSTRING_LEN(self)) { |
mzta | 0:158c61bb030f | 475 | mrb_raise(mrb, E_ARGUMENT_ERROR, "argument too big"); |
mzta | 0:158c61bb030f | 476 | } |
mzta | 0:158c61bb030f | 477 | |
mzta | 0:158c61bb030f | 478 | len = RSTRING_LEN(self)*times; |
mzta | 0:158c61bb030f | 479 | str2 = str_new(mrb, 0, len); |
mzta | 0:158c61bb030f | 480 | str_with_class(mrb, str2, self); |
mzta | 0:158c61bb030f | 481 | p = RSTR_PTR(str2); |
mzta | 0:158c61bb030f | 482 | if (len > 0) { |
mzta | 0:158c61bb030f | 483 | n = RSTRING_LEN(self); |
mzta | 0:158c61bb030f | 484 | memcpy(p, RSTRING_PTR(self), n); |
mzta | 0:158c61bb030f | 485 | while (n <= len/2) { |
mzta | 0:158c61bb030f | 486 | memcpy(p + n, p, n); |
mzta | 0:158c61bb030f | 487 | n *= 2; |
mzta | 0:158c61bb030f | 488 | } |
mzta | 0:158c61bb030f | 489 | memcpy(p + n, p, len-n); |
mzta | 0:158c61bb030f | 490 | } |
mzta | 0:158c61bb030f | 491 | p[RSTR_LEN(str2)] = '\0'; |
mzta | 0:158c61bb030f | 492 | |
mzta | 0:158c61bb030f | 493 | return mrb_obj_value(str2); |
mzta | 0:158c61bb030f | 494 | } |
mzta | 0:158c61bb030f | 495 | /* -------------------------------------------------------------- */ |
mzta | 0:158c61bb030f | 496 | |
mzta | 0:158c61bb030f | 497 | #define lesser(a,b) (((a)>(b))?(b):(a)) |
mzta | 0:158c61bb030f | 498 | |
mzta | 0:158c61bb030f | 499 | /* ---------------------------*/ |
mzta | 0:158c61bb030f | 500 | /* |
mzta | 0:158c61bb030f | 501 | * call-seq: |
mzta | 0:158c61bb030f | 502 | * mrb_value str1 <=> mrb_value str2 => int |
mzta | 0:158c61bb030f | 503 | * > 1 |
mzta | 0:158c61bb030f | 504 | * = 0 |
mzta | 0:158c61bb030f | 505 | * < -1 |
mzta | 0:158c61bb030f | 506 | */ |
mzta | 0:158c61bb030f | 507 | MRB_API int |
mzta | 0:158c61bb030f | 508 | mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2) |
mzta | 0:158c61bb030f | 509 | { |
mzta | 0:158c61bb030f | 510 | mrb_int len; |
mzta | 0:158c61bb030f | 511 | mrb_int retval; |
mzta | 0:158c61bb030f | 512 | struct RString *s1 = mrb_str_ptr(str1); |
mzta | 0:158c61bb030f | 513 | struct RString *s2 = mrb_str_ptr(str2); |
mzta | 0:158c61bb030f | 514 | |
mzta | 0:158c61bb030f | 515 | len = lesser(RSTR_LEN(s1), RSTR_LEN(s2)); |
mzta | 0:158c61bb030f | 516 | retval = memcmp(RSTR_PTR(s1), RSTR_PTR(s2), len); |
mzta | 0:158c61bb030f | 517 | if (retval == 0) { |
mzta | 0:158c61bb030f | 518 | if (RSTR_LEN(s1) == RSTR_LEN(s2)) return 0; |
mzta | 0:158c61bb030f | 519 | if (RSTR_LEN(s1) > RSTR_LEN(s2)) return 1; |
mzta | 0:158c61bb030f | 520 | return -1; |
mzta | 0:158c61bb030f | 521 | } |
mzta | 0:158c61bb030f | 522 | if (retval > 0) return 1; |
mzta | 0:158c61bb030f | 523 | return -1; |
mzta | 0:158c61bb030f | 524 | } |
mzta | 0:158c61bb030f | 525 | |
mzta | 0:158c61bb030f | 526 | /* 15.2.10.5.3 */ |
mzta | 0:158c61bb030f | 527 | |
mzta | 0:158c61bb030f | 528 | /* |
mzta | 0:158c61bb030f | 529 | * call-seq: |
mzta | 0:158c61bb030f | 530 | * str <=> other_str => -1, 0, +1 |
mzta | 0:158c61bb030f | 531 | * |
mzta | 0:158c61bb030f | 532 | * Comparison---Returns -1 if <i>other_str</i> is less than, 0 if |
mzta | 0:158c61bb030f | 533 | * <i>other_str</i> is equal to, and +1 if <i>other_str</i> is greater than |
mzta | 0:158c61bb030f | 534 | * <i>str</i>. If the strings are of different lengths, and the strings are |
mzta | 0:158c61bb030f | 535 | * equal when compared up to the shortest length, then the longer string is |
mzta | 0:158c61bb030f | 536 | * considered greater than the shorter one. If the variable <code>$=</code> is |
mzta | 0:158c61bb030f | 537 | * <code>false</code>, the comparison is based on comparing the binary values |
mzta | 0:158c61bb030f | 538 | * of each character in the string. In older versions of Ruby, setting |
mzta | 0:158c61bb030f | 539 | * <code>$=</code> allowed case-insensitive comparisons; this is now deprecated |
mzta | 0:158c61bb030f | 540 | * in favor of using <code>String#casecmp</code>. |
mzta | 0:158c61bb030f | 541 | * |
mzta | 0:158c61bb030f | 542 | * <code><=></code> is the basis for the methods <code><</code>, |
mzta | 0:158c61bb030f | 543 | * <code><=</code>, <code>></code>, <code>>=</code>, and <code>between?</code>, |
mzta | 0:158c61bb030f | 544 | * included from module <code>Comparable</code>. The method |
mzta | 0:158c61bb030f | 545 | * <code>String#==</code> does not use <code>Comparable#==</code>. |
mzta | 0:158c61bb030f | 546 | * |
mzta | 0:158c61bb030f | 547 | * "abcdef" <=> "abcde" #=> 1 |
mzta | 0:158c61bb030f | 548 | * "abcdef" <=> "abcdef" #=> 0 |
mzta | 0:158c61bb030f | 549 | * "abcdef" <=> "abcdefg" #=> -1 |
mzta | 0:158c61bb030f | 550 | * "abcdef" <=> "ABCDEF" #=> 1 |
mzta | 0:158c61bb030f | 551 | */ |
mzta | 0:158c61bb030f | 552 | static mrb_value |
mzta | 0:158c61bb030f | 553 | mrb_str_cmp_m(mrb_state *mrb, mrb_value str1) |
mzta | 0:158c61bb030f | 554 | { |
mzta | 0:158c61bb030f | 555 | mrb_value str2; |
mzta | 0:158c61bb030f | 556 | mrb_int result; |
mzta | 0:158c61bb030f | 557 | |
mzta | 0:158c61bb030f | 558 | mrb_get_args(mrb, "o", &str2); |
mzta | 0:158c61bb030f | 559 | if (!mrb_string_p(str2)) { |
mzta | 0:158c61bb030f | 560 | if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_s"))) { |
mzta | 0:158c61bb030f | 561 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 562 | } |
mzta | 0:158c61bb030f | 563 | else if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "<=>"))) { |
mzta | 0:158c61bb030f | 564 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 565 | } |
mzta | 0:158c61bb030f | 566 | else { |
mzta | 0:158c61bb030f | 567 | mrb_value tmp = mrb_funcall(mrb, str2, "<=>", 1, str1); |
mzta | 0:158c61bb030f | 568 | |
mzta | 0:158c61bb030f | 569 | if (mrb_nil_p(tmp)) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 570 | if (!mrb_fixnum(tmp)) { |
mzta | 0:158c61bb030f | 571 | return mrb_funcall(mrb, mrb_fixnum_value(0), "-", 1, tmp); |
mzta | 0:158c61bb030f | 572 | } |
mzta | 0:158c61bb030f | 573 | result = -mrb_fixnum(tmp); |
mzta | 0:158c61bb030f | 574 | } |
mzta | 0:158c61bb030f | 575 | } |
mzta | 0:158c61bb030f | 576 | else { |
mzta | 0:158c61bb030f | 577 | result = mrb_str_cmp(mrb, str1, str2); |
mzta | 0:158c61bb030f | 578 | } |
mzta | 0:158c61bb030f | 579 | return mrb_fixnum_value(result); |
mzta | 0:158c61bb030f | 580 | } |
mzta | 0:158c61bb030f | 581 | |
mzta | 0:158c61bb030f | 582 | static mrb_bool |
mzta | 0:158c61bb030f | 583 | str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) |
mzta | 0:158c61bb030f | 584 | { |
mzta | 0:158c61bb030f | 585 | const mrb_int len = RSTRING_LEN(str1); |
mzta | 0:158c61bb030f | 586 | |
mzta | 0:158c61bb030f | 587 | if (len != RSTRING_LEN(str2)) return FALSE; |
mzta | 0:158c61bb030f | 588 | if (memcmp(RSTRING_PTR(str1), RSTRING_PTR(str2), (size_t)len) == 0) |
mzta | 0:158c61bb030f | 589 | return TRUE; |
mzta | 0:158c61bb030f | 590 | return FALSE; |
mzta | 0:158c61bb030f | 591 | } |
mzta | 0:158c61bb030f | 592 | |
mzta | 0:158c61bb030f | 593 | MRB_API mrb_bool |
mzta | 0:158c61bb030f | 594 | mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) |
mzta | 0:158c61bb030f | 595 | { |
mzta | 0:158c61bb030f | 596 | if (mrb_immediate_p(str2)) return FALSE; |
mzta | 0:158c61bb030f | 597 | if (!mrb_string_p(str2)) { |
mzta | 0:158c61bb030f | 598 | if (mrb_nil_p(str2)) return FALSE; |
mzta | 0:158c61bb030f | 599 | if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { |
mzta | 0:158c61bb030f | 600 | return FALSE; |
mzta | 0:158c61bb030f | 601 | } |
mzta | 0:158c61bb030f | 602 | str2 = mrb_funcall(mrb, str2, "to_str", 0); |
mzta | 0:158c61bb030f | 603 | return mrb_equal(mrb, str2, str1); |
mzta | 0:158c61bb030f | 604 | } |
mzta | 0:158c61bb030f | 605 | return str_eql(mrb, str1, str2); |
mzta | 0:158c61bb030f | 606 | } |
mzta | 0:158c61bb030f | 607 | |
mzta | 0:158c61bb030f | 608 | /* 15.2.10.5.4 */ |
mzta | 0:158c61bb030f | 609 | /* |
mzta | 0:158c61bb030f | 610 | * call-seq: |
mzta | 0:158c61bb030f | 611 | * str == obj => true or false |
mzta | 0:158c61bb030f | 612 | * |
mzta | 0:158c61bb030f | 613 | * Equality--- |
mzta | 0:158c61bb030f | 614 | * If <i>obj</i> is not a <code>String</code>, returns <code>false</code>. |
mzta | 0:158c61bb030f | 615 | * Otherwise, returns <code>false</code> or <code>true</code> |
mzta | 0:158c61bb030f | 616 | * |
mzta | 0:158c61bb030f | 617 | * caution:if <i>str</i> <code><=></code> <i>obj</i> returns zero. |
mzta | 0:158c61bb030f | 618 | */ |
mzta | 0:158c61bb030f | 619 | static mrb_value |
mzta | 0:158c61bb030f | 620 | mrb_str_equal_m(mrb_state *mrb, mrb_value str1) |
mzta | 0:158c61bb030f | 621 | { |
mzta | 0:158c61bb030f | 622 | mrb_value str2; |
mzta | 0:158c61bb030f | 623 | |
mzta | 0:158c61bb030f | 624 | mrb_get_args(mrb, "o", &str2); |
mzta | 0:158c61bb030f | 625 | |
mzta | 0:158c61bb030f | 626 | return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); |
mzta | 0:158c61bb030f | 627 | } |
mzta | 0:158c61bb030f | 628 | /* ---------------------------------- */ |
mzta | 0:158c61bb030f | 629 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 630 | mrb_str_to_str(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 631 | { |
mzta | 0:158c61bb030f | 632 | mrb_value s; |
mzta | 0:158c61bb030f | 633 | |
mzta | 0:158c61bb030f | 634 | if (!mrb_string_p(str)) { |
mzta | 0:158c61bb030f | 635 | s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); |
mzta | 0:158c61bb030f | 636 | if (mrb_nil_p(s)) { |
mzta | 0:158c61bb030f | 637 | s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); |
mzta | 0:158c61bb030f | 638 | } |
mzta | 0:158c61bb030f | 639 | return s; |
mzta | 0:158c61bb030f | 640 | } |
mzta | 0:158c61bb030f | 641 | return str; |
mzta | 0:158c61bb030f | 642 | } |
mzta | 0:158c61bb030f | 643 | |
mzta | 0:158c61bb030f | 644 | MRB_API const char* |
mzta | 0:158c61bb030f | 645 | mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) |
mzta | 0:158c61bb030f | 646 | { |
mzta | 0:158c61bb030f | 647 | mrb_value str = mrb_str_to_str(mrb, ptr); |
mzta | 0:158c61bb030f | 648 | return RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 649 | } |
mzta | 0:158c61bb030f | 650 | |
mzta | 0:158c61bb030f | 651 | void |
mzta | 0:158c61bb030f | 652 | mrb_noregexp(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 653 | { |
mzta | 0:158c61bb030f | 654 | mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); |
mzta | 0:158c61bb030f | 655 | } |
mzta | 0:158c61bb030f | 656 | |
mzta | 0:158c61bb030f | 657 | void |
mzta | 0:158c61bb030f | 658 | mrb_regexp_check(mrb_state *mrb, mrb_value obj) |
mzta | 0:158c61bb030f | 659 | { |
mzta | 0:158c61bb030f | 660 | if (mrb_regexp_p(mrb, obj)) { |
mzta | 0:158c61bb030f | 661 | mrb_noregexp(mrb, obj); |
mzta | 0:158c61bb030f | 662 | } |
mzta | 0:158c61bb030f | 663 | } |
mzta | 0:158c61bb030f | 664 | |
mzta | 0:158c61bb030f | 665 | static inline mrb_int |
mzta | 0:158c61bb030f | 666 | mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n) |
mzta | 0:158c61bb030f | 667 | { |
mzta | 0:158c61bb030f | 668 | const unsigned char *x = xs, *xe = xs + m; |
mzta | 0:158c61bb030f | 669 | const unsigned char *y = ys; |
mzta | 0:158c61bb030f | 670 | int i, qstable[256]; |
mzta | 0:158c61bb030f | 671 | |
mzta | 0:158c61bb030f | 672 | /* Preprocessing */ |
mzta | 0:158c61bb030f | 673 | for (i = 0; i < 256; ++i) |
mzta | 0:158c61bb030f | 674 | qstable[i] = m + 1; |
mzta | 0:158c61bb030f | 675 | for (; x < xe; ++x) |
mzta | 0:158c61bb030f | 676 | qstable[*x] = xe - x; |
mzta | 0:158c61bb030f | 677 | /* Searching */ |
mzta | 0:158c61bb030f | 678 | for (; y + m <= ys + n; y += *(qstable + y[m])) { |
mzta | 0:158c61bb030f | 679 | if (*xs == *y && memcmp(xs, y, m) == 0) |
mzta | 0:158c61bb030f | 680 | return y - ys; |
mzta | 0:158c61bb030f | 681 | } |
mzta | 0:158c61bb030f | 682 | return -1; |
mzta | 0:158c61bb030f | 683 | } |
mzta | 0:158c61bb030f | 684 | |
mzta | 0:158c61bb030f | 685 | static mrb_int |
mzta | 0:158c61bb030f | 686 | mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) |
mzta | 0:158c61bb030f | 687 | { |
mzta | 0:158c61bb030f | 688 | const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0; |
mzta | 0:158c61bb030f | 689 | |
mzta | 0:158c61bb030f | 690 | if (m > n) return -1; |
mzta | 0:158c61bb030f | 691 | else if (m == n) { |
mzta | 0:158c61bb030f | 692 | return memcmp(x0, y0, m) == 0 ? 0 : -1; |
mzta | 0:158c61bb030f | 693 | } |
mzta | 0:158c61bb030f | 694 | else if (m < 1) { |
mzta | 0:158c61bb030f | 695 | return 0; |
mzta | 0:158c61bb030f | 696 | } |
mzta | 0:158c61bb030f | 697 | else if (m == 1) { |
mzta | 0:158c61bb030f | 698 | const unsigned char *ys = y, *ye = ys + n; |
mzta | 0:158c61bb030f | 699 | for (; y < ye; ++y) { |
mzta | 0:158c61bb030f | 700 | if (*x == *y) |
mzta | 0:158c61bb030f | 701 | return y - ys; |
mzta | 0:158c61bb030f | 702 | } |
mzta | 0:158c61bb030f | 703 | return -1; |
mzta | 0:158c61bb030f | 704 | } |
mzta | 0:158c61bb030f | 705 | return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n); |
mzta | 0:158c61bb030f | 706 | } |
mzta | 0:158c61bb030f | 707 | |
mzta | 0:158c61bb030f | 708 | static mrb_int |
mzta | 0:158c61bb030f | 709 | mrb_str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) |
mzta | 0:158c61bb030f | 710 | { |
mzta | 0:158c61bb030f | 711 | mrb_int pos; |
mzta | 0:158c61bb030f | 712 | char *s, *sptr; |
mzta | 0:158c61bb030f | 713 | mrb_int len, slen; |
mzta | 0:158c61bb030f | 714 | |
mzta | 0:158c61bb030f | 715 | len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 716 | slen = RSTRING_LEN(sub); |
mzta | 0:158c61bb030f | 717 | if (offset < 0) { |
mzta | 0:158c61bb030f | 718 | offset += len; |
mzta | 0:158c61bb030f | 719 | if (offset < 0) return -1; |
mzta | 0:158c61bb030f | 720 | } |
mzta | 0:158c61bb030f | 721 | if (len - offset < slen) return -1; |
mzta | 0:158c61bb030f | 722 | s = RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 723 | if (offset) { |
mzta | 0:158c61bb030f | 724 | s += offset; |
mzta | 0:158c61bb030f | 725 | } |
mzta | 0:158c61bb030f | 726 | if (slen == 0) return offset; |
mzta | 0:158c61bb030f | 727 | /* need proceed one character at a time */ |
mzta | 0:158c61bb030f | 728 | sptr = RSTRING_PTR(sub); |
mzta | 0:158c61bb030f | 729 | slen = RSTRING_LEN(sub); |
mzta | 0:158c61bb030f | 730 | len = RSTRING_LEN(str) - offset; |
mzta | 0:158c61bb030f | 731 | pos = mrb_memsearch(sptr, slen, s, len); |
mzta | 0:158c61bb030f | 732 | if (pos < 0) return pos; |
mzta | 0:158c61bb030f | 733 | return pos + offset; |
mzta | 0:158c61bb030f | 734 | } |
mzta | 0:158c61bb030f | 735 | |
mzta | 0:158c61bb030f | 736 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 737 | mrb_str_dup(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 738 | { |
mzta | 0:158c61bb030f | 739 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 740 | struct RString *dup = str_new(mrb, 0, 0); |
mzta | 0:158c61bb030f | 741 | |
mzta | 0:158c61bb030f | 742 | str_with_class(mrb, dup, str); |
mzta | 0:158c61bb030f | 743 | return str_replace(mrb, dup, s); |
mzta | 0:158c61bb030f | 744 | } |
mzta | 0:158c61bb030f | 745 | |
mzta | 0:158c61bb030f | 746 | static mrb_value |
mzta | 0:158c61bb030f | 747 | mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) |
mzta | 0:158c61bb030f | 748 | { |
mzta | 0:158c61bb030f | 749 | mrb_int idx; |
mzta | 0:158c61bb030f | 750 | |
mzta | 0:158c61bb030f | 751 | mrb_regexp_check(mrb, indx); |
mzta | 0:158c61bb030f | 752 | switch (mrb_type(indx)) { |
mzta | 0:158c61bb030f | 753 | case MRB_TT_FIXNUM: |
mzta | 0:158c61bb030f | 754 | idx = mrb_fixnum(indx); |
mzta | 0:158c61bb030f | 755 | |
mzta | 0:158c61bb030f | 756 | num_index: |
mzta | 0:158c61bb030f | 757 | str = mrb_str_substr(mrb, str, idx, 1); |
mzta | 0:158c61bb030f | 758 | if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 759 | return str; |
mzta | 0:158c61bb030f | 760 | |
mzta | 0:158c61bb030f | 761 | case MRB_TT_STRING: |
mzta | 0:158c61bb030f | 762 | if (mrb_str_index(mrb, str, indx, 0) != -1) |
mzta | 0:158c61bb030f | 763 | return mrb_str_dup(mrb, indx); |
mzta | 0:158c61bb030f | 764 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 765 | |
mzta | 0:158c61bb030f | 766 | case MRB_TT_RANGE: |
mzta | 0:158c61bb030f | 767 | /* check if indx is Range */ |
mzta | 0:158c61bb030f | 768 | { |
mzta | 0:158c61bb030f | 769 | mrb_int beg, len; |
mzta | 0:158c61bb030f | 770 | |
mzta | 0:158c61bb030f | 771 | len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 772 | if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { |
mzta | 0:158c61bb030f | 773 | return mrb_str_subseq(mrb, str, beg, len); |
mzta | 0:158c61bb030f | 774 | } |
mzta | 0:158c61bb030f | 775 | else { |
mzta | 0:158c61bb030f | 776 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 777 | } |
mzta | 0:158c61bb030f | 778 | } |
mzta | 0:158c61bb030f | 779 | default: |
mzta | 0:158c61bb030f | 780 | idx = mrb_fixnum(indx); |
mzta | 0:158c61bb030f | 781 | goto num_index; |
mzta | 0:158c61bb030f | 782 | } |
mzta | 0:158c61bb030f | 783 | return mrb_nil_value(); /* not reached */ |
mzta | 0:158c61bb030f | 784 | } |
mzta | 0:158c61bb030f | 785 | |
mzta | 0:158c61bb030f | 786 | /* 15.2.10.5.6 */ |
mzta | 0:158c61bb030f | 787 | /* 15.2.10.5.34 */ |
mzta | 0:158c61bb030f | 788 | /* |
mzta | 0:158c61bb030f | 789 | * call-seq: |
mzta | 0:158c61bb030f | 790 | * str[fixnum] => fixnum or nil |
mzta | 0:158c61bb030f | 791 | * str[fixnum, fixnum] => new_str or nil |
mzta | 0:158c61bb030f | 792 | * str[range] => new_str or nil |
mzta | 0:158c61bb030f | 793 | * str[regexp] => new_str or nil |
mzta | 0:158c61bb030f | 794 | * str[regexp, fixnum] => new_str or nil |
mzta | 0:158c61bb030f | 795 | * str[other_str] => new_str or nil |
mzta | 0:158c61bb030f | 796 | * str.slice(fixnum) => fixnum or nil |
mzta | 0:158c61bb030f | 797 | * str.slice(fixnum, fixnum) => new_str or nil |
mzta | 0:158c61bb030f | 798 | * str.slice(range) => new_str or nil |
mzta | 0:158c61bb030f | 799 | * str.slice(other_str) => new_str or nil |
mzta | 0:158c61bb030f | 800 | * |
mzta | 0:158c61bb030f | 801 | * Element Reference---If passed a single <code>Fixnum</code>, returns the code |
mzta | 0:158c61bb030f | 802 | * of the character at that position. If passed two <code>Fixnum</code> |
mzta | 0:158c61bb030f | 803 | * objects, returns a substring starting at the offset given by the first, and |
mzta | 0:158c61bb030f | 804 | * a length given by the second. If given a range, a substring containing |
mzta | 0:158c61bb030f | 805 | * characters at offsets given by the range is returned. In all three cases, if |
mzta | 0:158c61bb030f | 806 | * an offset is negative, it is counted from the end of <i>str</i>. Returns |
mzta | 0:158c61bb030f | 807 | * <code>nil</code> if the initial offset falls outside the string, the length |
mzta | 0:158c61bb030f | 808 | * is negative, or the beginning of the range is greater than the end. |
mzta | 0:158c61bb030f | 809 | * |
mzta | 0:158c61bb030f | 810 | * If a <code>String</code> is given, that string is returned if it occurs in |
mzta | 0:158c61bb030f | 811 | * <i>str</i>. In both cases, <code>nil</code> is returned if there is no |
mzta | 0:158c61bb030f | 812 | * match. |
mzta | 0:158c61bb030f | 813 | * |
mzta | 0:158c61bb030f | 814 | * a = "hello there" |
mzta | 0:158c61bb030f | 815 | * a[1] #=> 101(1.8.7) "e"(1.9.2) |
mzta | 0:158c61bb030f | 816 | * a[1,3] #=> "ell" |
mzta | 0:158c61bb030f | 817 | * a[1..3] #=> "ell" |
mzta | 0:158c61bb030f | 818 | * a[-3,2] #=> "er" |
mzta | 0:158c61bb030f | 819 | * a[-4..-2] #=> "her" |
mzta | 0:158c61bb030f | 820 | * a[12..-1] #=> nil |
mzta | 0:158c61bb030f | 821 | * a[-2..-4] #=> "" |
mzta | 0:158c61bb030f | 822 | * a["lo"] #=> "lo" |
mzta | 0:158c61bb030f | 823 | * a["bye"] #=> nil |
mzta | 0:158c61bb030f | 824 | */ |
mzta | 0:158c61bb030f | 825 | static mrb_value |
mzta | 0:158c61bb030f | 826 | mrb_str_aref_m(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 827 | { |
mzta | 0:158c61bb030f | 828 | mrb_value a1, a2; |
mzta | 0:158c61bb030f | 829 | int argc; |
mzta | 0:158c61bb030f | 830 | |
mzta | 0:158c61bb030f | 831 | argc = mrb_get_args(mrb, "o|o", &a1, &a2); |
mzta | 0:158c61bb030f | 832 | if (argc == 2) { |
mzta | 0:158c61bb030f | 833 | mrb_regexp_check(mrb, a1); |
mzta | 0:158c61bb030f | 834 | return mrb_str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2)); |
mzta | 0:158c61bb030f | 835 | } |
mzta | 0:158c61bb030f | 836 | if (argc != 1) { |
mzta | 0:158c61bb030f | 837 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); |
mzta | 0:158c61bb030f | 838 | } |
mzta | 0:158c61bb030f | 839 | return mrb_str_aref(mrb, str, a1); |
mzta | 0:158c61bb030f | 840 | } |
mzta | 0:158c61bb030f | 841 | |
mzta | 0:158c61bb030f | 842 | /* 15.2.10.5.8 */ |
mzta | 0:158c61bb030f | 843 | /* |
mzta | 0:158c61bb030f | 844 | * call-seq: |
mzta | 0:158c61bb030f | 845 | * str.capitalize! => str or nil |
mzta | 0:158c61bb030f | 846 | * |
mzta | 0:158c61bb030f | 847 | * Modifies <i>str</i> by converting the first character to uppercase and the |
mzta | 0:158c61bb030f | 848 | * remainder to lowercase. Returns <code>nil</code> if no changes are made. |
mzta | 0:158c61bb030f | 849 | * |
mzta | 0:158c61bb030f | 850 | * a = "hello" |
mzta | 0:158c61bb030f | 851 | * a.capitalize! #=> "Hello" |
mzta | 0:158c61bb030f | 852 | * a #=> "Hello" |
mzta | 0:158c61bb030f | 853 | * a.capitalize! #=> nil |
mzta | 0:158c61bb030f | 854 | */ |
mzta | 0:158c61bb030f | 855 | static mrb_value |
mzta | 0:158c61bb030f | 856 | mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 857 | { |
mzta | 0:158c61bb030f | 858 | char *p, *pend; |
mzta | 0:158c61bb030f | 859 | mrb_bool modify = FALSE; |
mzta | 0:158c61bb030f | 860 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 861 | |
mzta | 0:158c61bb030f | 862 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 863 | if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 864 | p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); |
mzta | 0:158c61bb030f | 865 | if (ISLOWER(*p)) { |
mzta | 0:158c61bb030f | 866 | *p = TOUPPER(*p); |
mzta | 0:158c61bb030f | 867 | modify = TRUE; |
mzta | 0:158c61bb030f | 868 | } |
mzta | 0:158c61bb030f | 869 | while (++p < pend) { |
mzta | 0:158c61bb030f | 870 | if (ISUPPER(*p)) { |
mzta | 0:158c61bb030f | 871 | *p = TOLOWER(*p); |
mzta | 0:158c61bb030f | 872 | modify = TRUE; |
mzta | 0:158c61bb030f | 873 | } |
mzta | 0:158c61bb030f | 874 | } |
mzta | 0:158c61bb030f | 875 | if (modify) return str; |
mzta | 0:158c61bb030f | 876 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 877 | } |
mzta | 0:158c61bb030f | 878 | |
mzta | 0:158c61bb030f | 879 | /* 15.2.10.5.7 */ |
mzta | 0:158c61bb030f | 880 | /* |
mzta | 0:158c61bb030f | 881 | * call-seq: |
mzta | 0:158c61bb030f | 882 | * str.capitalize => new_str |
mzta | 0:158c61bb030f | 883 | * |
mzta | 0:158c61bb030f | 884 | * Returns a copy of <i>str</i> with the first character converted to uppercase |
mzta | 0:158c61bb030f | 885 | * and the remainder to lowercase. |
mzta | 0:158c61bb030f | 886 | * |
mzta | 0:158c61bb030f | 887 | * "hello".capitalize #=> "Hello" |
mzta | 0:158c61bb030f | 888 | * "HELLO".capitalize #=> "Hello" |
mzta | 0:158c61bb030f | 889 | * "123ABC".capitalize #=> "123abc" |
mzta | 0:158c61bb030f | 890 | */ |
mzta | 0:158c61bb030f | 891 | static mrb_value |
mzta | 0:158c61bb030f | 892 | mrb_str_capitalize(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 893 | { |
mzta | 0:158c61bb030f | 894 | mrb_value str; |
mzta | 0:158c61bb030f | 895 | |
mzta | 0:158c61bb030f | 896 | str = mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 897 | mrb_str_capitalize_bang(mrb, str); |
mzta | 0:158c61bb030f | 898 | return str; |
mzta | 0:158c61bb030f | 899 | } |
mzta | 0:158c61bb030f | 900 | |
mzta | 0:158c61bb030f | 901 | /* 15.2.10.5.10 */ |
mzta | 0:158c61bb030f | 902 | /* |
mzta | 0:158c61bb030f | 903 | * call-seq: |
mzta | 0:158c61bb030f | 904 | * str.chomp!(separator=$/) => str or nil |
mzta | 0:158c61bb030f | 905 | * |
mzta | 0:158c61bb030f | 906 | * Modifies <i>str</i> in place as described for <code>String#chomp</code>, |
mzta | 0:158c61bb030f | 907 | * returning <i>str</i>, or <code>nil</code> if no modifications were made. |
mzta | 0:158c61bb030f | 908 | */ |
mzta | 0:158c61bb030f | 909 | static mrb_value |
mzta | 0:158c61bb030f | 910 | mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 911 | { |
mzta | 0:158c61bb030f | 912 | mrb_value rs; |
mzta | 0:158c61bb030f | 913 | mrb_int newline; |
mzta | 0:158c61bb030f | 914 | char *p, *pp; |
mzta | 0:158c61bb030f | 915 | mrb_int rslen; |
mzta | 0:158c61bb030f | 916 | mrb_int len; |
mzta | 0:158c61bb030f | 917 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 918 | |
mzta | 0:158c61bb030f | 919 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 920 | len = RSTR_LEN(s); |
mzta | 0:158c61bb030f | 921 | if (mrb_get_args(mrb, "|S", &rs) == 0) { |
mzta | 0:158c61bb030f | 922 | if (len == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 923 | smart_chomp: |
mzta | 0:158c61bb030f | 924 | if (RSTR_PTR(s)[len-1] == '\n') { |
mzta | 0:158c61bb030f | 925 | RSTR_SET_LEN(s, RSTR_LEN(s) - 1); |
mzta | 0:158c61bb030f | 926 | if (RSTR_LEN(s) > 0 && |
mzta | 0:158c61bb030f | 927 | RSTR_PTR(s)[RSTR_LEN(s)-1] == '\r') { |
mzta | 0:158c61bb030f | 928 | RSTR_SET_LEN(s, RSTR_LEN(s) - 1); |
mzta | 0:158c61bb030f | 929 | } |
mzta | 0:158c61bb030f | 930 | } |
mzta | 0:158c61bb030f | 931 | else if (RSTR_PTR(s)[len-1] == '\r') { |
mzta | 0:158c61bb030f | 932 | RSTR_SET_LEN(s, RSTR_LEN(s) - 1); |
mzta | 0:158c61bb030f | 933 | } |
mzta | 0:158c61bb030f | 934 | else { |
mzta | 0:158c61bb030f | 935 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 936 | } |
mzta | 0:158c61bb030f | 937 | RSTR_PTR(s)[RSTR_LEN(s)] = '\0'; |
mzta | 0:158c61bb030f | 938 | return str; |
mzta | 0:158c61bb030f | 939 | } |
mzta | 0:158c61bb030f | 940 | |
mzta | 0:158c61bb030f | 941 | if (len == 0 || mrb_nil_p(rs)) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 942 | p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 943 | rslen = RSTRING_LEN(rs); |
mzta | 0:158c61bb030f | 944 | if (rslen == 0) { |
mzta | 0:158c61bb030f | 945 | while (len>0 && p[len-1] == '\n') { |
mzta | 0:158c61bb030f | 946 | len--; |
mzta | 0:158c61bb030f | 947 | if (len>0 && p[len-1] == '\r') |
mzta | 0:158c61bb030f | 948 | len--; |
mzta | 0:158c61bb030f | 949 | } |
mzta | 0:158c61bb030f | 950 | if (len < RSTR_LEN(s)) { |
mzta | 0:158c61bb030f | 951 | RSTR_SET_LEN(s, len); |
mzta | 0:158c61bb030f | 952 | p[len] = '\0'; |
mzta | 0:158c61bb030f | 953 | return str; |
mzta | 0:158c61bb030f | 954 | } |
mzta | 0:158c61bb030f | 955 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 956 | } |
mzta | 0:158c61bb030f | 957 | if (rslen > len) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 958 | newline = RSTRING_PTR(rs)[rslen-1]; |
mzta | 0:158c61bb030f | 959 | if (rslen == 1 && newline == '\n') |
mzta | 0:158c61bb030f | 960 | newline = RSTRING_PTR(rs)[rslen-1]; |
mzta | 0:158c61bb030f | 961 | if (rslen == 1 && newline == '\n') |
mzta | 0:158c61bb030f | 962 | goto smart_chomp; |
mzta | 0:158c61bb030f | 963 | |
mzta | 0:158c61bb030f | 964 | pp = p + len - rslen; |
mzta | 0:158c61bb030f | 965 | if (p[len-1] == newline && |
mzta | 0:158c61bb030f | 966 | (rslen <= 1 || |
mzta | 0:158c61bb030f | 967 | memcmp(RSTRING_PTR(rs), pp, rslen) == 0)) { |
mzta | 0:158c61bb030f | 968 | RSTR_SET_LEN(s, len - rslen); |
mzta | 0:158c61bb030f | 969 | p[RSTR_LEN(s)] = '\0'; |
mzta | 0:158c61bb030f | 970 | return str; |
mzta | 0:158c61bb030f | 971 | } |
mzta | 0:158c61bb030f | 972 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 973 | } |
mzta | 0:158c61bb030f | 974 | |
mzta | 0:158c61bb030f | 975 | /* 15.2.10.5.9 */ |
mzta | 0:158c61bb030f | 976 | /* |
mzta | 0:158c61bb030f | 977 | * call-seq: |
mzta | 0:158c61bb030f | 978 | * str.chomp(separator=$/) => new_str |
mzta | 0:158c61bb030f | 979 | * |
mzta | 0:158c61bb030f | 980 | * Returns a new <code>String</code> with the given record separator removed |
mzta | 0:158c61bb030f | 981 | * from the end of <i>str</i> (if present). If <code>$/</code> has not been |
mzta | 0:158c61bb030f | 982 | * changed from the default Ruby record separator, then <code>chomp</code> also |
mzta | 0:158c61bb030f | 983 | * removes carriage return characters (that is it will remove <code>\n</code>, |
mzta | 0:158c61bb030f | 984 | * <code>\r</code>, and <code>\r\n</code>). |
mzta | 0:158c61bb030f | 985 | * |
mzta | 0:158c61bb030f | 986 | * "hello".chomp #=> "hello" |
mzta | 0:158c61bb030f | 987 | * "hello\n".chomp #=> "hello" |
mzta | 0:158c61bb030f | 988 | * "hello\r\n".chomp #=> "hello" |
mzta | 0:158c61bb030f | 989 | * "hello\n\r".chomp #=> "hello\n" |
mzta | 0:158c61bb030f | 990 | * "hello\r".chomp #=> "hello" |
mzta | 0:158c61bb030f | 991 | * "hello \n there".chomp #=> "hello \n there" |
mzta | 0:158c61bb030f | 992 | * "hello".chomp("llo") #=> "he" |
mzta | 0:158c61bb030f | 993 | */ |
mzta | 0:158c61bb030f | 994 | static mrb_value |
mzta | 0:158c61bb030f | 995 | mrb_str_chomp(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 996 | { |
mzta | 0:158c61bb030f | 997 | mrb_value str; |
mzta | 0:158c61bb030f | 998 | |
mzta | 0:158c61bb030f | 999 | str = mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 1000 | mrb_str_chomp_bang(mrb, str); |
mzta | 0:158c61bb030f | 1001 | return str; |
mzta | 0:158c61bb030f | 1002 | } |
mzta | 0:158c61bb030f | 1003 | |
mzta | 0:158c61bb030f | 1004 | /* 15.2.10.5.12 */ |
mzta | 0:158c61bb030f | 1005 | /* |
mzta | 0:158c61bb030f | 1006 | * call-seq: |
mzta | 0:158c61bb030f | 1007 | * str.chop! => str or nil |
mzta | 0:158c61bb030f | 1008 | * |
mzta | 0:158c61bb030f | 1009 | * Processes <i>str</i> as for <code>String#chop</code>, returning <i>str</i>, |
mzta | 0:158c61bb030f | 1010 | * or <code>nil</code> if <i>str</i> is the empty string. See also |
mzta | 0:158c61bb030f | 1011 | * <code>String#chomp!</code>. |
mzta | 0:158c61bb030f | 1012 | */ |
mzta | 0:158c61bb030f | 1013 | static mrb_value |
mzta | 0:158c61bb030f | 1014 | mrb_str_chop_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1015 | { |
mzta | 0:158c61bb030f | 1016 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1017 | |
mzta | 0:158c61bb030f | 1018 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 1019 | if (RSTR_LEN(s) > 0) { |
mzta | 0:158c61bb030f | 1020 | mrb_int len; |
mzta | 0:158c61bb030f | 1021 | len = RSTR_LEN(s) - 1; |
mzta | 0:158c61bb030f | 1022 | if (RSTR_PTR(s)[len] == '\n') { |
mzta | 0:158c61bb030f | 1023 | if (len > 0 && |
mzta | 0:158c61bb030f | 1024 | RSTR_PTR(s)[len-1] == '\r') { |
mzta | 0:158c61bb030f | 1025 | len--; |
mzta | 0:158c61bb030f | 1026 | } |
mzta | 0:158c61bb030f | 1027 | } |
mzta | 0:158c61bb030f | 1028 | RSTR_SET_LEN(s, len); |
mzta | 0:158c61bb030f | 1029 | RSTR_PTR(s)[len] = '\0'; |
mzta | 0:158c61bb030f | 1030 | return str; |
mzta | 0:158c61bb030f | 1031 | } |
mzta | 0:158c61bb030f | 1032 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1033 | } |
mzta | 0:158c61bb030f | 1034 | |
mzta | 0:158c61bb030f | 1035 | /* 15.2.10.5.11 */ |
mzta | 0:158c61bb030f | 1036 | /* |
mzta | 0:158c61bb030f | 1037 | * call-seq: |
mzta | 0:158c61bb030f | 1038 | * str.chop => new_str |
mzta | 0:158c61bb030f | 1039 | * |
mzta | 0:158c61bb030f | 1040 | * Returns a new <code>String</code> with the last character removed. If the |
mzta | 0:158c61bb030f | 1041 | * string ends with <code>\r\n</code>, both characters are removed. Applying |
mzta | 0:158c61bb030f | 1042 | * <code>chop</code> to an empty string returns an empty |
mzta | 0:158c61bb030f | 1043 | * string. <code>String#chomp</code> is often a safer alternative, as it leaves |
mzta | 0:158c61bb030f | 1044 | * the string unchanged if it doesn't end in a record separator. |
mzta | 0:158c61bb030f | 1045 | * |
mzta | 0:158c61bb030f | 1046 | * "string\r\n".chop #=> "string" |
mzta | 0:158c61bb030f | 1047 | * "string\n\r".chop #=> "string\n" |
mzta | 0:158c61bb030f | 1048 | * "string\n".chop #=> "string" |
mzta | 0:158c61bb030f | 1049 | * "string".chop #=> "strin" |
mzta | 0:158c61bb030f | 1050 | * "x".chop #=> "" |
mzta | 0:158c61bb030f | 1051 | */ |
mzta | 0:158c61bb030f | 1052 | static mrb_value |
mzta | 0:158c61bb030f | 1053 | mrb_str_chop(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1054 | { |
mzta | 0:158c61bb030f | 1055 | mrb_value str; |
mzta | 0:158c61bb030f | 1056 | str = mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 1057 | mrb_str_chop_bang(mrb, str); |
mzta | 0:158c61bb030f | 1058 | return str; |
mzta | 0:158c61bb030f | 1059 | } |
mzta | 0:158c61bb030f | 1060 | |
mzta | 0:158c61bb030f | 1061 | /* 15.2.10.5.14 */ |
mzta | 0:158c61bb030f | 1062 | /* |
mzta | 0:158c61bb030f | 1063 | * call-seq: |
mzta | 0:158c61bb030f | 1064 | * str.downcase! => str or nil |
mzta | 0:158c61bb030f | 1065 | * |
mzta | 0:158c61bb030f | 1066 | * Downcases the contents of <i>str</i>, returning <code>nil</code> if no |
mzta | 0:158c61bb030f | 1067 | * changes were made. |
mzta | 0:158c61bb030f | 1068 | */ |
mzta | 0:158c61bb030f | 1069 | static mrb_value |
mzta | 0:158c61bb030f | 1070 | mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1071 | { |
mzta | 0:158c61bb030f | 1072 | char *p, *pend; |
mzta | 0:158c61bb030f | 1073 | mrb_bool modify = FALSE; |
mzta | 0:158c61bb030f | 1074 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1075 | |
mzta | 0:158c61bb030f | 1076 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 1077 | p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 1078 | pend = RSTR_PTR(s) + RSTR_LEN(s); |
mzta | 0:158c61bb030f | 1079 | while (p < pend) { |
mzta | 0:158c61bb030f | 1080 | if (ISUPPER(*p)) { |
mzta | 0:158c61bb030f | 1081 | *p = TOLOWER(*p); |
mzta | 0:158c61bb030f | 1082 | modify = TRUE; |
mzta | 0:158c61bb030f | 1083 | } |
mzta | 0:158c61bb030f | 1084 | p++; |
mzta | 0:158c61bb030f | 1085 | } |
mzta | 0:158c61bb030f | 1086 | |
mzta | 0:158c61bb030f | 1087 | if (modify) return str; |
mzta | 0:158c61bb030f | 1088 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1089 | } |
mzta | 0:158c61bb030f | 1090 | |
mzta | 0:158c61bb030f | 1091 | /* 15.2.10.5.13 */ |
mzta | 0:158c61bb030f | 1092 | /* |
mzta | 0:158c61bb030f | 1093 | * call-seq: |
mzta | 0:158c61bb030f | 1094 | * str.downcase => new_str |
mzta | 0:158c61bb030f | 1095 | * |
mzta | 0:158c61bb030f | 1096 | * Returns a copy of <i>str</i> with all uppercase letters replaced with their |
mzta | 0:158c61bb030f | 1097 | * lowercase counterparts. The operation is locale insensitive---only |
mzta | 0:158c61bb030f | 1098 | * characters ``A'' to ``Z'' are affected. |
mzta | 0:158c61bb030f | 1099 | * |
mzta | 0:158c61bb030f | 1100 | * "hEllO".downcase #=> "hello" |
mzta | 0:158c61bb030f | 1101 | */ |
mzta | 0:158c61bb030f | 1102 | static mrb_value |
mzta | 0:158c61bb030f | 1103 | mrb_str_downcase(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1104 | { |
mzta | 0:158c61bb030f | 1105 | mrb_value str; |
mzta | 0:158c61bb030f | 1106 | |
mzta | 0:158c61bb030f | 1107 | str = mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 1108 | mrb_str_downcase_bang(mrb, str); |
mzta | 0:158c61bb030f | 1109 | return str; |
mzta | 0:158c61bb030f | 1110 | } |
mzta | 0:158c61bb030f | 1111 | |
mzta | 0:158c61bb030f | 1112 | /* 15.2.10.5.16 */ |
mzta | 0:158c61bb030f | 1113 | /* |
mzta | 0:158c61bb030f | 1114 | * call-seq: |
mzta | 0:158c61bb030f | 1115 | * str.empty? => true or false |
mzta | 0:158c61bb030f | 1116 | * |
mzta | 0:158c61bb030f | 1117 | * Returns <code>true</code> if <i>str</i> has a length of zero. |
mzta | 0:158c61bb030f | 1118 | * |
mzta | 0:158c61bb030f | 1119 | * "hello".empty? #=> false |
mzta | 0:158c61bb030f | 1120 | * "".empty? #=> true |
mzta | 0:158c61bb030f | 1121 | */ |
mzta | 0:158c61bb030f | 1122 | static mrb_value |
mzta | 0:158c61bb030f | 1123 | mrb_str_empty_p(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1124 | { |
mzta | 0:158c61bb030f | 1125 | struct RString *s = mrb_str_ptr(self); |
mzta | 0:158c61bb030f | 1126 | |
mzta | 0:158c61bb030f | 1127 | return mrb_bool_value(RSTR_LEN(s) == 0); |
mzta | 0:158c61bb030f | 1128 | } |
mzta | 0:158c61bb030f | 1129 | |
mzta | 0:158c61bb030f | 1130 | /* 15.2.10.5.17 */ |
mzta | 0:158c61bb030f | 1131 | /* |
mzta | 0:158c61bb030f | 1132 | * call-seq: |
mzta | 0:158c61bb030f | 1133 | * str.eql?(other) => true or false |
mzta | 0:158c61bb030f | 1134 | * |
mzta | 0:158c61bb030f | 1135 | * Two strings are equal if the have the same length and content. |
mzta | 0:158c61bb030f | 1136 | */ |
mzta | 0:158c61bb030f | 1137 | static mrb_value |
mzta | 0:158c61bb030f | 1138 | mrb_str_eql(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1139 | { |
mzta | 0:158c61bb030f | 1140 | mrb_value str2; |
mzta | 0:158c61bb030f | 1141 | mrb_bool eql_p; |
mzta | 0:158c61bb030f | 1142 | |
mzta | 0:158c61bb030f | 1143 | mrb_get_args(mrb, "o", &str2); |
mzta | 0:158c61bb030f | 1144 | eql_p = (mrb_type(str2) == MRB_TT_STRING) && str_eql(mrb, self, str2); |
mzta | 0:158c61bb030f | 1145 | |
mzta | 0:158c61bb030f | 1146 | return mrb_bool_value(eql_p); |
mzta | 0:158c61bb030f | 1147 | } |
mzta | 0:158c61bb030f | 1148 | |
mzta | 0:158c61bb030f | 1149 | static mrb_value |
mzta | 0:158c61bb030f | 1150 | mrb_str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) |
mzta | 0:158c61bb030f | 1151 | { |
mzta | 0:158c61bb030f | 1152 | struct RString *orig, *s; |
mzta | 0:158c61bb030f | 1153 | mrb_shared_string *shared; |
mzta | 0:158c61bb030f | 1154 | |
mzta | 0:158c61bb030f | 1155 | orig = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1156 | if (RSTR_EMBED_P(orig)) { |
mzta | 0:158c61bb030f | 1157 | s = str_new(mrb, orig->as.ary+beg, len); |
mzta | 0:158c61bb030f | 1158 | } else { |
mzta | 0:158c61bb030f | 1159 | str_make_shared(mrb, orig); |
mzta | 0:158c61bb030f | 1160 | shared = orig->as.heap.aux.shared; |
mzta | 0:158c61bb030f | 1161 | s = mrb_obj_alloc_string(mrb); |
mzta | 0:158c61bb030f | 1162 | s->as.heap.ptr = orig->as.heap.ptr + beg; |
mzta | 0:158c61bb030f | 1163 | s->as.heap.len = len; |
mzta | 0:158c61bb030f | 1164 | s->as.heap.aux.shared = shared; |
mzta | 0:158c61bb030f | 1165 | RSTR_SET_SHARED_FLAG(s); |
mzta | 0:158c61bb030f | 1166 | shared->refcnt++; |
mzta | 0:158c61bb030f | 1167 | } |
mzta | 0:158c61bb030f | 1168 | |
mzta | 0:158c61bb030f | 1169 | return mrb_obj_value(s); |
mzta | 0:158c61bb030f | 1170 | } |
mzta | 0:158c61bb030f | 1171 | |
mzta | 0:158c61bb030f | 1172 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1173 | mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) |
mzta | 0:158c61bb030f | 1174 | { |
mzta | 0:158c61bb030f | 1175 | if (len < 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1176 | if (!RSTRING_LEN(str)) { |
mzta | 0:158c61bb030f | 1177 | len = 0; |
mzta | 0:158c61bb030f | 1178 | } |
mzta | 0:158c61bb030f | 1179 | if (beg > RSTRING_LEN(str)) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1180 | if (beg < 0) { |
mzta | 0:158c61bb030f | 1181 | beg += RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 1182 | if (beg < 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1183 | } |
mzta | 0:158c61bb030f | 1184 | if (beg + len > RSTRING_LEN(str)) |
mzta | 0:158c61bb030f | 1185 | len = RSTRING_LEN(str) - beg; |
mzta | 0:158c61bb030f | 1186 | if (len <= 0) { |
mzta | 0:158c61bb030f | 1187 | len = 0; |
mzta | 0:158c61bb030f | 1188 | } |
mzta | 0:158c61bb030f | 1189 | return mrb_str_subseq(mrb, str, beg, len); |
mzta | 0:158c61bb030f | 1190 | } |
mzta | 0:158c61bb030f | 1191 | |
mzta | 0:158c61bb030f | 1192 | mrb_int |
mzta | 0:158c61bb030f | 1193 | mrb_str_hash(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1194 | { |
mzta | 0:158c61bb030f | 1195 | /* 1-8-7 */ |
mzta | 0:158c61bb030f | 1196 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1197 | mrb_int len = RSTR_LEN(s); |
mzta | 0:158c61bb030f | 1198 | char *p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 1199 | mrb_int key = 0; |
mzta | 0:158c61bb030f | 1200 | |
mzta | 0:158c61bb030f | 1201 | while (len--) { |
mzta | 0:158c61bb030f | 1202 | key = key*65599 + *p; |
mzta | 0:158c61bb030f | 1203 | p++; |
mzta | 0:158c61bb030f | 1204 | } |
mzta | 0:158c61bb030f | 1205 | return key + (key>>5); |
mzta | 0:158c61bb030f | 1206 | } |
mzta | 0:158c61bb030f | 1207 | |
mzta | 0:158c61bb030f | 1208 | /* 15.2.10.5.20 */ |
mzta | 0:158c61bb030f | 1209 | /* |
mzta | 0:158c61bb030f | 1210 | * call-seq: |
mzta | 0:158c61bb030f | 1211 | * str.hash => fixnum |
mzta | 0:158c61bb030f | 1212 | * |
mzta | 0:158c61bb030f | 1213 | * Return a hash based on the string's length and content. |
mzta | 0:158c61bb030f | 1214 | */ |
mzta | 0:158c61bb030f | 1215 | static mrb_value |
mzta | 0:158c61bb030f | 1216 | mrb_str_hash_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1217 | { |
mzta | 0:158c61bb030f | 1218 | mrb_int key = mrb_str_hash(mrb, self); |
mzta | 0:158c61bb030f | 1219 | return mrb_fixnum_value(key); |
mzta | 0:158c61bb030f | 1220 | } |
mzta | 0:158c61bb030f | 1221 | |
mzta | 0:158c61bb030f | 1222 | /* 15.2.10.5.21 */ |
mzta | 0:158c61bb030f | 1223 | /* |
mzta | 0:158c61bb030f | 1224 | * call-seq: |
mzta | 0:158c61bb030f | 1225 | * str.include? other_str => true or false |
mzta | 0:158c61bb030f | 1226 | * str.include? fixnum => true or false |
mzta | 0:158c61bb030f | 1227 | * |
mzta | 0:158c61bb030f | 1228 | * Returns <code>true</code> if <i>str</i> contains the given string or |
mzta | 0:158c61bb030f | 1229 | * character. |
mzta | 0:158c61bb030f | 1230 | * |
mzta | 0:158c61bb030f | 1231 | * "hello".include? "lo" #=> true |
mzta | 0:158c61bb030f | 1232 | * "hello".include? "ol" #=> false |
mzta | 0:158c61bb030f | 1233 | * "hello".include? ?h #=> true |
mzta | 0:158c61bb030f | 1234 | */ |
mzta | 0:158c61bb030f | 1235 | static mrb_value |
mzta | 0:158c61bb030f | 1236 | mrb_str_include(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1237 | { |
mzta | 0:158c61bb030f | 1238 | mrb_int i; |
mzta | 0:158c61bb030f | 1239 | mrb_value str2; |
mzta | 0:158c61bb030f | 1240 | mrb_bool include_p; |
mzta | 0:158c61bb030f | 1241 | |
mzta | 0:158c61bb030f | 1242 | mrb_get_args(mrb, "o", &str2); |
mzta | 0:158c61bb030f | 1243 | if (mrb_fixnum_p(str2)) { |
mzta | 0:158c61bb030f | 1244 | include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL); |
mzta | 0:158c61bb030f | 1245 | } |
mzta | 0:158c61bb030f | 1246 | else { |
mzta | 0:158c61bb030f | 1247 | str2 = mrb_str_to_str(mrb, str2); |
mzta | 0:158c61bb030f | 1248 | i = mrb_str_index(mrb, self, str2, 0); |
mzta | 0:158c61bb030f | 1249 | |
mzta | 0:158c61bb030f | 1250 | include_p = (i != -1); |
mzta | 0:158c61bb030f | 1251 | } |
mzta | 0:158c61bb030f | 1252 | |
mzta | 0:158c61bb030f | 1253 | return mrb_bool_value(include_p); |
mzta | 0:158c61bb030f | 1254 | } |
mzta | 0:158c61bb030f | 1255 | |
mzta | 0:158c61bb030f | 1256 | /* 15.2.10.5.22 */ |
mzta | 0:158c61bb030f | 1257 | /* |
mzta | 0:158c61bb030f | 1258 | * call-seq: |
mzta | 0:158c61bb030f | 1259 | * str.index(substring [, offset]) => fixnum or nil |
mzta | 0:158c61bb030f | 1260 | * str.index(fixnum [, offset]) => fixnum or nil |
mzta | 0:158c61bb030f | 1261 | * str.index(regexp [, offset]) => fixnum or nil |
mzta | 0:158c61bb030f | 1262 | * |
mzta | 0:158c61bb030f | 1263 | * Returns the index of the first occurrence of the given |
mzta | 0:158c61bb030f | 1264 | * <i>substring</i>, |
mzta | 0:158c61bb030f | 1265 | * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. |
mzta | 0:158c61bb030f | 1266 | * Returns |
mzta | 0:158c61bb030f | 1267 | * <code>nil</code> if not found. |
mzta | 0:158c61bb030f | 1268 | * If the second parameter is present, it |
mzta | 0:158c61bb030f | 1269 | * specifies the position in the string to begin the search. |
mzta | 0:158c61bb030f | 1270 | * |
mzta | 0:158c61bb030f | 1271 | * "hello".index('e') #=> 1 |
mzta | 0:158c61bb030f | 1272 | * "hello".index('lo') #=> 3 |
mzta | 0:158c61bb030f | 1273 | * "hello".index('a') #=> nil |
mzta | 0:158c61bb030f | 1274 | * "hello".index(101) #=> 1(101=0x65='e') |
mzta | 0:158c61bb030f | 1275 | * "hello".index(/[aeiou]/, -3) #=> 4 |
mzta | 0:158c61bb030f | 1276 | */ |
mzta | 0:158c61bb030f | 1277 | static mrb_value |
mzta | 0:158c61bb030f | 1278 | mrb_str_index_m(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1279 | { |
mzta | 0:158c61bb030f | 1280 | mrb_value *argv; |
mzta | 0:158c61bb030f | 1281 | mrb_int argc; |
mzta | 0:158c61bb030f | 1282 | mrb_value sub; |
mzta | 0:158c61bb030f | 1283 | mrb_int pos; |
mzta | 0:158c61bb030f | 1284 | |
mzta | 0:158c61bb030f | 1285 | mrb_get_args(mrb, "*", &argv, &argc); |
mzta | 0:158c61bb030f | 1286 | if (argc == 2) { |
mzta | 0:158c61bb030f | 1287 | pos = mrb_fixnum(argv[1]); |
mzta | 0:158c61bb030f | 1288 | sub = argv[0]; |
mzta | 0:158c61bb030f | 1289 | } |
mzta | 0:158c61bb030f | 1290 | else { |
mzta | 0:158c61bb030f | 1291 | pos = 0; |
mzta | 0:158c61bb030f | 1292 | if (argc > 0) |
mzta | 0:158c61bb030f | 1293 | sub = argv[0]; |
mzta | 0:158c61bb030f | 1294 | else |
mzta | 0:158c61bb030f | 1295 | sub = mrb_nil_value(); |
mzta | 0:158c61bb030f | 1296 | } |
mzta | 0:158c61bb030f | 1297 | mrb_regexp_check(mrb, sub); |
mzta | 0:158c61bb030f | 1298 | if (pos < 0) { |
mzta | 0:158c61bb030f | 1299 | pos += RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 1300 | if (pos < 0) { |
mzta | 0:158c61bb030f | 1301 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1302 | } |
mzta | 0:158c61bb030f | 1303 | } |
mzta | 0:158c61bb030f | 1304 | |
mzta | 0:158c61bb030f | 1305 | switch (mrb_type(sub)) { |
mzta | 0:158c61bb030f | 1306 | case MRB_TT_FIXNUM: { |
mzta | 0:158c61bb030f | 1307 | int c = mrb_fixnum(sub); |
mzta | 0:158c61bb030f | 1308 | mrb_int len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 1309 | unsigned char *p = (unsigned char*)RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 1310 | |
mzta | 0:158c61bb030f | 1311 | for (;pos<len;pos++) { |
mzta | 0:158c61bb030f | 1312 | if (p[pos] == c) return mrb_fixnum_value(pos); |
mzta | 0:158c61bb030f | 1313 | } |
mzta | 0:158c61bb030f | 1314 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1315 | } |
mzta | 0:158c61bb030f | 1316 | |
mzta | 0:158c61bb030f | 1317 | default: { |
mzta | 0:158c61bb030f | 1318 | mrb_value tmp; |
mzta | 0:158c61bb030f | 1319 | |
mzta | 0:158c61bb030f | 1320 | tmp = mrb_check_string_type(mrb, sub); |
mzta | 0:158c61bb030f | 1321 | if (mrb_nil_p(tmp)) { |
mzta | 0:158c61bb030f | 1322 | mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); |
mzta | 0:158c61bb030f | 1323 | } |
mzta | 0:158c61bb030f | 1324 | sub = tmp; |
mzta | 0:158c61bb030f | 1325 | } |
mzta | 0:158c61bb030f | 1326 | /* fall through */ |
mzta | 0:158c61bb030f | 1327 | case MRB_TT_STRING: |
mzta | 0:158c61bb030f | 1328 | pos = mrb_str_index(mrb, str, sub, pos); |
mzta | 0:158c61bb030f | 1329 | break; |
mzta | 0:158c61bb030f | 1330 | } |
mzta | 0:158c61bb030f | 1331 | |
mzta | 0:158c61bb030f | 1332 | if (pos == -1) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1333 | return mrb_fixnum_value(pos); |
mzta | 0:158c61bb030f | 1334 | } |
mzta | 0:158c61bb030f | 1335 | |
mzta | 0:158c61bb030f | 1336 | #define STR_REPLACE_SHARED_MIN 10 |
mzta | 0:158c61bb030f | 1337 | |
mzta | 0:158c61bb030f | 1338 | static mrb_value |
mzta | 0:158c61bb030f | 1339 | str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) |
mzta | 0:158c61bb030f | 1340 | { |
mzta | 0:158c61bb030f | 1341 | long len; |
mzta | 0:158c61bb030f | 1342 | |
mzta | 0:158c61bb030f | 1343 | len = RSTR_LEN(s2); |
mzta | 0:158c61bb030f | 1344 | if (RSTR_SHARED_P(s1)) { |
mzta | 0:158c61bb030f | 1345 | str_decref(mrb, s1->as.heap.aux.shared); |
mzta | 0:158c61bb030f | 1346 | } |
mzta | 0:158c61bb030f | 1347 | else if (!RSTR_EMBED_P(s1) && !RSTR_NOFREE_P(s1)) { |
mzta | 0:158c61bb030f | 1348 | mrb_free(mrb, s1->as.heap.ptr); |
mzta | 0:158c61bb030f | 1349 | } |
mzta | 0:158c61bb030f | 1350 | |
mzta | 0:158c61bb030f | 1351 | RSTR_UNSET_NOFREE_FLAG(s1); |
mzta | 0:158c61bb030f | 1352 | |
mzta | 0:158c61bb030f | 1353 | if (RSTR_SHARED_P(s2)) { |
mzta | 0:158c61bb030f | 1354 | L_SHARE: |
mzta | 0:158c61bb030f | 1355 | RSTR_UNSET_EMBED_FLAG(s1); |
mzta | 0:158c61bb030f | 1356 | s1->as.heap.ptr = s2->as.heap.ptr; |
mzta | 0:158c61bb030f | 1357 | s1->as.heap.len = len; |
mzta | 0:158c61bb030f | 1358 | s1->as.heap.aux.shared = s2->as.heap.aux.shared; |
mzta | 0:158c61bb030f | 1359 | RSTR_SET_SHARED_FLAG(s1); |
mzta | 0:158c61bb030f | 1360 | s1->as.heap.aux.shared->refcnt++; |
mzta | 0:158c61bb030f | 1361 | } |
mzta | 0:158c61bb030f | 1362 | else { |
mzta | 0:158c61bb030f | 1363 | if (len <= RSTRING_EMBED_LEN_MAX) { |
mzta | 0:158c61bb030f | 1364 | RSTR_UNSET_SHARED_FLAG(s1); |
mzta | 0:158c61bb030f | 1365 | RSTR_SET_EMBED_FLAG(s1); |
mzta | 0:158c61bb030f | 1366 | memcpy(s1->as.ary, RSTR_PTR(s2), len); |
mzta | 0:158c61bb030f | 1367 | RSTR_SET_EMBED_LEN(s1, len); |
mzta | 0:158c61bb030f | 1368 | } |
mzta | 0:158c61bb030f | 1369 | else { |
mzta | 0:158c61bb030f | 1370 | str_make_shared(mrb, s2); |
mzta | 0:158c61bb030f | 1371 | goto L_SHARE; |
mzta | 0:158c61bb030f | 1372 | } |
mzta | 0:158c61bb030f | 1373 | } |
mzta | 0:158c61bb030f | 1374 | |
mzta | 0:158c61bb030f | 1375 | return mrb_obj_value(s1); |
mzta | 0:158c61bb030f | 1376 | } |
mzta | 0:158c61bb030f | 1377 | |
mzta | 0:158c61bb030f | 1378 | /* 15.2.10.5.24 */ |
mzta | 0:158c61bb030f | 1379 | /* 15.2.10.5.28 */ |
mzta | 0:158c61bb030f | 1380 | /* |
mzta | 0:158c61bb030f | 1381 | * call-seq: |
mzta | 0:158c61bb030f | 1382 | * str.replace(other_str) => str |
mzta | 0:158c61bb030f | 1383 | * |
mzta | 0:158c61bb030f | 1384 | * s = "hello" #=> "hello" |
mzta | 0:158c61bb030f | 1385 | * s.replace "world" #=> "world" |
mzta | 0:158c61bb030f | 1386 | */ |
mzta | 0:158c61bb030f | 1387 | static mrb_value |
mzta | 0:158c61bb030f | 1388 | mrb_str_replace(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1389 | { |
mzta | 0:158c61bb030f | 1390 | mrb_value str2; |
mzta | 0:158c61bb030f | 1391 | |
mzta | 0:158c61bb030f | 1392 | mrb_get_args(mrb, "S", &str2); |
mzta | 0:158c61bb030f | 1393 | return str_replace(mrb, mrb_str_ptr(str), mrb_str_ptr(str2)); |
mzta | 0:158c61bb030f | 1394 | } |
mzta | 0:158c61bb030f | 1395 | |
mzta | 0:158c61bb030f | 1396 | /* 15.2.10.5.23 */ |
mzta | 0:158c61bb030f | 1397 | /* |
mzta | 0:158c61bb030f | 1398 | * call-seq: |
mzta | 0:158c61bb030f | 1399 | * String.new(str="") => new_str |
mzta | 0:158c61bb030f | 1400 | * |
mzta | 0:158c61bb030f | 1401 | * Returns a new string object containing a copy of <i>str</i>. |
mzta | 0:158c61bb030f | 1402 | */ |
mzta | 0:158c61bb030f | 1403 | static mrb_value |
mzta | 0:158c61bb030f | 1404 | mrb_str_init(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1405 | { |
mzta | 0:158c61bb030f | 1406 | mrb_value str2; |
mzta | 0:158c61bb030f | 1407 | |
mzta | 0:158c61bb030f | 1408 | if (mrb_get_args(mrb, "|S", &str2) == 1) { |
mzta | 0:158c61bb030f | 1409 | str_replace(mrb, mrb_str_ptr(self), mrb_str_ptr(str2)); |
mzta | 0:158c61bb030f | 1410 | } |
mzta | 0:158c61bb030f | 1411 | return self; |
mzta | 0:158c61bb030f | 1412 | } |
mzta | 0:158c61bb030f | 1413 | |
mzta | 0:158c61bb030f | 1414 | /* 15.2.10.5.25 */ |
mzta | 0:158c61bb030f | 1415 | /* 15.2.10.5.41 */ |
mzta | 0:158c61bb030f | 1416 | /* |
mzta | 0:158c61bb030f | 1417 | * call-seq: |
mzta | 0:158c61bb030f | 1418 | * str.intern => symbol |
mzta | 0:158c61bb030f | 1419 | * str.to_sym => symbol |
mzta | 0:158c61bb030f | 1420 | * |
mzta | 0:158c61bb030f | 1421 | * Returns the <code>Symbol</code> corresponding to <i>str</i>, creating the |
mzta | 0:158c61bb030f | 1422 | * symbol if it did not previously exist. See <code>Symbol#id2name</code>. |
mzta | 0:158c61bb030f | 1423 | * |
mzta | 0:158c61bb030f | 1424 | * "Koala".intern #=> :Koala |
mzta | 0:158c61bb030f | 1425 | * s = 'cat'.to_sym #=> :cat |
mzta | 0:158c61bb030f | 1426 | * s == :cat #=> true |
mzta | 0:158c61bb030f | 1427 | * s = '@cat'.to_sym #=> :@cat |
mzta | 0:158c61bb030f | 1428 | * s == :@cat #=> true |
mzta | 0:158c61bb030f | 1429 | * |
mzta | 0:158c61bb030f | 1430 | * This can also be used to create symbols that cannot be represented using the |
mzta | 0:158c61bb030f | 1431 | * <code>:xxx</code> notation. |
mzta | 0:158c61bb030f | 1432 | * |
mzta | 0:158c61bb030f | 1433 | * 'cat and dog'.to_sym #=> :"cat and dog" |
mzta | 0:158c61bb030f | 1434 | */ |
mzta | 0:158c61bb030f | 1435 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1436 | mrb_str_intern(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 1437 | { |
mzta | 0:158c61bb030f | 1438 | return mrb_symbol_value(mrb_intern_str(mrb, self)); |
mzta | 0:158c61bb030f | 1439 | } |
mzta | 0:158c61bb030f | 1440 | /* ---------------------------------- */ |
mzta | 0:158c61bb030f | 1441 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1442 | mrb_obj_as_string(mrb_state *mrb, mrb_value obj) |
mzta | 0:158c61bb030f | 1443 | { |
mzta | 0:158c61bb030f | 1444 | mrb_value str; |
mzta | 0:158c61bb030f | 1445 | |
mzta | 0:158c61bb030f | 1446 | if (mrb_string_p(obj)) { |
mzta | 0:158c61bb030f | 1447 | return obj; |
mzta | 0:158c61bb030f | 1448 | } |
mzta | 0:158c61bb030f | 1449 | str = mrb_funcall(mrb, obj, "to_s", 0); |
mzta | 0:158c61bb030f | 1450 | if (!mrb_string_p(str)) |
mzta | 0:158c61bb030f | 1451 | return mrb_any_to_s(mrb, obj); |
mzta | 0:158c61bb030f | 1452 | return str; |
mzta | 0:158c61bb030f | 1453 | } |
mzta | 0:158c61bb030f | 1454 | |
mzta | 0:158c61bb030f | 1455 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1456 | mrb_ptr_to_str(mrb_state *mrb, void *p) |
mzta | 0:158c61bb030f | 1457 | { |
mzta | 0:158c61bb030f | 1458 | struct RString *p_str; |
mzta | 0:158c61bb030f | 1459 | char *p1; |
mzta | 0:158c61bb030f | 1460 | char *p2; |
mzta | 0:158c61bb030f | 1461 | uintptr_t n = (uintptr_t)p; |
mzta | 0:158c61bb030f | 1462 | |
mzta | 0:158c61bb030f | 1463 | p_str = str_new(mrb, NULL, 2 + sizeof(uintptr_t) * CHAR_BIT / 4); |
mzta | 0:158c61bb030f | 1464 | p1 = RSTR_PTR(p_str); |
mzta | 0:158c61bb030f | 1465 | *p1++ = '0'; |
mzta | 0:158c61bb030f | 1466 | *p1++ = 'x'; |
mzta | 0:158c61bb030f | 1467 | p2 = p1; |
mzta | 0:158c61bb030f | 1468 | |
mzta | 0:158c61bb030f | 1469 | do { |
mzta | 0:158c61bb030f | 1470 | *p2++ = mrb_digitmap[n % 16]; |
mzta | 0:158c61bb030f | 1471 | n /= 16; |
mzta | 0:158c61bb030f | 1472 | } while (n > 0); |
mzta | 0:158c61bb030f | 1473 | *p2 = '\0'; |
mzta | 0:158c61bb030f | 1474 | RSTR_SET_LEN(p_str, (mrb_int)(p2 - RSTR_PTR(p_str))); |
mzta | 0:158c61bb030f | 1475 | |
mzta | 0:158c61bb030f | 1476 | while (p1 < p2) { |
mzta | 0:158c61bb030f | 1477 | const char c = *p1; |
mzta | 0:158c61bb030f | 1478 | *p1++ = *--p2; |
mzta | 0:158c61bb030f | 1479 | *p2 = c; |
mzta | 0:158c61bb030f | 1480 | } |
mzta | 0:158c61bb030f | 1481 | |
mzta | 0:158c61bb030f | 1482 | return mrb_obj_value(p_str); |
mzta | 0:158c61bb030f | 1483 | } |
mzta | 0:158c61bb030f | 1484 | |
mzta | 0:158c61bb030f | 1485 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1486 | mrb_string_type(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1487 | { |
mzta | 0:158c61bb030f | 1488 | return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); |
mzta | 0:158c61bb030f | 1489 | } |
mzta | 0:158c61bb030f | 1490 | |
mzta | 0:158c61bb030f | 1491 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1492 | mrb_check_string_type(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1493 | { |
mzta | 0:158c61bb030f | 1494 | return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); |
mzta | 0:158c61bb030f | 1495 | } |
mzta | 0:158c61bb030f | 1496 | |
mzta | 0:158c61bb030f | 1497 | /* ---------------------------------- */ |
mzta | 0:158c61bb030f | 1498 | /* 15.2.10.5.29 */ |
mzta | 0:158c61bb030f | 1499 | /* |
mzta | 0:158c61bb030f | 1500 | * call-seq: |
mzta | 0:158c61bb030f | 1501 | * str.reverse => new_str |
mzta | 0:158c61bb030f | 1502 | * |
mzta | 0:158c61bb030f | 1503 | * Returns a new string with the characters from <i>str</i> in reverse order. |
mzta | 0:158c61bb030f | 1504 | * |
mzta | 0:158c61bb030f | 1505 | * "stressed".reverse #=> "desserts" |
mzta | 0:158c61bb030f | 1506 | */ |
mzta | 0:158c61bb030f | 1507 | static mrb_value |
mzta | 0:158c61bb030f | 1508 | mrb_str_reverse(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1509 | { |
mzta | 0:158c61bb030f | 1510 | struct RString *s2; |
mzta | 0:158c61bb030f | 1511 | char *s, *e, *p; |
mzta | 0:158c61bb030f | 1512 | |
mzta | 0:158c61bb030f | 1513 | if (RSTRING_LEN(str) <= 1) return mrb_str_dup(mrb, str); |
mzta | 0:158c61bb030f | 1514 | |
mzta | 0:158c61bb030f | 1515 | s2 = str_new(mrb, 0, RSTRING_LEN(str)); |
mzta | 0:158c61bb030f | 1516 | str_with_class(mrb, s2, str); |
mzta | 0:158c61bb030f | 1517 | s = RSTRING_PTR(str); e = RSTRING_END(str) - 1; |
mzta | 0:158c61bb030f | 1518 | p = RSTR_PTR(s2); |
mzta | 0:158c61bb030f | 1519 | |
mzta | 0:158c61bb030f | 1520 | while (e >= s) { |
mzta | 0:158c61bb030f | 1521 | *p++ = *e--; |
mzta | 0:158c61bb030f | 1522 | } |
mzta | 0:158c61bb030f | 1523 | return mrb_obj_value(s2); |
mzta | 0:158c61bb030f | 1524 | } |
mzta | 0:158c61bb030f | 1525 | |
mzta | 0:158c61bb030f | 1526 | /* 15.2.10.5.30 */ |
mzta | 0:158c61bb030f | 1527 | /* |
mzta | 0:158c61bb030f | 1528 | * call-seq: |
mzta | 0:158c61bb030f | 1529 | * str.reverse! => str |
mzta | 0:158c61bb030f | 1530 | * |
mzta | 0:158c61bb030f | 1531 | * Reverses <i>str</i> in place. |
mzta | 0:158c61bb030f | 1532 | */ |
mzta | 0:158c61bb030f | 1533 | static mrb_value |
mzta | 0:158c61bb030f | 1534 | mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1535 | { |
mzta | 0:158c61bb030f | 1536 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1537 | char *p, *e; |
mzta | 0:158c61bb030f | 1538 | char c; |
mzta | 0:158c61bb030f | 1539 | |
mzta | 0:158c61bb030f | 1540 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 1541 | if (RSTR_LEN(s) > 1) { |
mzta | 0:158c61bb030f | 1542 | p = RSTR_PTR(s); |
mzta | 0:158c61bb030f | 1543 | e = p + RSTR_LEN(s) - 1; |
mzta | 0:158c61bb030f | 1544 | while (p < e) { |
mzta | 0:158c61bb030f | 1545 | c = *p; |
mzta | 0:158c61bb030f | 1546 | *p++ = *e; |
mzta | 0:158c61bb030f | 1547 | *e-- = c; |
mzta | 0:158c61bb030f | 1548 | } |
mzta | 0:158c61bb030f | 1549 | } |
mzta | 0:158c61bb030f | 1550 | return str; |
mzta | 0:158c61bb030f | 1551 | } |
mzta | 0:158c61bb030f | 1552 | |
mzta | 0:158c61bb030f | 1553 | /* |
mzta | 0:158c61bb030f | 1554 | * call-seq: |
mzta | 0:158c61bb030f | 1555 | * str.rindex(substring [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1556 | * str.rindex(fixnum [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1557 | * str.rindex(regexp [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1558 | * |
mzta | 0:158c61bb030f | 1559 | * Returns the index of the last occurrence of the given <i>substring</i>, |
mzta | 0:158c61bb030f | 1560 | * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns |
mzta | 0:158c61bb030f | 1561 | * <code>nil</code> if not found. If the second parameter is present, it |
mzta | 0:158c61bb030f | 1562 | * specifies the position in the string to end the search---characters beyond |
mzta | 0:158c61bb030f | 1563 | * this point will not be considered. |
mzta | 0:158c61bb030f | 1564 | * |
mzta | 0:158c61bb030f | 1565 | * "hello".rindex('e') #=> 1 |
mzta | 0:158c61bb030f | 1566 | * "hello".rindex('l') #=> 3 |
mzta | 0:158c61bb030f | 1567 | * "hello".rindex('a') #=> nil |
mzta | 0:158c61bb030f | 1568 | * "hello".rindex(101) #=> 1 |
mzta | 0:158c61bb030f | 1569 | * "hello".rindex(/[aeiou]/, -2) #=> 1 |
mzta | 0:158c61bb030f | 1570 | */ |
mzta | 0:158c61bb030f | 1571 | static mrb_int |
mzta | 0:158c61bb030f | 1572 | mrb_str_rindex(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) |
mzta | 0:158c61bb030f | 1573 | { |
mzta | 0:158c61bb030f | 1574 | char *s, *sbeg, *t; |
mzta | 0:158c61bb030f | 1575 | struct RString *ps = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 1576 | mrb_int len = RSTRING_LEN(sub); |
mzta | 0:158c61bb030f | 1577 | |
mzta | 0:158c61bb030f | 1578 | /* substring longer than string */ |
mzta | 0:158c61bb030f | 1579 | if (RSTR_LEN(ps) < len) return -1; |
mzta | 0:158c61bb030f | 1580 | if (RSTR_LEN(ps) - pos < len) { |
mzta | 0:158c61bb030f | 1581 | pos = RSTR_LEN(ps) - len; |
mzta | 0:158c61bb030f | 1582 | } |
mzta | 0:158c61bb030f | 1583 | sbeg = RSTR_PTR(ps); |
mzta | 0:158c61bb030f | 1584 | s = RSTR_PTR(ps) + pos; |
mzta | 0:158c61bb030f | 1585 | t = RSTRING_PTR(sub); |
mzta | 0:158c61bb030f | 1586 | if (len) { |
mzta | 0:158c61bb030f | 1587 | while (sbeg <= s) { |
mzta | 0:158c61bb030f | 1588 | if (memcmp(s, t, len) == 0) { |
mzta | 0:158c61bb030f | 1589 | return s - RSTR_PTR(ps); |
mzta | 0:158c61bb030f | 1590 | } |
mzta | 0:158c61bb030f | 1591 | s--; |
mzta | 0:158c61bb030f | 1592 | } |
mzta | 0:158c61bb030f | 1593 | return -1; |
mzta | 0:158c61bb030f | 1594 | } |
mzta | 0:158c61bb030f | 1595 | else { |
mzta | 0:158c61bb030f | 1596 | return pos; |
mzta | 0:158c61bb030f | 1597 | } |
mzta | 0:158c61bb030f | 1598 | } |
mzta | 0:158c61bb030f | 1599 | |
mzta | 0:158c61bb030f | 1600 | /* 15.2.10.5.31 */ |
mzta | 0:158c61bb030f | 1601 | /* |
mzta | 0:158c61bb030f | 1602 | * call-seq: |
mzta | 0:158c61bb030f | 1603 | * str.rindex(substring [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1604 | * str.rindex(fixnum [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1605 | * str.rindex(regexp [, fixnum]) => fixnum or nil |
mzta | 0:158c61bb030f | 1606 | * |
mzta | 0:158c61bb030f | 1607 | * Returns the index of the last occurrence of the given <i>substring</i>, |
mzta | 0:158c61bb030f | 1608 | * character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns |
mzta | 0:158c61bb030f | 1609 | * <code>nil</code> if not found. If the second parameter is present, it |
mzta | 0:158c61bb030f | 1610 | * specifies the position in the string to end the search---characters beyond |
mzta | 0:158c61bb030f | 1611 | * this point will not be considered. |
mzta | 0:158c61bb030f | 1612 | * |
mzta | 0:158c61bb030f | 1613 | * "hello".rindex('e') #=> 1 |
mzta | 0:158c61bb030f | 1614 | * "hello".rindex('l') #=> 3 |
mzta | 0:158c61bb030f | 1615 | * "hello".rindex('a') #=> nil |
mzta | 0:158c61bb030f | 1616 | * "hello".rindex(101) #=> 1 |
mzta | 0:158c61bb030f | 1617 | * "hello".rindex(/[aeiou]/, -2) #=> 1 |
mzta | 0:158c61bb030f | 1618 | */ |
mzta | 0:158c61bb030f | 1619 | static mrb_value |
mzta | 0:158c61bb030f | 1620 | mrb_str_rindex_m(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1621 | { |
mzta | 0:158c61bb030f | 1622 | mrb_value *argv; |
mzta | 0:158c61bb030f | 1623 | mrb_int argc; |
mzta | 0:158c61bb030f | 1624 | mrb_value sub; |
mzta | 0:158c61bb030f | 1625 | mrb_value vpos; |
mzta | 0:158c61bb030f | 1626 | mrb_int pos, len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 1627 | |
mzta | 0:158c61bb030f | 1628 | mrb_get_args(mrb, "*", &argv, &argc); |
mzta | 0:158c61bb030f | 1629 | if (argc == 2) { |
mzta | 0:158c61bb030f | 1630 | sub = argv[0]; |
mzta | 0:158c61bb030f | 1631 | vpos = argv[1]; |
mzta | 0:158c61bb030f | 1632 | pos = mrb_fixnum(vpos); |
mzta | 0:158c61bb030f | 1633 | if (pos < 0) { |
mzta | 0:158c61bb030f | 1634 | pos += len; |
mzta | 0:158c61bb030f | 1635 | if (pos < 0) { |
mzta | 0:158c61bb030f | 1636 | mrb_regexp_check(mrb, sub); |
mzta | 0:158c61bb030f | 1637 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1638 | } |
mzta | 0:158c61bb030f | 1639 | } |
mzta | 0:158c61bb030f | 1640 | if (pos > len) pos = len; |
mzta | 0:158c61bb030f | 1641 | } |
mzta | 0:158c61bb030f | 1642 | else { |
mzta | 0:158c61bb030f | 1643 | pos = len; |
mzta | 0:158c61bb030f | 1644 | if (argc > 0) |
mzta | 0:158c61bb030f | 1645 | sub = argv[0]; |
mzta | 0:158c61bb030f | 1646 | else |
mzta | 0:158c61bb030f | 1647 | sub = mrb_nil_value(); |
mzta | 0:158c61bb030f | 1648 | } |
mzta | 0:158c61bb030f | 1649 | mrb_regexp_check(mrb, sub); |
mzta | 0:158c61bb030f | 1650 | |
mzta | 0:158c61bb030f | 1651 | switch (mrb_type(sub)) { |
mzta | 0:158c61bb030f | 1652 | case MRB_TT_FIXNUM: { |
mzta | 0:158c61bb030f | 1653 | int c = mrb_fixnum(sub); |
mzta | 0:158c61bb030f | 1654 | unsigned char *p = (unsigned char*)RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 1655 | |
mzta | 0:158c61bb030f | 1656 | for (pos=len-1;pos>=0;pos--) { |
mzta | 0:158c61bb030f | 1657 | if (p[pos] == c) return mrb_fixnum_value(pos); |
mzta | 0:158c61bb030f | 1658 | } |
mzta | 0:158c61bb030f | 1659 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1660 | } |
mzta | 0:158c61bb030f | 1661 | |
mzta | 0:158c61bb030f | 1662 | default: { |
mzta | 0:158c61bb030f | 1663 | mrb_value tmp; |
mzta | 0:158c61bb030f | 1664 | |
mzta | 0:158c61bb030f | 1665 | tmp = mrb_check_string_type(mrb, sub); |
mzta | 0:158c61bb030f | 1666 | if (mrb_nil_p(tmp)) { |
mzta | 0:158c61bb030f | 1667 | mrb_raisef(mrb, E_TYPE_ERROR, "type mismatch: %S given", sub); |
mzta | 0:158c61bb030f | 1668 | } |
mzta | 0:158c61bb030f | 1669 | sub = tmp; |
mzta | 0:158c61bb030f | 1670 | } |
mzta | 0:158c61bb030f | 1671 | /* fall through */ |
mzta | 0:158c61bb030f | 1672 | case MRB_TT_STRING: |
mzta | 0:158c61bb030f | 1673 | pos = mrb_str_rindex(mrb, str, sub, pos); |
mzta | 0:158c61bb030f | 1674 | if (pos >= 0) return mrb_fixnum_value(pos); |
mzta | 0:158c61bb030f | 1675 | break; |
mzta | 0:158c61bb030f | 1676 | |
mzta | 0:158c61bb030f | 1677 | } /* end of switch (TYPE(sub)) */ |
mzta | 0:158c61bb030f | 1678 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1679 | } |
mzta | 0:158c61bb030f | 1680 | |
mzta | 0:158c61bb030f | 1681 | /* 15.2.10.5.35 */ |
mzta | 0:158c61bb030f | 1682 | |
mzta | 0:158c61bb030f | 1683 | /* |
mzta | 0:158c61bb030f | 1684 | * call-seq: |
mzta | 0:158c61bb030f | 1685 | * str.split(pattern=$;, [limit]) => anArray |
mzta | 0:158c61bb030f | 1686 | * |
mzta | 0:158c61bb030f | 1687 | * Divides <i>str</i> into substrings based on a delimiter, returning an array |
mzta | 0:158c61bb030f | 1688 | * of these substrings. |
mzta | 0:158c61bb030f | 1689 | * |
mzta | 0:158c61bb030f | 1690 | * If <i>pattern</i> is a <code>String</code>, then its contents are used as |
mzta | 0:158c61bb030f | 1691 | * the delimiter when splitting <i>str</i>. If <i>pattern</i> is a single |
mzta | 0:158c61bb030f | 1692 | * space, <i>str</i> is split on whitespace, with leading whitespace and runs |
mzta | 0:158c61bb030f | 1693 | * of contiguous whitespace characters ignored. |
mzta | 0:158c61bb030f | 1694 | * |
mzta | 0:158c61bb030f | 1695 | * If <i>pattern</i> is a <code>Regexp</code>, <i>str</i> is divided where the |
mzta | 0:158c61bb030f | 1696 | * pattern matches. Whenever the pattern matches a zero-length string, |
mzta | 0:158c61bb030f | 1697 | * <i>str</i> is split into individual characters. |
mzta | 0:158c61bb030f | 1698 | * |
mzta | 0:158c61bb030f | 1699 | * If <i>pattern</i> is omitted, the value of <code>$;</code> is used. If |
mzta | 0:158c61bb030f | 1700 | * <code>$;</code> is <code>nil</code> (which is the default), <i>str</i> is |
mzta | 0:158c61bb030f | 1701 | * split on whitespace as if ` ' were specified. |
mzta | 0:158c61bb030f | 1702 | * |
mzta | 0:158c61bb030f | 1703 | * If the <i>limit</i> parameter is omitted, trailing null fields are |
mzta | 0:158c61bb030f | 1704 | * suppressed. If <i>limit</i> is a positive number, at most that number of |
mzta | 0:158c61bb030f | 1705 | * fields will be returned (if <i>limit</i> is <code>1</code>, the entire |
mzta | 0:158c61bb030f | 1706 | * string is returned as the only entry in an array). If negative, there is no |
mzta | 0:158c61bb030f | 1707 | * limit to the number of fields returned, and trailing null fields are not |
mzta | 0:158c61bb030f | 1708 | * suppressed. |
mzta | 0:158c61bb030f | 1709 | * |
mzta | 0:158c61bb030f | 1710 | * " now's the time".split #=> ["now's", "the", "time"] |
mzta | 0:158c61bb030f | 1711 | * " now's the time".split(' ') #=> ["now's", "the", "time"] |
mzta | 0:158c61bb030f | 1712 | * " now's the time".split(/ /) #=> ["", "now's", "", "the", "time"] |
mzta | 0:158c61bb030f | 1713 | * "1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"] |
mzta | 0:158c61bb030f | 1714 | * "hello".split(//) #=> ["h", "e", "l", "l", "o"] |
mzta | 0:158c61bb030f | 1715 | * "hello".split(//, 3) #=> ["h", "e", "llo"] |
mzta | 0:158c61bb030f | 1716 | * "hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"] |
mzta | 0:158c61bb030f | 1717 | * |
mzta | 0:158c61bb030f | 1718 | * "mellow yellow".split("ello") #=> ["m", "w y", "w"] |
mzta | 0:158c61bb030f | 1719 | * "1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"] |
mzta | 0:158c61bb030f | 1720 | * "1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"] |
mzta | 0:158c61bb030f | 1721 | * "1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""] |
mzta | 0:158c61bb030f | 1722 | */ |
mzta | 0:158c61bb030f | 1723 | |
mzta | 0:158c61bb030f | 1724 | static mrb_value |
mzta | 0:158c61bb030f | 1725 | mrb_str_split_m(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 1726 | { |
mzta | 0:158c61bb030f | 1727 | int argc; |
mzta | 0:158c61bb030f | 1728 | mrb_value spat = mrb_nil_value(); |
mzta | 0:158c61bb030f | 1729 | enum {awk, string, regexp} split_type = string; |
mzta | 0:158c61bb030f | 1730 | long i = 0, lim_p; |
mzta | 0:158c61bb030f | 1731 | mrb_int beg; |
mzta | 0:158c61bb030f | 1732 | mrb_int end; |
mzta | 0:158c61bb030f | 1733 | mrb_int lim = 0; |
mzta | 0:158c61bb030f | 1734 | mrb_value result, tmp; |
mzta | 0:158c61bb030f | 1735 | |
mzta | 0:158c61bb030f | 1736 | argc = mrb_get_args(mrb, "|oi", &spat, &lim); |
mzta | 0:158c61bb030f | 1737 | lim_p = (lim > 0 && argc == 2); |
mzta | 0:158c61bb030f | 1738 | if (argc == 2) { |
mzta | 0:158c61bb030f | 1739 | if (lim == 1) { |
mzta | 0:158c61bb030f | 1740 | if (RSTRING_LEN(str) == 0) |
mzta | 0:158c61bb030f | 1741 | return mrb_ary_new_capa(mrb, 0); |
mzta | 0:158c61bb030f | 1742 | return mrb_ary_new_from_values(mrb, 1, &str); |
mzta | 0:158c61bb030f | 1743 | } |
mzta | 0:158c61bb030f | 1744 | i = 1; |
mzta | 0:158c61bb030f | 1745 | } |
mzta | 0:158c61bb030f | 1746 | |
mzta | 0:158c61bb030f | 1747 | if (argc == 0 || mrb_nil_p(spat)) { |
mzta | 0:158c61bb030f | 1748 | split_type = awk; |
mzta | 0:158c61bb030f | 1749 | } |
mzta | 0:158c61bb030f | 1750 | else { |
mzta | 0:158c61bb030f | 1751 | if (mrb_string_p(spat)) { |
mzta | 0:158c61bb030f | 1752 | split_type = string; |
mzta | 0:158c61bb030f | 1753 | if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { |
mzta | 0:158c61bb030f | 1754 | split_type = awk; |
mzta | 0:158c61bb030f | 1755 | } |
mzta | 0:158c61bb030f | 1756 | } |
mzta | 0:158c61bb030f | 1757 | else { |
mzta | 0:158c61bb030f | 1758 | mrb_noregexp(mrb, str); |
mzta | 0:158c61bb030f | 1759 | } |
mzta | 0:158c61bb030f | 1760 | } |
mzta | 0:158c61bb030f | 1761 | |
mzta | 0:158c61bb030f | 1762 | result = mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 1763 | beg = 0; |
mzta | 0:158c61bb030f | 1764 | if (split_type == awk) { |
mzta | 0:158c61bb030f | 1765 | char *ptr = RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 1766 | char *eptr = RSTRING_END(str); |
mzta | 0:158c61bb030f | 1767 | char *bptr = ptr; |
mzta | 0:158c61bb030f | 1768 | mrb_bool skip = TRUE; |
mzta | 0:158c61bb030f | 1769 | unsigned int c; |
mzta | 0:158c61bb030f | 1770 | |
mzta | 0:158c61bb030f | 1771 | end = beg; |
mzta | 0:158c61bb030f | 1772 | while (ptr < eptr) { |
mzta | 0:158c61bb030f | 1773 | int ai = mrb_gc_arena_save(mrb); |
mzta | 0:158c61bb030f | 1774 | c = (unsigned char)*ptr++; |
mzta | 0:158c61bb030f | 1775 | if (skip) { |
mzta | 0:158c61bb030f | 1776 | if (ISSPACE(c)) { |
mzta | 0:158c61bb030f | 1777 | beg = ptr - bptr; |
mzta | 0:158c61bb030f | 1778 | } |
mzta | 0:158c61bb030f | 1779 | else { |
mzta | 0:158c61bb030f | 1780 | end = ptr - bptr; |
mzta | 0:158c61bb030f | 1781 | skip = FALSE; |
mzta | 0:158c61bb030f | 1782 | if (lim_p && lim <= i) break; |
mzta | 0:158c61bb030f | 1783 | } |
mzta | 0:158c61bb030f | 1784 | } |
mzta | 0:158c61bb030f | 1785 | else if (ISSPACE(c)) { |
mzta | 0:158c61bb030f | 1786 | mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, beg, end-beg)); |
mzta | 0:158c61bb030f | 1787 | mrb_gc_arena_restore(mrb, ai); |
mzta | 0:158c61bb030f | 1788 | skip = TRUE; |
mzta | 0:158c61bb030f | 1789 | beg = ptr - bptr; |
mzta | 0:158c61bb030f | 1790 | if (lim_p) ++i; |
mzta | 0:158c61bb030f | 1791 | } |
mzta | 0:158c61bb030f | 1792 | else { |
mzta | 0:158c61bb030f | 1793 | end = ptr - bptr; |
mzta | 0:158c61bb030f | 1794 | } |
mzta | 0:158c61bb030f | 1795 | } |
mzta | 0:158c61bb030f | 1796 | } |
mzta | 0:158c61bb030f | 1797 | else if (split_type == string) { |
mzta | 0:158c61bb030f | 1798 | char *ptr = RSTRING_PTR(str); /* s->as.ary */ |
mzta | 0:158c61bb030f | 1799 | char *temp = ptr; |
mzta | 0:158c61bb030f | 1800 | char *eptr = RSTRING_END(str); |
mzta | 0:158c61bb030f | 1801 | mrb_int slen = RSTRING_LEN(spat); |
mzta | 0:158c61bb030f | 1802 | |
mzta | 0:158c61bb030f | 1803 | if (slen == 0) { |
mzta | 0:158c61bb030f | 1804 | int ai = mrb_gc_arena_save(mrb); |
mzta | 0:158c61bb030f | 1805 | while (ptr < eptr) { |
mzta | 0:158c61bb030f | 1806 | mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr-temp, 1)); |
mzta | 0:158c61bb030f | 1807 | mrb_gc_arena_restore(mrb, ai); |
mzta | 0:158c61bb030f | 1808 | ptr++; |
mzta | 0:158c61bb030f | 1809 | if (lim_p && lim <= ++i) break; |
mzta | 0:158c61bb030f | 1810 | } |
mzta | 0:158c61bb030f | 1811 | } |
mzta | 0:158c61bb030f | 1812 | else { |
mzta | 0:158c61bb030f | 1813 | char *sptr = RSTRING_PTR(spat); |
mzta | 0:158c61bb030f | 1814 | int ai = mrb_gc_arena_save(mrb); |
mzta | 0:158c61bb030f | 1815 | |
mzta | 0:158c61bb030f | 1816 | while (ptr < eptr && |
mzta | 0:158c61bb030f | 1817 | (end = mrb_memsearch(sptr, slen, ptr, eptr - ptr)) >= 0) { |
mzta | 0:158c61bb030f | 1818 | mrb_ary_push(mrb, result, mrb_str_subseq(mrb, str, ptr - temp, end)); |
mzta | 0:158c61bb030f | 1819 | mrb_gc_arena_restore(mrb, ai); |
mzta | 0:158c61bb030f | 1820 | ptr += end + slen; |
mzta | 0:158c61bb030f | 1821 | if (lim_p && lim <= ++i) break; |
mzta | 0:158c61bb030f | 1822 | } |
mzta | 0:158c61bb030f | 1823 | } |
mzta | 0:158c61bb030f | 1824 | beg = ptr - temp; |
mzta | 0:158c61bb030f | 1825 | } |
mzta | 0:158c61bb030f | 1826 | else { |
mzta | 0:158c61bb030f | 1827 | mrb_noregexp(mrb, str); |
mzta | 0:158c61bb030f | 1828 | } |
mzta | 0:158c61bb030f | 1829 | if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { |
mzta | 0:158c61bb030f | 1830 | if (RSTRING_LEN(str) == beg) { |
mzta | 0:158c61bb030f | 1831 | tmp = mrb_str_new_empty(mrb, str); |
mzta | 0:158c61bb030f | 1832 | } |
mzta | 0:158c61bb030f | 1833 | else { |
mzta | 0:158c61bb030f | 1834 | tmp = mrb_str_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); |
mzta | 0:158c61bb030f | 1835 | } |
mzta | 0:158c61bb030f | 1836 | mrb_ary_push(mrb, result, tmp); |
mzta | 0:158c61bb030f | 1837 | } |
mzta | 0:158c61bb030f | 1838 | if (!lim_p && lim == 0) { |
mzta | 0:158c61bb030f | 1839 | mrb_int len; |
mzta | 0:158c61bb030f | 1840 | while ((len = RARRAY_LEN(result)) > 0 && |
mzta | 0:158c61bb030f | 1841 | (tmp = RARRAY_PTR(result)[len-1], RSTRING_LEN(tmp) == 0)) |
mzta | 0:158c61bb030f | 1842 | mrb_ary_pop(mrb, result); |
mzta | 0:158c61bb030f | 1843 | } |
mzta | 0:158c61bb030f | 1844 | |
mzta | 0:158c61bb030f | 1845 | return result; |
mzta | 0:158c61bb030f | 1846 | } |
mzta | 0:158c61bb030f | 1847 | |
mzta | 0:158c61bb030f | 1848 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1849 | mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) |
mzta | 0:158c61bb030f | 1850 | { |
mzta | 0:158c61bb030f | 1851 | const char *p; |
mzta | 0:158c61bb030f | 1852 | char sign = 1; |
mzta | 0:158c61bb030f | 1853 | int c, uscore; |
mzta | 0:158c61bb030f | 1854 | unsigned long n = 0; |
mzta | 0:158c61bb030f | 1855 | mrb_int val; |
mzta | 0:158c61bb030f | 1856 | |
mzta | 0:158c61bb030f | 1857 | #define conv_digit(c) \ |
mzta | 0:158c61bb030f | 1858 | (ISDIGIT(c) ? ((c) - '0') : \ |
mzta | 0:158c61bb030f | 1859 | ISLOWER(c) ? ((c) - 'a' + 10) : \ |
mzta | 0:158c61bb030f | 1860 | ISUPPER(c) ? ((c) - 'A' + 10) : \ |
mzta | 0:158c61bb030f | 1861 | -1) |
mzta | 0:158c61bb030f | 1862 | |
mzta | 0:158c61bb030f | 1863 | if (!str) { |
mzta | 0:158c61bb030f | 1864 | if (badcheck) goto bad; |
mzta | 0:158c61bb030f | 1865 | return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 1866 | } |
mzta | 0:158c61bb030f | 1867 | while (ISSPACE(*str)) str++; |
mzta | 0:158c61bb030f | 1868 | |
mzta | 0:158c61bb030f | 1869 | if (str[0] == '+') { |
mzta | 0:158c61bb030f | 1870 | str++; |
mzta | 0:158c61bb030f | 1871 | } |
mzta | 0:158c61bb030f | 1872 | else if (str[0] == '-') { |
mzta | 0:158c61bb030f | 1873 | str++; |
mzta | 0:158c61bb030f | 1874 | sign = 0; |
mzta | 0:158c61bb030f | 1875 | } |
mzta | 0:158c61bb030f | 1876 | if (str[0] == '+' || str[0] == '-') { |
mzta | 0:158c61bb030f | 1877 | if (badcheck) goto bad; |
mzta | 0:158c61bb030f | 1878 | return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 1879 | } |
mzta | 0:158c61bb030f | 1880 | if (base <= 0) { |
mzta | 0:158c61bb030f | 1881 | if (str[0] == '0') { |
mzta | 0:158c61bb030f | 1882 | switch (str[1]) { |
mzta | 0:158c61bb030f | 1883 | case 'x': case 'X': |
mzta | 0:158c61bb030f | 1884 | base = 16; |
mzta | 0:158c61bb030f | 1885 | break; |
mzta | 0:158c61bb030f | 1886 | case 'b': case 'B': |
mzta | 0:158c61bb030f | 1887 | base = 2; |
mzta | 0:158c61bb030f | 1888 | break; |
mzta | 0:158c61bb030f | 1889 | case 'o': case 'O': |
mzta | 0:158c61bb030f | 1890 | base = 8; |
mzta | 0:158c61bb030f | 1891 | break; |
mzta | 0:158c61bb030f | 1892 | case 'd': case 'D': |
mzta | 0:158c61bb030f | 1893 | base = 10; |
mzta | 0:158c61bb030f | 1894 | break; |
mzta | 0:158c61bb030f | 1895 | default: |
mzta | 0:158c61bb030f | 1896 | base = 8; |
mzta | 0:158c61bb030f | 1897 | } |
mzta | 0:158c61bb030f | 1898 | } |
mzta | 0:158c61bb030f | 1899 | else if (base < -1) { |
mzta | 0:158c61bb030f | 1900 | base = -base; |
mzta | 0:158c61bb030f | 1901 | } |
mzta | 0:158c61bb030f | 1902 | else { |
mzta | 0:158c61bb030f | 1903 | base = 10; |
mzta | 0:158c61bb030f | 1904 | } |
mzta | 0:158c61bb030f | 1905 | } |
mzta | 0:158c61bb030f | 1906 | switch (base) { |
mzta | 0:158c61bb030f | 1907 | case 2: |
mzta | 0:158c61bb030f | 1908 | if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) { |
mzta | 0:158c61bb030f | 1909 | str += 2; |
mzta | 0:158c61bb030f | 1910 | } |
mzta | 0:158c61bb030f | 1911 | break; |
mzta | 0:158c61bb030f | 1912 | case 3: |
mzta | 0:158c61bb030f | 1913 | break; |
mzta | 0:158c61bb030f | 1914 | case 8: |
mzta | 0:158c61bb030f | 1915 | if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) { |
mzta | 0:158c61bb030f | 1916 | str += 2; |
mzta | 0:158c61bb030f | 1917 | } |
mzta | 0:158c61bb030f | 1918 | case 4: case 5: case 6: case 7: |
mzta | 0:158c61bb030f | 1919 | break; |
mzta | 0:158c61bb030f | 1920 | case 10: |
mzta | 0:158c61bb030f | 1921 | if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) { |
mzta | 0:158c61bb030f | 1922 | str += 2; |
mzta | 0:158c61bb030f | 1923 | } |
mzta | 0:158c61bb030f | 1924 | case 9: case 11: case 12: case 13: case 14: case 15: |
mzta | 0:158c61bb030f | 1925 | break; |
mzta | 0:158c61bb030f | 1926 | case 16: |
mzta | 0:158c61bb030f | 1927 | if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) { |
mzta | 0:158c61bb030f | 1928 | str += 2; |
mzta | 0:158c61bb030f | 1929 | } |
mzta | 0:158c61bb030f | 1930 | break; |
mzta | 0:158c61bb030f | 1931 | default: |
mzta | 0:158c61bb030f | 1932 | if (base < 2 || 36 < base) { |
mzta | 0:158c61bb030f | 1933 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); |
mzta | 0:158c61bb030f | 1934 | } |
mzta | 0:158c61bb030f | 1935 | break; |
mzta | 0:158c61bb030f | 1936 | } /* end of switch (base) { */ |
mzta | 0:158c61bb030f | 1937 | if (*str == '0') { /* squeeze preceeding 0s */ |
mzta | 0:158c61bb030f | 1938 | uscore = 0; |
mzta | 0:158c61bb030f | 1939 | while ((c = *++str) == '0' || c == '_') { |
mzta | 0:158c61bb030f | 1940 | if (c == '_') { |
mzta | 0:158c61bb030f | 1941 | if (++uscore >= 2) |
mzta | 0:158c61bb030f | 1942 | break; |
mzta | 0:158c61bb030f | 1943 | } |
mzta | 0:158c61bb030f | 1944 | else |
mzta | 0:158c61bb030f | 1945 | uscore = 0; |
mzta | 0:158c61bb030f | 1946 | } |
mzta | 0:158c61bb030f | 1947 | if (!(c = *str) || ISSPACE(c)) --str; |
mzta | 0:158c61bb030f | 1948 | } |
mzta | 0:158c61bb030f | 1949 | c = *str; |
mzta | 0:158c61bb030f | 1950 | c = conv_digit(c); |
mzta | 0:158c61bb030f | 1951 | if (c < 0 || c >= base) { |
mzta | 0:158c61bb030f | 1952 | if (badcheck) goto bad; |
mzta | 0:158c61bb030f | 1953 | return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 1954 | } |
mzta | 0:158c61bb030f | 1955 | |
mzta | 0:158c61bb030f | 1956 | uscore = 0; |
mzta | 0:158c61bb030f | 1957 | for (p=str;*p;p++) { |
mzta | 0:158c61bb030f | 1958 | if (*p == '_') { |
mzta | 0:158c61bb030f | 1959 | if (uscore == 0) { |
mzta | 0:158c61bb030f | 1960 | uscore++; |
mzta | 0:158c61bb030f | 1961 | continue; |
mzta | 0:158c61bb030f | 1962 | } |
mzta | 0:158c61bb030f | 1963 | if (badcheck) goto bad; |
mzta | 0:158c61bb030f | 1964 | break; |
mzta | 0:158c61bb030f | 1965 | } |
mzta | 0:158c61bb030f | 1966 | uscore = 0; |
mzta | 0:158c61bb030f | 1967 | c = conv_digit(*p); |
mzta | 0:158c61bb030f | 1968 | if (c < 0 || c >= base) { |
mzta | 0:158c61bb030f | 1969 | if (badcheck) goto bad; |
mzta | 0:158c61bb030f | 1970 | break; |
mzta | 0:158c61bb030f | 1971 | } |
mzta | 0:158c61bb030f | 1972 | n *= base; |
mzta | 0:158c61bb030f | 1973 | n += c; |
mzta | 0:158c61bb030f | 1974 | } |
mzta | 0:158c61bb030f | 1975 | if (n > MRB_INT_MAX) { |
mzta | 0:158c61bb030f | 1976 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", mrb_str_new_cstr(mrb, str)); |
mzta | 0:158c61bb030f | 1977 | } |
mzta | 0:158c61bb030f | 1978 | val = n; |
mzta | 0:158c61bb030f | 1979 | if (badcheck) { |
mzta | 0:158c61bb030f | 1980 | if (p == str) goto bad; /* no number */ |
mzta | 0:158c61bb030f | 1981 | while (*p && ISSPACE(*p)) p++; |
mzta | 0:158c61bb030f | 1982 | if (*p) goto bad; /* trailing garbage */ |
mzta | 0:158c61bb030f | 1983 | } |
mzta | 0:158c61bb030f | 1984 | |
mzta | 0:158c61bb030f | 1985 | return mrb_fixnum_value(sign ? val : -val); |
mzta | 0:158c61bb030f | 1986 | bad: |
mzta | 0:158c61bb030f | 1987 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for number(%S)", mrb_str_new_cstr(mrb, str)); |
mzta | 0:158c61bb030f | 1988 | /* not reached */ |
mzta | 0:158c61bb030f | 1989 | return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 1990 | } |
mzta | 0:158c61bb030f | 1991 | |
mzta | 0:158c61bb030f | 1992 | MRB_API const char* |
mzta | 0:158c61bb030f | 1993 | mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) |
mzta | 0:158c61bb030f | 1994 | { |
mzta | 0:158c61bb030f | 1995 | struct RString *ps = mrb_str_ptr(*ptr); |
mzta | 0:158c61bb030f | 1996 | mrb_int len = mrb_str_strlen(mrb, ps); |
mzta | 0:158c61bb030f | 1997 | char *p = RSTR_PTR(ps); |
mzta | 0:158c61bb030f | 1998 | |
mzta | 0:158c61bb030f | 1999 | if (!p || p[len] != '\0') { |
mzta | 0:158c61bb030f | 2000 | mrb_str_modify(mrb, ps); |
mzta | 0:158c61bb030f | 2001 | return RSTR_PTR(ps); |
mzta | 0:158c61bb030f | 2002 | } |
mzta | 0:158c61bb030f | 2003 | return p; |
mzta | 0:158c61bb030f | 2004 | } |
mzta | 0:158c61bb030f | 2005 | |
mzta | 0:158c61bb030f | 2006 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 2007 | mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck) |
mzta | 0:158c61bb030f | 2008 | { |
mzta | 0:158c61bb030f | 2009 | const char *s; |
mzta | 0:158c61bb030f | 2010 | mrb_int len; |
mzta | 0:158c61bb030f | 2011 | |
mzta | 0:158c61bb030f | 2012 | str = mrb_str_to_str(mrb, str); |
mzta | 0:158c61bb030f | 2013 | if (badcheck) { |
mzta | 0:158c61bb030f | 2014 | s = mrb_string_value_cstr(mrb, &str); |
mzta | 0:158c61bb030f | 2015 | } |
mzta | 0:158c61bb030f | 2016 | else { |
mzta | 0:158c61bb030f | 2017 | s = RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 2018 | } |
mzta | 0:158c61bb030f | 2019 | if (s) { |
mzta | 0:158c61bb030f | 2020 | len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 2021 | if (s[len]) { /* no sentinel somehow */ |
mzta | 0:158c61bb030f | 2022 | struct RString *temp_str = str_new(mrb, s, len); |
mzta | 0:158c61bb030f | 2023 | s = RSTR_PTR(temp_str); |
mzta | 0:158c61bb030f | 2024 | } |
mzta | 0:158c61bb030f | 2025 | } |
mzta | 0:158c61bb030f | 2026 | return mrb_cstr_to_inum(mrb, s, base, badcheck); |
mzta | 0:158c61bb030f | 2027 | } |
mzta | 0:158c61bb030f | 2028 | |
mzta | 0:158c61bb030f | 2029 | /* 15.2.10.5.38 */ |
mzta | 0:158c61bb030f | 2030 | /* |
mzta | 0:158c61bb030f | 2031 | * call-seq: |
mzta | 0:158c61bb030f | 2032 | * str.to_i(base=10) => integer |
mzta | 0:158c61bb030f | 2033 | * |
mzta | 0:158c61bb030f | 2034 | * Returns the result of interpreting leading characters in <i>str</i> as an |
mzta | 0:158c61bb030f | 2035 | * integer base <i>base</i> (between 2 and 36). Extraneous characters past the |
mzta | 0:158c61bb030f | 2036 | * end of a valid number are ignored. If there is not a valid number at the |
mzta | 0:158c61bb030f | 2037 | * start of <i>str</i>, <code>0</code> is returned. This method never raises an |
mzta | 0:158c61bb030f | 2038 | * exception. |
mzta | 0:158c61bb030f | 2039 | * |
mzta | 0:158c61bb030f | 2040 | * "12345".to_i #=> 12345 |
mzta | 0:158c61bb030f | 2041 | * "99 red balloons".to_i #=> 99 |
mzta | 0:158c61bb030f | 2042 | * "0a".to_i #=> 0 |
mzta | 0:158c61bb030f | 2043 | * "0a".to_i(16) #=> 10 |
mzta | 0:158c61bb030f | 2044 | * "hello".to_i #=> 0 |
mzta | 0:158c61bb030f | 2045 | * "1100101".to_i(2) #=> 101 |
mzta | 0:158c61bb030f | 2046 | * "1100101".to_i(8) #=> 294977 |
mzta | 0:158c61bb030f | 2047 | * "1100101".to_i(10) #=> 1100101 |
mzta | 0:158c61bb030f | 2048 | * "1100101".to_i(16) #=> 17826049 |
mzta | 0:158c61bb030f | 2049 | */ |
mzta | 0:158c61bb030f | 2050 | static mrb_value |
mzta | 0:158c61bb030f | 2051 | mrb_str_to_i(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 2052 | { |
mzta | 0:158c61bb030f | 2053 | mrb_int base = 10; |
mzta | 0:158c61bb030f | 2054 | |
mzta | 0:158c61bb030f | 2055 | mrb_get_args(mrb, "|i", &base); |
mzta | 0:158c61bb030f | 2056 | if (base < 0) { |
mzta | 0:158c61bb030f | 2057 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal radix %S", mrb_fixnum_value(base)); |
mzta | 0:158c61bb030f | 2058 | } |
mzta | 0:158c61bb030f | 2059 | return mrb_str_to_inum(mrb, self, base, FALSE); |
mzta | 0:158c61bb030f | 2060 | } |
mzta | 0:158c61bb030f | 2061 | |
mzta | 0:158c61bb030f | 2062 | MRB_API double |
mzta | 0:158c61bb030f | 2063 | mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) |
mzta | 0:158c61bb030f | 2064 | { |
mzta | 0:158c61bb030f | 2065 | char *end; |
mzta | 0:158c61bb030f | 2066 | double d; |
mzta | 0:158c61bb030f | 2067 | |
mzta | 0:158c61bb030f | 2068 | enum {max_width = 20}; |
mzta | 0:158c61bb030f | 2069 | |
mzta | 0:158c61bb030f | 2070 | if (!p) return 0.0; |
mzta | 0:158c61bb030f | 2071 | while (ISSPACE(*p)) p++; |
mzta | 0:158c61bb030f | 2072 | |
mzta | 0:158c61bb030f | 2073 | if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { |
mzta | 0:158c61bb030f | 2074 | return 0.0; |
mzta | 0:158c61bb030f | 2075 | } |
mzta | 0:158c61bb030f | 2076 | d = strtod(p, &end); |
mzta | 0:158c61bb030f | 2077 | if (p == end) { |
mzta | 0:158c61bb030f | 2078 | if (badcheck) { |
mzta | 0:158c61bb030f | 2079 | bad: |
mzta | 0:158c61bb030f | 2080 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid string for float(%S)", mrb_str_new_cstr(mrb, p)); |
mzta | 0:158c61bb030f | 2081 | /* not reached */ |
mzta | 0:158c61bb030f | 2082 | } |
mzta | 0:158c61bb030f | 2083 | return d; |
mzta | 0:158c61bb030f | 2084 | } |
mzta | 0:158c61bb030f | 2085 | if (*end) { |
mzta | 0:158c61bb030f | 2086 | char buf[DBL_DIG * 4 + 10]; |
mzta | 0:158c61bb030f | 2087 | char *n = buf; |
mzta | 0:158c61bb030f | 2088 | char *e = buf + sizeof(buf) - 1; |
mzta | 0:158c61bb030f | 2089 | char prev = 0; |
mzta | 0:158c61bb030f | 2090 | |
mzta | 0:158c61bb030f | 2091 | while (p < end && n < e) prev = *n++ = *p++; |
mzta | 0:158c61bb030f | 2092 | while (*p) { |
mzta | 0:158c61bb030f | 2093 | if (*p == '_') { |
mzta | 0:158c61bb030f | 2094 | /* remove underscores between digits */ |
mzta | 0:158c61bb030f | 2095 | if (badcheck) { |
mzta | 0:158c61bb030f | 2096 | if (n == buf || !ISDIGIT(prev)) goto bad; |
mzta | 0:158c61bb030f | 2097 | ++p; |
mzta | 0:158c61bb030f | 2098 | if (!ISDIGIT(*p)) goto bad; |
mzta | 0:158c61bb030f | 2099 | } |
mzta | 0:158c61bb030f | 2100 | else { |
mzta | 0:158c61bb030f | 2101 | while (*++p == '_'); |
mzta | 0:158c61bb030f | 2102 | continue; |
mzta | 0:158c61bb030f | 2103 | } |
mzta | 0:158c61bb030f | 2104 | } |
mzta | 0:158c61bb030f | 2105 | prev = *p++; |
mzta | 0:158c61bb030f | 2106 | if (n < e) *n++ = prev; |
mzta | 0:158c61bb030f | 2107 | } |
mzta | 0:158c61bb030f | 2108 | *n = '\0'; |
mzta | 0:158c61bb030f | 2109 | p = buf; |
mzta | 0:158c61bb030f | 2110 | |
mzta | 0:158c61bb030f | 2111 | if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { |
mzta | 0:158c61bb030f | 2112 | return 0.0; |
mzta | 0:158c61bb030f | 2113 | } |
mzta | 0:158c61bb030f | 2114 | |
mzta | 0:158c61bb030f | 2115 | d = strtod(p, &end); |
mzta | 0:158c61bb030f | 2116 | if (badcheck) { |
mzta | 0:158c61bb030f | 2117 | if (!end || p == end) goto bad; |
mzta | 0:158c61bb030f | 2118 | while (*end && ISSPACE(*end)) end++; |
mzta | 0:158c61bb030f | 2119 | if (*end) goto bad; |
mzta | 0:158c61bb030f | 2120 | } |
mzta | 0:158c61bb030f | 2121 | } |
mzta | 0:158c61bb030f | 2122 | return d; |
mzta | 0:158c61bb030f | 2123 | } |
mzta | 0:158c61bb030f | 2124 | |
mzta | 0:158c61bb030f | 2125 | MRB_API double |
mzta | 0:158c61bb030f | 2126 | mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) |
mzta | 0:158c61bb030f | 2127 | { |
mzta | 0:158c61bb030f | 2128 | char *s; |
mzta | 0:158c61bb030f | 2129 | mrb_int len; |
mzta | 0:158c61bb030f | 2130 | |
mzta | 0:158c61bb030f | 2131 | str = mrb_str_to_str(mrb, str); |
mzta | 0:158c61bb030f | 2132 | s = RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 2133 | len = RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 2134 | if (s) { |
mzta | 0:158c61bb030f | 2135 | if (badcheck && memchr(s, '\0', len)) { |
mzta | 0:158c61bb030f | 2136 | mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); |
mzta | 0:158c61bb030f | 2137 | } |
mzta | 0:158c61bb030f | 2138 | if (s[len]) { /* no sentinel somehow */ |
mzta | 0:158c61bb030f | 2139 | struct RString *temp_str = str_new(mrb, s, len); |
mzta | 0:158c61bb030f | 2140 | s = RSTR_PTR(temp_str); |
mzta | 0:158c61bb030f | 2141 | } |
mzta | 0:158c61bb030f | 2142 | } |
mzta | 0:158c61bb030f | 2143 | return mrb_cstr_to_dbl(mrb, s, badcheck); |
mzta | 0:158c61bb030f | 2144 | } |
mzta | 0:158c61bb030f | 2145 | |
mzta | 0:158c61bb030f | 2146 | /* 15.2.10.5.39 */ |
mzta | 0:158c61bb030f | 2147 | /* |
mzta | 0:158c61bb030f | 2148 | * call-seq: |
mzta | 0:158c61bb030f | 2149 | * str.to_f => float |
mzta | 0:158c61bb030f | 2150 | * |
mzta | 0:158c61bb030f | 2151 | * Returns the result of interpreting leading characters in <i>str</i> as a |
mzta | 0:158c61bb030f | 2152 | * floating point number. Extraneous characters past the end of a valid number |
mzta | 0:158c61bb030f | 2153 | * are ignored. If there is not a valid number at the start of <i>str</i>, |
mzta | 0:158c61bb030f | 2154 | * <code>0.0</code> is returned. This method never raises an exception. |
mzta | 0:158c61bb030f | 2155 | * |
mzta | 0:158c61bb030f | 2156 | * "123.45e1".to_f #=> 1234.5 |
mzta | 0:158c61bb030f | 2157 | * "45.67 degrees".to_f #=> 45.67 |
mzta | 0:158c61bb030f | 2158 | * "thx1138".to_f #=> 0.0 |
mzta | 0:158c61bb030f | 2159 | */ |
mzta | 0:158c61bb030f | 2160 | static mrb_value |
mzta | 0:158c61bb030f | 2161 | mrb_str_to_f(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 2162 | { |
mzta | 0:158c61bb030f | 2163 | return mrb_float_value(mrb, mrb_str_to_dbl(mrb, self, FALSE)); |
mzta | 0:158c61bb030f | 2164 | } |
mzta | 0:158c61bb030f | 2165 | |
mzta | 0:158c61bb030f | 2166 | /* 15.2.10.5.40 */ |
mzta | 0:158c61bb030f | 2167 | /* |
mzta | 0:158c61bb030f | 2168 | * call-seq: |
mzta | 0:158c61bb030f | 2169 | * str.to_s => str |
mzta | 0:158c61bb030f | 2170 | * str.to_str => str |
mzta | 0:158c61bb030f | 2171 | * |
mzta | 0:158c61bb030f | 2172 | * Returns the receiver. |
mzta | 0:158c61bb030f | 2173 | */ |
mzta | 0:158c61bb030f | 2174 | static mrb_value |
mzta | 0:158c61bb030f | 2175 | mrb_str_to_s(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 2176 | { |
mzta | 0:158c61bb030f | 2177 | if (mrb_obj_class(mrb, self) != mrb->string_class) { |
mzta | 0:158c61bb030f | 2178 | return mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 2179 | } |
mzta | 0:158c61bb030f | 2180 | return self; |
mzta | 0:158c61bb030f | 2181 | } |
mzta | 0:158c61bb030f | 2182 | |
mzta | 0:158c61bb030f | 2183 | /* 15.2.10.5.43 */ |
mzta | 0:158c61bb030f | 2184 | /* |
mzta | 0:158c61bb030f | 2185 | * call-seq: |
mzta | 0:158c61bb030f | 2186 | * str.upcase! => str or nil |
mzta | 0:158c61bb030f | 2187 | * |
mzta | 0:158c61bb030f | 2188 | * Upcases the contents of <i>str</i>, returning <code>nil</code> if no changes |
mzta | 0:158c61bb030f | 2189 | * were made. |
mzta | 0:158c61bb030f | 2190 | */ |
mzta | 0:158c61bb030f | 2191 | static mrb_value |
mzta | 0:158c61bb030f | 2192 | mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 2193 | { |
mzta | 0:158c61bb030f | 2194 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 2195 | char *p, *pend; |
mzta | 0:158c61bb030f | 2196 | mrb_bool modify = FALSE; |
mzta | 0:158c61bb030f | 2197 | |
mzta | 0:158c61bb030f | 2198 | mrb_str_modify(mrb, s); |
mzta | 0:158c61bb030f | 2199 | p = RSTRING_PTR(str); |
mzta | 0:158c61bb030f | 2200 | pend = RSTRING_END(str); |
mzta | 0:158c61bb030f | 2201 | while (p < pend) { |
mzta | 0:158c61bb030f | 2202 | if (ISLOWER(*p)) { |
mzta | 0:158c61bb030f | 2203 | *p = TOUPPER(*p); |
mzta | 0:158c61bb030f | 2204 | modify = TRUE; |
mzta | 0:158c61bb030f | 2205 | } |
mzta | 0:158c61bb030f | 2206 | p++; |
mzta | 0:158c61bb030f | 2207 | } |
mzta | 0:158c61bb030f | 2208 | |
mzta | 0:158c61bb030f | 2209 | if (modify) return str; |
mzta | 0:158c61bb030f | 2210 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 2211 | } |
mzta | 0:158c61bb030f | 2212 | |
mzta | 0:158c61bb030f | 2213 | /* 15.2.10.5.42 */ |
mzta | 0:158c61bb030f | 2214 | /* |
mzta | 0:158c61bb030f | 2215 | * call-seq: |
mzta | 0:158c61bb030f | 2216 | * str.upcase => new_str |
mzta | 0:158c61bb030f | 2217 | * |
mzta | 0:158c61bb030f | 2218 | * Returns a copy of <i>str</i> with all lowercase letters replaced with their |
mzta | 0:158c61bb030f | 2219 | * uppercase counterparts. The operation is locale insensitive---only |
mzta | 0:158c61bb030f | 2220 | * characters ``a'' to ``z'' are affected. |
mzta | 0:158c61bb030f | 2221 | * |
mzta | 0:158c61bb030f | 2222 | * "hEllO".upcase #=> "HELLO" |
mzta | 0:158c61bb030f | 2223 | */ |
mzta | 0:158c61bb030f | 2224 | static mrb_value |
mzta | 0:158c61bb030f | 2225 | mrb_str_upcase(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 2226 | { |
mzta | 0:158c61bb030f | 2227 | mrb_value str; |
mzta | 0:158c61bb030f | 2228 | |
mzta | 0:158c61bb030f | 2229 | str = mrb_str_dup(mrb, self); |
mzta | 0:158c61bb030f | 2230 | mrb_str_upcase_bang(mrb, str); |
mzta | 0:158c61bb030f | 2231 | return str; |
mzta | 0:158c61bb030f | 2232 | } |
mzta | 0:158c61bb030f | 2233 | |
mzta | 0:158c61bb030f | 2234 | #define IS_EVSTR(p,e) ((p) < (e) && (*(p) == '$' || *(p) == '@' || *(p) == '{')) |
mzta | 0:158c61bb030f | 2235 | |
mzta | 0:158c61bb030f | 2236 | /* |
mzta | 0:158c61bb030f | 2237 | * call-seq: |
mzta | 0:158c61bb030f | 2238 | * str.dump -> new_str |
mzta | 0:158c61bb030f | 2239 | * |
mzta | 0:158c61bb030f | 2240 | * Produces a version of <i>str</i> with all nonprinting characters replaced by |
mzta | 0:158c61bb030f | 2241 | * <code>\nnn</code> notation and all special characters escaped. |
mzta | 0:158c61bb030f | 2242 | */ |
mzta | 0:158c61bb030f | 2243 | mrb_value |
mzta | 0:158c61bb030f | 2244 | mrb_str_dump(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 2245 | { |
mzta | 0:158c61bb030f | 2246 | mrb_int len; |
mzta | 0:158c61bb030f | 2247 | const char *p, *pend; |
mzta | 0:158c61bb030f | 2248 | char *q; |
mzta | 0:158c61bb030f | 2249 | struct RString *result; |
mzta | 0:158c61bb030f | 2250 | |
mzta | 0:158c61bb030f | 2251 | len = 2; /* "" */ |
mzta | 0:158c61bb030f | 2252 | p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 2253 | while (p < pend) { |
mzta | 0:158c61bb030f | 2254 | unsigned char c = *p++; |
mzta | 0:158c61bb030f | 2255 | switch (c) { |
mzta | 0:158c61bb030f | 2256 | case '"': case '\\': |
mzta | 0:158c61bb030f | 2257 | case '\n': case '\r': |
mzta | 0:158c61bb030f | 2258 | case '\t': case '\f': |
mzta | 0:158c61bb030f | 2259 | case '\013': case '\010': case '\007': case '\033': |
mzta | 0:158c61bb030f | 2260 | len += 2; |
mzta | 0:158c61bb030f | 2261 | break; |
mzta | 0:158c61bb030f | 2262 | |
mzta | 0:158c61bb030f | 2263 | case '#': |
mzta | 0:158c61bb030f | 2264 | len += IS_EVSTR(p, pend) ? 2 : 1; |
mzta | 0:158c61bb030f | 2265 | break; |
mzta | 0:158c61bb030f | 2266 | |
mzta | 0:158c61bb030f | 2267 | default: |
mzta | 0:158c61bb030f | 2268 | if (ISPRINT(c)) { |
mzta | 0:158c61bb030f | 2269 | len++; |
mzta | 0:158c61bb030f | 2270 | } |
mzta | 0:158c61bb030f | 2271 | else { |
mzta | 0:158c61bb030f | 2272 | len += 4; /* \NNN */ |
mzta | 0:158c61bb030f | 2273 | } |
mzta | 0:158c61bb030f | 2274 | break; |
mzta | 0:158c61bb030f | 2275 | } |
mzta | 0:158c61bb030f | 2276 | } |
mzta | 0:158c61bb030f | 2277 | |
mzta | 0:158c61bb030f | 2278 | result = str_new(mrb, 0, len); |
mzta | 0:158c61bb030f | 2279 | str_with_class(mrb, result, str); |
mzta | 0:158c61bb030f | 2280 | p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); |
mzta | 0:158c61bb030f | 2281 | q = RSTR_PTR(result); |
mzta | 0:158c61bb030f | 2282 | *q++ = '"'; |
mzta | 0:158c61bb030f | 2283 | while (p < pend) { |
mzta | 0:158c61bb030f | 2284 | unsigned char c = *p++; |
mzta | 0:158c61bb030f | 2285 | |
mzta | 0:158c61bb030f | 2286 | switch (c) { |
mzta | 0:158c61bb030f | 2287 | case '"': |
mzta | 0:158c61bb030f | 2288 | case '\\': |
mzta | 0:158c61bb030f | 2289 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2290 | *q++ = c; |
mzta | 0:158c61bb030f | 2291 | break; |
mzta | 0:158c61bb030f | 2292 | |
mzta | 0:158c61bb030f | 2293 | case '\n': |
mzta | 0:158c61bb030f | 2294 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2295 | *q++ = 'n'; |
mzta | 0:158c61bb030f | 2296 | break; |
mzta | 0:158c61bb030f | 2297 | |
mzta | 0:158c61bb030f | 2298 | case '\r': |
mzta | 0:158c61bb030f | 2299 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2300 | *q++ = 'r'; |
mzta | 0:158c61bb030f | 2301 | break; |
mzta | 0:158c61bb030f | 2302 | |
mzta | 0:158c61bb030f | 2303 | case '\t': |
mzta | 0:158c61bb030f | 2304 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2305 | *q++ = 't'; |
mzta | 0:158c61bb030f | 2306 | break; |
mzta | 0:158c61bb030f | 2307 | |
mzta | 0:158c61bb030f | 2308 | case '\f': |
mzta | 0:158c61bb030f | 2309 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2310 | *q++ = 'f'; |
mzta | 0:158c61bb030f | 2311 | break; |
mzta | 0:158c61bb030f | 2312 | |
mzta | 0:158c61bb030f | 2313 | case '\013': |
mzta | 0:158c61bb030f | 2314 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2315 | *q++ = 'v'; |
mzta | 0:158c61bb030f | 2316 | break; |
mzta | 0:158c61bb030f | 2317 | |
mzta | 0:158c61bb030f | 2318 | case '\010': |
mzta | 0:158c61bb030f | 2319 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2320 | *q++ = 'b'; |
mzta | 0:158c61bb030f | 2321 | break; |
mzta | 0:158c61bb030f | 2322 | |
mzta | 0:158c61bb030f | 2323 | case '\007': |
mzta | 0:158c61bb030f | 2324 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2325 | *q++ = 'a'; |
mzta | 0:158c61bb030f | 2326 | break; |
mzta | 0:158c61bb030f | 2327 | |
mzta | 0:158c61bb030f | 2328 | case '\033': |
mzta | 0:158c61bb030f | 2329 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2330 | *q++ = 'e'; |
mzta | 0:158c61bb030f | 2331 | break; |
mzta | 0:158c61bb030f | 2332 | |
mzta | 0:158c61bb030f | 2333 | case '#': |
mzta | 0:158c61bb030f | 2334 | if (IS_EVSTR(p, pend)) *q++ = '\\'; |
mzta | 0:158c61bb030f | 2335 | *q++ = '#'; |
mzta | 0:158c61bb030f | 2336 | break; |
mzta | 0:158c61bb030f | 2337 | |
mzta | 0:158c61bb030f | 2338 | default: |
mzta | 0:158c61bb030f | 2339 | if (ISPRINT(c)) { |
mzta | 0:158c61bb030f | 2340 | *q++ = c; |
mzta | 0:158c61bb030f | 2341 | } |
mzta | 0:158c61bb030f | 2342 | else { |
mzta | 0:158c61bb030f | 2343 | *q++ = '\\'; |
mzta | 0:158c61bb030f | 2344 | q[2] = '0' + c % 8; c /= 8; |
mzta | 0:158c61bb030f | 2345 | q[1] = '0' + c % 8; c /= 8; |
mzta | 0:158c61bb030f | 2346 | q[0] = '0' + c % 8; |
mzta | 0:158c61bb030f | 2347 | q += 3; |
mzta | 0:158c61bb030f | 2348 | } |
mzta | 0:158c61bb030f | 2349 | } |
mzta | 0:158c61bb030f | 2350 | } |
mzta | 0:158c61bb030f | 2351 | *q = '"'; |
mzta | 0:158c61bb030f | 2352 | return mrb_obj_value(result); |
mzta | 0:158c61bb030f | 2353 | } |
mzta | 0:158c61bb030f | 2354 | |
mzta | 0:158c61bb030f | 2355 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 2356 | mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len) |
mzta | 0:158c61bb030f | 2357 | { |
mzta | 0:158c61bb030f | 2358 | str_buf_cat(mrb, mrb_str_ptr(str), ptr, len); |
mzta | 0:158c61bb030f | 2359 | return str; |
mzta | 0:158c61bb030f | 2360 | } |
mzta | 0:158c61bb030f | 2361 | |
mzta | 0:158c61bb030f | 2362 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 2363 | mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr) |
mzta | 0:158c61bb030f | 2364 | { |
mzta | 0:158c61bb030f | 2365 | return mrb_str_cat(mrb, str, ptr, strlen(ptr)); |
mzta | 0:158c61bb030f | 2366 | } |
mzta | 0:158c61bb030f | 2367 | |
mzta | 0:158c61bb030f | 2368 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 2369 | mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) |
mzta | 0:158c61bb030f | 2370 | { |
mzta | 0:158c61bb030f | 2371 | return mrb_str_cat(mrb, str, RSTRING_PTR(str2), RSTRING_LEN(str2)); |
mzta | 0:158c61bb030f | 2372 | } |
mzta | 0:158c61bb030f | 2373 | |
mzta | 0:158c61bb030f | 2374 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 2375 | mrb_str_append(mrb_state *mrb, mrb_value str, mrb_value str2) |
mzta | 0:158c61bb030f | 2376 | { |
mzta | 0:158c61bb030f | 2377 | str2 = mrb_str_to_str(mrb, str2); |
mzta | 0:158c61bb030f | 2378 | return mrb_str_cat_str(mrb, str, str2); |
mzta | 0:158c61bb030f | 2379 | } |
mzta | 0:158c61bb030f | 2380 | |
mzta | 0:158c61bb030f | 2381 | #define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ |
mzta | 0:158c61bb030f | 2382 | |
mzta | 0:158c61bb030f | 2383 | /* |
mzta | 0:158c61bb030f | 2384 | * call-seq: |
mzta | 0:158c61bb030f | 2385 | * str.inspect -> string |
mzta | 0:158c61bb030f | 2386 | * |
mzta | 0:158c61bb030f | 2387 | * Returns a printable version of _str_, surrounded by quote marks, |
mzta | 0:158c61bb030f | 2388 | * with special characters escaped. |
mzta | 0:158c61bb030f | 2389 | * |
mzta | 0:158c61bb030f | 2390 | * str = "hello" |
mzta | 0:158c61bb030f | 2391 | * str[3] = "\b" |
mzta | 0:158c61bb030f | 2392 | * str.inspect #=> "\"hel\\bo\"" |
mzta | 0:158c61bb030f | 2393 | */ |
mzta | 0:158c61bb030f | 2394 | mrb_value |
mzta | 0:158c61bb030f | 2395 | mrb_str_inspect(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 2396 | { |
mzta | 0:158c61bb030f | 2397 | const char *p, *pend; |
mzta | 0:158c61bb030f | 2398 | char buf[CHAR_ESC_LEN + 1]; |
mzta | 0:158c61bb030f | 2399 | mrb_value result = mrb_str_new_lit(mrb, "\""); |
mzta | 0:158c61bb030f | 2400 | |
mzta | 0:158c61bb030f | 2401 | p = RSTRING_PTR(str); pend = RSTRING_END(str); |
mzta | 0:158c61bb030f | 2402 | for (;p < pend; p++) { |
mzta | 0:158c61bb030f | 2403 | unsigned char c, cc; |
mzta | 0:158c61bb030f | 2404 | |
mzta | 0:158c61bb030f | 2405 | c = *p; |
mzta | 0:158c61bb030f | 2406 | if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) { |
mzta | 0:158c61bb030f | 2407 | buf[0] = '\\'; buf[1] = c; |
mzta | 0:158c61bb030f | 2408 | mrb_str_cat(mrb, result, buf, 2); |
mzta | 0:158c61bb030f | 2409 | continue; |
mzta | 0:158c61bb030f | 2410 | } |
mzta | 0:158c61bb030f | 2411 | if (ISPRINT(c)) { |
mzta | 0:158c61bb030f | 2412 | buf[0] = c; |
mzta | 0:158c61bb030f | 2413 | mrb_str_cat(mrb, result, buf, 1); |
mzta | 0:158c61bb030f | 2414 | continue; |
mzta | 0:158c61bb030f | 2415 | } |
mzta | 0:158c61bb030f | 2416 | switch (c) { |
mzta | 0:158c61bb030f | 2417 | case '\n': cc = 'n'; break; |
mzta | 0:158c61bb030f | 2418 | case '\r': cc = 'r'; break; |
mzta | 0:158c61bb030f | 2419 | case '\t': cc = 't'; break; |
mzta | 0:158c61bb030f | 2420 | case '\f': cc = 'f'; break; |
mzta | 0:158c61bb030f | 2421 | case '\013': cc = 'v'; break; |
mzta | 0:158c61bb030f | 2422 | case '\010': cc = 'b'; break; |
mzta | 0:158c61bb030f | 2423 | case '\007': cc = 'a'; break; |
mzta | 0:158c61bb030f | 2424 | case 033: cc = 'e'; break; |
mzta | 0:158c61bb030f | 2425 | default: cc = 0; break; |
mzta | 0:158c61bb030f | 2426 | } |
mzta | 0:158c61bb030f | 2427 | if (cc) { |
mzta | 0:158c61bb030f | 2428 | buf[0] = '\\'; |
mzta | 0:158c61bb030f | 2429 | buf[1] = (char)cc; |
mzta | 0:158c61bb030f | 2430 | mrb_str_cat(mrb, result, buf, 2); |
mzta | 0:158c61bb030f | 2431 | continue; |
mzta | 0:158c61bb030f | 2432 | } |
mzta | 0:158c61bb030f | 2433 | else { |
mzta | 0:158c61bb030f | 2434 | buf[0] = '\\'; |
mzta | 0:158c61bb030f | 2435 | buf[3] = '0' + c % 8; c /= 8; |
mzta | 0:158c61bb030f | 2436 | buf[2] = '0' + c % 8; c /= 8; |
mzta | 0:158c61bb030f | 2437 | buf[1] = '0' + c % 8; |
mzta | 0:158c61bb030f | 2438 | mrb_str_cat(mrb, result, buf, 4); |
mzta | 0:158c61bb030f | 2439 | continue; |
mzta | 0:158c61bb030f | 2440 | } |
mzta | 0:158c61bb030f | 2441 | } |
mzta | 0:158c61bb030f | 2442 | mrb_str_cat_lit(mrb, result, "\""); |
mzta | 0:158c61bb030f | 2443 | |
mzta | 0:158c61bb030f | 2444 | return result; |
mzta | 0:158c61bb030f | 2445 | } |
mzta | 0:158c61bb030f | 2446 | |
mzta | 0:158c61bb030f | 2447 | /* |
mzta | 0:158c61bb030f | 2448 | * call-seq: |
mzta | 0:158c61bb030f | 2449 | * str.bytes -> array of fixnums |
mzta | 0:158c61bb030f | 2450 | * |
mzta | 0:158c61bb030f | 2451 | * Returns an array of bytes in _str_. |
mzta | 0:158c61bb030f | 2452 | * |
mzta | 0:158c61bb030f | 2453 | * str = "hello" |
mzta | 0:158c61bb030f | 2454 | * str.bytes #=> [104, 101, 108, 108, 111] |
mzta | 0:158c61bb030f | 2455 | */ |
mzta | 0:158c61bb030f | 2456 | static mrb_value |
mzta | 0:158c61bb030f | 2457 | mrb_str_bytes(mrb_state *mrb, mrb_value str) |
mzta | 0:158c61bb030f | 2458 | { |
mzta | 0:158c61bb030f | 2459 | struct RString *s = mrb_str_ptr(str); |
mzta | 0:158c61bb030f | 2460 | mrb_value a = mrb_ary_new_capa(mrb, RSTR_LEN(s)); |
mzta | 0:158c61bb030f | 2461 | unsigned char *p = (unsigned char *)(RSTR_PTR(s)), *pend = p + RSTR_LEN(s); |
mzta | 0:158c61bb030f | 2462 | |
mzta | 0:158c61bb030f | 2463 | while (p < pend) { |
mzta | 0:158c61bb030f | 2464 | mrb_ary_push(mrb, a, mrb_fixnum_value(p[0])); |
mzta | 0:158c61bb030f | 2465 | p++; |
mzta | 0:158c61bb030f | 2466 | } |
mzta | 0:158c61bb030f | 2467 | return a; |
mzta | 0:158c61bb030f | 2468 | } |
mzta | 0:158c61bb030f | 2469 | |
mzta | 0:158c61bb030f | 2470 | /* ---------------------------*/ |
mzta | 0:158c61bb030f | 2471 | void |
mzta | 0:158c61bb030f | 2472 | mrb_init_string(mrb_state *mrb) |
mzta | 0:158c61bb030f | 2473 | { |
mzta | 0:158c61bb030f | 2474 | struct RClass *s; |
mzta | 0:158c61bb030f | 2475 | |
mzta | 0:158c61bb030f | 2476 | mrb_static_assert(RSTRING_EMBED_LEN_MAX < (1 << 5), "pointer size too big for embedded string"); |
mzta | 0:158c61bb030f | 2477 | |
mzta | 0:158c61bb030f | 2478 | s = mrb->string_class = mrb_define_class(mrb, "String", mrb->object_class); /* 15.2.10 */ |
mzta | 0:158c61bb030f | 2479 | MRB_SET_INSTANCE_TT(s, MRB_TT_STRING); |
mzta | 0:158c61bb030f | 2480 | |
mzta | 0:158c61bb030f | 2481 | mrb_define_method(mrb, s, "bytesize", mrb_str_size, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 2482 | |
mzta | 0:158c61bb030f | 2483 | mrb_define_method(mrb, s, "<=>", mrb_str_cmp_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.1 */ |
mzta | 0:158c61bb030f | 2484 | mrb_define_method(mrb, s, "==", mrb_str_equal_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.2 */ |
mzta | 0:158c61bb030f | 2485 | mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ |
mzta | 0:158c61bb030f | 2486 | mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ |
mzta | 0:158c61bb030f | 2487 | mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ |
mzta | 0:158c61bb030f | 2488 | mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ |
mzta | 0:158c61bb030f | 2489 | mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ |
mzta | 0:158c61bb030f | 2490 | mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ |
mzta | 0:158c61bb030f | 2491 | mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ |
mzta | 0:158c61bb030f | 2492 | mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */ |
mzta | 0:158c61bb030f | 2493 | mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */ |
mzta | 0:158c61bb030f | 2494 | mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */ |
mzta | 0:158c61bb030f | 2495 | mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */ |
mzta | 0:158c61bb030f | 2496 | mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ |
mzta | 0:158c61bb030f | 2497 | mrb_define_method(mrb, s, "eql?", mrb_str_eql, MRB_ARGS_REQ(1)); /* 15.2.10.5.17 */ |
mzta | 0:158c61bb030f | 2498 | |
mzta | 0:158c61bb030f | 2499 | mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ |
mzta | 0:158c61bb030f | 2500 | mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ |
mzta | 0:158c61bb030f | 2501 | mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ |
mzta | 0:158c61bb030f | 2502 | mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ |
mzta | 0:158c61bb030f | 2503 | mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */ |
mzta | 0:158c61bb030f | 2504 | mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */ |
mzta | 0:158c61bb030f | 2505 | mrb_define_method(mrb, s, "length", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.26 */ |
mzta | 0:158c61bb030f | 2506 | mrb_define_method(mrb, s, "replace", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.28 */ |
mzta | 0:158c61bb030f | 2507 | mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE()); /* 15.2.10.5.29 */ |
mzta | 0:158c61bb030f | 2508 | mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE()); /* 15.2.10.5.30 */ |
mzta | 0:158c61bb030f | 2509 | mrb_define_method(mrb, s, "rindex", mrb_str_rindex_m, MRB_ARGS_ANY()); /* 15.2.10.5.31 */ |
mzta | 0:158c61bb030f | 2510 | mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE()); /* 15.2.10.5.33 */ |
mzta | 0:158c61bb030f | 2511 | mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.34 */ |
mzta | 0:158c61bb030f | 2512 | mrb_define_method(mrb, s, "split", mrb_str_split_m, MRB_ARGS_ANY()); /* 15.2.10.5.35 */ |
mzta | 0:158c61bb030f | 2513 | |
mzta | 0:158c61bb030f | 2514 | mrb_define_method(mrb, s, "to_f", mrb_str_to_f, MRB_ARGS_NONE()); /* 15.2.10.5.38 */ |
mzta | 0:158c61bb030f | 2515 | mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ |
mzta | 0:158c61bb030f | 2516 | mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ |
mzta | 0:158c61bb030f | 2517 | mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 2518 | mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ |
mzta | 0:158c61bb030f | 2519 | mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ |
mzta | 0:158c61bb030f | 2520 | mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ |
mzta | 0:158c61bb030f | 2521 | mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ |
mzta | 0:158c61bb030f | 2522 | mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); |
mzta | 0:158c61bb030f | 2523 | } |
mzta | 0:158c61bb030f | 2524 |