mirror of
https://github.com/apache/httpd.git
synced 2025-08-01 07:26:57 +03:00
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1901506 13f79535-47bb-0310-9956-ffa450edef68
1111 lines
30 KiB
C
1111 lines
30 KiB
C
/*
|
|
* Copyright (c) 2005, 2008 Sun Microsystems, Inc. All Rights Reserved.
|
|
* Use is subject to license terms.
|
|
*
|
|
* Copyright (c) 1984 AT&T
|
|
* All Rights Reserved
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
|
* or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "apr.h"
|
|
#include "apr_lib.h"
|
|
#include "libsed.h"
|
|
#include "sed.h"
|
|
#include "apr_strings.h"
|
|
#include "regexp.h"
|
|
|
|
static const char *const trans[040] = {
|
|
"\\01",
|
|
"\\02",
|
|
"\\03",
|
|
"\\04",
|
|
"\\05",
|
|
"\\06",
|
|
"\\07",
|
|
"\\10",
|
|
"\\11",
|
|
"\n",
|
|
"\\13",
|
|
"\\14",
|
|
"\\15",
|
|
"\\16",
|
|
"\\17",
|
|
"\\20",
|
|
"\\21",
|
|
"\\22",
|
|
"\\23",
|
|
"\\24",
|
|
"\\25",
|
|
"\\26",
|
|
"\\27",
|
|
"\\30",
|
|
"\\31",
|
|
"\\32",
|
|
"\\33",
|
|
"\\34",
|
|
"\\35",
|
|
"\\36",
|
|
"\\37"
|
|
};
|
|
static const char rub[] = {"\\177"};
|
|
|
|
extern int sed_step(char *p1, char *p2, int circf, step_vars_storage *vars);
|
|
static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
|
|
step_vars_storage *step_vars);
|
|
static apr_status_t execute(sed_eval_t *eval);
|
|
static int match(sed_eval_t *eval, char *expbuf, int gf,
|
|
step_vars_storage *step_vars);
|
|
static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
|
step_vars_storage *step_vars);
|
|
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
|
|
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
|
step_vars_storage *step_vars);
|
|
static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz);
|
|
static apr_status_t arout(sed_eval_t *eval);
|
|
|
|
static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
|
|
{
|
|
if (eval->errfn && eval->pool) {
|
|
va_list args;
|
|
const char* error;
|
|
va_start(args, fmt);
|
|
error = apr_pvsprintf(eval->pool, fmt, args);
|
|
eval->errfn(eval->data, error);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
#define INIT_BUF_SIZE 1024
|
|
#define MAX_BUF_SIZE 1024*8192
|
|
|
|
/*
|
|
* grow_buffer
|
|
*/
|
|
static apr_status_t grow_buffer(apr_pool_t *pool, char **buffer,
|
|
char **spend, apr_size_t *cursize,
|
|
apr_size_t newsize)
|
|
{
|
|
char* newbuffer = NULL;
|
|
apr_size_t spendsize = 0;
|
|
if (*cursize >= newsize) {
|
|
return APR_SUCCESS;
|
|
}
|
|
/* Avoid number of times realloc is called. It could cause huge memory
|
|
* requirement if line size is huge e.g 2 MB */
|
|
if (newsize < *cursize * 2) {
|
|
newsize = *cursize * 2;
|
|
}
|
|
|
|
/* Align it to 4 KB boundary */
|
|
newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) - 1);
|
|
if (newsize > MAX_BUF_SIZE) {
|
|
return APR_ENOMEM;
|
|
}
|
|
newbuffer = apr_pcalloc(pool, newsize);
|
|
if (*spend && *buffer && (*cursize > 0)) {
|
|
spendsize = *spend - *buffer;
|
|
}
|
|
if ((*cursize > 0) && *buffer) {
|
|
memcpy(newbuffer, *buffer, *cursize);
|
|
}
|
|
*buffer = newbuffer;
|
|
*cursize = newsize;
|
|
if (spend != buffer) {
|
|
*spend = *buffer + spendsize;
|
|
}
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* grow_line_buffer
|
|
*/
|
|
static apr_status_t grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
|
|
{
|
|
return grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
|
|
&eval->lsize, newsize);
|
|
}
|
|
|
|
/*
|
|
* grow_hold_buffer
|
|
*/
|
|
static apr_status_t grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
|
|
{
|
|
return grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
|
|
&eval->hsize, newsize);
|
|
}
|
|
|
|
/*
|
|
* grow_gen_buffer
|
|
*/
|
|
static apr_status_t grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
|
|
char **gspend)
|
|
{
|
|
apr_status_t rc = 0;
|
|
if (gspend == NULL) {
|
|
gspend = &eval->genbuf;
|
|
}
|
|
rc = grow_buffer(eval->pool, &eval->genbuf, gspend,
|
|
&eval->gsize, newsize);
|
|
if (rc == APR_SUCCESS) {
|
|
eval->lcomend = &eval->genbuf[71];
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* appendmem_to_linebuf
|
|
*/
|
|
static apr_status_t appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
|
|
{
|
|
apr_status_t rc = 0;
|
|
apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
|
|
if (eval->lsize < reqsize) {
|
|
rc = grow_line_buffer(eval, reqsize);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
memcpy(eval->lspend, sz, len);
|
|
eval->lspend += len;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* append_to_linebuf
|
|
*/
|
|
static apr_status_t append_to_linebuf(sed_eval_t *eval, const char* sz,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
apr_size_t len = strlen(sz);
|
|
char *old_linebuf = eval->linebuf;
|
|
apr_status_t rc = 0;
|
|
/* Copy string including null character */
|
|
rc = appendmem_to_linebuf(eval, sz, len + 1);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
--eval->lspend; /* lspend will now point to NULL character */
|
|
/* Sync step_vars after a possible linebuf expansion */
|
|
if (step_vars && old_linebuf != eval->linebuf) {
|
|
if (step_vars->loc1) {
|
|
step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf;
|
|
}
|
|
if (step_vars->loc2) {
|
|
step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf;
|
|
}
|
|
if (step_vars->locs) {
|
|
step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
|
|
}
|
|
}
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* copy_to_linebuf
|
|
*/
|
|
static apr_status_t copy_to_linebuf(sed_eval_t *eval, const char* sz,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
eval->lspend = eval->linebuf;
|
|
return append_to_linebuf(eval, sz, step_vars);
|
|
}
|
|
|
|
/*
|
|
* append_to_holdbuf
|
|
*/
|
|
static apr_status_t append_to_holdbuf(sed_eval_t *eval, const char* sz)
|
|
{
|
|
apr_size_t len = strlen(sz);
|
|
apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
|
|
apr_status_t rc = 0;
|
|
if (eval->hsize <= reqsize) {
|
|
rc = grow_hold_buffer(eval, reqsize);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
memcpy(eval->hspend, sz, len + 1);
|
|
/* hspend will now point to NULL character */
|
|
eval->hspend += len;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* copy_to_holdbuf
|
|
*/
|
|
static apr_status_t copy_to_holdbuf(sed_eval_t *eval, const char* sz)
|
|
{
|
|
eval->hspend = eval->holdbuf;
|
|
return append_to_holdbuf(eval, sz);
|
|
}
|
|
|
|
/*
|
|
* append_to_genbuf
|
|
*/
|
|
static apr_status_t append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
|
|
{
|
|
apr_size_t len = strlen(sz);
|
|
apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
|
|
apr_status_t rc = 0;
|
|
if (eval->gsize < reqsize) {
|
|
rc = grow_gen_buffer(eval, reqsize, gspend);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
memcpy(*gspend, sz, len + 1);
|
|
/* *gspend will now point to NULL character */
|
|
*gspend += len;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* copy_to_genbuf
|
|
*/
|
|
static apr_status_t copy_to_genbuf(sed_eval_t *eval, const char* sz)
|
|
{
|
|
apr_size_t len = strlen(sz);
|
|
apr_size_t reqsize = len + 1;
|
|
apr_status_t rc = APR_SUCCESS;;
|
|
if (eval->gsize < reqsize) {
|
|
rc = grow_gen_buffer(eval, reqsize, NULL);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
memcpy(eval->genbuf, sz, len + 1);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* sed_init_eval
|
|
*/
|
|
apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data, sed_write_fn_t *writefn, apr_pool_t* p)
|
|
{
|
|
memset(eval, 0, sizeof(*eval));
|
|
eval->pool = p;
|
|
eval->writefn = writefn;
|
|
return sed_reset_eval(eval, commands, errfn, data);
|
|
}
|
|
|
|
/*
|
|
* sed_reset_eval
|
|
*/
|
|
apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data)
|
|
{
|
|
int i;
|
|
|
|
eval->errfn = errfn;
|
|
eval->data = data;
|
|
|
|
eval->commands = commands;
|
|
|
|
eval->lnum = 0;
|
|
eval->fout = NULL;
|
|
|
|
if (eval->linebuf == NULL) {
|
|
eval->lsize = INIT_BUF_SIZE;
|
|
eval->linebuf = apr_pcalloc(eval->pool, eval->lsize);
|
|
}
|
|
if (eval->holdbuf == NULL) {
|
|
eval->hsize = INIT_BUF_SIZE;
|
|
eval->holdbuf = apr_pcalloc(eval->pool, eval->hsize);
|
|
}
|
|
if (eval->genbuf == NULL) {
|
|
eval->gsize = INIT_BUF_SIZE;
|
|
eval->genbuf = apr_pcalloc(eval->pool, eval->gsize);
|
|
}
|
|
eval->lspend = eval->linebuf;
|
|
eval->hspend = eval->holdbuf;
|
|
eval->lcomend = &eval->genbuf[71];
|
|
|
|
for (i = 0; i < sizeof(eval->abuf) / sizeof(eval->abuf[0]); i++)
|
|
eval->abuf[i] = NULL;
|
|
eval->aptr = eval->abuf;
|
|
eval->pending = NULL;
|
|
eval->inar = apr_pcalloc(eval->pool, commands->nrep * sizeof(unsigned char));
|
|
eval->nrep = commands->nrep;
|
|
|
|
eval->dolflag = 0;
|
|
eval->sflag = 0;
|
|
eval->jflag = 0;
|
|
eval->delflag = 0;
|
|
eval->lreadyflag = 0;
|
|
eval->quitflag = 0;
|
|
eval->finalflag = 1; /* assume we're evaluating only one file/stream */
|
|
eval->numpass = 0;
|
|
eval->nullmatch = 0;
|
|
eval->col = 0;
|
|
|
|
for (i = 0; i < commands->nfiles; i++) {
|
|
const char* filename = commands->fname[i];
|
|
if (apr_file_open(&eval->fcode[i], filename,
|
|
APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
|
|
eval->pool) != APR_SUCCESS) {
|
|
eval_errf(eval, SEDERR_COMES, filename);
|
|
return APR_EGENERAL;
|
|
}
|
|
}
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* sed_destroy_eval
|
|
*/
|
|
void sed_destroy_eval(sed_eval_t *eval)
|
|
{
|
|
int i;
|
|
/* eval->linebuf, eval->holdbuf, eval->genbuf and eval->inar are allocated
|
|
* on pool. It will be freed when pool will be freed */
|
|
for (i = 0; i < eval->commands->nfiles; i++) {
|
|
if (eval->fcode[i] != NULL) {
|
|
apr_file_close(eval->fcode[i]);
|
|
eval->fcode[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* sed_eval_file
|
|
*/
|
|
apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
|
|
{
|
|
for (;;) {
|
|
char buf[1024];
|
|
apr_size_t read_bytes = 0;
|
|
|
|
read_bytes = sizeof(buf);
|
|
if (apr_file_read(fin, buf, &read_bytes) != APR_SUCCESS)
|
|
break;
|
|
|
|
if (sed_eval_buffer(eval, buf, read_bytes, fout) != APR_SUCCESS)
|
|
return APR_EGENERAL;
|
|
|
|
if (eval->quitflag)
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
return sed_finalize_eval(eval, fout);
|
|
}
|
|
|
|
/*
|
|
* sed_eval_buffer
|
|
*/
|
|
apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout)
|
|
{
|
|
apr_status_t rv;
|
|
|
|
if (eval->quitflag)
|
|
return APR_SUCCESS;
|
|
|
|
if (!sed_canbe_finalized(eval->commands)) {
|
|
/* Commands were not finalized properly. */
|
|
const char* error = sed_get_finalize_error(eval->commands, eval->pool);
|
|
if (error) {
|
|
eval_errf(eval, error);
|
|
return APR_EGENERAL;
|
|
}
|
|
}
|
|
|
|
eval->fout = fout;
|
|
|
|
/* Process leftovers */
|
|
if (bufsz && eval->lreadyflag) {
|
|
eval->lreadyflag = 0;
|
|
eval->lspend--;
|
|
*eval->lspend = '\0';
|
|
rv = execute(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
while (bufsz) {
|
|
apr_status_t rc = 0;
|
|
char *n;
|
|
apr_size_t llen;
|
|
|
|
n = memchr(buf, '\n', bufsz);
|
|
if (n == NULL)
|
|
break;
|
|
|
|
llen = n - buf;
|
|
if (llen == bufsz - 1) {
|
|
/* This might be the last line; delay its processing */
|
|
eval->lreadyflag = 1;
|
|
break;
|
|
}
|
|
|
|
rc = appendmem_to_linebuf(eval, buf, llen + 1);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
--eval->lspend;
|
|
/* replace new line character with NULL */
|
|
*eval->lspend = '\0';
|
|
buf += (llen + 1);
|
|
bufsz -= (llen + 1);
|
|
rv = execute(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
if (eval->quitflag)
|
|
break;
|
|
}
|
|
|
|
/* Save the leftovers for later */
|
|
if (bufsz) {
|
|
apr_status_t rc = appendmem_to_linebuf(eval, buf, bufsz);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* sed_finalize_eval
|
|
*/
|
|
apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout)
|
|
{
|
|
if (eval->quitflag)
|
|
return APR_SUCCESS;
|
|
|
|
if (eval->finalflag)
|
|
eval->dolflag = 1;
|
|
|
|
eval->fout = fout;
|
|
|
|
/* Process leftovers */
|
|
if (eval->lspend > eval->linebuf) {
|
|
apr_status_t rv;
|
|
apr_status_t rc = 0;
|
|
|
|
if (eval->lreadyflag) {
|
|
eval->lreadyflag = 0;
|
|
eval->lspend--;
|
|
} else {
|
|
/* Code can probably reach here when last character in output
|
|
* buffer is not a newline.
|
|
*/
|
|
/* Assure space for NULL */
|
|
rc = append_to_linebuf(eval, "", NULL);
|
|
if (rc != APR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
*eval->lspend = '\0';
|
|
rv = execute(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
eval->quitflag = 1;
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* execute
|
|
*/
|
|
static apr_status_t execute(sed_eval_t *eval)
|
|
{
|
|
sed_reptr_t *ipc = eval->commands->ptrspace;
|
|
step_vars_storage step_vars;
|
|
apr_status_t rv = APR_SUCCESS;
|
|
|
|
eval->lnum++;
|
|
|
|
eval->sflag = 0;
|
|
|
|
if (eval->pending) {
|
|
ipc = eval->pending;
|
|
eval->pending = NULL;
|
|
}
|
|
|
|
memset(&step_vars, 0, sizeof(step_vars));
|
|
|
|
while (ipc->command) {
|
|
char *p1;
|
|
char *p2;
|
|
int c;
|
|
|
|
p1 = ipc->ad1;
|
|
p2 = ipc->ad2;
|
|
|
|
if (p1) {
|
|
|
|
if (eval->inar[ipc->nrep]) {
|
|
if (*p2 == CEND) {
|
|
p1 = 0;
|
|
} else if (*p2 == CLNUM) {
|
|
c = (unsigned char)p2[1];
|
|
if (eval->lnum > eval->commands->tlno[c]) {
|
|
eval->inar[ipc->nrep] = 0;
|
|
if (ipc->negfl)
|
|
goto yes;
|
|
ipc = ipc->next;
|
|
continue;
|
|
}
|
|
if (eval->lnum == eval->commands->tlno[c]) {
|
|
eval->inar[ipc->nrep] = 0;
|
|
}
|
|
} else if (match(eval, p2, 0, &step_vars)) {
|
|
eval->inar[ipc->nrep] = 0;
|
|
}
|
|
} else if (*p1 == CEND) {
|
|
if (!eval->dolflag) {
|
|
if (ipc->negfl)
|
|
goto yes;
|
|
ipc = ipc->next;
|
|
continue;
|
|
}
|
|
} else if (*p1 == CLNUM) {
|
|
c = (unsigned char)p1[1];
|
|
if (eval->lnum != eval->commands->tlno[c]) {
|
|
if (ipc->negfl)
|
|
goto yes;
|
|
ipc = ipc->next;
|
|
continue;
|
|
}
|
|
if (p2)
|
|
eval->inar[ipc->nrep] = 1;
|
|
} else if (match(eval, p1, 0, &step_vars)) {
|
|
if (p2)
|
|
eval->inar[ipc->nrep] = 1;
|
|
} else {
|
|
if (ipc->negfl)
|
|
goto yes;
|
|
ipc = ipc->next;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (ipc->negfl) {
|
|
ipc = ipc->next;
|
|
continue;
|
|
}
|
|
|
|
yes:
|
|
rv = command(eval, ipc, &step_vars);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
|
|
if (eval->quitflag)
|
|
return APR_SUCCESS;
|
|
|
|
if (eval->pending)
|
|
return APR_SUCCESS;
|
|
|
|
if (eval->delflag)
|
|
break;
|
|
|
|
if (eval->jflag) {
|
|
eval->jflag = 0;
|
|
if ((ipc = ipc->lb1) == 0) {
|
|
ipc = eval->commands->ptrspace;
|
|
break;
|
|
}
|
|
} else
|
|
ipc = ipc->next;
|
|
}
|
|
|
|
if (!eval->commands->nflag && !eval->delflag) {
|
|
rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
if (eval->aptr > eval->abuf)
|
|
rv = arout(eval);
|
|
|
|
eval->delflag = 0;
|
|
|
|
eval->lspend = eval->linebuf;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* match
|
|
*/
|
|
static int match(sed_eval_t *eval, char *expbuf, int gf,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
char *p1;
|
|
int circf;
|
|
|
|
if (gf) {
|
|
if (*expbuf) return(0);
|
|
step_vars->locs = p1 = step_vars->loc2;
|
|
} else {
|
|
p1 = eval->linebuf;
|
|
step_vars->locs = 0;
|
|
}
|
|
|
|
circf = *expbuf++;
|
|
return(sed_step(p1, expbuf, circf, step_vars));
|
|
}
|
|
|
|
/*
|
|
* substitute
|
|
*/
|
|
static int substitute(sed_eval_t *eval, sed_reptr_t *ipc,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
if (match(eval, ipc->re1, 0, step_vars) == 0) return(0);
|
|
|
|
eval->numpass = 0;
|
|
eval->sflag = 0; /* Flags if any substitution was made */
|
|
if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
|
|
return -1;
|
|
|
|
if (ipc->gfl) {
|
|
while (*step_vars->loc2) {
|
|
if (match(eval, ipc->re1, 1, step_vars) == 0) break;
|
|
if (dosub(eval, ipc->rhs, ipc->gfl, step_vars) != APR_SUCCESS)
|
|
return -1;
|
|
}
|
|
}
|
|
return(eval->sflag);
|
|
}
|
|
|
|
/*
|
|
* dosub
|
|
*/
|
|
static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
char *lp, *sp, *rp;
|
|
int c;
|
|
apr_status_t rv = APR_SUCCESS;
|
|
|
|
if (n > 0 && n < 999) {
|
|
eval->numpass++;
|
|
if (n != eval->numpass) return APR_SUCCESS;
|
|
}
|
|
eval->sflag = 1;
|
|
lp = eval->linebuf;
|
|
sp = eval->genbuf;
|
|
rp = rhsbuf;
|
|
sp = place(eval, sp, lp, step_vars->loc1);
|
|
if (sp == NULL) {
|
|
return APR_EGENERAL;
|
|
}
|
|
while ((c = *rp++) != 0) {
|
|
if (c == '&') {
|
|
sp = place(eval, sp, step_vars->loc1, step_vars->loc2);
|
|
if (sp == NULL) {
|
|
return APR_EGENERAL;
|
|
}
|
|
}
|
|
else if (c == '\\') {
|
|
c = *rp++;
|
|
if (c >= '1' && c < NBRA+'1') {
|
|
sp = place(eval, sp, step_vars->braslist[c-'1'],
|
|
step_vars->braelist[c-'1']);
|
|
if (sp == NULL)
|
|
return APR_EGENERAL;
|
|
}
|
|
else
|
|
*sp++ = c;
|
|
} else
|
|
*sp++ = c;
|
|
if (sp >= eval->genbuf + eval->gsize) {
|
|
/* expand genbuf and set the sp appropriately */
|
|
rv = grow_gen_buffer(eval, eval->gsize + 1024, &sp);
|
|
if (rv != APR_SUCCESS) {
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
lp = step_vars->loc2;
|
|
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
|
|
rv = append_to_genbuf(eval, lp, &sp);
|
|
if (rv != APR_SUCCESS) {
|
|
return rv;
|
|
}
|
|
rv = copy_to_linebuf(eval, eval->genbuf, step_vars);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* place
|
|
*/
|
|
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
|
|
{
|
|
char *sp = asp;
|
|
apr_size_t n = al2 - al1;
|
|
apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
|
|
|
|
if (eval->gsize < reqsize) {
|
|
apr_status_t rc = grow_gen_buffer(eval, reqsize, &sp);
|
|
if (rc != APR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
}
|
|
memcpy(sp, al1, n);
|
|
return sp + n;
|
|
}
|
|
|
|
/*
|
|
* command
|
|
*/
|
|
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
|
|
step_vars_storage *step_vars)
|
|
{
|
|
int i;
|
|
char *p1, *p2;
|
|
const char *p3;
|
|
int length;
|
|
char sz[32]; /* 32 bytes enough to store 64 bit integer in decimal */
|
|
apr_status_t rv = APR_SUCCESS;
|
|
|
|
|
|
switch(ipc->command) {
|
|
|
|
case ACOM:
|
|
if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
|
|
eval_errf(eval, SEDERR_TMAMES, eval->lnum);
|
|
} else {
|
|
*eval->aptr++ = ipc;
|
|
*eval->aptr = NULL;
|
|
}
|
|
break;
|
|
|
|
case CCOM:
|
|
eval->delflag = 1;
|
|
if (!eval->inar[ipc->nrep] || eval->dolflag) {
|
|
for (p1 = ipc->re1; *p1; p1++)
|
|
;
|
|
rv = wline(eval, ipc->re1, p1 - ipc->re1);
|
|
}
|
|
break;
|
|
|
|
case DCOM:
|
|
eval->delflag++;
|
|
break;
|
|
|
|
case CDCOM:
|
|
p1 = eval->linebuf;
|
|
|
|
while (*p1 != '\n') {
|
|
if (*p1++ == 0) {
|
|
eval->delflag++;
|
|
return APR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
p1++;
|
|
rv = copy_to_linebuf(eval, p1, step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
eval->jflag++;
|
|
break;
|
|
|
|
case EQCOM:
|
|
length = apr_snprintf(sz, sizeof(sz), "%d", (int) eval->lnum);
|
|
rv = wline(eval, sz, length);
|
|
break;
|
|
|
|
case GCOM:
|
|
rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
break;
|
|
|
|
case CGCOM:
|
|
rv = append_to_linebuf(eval, "\n", step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
rv = append_to_linebuf(eval, eval->holdbuf, step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
break;
|
|
|
|
case HCOM:
|
|
rv = copy_to_holdbuf(eval, eval->linebuf);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
break;
|
|
|
|
case CHCOM:
|
|
rv = append_to_holdbuf(eval, "\n");
|
|
if (rv != APR_SUCCESS) return rv;
|
|
rv = append_to_holdbuf(eval, eval->linebuf);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
break;
|
|
|
|
case ICOM:
|
|
for (p1 = ipc->re1; *p1; p1++);
|
|
rv = wline(eval, ipc->re1, p1 - ipc->re1);
|
|
break;
|
|
|
|
case BCOM:
|
|
eval->jflag = 1;
|
|
break;
|
|
|
|
case LCOM:
|
|
p1 = eval->linebuf;
|
|
p2 = eval->genbuf;
|
|
eval->genbuf[72] = 0;
|
|
while (*p1) {
|
|
if ((unsigned char)*p1 >= 040) {
|
|
if (*p1 == 0177) {
|
|
p3 = rub;
|
|
while ((*p2++ = *p3++) != 0)
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
p2--;
|
|
p1++;
|
|
continue;
|
|
}
|
|
if (!isprint(*p1 & 0377)) {
|
|
*p2++ = '\\';
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
*p2++ = (*p1 >> 6) + '0';
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
*p2++ = ((*p1 >> 3) & 07) + '0';
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
*p2++ = (*p1++ & 07) + '0';
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
} else {
|
|
*p2++ = *p1++;
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
}
|
|
} else {
|
|
p3 = trans[(unsigned char)*p1-1];
|
|
while ((*p2++ = *p3++) != 0)
|
|
if (p2 >= eval->lcomend) {
|
|
*p2 = '\\';
|
|
rv = wline(eval, eval->genbuf,
|
|
strlen(eval->genbuf));
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
p2 = eval->genbuf;
|
|
}
|
|
p2--;
|
|
p1++;
|
|
}
|
|
}
|
|
*p2 = 0;
|
|
rv = wline(eval, eval->genbuf, strlen(eval->genbuf));
|
|
break;
|
|
|
|
case NCOM:
|
|
if (!eval->commands->nflag) {
|
|
rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
if (eval->aptr > eval->abuf) {
|
|
rv = arout(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
eval->lspend = eval->linebuf;
|
|
eval->pending = ipc->next;
|
|
break;
|
|
|
|
case CNCOM:
|
|
if (eval->aptr > eval->abuf) {
|
|
rv = arout(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
rv = append_to_linebuf(eval, "\n", step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
eval->pending = ipc->next;
|
|
break;
|
|
|
|
case PCOM:
|
|
rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
|
|
break;
|
|
|
|
case CPCOM:
|
|
for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
|
|
rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
|
|
break;
|
|
|
|
case QCOM:
|
|
if (!eval->commands->nflag) {
|
|
rv = wline(eval, eval->linebuf, eval->lspend - eval->linebuf);
|
|
if (rv != APR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
if (eval->aptr > eval->abuf) {
|
|
rv = arout(eval);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
|
|
eval->quitflag = 1;
|
|
break;
|
|
|
|
case RCOM:
|
|
if (eval->aptr >= &eval->abuf[SED_ABUFSIZE]) {
|
|
eval_errf(eval, SEDERR_TMRMES, eval->lnum);
|
|
} else {
|
|
*eval->aptr++ = ipc;
|
|
*eval->aptr = NULL;
|
|
}
|
|
break;
|
|
|
|
case SCOM:
|
|
i = substitute(eval, ipc, step_vars);
|
|
if (i == -1) {
|
|
return APR_EGENERAL;
|
|
}
|
|
if (ipc->pfl && eval->commands->nflag && i) {
|
|
if (ipc->pfl == 1) {
|
|
rv = wline(eval, eval->linebuf, eval->lspend -
|
|
eval->linebuf);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
} else {
|
|
for (p1 = eval->linebuf; *p1 != '\n' && *p1 != '\0'; p1++);
|
|
rv = wline(eval, eval->linebuf, p1 - eval->linebuf);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
}
|
|
}
|
|
if (i && (ipc->findex >= 0) && eval->fcode[ipc->findex])
|
|
apr_file_printf(eval->fcode[ipc->findex], "%s\n",
|
|
eval->linebuf);
|
|
break;
|
|
|
|
case TCOM:
|
|
if (eval->sflag == 0) break;
|
|
eval->sflag = 0;
|
|
eval->jflag = 1;
|
|
break;
|
|
|
|
case WCOM:
|
|
if (ipc->findex >= 0)
|
|
apr_file_printf(eval->fcode[ipc->findex], "%s\n",
|
|
eval->linebuf);
|
|
break;
|
|
|
|
case XCOM:
|
|
rv = copy_to_genbuf(eval, eval->linebuf);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
rv = copy_to_linebuf(eval, eval->holdbuf, step_vars);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
rv = copy_to_holdbuf(eval, eval->genbuf);
|
|
if (rv != APR_SUCCESS) return rv;
|
|
break;
|
|
|
|
case YCOM:
|
|
p1 = eval->linebuf;
|
|
p2 = ipc->re1;
|
|
while ((*p1 = p2[(unsigned char)*p1]) != 0) p1++;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* arout
|
|
*/
|
|
static apr_status_t arout(sed_eval_t *eval)
|
|
{
|
|
apr_status_t rv = APR_SUCCESS;
|
|
eval->aptr = eval->abuf - 1;
|
|
while (*++eval->aptr) {
|
|
if ((*eval->aptr)->command == ACOM) {
|
|
char *p1;
|
|
|
|
for (p1 = (*eval->aptr)->re1; *p1; p1++);
|
|
rv = wline(eval, (*eval->aptr)->re1, p1 - (*eval->aptr)->re1);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
} else {
|
|
apr_file_t *fi = NULL;
|
|
char buf[512];
|
|
apr_size_t n = sizeof(buf);
|
|
|
|
if (apr_file_open(&fi, (*eval->aptr)->re1, APR_READ, 0, eval->pool)
|
|
!= APR_SUCCESS)
|
|
continue;
|
|
while ((apr_file_read(fi, buf, &n)) == APR_SUCCESS) {
|
|
if (n == 0)
|
|
break;
|
|
rv = eval->writefn(eval->fout, buf, n);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_file_close(fi);
|
|
return rv;
|
|
}
|
|
n = sizeof(buf);
|
|
}
|
|
apr_file_close(fi);
|
|
}
|
|
}
|
|
eval->aptr = eval->abuf;
|
|
*eval->aptr = NULL;
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* wline
|
|
*/
|
|
static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz)
|
|
{
|
|
apr_status_t rv = APR_SUCCESS;
|
|
rv = eval->writefn(eval->fout, buf, sz);
|
|
if (rv != APR_SUCCESS)
|
|
return rv;
|
|
rv = eval->writefn(eval->fout, "\n", 1);
|
|
return rv;
|
|
}
|
|
|