version 1.80, 2023/10/28 22:38:22 |
version 1.81, 2023/11/22 01:01:21 |
|
|
|
|
void backsub(char **pb_ptr, const char **sptr_ptr); |
void backsub(char **pb_ptr, const char **sptr_ptr); |
|
|
Cell *sub(Node **a, int nnn) /* substitute command */ |
Cell *dosub(Node **a, int subop) /* sub and gsub */ |
{ |
{ |
const char *sptr, *q; |
|
Cell *x, *y, *result; |
|
char *t, *buf, *pb; |
|
fa *pfa; |
fa *pfa; |
|
int tempstat; |
|
char *repl; |
|
Cell *x; |
|
|
|
char *buf = NULL; |
|
char *pb = NULL; |
int bufsz = recsize; |
int bufsz = recsize; |
|
|
if ((buf = (char *) malloc(bufsz)) == NULL) |
const char *r, *s; |
FATAL("out of memory in sub"); |
const char *start; |
x = execute(a[3]); /* target string */ |
const char *noempty = NULL; /* empty match disallowed here */ |
t = getsval(x); |
size_t m = 0; /* match count */ |
if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */ |
size_t whichm; /* which match to select, 0 = global */ |
pfa = (fa *) a[1]; /* regular expression */ |
int mtype; /* match type */ |
else { |
|
y = execute(a[1]); |
if (a[0] == NULL) { /* 0 => a[1] is already-compiled regexpr */ |
pfa = makedfa(getsval(y), 1); |
pfa = (fa *) a[1]; |
tempfree(y); |
} else { |
|
x = execute(a[1]); |
|
pfa = makedfa(getsval(x), 1); |
|
tempfree(x); |
} |
} |
y = execute(a[2]); /* replacement string */ |
|
result = False; |
x = execute(a[2]); /* replacement string */ |
if (pmatch(pfa, t)) { |
repl = tostring(getsval(x)); |
sptr = t; |
tempfree(x); |
adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); |
|
pb = buf; |
switch (subop) { |
while (sptr < patbeg) |
case SUB: |
*pb++ = *sptr++; |
whichm = 1; |
sptr = getsval(y); |
x = execute(a[3]); /* source string */ |
while (*sptr != '\0') { |
break; |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); |
case GSUB: |
if (*sptr == '\\') { |
whichm = 0; |
backsub(&pb, &sptr); |
x = execute(a[3]); /* source string */ |
} else if (*sptr == '&') { |
break; |
sptr++; |
default: |
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); |
FATAL("dosub: unrecognized subop: %d", subop); |
for (q = patbeg; q < patbeg+patlen; ) |
} |
*pb++ = *q++; |
|
} else |
start = getsval(x); |
*pb++ = *sptr++; |
while (pmatch(pfa, start)) { |
|
if (buf == NULL) { |
|
if ((pb = buf = malloc(bufsz)) == NULL) |
|
FATAL("out of memory in dosub"); |
|
tempstat = pfa->initstat; |
|
pfa->initstat = 2; |
} |
} |
*pb = '\0'; |
|
if (pb > buf + bufsz) |
/* match types */ |
FATAL("sub result1 %.30s too big; can't happen", buf); |
#define MT_IGNORE 0 /* unselected or invalid */ |
sptr = patbeg + patlen; |
#define MT_INSERT 1 /* selected, empty */ |
if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { |
#define MT_REPLACE 2 /* selected, not empty */ |
adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); |
|
while ((*pb++ = *sptr++) != '\0') |
/* an empty match just after replacement is invalid */ |
continue; |
|
|
if (patbeg == noempty && patlen == 0) { |
|
mtype = MT_IGNORE; /* invalid, not counted */ |
|
} else if (whichm == ++m || whichm == 0) { |
|
mtype = patlen ? MT_REPLACE : MT_INSERT; |
|
} else { |
|
mtype = MT_IGNORE; /* unselected, but counted */ |
} |
} |
if (pb > buf + bufsz) |
|
FATAL("sub result2 %.30s too big; can't happen", buf); |
|
setsval(x, buf); /* BUG: should be able to avoid copy */ |
|
result = True; |
|
} |
|
tempfree(x); |
|
tempfree(y); |
|
free(buf); |
|
return result; |
|
} |
|
|
|
Cell *gsub(Node **a, int nnn) /* global substitute */ |
/* leading text: */ |
{ |
if (patbeg > start) { |
Cell *x, *y; |
adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - start), |
char *rptr, *pb; |
recsize, &pb, "dosub"); |
const char *q, *t, *sptr; |
s = start; |
char *buf; |
while (s < patbeg) |
fa *pfa; |
*pb++ = *s++; |
int mflag, tempstat, num; |
} |
int bufsz = recsize; |
|
int charlen = 0; |
|
|
|
if ((buf = (char *) malloc(bufsz)) == NULL) |
if (mtype == MT_IGNORE) |
FATAL("out of memory in gsub"); |
goto matching_text; /* skip replacement text */ |
mflag = 0; /* if mflag == 0, can replace empty string */ |
|
num = 0; |
r = repl; |
x = execute(a[3]); /* target string */ |
while (*r != 0) { |
t = getsval(x); |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "dosub"); |
if (a[0] == NULL) /* 0 => a[1] is already-compiled regexpr */ |
if (*r == '\\') { |
pfa = (fa *) a[1]; /* regular expression */ |
backsub(&pb, &r); |
else { |
} else if (*r == '&') { |
y = execute(a[1]); |
r++; |
pfa = makedfa(getsval(y), 1); |
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, |
tempfree(y); |
&pb, "dosub"); |
} |
for (s = patbeg; s < patbeg+patlen; ) |
y = execute(a[2]); /* replacement string */ |
*pb++ = *s++; |
if (pmatch(pfa, t)) { |
} else { |
tempstat = pfa->initstat; |
*pb++ = *r++; |
pfa->initstat = 2; |
|
pb = buf; |
|
rptr = getsval(y); |
|
do { |
|
if (patlen == 0 && *patbeg != '\0') { /* matched empty string */ |
|
if (mflag == 0) { /* can replace empty */ |
|
num++; |
|
sptr = rptr; |
|
while (*sptr != '\0') { |
|
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); |
|
if (*sptr == '\\') { |
|
backsub(&pb, &sptr); |
|
} else if (*sptr == '&') { |
|
sptr++; |
|
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); |
|
for (q = patbeg; q < patbeg+patlen; ) |
|
*pb++ = *q++; |
|
} else |
|
*pb++ = *sptr++; |
|
} |
|
} |
|
if (*t == '\0') /* at end */ |
|
goto done; |
|
adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); |
|
charlen = u8_nextlen(t); |
|
while (charlen-- > 0) |
|
*pb++ = *t++; |
|
if (pb > buf + bufsz) /* BUG: not sure of this test */ |
|
FATAL("gsub result0 %.30s too big; can't happen", buf); |
|
mflag = 0; |
|
} |
} |
else { /* matched nonempty string */ |
} |
num++; |
|
sptr = t; |
matching_text: |
adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); |
if (mtype == MT_REPLACE || *patbeg == '\0') |
while (sptr < patbeg) |
goto next_search; /* skip matching text */ |
*pb++ = *sptr++; |
|
sptr = rptr; |
if (patlen == 0) |
while (*sptr != '\0') { |
patlen = u8_nextlen(patbeg); |
adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); |
adjbuf(&buf, &bufsz, (pb-buf) + patlen, recsize, &pb, "dosub"); |
if (*sptr == '\\') { |
s = patbeg; |
backsub(&pb, &sptr); |
while (s < patbeg + patlen) |
} else if (*sptr == '&') { |
*pb++ = *s++; |
sptr++; |
|
adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); |
next_search: |
for (q = patbeg; q < patbeg+patlen; ) |
start = patbeg + patlen; |
*pb++ = *q++; |
if (m == whichm || *patbeg == '\0') |
} else |
break; |
*pb++ = *sptr++; |
if (mtype == MT_REPLACE) |
} |
noempty = start; |
t = patbeg + patlen; |
|
if (patlen == 0 || *t == '\0' || *(t-1) == '\0') |
#undef MT_IGNORE |
goto done; |
#undef MT_INSERT |
if (pb > buf + bufsz) |
#undef MT_REPLACE |
FATAL("gsub result1 %.30s too big; can't happen", buf); |
} |
mflag = 1; |
|
} |
xfree(repl); |
} while (pmatch(pfa,t)); |
|
sptr = t; |
if (buf != NULL) { |
adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); |
|
while ((*pb++ = *sptr++) != '\0') |
|
continue; |
|
done: if (pb < buf + bufsz) |
|
*pb = '\0'; |
|
else if (*(pb-1) != '\0') |
|
FATAL("gsub result2 %.30s truncated; can't happen", buf); |
|
setsval(x, buf); /* BUG: should be able to avoid copy + free */ |
|
pfa->initstat = tempstat; |
pfa->initstat = tempstat; |
|
|
|
/* trailing text */ |
|
adjbuf(&buf, &bufsz, 1+strlen(start)+pb-buf, 0, &pb, "dosub"); |
|
while ((*pb++ = *start++) != '\0') |
|
; |
|
|
|
setsval(x, buf); |
|
free(buf); |
} |
} |
|
|
tempfree(x); |
tempfree(x); |
tempfree(y); |
|
x = gettemp(); |
x = gettemp(); |
x->tval = NUM; |
x->tval = NUM; |
x->fval = num; |
x->fval = m; |
free(buf); |
return x; |
return(x); |
|
} |
} |
|
|
Cell *gensub(Node **a, int nnn) /* global selective substitute */ |
Cell *gensub(Node **a, int nnn) /* global selective substitute */ |