diff --git a/src/Makefile.am b/src/Makefile.am
index a8276ac3..36ab8f51 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -171,6 +171,8 @@ conky_SOURCES = \
$(weather) \
$(lua) \
$(solaris) \
+ template.c \
+ template.h \
timed_thread.c \
timed_thread.h \
mboxscan.c \
@@ -239,6 +241,8 @@ EXTRA_DIST = \
specials.h \
tailhead.c \
tailhead.h \
+ template.c \
+ template.h \
top.h \
diskio.h \
x11.c \
diff --git a/src/conky.c b/src/conky.c
index 59987dad..40cb317b 100644
--- a/src/conky.c
+++ b/src/conky.c
@@ -87,6 +87,7 @@
#include "mboxscan.h"
#include "specials.h"
#include "temphelper.h"
+#include "template.h"
#include "tailhead.h"
#include "top.h"
@@ -381,13 +382,6 @@ static int sensor_device;
long color0, color1, color2, color3, color4, color5, color6, color7, color8,
color9;
-static char *template[MAX_TEMPLATES];
-
-char **get_templates(void)
-{
- return template;
-}
-
/* maximum size of config TEXT buffer, i.e. below TEXT line. */
unsigned int max_user_text;
@@ -4886,12 +4880,7 @@ void clean_up(void *memtofree1, void* memtofree2)
#endif /* X11 */
- for (i = 0; i < MAX_TEMPLATES; i++) {
- if (template[i]) {
- free(template[i]);
- template[i] = NULL;
- }
- }
+ free_templates();
free_text_objects(&global_root_object, 0);
if (tmpstring1) {
@@ -5035,7 +5024,6 @@ static void set_default_configurations_for_x(void)
static void set_default_configurations(void)
{
- int i;
#ifdef MPD
char *mpd_env_host;
char *mpd_env_port;
@@ -5141,11 +5129,7 @@ static void set_default_configurations(void)
info.x11.desktop.name = NULL;
#endif /* X11 */
- for (i = 0; i < MAX_TEMPLATES; i++) {
- if (template[i])
- free(template[i]);
- template[i] = strdup("");
- }
+ free_templates();
free(current_mail_spool);
{
@@ -5463,12 +5447,8 @@ char load_config_file(const char *f)
#endif /* X11 */
#define TEMPLATE_CONF(n) \
CONF("template"#n) { \
- if (value) { \
- free(template[n]); \
- template[n] = strdup(value); \
- } else { \
+ if (set_template(n, value)) \
CONF_ERR; \
- } \
}
TEMPLATE_CONF(0)
TEMPLATE_CONF(1)
@@ -6604,7 +6584,7 @@ int main(int argc, char **argv)
max_user_text = MAX_USER_TEXT_DEFAULT;
current_config = 0;
memset(&info, 0, sizeof(info));
- memset(template, 0, sizeof(template));
+ free_templates();
clear_net_stats();
#ifdef TCP_PORT_MONITOR
diff --git a/src/core.c b/src/core.c
index aa7c8e69..bfc636ed 100644
--- a/src/core.c
+++ b/src/core.c
@@ -46,6 +46,7 @@
#include "mboxscan.h"
#include "specials.h"
#include "temphelper.h"
+#include "template.h"
#include "tailhead.h"
#include "top.h"
@@ -2173,197 +2174,6 @@ struct text_object *construct_text_object(const char *s, const char *arg, long
return obj;
}
-/* backslash_escape - do the actual substitution task for template objects
- *
- * The field templates is used for substituting the \N occurences. Set it to
- * NULL to leave them as they are.
- */
-static char *backslash_escape(const char *src, char **templates, unsigned int template_count)
-{
- char *src_dup;
- const char *p;
- unsigned int dup_idx = 0, dup_len;
-
- dup_len = strlen(src) + 1;
- src_dup = malloc(dup_len * sizeof(char));
-
- p = src;
- while (*p) {
- switch (*p) {
- case '\\':
- if (!*(p + 1))
- break;
- if (*(p + 1) == '\\') {
- src_dup[dup_idx++] = '\\';
- p++;
- } else if (*(p + 1) == ' ') {
- src_dup[dup_idx++] = ' ';
- p++;
- } else if (*(p + 1) == 'n') {
- src_dup[dup_idx++] = '\n';
- p++;
- } else if (templates) {
- unsigned int tmpl_num;
- int digits;
- if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
- (tmpl_num > template_count))
- break;
- dup_len += strlen(templates[tmpl_num - 1]);
- src_dup = realloc(src_dup, dup_len * sizeof(char));
- sprintf(src_dup + dup_idx, "%s", templates[tmpl_num - 1]);
- dup_idx += strlen(templates[tmpl_num - 1]);
- p += digits;
- }
- break;
- default:
- src_dup[dup_idx++] = *p;
- break;
- }
- p++;
- }
- src_dup[dup_idx] = '\0';
- src_dup = realloc(src_dup, (strlen(src_dup) + 1) * sizeof(char));
- return src_dup;
-}
-
-/* handle_template_object - core logic of the template object
- *
- * use config variables like this:
- * template1 = "$\1\2"
- * template2 = "\1: ${fs_bar 4,100 \2} ${fs_used \2} / ${fs_size \2}"
- *
- * and use them like this:
- * ${template1 node name}
- * ${template2 root /}
- * ${template2 cdrom /mnt/cdrom}
- */
-static char *handle_template(const char *tmpl, const char *args)
-{
- char *args_dup = NULL;
- char *p, *p_old;
- char **argsp = NULL;
- unsigned int argcnt = 0, template_idx, i;
- char *eval_text;
-
- if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
- (template_idx >= MAX_TEMPLATES))
- return NULL;
-
- if(args) {
- args_dup = strdup(args);
- p = args_dup;
- while (*p) {
- while (*p && (*p == ' ' && (p == args_dup || *(p - 1) != '\\')))
- p++;
- if (p > args_dup && *(p - 1) == '\\')
- p--;
- p_old = p;
- while (*p && (*p != ' ' || (p > args_dup && *(p - 1) == '\\')))
- p++;
- if (*p) {
- (*p) = '\0';
- p++;
- }
- argsp = realloc(argsp, ++argcnt * sizeof(char *));
- argsp[argcnt - 1] = p_old;
- }
- for (i = 0; i < argcnt; i++) {
- char *tmp;
- tmp = backslash_escape(argsp[i], NULL, 0);
- DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
- argsp[i] = tmp;
- }
- }
-
- eval_text = backslash_escape(get_templates()[template_idx], argsp, argcnt);
- DBGP("substituted %s, output is '%s'", tmpl, eval_text);
- free(args_dup);
- for (i = 0; i < argcnt; i++)
- free(argsp[i]);
- free(argsp);
- return eval_text;
-}
-
-static char *find_and_replace_templates(const char *inbuf)
-{
- char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
- int stack, outlen;
-
- outlen = strlen(inbuf) + 1;
- o = outbuf = calloc(outlen, sizeof(char));
- memset(outbuf, 0, outlen * sizeof(char));
-
- p = indup = strdup(inbuf);
- while (*p) {
- while (*p && *p != '$')
- *(o++) = *(p++);
-
- if (!(*p))
- break;
-
- if (strncmp(p, "$template", 9) && strncmp(p, "${template", 10)) {
- *(o++) = *(p++);
- continue;
- }
-
- if (*(p + 1) == '{') {
- p += 2;
- templ = p;
- while (*p && !isspace(*p) && *p != '{' && *p != '}')
- p++;
- if (*p == '}')
- args = NULL;
- else
- args = p;
-
- stack = 1;
- while (*p && stack > 0) {
- if (*p == '{')
- stack++;
- else if (*p == '}')
- stack--;
- p++;
- }
- if (stack == 0) {
- // stack is empty. that means the previous char was }, so we zero it
- *(p - 1) = '\0';
- } else {
- // we ran into the end of string without finding a closing }, bark
- CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
- }
- } else {
- templ = p + 1;
- while (*p && !isspace(*p))
- p++;
- args = NULL;
- }
- tmpl_out = handle_template(templ, args);
- if (tmpl_out) {
- outlen += strlen(tmpl_out);
- *o = '\0';
- outbuf = realloc(outbuf, outlen * sizeof(char));
- strcat (outbuf, tmpl_out);
- free(tmpl_out);
- o = outbuf + strlen(outbuf);
- } else {
- NORM_ERR("failed to handle template '%s' with args '%s'", templ, args);
- }
- }
- *o = '\0';
- outbuf = realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char));
- free(indup);
- return outbuf;
-}
-
-static int text_contains_templates(const char *text)
-{
- if (strcasestr(text, "${template") != NULL)
- return 1;
- if (strcasestr(text, "$template") != NULL)
- return 1;
- return 0;
-}
-
/*
* - assumes that *string is '#'
* - removes the part from '#' to the end of line ('\n' or '\0')
diff --git a/src/template.c b/src/template.c
new file mode 100644
index 00000000..b98166ac
--- /dev/null
+++ b/src/template.c
@@ -0,0 +1,270 @@
+/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
+ *
+ * Conky, a system monitor, based on torsmo
+ *
+ * Any original torsmo code is licensed under the BSD license
+ *
+ * All code written since the fork of torsmo is licensed under the GPL
+ *
+ * Please see COPYING for details
+ *
+ * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
+ * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ * (see AUTHORS)
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * vim: ts=4 sw=4 noet ai cindent syntax=c
+ *
+ */
+#include "conky.h"
+#include "logging.h"
+#include
+#include
+#include
+/* The templates defined by the user.
+ *
+ * This is a 1 to 1 mapping from templateN config option to template[N] field. */
+static char *template[MAX_TEMPLATES];
+
+/* free all templates
+ *
+ * On first invocation, just memset all pointers to zero, so this function can
+ * be used when initialising data upon startup. */
+void free_templates(void)
+{
+ int i;
+ static int initialised = 0;
+
+ if (!initialised) {
+ memset(template, 0, MAX_TEMPLATES * sizeof(char *));
+ initialised = 1;
+ return;
+ }
+
+ for (i = 0; i < MAX_TEMPLATES; i++) {
+ if (template[i]) {
+ free(template[i]);
+ template[i] = NULL;
+ }
+ }
+}
+
+/* set the value of template at index n
+ *
+ * Returns non-zero on illegal arguments passed, zero otherwise. */
+int set_template(int n, const char *val)
+{
+ if (n < 0 || n >= MAX_TEMPLATES || !val)
+ return 1;
+ if (template[n])
+ free(template[n]);
+ template[n] = strdup(val);
+ return 0;
+}
+
+/* backslash_escape - do the actual substitution task for template objects
+ *
+ * The field templates is used for substituting the \N occurences. Set it to
+ * NULL to leave them as they are.
+ */
+static char *backslash_escape(const char *src, char **templates, unsigned int template_count)
+{
+ char *src_dup;
+ const char *p;
+ unsigned int dup_idx = 0, dup_len;
+
+ dup_len = strlen(src) + 1;
+ src_dup = malloc(dup_len * sizeof(char));
+
+ p = src;
+ while (*p) {
+ switch (*p) {
+ case '\\':
+ if (!*(p + 1))
+ break;
+ if (*(p + 1) == '\\') {
+ src_dup[dup_idx++] = '\\';
+ p++;
+ } else if (*(p + 1) == ' ') {
+ src_dup[dup_idx++] = ' ';
+ p++;
+ } else if (*(p + 1) == 'n') {
+ src_dup[dup_idx++] = '\n';
+ p++;
+ } else if (templates) {
+ unsigned int tmpl_num;
+ int digits;
+ if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
+ (tmpl_num > template_count))
+ break;
+ dup_len += strlen(templates[tmpl_num - 1]);
+ src_dup = realloc(src_dup, dup_len * sizeof(char));
+ sprintf(src_dup + dup_idx, "%s", templates[tmpl_num - 1]);
+ dup_idx += strlen(templates[tmpl_num - 1]);
+ p += digits;
+ }
+ break;
+ default:
+ src_dup[dup_idx++] = *p;
+ break;
+ }
+ p++;
+ }
+ src_dup[dup_idx] = '\0';
+ src_dup = realloc(src_dup, (strlen(src_dup) + 1) * sizeof(char));
+ return src_dup;
+}
+
+/* handle_template_object - core logic of the template object
+ *
+ * use config variables like this:
+ * template1 = "$\1\2"
+ * template2 = "\1: ${fs_bar 4,100 \2} ${fs_used \2} / ${fs_size \2}"
+ *
+ * and use them like this:
+ * ${template1 node name}
+ * ${template2 root /}
+ * ${template2 cdrom /mnt/cdrom}
+ */
+static char *handle_template(const char *tmpl, const char *args)
+{
+ char *args_dup = NULL;
+ char *p, *p_old;
+ char **argsp = NULL;
+ unsigned int argcnt = 0, template_idx, i;
+ char *eval_text;
+
+ if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
+ (template_idx >= MAX_TEMPLATES))
+ return NULL;
+
+ if(args) {
+ args_dup = strdup(args);
+ p = args_dup;
+ while (*p) {
+ while (*p && (*p == ' ' && (p == args_dup || *(p - 1) != '\\')))
+ p++;
+ if (p > args_dup && *(p - 1) == '\\')
+ p--;
+ p_old = p;
+ while (*p && (*p != ' ' || (p > args_dup && *(p - 1) == '\\')))
+ p++;
+ if (*p) {
+ (*p) = '\0';
+ p++;
+ }
+ argsp = realloc(argsp, ++argcnt * sizeof(char *));
+ argsp[argcnt - 1] = p_old;
+ }
+ for (i = 0; i < argcnt; i++) {
+ char *tmp;
+ tmp = backslash_escape(argsp[i], NULL, 0);
+ DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
+ argsp[i] = tmp;
+ }
+ }
+
+ eval_text = backslash_escape(template[template_idx], argsp, argcnt);
+ DBGP("substituted %s, output is '%s'", tmpl, eval_text);
+ free(args_dup);
+ for (i = 0; i < argcnt; i++)
+ free(argsp[i]);
+ free(argsp);
+ return eval_text;
+}
+
+/* Search inbuf and replace all found template object references
+ * with the substituted value. */
+char *find_and_replace_templates(const char *inbuf)
+{
+ char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
+ int stack, outlen;
+
+ outlen = strlen(inbuf) + 1;
+ o = outbuf = calloc(outlen, sizeof(char));
+ memset(outbuf, 0, outlen * sizeof(char));
+
+ p = indup = strdup(inbuf);
+ while (*p) {
+ while (*p && *p != '$')
+ *(o++) = *(p++);
+
+ if (!(*p))
+ break;
+
+ if (strncmp(p, "$template", 9) && strncmp(p, "${template", 10)) {
+ *(o++) = *(p++);
+ continue;
+ }
+
+ if (*(p + 1) == '{') {
+ p += 2;
+ templ = p;
+ while (*p && !isspace(*p) && *p != '{' && *p != '}')
+ p++;
+ if (*p == '}')
+ args = NULL;
+ else
+ args = p;
+
+ stack = 1;
+ while (*p && stack > 0) {
+ if (*p == '{')
+ stack++;
+ else if (*p == '}')
+ stack--;
+ p++;
+ }
+ if (stack == 0) {
+ // stack is empty. that means the previous char was }, so we zero it
+ *(p - 1) = '\0';
+ } else {
+ // we ran into the end of string without finding a closing }, bark
+ CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
+ }
+ } else {
+ templ = p + 1;
+ while (*p && !isspace(*p))
+ p++;
+ args = NULL;
+ }
+ tmpl_out = handle_template(templ, args);
+ if (tmpl_out) {
+ outlen += strlen(tmpl_out);
+ *o = '\0';
+ outbuf = realloc(outbuf, outlen * sizeof(char));
+ strcat (outbuf, tmpl_out);
+ free(tmpl_out);
+ o = outbuf + strlen(outbuf);
+ } else {
+ NORM_ERR("failed to handle template '%s' with args '%s'", templ, args);
+ }
+ }
+ *o = '\0';
+ outbuf = realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char));
+ free(indup);
+ return outbuf;
+}
+
+/* check text for any template object references */
+int text_contains_templates(const char *text)
+{
+ if (strcasestr(text, "${template") != NULL)
+ return 1;
+ if (strcasestr(text, "$template") != NULL)
+ return 1;
+ return 0;
+}
+
diff --git a/src/template.h b/src/template.h
new file mode 100644
index 00000000..81b3e9e6
--- /dev/null
+++ b/src/template.h
@@ -0,0 +1,41 @@
+/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
+ *
+ * Conky, a system monitor, based on torsmo
+ *
+ * Any original torsmo code is licensed under the BSD license
+ *
+ * All code written since the fork of torsmo is licensed under the GPL
+ *
+ * Please see COPYING for details
+ *
+ * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
+ * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ * (see AUTHORS)
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * vim: ts=4 sw=4 noet ai cindent syntax=c
+ *
+ */
+
+#ifndef _TEMPLATE_H
+#define _TEMPLATE_H
+
+void free_templates(void);
+int set_template(int, const char *);
+
+char *find_and_replace_templates(const char *);
+int text_contains_templates(const char *);
+
+#endif /* _TEMPLATE_H */