1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2 * vim: ts=4 sw=4 noet ai cindent syntax=c
4 * Conky, a system monitor, based on torsmo
6 * Any original torsmo code is licensed under the BSD license
8 * All code written since the fork of torsmo is licensed under the GPL
10 * Please see COPYING for details
12 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13 * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
15 * All rights reserved.
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35 /* The templates defined by the user.
37 * This is a 1 to 1 mapping from templateN config option to template[N] field. */
38 static char *template[MAX_TEMPLATES];
42 * On first invocation, just memset all pointers to zero, so this function can
43 * be used when initialising data upon startup. */
44 void free_templates(void)
47 static int initialised = 0;
50 memset(template, 0, MAX_TEMPLATES * sizeof(char *));
55 for (i = 0; i < MAX_TEMPLATES; i++) {
63 /* set the value of template at index n
65 * Returns non-zero on illegal arguments passed, zero otherwise. */
66 int set_template(int n, const char *val)
68 if (n < 0 || n >= MAX_TEMPLATES || !val)
72 template[n] = strdup(val);
76 /* backslash_escape - do the actual substitution task for template objects
78 * The field templates is used for substituting the \N occurences. Set it to
79 * NULL to leave them as they are.
81 static char *backslash_escape(const char *src, char **templates, unsigned int template_count)
85 unsigned int dup_idx = 0, dup_len;
87 dup_len = strlen(src) + 1;
88 src_dup = malloc(dup_len * sizeof(char));
96 if (*(p + 1) == '\\') {
97 src_dup[dup_idx++] = '\\';
99 } else if (*(p + 1) == ' ') {
100 src_dup[dup_idx++] = ' ';
102 } else if (*(p + 1) == 'n') {
103 src_dup[dup_idx++] = '\n';
105 } else if (templates) {
106 unsigned int tmpl_num;
108 if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
109 (tmpl_num > template_count))
111 dup_len += strlen(templates[tmpl_num - 1]);
112 src_dup = realloc(src_dup, dup_len * sizeof(char));
113 sprintf(src_dup + dup_idx, "%s", templates[tmpl_num - 1]);
114 dup_idx += strlen(templates[tmpl_num - 1]);
119 src_dup[dup_idx++] = *p;
124 src_dup[dup_idx] = '\0';
125 src_dup = realloc(src_dup, (strlen(src_dup) + 1) * sizeof(char));
129 /* handle_template_object - core logic of the template object
131 * use config variables like this:
132 * template1 = "$\1\2"
133 * template2 = "\1: ${fs_bar 4,100 \2} ${fs_used \2} / ${fs_size \2}"
135 * and use them like this:
136 * ${template1 node name}
137 * ${template2 root /}
138 * ${template2 cdrom /mnt/cdrom}
140 static char *handle_template(const char *tmpl, const char *args)
142 char *args_dup = NULL;
145 unsigned int argcnt = 0, template_idx, i;
148 if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
149 (template_idx >= MAX_TEMPLATES))
153 args_dup = strdup(args);
156 while (*p && (*p == ' ' && (p == args_dup || *(p - 1) != '\\')))
158 if (p > args_dup && *(p - 1) == '\\')
161 while (*p && (*p != ' ' || (p > args_dup && *(p - 1) == '\\')))
167 argsp = realloc(argsp, ++argcnt * sizeof(char *));
168 argsp[argcnt - 1] = p_old;
170 for (i = 0; i < argcnt; i++) {
172 tmp = backslash_escape(argsp[i], NULL, 0);
173 DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
178 eval_text = backslash_escape(template[template_idx], argsp, argcnt);
179 DBGP("substituted %s, output is '%s'", tmpl, eval_text);
181 for (i = 0; i < argcnt; i++)
187 /* Search inbuf and replace all found template object references
188 * with the substituted value. */
189 char *find_and_replace_templates(const char *inbuf)
191 char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
194 outlen = strlen(inbuf) + 1;
195 o = outbuf = calloc(outlen, sizeof(char));
196 memset(outbuf, 0, outlen * sizeof(char));
198 p = indup = strdup(inbuf);
200 while (*p && *p != '$')
206 if (strncmp(p, "$template", strlen("$template")) && strncmp(p, "${template", strlen("${template"))) {
211 if (*(p + 1) == '{') {
214 while (*p && !isspace(*p) && *p != '{' && *p != '}')
222 while (*p && stack > 0) {
230 // stack is empty. that means the previous char was }, so we zero it
233 // we ran into the end of string without finding a closing }, bark
234 CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
238 p += strlen("$template");
239 while (*p && isdigit(*p))
243 tmpl_out = handle_template(templ, args);
245 outlen += strlen(tmpl_out);
247 outbuf = realloc(outbuf, outlen * sizeof(char));
248 strcat (outbuf, tmpl_out);
250 o = outbuf + strlen(outbuf);
252 NORM_ERR("failed to handle template '%s' with args '%s'", templ, args);
256 outbuf = realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char));
261 /* check text for any template object references */
262 int text_contains_templates(const char *text)
264 if (strcasestr(text, "${template") != NULL)
266 if (strcasestr(text, "$template") != NULL)