// -*- c-basic-offset: 4; related-file-name: "../include/click/variableenv.hh" -*-
/*
* variableenv.{cc,hh} -- scoped configuration variables
* Eddie Kohler
*
* Copyright (c) 2000 Massachusetts Institute of Technology
* Copyright (c) 2000 Mazu Networks, Inc.
* Copyright (c) 2004-2005 Regents of the University of California
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include <click/variableenv.hh>
#include <click/straccum.hh>
#include <click/confparse.hh>
CLICK_DECLS
String
cp_expand(const String &config, VariableExpander &ve, bool expand_quote)
{
if (!config || find(config, '$') == config.end())
return config;
const char *s = config.begin();
const char *end = config.end();
const char *uninterpolated = s;
int quote = 0;
StringAccum output;
for (; s < end; s++)
switch (*s) {
case '\\':
if (s + 1 < end && quote == '\"')
s++;
break;
case '\'':
case '\"':
if (quote == 0)
quote = *s;
else if (quote == *s)
quote = 0;
break;
case '/':
if (s + 1 < end && (s[1] == '/' || s[1] == '*') && quote == 0)
s = cp_skip_comment_space(s, end) - 1;
break;
case '$': {
if (s + 1 >= end || quote == '\'')
break;
const char *beforedollar = s, *cstart;
String vname;
int vtype;
if (s[1] == '{') {
vtype = '{';
s += 2;
for (cstart = s; s < end && *s != '}'; s++)
/* nada */;
if (s == end)
goto done;
vname = config.substring(cstart, s++);
} else if (s[1] == '(') {
int level = 1, nquote = 0, anydollar = 0;
vtype = '(';
s += 2;
for (cstart = s; s < end && level; s++)
switch (*s) {
case '(':
if (nquote == 0)
level++;
break;
case ')':
if (nquote == 0)
level--;
break;
case '\"':
case '\'':
if (nquote == 0)
nquote = *s;
else if (nquote == *s)
nquote = 0;
break;
case '\\':
if (s + 1 < end && nquote != '\'')
s++;
break;
case '$':
if (nquote != '\'')
anydollar = 1;
break;
}
if (s == cstart || s[-1] != ')')
goto done;
if (anydollar)
// XXX recursive call: potential stack overflow
vname = cp_expand(config.substring(cstart, s - 1), ve);
else
vname = config.substring(cstart, s - 1);
} else if (isalnum(s[1]) || s[1] == '_') {
vtype = 'a';
s++;
for (cstart = s; s < end && (isalnum(*s) || *s == '_'); s++)
/* nada */;
vname = config.substring(cstart, s);
} else if (s[1] == '?') {
vtype = 'a';
s++;
vname = config.substring(s, s + 1);
s++;
} else
break;
output << config.substring(uninterpolated, beforedollar);
bool result;
if (expand_quote && quote == 0) {
output << '\"';
result = ve.expand(vname, vtype, '\"', output);
output << '\"';
} else
result = ve.expand(vname, vtype, quote, output);
uninterpolated = (result ? s : beforedollar);
s--;
}
}
done:
if (!output.length())
return config;
else {
output << config.substring(uninterpolated, s);
return output.take_string();
}
}
String
cp_expand_in_quotes(const String &s, int quote)
{
if (quote == '\"') {
String ss = cp_quote(s);
if (ss[0] == '\"')
ss = ss.substring(1, ss.length() - 2);
return ss;
} else
return s;
}
void
VariableEnvironment::enter(const VariableEnvironment &ve)
{
assert(_depths.size() == 0 || ve._depths.size() == 0 || _depths.back() < ve._depths[0]);
for (int i = 0; i < ve._formals.size(); i++) {
_formals.push_back(ve._formals[i]);
_values.push_back(ve._values[i]);
_depths.push_back(ve._depths[i]);
}
}
void
VariableEnvironment::enter(const Vector<String> &formals, const Vector<String> &values, int enter_depth)
{
assert(enter_depth > depth());
for (int arg = 0; arg < formals.size(); arg++) {
_formals.push_back(formals[arg]);
_values.push_back(values[arg]);
_depths.push_back(enter_depth);
}
}
void
VariableEnvironment::limit_depth(int deepest)
{
int s = _formals.size();
while (s > 0 && _depths[s-1] >= deepest)
s--;
_formals.resize(s);
_values.resize(s);
_depths.resize(s);
}
bool
VariableEnvironment::expand(const String &var, int vartype, int quote,
StringAccum &output)
{
String v(var);
const char *minus = 0;
if (vartype == '{' && (minus = find(var, '-')) != var.end())
v = var.substring(var.begin(), minus);
for (int vnum = _formals.size() - 1; vnum >= 0; vnum--)
if (v == _formals[vnum]) {
output << cp_expand_in_quotes(_values[vnum], quote);
return true;
}
if (minus) {
output << cp_expand_in_quotes(var.substring(minus + 1, var.end()), quote);
return true;
} else
return false;
}
#if 0
void
VariableEnvironment::print() const
{
for (int i = 0; i < _formals.size(); i++)
fprintf(stderr, "%s.%d=%s ", _formals[i].c_str(), _depths[i], _values[i].c_str());
fprintf(stderr, "\n");
}
#endif
CLICK_ENDDECLS
syntax highlighted by Code2HTML, v. 0.9.1