static int read_check(struct io_args *a, long n, const char *msg, int io_wait) { if (n == -1) { if (errno == EINTR) { a->fd = my_fileno(a->io); return -1; } rb_str_set_len(a->buf, 0); if (errno == EAGAIN) { if (io_wait) { (void)kgio_call_wait_readable(a->io); /* buf may be modified in other thread/fiber */ rb_str_modify(a->buf); rb_str_resize(a->buf, a->len); a->ptr = RSTRING_PTR(a->buf); return -1; } else { a->buf = sym_wait_readable; return 0; } } rd_sys_fail(msg); } rb_str_set_len(a->buf, n); if (n == 0) a->buf = Qnil; return 0; }
/** Gets returns a line. this is okay for small lines, but shouldn't really be used. Limited to ~ 1Mb of a line length. */ static VALUE tfio_gets(VALUE self) { int fd = get_tmpfile(self); size_t pos = get_pos(self); size_t end = get_end(self); if (pos == end) return Qnil; size_t pos_e = pos; char c; int ret; VALUE buffer; do { ret = pread(fd, &c, 1, pos_e); } while (ret > 0 && c != '\n' && (++pos_e < end)); set_pos(self, pos_e + 1); if (pos > pos_e) { buffer = rb_str_buf_new(pos_e - pos); // make sure the buffer is binary encoded. rb_enc_associate(buffer, BinaryEncoding); if (pread(fd, RSTRING_PTR(buffer), pos_e - pos, pos) < 0) return Qnil; rb_str_set_len(buffer, pos_e - pos); return buffer; } return Qnil; }
/* * call-seq: * remove_scope_id(ip_address) * * Returns copy of IP address with Scope ID removed, * if address has it (only IPv6 actually may have it). */ static VALUE remove_scope_id(const char *addr) { VALUE rv = rb_str_new2(addr); long len = RSTRING_LEN(rv); char *ptr = RSTRING_PTR(rv); char *pct = memchr(ptr, '%', len); /* * remove scoped portion * Ruby equivalent: rv.sub!(/%([^\]]*)\]/, "]") */ if (pct) { size_t newlen = pct - ptr; char *rbracket = memchr(pct, ']', len - newlen); if (rbracket) { size_t move = len - (rbracket - ptr); memmove(pct, rbracket, move); newlen += move; rb_str_set_len(rv, newlen); } else { rb_raise(rb_eArgError, "']' not found in IPv6 addr=%s", ptr); } } return rv; }
/* * call-seq: * cipher.update(data [, buffer]) -> string or buffer * * === Parameters * +data+ is a nonempty string. * +buffer+ is an optional string to store the result. */ static VALUE ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; char *in; int in_len, out_len; VALUE data, str; rb_scan_args(argc, argv, "11", &data, &str); StringValue(data); in = RSTRING_PTR(data); if ((in_len = RSTRING_LEN(data)) == 0) rb_raise(rb_eArgError, "data must not be empty"); GetCipher(self, ctx); out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); if (NIL_P(str)) { str = rb_str_new(0, out_len); } else { StringValue(str); rb_str_resize(str, out_len); } if (!EVP_CipherUpdate(ctx, RSTRING_PTR(str), &out_len, in, in_len)) ossl_raise(eCipherError, NULL); assert(out_len < RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; }
static VALUE in_addr_set(VALUE io, struct sockaddr_storage *addr, socklen_t len) { VALUE host; int host_len, rc; char *host_ptr; switch (addr->ss_family) { case AF_INET: host_len = (long)INET_ADDRSTRLEN; break; case AF_INET6: host_len = (long)INET6_ADDRSTRLEN; break; default: rb_raise(rb_eRuntimeError, "unsupported address family"); } host = rb_str_new(NULL, host_len); host_ptr = RSTRING_PTR(host); rc = getnameinfo((struct sockaddr *)addr, len, host_ptr, host_len, NULL, 0, NI_NUMERICHOST); if (rc != 0) rb_raise(rb_eRuntimeError, "getnameinfo: %s", gai_strerror(rc)); rb_str_set_len(host, strlen(host_ptr)); return rb_ivar_set(io, iv_kgio_addr, host); }
/* * call-seq: * cipher.update(data [, buffer]) -> string or buffer * * Encrypts data in a streaming fashion. Hand consecutive blocks of data * to the +update+ method in order to encrypt it. Returns the encrypted * data chunk. When done, the output of Cipher#final should be additionally * added to the result. * * === Parameters * +data+ is a nonempty string. * +buffer+ is an optional string to store the result. */ static VALUE ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; unsigned char *in; long in_len, out_len; VALUE data, str; rb_scan_args(argc, argv, "11", &data, &str); StringValue(data); in = (unsigned char *)RSTRING_PTR(data); if ((in_len = RSTRING_LEN(data)) == 0) ossl_raise(rb_eArgError, "data must not be empty"); GetCipher(self, ctx); out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); if (out_len <= 0) { ossl_raise(rb_eRangeError, "data too big to make output buffer: %ld bytes", in_len); } if (NIL_P(str)) { str = rb_str_new(0, out_len); } else { StringValue(str); rb_str_resize(str, out_len); } if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len)) ossl_raise(eCipherError, NULL); assert(out_len < RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; }
static VALUE rg_read_all(int argc, VALUE *argv, VALUE self) { VALUE rbcount, cancellable, result; gsize count; GError *error = NULL; gsize bytes_read; rb_scan_args(argc, argv, "11", &rbcount, &cancellable); count = RVAL2GSIZE(rbcount); result = rb_str_new(NULL, count); if (!g_input_stream_read_all(_SELF(self), RSTRING_PTR(result), count, &bytes_read, RVAL2GCANCELLABLE(cancellable), &error)) rbgio_raise_error(error); rb_str_set_len(result, bytes_read); rb_str_resize(result, bytes_read); OBJ_TAINT(result); return result; }
static int ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio) { struct __siov *iov; VALUE result = (VALUE)fp->_bf._base; char *buf = (char*)fp->_p; size_t len, n; size_t blen = buf - RSTRING_PTR(result), bsiz = fp->_w; if (RBASIC(result)->klass) { rb_raise(rb_eRuntimeError, "rb_vsprintf reentered"); } if ((len = uio->uio_resid) == 0) return 0; CHECK(len); buf += blen; fp->_w = bsiz; for (iov = uio->uio_iov; len > 0; ++iov) { MEMCPY(buf, iov->iov_base, char, n = iov->iov_len); buf += n; len -= n; } fp->_p = (unsigned char *)buf; rb_str_set_len(result, buf - RSTRING_PTR(result)); return 0; }
// This function is equivalent to rb_str_cat(), but unlike the real // rb_str_cat(), it doesn't leak memory in some versions of Ruby. // For more information, see: // https://bugs.ruby-lang.org/issues/11328 VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) { size_t oldlen = RSTRING_LEN(rb_str); rb_str_modify_expand(rb_str, len); char *p = RSTRING_PTR(rb_str); memcpy(p + oldlen, str, len); rb_str_set_len(rb_str, oldlen + len); }
// Reads data from the IO, according to the Rack specifications for `#read`. static VALUE tfio_read(int argc, VALUE *argv, VALUE self) { int fd = get_tmpfile(self); size_t pos = get_pos(self); size_t end = get_end(self); VALUE buffer = Qnil; char ret_nil = 0; ssize_t len = 0; // get the buffer object if given if (argc == 2) { Check_Type(argv[1], T_STRING); buffer = argv[1]; } // get the length object, if given if (argc > 0 && argv[0] != Qnil) { Check_Type(argv[0], T_FIXNUM); len = FIX2LONG(argv[0]); if (len < 0) rb_raise(rb_eRangeError, "length should be bigger then 0."); ret_nil = 1; } // return if we're at the EOF. if (pos == end) goto no_data; // calculate length if it wasn't specified. if (len == 0) { // make sure we're not reading more then we have len = end - pos; // set position for future reads set_pos(self, end); if (len == 0) goto no_data; } else { // set position for future reads set_pos(self, pos + len); } // limit read to what we have if (len + pos > end) len = end - pos; // create the buffer if we don't have one. if (buffer == Qnil) { buffer = rb_str_buf_new(len); // make sure the buffer is binary encoded. rb_enc_associate(buffer, BinaryEncoding); } else { // make sure the buffer is binary encoded. rb_enc_associate(buffer, BinaryEncoding); if (rb_str_capacity(buffer) < len) rb_str_resize(buffer, len); } // read the data. if (pread(fd, RSTRING_PTR(buffer), len, pos) <= 0) goto no_data; rb_str_set_len(buffer, len); return buffer; no_data: if (ret_nil) return Qnil; else return rb_str_buf_new(0); }
/* * call-seq: * ssl.sysread(length) => string * ssl.sysread(length, buffer) => buffer * * === Parameters * * +length+ is a positive integer. * * +buffer+ is a string used to store the result. */ static VALUE ossl_ssl_read(int argc, VALUE *argv, VALUE self) { SSL *ssl; int ilen, nread = 0; VALUE len, str; rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); if(NIL_P(str)) { str = rb_str_new(0, ilen); } else { StringValue(str); rb_str_modify(str); rb_str_resize(str, ilen); } if(ilen == 0) return str; Data_Get_Struct(self, SSL, ssl); int fd = rb_io_fd(ossl_ssl_get_io(self)); if (ssl) { if(SSL_pending(ssl) <= 0) rb_thread_wait_fd(fd); for (;;) { nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); switch(ssl_get_error(ssl, nread)) { case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: rb_eof_error(); case SSL_ERROR_WANT_WRITE: rb_io_wait_writable(fd); continue; case SSL_ERROR_WANT_READ: rb_io_wait_readable(fd); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read:"); } } } else { ID id_sysread = rb_intern("sysread"); rb_warning("SSL session is not started yet."); return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str); } end: rb_str_set_len(str, nread); OBJ_TAINT(str); return str; }
/* Use somewhat faster version with access to string capacity on MRI */ char * pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr ) { long curr_len = curr_ptr - RSTRING_PTR(str); long curr_capa = rb_str_capacity( str ); if( curr_capa < curr_len + expand_len ){ rb_str_set_len( str, curr_len ); rb_str_modify_expand( str, (curr_len + expand_len) * 2 - curr_capa ); curr_ptr = RSTRING_PTR(str) + curr_len; } if( end_ptr ) *end_ptr = RSTRING_PTR(str) + rb_str_capacity( str ); return curr_ptr; }
/* * call-seq: * coder.encode( value [, encoding] ) * * Encodes the given Ruby object into string representation, without * sending data to/from the database server. * * A nil value is passed through. * */ static VALUE pg_coder_encode(int argc, VALUE *argv, VALUE self) { VALUE res; VALUE intermediate; VALUE value; int len, len2; int enc_idx; t_pg_coder *this = DATA_PTR(self); if(argc < 1 || argc > 2){ rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc); }else if(argc == 1){ enc_idx = rb_ascii8bit_encindex(); }else{ enc_idx = rb_to_encoding_index(argv[1]); } value = argv[0]; if( NIL_P(value) ) return Qnil; if( !this->enc_func ){ rb_raise(rb_eRuntimeError, "no encoder function defined"); } len = this->enc_func( this, value, NULL, &intermediate, enc_idx ); if( len == -1 ){ /* The intermediate value is a String that can be used directly. */ OBJ_INFECT(intermediate, value); return intermediate; } res = rb_str_new(NULL, len); PG_ENCODING_SET_NOCHECK(res, enc_idx); len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate, enc_idx ); if( len < len2 ){ rb_bug("%s: result length of first encoder run (%i) is less than second run (%i)", rb_obj_classname( self ), len, len2 ); } rb_str_set_len( res, len2 ); OBJ_INFECT(res, value); RB_GC_GUARD(intermediate); return res; }
/* * call-seq: * cipher.final -> string * * Returns the remaining data held in the cipher object. Further calls to * Cipher#update or Cipher#final will return garbage. This call should always * be made as the last call of an encryption or decryption operation, after * after having fed the entire plaintext or ciphertext to the Cipher instance. * * If an authenticated cipher was used, a CipherError is raised if the tag * could not be authenticated successfully. Only call this method after * setting the authentication tag and passing the entire contents of the * ciphertext into the cipher. */ static VALUE ossl_cipher_final(VALUE self) { EVP_CIPHER_CTX *ctx; int out_len; VALUE str; GetCipher(self, ctx); str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx)); if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) ossl_raise(eCipherError, NULL); assert(out_len <= RSTRING_LEN(str)); rb_str_set_len(str, out_len); return str; }
static VALUE rg_peek(VALUE self, VALUE rboffset, VALUE rbcount) { gsize offset = RVAL2GSIZE(rboffset); gsize count = RVAL2GSIZE(rbcount); VALUE result = rb_str_new(NULL, count); gsize bytes_peeked = g_buffered_input_stream_peek(_SELF(self), RSTRING_PTR(result), offset, count); rb_str_set_len(result, bytes_peeked); rb_str_resize(result, bytes_peeked); OBJ_TAINT(result); return result; }
VALUE mCDB_Reader_get(VALUE self, VALUE key) { struct cdb db; VALUE value; StringValue(key); int fd = open_cdb_fd(self); size_t vlen; cdb_init(&db,fd); if(cdb_find(&db,RSTRING_PTR(key),RSTRING_LEN(key)) > 0) { vlen = cdb_datalen(&db); value = rb_str_buf_new(vlen); cdb_read(&db,RSTRING_PTR(value),vlen,cdb_datapos(&db)); rb_str_set_len(value,vlen); return value; } close(fd); return Qnil; }
static VALUE pkcs11_C_GetOperationState(VALUE self, VALUE session) { CK_RV rv; CK_C_GetOperationState func; VALUE state; CK_ULONG size; GetFunction(self, C_GetOperationState, func); CallFunction(C_GetOperationState, func, rv, NUM2HANDLE(session), NULL_PTR, &size); if (rv != CKR_OK) pkcs11_raise(self,rv); state = rb_str_new(0, size); CallFunction(C_GetOperationState, func, rv, NUM2HANDLE(session), (CK_BYTE_PTR)RSTRING_PTR(state), &size); if (rv != CKR_OK) pkcs11_raise(self,rv); rb_str_set_len(state, size); return state; }
VALUE mCDB_Reader_each_for_key(VALUE self,VALUE key) { struct cdb db; VALUE value; struct cdb_find find; StringValue(key); int fd = open_cdb_fd(self); size_t vlen; cdb_init(&db,fd); cdb_findinit(&find,&db,RSTRING_PTR(key),RSTRING_LEN(key)); while(cdb_findnext(&find) > 0) { vlen = cdb_datalen(&db); value = rb_str_buf_new(vlen); cdb_read(&db,RSTRING_PTR(value),vlen,cdb_datapos(&db)); rb_str_set_len(value,vlen); rb_yield(value); } close(fd); return Qnil; }
static VALUE _receive(int rflags, int argc, VALUE *argv, VALUE self) { struct posix_mq *mq = get(self, 1); struct rw_args x; VALUE buffer, timeout; struct timespec expire; if (mq->attr.mq_msgsize < 0) { if (mq_getattr(mq->des, &mq->attr) < 0) rb_sys_fail("mq_getattr"); } rb_scan_args(argc, argv, "02", &buffer, &timeout); x.timeout = convert_timeout(&expire, timeout); if (NIL_P(buffer)) { buffer = rb_str_new(0, mq->attr.mq_msgsize); } else { StringValue(buffer); rb_str_modify(buffer); rb_str_resize(buffer, mq->attr.mq_msgsize); } OBJ_TAINT(buffer); x.msg_ptr = RSTRING_PTR(buffer); x.msg_len = (size_t)mq->attr.mq_msgsize; x.des = mq->des; retry: WITHOUT_GVL(xrecv, &x, RUBY_UBF_IO, 0); if (x.received < 0) { if (errno == EINTR) goto retry; if (errno == EAGAIN && (rflags & PMQ_TRY)) return Qnil; rb_sys_fail("mq_receive"); } rb_str_set_len(buffer, x.received); if (rflags & PMQ_WANTARRAY) return rb_ary_new3(2, buffer, UINT2NUM(x.msg_prio)); return buffer; }
void rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...) { VALUE mesg; va_list args; int errno_save; errno_save = errno; if (!RTEST(ruby_verbose)) return; va_start(args, fmt); mesg = warning_string(enc, fmt, args); va_end(args); rb_str_set_len(mesg, RSTRING_LEN(mesg)-1); rb_str_catf(mesg, ": %s\n", strerror(errno_save)); rb_write_error_str(mesg); errno = errno_save; }
/* * call-seq: * dh.compute_key(pub_bn) -> aString * * Returns a String containing a shared secret computed from the other party's public value. * See DH_compute_key() for further information. * * === Parameters * * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by * DH#public_key as that contains the DH parameters only. */ static VALUE ossl_dh_compute_key(VALUE self, VALUE pub) { DH *dh; EVP_PKEY *pkey; BIGNUM *pub_key; VALUE str; int len; GetPKeyDH(self, pkey); dh = pkey->pkey.dh; pub_key = GetBNPtr(pub); len = DH_size(dh); str = rb_str_new(0, len); if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { ossl_raise(eDHError, NULL); } rb_str_set_len(str, len); return str; }
/* * call-seq: * entry.inspect => String * * Produce a concise representation of the entry. */ VALUE rb_ldap_entry_inspect (VALUE self) { VALUE str; const char *c; c = rb_obj_classname (self); str = rb_str_new (0, strlen (c) + 10 + 16 + 1); /* 10:tags 16:addr 1:nul */ sprintf (RSTRING_PTR (str), "#<%s:0x%lx\n", c, self); #if RUBY_VERSION_CODE < 190 RSTRING(str)->len = strlen (RSTRING_PTR (str)); #else rb_str_set_len(str, strlen (RSTRING_PTR (str))); #endif rb_str_concat (str, rb_inspect (rb_ldap_entry_to_hash (self))); rb_str_cat2 (str, ">"); return str; }
/* * call-seq: * dh.compute_key(pub_bn) -> aString * * Returns a String containing a shared secret computed from the other party's public value. * See DH_compute_key() for further information. * * === Parameters * * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by * DH#public_key as that contains the DH parameters only. */ static VALUE ossl_dh_compute_key(VALUE self, VALUE pub) { DH *dh; const BIGNUM *pub_key, *dh_p; VALUE str; int len; GetDH(self, dh); DH_get0_pqg(dh, &dh_p, NULL, NULL); if (!dh_p) ossl_raise(eDHError, "incomplete DH"); pub_key = GetBNPtr(pub); len = DH_size(dh); str = rb_str_new(0, len); if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) { ossl_raise(eDHError, NULL); } rb_str_set_len(str, len); return str; }
static VALUE rb_nkf_convert(VALUE obj, VALUE opt, VALUE src) { reinit(); StringValue(opt); nkf_split_options(RSTRING_PTR(opt)); if (!output_encoding) rb_raise(rb_eArgError, "no output encoding given"); switch (nkf_enc_to_index(output_encoding)) { case UTF_8_BOM: output_encoding = nkf_enc_from_index(UTF_8); break; case UTF_16BE_BOM: output_encoding = nkf_enc_from_index(UTF_16BE); break; case UTF_16LE_BOM: output_encoding = nkf_enc_from_index(UTF_16LE); break; case UTF_32BE_BOM: output_encoding = nkf_enc_from_index(UTF_32BE); break; case UTF_32LE_BOM: output_encoding = nkf_enc_from_index(UTF_32LE); break; } output_bom_f = FALSE; incsize = INCSIZE; input_ctr = 0; StringValue(src); input = (unsigned char *)RSTRING_PTR(src); i_len = RSTRING_LEN(src); result = rb_str_new(0, i_len*3 + 10); output_ctr = 0; output = (unsigned char *)RSTRING_PTR(result); o_len = RSTRING_LEN(result); *output = '\0'; kanji_convert(NULL); rb_str_set_len(result, output_ctr); OBJ_INFECT(result, src); rb_enc_associate(result, rb_nkf_enc_get(nkf_enc_name(output_encoding))); return result; }
static VALUE append_wstr(VALUE dst, const wchar_t *ws, size_t len, UINT cp, UINT path_cp, rb_encoding *path_encoding) { long olen, nlen = (long)len; if (cp == path_cp) { nlen = WideCharToMultiByte(cp, 0, ws, len, NULL, 0, NULL, NULL); olen = RSTRING_LEN(dst); rb_str_modify_expand(dst, nlen); WideCharToMultiByte(cp, 0, ws, len, RSTRING_PTR(dst) + olen, nlen, NULL, NULL); rb_enc_associate(dst, path_encoding); rb_str_set_len(dst, olen + nlen); } else { const int replaceflags = ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE; char *utf8str = wstr_to_mbstr(CP_UTF8, ws, (int)len, &nlen); rb_econv_t *ec = rb_econv_open("UTF-8", rb_enc_name(path_encoding), replaceflags); dst = rb_econv_append(ec, utf8str, nlen, dst, replaceflags); rb_econv_close(ec); free(utf8str); } return dst; }
/* * call-seq: * pkey.sign(digest, data) -> String * * To sign the +String+ +data+, +digest+, an instance of OpenSSL::Digest, must * be provided. The return value is again a +String+ containing the signature. * A PKeyError is raised should errors occur. * Any previous state of the +Digest+ instance is irrelevant to the signature * outcome, the digest instance is reset to its initial state during the * operation. * * == Example * data = 'Sign me!' * digest = OpenSSL::Digest::SHA256.new * pkey = OpenSSL::PKey::RSA.new(2048) * signature = pkey.sign(digest, data) */ static VALUE ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) { EVP_PKEY *pkey; EVP_MD_CTX ctx; unsigned int buf_len; VALUE str; if (rb_funcallv(self, id_private_q, 0, NULL) != Qtrue) { ossl_raise(rb_eArgError, "Private key is needed."); } GetPKey(self, pkey); EVP_SignInit(&ctx, GetDigestPtr(digest)); StringValue(data); EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); str = rb_str_new(0, EVP_PKEY_size(pkey)+16); if (!EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey)) ossl_raise(ePKeyError, NULL); assert((long)buf_len <= RSTRING_LEN(str)); rb_str_set_len(str, buf_len); return str; }
/* * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder * * This is an encoder class for conversion of base64 encoded data * to it's binary representation. * */ static int pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate) { int strlen; VALUE subint; t_pg_composite_coder *this = (t_pg_composite_coder *)conv; t_pg_coder_enc_func enc_func = pg_coder_enc_func(this->elem); if(out){ /* Second encoder pass, if required */ strlen = enc_func(this->elem, value, out, intermediate); strlen = base64_decode( out, out, strlen ); return strlen; } else { /* First encoder pass */ strlen = enc_func(this->elem, value, NULL, &subint); if( strlen == -1 ){ /* Encoded string is returned in subint */ VALUE out_str; strlen = RSTRING_LENINT(subint); out_str = rb_str_new(NULL, BASE64_DECODED_SIZE(strlen)); strlen = base64_decode( RSTRING_PTR(out_str), RSTRING_PTR(subint), strlen); rb_str_set_len( out_str, strlen ); *intermediate = out_str; return -1; } else { *intermediate = subint; return BASE64_DECODED_SIZE(strlen); } } }
/* * IO.pread(fd, length, offset) * * This is similar to the IO.read method, except that it reads from a given * position in the file without changing the file pointer. And unlike IO.read, * the +fd+, +length+ and +offset+ arguments are all mandatory. */ static VALUE s_io_pread(VALUE klass, VALUE fd, VALUE nbyte, VALUE offset){ struct pread_args args; VALUE str; ssize_t nread; args.fd = NUM2INT(fd); args.nbyte = NUM2ULONG(nbyte); args.offset = NUM2OFFT(offset); str = rb_str_new(NULL, args.nbyte); args.buf = RSTRING_PTR(str); #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL nread = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pread, &args, RUBY_UBF_IO, 0); #else nread = (ssize_t)rb_thread_blocking_region(nogvl_pread, &args, RUBY_UBF_IO, 0); #endif if (nread == -1) rb_sys_fail("pread"); if ((size_t)nread != args.nbyte) rb_str_set_len(str, nread); return str; }
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt) { enum {default_float_precision = 6}; rb_encoding *enc; const char *p, *end; char *buf; long blen, bsiz; VALUE result; long scanned = 0; int coderange = ENC_CODERANGE_7BIT; int width, prec, flags = FNONE; int nextarg = 1; int posarg = 0; int tainted = 0; VALUE nextvalue; VALUE tmp; VALUE str; volatile VALUE hash = Qundef; #define CHECK_FOR_WIDTH(f) \ if ((f) & FWIDTH) { \ rb_raise(rb_eArgError, "width given twice"); \ } \ if ((f) & FPREC0) { \ rb_raise(rb_eArgError, "width after precision"); \ } #define CHECK_FOR_FLAGS(f) \ if ((f) & FWIDTH) { \ rb_raise(rb_eArgError, "flag after width"); \ } \ if ((f) & FPREC0) { \ rb_raise(rb_eArgError, "flag after precision"); \ } ++argc; --argv; if (OBJ_TAINTED(fmt)) tainted = 1; StringValue(fmt); enc = rb_enc_get(fmt); fmt = rb_str_new4(fmt); p = RSTRING_PTR(fmt); end = p + RSTRING_LEN(fmt); blen = 0; bsiz = 120; result = rb_str_buf_new(bsiz); rb_enc_copy(result, fmt); buf = RSTRING_PTR(result); memset(buf, 0, bsiz); ENC_CODERANGE_SET(result, coderange); for (; p < end; p++) { const char *t; int n; VALUE sym = Qnil; for (t = p; t < end && *t != '%'; t++) ; PUSH(p, t - p); if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) { scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &coderange); ENC_CODERANGE_SET(result, coderange); } if (t >= end) { /* end of fmt string */ goto sprint_exit; } p = t + 1; /* skip `%' */ width = prec = -1; nextvalue = Qundef; retry: switch (*p) { default: if (rb_enc_isprint(*p, enc)) rb_raise(rb_eArgError, "malformed format string - %%%c", *p); else rb_raise(rb_eArgError, "malformed format string"); break; case ' ': CHECK_FOR_FLAGS(flags); flags |= FSPACE; p++; goto retry; case '#': CHECK_FOR_FLAGS(flags); flags |= FSHARP; p++; goto retry; case '+': CHECK_FOR_FLAGS(flags); flags |= FPLUS; p++; goto retry; case '-': CHECK_FOR_FLAGS(flags); flags |= FMINUS; p++; goto retry; case '0': CHECK_FOR_FLAGS(flags); flags |= FZERO; p++; goto retry; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; GETNUM(n, width); if (*p == '$') { if (nextvalue != Qundef) { rb_raise(rb_eArgError, "value given twice - %d$", n); } nextvalue = GETPOSARG(n); p++; goto retry; } CHECK_FOR_WIDTH(flags); width = n; flags |= FWIDTH; goto retry; case '<': case '{': { const char *start = p; char term = (*p == '<') ? '>' : '}'; int len; for (; p < end && *p != term; ) { p += rb_enc_mbclen(p, end, enc); } if (p >= end) { rb_raise(rb_eArgError, "malformed name - unmatched parenthesis"); } #if SIZEOF_INT < SIZEOF_SIZE_T if ((size_t)(p - start) >= INT_MAX) { const int message_limit = 20; len = (int)(rb_enc_right_char_head(start, start + message_limit, p, enc) - start); rb_enc_raise(enc, rb_eArgError, "too long name (%"PRIdSIZE" bytes) - %.*s...%c", (size_t)(p - start - 2), len, start, term); } #endif len = (int)(p - start + 1); /* including parenthesis */ if (sym != Qnil) { rb_enc_raise(enc, rb_eArgError, "named%.*s after <%"PRIsVALUE">", len, start, rb_sym2str(sym)); } CHECKNAMEARG(start, len, enc); get_hash(&hash, argc, argv); sym = rb_check_symbol_cstr(start + 1, len - 2 /* without parenthesis */, enc); if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef); if (nextvalue == Qundef) { rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start); } if (term == '}') goto format_s; p++; goto retry; } case '*': CHECK_FOR_WIDTH(flags); flags |= FWIDTH; GETASTER(width); if (width < 0) { flags |= FMINUS; width = -width; } p++; goto retry; case '.': if (flags & FPREC0) { rb_raise(rb_eArgError, "precision given twice"); } flags |= FPREC|FPREC0; prec = 0; p++; if (*p == '*') { GETASTER(prec); if (prec < 0) { /* ignore negative precision */ flags &= ~FPREC; } p++; goto retry; } GETNUM(prec, precision); goto retry; case '\n': case '\0': p--; case '%': if (flags != FNONE) { rb_raise(rb_eArgError, "invalid format character - %%"); } PUSH("%", 1); break; case 'c': { VALUE val = GETARG(); VALUE tmp; unsigned int c; int n; tmp = rb_check_string_type(val); if (!NIL_P(tmp)) { if (rb_enc_strlen(RSTRING_PTR(tmp),RSTRING_END(tmp),enc) != 1) { rb_raise(rb_eArgError, "%%c requires a character"); } c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, enc); RB_GC_GUARD(tmp); } else { c = NUM2INT(val); n = rb_enc_codelen(c, enc); } if (n <= 0) { rb_raise(rb_eArgError, "invalid character"); } if (!(flags & FWIDTH)) { CHECK(n); rb_enc_mbcput(c, &buf[blen], enc); blen += n; } else if ((flags & FMINUS)) { CHECK(n); rb_enc_mbcput(c, &buf[blen], enc); blen += n; FILL(' ', width-1); } else { FILL(' ', width-1); CHECK(n); rb_enc_mbcput(c, &buf[blen], enc); blen += n; } } break; case 's': case 'p': format_s: { VALUE arg = GETARG(); long len, slen; if (*p == 'p') arg = rb_inspect(arg); str = rb_obj_as_string(arg); if (OBJ_TAINTED(str)) tainted = 1; len = RSTRING_LEN(str); rb_str_set_len(result, blen); if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) { int cr = coderange; scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr); ENC_CODERANGE_SET(result, (cr == ENC_CODERANGE_UNKNOWN ? ENC_CODERANGE_BROKEN : (coderange = cr))); } enc = rb_enc_check(result, str); if (flags&(FPREC|FWIDTH)) { slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc); if (slen < 0) { rb_raise(rb_eArgError, "invalid mbstring sequence"); } if ((flags&FPREC) && (prec < slen)) { char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str), prec, enc); slen = prec; len = p - RSTRING_PTR(str); } /* need to adjust multi-byte string pos */ if ((flags&FWIDTH) && (width > slen)) { width -= (int)slen; if (!(flags&FMINUS)) { CHECK(width); while (width--) { buf[blen++] = ' '; } } CHECK(len); memcpy(&buf[blen], RSTRING_PTR(str), len); RB_GC_GUARD(str); blen += len; if (flags&FMINUS) { CHECK(width); while (width--) { buf[blen++] = ' '; } } rb_enc_associate(result, enc); break; } } PUSH(RSTRING_PTR(str), len); RB_GC_GUARD(str); rb_enc_associate(result, enc); } break; case 'd': case 'i': case 'o': case 'x': case 'X': case 'b': case 'B': case 'u': { volatile VALUE val = GETARG(); int valsign; char nbuf[64], *s; const char *prefix = 0; int sign = 0, dots = 0; char sc = 0; long v = 0; int base, bignum = 0; int len; switch (*p) { case 'd': case 'i': case 'u': sign = 1; break; case 'o': case 'x': case 'X': case 'b': case 'B': if (flags&(FPLUS|FSPACE)) sign = 1; break; } if (flags & FSHARP) { switch (*p) { case 'o': prefix = "0"; break; case 'x': prefix = "0x"; break; case 'X': prefix = "0X"; break; case 'b': prefix = "0b"; break; case 'B': prefix = "0B"; break; } } bin_retry: switch (TYPE(val)) { case T_FLOAT: if (FIXABLE(RFLOAT_VALUE(val))) { val = LONG2FIX((long)RFLOAT_VALUE(val)); goto bin_retry; } val = rb_dbl2big(RFLOAT_VALUE(val)); if (FIXNUM_P(val)) goto bin_retry; bignum = 1; break; case T_STRING: val = rb_str_to_inum(val, 0, TRUE); goto bin_retry; case T_BIGNUM: bignum = 1; break; case T_FIXNUM: v = FIX2LONG(val); break; default: val = rb_Integer(val); goto bin_retry; } switch (*p) { case 'o': base = 8; break; case 'x': case 'X': base = 16; break; case 'b': case 'B': base = 2; break; case 'u': case 'd': case 'i': default: base = 10; break; } if (base != 10) { int numbits = ffs(base)-1; size_t abs_nlz_bits; size_t numdigits = rb_absint_numwords(val, numbits, &abs_nlz_bits); long i; if (INT_MAX-1 < numdigits) /* INT_MAX is used because rb_long2int is used later. */ rb_raise(rb_eArgError, "size too big"); if (sign) { if (numdigits == 0) numdigits = 1; tmp = rb_str_new(NULL, numdigits); valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp), 1, CHAR_BIT-numbits, INTEGER_PACK_BIG_ENDIAN); for (i = 0; i < RSTRING_LEN(tmp); i++) RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]]; s = RSTRING_PTR(tmp); if (valsign < 0) { sc = '-'; width--; } else if (flags & FPLUS) { sc = '+'; width--; } else if (flags & FSPACE) { sc = ' '; width--; } } else { /* Following conditional "numdigits++" guarantees the * most significant digit as * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers * - '0' for zero * - not '0' for positive numbers. * * It also guarantees the most significant two * digits will not be '11'(bin), '77'(oct), 'ff'(hex) * or '00'. */ if (numdigits == 0 || ((abs_nlz_bits != (size_t)(numbits-1) || !rb_absint_singlebit_p(val)) && (!bignum ? v < 0 : BIGNUM_NEGATIVE_P(val)))) numdigits++; tmp = rb_str_new(NULL, numdigits); valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp), 1, CHAR_BIT-numbits, INTEGER_PACK_2COMP | INTEGER_PACK_BIG_ENDIAN); for (i = 0; i < RSTRING_LEN(tmp); i++) RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]]; s = RSTRING_PTR(tmp); dots = valsign < 0; } len = rb_long2int(RSTRING_END(tmp) - s); } else if (!bignum) { valsign = 1; if (v < 0) { v = -v; sc = '-'; width--; valsign = -1; } else if (flags & FPLUS) { sc = '+'; width--; } else if (flags & FSPACE) { sc = ' '; width--; } snprintf(nbuf, sizeof(nbuf), "%ld", v); s = nbuf; len = (int)strlen(s); } else { tmp = rb_big2str(val, 10); s = RSTRING_PTR(tmp); valsign = 1; if (s[0] == '-') { s++; sc = '-'; width--; valsign = -1; } else if (flags & FPLUS) { sc = '+'; width--; } else if (flags & FSPACE) { sc = ' '; width--; } len = rb_long2int(RSTRING_END(tmp) - s); } if (dots) { prec -= 2; width -= 2; } if (*p == 'X') { char *pp = s; int c; while ((c = (int)(unsigned char)*pp) != 0) { *pp = rb_enc_toupper(c, enc); pp++; } } if (prefix && !prefix[1]) { /* octal */ if (dots) { prefix = 0; } else if (len == 1 && *s == '0') { len = 0; if (flags & FPREC) prec--; } else if ((flags & FPREC) && (prec > len)) { prefix = 0; } } else if (len == 1 && *s == '0') { prefix = 0; } if (prefix) { width -= (int)strlen(prefix); } if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) { prec = width; width = 0; } else { if (prec < len) { if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0; prec = len; } width -= prec; } if (!(flags&FMINUS)) { CHECK(width); while (width-- > 0) { buf[blen++] = ' '; } } if (sc) PUSH(&sc, 1); if (prefix) { int plen = (int)strlen(prefix); PUSH(prefix, plen); } CHECK(prec - len); if (dots) PUSH("..", 2); if (!sign && valsign < 0) { char c = sign_bits(base, p); while (len < prec--) { buf[blen++] = c; } } else if ((flags & (FMINUS|FPREC)) != FMINUS) { while (len < prec--) { buf[blen++] = '0'; } } PUSH(s, len); RB_GC_GUARD(tmp); CHECK(width); while (width-- > 0) { buf[blen++] = ' '; } } break; case 'f': { VALUE val = GETARG(), num, den; int sign = (flags&FPLUS) ? 1 : 0, zero = 0; long len, done = 0; int prefix = 0; if (!RB_TYPE_P(val, T_RATIONAL)) { nextvalue = val; goto float_value; } if (!(flags&FPREC)) prec = default_float_precision; den = rb_rational_den(val); num = rb_rational_num(val); if (FIXNUM_P(num)) { if ((SIGNED_VALUE)num < 0) { long n = -FIX2LONG(num); num = LONG2FIX(n); sign = -1; } } else if (rb_num_negative_p(num)) { sign = -1; num = rb_funcallv(num, idUMinus, 0, 0); } if (den != INT2FIX(1) || prec > 1) { const ID idDiv = rb_intern("div"); VALUE p10 = rb_int_positive_pow(10, prec); VALUE den_2 = rb_funcall(den, idDiv, 1, INT2FIX(2)); num = rb_funcallv(num, '*', 1, &p10); num = rb_funcallv(num, '+', 1, &den_2); num = rb_funcallv(num, idDiv, 1, &den); } else if (prec >= 0) { zero = prec; } val = rb_obj_as_string(num); len = RSTRING_LEN(val) + zero; if (prec >= len) ++len; /* integer part 0 */ if (sign || (flags&FSPACE)) ++len; if (prec > 0) ++len; /* period */ CHECK(len > width ? len : width); if (sign || (flags&FSPACE)) { buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' '; prefix++; done++; } len = RSTRING_LEN(val) + zero; t = RSTRING_PTR(val); if (len > prec) { memcpy(&buf[blen], t, len - prec); blen += len - prec; done += len - prec; } else { buf[blen++] = '0'; done++; } if (prec > 0) { buf[blen++] = '.'; done++; } if (zero) { FILL('0', zero); done += zero; } else if (prec > len) { FILL('0', prec - len); memcpy(&buf[blen], t, len); blen += len; done += prec; } else if (prec > 0) { memcpy(&buf[blen], t + len - prec, prec); blen += prec; done += prec; } if ((flags & FWIDTH) && width > done) { int fill = ' '; long shifting = 0; if (!(flags&FMINUS)) { shifting = done; if (flags&FZERO) { shifting -= prefix; fill = '0'; } blen -= shifting; memmove(&buf[blen + width - done], &buf[blen], shifting); } FILL(fill, width - done); blen += shifting; } RB_GC_GUARD(val); break; } case 'g': case 'G': case 'e': case 'E': /* TODO: rational support */ case 'a': case 'A': float_value: { VALUE val = GETARG(); double fval; int i, need; char fbuf[32]; fval = RFLOAT_VALUE(rb_Float(val)); if (isnan(fval) || isinf(fval)) { const char *expr; if (isnan(fval)) { expr = "NaN"; } else { expr = "Inf"; } need = (int)strlen(expr); if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS)) need++; if ((flags & FWIDTH) && need < width) need = width; CHECK(need + 1); snprintf(&buf[blen], need + 1, "%*s", need, ""); if (flags & FMINUS) { if (!isnan(fval) && fval < 0.0) buf[blen++] = '-'; else if (flags & FPLUS) buf[blen++] = '+'; else if (flags & FSPACE) blen++; memcpy(&buf[blen], expr, strlen(expr)); } else { if (!isnan(fval) && fval < 0.0) buf[blen + need - strlen(expr) - 1] = '-'; else if (flags & FPLUS) buf[blen + need - strlen(expr) - 1] = '+'; else if ((flags & FSPACE) && need > width) blen++; memcpy(&buf[blen + need - strlen(expr)], expr, strlen(expr)); } blen += strlen(&buf[blen]); break; } fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec); need = 0; if (*p != 'e' && *p != 'E') { i = INT_MIN; frexp(fval, &i); if (i > 0) need = BIT_DIGITS(i); } need += (flags&FPREC) ? prec : default_float_precision; if ((flags&FWIDTH) && need < width) need = width; need += 20; CHECK(need); snprintf(&buf[blen], need, fbuf, fval); blen += strlen(&buf[blen]); } break; } flags = FNONE; } sprint_exit: RB_GC_GUARD(fmt); /* XXX - We cannot validate the number of arguments if (digit)$ style used. */ if (posarg >= 0 && nextarg < argc) { const char *mesg = "too many arguments for format string"; if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg); if (RTEST(ruby_verbose)) rb_warn("%s", mesg); } rb_str_resize(result, blen); if (tainted) OBJ_TAINT(result); return result; }
void ruby_init_loadpath_safe(int safe_level, const char* szRoot) { VALUE load_path; ID id_initial_load_path_mark; extern const char ruby_initial_load_paths[]; const char *paths = ruby_initial_load_paths; #if defined LOAD_RELATIVE # if defined HAVE_DLADDR || (defined __CYGWIN__ && defined CCP_WIN_A_TO_POSIX) # define VARIABLE_LIBPATH 1 # else # define VARIABLE_LIBPATH 0 # endif # if VARIABLE_LIBPATH char *libpath; VALUE sopath; # else char libpath[MAXPATHLEN + 1]; # endif size_t baselen; char *p; if ( szRoot ) strncpy(libpath, szRoot, sizeof(libpath) - 1); else { #if defined _WIN32 || defined __CYGWIN__ # if VARIABLE_LIBPATH sopath = rb_str_new(0, MAXPATHLEN); libpath = RSTRING_PTR(sopath); GetModuleFileName(libruby, libpath, MAXPATHLEN); # else GetModuleFileName(libruby, libpath, sizeof libpath); # endif #elif defined(__EMX__) _execname(libpath, sizeof(libpath) - 1); #elif defined(HAVE_DLADDR) Dl_info dli; if (dladdr((void *)(VALUE)expand_include_path, &dli)) { VALUE fname = rb_str_new_cstr(dli.dli_fname); sopath = rb_file_absolute_path(fname, Qnil); rb_str_resize(fname, 0); } else { sopath = rb_str_new(0, 0); } libpath = RSTRING_PTR(sopath); #endif } //RHO #if !VARIABLE_LIBPATH libpath[sizeof(libpath) - 1] = '\0'; #endif #if defined DOSISH translit_char(libpath, '\\', '/'); #elif defined __CYGWIN__ { # if VARIABLE_LIBPATH const int win_to_posix = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; size_t newsize = cygwin_conv_path(win_to_posix, libpath, 0, 0); if (newsize > 0) { VALUE rubylib = rb_str_new(0, newsize); p = RSTRING_PTR(rubylib); if (cygwin_conv_path(win_to_posix, libpath, p, newsize) == 0) { rb_str_resize(sopath, 0); sopath = rubylib; libpath = p; } } # else char rubylib[FILENAME_MAX]; cygwin_conv_to_posix_path(libpath, rubylib); strncpy(libpath, rubylib, sizeof(libpath)); # endif } #endif p = strrchr(libpath, '/'); if (p) { *p = 0; if (p - libpath > 3 && !(STRCASECMP(p - 4, "/bin") && strcmp(p - 4, "/lib"))) { p -= 4; *p = 0; } } #if !VARIABLE_LIBPATH else { strlcpy(libpath, ".", sizeof(libpath)); p = libpath + 1; } baselen = p - libpath; #define PREFIX_PATH() rb_str_new(libpath, baselen) #else baselen = p - libpath; rb_str_set_len(sopath, baselen); libpath = RSTRING_PTR(sopath); #define PREFIX_PATH() sopath #endif #define BASEPATH() rb_str_buf_cat(rb_str_buf_new(baselen+len), libpath, baselen) #define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), path, len) #else static const char exec_prefix[] = RUBY_EXEC_PREFIX; #define RUBY_RELATIVE(path, len) rubylib_mangled_path(path, len) #define PREFIX_PATH() RUBY_RELATIVE(exec_prefix, sizeof(exec_prefix)-1) #endif load_path = GET_VM()->load_path; if (safe_level == 0) { ruby_push_include(getenv("RUBYLIB"), identical_path); } id_initial_load_path_mark = rb_intern_const("@gem_prelude_index"); while (*paths) { size_t len = strlen(paths); VALUE path = RUBY_RELATIVE(paths, len); rb_ivar_set(path, id_initial_load_path_mark, path); rb_ary_push(load_path, path); paths += len + 1; } rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), rb_obj_freeze(PREFIX_PATH())); }