|
|
5ea1d7 |
/**************************************************************/
|
|
|
5ea1d7 |
/* tpax: a topological pax implementation */
|
|
|
5ea1d7 |
/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
|
|
|
5ea1d7 |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
5ea1d7 |
/**************************************************************/
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
#include <regex.h>
|
|
|
5ea1d7 |
#include <stdlib.h>
|
|
|
5ea1d7 |
#include <string.h>
|
|
|
5ea1d7 |
#include <errno.h>
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
#include <tpax/tpax.h>
|
|
|
5ea1d7 |
#include "tpax_driver_impl.h"
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
static int tpax_backref_idx(const char c)
|
|
|
5ea1d7 |
{
|
|
|
5ea1d7 |
return ((c >= '1') && (c <= '9')) ? c - '0' : 0;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
int tpax_util_path_replstr(
|
|
|
5ea1d7 |
char * dstpath,
|
|
|
5ea1d7 |
const char * srcpath,
|
|
|
5ea1d7 |
const char * replstr,
|
|
|
5ea1d7 |
const regex_t * regex,
|
|
|
5ea1d7 |
size_t buflen,
|
|
|
5ea1d7 |
int flags)
|
|
|
5ea1d7 |
{
|
|
|
5ea1d7 |
int ret;
|
|
|
5ea1d7 |
int idx;
|
|
|
5ea1d7 |
regoff_t ro;
|
|
|
5ea1d7 |
const char * ch;
|
|
|
5ea1d7 |
char * dst;
|
|
|
5ea1d7 |
size_t explen;
|
|
|
5ea1d7 |
regmatch_t pmatch[11];
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* attempt to match */
|
|
|
5ea1d7 |
switch (regexec(regex,srcpath,11,pmatch,0)) {
|
|
|
5ea1d7 |
case 0:
|
|
|
5ea1d7 |
break;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
case REG_NOMATCH:
|
|
|
5ea1d7 |
return 0;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
default:
|
|
|
5ea1d7 |
return -1;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* copy bytes leading up to match */
|
|
|
5ea1d7 |
if (buflen <= (explen = pmatch[0].rm_so)) {
|
|
|
5ea1d7 |
errno = ENOBUFS;
|
|
|
5ea1d7 |
return -1;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
for (ro=0,dst=dstpath; ro
|
|
|
5ea1d7 |
*dst++ = srcpath[ro];
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
buflen -= explen;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* copy replacement string */
|
|
|
5ea1d7 |
for (ch=replstr,ret=0; buflen && *ch; ch++) {
|
|
|
5ea1d7 |
/* <ampersand> stands for the entire matched string */
|
|
|
5ea1d7 |
if (ch[0] == '&') {
|
|
|
5ea1d7 |
idx = 0;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* back-reference semantics: a matched subexpression or an empty string */
|
|
|
5ea1d7 |
} else if ((ch[0] == '\\') && (idx = tpax_backref_idx(ch[1]))) {
|
|
|
5ea1d7 |
if (pmatch[idx].rm_so < 0)
|
|
|
5ea1d7 |
idx = -1;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
ch++;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* all other escaped characters */
|
|
|
5ea1d7 |
} else if (ch[0] == '\\') {
|
|
|
5ea1d7 |
*dst++ = *++ch;
|
|
|
5ea1d7 |
idx = -1;
|
|
|
5ea1d7 |
buflen--;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* all other characters */
|
|
|
5ea1d7 |
} else {
|
|
|
5ea1d7 |
*dst++ = *ch;
|
|
|
5ea1d7 |
idx = -1;
|
|
|
5ea1d7 |
buflen--;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* copy matched string or matched subexpression, if any */
|
|
|
5ea1d7 |
if (idx >= 0) {
|
|
|
5ea1d7 |
if (buflen <= (explen = (pmatch[idx].rm_eo - pmatch[idx].rm_so))) {
|
|
|
5ea1d7 |
errno = ENOBUFS;
|
|
|
5ea1d7 |
return -1;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
for (ro=pmatch[idx].rm_so; ro
|
|
|
5ea1d7 |
*dst++ = srcpath[ro];
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
buflen -= explen;
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* replace further occurrences as needed */
|
|
|
5ea1d7 |
if ((flags & TPAX_REPL_GLOBAL) && srcpath[pmatch[0].rm_eo])
|
|
|
5ea1d7 |
ret = tpax_util_path_replstr(
|
|
|
5ea1d7 |
dst,&srcpath[pmatch[0].rm_eo],replstr,
|
|
|
5ea1d7 |
regex,buflen,flags);
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
if (ret < 0)
|
|
|
5ea1d7 |
return -1;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* copy remaining, non-matching bytes as needed */
|
|
|
5ea1d7 |
if (ret == 0) {
|
|
|
5ea1d7 |
for (ch=&srcpath[pmatch[0].rm_eo]; *ch; ch++)
|
|
|
5ea1d7 |
*dst++ = *ch;
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
*dst = '\0';
|
|
|
5ea1d7 |
}
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
/* all done */
|
|
|
5ea1d7 |
ret += (dst - dstpath);
|
|
|
5ea1d7 |
|
|
|
5ea1d7 |
return ret;
|
|
|
5ea1d7 |
}
|