2018-05-12 16:03:00 +00:00
|
|
|
/*
|
2009-09-03 21:53:20 +00:00
|
|
|
*
|
|
|
|
* 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
|
2019-01-05 15:52:43 +00:00
|
|
|
* Copyright (c) 2005-2019 Brenden Matthews, Philip Kovacs, et. al.
|
2009-09-03 21:53:20 +00:00
|
|
|
* (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 <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
2018-05-12 23:26:31 +00:00
|
|
|
#include <cctype>
|
|
|
|
#include <cstdlib>
|
2010-02-08 23:28:33 +00:00
|
|
|
#include <string>
|
2018-05-12 16:03:00 +00:00
|
|
|
#include "conky.h"
|
|
|
|
#include "logging.h"
|
2009-09-03 21:53:20 +00:00
|
|
|
|
2010-06-20 22:37:58 +00:00
|
|
|
namespace {
|
2018-05-12 16:03:00 +00:00
|
|
|
conky::simple_config_setting<std::string> _template[10] = {
|
|
|
|
{"template0", std::string(), true}, {"template1", std::string(), true},
|
|
|
|
{"template2", std::string(), true}, {"template3", std::string(), true},
|
|
|
|
{"template4", std::string(), true}, {"template5", std::string(), true},
|
|
|
|
{"template6", std::string(), true}, {"template7", std::string(), true},
|
|
|
|
{"template8", std::string(), true}, {"template9", std::string(), true}};
|
2018-05-12 23:26:31 +00:00
|
|
|
} // namespace
|
2009-09-03 21:53:20 +00:00
|
|
|
|
|
|
|
/* backslash_escape - do the actual substitution task for template objects
|
|
|
|
*
|
|
|
|
* The field templates is used for substituting the \N occurences. Set it to
|
2018-05-12 23:26:31 +00:00
|
|
|
* nullptr to leave them as they are.
|
2009-09-03 21:53:20 +00:00
|
|
|
*/
|
2018-05-12 16:03:00 +00:00
|
|
|
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;
|
2018-05-12 23:26:31 +00:00
|
|
|
src_dup = static_cast<char *>(malloc(dup_len * sizeof(char)));
|
2018-05-12 16:03:00 +00:00
|
|
|
|
|
|
|
p = src;
|
2018-05-12 23:26:31 +00:00
|
|
|
while (*p != 0) {
|
2018-05-12 16:03:00 +00:00
|
|
|
switch (*p) {
|
|
|
|
case '\\':
|
2018-05-13 22:46:09 +00:00
|
|
|
if (*(p + 1) == 0) { break; }
|
2018-05-12 16:03:00 +00:00
|
|
|
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++;
|
2018-05-12 23:26:31 +00:00
|
|
|
} else if (templates != nullptr) {
|
2018-05-12 16:03:00 +00:00
|
|
|
unsigned int tmpl_num;
|
|
|
|
int digits;
|
|
|
|
if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
|
2018-05-12 23:26:31 +00:00
|
|
|
(tmpl_num > template_count)) {
|
2018-05-12 16:03:00 +00:00
|
|
|
break;
|
2018-05-12 23:26:31 +00:00
|
|
|
}
|
2018-05-12 16:03:00 +00:00
|
|
|
if (tmpl_num == 0)
|
|
|
|
CRIT_ERR(
|
2018-05-12 23:26:31 +00:00
|
|
|
nullptr, nullptr,
|
2018-05-12 16:03:00 +00:00
|
|
|
"invalid template argument \\0; arguments must start at \\1");
|
|
|
|
dup_len += strlen(templates[tmpl_num - 1]);
|
2018-05-12 23:26:31 +00:00
|
|
|
src_dup =
|
|
|
|
static_cast<char *>(realloc(src_dup, dup_len * sizeof(char)));
|
2018-05-12 16:03:00 +00:00
|
|
|
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';
|
2018-05-12 23:26:31 +00:00
|
|
|
src_dup = static_cast<char *>(realloc(src_dup, dup_idx * sizeof(char)));
|
2018-05-12 16:03:00 +00:00
|
|
|
return src_dup;
|
2009-09-03 21:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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}
|
|
|
|
*/
|
2018-05-12 16:03:00 +00:00
|
|
|
static char *handle_template(const char *tmpl, const char *args) {
|
2018-05-12 23:26:31 +00:00
|
|
|
char *args_dup = nullptr;
|
2018-05-12 16:03:00 +00:00
|
|
|
char *p, *p_old;
|
2018-05-12 23:26:31 +00:00
|
|
|
char **argsp = nullptr;
|
2018-05-12 16:03:00 +00:00
|
|
|
unsigned int argcnt = 0, template_idx, i;
|
|
|
|
char *eval_text;
|
|
|
|
|
|
|
|
if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
|
2018-05-12 23:26:31 +00:00
|
|
|
(template_idx >= MAX_TEMPLATES)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-05-12 16:03:00 +00:00
|
|
|
|
2018-05-12 23:26:31 +00:00
|
|
|
if (args != nullptr) {
|
2018-05-12 16:03:00 +00:00
|
|
|
args_dup = strdup(args);
|
|
|
|
p = args_dup;
|
2018-05-12 23:26:31 +00:00
|
|
|
while (*p != 0) {
|
|
|
|
while ((*p != 0) && (*p == ' ' && (p == args_dup || *(p - 1) != '\\'))) {
|
|
|
|
p++;
|
|
|
|
}
|
2018-05-13 22:46:09 +00:00
|
|
|
if (p > args_dup && *(p - 1) == '\\') { p--; }
|
2018-05-12 16:03:00 +00:00
|
|
|
p_old = p;
|
2018-05-12 23:26:31 +00:00
|
|
|
while ((*p != 0) && (*p != ' ' || (p > args_dup && *(p - 1) == '\\'))) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p != 0) {
|
2018-05-12 16:03:00 +00:00
|
|
|
(*p) = '\0';
|
|
|
|
p++;
|
|
|
|
}
|
2018-05-12 23:26:31 +00:00
|
|
|
argsp = static_cast<char **>(realloc(argsp, ++argcnt * sizeof(char *)));
|
2018-05-12 16:03:00 +00:00
|
|
|
argsp[argcnt - 1] = p_old;
|
|
|
|
}
|
|
|
|
for (i = 0; i < argcnt; i++) {
|
|
|
|
char *tmp;
|
2018-05-12 23:26:31 +00:00
|
|
|
tmp = backslash_escape(argsp[i], nullptr, 0);
|
2018-05-12 16:03:00 +00:00
|
|
|
DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
|
|
|
|
argsp[i] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
eval_text = backslash_escape(_template[template_idx].get(*state).c_str(),
|
|
|
|
argsp, argcnt);
|
|
|
|
DBGP("substituted %s, output is '%s'", tmpl, eval_text);
|
|
|
|
free(args_dup);
|
2018-05-13 22:46:09 +00:00
|
|
|
for (i = 0; i < argcnt; i++) { free(argsp[i]); }
|
2018-05-12 16:03:00 +00:00
|
|
|
free(argsp);
|
|
|
|
return eval_text;
|
2009-09-03 21:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Search inbuf and replace all found template object references
|
|
|
|
* with the substituted value. */
|
2018-05-12 16:03:00 +00:00
|
|
|
char *find_and_replace_templates(const char *inbuf) {
|
|
|
|
char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
|
|
|
|
int stack, outlen;
|
|
|
|
|
|
|
|
outlen = strlen(inbuf) + 1;
|
2018-05-12 23:26:31 +00:00
|
|
|
o = outbuf = static_cast<char *>(calloc(outlen, sizeof(char)));
|
2018-05-12 16:03:00 +00:00
|
|
|
memset(outbuf, 0, outlen * sizeof(char));
|
|
|
|
|
|
|
|
p = indup = strdup(inbuf);
|
2018-05-12 23:26:31 +00:00
|
|
|
while (*p != 0) {
|
2018-05-13 22:46:09 +00:00
|
|
|
while ((*p != 0) && *p != '$') { *(o++) = *(p++); }
|
2018-05-12 16:03:00 +00:00
|
|
|
|
2018-05-13 22:46:09 +00:00
|
|
|
if ((*p) == 0) { break; }
|
2018-05-12 16:03:00 +00:00
|
|
|
|
2018-05-12 23:26:31 +00:00
|
|
|
if ((static_cast<int>(strncmp(p, "$template", strlen("$template")) != 0) !=
|
|
|
|
0) &&
|
|
|
|
(strncmp(p, "${template", strlen("${template")) != 0)) {
|
2018-05-12 16:03:00 +00:00
|
|
|
*(o++) = *(p++);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*(p + 1) == '{') {
|
|
|
|
p += 2;
|
|
|
|
templ = p;
|
2018-08-02 15:15:16 +00:00
|
|
|
while ((*p != 0) && (isspace((unsigned char)*p) == 0) && *p != '{' && *p != '}') { p++; }
|
2018-05-12 23:26:31 +00:00
|
|
|
if (*p == '}') {
|
|
|
|
args = nullptr;
|
|
|
|
} else {
|
2018-05-12 16:03:00 +00:00
|
|
|
args = p;
|
2018-05-12 23:26:31 +00:00
|
|
|
}
|
2018-05-12 16:03:00 +00:00
|
|
|
|
|
|
|
stack = 1;
|
2018-05-12 23:26:31 +00:00
|
|
|
while ((*p != 0) && stack > 0) {
|
|
|
|
if (*p == '{') {
|
2018-05-12 16:03:00 +00:00
|
|
|
stack++;
|
2018-05-12 23:26:31 +00:00
|
|
|
} else if (*p == '}') {
|
2018-05-12 16:03:00 +00:00
|
|
|
stack--;
|
2018-05-12 23:26:31 +00:00
|
|
|
}
|
2018-05-12 16:03:00 +00:00
|
|
|
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
|
2018-05-12 23:26:31 +00:00
|
|
|
CRIT_ERR(nullptr, nullptr,
|
|
|
|
"cannot find a closing '}' in template expansion");
|
2018-05-12 16:03:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
templ = p + 1;
|
|
|
|
p += strlen("$template");
|
2018-08-02 15:15:16 +00:00
|
|
|
while ((*p != 0) && (isdigit((unsigned char)*p) != 0)) { p++; }
|
2018-05-12 23:26:31 +00:00
|
|
|
args = nullptr;
|
2018-05-12 16:03:00 +00:00
|
|
|
}
|
|
|
|
tmpl_out = handle_template(templ, args);
|
2018-05-12 23:26:31 +00:00
|
|
|
if (tmpl_out != nullptr) {
|
2018-05-13 22:46:09 +00:00
|
|
|
int len = strlen(tmpl_out);
|
|
|
|
outlen += len;
|
2018-05-12 16:03:00 +00:00
|
|
|
*o = '\0';
|
2018-05-12 23:26:31 +00:00
|
|
|
outbuf = static_cast<char *>(realloc(outbuf, outlen * sizeof(char)));
|
2018-05-13 22:46:09 +00:00
|
|
|
strncat(outbuf, tmpl_out, len);
|
2018-05-12 16:03:00 +00:00
|
|
|
free(tmpl_out);
|
|
|
|
o = outbuf + strlen(outbuf);
|
|
|
|
} else {
|
|
|
|
NORM_ERR("failed to handle template '%s' with args '%s'", templ, args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*o = '\0';
|
2018-05-12 23:26:31 +00:00
|
|
|
outbuf =
|
|
|
|
static_cast<char *>(realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char)));
|
2018-05-12 16:03:00 +00:00
|
|
|
free(indup);
|
|
|
|
return outbuf;
|
2009-09-03 21:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check text for any template object references */
|
2018-05-12 16:03:00 +00:00
|
|
|
int text_contains_templates(const char *text) {
|
2018-05-13 22:46:09 +00:00
|
|
|
if (strcasestr(text, "${template") != nullptr) { return 1; }
|
|
|
|
if (strcasestr(text, "$template") != nullptr) { return 1; }
|
2018-05-12 16:03:00 +00:00
|
|
|
return 0;
|
2009-09-03 21:53:20 +00:00
|
|
|
}
|