Ejemplo n.º 1
0
/* Note: It is kind of stupid to first call strbuf_free_to_string,
 * then later free (above this function). But with the current API
 * of strbuf_free there's no other way!
 */
char *
expand_substitution(const char *repl, MatchState *ms, uint32_t subc, SubmatchSpec *subv)
{
	StrBuf *buf = strbuf_new(); /* XXX: memory management */
	bool escaped = false;
	uint32_t c;

	for (c = 0; repl[c] != '\0'; c++) {
		if (!escaped && repl[c] == '$') {
			uint32_t d;
			if (repl[c+1] == '{') {
				for (d = c+2; repl[d] != '}' && repl[d] != '\0'; d++);
				if (repl[d] != '\0') {
					if (expand_variable(buf, repl+c+2, d-c-2, ms, subc, subv)) {
						c = d;
						continue;
					}
				}
			} else if (isdigit(repl[c+1])) {
				for (d = c+2; isdigit(repl[d]); d++);
				if (expand_variable(buf, repl+c+1, d-c-1, ms, subc, subv)) {
					c = d-1;
					continue;
				}
			} else if (repl[c+1] != '\0' && strchr("`'&", repl[c+1]) != NULL) {
				expand_variable(buf, repl+c+1, 1, ms, subc, subv);
				c++;
				continue;
			}
		}
		escaped = (!escaped && repl[c] == '\\');
		if (!escaped)
			strbuf_append_char(buf, repl[c]);
	}

	return strbuf_free_to_string(buf);
}
Ejemplo n.º 2
0
/*
 * recurse == 1: don't expand '@(command)@'
 * recurse == 2: don't expand '@<java script>@'
*/
gchar*
expand(const char* s, guint recurse) {
    enum exp_type etype;
    char*         end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
    char*         ret = NULL;
    char*         vend = NULL;
    GError*       err = NULL;
    gchar*        cmd_stdout = NULL;
    gchar*        mycmd = NULL;
    GString*      buf = g_string_new("");
    GString*      js_ret = g_string_new("");

    while (s && *s) {
        switch(*s) {
            case '\\':
                g_string_append_c(buf, *++s);
                s++;
                break;

            case '@':
                etype = get_exp_type(s);
                s++;

                switch(etype) {
                    case EXP_SIMPLE_VAR:
                        vend = strpbrk(s, end_simple_var);
                        if(!vend) vend = strchr(s, '\0');
                        break;
                    case EXP_BRACED_VAR:
                        s++;
                        vend = strchr(s, '}');
                        if(!vend) vend = strchr(s, '\0');
                        break;
                    case EXP_EXPR:
                        s++;
                        vend = strstr(s, ")@");
                        if(!vend) vend = strchr(s, '\0');
                        break;
                    case EXP_JS:
                        s++;
                        vend = strstr(s, ">@");
                        if(!vend) vend = strchr(s, '\0');
                        break;
                    case EXP_ESCAPE:
                        s++;
                        vend = strstr(s, "]@");
                        if(!vend) vend = strchr(s, '\0');
                        break;
                    /*@notreached@*/
                    case EXP_ERR:
                        break;
                }
                assert(vend);

                ret = g_strndup(s, vend-s);

                if(etype == EXP_SIMPLE_VAR ||
                   etype == EXP_BRACED_VAR) {

                    expand_variable(buf, ret);

                    if(etype == EXP_SIMPLE_VAR)
                        s = vend;
                    else
                        s = vend+1;
                }
                else if(recurse != 1 &&
                        etype == EXP_EXPR) {

                    /* execute program directly */
                    if(ret[0] == '+') {
                        mycmd = expand(ret+1, 1);
                        g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
                        g_free(mycmd);
                    }
                    /* execute program through shell, quote it first */
                    else {
                        mycmd = expand(ret, 1);
                        gchar *quoted = g_shell_quote(mycmd);
                        gchar *tmp = g_strdup_printf("%s %s",
                                uzbl.behave.shell_cmd?uzbl.behave.shell_cmd:"/bin/sh -c",
                                quoted);
                        g_spawn_command_line_sync(tmp, &cmd_stdout, NULL, NULL, &err);
                        g_free(mycmd);
                        g_free(quoted);
                        g_free(tmp);
                    }

                    if (err) {
                        g_printerr("error on running command: %s\n", err->message);
                        g_error_free (err);
                    }
                    else if (*cmd_stdout) {
                        size_t len = strlen(cmd_stdout);

                        if(len > 0 && cmd_stdout[len-1] == '\n')
                            cmd_stdout[--len] = '\0'; /* strip trailing newline */

                        g_string_append(buf, cmd_stdout);
                        g_free(cmd_stdout);
                    }
                    s = vend+2;
                }
                else if(recurse != 2 &&
                        etype == EXP_JS) {

                    /* read JS from file */
                    if(ret[0] == '+') {
                        GArray *tmp = g_array_new(TRUE, FALSE, sizeof(gchar *));
                        mycmd = expand(ret+1, 2);
                        g_array_append_val(tmp, mycmd);

                        run_external_js(uzbl.gui.web_view, tmp, js_ret);
                        g_array_free(tmp, TRUE);
                    }
                    /* JS from string */
                    else {
                        mycmd = expand(ret, 2);
                        eval_js(uzbl.gui.web_view, mycmd, js_ret, "(command)");
                        g_free(mycmd);
                    }

                    if(js_ret->str) {
                        g_string_append(buf, js_ret->str);
                        g_string_free(js_ret, TRUE);
                        js_ret = g_string_new("");
                    }
                    s = vend+2;
                }
                else if(etype == EXP_ESCAPE) {
                    mycmd = expand(ret, 0);
                    char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));

                    g_string_append(buf, escaped);

                    g_free(escaped);
                    g_free(mycmd);
                    s = vend+2;
                }

                g_free(ret);
                ret = NULL;
                break;

            default:
                g_string_append_c(buf, *s);
                s++;
                break;
        }
    }
    g_string_free(js_ret, TRUE);
    return g_string_free(buf, FALSE);
}
Ejemplo n.º 3
0
static bool recursive_print(std::ostream& out, const NodePtr root,
	 const RuleTable& rules, BindingsPtr bindings,
	 std::size_t indent,
	 Context& context) {
   if (root->is_leaf()) {
      return !!(out << root->get_token().get_literal());
   } else {
      Arity arity(root->size());
      Operator op = root->get_op();
      BindingsPtr local_bindings;
      RuleTable::print_iterator it, end;
      int found = 0;
      for (it = rules.reversed_find(op, arity, end); it != end; ++it) {
	 ++found;
	 local_bindings = std::make_shared<Bindings>(bindings);
	 if (matches(root, it->second->get_tree_expression(),
	       local_bindings, context)) break;
      }
      if (it == end) {
	 // try wildcard rules
	 for (it = rules.reversed_find(op, Arity(), end);
	       it != end; ++it) {
	    ++found;
	    local_bindings = std::make_shared<Bindings>(bindings);
	    if (matches(root, it->second->get_tree_expression(),
		  local_bindings, context)) break;
	 }
	 if (it == end) {
	    std::ostringstream os;
	    if (found > 0) {
	       os << "no matching ";
	    } else {
	       os << "no ";
	    }
	    os << "rule found for '" << op.get_name() << "' with " <<
	       root->size() << " parameters";
	    throw Exception(root->get_location(), os.str());
	 }
      }
      context.descend(root);
      const NodePtr& node = it->second->get_rhs();
      std::size_t add_indent = 0;
      for (std::size_t pi = 0; pi < node->size(); ++pi) {
	 const NodePtr& subnode = node->get_operand(pi);
	 if (subnode->is_leaf()) {
	    Token t = subnode->get_token();
	    switch (t.get_tokenval()) {
	       case parser::token::TEXT_LITERAL: {
		     expand_text(out, t, indent);
		     int new_indent = get_indent(t.get_text());
		     if (new_indent >= 0) add_indent = new_indent;
		     break;
		  }
	       case parser::token::VARIABLE:
		  if (!expand_variable(out, t.get_text(), rules,
			indent + add_indent,
			bindings, local_bindings, context)) {
		     std::ostringstream os;
		     os << "undefined variable in replacement text: " <<
			t.get_text();
		     throw Exception(subnode->get_location(), os.str());
		  }
		  break;
	       default:
		  assert(false); std::abort();
	    }
	 } else if (subnode->get_op() == Op::print_expression_listvar) {
	    std::string varname =
	       subnode->get_operand(0)->get_token().get_text();
	    if (!local_bindings->defined(varname)) {
	       std::ostringstream os;
	       os << "undefined variable in replacement list: " <<
		  varname;
	       throw Exception(subnode->get_location(), os.str());
	    }
	    AttributePtr list = local_bindings->get(varname);
	    if (list->get_type() != Attribute::list) {
	       std::ostringstream os;
	       os << "list expected: " << varname;
	       throw Exception(subnode->get_location(), os.str());
	    }
	    if (list->size() > 0) {
	       recursive_print(out, list->get_value(0)->get_node(),
		  rules, bindings, indent + add_indent, context);
	    }
	    for (std::size_t i = 1; i < list->size(); ++i) {
	       if (subnode->size() == 2) {
		  Token t = subnode->get_operand(1)->get_token();
		  expand_text(out, t, indent);
		  int new_indent = get_indent(t.get_text());
		  if (new_indent >= 0) add_indent = new_indent;
	       }
	       recursive_print(out, list->get_value(i)->get_node(),
		  rules, bindings, indent + add_indent, context);
	    }
	 } else {
	    assert(subnode->get_op() == Op::expression);
	    Expression expr(subnode, local_bindings);
	    if (!recursive_print(out, expr.convert_to_node(),
		  rules, bindings, indent, context)) {
	       return false;
	    }
	 }
      }
   }
   context.ascend();
   return true;
}
Ejemplo n.º 4
0
/* This routine will expand the pathname to account for ~ and $
 * characters as described above.  Returns a pointer to a newly
 * malloc'd string.  If an error occurs, an error message is printed
 * via error() and NULL is returned.  FILE and LINE are the filename
 * and linenumber to include in the error message.  FILE must point
 * to something; LINE can be zero to indicate the line number is not
 * known.
 *
 * When FORMATSAFE is set, percent signs (`%') in variable contents are doubled
 * to prevent later expansion by format_cmdline.
 *
 * CVSROOT is used to expanding $CVSROOT.
 */
char *
expand_path (const char *name, const char *cvsroot, bool formatsafe,
	     const char *file, int line)
{
    size_t s, d, p;
    const char *e;

    char *mybuf = NULL;
    size_t mybuf_size = 0;
    char *buf = NULL;
    size_t buf_size = 0;

    char inquotes = '\0';

    char *result;

    /* Sorry this routine is so ugly; it is a head-on collision
       between the `traditional' unix *d++ style and the need to
       dynamically allocate.  It would be much cleaner (and probably
       faster, not that this is a bottleneck for CVS) with more use of
       strcpy & friends, but I haven't taken the effort to rewrite it
       thusly.  */

    /* First copy from NAME to MYBUF, expanding $<foo> as we go.  */
    s = d = 0;
    expand_string (&mybuf, &mybuf_size, d + 1);
    while ((mybuf[d++] = name[s]) != '\0')
    {
	if (name[s] == '\\')
	{
	    /* The next character is a literal.  Leave the \ in the string
	     * since it will be needed again when the string is split into
	     * arguments.
	     */
	    /* if we have a \ as the last character of the string, just leave
	     * it there - this is where we would set the escape flag to tell
	     * our parent we want another line if we cared.
	     */
	    if (name[++s])
	    {
		expand_string (&mybuf, &mybuf_size, d + 1);
		mybuf[d++] = name[s++];
	    }
	}
	/* skip $ variable processing for text inside single quotes */
	else if (inquotes == '\'')
	{
	    if (name[s++] == '\'')
	    {
		inquotes = '\0';
	    }
	}
	else if (name[s] == '\'')
	{
	    s++;
	    inquotes = '\'';
	}
	else if (name[s] == '"')
	{
	    s++;
	    if (inquotes) inquotes = '\0';
	    else inquotes = '"';
	}
	else if (name[s++] == '$')
	{
	    int flag = (name[s] == '{');
	    p = d;

	    expand_string (&mybuf, &mybuf_size, d + 1);
	    for (; (mybuf[d++] = name[s]); s++)
	    {
		if (flag
		    ? name[s] =='}'
		    : !isalnum (name[s]) && name[s] != '_')
		    break;
		expand_string (&mybuf, &mybuf_size, d + 1);
	    }
	    mybuf[--d] = '\0';
	    e = expand_variable (&mybuf[p+flag], cvsroot, file, line);

	    if (e)
	    {
		expand_string (&mybuf, &mybuf_size, d + 1);
		for (d = p - 1; (mybuf[d++] = *e++); )
		{
		    expand_string (&mybuf, &mybuf_size, d + 1);
		    if (mybuf[d-1] == '"')
		    {
			/* escape the double quotes if we're between a matched
			 * pair of double quotes so that this sub will be
			 * passed inside as or as part of a single argument
			 * during the argument split later.
			 */
			if (inquotes)
			{
			    mybuf[d-1] = '\\';
			    expand_string (&mybuf, &mybuf_size, d + 1);
			    mybuf[d++] = '"';
			}
		    }
		    else if (formatsafe && mybuf[d-1] == '%')
		    {
			/* escape '%' to get past printf style format strings
			 * later (in make_cmdline).
			 */
			expand_string (&mybuf, &mybuf_size, d + 1);
			mybuf[d] = '%';
			d++;
		    }
		}
		--d;
		if (flag && name[s])
		    s++;
	    }
	    else
		/* expand_variable has already printed an error message.  */
		goto error_exit;
	}
	expand_string (&mybuf, &mybuf_size, d + 1);
    }
    expand_string (&mybuf, &mybuf_size, d + 1);
    mybuf[d] = '\0';

    /* Then copy from MYBUF to BUF, expanding ~.  */
    s = d = 0;
    /* If you don't want ~username ~/ to be expanded simply remove
     * This entire if statement including the else portion
     */
    if (mybuf[s] == '~')
    {
	p = d;
	while (mybuf[++s] != '/' && mybuf[s] != '\0')
	{
	    expand_string (&buf, &buf_size, p + 1);
	    buf[p++] = name[s];
	}
	expand_string (&buf, &buf_size, p + 1);
	buf[p] = '\0';

	if (p == d)
	    e = get_homedir ();
	else
	{
#ifdef GETPWNAM_MISSING
	    if (line)
		error (0, 0,
		       "%s:%d:tilde expansion not supported on this system",
		       file, line);
	    else
		error (0, 0, "%s:tilde expansion not supported on this system",
		       file);
	    goto error_exit;
#else
	    struct passwd *ps;
	    ps = getpwnam (buf + d);
	    if (ps == NULL)
	    {
		if (line)
		    error (0, 0, "%s:%d: no such user %s",
			   file, line, buf + d);
		else
		    error (0, 0, "%s: no such user %s", file, buf + d);
		goto error_exit;
	    }
	    e = ps->pw_dir;
#endif
	}
	if (!e)
	    error (1, 0, "cannot find home directory");

	p = strlen (e);
	expand_string (&buf, &buf_size, d + p);
	memcpy (buf + d, e, p);
	d += p;
    }
    /* Kill up to here */
    p = strlen (mybuf + s) + 1;
    expand_string (&buf, &buf_size, d + p);
    memcpy (buf + d, mybuf + s, p);

    /* OK, buf contains the value we want to return.  Clean up and return
       it.  */
    free (mybuf);
    /* Save a little memory with xstrdup; buf will tend to allocate
       more than it needs to.  */
    result = xstrdup (buf);
    free (buf);
    return result;

 error_exit:
    if (mybuf) free (mybuf);
    if (buf) free (buf);
    return NULL;
}