#ifndef __SYMBIAN32__
/*
* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
/*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1999 Sven Wischnowsky
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Sven Wischnowsky or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Sven Wischnowsky and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Sven Wischnowsky and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#include "zutil.mdh"
#include "zutil.pro"
#ifdef __SYMBIAN32__
#ifdef __WINSCW__
#pragma warn_unusedarg off
#pragma warn_possunwant off
#endif//__WINSCW__
#endif//__SYMBIAN32__
/* Style stuff. */
typedef struct stypat *Stypat;
typedef struct style *Style;
/* A pattern and the styles for it. */
struct style {
Style next; /* next in stypat list */
Stypat pats; /* patterns */
char *name;
};
struct stypat {
Stypat next;
char *pat; /* pattern string */
Patprog prog; /* compiled pattern */
int weight; /* how specific is the pattern? */
Eprog eval; /* eval-on-retrieve? */
char **vals;
};
/* List of styles. */
static Style zstyles, zlstyles;
/* Memory stuff. */
static void
freestypat(Stypat p)
{
zsfree(p->pat);
freepatprog(p->prog);
if (p->vals)
freearray(p->vals);
if (p->eval)
freeeprog(p->eval);
zfree(p, sizeof(*p));
}
static void
freeallstyles(void)
{
Style s, sn;
Stypat p, pn;
for (s = zstyles; s; s = sn) {
sn = s->next;
for (p = s->pats; p; p = pn) {
pn = p->next;
freestypat(p);
}
zsfree(s->name);
zfree(s, sizeof(*s));
}
zstyles = zlstyles = NULL;
}
/* Get the style struct for a name. */
static Style
getstyle(char *name)
{
Style s;
for (s = zstyles; s; s = s->next)
if (!strcmp(name, s->name))
return s;
return NULL;
}
/* Store a value for a style. */
static int
setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
{
int weight, tmp, first;
char *str;
Stypat p, q, qq;
Eprog eprog = NULL;
if (eval) {
int ef = errflag;
eprog = parse_string(zjoin(vals, ' ', 1));
errflag = ef;
if (!eprog)
{
freepatprog(prog);
return 1;
}
eprog = dupeprog(eprog, 0);
}
for (p = s->pats; p; p = p->next)
if (!strcmp(pat, p->pat)) {
/* Exists -> replace. */
if (p->vals)
freearray(p->vals);
if (p->eval)
freeeprog(p->eval);
p->vals = zarrdup(vals);
p->eval = eprog;
freepatprog(prog);
return 0;
}
/* New pattern. */
p = (Stypat) zalloc(sizeof(*p));
p->pat = ztrdup(pat);
p->prog = prog;
p->vals = zarrdup(vals);
p->eval = eprog;
p->next = NULL;
/* Calculate the weight. */
for (weight = 0, tmp = 2, first = 1, str = pat; *str; str++) {
if (first && *str == '*' && (!str[1] || str[1] == ':')) {
/* Only `*' in this component. */
tmp = 0;
continue;
}
first = 0;
if (*str == '(' || *str == '|' || *str == '*' || *str == '[' ||
*str == '<' || *str == '?' || *str == '#' || *str == '^')
/* Is pattern. */
tmp = 1;
if (*str == ':') {
/* Yet another component. */
first = 1;
weight += tmp;
tmp = 2;
}
}
p->weight = (weight += tmp);
for (qq = NULL, q = s->pats; q && q->weight >= weight;
qq = q, q = q->next);
p->next = q;
if (qq)
qq->next = p;
else
s->pats = p;
return 0;
}
/* Add a new style. */
static Style
addstyle(char *name)
{
Style s;
s = (Style) zalloc(sizeof(*s));
s->next = NULL;
s->pats = NULL;
s->name = ztrdup(name);
if (zlstyles)
zlstyles->next = s;
else
zstyles = s;
zlstyles = s;
return s;
}
static char **
evalstyle(Stypat p)
{
int ef = errflag;
char **ret, *str;
unsetparam("reply");
execode(p->eval, 1, 0);
if (errflag) {
errflag = ef;
return NULL;
}
errflag = ef;
queue_signals();
if ((ret = getaparam("reply")))
ret = arrdup(ret);
else if ((str = getsparam("reply"))) {
ret = (char **) hcalloc(2 * sizeof(char *));
ret[0] = dupstring(str);
}
unqueue_signals();
unsetparam("reply");
return ret;
}
/* Look up a style for a context pattern. This does the matching. */
static char **
lookupstyle(char *ctxt, char *style)
{
Style s;
Stypat p;
for (s = zstyles; s; s = s->next)
if (!strcmp(s->name, style))
for (p = s->pats; p; p = p->next)
if (pattry(p->prog, ctxt))
return (p->eval ? evalstyle(p) : p->vals);
return NULL;
}
static int
bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
int min, max, n, add = 0, list = 0, eval = 0;
if (!args[0])
list = 1;
else if (args[0][0] == '-') {
char oc;
if ((oc = args[0][1]) && oc != '-') {
if (args[0][2]) {
zwarnnam(nam, "invalid argument: %s", args[0], 0);
return 1;
}
if (oc == 'L')
list = 2;
else if (oc == 'e') {
eval = add = 1;
args++;
}
} else {
add = 1;
args++;
}
} else
add = 1;
if (add) {
Style s;
Patprog prog;
char *pat;
if (arrlen(args) < 2) {
zwarnnam(nam, "not enough arguments", NULL, 0);
return 1;
}
pat = dupstring(args[0]);
tokenize(pat);
if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) {
zwarnnam(nam, "invalid pattern: %s", args[0], 0);
return 1;
}
if (!(s = getstyle(args[1])))
s = addstyle(args[1]);
return setstypat(s, args[0], prog, args + 2, eval);
}
if (list) {
Style s;
Stypat p;
char **v;
for (s = zstyles; s; s = s->next) {
if (list == 1) {
quotedzputs(s->name, stdout);
putchar('\n');
}
for (p = s->pats; p; p = p->next) {
if (list == 1)
printf("%s %s", (p->eval ? "(eval)" : " "), p->pat);
else {
printf("zstyle %s", (p->eval ? "-e " : ""));
quotedzputs(p->pat, stdout);
printf(" %s", s->name);
}
for (v = p->vals; *v; v++) {
putchar(' ');
quotedzputs(*v, stdout);
}
putchar('\n');
}
}
return 0;
}
switch (args[0][1]) {
case 'd': min = 0; max = -1; break;
case 's': min = 3; max = 4; break;
case 'b': min = 3; max = 3; break;
case 'a': min = 3; max = 3; break;
case 't': min = 2; max = -1; break;
case 'T': min = 2; max = -1; break;
case 'm': min = 3; max = 3; break;
case 'g': min = 1; max = 3; break;
default:
zwarnnam(nam, "invalid option: %s", args[0], 0);
return 1;
}
n = arrlen(args) - 1;
if (n < min) {
zwarnnam(nam, "not enough arguments", NULL, 0);
return 1;
} else if (max >= 0 && n > max) {
zwarnnam(nam, "too many arguments", NULL, 0);
return 1;
}
switch (args[0][1]) {
case 'd':
{
Style s;
if (args[1]) {
if (args[2]) {
char *pat = args[1];
for (args += 2; *args; args++) {
if ((s = getstyle(*args))) {
Stypat p, q;
for (q = NULL, p = s->pats; p;
q = p, p = p->next) {
if (!strcmp(p->pat, pat)) {
if (q)
q->next = p->next;
else
s->pats = p->next;
freestypat(p);
break;
}
}
}
}
} else {
Stypat p, q;
for (s = zstyles; s; s = s->next) {
for (q = NULL, p = s->pats; p; q = p, p = p->next) {
if (!strcmp(p->pat, args[1])) {
if (q)
q->next = p->next;
else
s->pats = p->next;
freestypat(p);
break;
}
}
}
}
} else
freeallstyles();
}
break;
case 's':
{
char **vals, *ret;
int val;
if ((vals = lookupstyle(args[1], args[2])) && vals[0]) {
ret = sepjoin(vals, (args[4] ? args[4] : " "), 0);
val = 0;
} else {
ret = ztrdup("");
val = 1;
}
setsparam(args[3], ret);
return val;
}
break;
case 'b':
{
char **vals, *ret;
int val;
if ((vals = lookupstyle(args[1], args[2])) &&
vals[0] && !vals[1] &&
(!strcmp(vals[0], "yes") ||
!strcmp(vals[0], "true") ||
!strcmp(vals[0], "on") ||
!strcmp(vals[0], "1"))) {
ret = "yes";
val = 0;
} else {
ret = "no";
val = 1;
}
setsparam(args[3], ztrdup(ret));
return val;
}
break;
case 'a':
{
char **vals, **ret;
int val;
if ((vals = lookupstyle(args[1], args[2]))) {
ret = zarrdup(vals);
val = 0;
} else {
char *dummy = NULL;
ret = zarrdup(&dummy);
val = 1;
}
setaparam(args[3], ret);
return val;
}
break;
case 't':
case 'T':
{
char **vals;
if ((vals = lookupstyle(args[1], args[2])) && vals[0]) {
if (args[3]) {
char **ap = args + 3, **p;
while (*ap) {
p = vals;
while (*p)
if (!strcmp(*ap, *p++))
return 0;
ap++;
}
return 1;
} else
return !(!strcmp(vals[0], "true") ||
!strcmp(vals[0], "yes") ||
!strcmp(vals[0], "on") ||
!strcmp(vals[0], "1"));
}
return (args[0][1] == 't' ? (vals ? 1 : 2) : 0);
}
break;
case 'm':
{
char **vals;
Patprog prog;
tokenize(args[3]);
if ((vals = lookupstyle(args[1], args[2])) &&
(prog = patcompile(args[3], PAT_STATIC, NULL))) {
while (*vals)
if (pattry(prog, *vals++))
return 0;
}
return 1;
}
break;
case 'g':
{
LinkList l = newlinklist();
int ret = 1;
Style s;
Stypat p;
if (args[2]) {
if (args[3]) {
if ((s = getstyle(args[3]))) {
for (p = s->pats; p; p = p->next) {
if (!strcmp(args[2], p->pat)) {
char **v = p->vals;
while (*v)
addlinknode(l, *v++);
ret = 0;
break;
}
}
}
} else {
for (s = zstyles; s; s = s->next)
for (p = s->pats; p; p = p->next)
if (!strcmp(args[2], p->pat)) {
addlinknode(l, s->name);
break;
}
ret = 0;
}
} else {
LinkNode n;
for (s = zstyles; s; s = s->next)
for (p = s->pats; p; p = p->next) {
for (n = firstnode(l); n; incnode(n))
if (!strcmp(p->pat, (char *) getdata(n)))
break;
if (!n)
addlinknode(l, p->pat);
}
ret = 0;
}
set_list_array(args[1], l);
return ret;
}
}
return 0;
}
/* Format stuff. */
/*
* One chunk of text, to allow recursive handling of ternary
* expressions in zformat -f output.
* instr The input string.
* specs The format specifiers, specs[c] is the string from c:string
* outp *outp is the start of the output string
* ousedp (*outp)[*ousedp] is where to write next
* olenp *olenp is the size allocated for *outp
* endchar Terminator character in addition to `\0' (may be '\0')
* skip If 1, don't output, just parse.
*/
static char *zformat_substring(char* instr, char **specs, char **outp,
int *ousedp, int *olenp, int endchar, int skip)
{
char *s;
for (s = instr; *s && *s != endchar; s++) {
if (*s == '%') {
int right, min = -1, max = -1, outl, testit;
char *spec, *start = s;
if ((right = (*++s == '-')))
s++;
if (*s >= '0' && *s <= '9') {
for (min = 0; *s >= '0' && *s <= '9'; s++)
min = (min * 10) + (int) STOUC(*s) - '0';
}
/* Ternary expressions */
testit = (STOUC(*s) == '(');
if (testit && s[1] == '-')
{
/* Allow %(-1... etc. */
right = 1;
s++;
}
if ((*s == '.' || testit) && s[1] >= '0' && s[1] <= '9') {
for (max = 0, s++; *s >= '0' && *s <= '9'; s++)
max = (max * 10) + (int) STOUC(*s) - '0';
}
else if (testit)
s++;
if (testit && STOUC(*s)) {
int actval, testval, endcharl;
/*
* One one number is useful for ternary expressions.
* Remember to put the sign back.
*/
testval = (min >= 0) ? min : (max >= 0) ? max : 0;
if (right)
testval *= -1;
if (specs[STOUC(*s)])
actval = (int)mathevali(specs[STOUC(*s)]);
else
actval = 0;
/* zero means values are equal, i.e. true */
actval -= testval;
/* careful about premature end of string */
if (!(endcharl = *++s))
return NULL;
/*
* Either skip true text and output false text, or
* vice versa... unless we are already skipping.
*/
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, endcharl, skip || actval)))
return NULL;
if (!(s = zformat_substring(s+1, specs, outp, ousedp,
olenp, ')', skip || !actval)))
return NULL;
} else if (skip) {
continue;
} else if ((spec = specs[STOUC(*s)])) {
int len;
if ((len = strlen(spec)) > max && max >= 0)
len = max;
outl = (min >= 0 ? (min > len ? min : len) : len);
if (*ousedp + outl >= *olenp) {
int nlen = *olenp + outl + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, *outp, *olenp);
*olenp = nlen;
*outp = tmp;
}
if (len >= outl) {
memcpy(*outp + *ousedp, spec, outl);
*ousedp += outl;
} else {
int diff = outl - len;
if (right) {
while (diff--)
(*outp)[(*ousedp)++] = ' ';
memcpy(*outp + *ousedp, spec, len);
*ousedp += len;
} else {
memcpy(*outp + *ousedp, spec, len);
*ousedp += len;
while (diff--)
(*outp)[(*ousedp)++] = ' ';
}
}
} else {
int len = s - start + 1;
if (*ousedp + len >= *olenp) {
int nlen = *olenp + len + 128;
char *tmp = (char *) zhalloc(nlen);
memcpy(tmp, *outp, *olenp);
*olenp = nlen;
*outp = tmp;
}
memcpy(*outp + *ousedp, start, len);
*ousedp += len;
}
} else {
if (skip)
continue;
if (*ousedp + 1 >= *olenp) {
char *tmp = (char *) zhalloc((*olenp) << 1);
memcpy(tmp, *outp, *olenp);
*olenp <<= 1;
*outp = tmp;
}
(*outp)[(*ousedp)++] = *s;
}
}
return s;
}
static int
bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
char opt;
if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) {
zwarnnam(nam, "invalid argument: %s", args[0], 0);
return 1;
}
args++;
switch (opt) {
case 'f':
{
char **ap, *specs[256], *out;
int olen, oused = 0;
memset(specs, 0, 256 * sizeof(char *));
specs['%'] = "%";
specs[')'] = ")";
for (ap = args + 2; *ap; ap++) {
if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' ||
(ap[0][0] >= '0' && ap[0][0] <= '9') ||
ap[0][1] != ':') {
zwarnnam(nam, "invalid argument: %s", *ap, 0);
return 1;
}
specs[STOUC(ap[0][0])] = ap[0] + 2;
}
out = (char *) zhalloc(olen = 128);
zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0);
out[oused] = '\0';
setsparam(args[0], ztrdup(out));
return 0;
}
break;
case 'a':
{
char **ap, *cp;
int nbc = 0, colon = 0, pre = 0, suf = 0;
for (ap = args + 2; *ap; ap++) {
for (nbc = 0, cp = *ap; *cp && *cp != ':'; cp++)
if (*cp == '\\' && cp[1])
cp++, nbc++;
if (*cp == ':' && cp[1]) {
int d;
colon++;
if ((d = cp - *ap - nbc) > pre)
pre = d;
if ((d = strlen(cp + 1)) > suf)
suf = d;
}
}
{
int sl = strlen(args[1]);
VARARR(char, buf, pre + suf + sl + 1);
char **ret, **rp, *copy, *cpp, oldc;
ret = (char **) zalloc((arrlen(args + 2) + 1) *
sizeof(char *));
memcpy(buf + pre, args[1], sl);
suf = pre + sl;
for (rp = ret, ap = args + 2; *ap; ap++) {
copy = dupstring(*ap);
for (cp = cpp = copy; *cp && *cp != ':'; cp++) {
if (*cp == '\\' && cp[1])
cp++;
*cpp++ = *cp;
}
oldc = *cpp;
*cpp = '\0';
if (((cpp == cp && oldc == ':') || *cp == ':') && cp[1]) {
memset(buf, ' ', pre);
memcpy(buf, copy, (cpp - copy));
strcpy(buf + suf, cp + 1);
*rp++ = ztrdup(buf);
} else
*rp++ = ztrdup(copy);
}
*rp = NULL;
setaparam(args[0], ret);
return 0;
}
}
break;
}
zwarnnam(nam, "invalid option: -%c", 0, opt);
return 1;
}
/* Zregexparse stuff. */
typedef struct {
char **match;
char **mbegin;
char **mend;
} MatchData;
static void
savematch(MatchData *m)
{
char **a;
queue_signals();
a = getaparam("match");
m->match = a ? zarrdup(a) : NULL;
a = getaparam("mbegin");
m->mbegin = a ? zarrdup(a) : NULL;
a = getaparam("mend");
m->mend = a ? zarrdup(a) : NULL;
unqueue_signals();
}
static void
restorematch(MatchData *m)
{
if (m->match)
setaparam("match", m->match);
else
unsetparam("match");
if (m->mbegin)
setaparam("mbegin", m->mbegin);
else
unsetparam("mbegin");
if (m->mend)
setaparam("mend", m->mend);
else
unsetparam("mend");
}
static void
freematch(MatchData *m)
{
if (m->match)
freearray(m->match);
if (m->mbegin)
freearray(m->mbegin);
if (m->mend)
freearray(m->mend);
}
typedef struct {
int cutoff;
char *pattern;
Patprog patprog;
char *guard;
char *action;
LinkList branches;
} RParseState;
typedef struct {
RParseState *state;
LinkList actions;
} RParseBranch;
typedef struct {
LinkList nullacts;
LinkList in;
LinkList out;
} RParseResult;
static char **rparseargs;
static LinkList rparsestates;
static int rparsealt(RParseResult *result, jmp_buf *perr);
static void
connectstates(LinkList out, LinkList in)
{
LinkNode outnode, innode, ln;
for (outnode = firstnode(out); outnode; outnode = nextnode(outnode)) {
RParseBranch *outbranch = getdata(outnode);
for (innode = firstnode(in); innode; innode = nextnode(innode)) {
RParseBranch *inbranch = getdata(innode);
RParseBranch *br = hcalloc(sizeof(*br));
br->state = inbranch->state;
br->actions = newlinklist();
for (ln = firstnode(outbranch->actions); ln; ln = nextnode(ln))
addlinknode(br->actions, getdata(ln));
for (ln = firstnode(inbranch->actions); ln; ln = nextnode(ln))
addlinknode(br->actions, getdata(ln));
addlinknode(outbranch->state->branches, br);
}
}
}
static int
rparseelt(RParseResult *result, jmp_buf *perr)
{
int l;
char *s = *rparseargs;
if (!s)
return 1;
switch (s[0]) {
case '/': {
RParseState *st;
RParseBranch *br;
char *pattern, *lookahead;
int patternlen, lookaheadlen = 0;
l = strlen(s);
if (!((2 <= l && s[l - 1] == '/') ||
(3 <= l && s[l - 2] == '/' && (s[l - 1] == '+' ||
s[l - 1] == '-'))))
return 1;
st = hcalloc(sizeof(*st));
st->branches = newlinklist();
st->cutoff = s[l - 1];
if (s[l - 1] == '/') {
pattern = s + 1;
patternlen = l - 2;
} else {
pattern = s + 1;
patternlen = l - 3;
}
rparseargs++;
if ((s = *rparseargs) && s[0] == '%' &&
2 <= (l = strlen(s)) && s[l - 1] == '%') {
rparseargs++;
lookahead = s + 1;
lookaheadlen = l - 2;
} else {
lookahead = NULL;
}
if (patternlen == 2 && !strncmp(pattern, "[]", 2))
st->pattern = NULL;
else {
char *cp;
int l = patternlen + 12; /* (#b)((#B)...)...* */
if(lookahead)
l += lookaheadlen + 4; /* (#B)... */
cp = st->pattern = hcalloc(l);
strcpy(cp, "(#b)((#B)");
cp += 9;
strcpy(cp, pattern);
cp += patternlen;
strcpy(cp, ")");
cp += 1;
if (lookahead) {
strcpy(cp, "(#B)");
cp += 4;
strcpy(cp, lookahead);
cp += lookaheadlen;
}
strcpy(cp, "*");
}
st->patprog = NULL;
if ((s = *rparseargs) && *s == '-') {
rparseargs++;
l = strlen(s);
st->guard = hcalloc(l);
memcpy(st->guard, s + 1, l - 1);
st->guard[l - 1] = '\0';
} else
st->guard = NULL;
if ((s = *rparseargs) && *s == ':') {
rparseargs++;
l = strlen(s);
st->action = hcalloc(l);
memcpy(st->action, s + 1, l - 1);
st->action[l - 1] = '\0';
} else
st->action = NULL;
result->nullacts = NULL;
result->in = newlinklist();
br = hcalloc(sizeof(*br));
br->state = st;
br->actions = newlinklist();
addlinknode(result->in, br);
result->out = newlinklist();
br = hcalloc(sizeof(*br));
br->state = st;
br->actions = newlinklist();
addlinknode(result->out, br);
break;
}
case '(':
if (s[1])
return 1;
rparseargs++;
if (rparsealt(result, perr))
longjmp(*perr, 2);
s = *rparseargs;
if (!s || s[0] != ')' || s[1] != '\0')
longjmp(*perr, 2);
rparseargs++;
break;
default:
return 1;
}
return 0;
}
static int
rparseclo(RParseResult *result, jmp_buf *perr)
{
if (rparseelt(result, perr))
return 1;
if (*rparseargs && !strcmp(*rparseargs, "#")) {
rparseargs++;
while (*rparseargs && !strcmp(*rparseargs, "#"))
rparseargs++;
connectstates(result->out, result->in);
result->nullacts = newlinklist();
}
return 0;
}
static void
prependactions(LinkList acts, LinkList branches)
{
LinkNode aln, bln;
for (bln = firstnode(branches); bln; bln = nextnode(bln)) {
RParseBranch *br = getdata(bln);
for (aln = lastnode(acts); aln != (LinkNode)acts; aln = prevnode(aln))
pushnode(br->actions, getdata(aln));
}
}
static void
appendactions(LinkList acts, LinkList branches)
{
LinkNode aln, bln;
for (bln = firstnode(branches); bln; bln = nextnode(bln)) {
RParseBranch *br = getdata(bln);
for (aln = firstnode(acts); aln; aln = nextnode(aln))
addlinknode(br->actions, getdata(aln));
}
}
static int
rparseseq(RParseResult *result, jmp_buf *perr)
{
int l;
char *s;
RParseResult sub;
result->nullacts = newlinklist();
result->in = newlinklist();
result->out = newlinklist();
while (1) {
if ((s = *rparseargs) && s[0] == '{' && s[(l = strlen(s)) - 1] == '}') {
char *action = hcalloc(l - 1);
LinkNode ln;
rparseargs++;
memcpy(action, s + 1, l - 2);
action[l - 2] = '\0';
if (result->nullacts)
addlinknode(result->nullacts, action);
for (ln = firstnode(result->out); ln; ln = nextnode(ln)) {
RParseBranch *br = getdata(ln);
addlinknode(br->actions, action);
}
}
else if (!rparseclo(&sub, perr)) {
connectstates(result->out, sub.in);
if (result->nullacts) {
prependactions(result->nullacts, sub.in);
insertlinklist(sub.in, lastnode(result->in), result->in);
}
if (sub.nullacts) {
appendactions(sub.nullacts, result->out);
insertlinklist(sub.out, lastnode(result->out), result->out);
} else
result->out = sub.out;
if (result->nullacts && sub.nullacts)
insertlinklist(sub.nullacts, lastnode(result->nullacts),
result->nullacts);
else
result->nullacts = NULL;
}
else
break;
}
return 0;
}
static int
rparsealt(RParseResult *result, jmp_buf *perr)
{
RParseResult sub;
if (rparseseq(result, perr))
return 1;
while (*rparseargs && !strcmp(*rparseargs, "|")) {
rparseargs++;
if (rparseseq(&sub, perr))
longjmp(*perr, 2);
if (!result->nullacts && sub.nullacts)
result->nullacts = sub.nullacts;
insertlinklist(sub.in, lastnode(result->in), result->in);
insertlinklist(sub.out, lastnode(result->out), result->out);
}
return 0;
}
static int
rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp)
{
LinkNode ln, lnn;
LinkList nexts;
LinkList nextslist;
RParseBranch *br;
RParseState *st = NULL;
int point1 = 0, point2 = 0;
setiparam(var1, point1);
setiparam(var2, point2);
if (!comp && !*subj && sm->nullacts) {
for (ln = firstnode(sm->nullacts); ln; ln = nextnode(ln)) {
char *action = getdata(ln);
if (action)
execstring(action, 1, 0);
}
return 0;
}
nextslist = newlinklist();
nexts = sm->in;
addlinknode(nextslist, nexts);
do {
MatchData match1, match2;
savematch(&match1);
for (ln = firstnode(nexts); ln; ln = nextnode(ln)) {
int i;
RParseState *next;
br = getdata(ln);
next = br->state;
if (next->pattern && !next->patprog) {
tokenize(next->pattern);
if (!(next->patprog = patcompile(next->pattern, 0, NULL)))
return 3;
}
if (next->pattern && pattry(next->patprog, subj) &&
(!next->guard || (execstring(next->guard, 1, 0), !lastval))) {
LinkNode aln;
char **mend;
int len;
queue_signals();
mend = getaparam("mend");
len = atoi(mend[0]);
unqueue_signals();
for (i = len; i; i--)
if (*subj++ == Meta)
subj++;
savematch(&match2);
restorematch(&match1);
for (aln = firstnode(br->actions); aln; aln = nextnode(aln)) {
char *action = getdata(aln);
if (action)
execstring(action, 1, 0);
}
restorematch(&match2);
point2 += len;
setiparam(var2, point2);
st = br->state;
nexts = st->branches;
if (next->cutoff == '-' || (next->cutoff == '/' && len)) {
nextslist = newlinklist();
point1 = point2;
setiparam(var1, point1);
}
addlinknode(nextslist, nexts);
break;
}
}
if (!ln)
freematch(&match1);
} while (ln);
if (!comp && !*subj)
for (ln = firstnode(sm->out); ln; ln = nextnode(ln)) {
br = getdata(ln);
if (br->state == st) {
for (ln = firstnode(br->actions); ln; ln = nextnode(ln)) {
char *action = getdata(ln);
if (action)
execstring(action, 1, 0);
}
return 0;
}
}
for (lnn = firstnode(nextslist); lnn; lnn = nextnode(lnn)) {
nexts = getdata(lnn);
for (ln = firstnode(nexts); ln; ln = nextnode(ln)) {
br = getdata(ln);
if (br->state->action)
execstring(br->state->action, 1, 0);
}
}
return empty(nexts) ? 2 : 1;
}
/*
usage: zregexparse [-c] var1 var2 string regex...
status:
0: matched
1: unmatched (all next state candidates are failed)
2: unmatched (there is no next state candidates)
3: regex parse error
*/
static int
bin_zregexparse(char *nam, char **args, Options ops, UNUSED(int func))
{
int oldextendedglob = opts[EXTENDEDGLOB];
char *var1 = args[0];
char *var2 = args[1];
char *subj = args[2];
int ret;
jmp_buf rparseerr;
RParseResult result;
opts[EXTENDEDGLOB] = 1;
rparseargs = args + 3;
pushheap();
rparsestates = newlinklist();
if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) {
if (*rparseargs)
zwarnnam(nam, "invalid regex : %s", *rparseargs, 0);
else
zwarnnam(nam, "not enough regex arguments", NULL, 0);
ret = 3;
} else
ret = 0;
if (!ret)
ret = rmatch(&result, subj, var1, var2, OPT_ISSET(ops,'c'));
popheap();
opts[EXTENDEDGLOB] = oldextendedglob;
return ret;
}
typedef struct zoptdesc *Zoptdesc;
typedef struct zoptarr *Zoptarr;
typedef struct zoptval *Zoptval;
struct zoptdesc {
Zoptdesc next;
char *name;
int flags;
Zoptarr arr;
Zoptval vals, last;
};
#define ZOF_ARG 1
#define ZOF_OPT 2
#define ZOF_MULT 4
#define ZOF_SAME 8
struct zoptarr {
Zoptarr next;
char *name;
Zoptval vals, last;
int num;
};
struct zoptval {
Zoptval next, onext;
char *name;
char *arg;
char *str;
};
static Zoptdesc opt_descs;
static Zoptarr opt_arrs;
static Zoptdesc
get_opt_desc(char *name)
{
Zoptdesc p;
for (p = opt_descs; p; p = p->next)
if (!strcmp(name, p->name))
return p;
return NULL;
}
static Zoptdesc
lookup_opt(char *str)
{
Zoptdesc p;
for (p = opt_descs; p; p = p->next) {
if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str))
return p;
}
return NULL;
}
static Zoptarr
get_opt_arr(char *name)
{
Zoptarr p;
for (p = opt_arrs; p; p = p->next)
if (!strcmp(name, p->name))
return p;
return NULL;
}
static void
add_opt_val(Zoptdesc d, char *arg)
{
Zoptval v = NULL;
char *n = dyncat("-", d->name);
int new = 0;
if (!(d->flags & ZOF_MULT))
v = d->vals;
if (!v) {
v = (Zoptval) zhalloc(sizeof(*v));
v->next = v->onext = NULL;
v->name = n;
new = 1;
}
v->arg = arg;
if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) {
v->str = NULL;
if (d->arr)
d->arr->num += (arg ? 2 : 1);
} else if (arg) {
char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2);
*s = '-';
strcpy(s + 1, d->name);
strcat(s, arg);
v->str = s;
if (d->arr)
d->arr->num += 1;
} else {
v->str = NULL;
if (d->arr)
d->arr->num += 1;
}
if (new) {
if (d->arr) {
if (d->arr->last)
d->arr->last->next = v;
else
d->arr->vals = v;
d->arr->last = v;
}
if (d->last)
d->last->onext = v;
else
d->vals = v;
d->last = v;
}
}
static int
bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np;
int del = 0, f, extract = 0, keep = 0;
Zoptdesc sopts[256], d;
Zoptarr a, defarr = NULL;
Zoptval v;
opt_descs = NULL;
opt_arrs = NULL;
memset(sopts, 0, 256 * sizeof(Zoptdesc));
while ((o = *args++)) {
if (*o == '-') {
switch (o[1]) {
case '\0':
o = NULL;
break;
case '-':
if (o[2])
args--;
o = NULL;
break;
case 'D':
if (o[2]) {
args--;
o = NULL;
break;
}
del = 1;
break;
case 'E':
if (o[2]) {
args--;
o = NULL;
break;
}
extract = 1;
break;
case 'K':
if (o[2]) {
args--;
o = NULL;
break;
}
keep = 1;
break;
case 'a':
if (defarr) {
zwarnnam(nam, "default array given more than once", NULL, 0);
return 1;
}
if (o[2])
n = o + 2;
else if (*args)
n = *args++;
else {
zwarnnam(nam, "missing array name", NULL, 0);
return 1;
}
defarr = (Zoptarr) zhalloc(sizeof(*defarr));
defarr->name = n;
defarr->num = 0;
defarr->vals = defarr->last = NULL;
defarr->next = NULL;
opt_arrs = defarr;
break;
case 'A':
if (o[2])
assoc = o + 2;
else if (*args)
assoc = *args++;
else {
zwarnnam(nam, "missing array name", NULL, 0);
return 1;
}
break;
}
if (!o) {
o = "";
break;
}
} else {
args--;
break;
}
}
if (!o) {
zwarnnam(nam, "missing option descriptions", NULL, 0);
return 1;
}
while ((o = dupstring(*args++))) {
if (!*o) {
zwarnnam(nam, "invalid option description: %s", o, 0);
return 1;
}
f = 0;
for (p = o; *p; p++) {
if (*p == '\\' && p[1])
p++;
else if (*p == '+') {
f |= ZOF_MULT;
*p = '\0';
p++;
break;
} else if (*p == ':' || *p == '=')
break;
}
if (*p == ':') {
f |= ZOF_ARG;
*p = '\0';
if (*++p == ':') {
p++;
f |= ZOF_OPT;
}
if (*p == '-') {
p++;
f |= ZOF_SAME;
}
}
a = NULL;
if (*p == '=') {
*p++ = '\0';
if (!(a = get_opt_arr(p))) {
a = (Zoptarr) zhalloc(sizeof(*a));
a->name = p;
a->num = 0;
a->vals = a->last = NULL;
a->next = opt_arrs;
opt_arrs = a;
}
} else if (*p) {
zwarnnam(nam, "invalid option description: %s", args[-1], 0);
return 1;
} else if (!(a = defarr) && !assoc) {
zwarnnam(nam, "no default array defined: %s", args[-1], 0);
return 1;
}
for (p = n = o; *p; p++) {
if (*p == '\\' && p[1])
p++;
*n++ = *p;
}
if (get_opt_desc(o)) {
zwarnnam(nam, "option defined more than once: %s", o, 0);
return 1;
}
d = (Zoptdesc) zhalloc(sizeof(*d));
d->name = o;
d->flags = f;
d->arr = a;
d->next = opt_descs;
d->vals = d->last = NULL;
opt_descs = d;
if (!o[1])
sopts[STOUC(*o)] = d;
}
np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams);
for (; (o = *pp); pp++) {
if (*o != '-') {
if (extract) {
if (del)
*cp++ = o;
continue;
} else
break;
}
if (!o[1] || (o[1] == '-' && !o[2])) {
if (del && extract)
*cp++ = o;
pp++;
break;
}
if (!(d = lookup_opt(o + 1))) {
while (*++o) {
if (!(d = sopts[STOUC(*o)])) {
o = NULL;
break;
}
if (d->flags & ZOF_ARG) {
if (o[1]) {
add_opt_val(d, o + 1);
break;
} else if (!(d->flags & ZOF_OPT)) {
if (!pp[1]) {
zwarnnam(nam, "missing argument for option: %s",
d->name, 0);
return 1;
}
add_opt_val(d, *++pp);
} else
add_opt_val(d, NULL);
} else
add_opt_val(d, NULL);
}
if (!o) {
if (extract) {
if (del)
*cp++ = *pp;
continue;
} else
break;
}
} else {
if (d->flags & ZOF_ARG) {
char *e = o + strlen(d->name) + 1;
if (*e)
add_opt_val(d, e);
else if (!(d->flags & ZOF_OPT)) {
if (!pp[1]) {
zwarnnam(nam, "missing argument for option: %s",
d->name, 0);
return 1;
}
add_opt_val(d, *++pp);
} else
add_opt_val(d, NULL);
} else
add_opt_val(d, NULL);
}
}
if (extract && del)
while (*pp)
*cp++ = *pp++;
for (a = opt_arrs; a; a = a->next) {
if (!keep || a->num) {
aval = (char **) zalloc((a->num + 1) * sizeof(char *));
for (ap = aval, v = a->vals; v; ap++, v = v->next) {
if (v->str)
*ap = ztrdup(v->str);
else {
*ap = ztrdup(v->name);
if (v->arg)
*++ap = ztrdup(v->arg);
}
}
*ap = NULL;
setaparam(a->name, aval);
}
}
if (assoc) {
int num;
for (num = 0, d = opt_descs; d; d = d->next)
if (d->vals)
num++;
if (!keep || num) {
aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *));
for (ap = aval, d = opt_descs; d; d = d->next) {
if (d->vals) {
*ap++ = n = (char *) zalloc(strlen(d->name) + 2);
*n = '-';
strcpy(n + 1, d->name);
for (num = 1, v = d->vals; v; v = v->onext) {
num += (v->arg ? strlen(v->arg) : 0);
if (v->next)
num++;
}
*ap++ = n = (char *) zalloc(num);
for (v = d->vals; v; v = v->onext) {
if (v->arg) {
strcpy(n, v->arg);
n += strlen(v->arg);
}
*n = ' ';
}
*n = '\0';
}
}
*ap = NULL;
sethparam(assoc, aval);
}
}
if (del) {
if (extract) {
*cp = NULL;
freearray(pparams);
pparams = zarrdup(np);
} else {
pp = zarrdup(pp);
freearray(pparams);
pparams = pp;
}
}
return 0;
}
static struct builtin bintab[] = {
BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL),
};
/**/
int
setup_(UNUSED(Module m))
{
zstyles = zlstyles = NULL;
return 0;
}
/**/
int
boot_(Module m)
{
return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
}
/**/
int
cleanup_(Module m)
{
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
return 0;
}
/**/
int
finish_(UNUSED(Module m))
{
freeallstyles();
return 0;
}
#endif //__SYMBIAN32__