dockapps/wmsupermon/panes.c
2014-10-05 19:18:49 +01:00

301 lines
9.6 KiB
C

/* Copyright (C) 2006 Sergei Golubchik
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
/*
originally based on:
WMgMon - Window Maker Generic Monitor
by Nicolas Chauvat <nico@caesium.fr>
*/
#include <stdlib.h>
#include <ctype.h>
#include "expr.h"
#include "panes.h"
#define _(S) S,sizeof(S)-1
struct {
char *name;
int name_length;
int default_height;
int possible_flags;
} pane_defs[]={
{ _("bar"), 1, P_LABEL | P_SMOOTH },
{ _("number"), 1, P_LABEL | P_FLOAT | P_SMOOTH },
{ _("percent"), 1, P_LABEL | P_SMOOTH },
{ _("graph"), 3, P_LABEL | P_SIZE | P_SMOOTH | P_SCALEDOWN | P_LOG },
{ 0, 0, 0, 0 }
};
struct {
char *name;
int name_length;
int flag;
} options[]= {
{ _("-big"), P_BIG },
{ _("-float"), P_FLOAT },
{ _("-label"), P_LABEL },
{ _("-log"), P_LOG },
{ _("-medium"), P_MEDIUM },
{ _("-scaledown"), P_SCALEDOWN },
{ _("-small"), P_SMALL },
{ _("-smooth"), P_SMOOTH },
{ 0, 0, 0 }
};
#undef _
static const char *parse_regex(regex_t *preg, char *re, unsigned *flags);
/******************************************************************************/
/* panes functions */
/******************************************************************************/
#define streq(A,B) !strcasecmp((A),(B))
#define error(format, ...) \
do { \
fprintf(stderr, "Line %d: " format "\n", line, ## __VA_ARGS__); \
return -1; \
} while (0)
#define dup_keyword error("Duplicate keyword '%s'", keyword)
static char *next_token(char *s)
{
char *p;
while (*s && !isspace(*s)) s++; p=s;
while (*s && isspace(*s)) s++; *p=0;
return s;
}
int read_config_file(pane_desc panes[], int *pane_num, const int max_pane,
stat_dev stats[], int *stat_num, const int stat_max,
wind_desc winds[], int *wind_num, const int wind_max)
{
int i, cur_wind=-1, cur_stat=-1, cur_pane=0, cur_part=-1, line=0;
char *home, buf[4096];
FILE *cfg;
if (!config) {
config=buf;
if (!(home=getenv("HOME"))) return 1;
snprintf(buf, sizeof(buf), "%s/.wmsupermonrc", home);
}
cfg=fopen(config, "r");
if(!cfg) return 1;
while (fgets(buf, sizeof(buf), cfg)) {
line++;
if (buf[0] == '#') {
/* comment */
} else if (buf[0] == '[' && buf[1] == '[') {
char *s=buf+2;
while (s[0] && s[0] != '\n' && !(s[0] == ']' && s[1] == ']')) s++;
if (s[0] != ']' || s[1] != ']') error("Syntax error");
if (s-buf > WNAME_LEN+2)
error("Too long name %s", buf);
*s=0; s=buf+2;
if (++cur_wind >= wind_max)
error("Too many window definition, max is %i", wind_max);
strncpy(winds[cur_wind].name, *s ? s : "wmsupermon", WNAME_LEN);
winds[cur_wind].panes=panes+cur_pane;
cur_part=0;
} else if (buf[0] == '[') {
cur_part=-1;
if (cur_stat != -1) {
if (!stats[cur_stat].source)
error("Label [%s] has no source", stats[cur_stat].name);
}
if (++cur_stat >= stat_max)
error("Too many stat definition, max is %i", stat_max);
stats[cur_stat].scale=1;
for (i=1; buf[i] !=']' && i <= NAME_LEN && buf[i] && buf[i] != '\n'; i++)
stats[cur_stat].name[i-1]=buf[i];
if (buf[i] != ']')
error("Too long label %s", buf);
} else if (cur_stat >= 0 || cur_part >=0) {
char *s=buf, *keyword, *value;
if (*s == '\n') s=keyword=value=0;
else {
while (isspace(*s)) s++;
keyword=s;
while (isalnum(*s) || *s == '/' || *s == '-' || *s == '%') s++;
value=s;
while (isspace(*s)) s++;
if (*s++ != '=') error("Syntax error");
while (isspace(*s)) s++;
*value=0;
value=s;
s+=strlen(value)-1;
while (isspace(*s)) s--;
s[1]=0;
}
if (cur_part >=0) {
if (!s) {
if (panes[cur_pane][0].stat) { cur_pane++; winds[cur_wind].num_panes++; }
cur_part=0;
} else {
pane_part *widget=&panes[cur_pane][cur_part];
int possible_flags;
if (cur_pane >= max_pane)
error("Too many pane definition, max is %i", max_pane);
/* label */
for (i=0; i <= cur_stat; i++) {
if (streq(keyword, stats[i].name))
break;
}
if (i > cur_stat)
error("unknown label %s", keyword);
widget->stat=&stats[i];
stats[i].flags|=F_USED;
/* widget name */
s=next_token(value);
for (i=0; pane_defs[i].name; i++)
if (streq(value, pane_defs[i].name))
break;
if (!pane_defs[i].name)
error("unknown widget %s", value);
widget->type=i;
/* options */
possible_flags=pane_defs[widget->type].possible_flags;
for ( s=next_token(value=s); *value; s=next_token(value=s)) {
for (i=0; options[i].name; i++)
if (streq(value, options[i].name))
break;
if (!options[i].name)
error("Unknown option %s", value);
if (!(possible_flags & options[i].flag))
error("Widget %s does not support the option %s",
pane_defs[widget->type].name, value);
if (options[i].flag & P_SIZE && widget->flags & P_SIZE)
error("Duplicate size option (-small, -medium, -big)");
widget->flags|=options[i].flag;
}
if (widget->flags & P_SMALL)
widget->height=1;
else if (widget->flags & P_MEDIUM)
widget->height=2;
else if (widget->flags & P_BIG)
widget->height=4;
else
widget->height=pane_defs[widget->type].default_height;
if (widget->flags & P_SMOOTH && !widget->stat->smooth)
widget->stat->smooth=calloc(SMOOTH_SIZE-1, sizeof(double));
if (widget->type == PTGraph) {
history **x=&widget->stat->hist[widget->flags & P_HIST];
if (!*x) {
*x=calloc(1, sizeof(history));
(*x)->max=1;
}
}
cur_part++;
}
} else if (!s) continue;
else if (streq(keyword, "source")) {
if (stats[cur_stat].source) dup_keyword;
stats[cur_stat].source=strdup(value);
} else if (streq(keyword, "regex")) { const char *err;
if (stats[cur_stat].expr) dup_keyword;
err=parse_regex(&stats[cur_stat].regex, value, &stats[cur_stat].flags);
if (err)
error("Regex: %s\n", err);
stats[cur_stat].expr=yy_expr;
stats[cur_stat].diff_old=calloc(yy_ndiff, sizeof(double));
stats[cur_stat].diff_new=calloc(yy_ndiff, sizeof(double));
stats[cur_stat].sum_acc =calloc(yy_nsum, sizeof(double));
stats[cur_stat].nsum=yy_nsum;
} else if (streq(keyword, "action")) {
if (stats[cur_stat].action) dup_keyword;
stats[cur_stat].action=strdup(value);
} else if (streq(keyword, "interval")) {
stats[cur_stat].hist_update_interval=
stats[cur_stat].update_interval=atoi(value);
} else if (streq(keyword, "scale")) {
stats[cur_stat].scale=atof(value);
} else if (streq(keyword, "range")) {
if (sscanf(value, " %lf .. %lf", &stats[cur_stat].min, &stats[cur_stat].max) != 2)
error("Syntax error.\n");
if (!(stats[cur_stat].max-=stats[cur_stat].min))
error("Invalid range.\n");
} else error("Syntax error.\n");
} else if (*buf != '\n')
error("Syntax error.\n");
}
if (cur_wind < 0)
error("No window definitions.\n");
if (cur_pane < 0)
error("No pane definitions.\n");
if (cur_stat < 0)
error("No stat definitions.\n");
*pane_num=cur_pane;
*stat_num=cur_stat+1;
*wind_num=cur_wind+1;
return 0;
}
static char bracket(char c)
{
return c == '<' ? '>' :
c == '{' ? '}' :
c == '[' ? ']' :
c == '(' ? ')' : c;
}
static const char *parse_regex(regex_t *preg, char *re, unsigned *flags)
{
char bra, ket, *s, *subs;
int cflags=REG_EXTENDED, err;
static char error_buf[256];
bra=*re++;
ket=bracket(bra);
for (s=re; *s && *s != ket; s++);
if (*s != ket) return "Not terminated regex";
*s++=0;
if (bra != ket) {
bra=*s++;
if (!bra) return "Missing substitution";
ket=bracket(bra);
}
for (subs=s; *s && *s != ket; s++);
if (*s != ket) return s == subs ? "Missing substitution" : "Not terminated substitution";
for (*s++=0; *s; s++)
if (*s == 'i') cflags|=REG_ICASE; else
if (*s == 's') *flags|=F_SINGLE_LINE; else
if (*s == 'd') *flags|=F_DEBUG; else
return "Trailing characters";
err=regcomp(preg, re, cflags);
if (err) {
regerror(err, preg, error_buf, sizeof(error_buf));
regfree(preg);
return error_buf;
}
yy_str=subs; yy_nsum=yy_ndiff=0;
strcpy(error_buf, "Expression: ");
yy_err=error_buf+12;
if (yyparse()) return error_buf;
return 0;
}