Blame src/util/tpax_path_replstr.c

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
}