/* * call-seq: * str.prepend(other_str) -> str * * Prepend---Prepend the given string to <i>str</i>. * * a = "world" * a.prepend("hello ") #=> "hello world" * a #=> "hello world" */ static mrb_value mrb_str_prepend(mrb_state *mrb, mrb_value self) { struct RString *s1 = mrb_str_ptr(self), *s2, *temp_s; mrb_int len; mrb_value other, temp_str; mrb_get_args(mrb, "S", &other); mrb_str_modify(mrb, s1); if (!mrb_string_p(other)) { other = mrb_str_to_str(mrb, other); } s2 = mrb_str_ptr(other); len = RSTR_LEN(s1) + RSTR_LEN(s2); temp_str = mrb_str_new(mrb, NULL, RSTR_LEN(s1)); temp_s = mrb_str_ptr(temp_str); memcpy(RSTR_PTR(temp_s), RSTR_PTR(s1), RSTR_LEN(s1)); if (RSTRING_CAPA(self) < len) { mrb_str_resize(mrb, self, len); } memcpy(RSTR_PTR(s1), RSTR_PTR(s2), RSTR_LEN(s2)); memcpy(RSTR_PTR(s1) + RSTR_LEN(s2), RSTR_PTR(temp_s), RSTR_LEN(temp_s)); RSTR_SET_LEN(s1, len); RSTR_PTR(s1)[len] = '\0'; return self; }
/* * call-seq: * str.swapcase! -> str or nil * * Equivalent to <code>String#swapcase</code>, but modifies the receiver in * place, returning <i>str</i>, or <code>nil</code> if no changes were made. * Note: case conversion is effective only in ASCII region. */ static mrb_value mrb_str_swapcase_bang(mrb_state *mrb, mrb_value str) { char *p, *pend; int modify = 0; struct RString *s = mrb_str_ptr(str); mrb_str_modify(mrb, s); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); while (p < pend) { if (ISUPPER(*p)) { *p = TOLOWER(*p); modify = 1; } else if (ISLOWER(*p)) { *p = TOUPPER(*p); modify = 1; } p++; } if (modify) return str; return mrb_nil_value(); }
static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { mrb_int utf8_len = mrb_utf8_strlen(str, -1); if (utf8_len > 1) { mrb_int len; char *buf; unsigned char *p, *e, *r; mrb_str_modify(mrb, mrb_str_ptr(str)); len = RSTRING_LEN(str); buf = (char *)mrb_malloc(mrb, (size_t)len); p = (unsigned char*)buf; e = (unsigned char*)buf + len; memcpy(buf, RSTRING_PTR(str), len); r = (unsigned char*)RSTRING_PTR(str) + len; while (p<e) { mrb_int clen = utf8len(p); r -= clen; memcpy(r, p, clen); p += clen; } mrb_free(mrb, buf); } return str; }
mrb_value mrb_io_sysread(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; mrb_value buf = mrb_nil_value(); mrb_int maxlen; int ret; mrb_get_args(mrb, "i|S", &maxlen, &buf); if (maxlen < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size"); } else if (maxlen == 0) { return mrb_str_new(mrb, NULL, maxlen); } if (mrb_nil_p(buf)) { buf = mrb_str_new(mrb, NULL, maxlen); } if (RSTRING_LEN(buf) != maxlen) { buf = mrb_str_resize(mrb, buf, maxlen); } else { mrb_str_modify(mrb, RSTRING(buf)); } fptr = (struct mrb_io *)io_get_open_fptr(mrb, io); if (!fptr->readable) { mrb_raise(mrb, E_IO_ERROR, "not opened for reading"); } ret = read(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen); switch (ret) { case 0: /* EOF */ if (maxlen == 0) { buf = mrb_str_new_cstr(mrb, ""); } else { mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File"); } break; case -1: /* Error */ mrb_sys_fail(mrb, "sysread failed"); break; default: if (RSTRING_LEN(buf) != ret) { buf = mrb_str_resize(mrb, buf, ret); } break; } return buf; }
static mrb_value mrb_str_setbyte(mrb_state *mrb, mrb_value str) { mrb_int pos, byte; long len = RSTRING_LEN(str); mrb_get_args(mrb, "ii", &pos, &byte); if (pos < -len || len <= pos) mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); if (pos < 0) pos += len; mrb_str_modify(mrb, mrb_str_ptr(str)); byte &= 0xff; RSTRING_PTR(str)[pos] = byte; return mrb_fixnum_value((unsigned char)byte); }
int mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) { mrb_value emsg; int fd, retry = FALSE; char* fname = mrb_locale_from_utf8(pathname, -1); #ifdef O_CLOEXEC /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ flags |= O_CLOEXEC; #elif defined O_NOINHERIT flags |= O_NOINHERIT; #endif reopen: fd = open(fname, (int)flags, (fmode_t)mode); if (fd == -1) { if (!retry) { switch (errno) { case ENFILE: case EMFILE: mrb_garbage_collect(mrb); retry = TRUE; goto reopen; } } emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname)); mrb_str_modify(mrb, mrb_str_ptr(emsg)); mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } mrb_locale_free(fname); if (fd <= 2) { mrb_fd_cloexec(mrb, fd); } return fd; }
/* * call-seq: * string.succ -> string * * Returns next sequence of the string; * * a = "abc" * a.succ #=> "abd" */ static mrb_value mrb_str_succ_bang(mrb_state *mrb, mrb_value self) { mrb_value result; unsigned char *p, *e, *b, *t; const char *prepend; struct RString *s = mrb_str_ptr(self); size_t l; if (RSTRING_LEN(self) == 0) return self; mrb_str_modify(mrb, s); l = RSTRING_LEN(self); b = p = (unsigned char*) RSTRING_PTR(self); t = e = p + l; *(e--) = 0; // find trailing ascii/number while (e >= b) { if (ISALNUM(*e)) break; e--; } if (e < b) { e = p + l - 1; result = mrb_str_new_lit(mrb, ""); } else { // find leading letter of the ascii/number b = e; while (b > p) { if (!ISALNUM(*b) || (ISALNUM(*b) && *b != '9' && *b != 'z' && *b != 'Z')) break; b--; } if (!ISALNUM(*b)) b++; result = mrb_str_new(mrb, (char*) p, b - p); } while (e >= b) { if (!ISALNUM(*e)) { if (*e == 0xff) { mrb_str_cat_lit(mrb, result, "\x01"); (*e) = 0; } else (*e)++; break; } prepend = NULL; if (*e == '9') { if (e == b) prepend = "1"; *e = '0'; } else if (*e == 'z') { if (e == b) prepend = "a"; *e = 'a'; } else if (*e == 'Z') { if (e == b) prepend = "A"; *e = 'A'; } else { (*e)++; break; } if (prepend) mrb_str_cat_cstr(mrb, result, prepend); e--; } result = mrb_str_cat(mrb, result, (char*) b, t - b); l = RSTRING_LEN(result); mrb_str_resize(mrb, self, l); memcpy(RSTRING_PTR(self), RSTRING_PTR(result), l); return self; }