/* * This file is part of Cockpit. * * Copyright (C) 2014 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * Cockpit is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Cockpit; If not, see . */ #include "config.h" #include "cockpittemplate.h" #include #include #define VARCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-" static gchar * find_variable (const gchar *start_marker, const gchar *end_marker, const gchar *data, const gchar *end, const gchar **before, const gchar **after) { const gchar *a; const gchar *b; const gchar *c; const gchar *d; for (;;) { /* Look for start_marker to end_marker */ a = memmem (data, strlen(data), start_marker, strlen (start_marker)); if (a == NULL) return NULL; data = a + strlen (start_marker); b = data; c = memmem (data, strlen(data), end_marker, strlen (end_marker)); if (c == NULL) return NULL; data = c + strlen (end_marker); d = data; /* * We've found a variable like this: * * Some text @@variable.part@@ trailing. * a b c d * * Check that the name makes sense. */ if (b != c && b + strspn (b, VARCHARS) == c) break; } if (before) *before = a; if (after) *after = d; return g_strndup (b, c - b); } GList * cockpit_template_expand (GBytes *input, CockpitTemplateFunc func, const gchar *start_marker, const gchar *end_marker, gpointer user_data) { GList *output = NULL; const gchar *data; const gchar *end; const gchar *before; const gchar *after; GBytes *bytes; gchar *name; gboolean escaped; gint before_len; g_return_val_if_fail (func != NULL, NULL); data = g_bytes_get_data (input, NULL); end = data + g_bytes_get_size (input); for (;;) { escaped = FALSE; name = find_variable (start_marker, end_marker, data, end, &before, &after); if (name == NULL) break; if (before != data) { g_assert (before > data); /* Check if the char before the match is the escape char '/' */ before_len = before - data; if (data[before_len - 1] == '\\') { escaped = TRUE; before_len--; } bytes = g_bytes_new_with_free_func (data, before_len, (GDestroyNotify)g_bytes_unref, g_bytes_ref (input)); output = g_list_prepend (output, bytes); } if (!escaped) bytes = (func) (name, user_data); else bytes = NULL; // Set bytes to null so it's treated as skipped g_free (name); if (!bytes) { g_assert (after > before); bytes = g_bytes_new_with_free_func (before, after - before, (GDestroyNotify)g_bytes_unref, g_bytes_ref (input)); } if (g_bytes_get_size (bytes) > 0) output = g_list_prepend (output, bytes); else g_bytes_unref (bytes); g_assert (after <= end); data = after; } if (data != end) { g_assert (end > data); bytes = g_bytes_new_with_free_func (data, end - data, (GDestroyNotify)g_bytes_unref, g_bytes_ref (input)); output = g_list_prepend (output, bytes); } return g_list_reverse (output); }