+2008-12-20
+ * Add if_match object comparing strings, floats and ints
+
2008-12-18
* Fix segfault for diskiograph*, note the changed order of arguments
* Fix documentation for all graph objects
$if_empty and the matching $endif
+ 1mif_existing file (string)0m
+ if FILE exists, display everything between if_existing and the
+ matching $endif. The optional second paramater checks for FILE
+ containing the specified string and prints everything between
+ $if_existing and the matching $endif.
+
+
1mif_gw 22mif there is at least one default gateway, display everything be‐
tween $if_gw and the matching $endif
- 1mif_running (process)0m
- if PROCESS is running, display everything $if_running and the
- matching $endif
+ 1mif_match expression0m
+ Evaluates the given boolean expression, printing everything be‐
+ tween $if_match and the matching $endif depending on whether the
+ evaluation returns true or not. Valid expressions consist of a
+ left side, an operator and a right side. Left and right sides
+ are being parsed for contained text objects before evaluation.
+ Recognised left and right side types are:
+ 1mdouble22m: argument consists of only digits and a single dot.
+ 1mlong22m: argument consists of only digits.
+ 1mstring22m: argument is enclosed in quotation mark or the checks for
+ double and long failed before.
- 1mif_existing file (string)0m
- if FILE exists, display everything between if_existing and the
- matching $endif. The optional second paramater checks for FILE
- containing the specified string and prints everything between
- $if_existing and the matching $endif.
+ Valid operands are: ’>’, ’<’, ’>=’, ’<=’, ’==’, ’!=’.
+
+
+ 1mif_running (process)0m
+ if PROCESS is running, display everything $if_running and the
+ matching $endif
1mif_mounted (mountpoint)0m
.TP
\fB\*(T<\fBif_empty\fR\*(T>\fR \*(T<\fB(var)\fR\*(T>
-if conky variable VAR is empty, display everything between $if_empty and the matching $endif
+if conky variable VAR is empty, display everything
+between $if_empty and the matching $endif
.TP
-\fB\*(T<\fBif_gw\fR\*(T>\fR
-if there is at least one default gateway, display everything between $if_gw and the matching $endif
+\fB\*(T<\fBif_existing\fR\*(T>\fR \*(T<\fBfile (string)\fR\*(T>
+if FILE exists, display everything between if_existing
+and the matching $endif. The optional second paramater
+checks for FILE containing the specified string and
+prints everything between $if_existing and the matching
+$endif.
.TP
-\fB\*(T<\fBif_running\fR\*(T>\fR \*(T<\fB(process)\fR\*(T>
-if PROCESS is running, display everything $if_running and the matching $endif
+\fB\*(T<\fBif_gw\fR\*(T>\fR
+if there is at least one default gateway, display
+everything between $if_gw and the matching $endif
+
+.TP
+\fB\*(T<\fBif_match\fR\*(T>\fR \*(T<\fBexpression\fR\*(T>
+Evaluates the given boolean expression, printing
+everything between $if_match and the matching $endif
+depending on whether the evaluation returns true or not.
+Valid expressions consist of a left side, an operator
+and a right side. Left and right sides are being parsed
+for contained text objects before evaluation. Recognised
+left and right side types are:
+
+\fBdouble\fR:
+argument consists of only digits and a
+single dot.
+.br
+\fBlong\fR:
+argument consists of only digits.
+.br
+\fBstring\fR:
+argument is enclosed in quotation mark
+or the checks for double and long failed
+before.
+
+Valid operands are:
+\&'>', '<', '>=', '<=', '==', '!='.
.TP
-\fB\*(T<\fBif_existing\fR\*(T>\fR \*(T<\fBfile (string)\fR\*(T>
-if FILE exists, display everything between if_existing and the matching $endif. The optional second paramater checks for FILE containing the specified string and prints everything between $if_existing and the matching $endif.
+\fB\*(T<\fBif_running\fR\*(T>\fR \*(T<\fB(process)\fR\*(T>
+if PROCESS is running, display everything $if_running
+and the matching $endif
.TP
\fB\*(T<\fBif_mounted\fR\*(T>\fR \*(T<\fB(mountpoint)\fR\*(T>
-if MOUNTPOINT is mounted, display everything between $if_mounted and the matching $endif
+if MOUNTPOINT is mounted, display everything between
+$if_mounted and the matching $endif
.TP
\fB\*(T<\fBif_smapi_bat_installed\fR\*(T>\fR \*(T<\fB(INDEX)\fR\*(T>
-when using smapi, if the battery with index INDEX is installed, display everything between $if_smapi_bat_installed and the matching $endif
+when using smapi, if the battery with index INDEX is
+installed, display everything between
+$if_smapi_bat_installed and the matching $endif
.TP
\fB\*(T<\fBif_up\fR\*(T>\fR \*(T<\fB(interface)\fR\*(T>
Title of current tune with optional maximum length specifier
<para></para></listitem>
</varlistentry>
-
+
<varlistentry>
<term>
<command><option>audacious_main_volume</option></command>
<option>(var)</option>
</term>
<listitem>
- if conky variable VAR is empty, display everything between $if_empty and the matching $endif
+ if conky variable VAR is empty, display everything
+ between $if_empty and the matching $endif
+ <para></para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command><option>if_existing</option></command>
+ <option>file (string)</option>
+ </term>
+ <listitem>
+ if FILE exists, display everything between if_existing
+ and the matching $endif. The optional second paramater
+ checks for FILE containing the specified string and
+ prints everything between $if_existing and the matching
+ $endif.
<para></para></listitem>
</varlistentry>
<command><option>if_gw</option></command>
</term>
<listitem>
- if there is at least one default gateway, display everything between $if_gw and the matching $endif
+ if there is at least one default gateway, display
+ everything between $if_gw and the matching $endif
<para></para></listitem>
</varlistentry>
<varlistentry>
<term>
- <command><option>if_running</option></command>
- <option>(process)</option>
+ <command><option>if_match</option></command>
+ <option>expression</option>
</term>
<listitem>
- if PROCESS is running, display everything $if_running and the matching $endif
+ Evaluates the given boolean expression, printing
+ everything between $if_match and the matching $endif
+ depending on whether the evaluation returns true or not.
+ Valid expressions consist of a left side, an operator
+ and a right side. Left and right sides are being parsed
+ for contained text objects before evaluation. Recognised
+ left and right side types are:
+ <simplelist>
+ <member><command>double</command>:
+ argument consists of only digits and a
+ single dot.
+ </member>
+ <member><command>long</command>:
+ argument consists of only digits.
+ </member>
+ <member><command>string</command>:
+ argument is enclosed in quotation mark
+ or the checks for double and long failed
+ before.
+ </member>
+ </simplelist>
+ Valid operands are:
+ '>', '<', '>=', '<=', '==', '!='.
<para></para></listitem>
</varlistentry>
<varlistentry>
<term>
- <command><option>if_existing</option></command>
- <option>file (string)</option>
+ <command><option>if_running</option></command>
+ <option>(process)</option>
</term>
<listitem>
- if FILE exists, display everything between if_existing and the matching $endif. The optional second paramater checks for FILE containing the specified string and prints everything between $if_existing and the matching $endif.
+ if PROCESS is running, display everything $if_running
+ and the matching $endif
<para></para></listitem>
</varlistentry>
<option>(mountpoint)</option>
</term>
<listitem>
- if MOUNTPOINT is mounted, display everything between $if_mounted and the matching $endif
+ if MOUNTPOINT is mounted, display everything between
+ $if_mounted and the matching $endif
<para></para></listitem>
</varlistentry>
<option>(INDEX)</option>
</term>
<listitem>
- when using smapi, if the battery with index INDEX is installed, display everything between $if_smapi_bat_installed and the matching $endif
+ when using smapi, if the battery with index INDEX is
+ installed, display everything between
+ $if_smapi_bat_installed and the matching $endif
<para></para></listitem>
</varlistentry>
temphelper.c \
temphelper.h \
text_object.h \
- text_object.c
+ text_object.c \
+ algebra.h \
+ algebra.c
conky_LDFLAGS = \
$(PTHREAD_LIBS) \
--- /dev/null
+/* 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-2008 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#define _GNU_SOURCE
+#include "config.h"
+#include "algebra.h"
+#include "logging.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* find the operand in the given expression
+ * returns the index of the first op character or -1 on error
+ */
+int find_match_op(const char *expr)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < strlen(expr); idx++) {
+ switch (expr[idx]) {
+ case '=':
+ case '!':
+ if (expr[idx + 1] != '=')
+ return -1;
+ /* fall through */
+ case '<':
+ case '>':
+ return idx;
+ break;
+ }
+ }
+ return -1;
+}
+
+int get_match_type(const char *expr)
+{
+ int idx;
+ const char *str;
+
+ if ((idx = find_match_op(expr)) == -1)
+ return -1;
+ str = expr + idx;
+
+ if (*str == '=' && *(str + 1) == '=')
+ return OP_EQ;
+ else if (*str == '!' && *(str + 1) == '=')
+ return OP_NEQ;
+ else if (*str == '>') {
+ if (*(str + 1) == '=')
+ return OP_GEQ;
+ return OP_GT;
+ } else if (*str == '<') {
+ if (*(str + 1) == '=')
+ return OP_LEQ;
+ return OP_LT;
+ }
+ return -1;
+}
+
+
+
+/* generic compare function
+ *
+ * v is actually the difference of the compared values. For strings
+ * this is equal to the output of str(n)cmp(). Use a macro here, as
+ * it's type-independent.
+ */
+#define COMPARE(v, t) \
+ switch (t) { \
+ case OP_GT: return (v > 0); \
+ case OP_LT: return (v < 0); \
+ case OP_EQ: return (v == 0); \
+ case OP_GEQ: return (v >= 0); \
+ case OP_LEQ: return (v <= 0); \
+ case OP_NEQ: return (v != 0); \
+ } \
+ return 0
+
+int lcompare(long a, enum match_type mtype, long b)
+{
+ DBGP2("comparing longs '%ld' and '%ld'", a, b);
+ COMPARE((a - b), mtype);
+}
+int dcompare(double a, enum match_type mtype, double b)
+{
+ DBGP2("comparing doubles '%.lf' and '%.lf'", a, b);
+ COMPARE((a - b), mtype);
+}
+
+int scompare(const char *a, enum match_type mtype, const char *b)
+{
+ DBGP2("comparing strings '%s' and '%s'", a, b);
+ COMPARE(strcmp(a, b), mtype);
+}
+
+enum arg_type get_arg_type(const char *arg)
+{
+ const char *p, *e;
+
+ p = arg;
+ e = arg + strlen(arg);
+
+ if (*(e - 1) == ' ')
+ e--;
+ while (*e && *e == ' ')
+ e--;
+ while (p != e && *p == ' ')
+ p++;
+
+ if (*p == '"' && *e == '"')
+ return ARG_STRING;
+
+ while (p != e) {
+ if (!isdigit(*p))
+ break;
+ p++;
+ }
+ if (p == e)
+ return ARG_LONG;
+ if (*p == '.') {
+ p++;
+ while (p != e) {
+ if (!isdigit(*p))
+ return ARG_STRING;
+ p++;
+ }
+ return ARG_DOUBLE;
+ }
+ return ARG_STRING;
+}
+
+char *arg_to_string(const char *arg)
+{
+ const char *start;
+ int len;
+
+ start = arg;
+ len = 0;
+ while (*start && *start == ' ')
+ start++;
+ if (!(*(start++) == '"'))
+ return NULL;
+ while (start[len] != '"')
+ len++;
+ return strndup(start, len);
+}
+double arg_to_double(const char *arg)
+{
+ double d;
+ if (sscanf(arg, "%lf", &d) != 1) {
+ ERR("converting '%s' to double failed", arg);
+ return 0.0;
+ }
+ return d;
+}
+long arg_to_long(const char *arg)
+{
+ long l;
+ if (sscanf(arg, "%ld", &l) != 1) {
+ ERR("converting '%s' to long failed", arg);
+ return 0;
+ }
+ return l;
+}
+int compare(const char *expr)
+{
+ char *expr_dup;
+ int idx, mtype;
+ enum arg_type type1, type2;
+
+ idx = find_match_op(expr);
+ mtype = get_match_type(expr);
+
+ if (!idx || mtype == -1) {
+ ERR("failed to parse compare string '%s'", expr);
+ return -2;
+ }
+
+ expr_dup = strdup(expr);
+ expr_dup[idx] = '\0';
+ if (expr_dup[idx + 1] == '=')
+ expr_dup[++idx] = '\0';
+
+ type1 = get_arg_type(expr_dup);
+ type2 = get_arg_type(expr_dup + idx + 1);
+ if (type1 == ARG_LONG && type2 == ARG_DOUBLE)
+ type1 = ARG_DOUBLE;
+ if (type1 == ARG_DOUBLE && type2 == ARG_LONG)
+ type2 = ARG_DOUBLE;
+ if (type1 != type2) {
+ ERR("trying to compare args '%s' and '%s' of different type",
+ expr_dup, (expr_dup + idx + 1));
+ return -2;
+ }
+ switch (type1) {
+ case ARG_STRING:
+ {
+ char *a, *b;
+ a = arg_to_string(expr_dup);
+ b = arg_to_string(expr_dup + idx + 1);
+ idx = scompare(a, mtype, b);
+ free(a);
+ free(b);
+ return idx;
+ }
+ case ARG_LONG:
+ return lcompare(arg_to_long(expr_dup), mtype,
+ arg_to_long(expr_dup + idx + 1));
+ case ARG_DOUBLE:
+ return dcompare(arg_to_double(expr_dup), mtype,
+ arg_to_double(expr_dup + idx + 1));
+ }
+ /* not reached */
+ return -2;
+}
--- /dev/null
+/* 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-2008 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef _ALGEBRA_H
+#define _ALGEBRA_H
+
+enum match_type {
+ OP_LT = 1, /* < */
+ OP_GT = 2, /* > */
+ OP_EQ = 3, /* == */
+ OP_LEQ = 4, /* <= */
+ OP_GEQ = 5, /* >= */
+ OP_NEQ = 6, /* != */
+};
+
+enum arg_type {
+ ARG_STRING = 1, /* "asdf" */
+ ARG_LONG = 2, /* 123456 */
+ ARG_DOUBLE = 3, /* 12.456 */
+};
+
+int compare(const char *);
+
+#endif /* _ALGEBRA_H */
#include <getopt.h>
/* local headers */
+#include "algebra.h"
#include "build.h"
#include "diskio.h"
#include "fs.h"
}
break;
case OBJ_if_empty:
+ case OBJ_if_match:
case OBJ_if_existing:
case OBJ_if_mounted:
case OBJ_if_running:
obj->data.ifblock.s = strndup(arg, text_buffer_size);
}
obj_be_ifblock_if(obj);
+ END OBJ(if_match, 0)
+ if (!arg) {
+ ERR("if_match needs arguments");
+ obj->data.ifblock.s = 0;
+ } else {
+ obj->data.ifblock.s = strndup(arg, text_buffer_size);
+ }
+ obj_be_ifblock_if(obj);
END OBJ(if_existing, 0)
if (!arg) {
ERR("if_existing needs an argument or two");
free_text_objects(&subroot);
free(tmp_info);
}
+ OBJ(if_match) {
+ char expression[max_user_text];
+ int val;
+ struct text_object subroot;
+ struct information *tmp_info;
+
+ tmp_info = malloc(sizeof(struct information));
+ memcpy(tmp_info, cur, sizeof(struct information));
+ parse_conky_vars(&subroot, obj->data.ifblock.s,
+ expression, tmp_info);
+ DBGP("parsed arg into '%s'", expression);
+
+ val = compare(expression);
+ if (val == -2) {
+ ERR("compare failed for expression '%s'",
+ expression);
+ } else if (!val) {
+ DO_JUMP;
+ }
+ free_text_objects(&subroot);
+ free(tmp_info);
+ }
OBJ(if_existing) {
if (obj->data.ifblock.str
&& !check_contains(obj->data.ifblock.s,
OBJ_wireless_link_bar,
#endif /* __linux__ */
OBJ_if_empty,
+ OBJ_if_match,
OBJ_if_existing,
OBJ_if_mounted,
OBJ_if_running,