void ffi_pl_complex_float_to_perl(SV *sv, float *ptr) { if(SvOK(sv) && sv_isobject(sv) && sv_derived_from(sv, "Math::Complex")) { /* the complex variable is a Math::Complex object */ set(sv, sv_2mortal(newSVnv(ptr[0])), 0); set(sv, sv_2mortal(newSVnv(ptr[1])), 1); } else if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) { /* the compex variable is already an array */ AV *av = (AV*) SvRV(sv); av_store(av, 0, newSVnv(ptr[0])); av_store(av, 1, newSVnv(ptr[1])); } else { /* the complex variable is something else and an array needs to be created */ SV *values[2]; AV *av; values[0] = newSVnv(ptr[0]); values[1] = newSVnv(ptr[1]); av = av_make(2, values); sv_setsv(sv, newRV_noinc((SV*)av)); } }
const Array::Temp Call_stack::unpack(const Raw_string pattern, const Raw_string value) { prepare_call(); int count = unpackstring(const_cast<char*>(pattern.value), const_cast<char*>(pattern.value + pattern.length), const_cast<char*>(value.value), const_cast<char*>(value.value + value.length), value.utf8 && !IN_BYTES ? FLAG_UNPACK_DO_UTF8 : 0); finish_call(); return Array::Temp(interp, av_make(count, SP - count + 1), true); }
PJS_EXTERN JSBool PJS_Call_sv_with_jsvals_rsv( pTHX_ JSContext *cx, JSObject *obj, SV *code, SV *caller, /* Will be disposed inside */ uintN argc, jsval *argv, SV **rsv, I32 flag ) { dSP; JSBool ok = JS_TRUE; uintN arg; I32 rcount = caller ? 1 : 0; PJS_Context *pcx = PJS_GET_CONTEXT(cx); if(SvROK(code) && SvTYPE(SvRV(code)) == SVt_PVCV) { ENTER; SAVETMPS; PUSHMARK(SP) ; sv_setiv(save_scalar(PJS_Context_SV), PTR2IV(pcx)); EXTEND(SP, argc + rcount); PUTBACK; /* From here we are working with the global stack, * a) at PUSH time we can fail, so we need to abort the call * b) Want to avoid copying local <=> global SP at every single PUSH * * Before 'call_sv', rcount is the number of SVs pushed so far */ if(caller) *++PL_stack_sp = sv_2mortal(caller); if(argv && !(flag & G_NOARGS)) { /* HACK: We use G_NOARGS as a guard against use argv[-1] to get This. * Needed for the use in PJS_invoke_perl_property_setter where given * argc is faked */ SV *This; ok = PJS_ReflectJS2Perl(aTHX_ cx, argv[-1], &This, 0); if(ok) sv_setsv(save_scalar(PJS_This), sv_2mortal(This)); else goto forget; } else flag &= ~G_NOARGS; for(arg = 0; arg < argc; arg++) { SV *sv; ok = PJS_ReflectJS2Perl(aTHX_ cx, argv[arg], &sv, 1); if(!ok) { rcount += arg; goto forget; } *++PL_stack_sp = sv_2mortal(sv); } rcount = call_sv(code, flag | G_EVAL); if(rsv) { if(flag == G_SCALAR || rcount == 1) *rsv = SvREFCNT_inc_simple_NN(*PL_stack_sp); else *rsv = newRV((SV *)av_make(rcount, PL_stack_sp-rcount+1)); SAVEMORTALIZESV(*rsv); } forget: PL_stack_sp -= rcount; FREETMPS; LEAVE; if(ok && SvTRUE(ERRSV)) { propagate2JS(aTHX_ pcx, obj); ok = JS_FALSE; } } else croak("Not a coderef"); return ok; }
AV* Call_stack::pop_array(int count) { AV* ret = av_make(count, SP - count + 1); SP -= count; return ret; }
SV *ngx_http_psgi_create_env(pTHX_ ngx_http_request_t *r, char *app) { ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i, c, x; SV *_version[2]; AV *version; HV* env = newHV(); /* PSGI version 1.0, arrayref [1,0] */ _version[0] = newSViv(1); _version[1] = newSViv(0); version = av_make(2, _version); SvREFCNT_dec(_version[0]); SvREFCNT_dec(_version[1]); hv_store(env, "psgi.version", sizeof("psgi.version")-1, newRV_noinc((SV*)version), 0); /* FIXME: after any of this two operations $! is set to 'Inappropriate ioctl for device' */ SV *errors_h = PerlIONginxError_newhandle(aTHX_ r); if (errors_h == NULL) return NULL; hv_store(env, "psgi.errors", sizeof("psgi.errors")-1, errors_h, 0); SV *input_h = PerlIONginxInput_newhandle(aTHX_ r); if (input_h == NULL) return NULL; hv_store(env, "psgi.input", sizeof("psgi.input")-1, input_h, 0); /* Detect scheme. * TODO: Check if only http and https schemes allowed here. What about ws and others? * FIXME: mb nginx should parse scheme in safe way: [a-z][a-z0-9\=\0\.]* allowed to be valid scheme (rfc3986) * but nginx allows only [a-z]+ */ #if (NGX_HTTP_SSL) char *scheme; if (r->connection->ssl) { scheme = "https"; } else { scheme = "http"; } hv_store(env, "psgi.url_scheme", sizeof("psgi.url_scheme")-1, newSVpv(scheme, 0), 0); #else hv_store(env, "psgi.url_scheme", sizeof("psgi.url_scheme")-1, newSVpv("http", 0), 0); #endif // Buffered body in file if (r->request_body != NULL && r->request_body->temp_file != NULL) { hv_store(env, "psgix.input.buffered", sizeof("psgix.input.buffered")-1, newSViv(1), 0); } /* port defined in first line of HTTP request and parsed by nginx */ if (r->port_start) { STRLEN port_len = r->port_end - r->port_start; hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVpv((char *)r->port_start, port_len), 0); } else { /* copypasted from ngx_http_variables.c: get port from nginx conf */ /* TODO: Maybe reuse code from ngx_http_variables.c is a good idea? */ ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif u_char *strport; if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) { // TODO: Throw error return NULL; } strport = ngx_pnalloc(r->pool, sizeof("65535") - 1); if (strport == NULL) { return NULL; } switch (r->connection->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); break; } if (port > 0 && port < 65536) { hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVuv(port), 0); } else { hv_store(env, "SERVER_PORT", sizeof("SERVER_PORT")-1, newSVpv("", 0), 0); } } hv_store(env, "SERVER_PROTOCOL", sizeof("SERVER_PROTOCOL")-1, newSVpv((char *)r->http_protocol.data, r->http_protocol.len), 0); if (r->headers_in.content_length_n != -1) { hv_store(env, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1, newSViv(r->headers_in.content_length_n), 0); } if (r->headers_in.content_type != NULL) { hv_store(env, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1, newSVpv((char*)r->headers_in.content_type->value.data, r->headers_in.content_type->value.len), 0); } hv_store(env, "REQUEST_URI", sizeof("REQUEST_URI")-1, newSVpv((char *)r->unparsed_uri.data, r->unparsed_uri.len), 0); /* TODO: SCRIPT_NAME should be string matched by 'location' value in nginx.conf */ hv_store(env, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1, newSVpv("", 0), 0); /* FIXME: * PATH_INFO should be relative to SCRIPT_NAME (current 'location') path in nginx.conf * How to achieve this? Should I allow psgi only in 'exact match' locations? * It would be hard to find PATH_INFO for locations like "location ~ /(foo|bar)/.* { }". Or it wouldn't? */ hv_store(env, "PATH_INFO", sizeof("PATH_INFO")-1, newSVpv((char *)r->uri.data, r->uri.len), 0); hv_store(env, "REQUEST_METHOD", sizeof("REQUEST_METHOD")-1, newSVpv((char *)r->method_name.data, r->method_name.len), 0); if (r->args.len > 0) { hv_store(env, "QUERY_STRING", sizeof("QUERY_STRING")-1, newSVpv((char *)r->args.data, r->args.len), 0); } else { hv_store(env, "QUERY_STRING", sizeof("QUERY_STRING")-1, newSVpv("", 0), 0); } if (r->host_start && r->host_end) { hv_store(env, "SERVER_NAME", sizeof("SERVER_NAME")-1, newSVpv((char *)r->host_start, r->host_end - r->host_start), 0); } else { ngx_http_core_srv_conf_t *cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); hv_store(env, "SERVER_NAME", sizeof("SERVER_NAME")-1, newSVpv((char *)cscf->server_name.data, cscf->server_name.len), 0); } hv_store(env, "REMOTE_ADDR", sizeof("REMOTE_ADDR")-1, newSVpv((char *)r->connection->addr_text.data, r->connection->addr_text.len), 0); /* TODO * * psgi.multithread * psgi.multiprocess */ part = &r->headers_in.headers.part; h = part->elts; c = 0; for (i = 0; /* void */ ; i++) { ngx_str_t name; u_char *p; if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } /* The environment MUST NOT contain keys named HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH. * PSGI 1.09_3 */ if (ngx_strncasecmp(h[i].key.data, (u_char*)"CONTENT-LENGTH", h[i].key.len) == 0) { continue; } if (ngx_strncasecmp(h[i].key.data, (u_char*)"CONTENT-TYPE", h[i].key.len) == 0) { continue; } p = ngx_pnalloc(r->pool, sizeof("HTTP_") - 1 + h[i].key.len); if (p == NULL) { return NULL; } name.data = p; name.len = sizeof("HTTP_") + h[i].key.len -1 ; p = ngx_copy(p, (u_char*)"HTTP_", sizeof("HTTP_")-1); p = ngx_copy(p, h[i].key.data, h[i].key.len ); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Set env header: '%s' => '%s'", h[i].key.data, h[i].value.data); x = h[i].key.len + sizeof("HTTP_"); while (x > 0) { if (name.data[x] == '-') { name.data[x] = '_'; } else { name.data[x] = ngx_toupper(name.data[x]); } x--; } SV **exists = hv_fetch(env, (char*)name.data, name.len, 0); if (exists == NULL) { hv_store(env, (char *)name.data, name.len, newSVpv((char *)h[i].value.data, h[i].value.len), 0); } else { /* join ',', @values; * FIXME: Can I do this better */ SV *newval = newSVpvf("%s,%s", SvPV_nolen(*exists), h[i].value.data); hv_store(env, (char *)name.data, name.len, newval, 0); } c += 2; } return newRV_noinc((SV*)env); }