AP_DECLARE(apr_status_t) ap_fcgi_encode_env(request_rec *r,
                                            apr_table_t *env,
                                            void *buffer,
                                            apr_size_t buflen,
                                            int *starting_elem)
{
    apr_status_t rv = APR_SUCCESS;
    const apr_array_header_t *envarr;
    const apr_table_entry_t *elts;
    char *itr;
    int i;

    envarr = apr_table_elts(env);
    elts = (const apr_table_entry_t *) envarr->elts;

    itr = buffer;

    for (i = *starting_elem; i < envarr->nelts; ) {
        apr_size_t keylen, vallen;

        if (!elts[i].key) {
            (*starting_elem)++;
            i++;
            continue;
        }

        keylen = strlen(elts[i].key);

        if (keylen >> 7 == 0) {
            if (buflen < 1) {
                rv = APR_ENOSPC; /* overflow */
                break;
            }
            itr[0] = keylen & 0xff;
            itr += 1;
            buflen -= 1;
        }
        else {
            if (buflen < 4) {
                rv = APR_ENOSPC; /* overflow */
                break;
            }
            itr[0] = ((keylen >> 24) & 0xff) | 0x80;
            itr[1] = ((keylen >> 16) & 0xff);
            itr[2] = ((keylen >> 8) & 0xff);
            itr[3] = ((keylen) & 0xff);
            itr += 4;
            buflen -= 4;
        }

        vallen = elts[i].val ? strlen(elts[i].val) : 0;

        if (vallen >> 7 == 0) {
            if (buflen < 1) {
                rv = APR_ENOSPC; /* overflow */
                break;
            }
            itr[0] = vallen & 0xff;
            itr += 1;
            buflen -= 1;
        }
        else {
            if (buflen < 4) {
                rv = APR_ENOSPC; /* overflow */
                break;
            }
            itr[0] = ((vallen >> 24) & 0xff) | 0x80;
            itr[1] = ((vallen >> 16) & 0xff);
            itr[2] = ((vallen >> 8) & 0xff);
            itr[3] = ((vallen) & 0xff);
            itr += 4;
            buflen -= 4;
        }

        if (buflen < keylen) {
            rv = APR_ENOSPC; /* overflow */
            break;
        }
        memcpy(itr, elts[i].key, keylen);
        itr += keylen;
        buflen -= keylen;

        if (buflen < vallen) {
            rv = APR_ENOSPC; /* overflow */
            break;
        }

        if (elts[i].val) {
            memcpy(itr, elts[i].val, vallen);
            itr += vallen;
        }

        if (buflen == vallen) {
            (*starting_elem)++;
            i++;
            break; /* filled up predicted space, as expected */
        }

        buflen -= vallen;

        (*starting_elem)++;
        i++;
    }

    if (rv != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02492)
                      "ap_fcgi_encode_env: out of space "
                      "encoding environment");
    }

    return rv;
}