// -*- 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 #include #include #include 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 &formals, const Vector &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