wmshutdown: Destroy dialog window before shutting down. This is especially useful...
[dockapps.git] / wmsupermon / panes.c
blobc5db31163513246816f41c9101a8392cd8cf1144
1 /* Copyright (C) 2006 Sergei Golubchik
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License version 2
5 as published by the Free Software Foundation
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17 originally based on:
18 WMgMon - Window Maker Generic Monitor
19 by Nicolas Chauvat <nico@caesium.fr>
22 #include <stdlib.h>
23 #include <ctype.h>
24 #include "expr.h"
25 #include "panes.h"
27 #define _(S) S,sizeof(S)-1
28 struct {
29 char *name;
30 int name_length;
31 int default_height;
32 int possible_flags;
33 } pane_defs[]={
34 { _("bar"), 1, P_LABEL | P_SMOOTH },
35 { _("number"), 1, P_LABEL | P_FLOAT | P_SMOOTH },
36 { _("percent"), 1, P_LABEL | P_SMOOTH },
37 { _("graph"), 3, P_LABEL | P_SIZE | P_SMOOTH | P_SCALEDOWN | P_LOG },
38 { 0, 0, 0, 0 }
41 struct {
42 char *name;
43 int name_length;
44 int flag;
45 } options[]= {
46 { _("-big"), P_BIG },
47 { _("-float"), P_FLOAT },
48 { _("-label"), P_LABEL },
49 { _("-log"), P_LOG },
50 { _("-medium"), P_MEDIUM },
51 { _("-scaledown"), P_SCALEDOWN },
52 { _("-small"), P_SMALL },
53 { _("-smooth"), P_SMOOTH },
54 { 0, 0, 0 }
57 #undef _
59 static const char *parse_regex(regex_t *preg, char *re, unsigned *flags);
61 /******************************************************************************/
62 /* panes functions */
63 /******************************************************************************/
65 #define streq(A,B) !strcasecmp((A),(B))
66 #define error(format, ...) \
67 do { \
68 fprintf(stderr, "Line %d: " format "\n", line, ## __VA_ARGS__); \
69 return -1; \
70 } while (0)
71 #define dup_keyword error("Duplicate keyword '%s'", keyword)
73 static char *next_token(char *s)
75 char *p;
76 while (*s && !isspace(*s)) s++; p=s;
77 while (*s && isspace(*s)) s++; *p=0;
78 return s;
81 int read_config_file(pane_desc panes[], int *pane_num, const int max_pane,
82 stat_dev stats[], int *stat_num, const int stat_max,
83 wind_desc winds[], int *wind_num, const int wind_max)
85 int i, cur_wind=-1, cur_stat=-1, cur_pane=0, cur_part=-1, line=0;
86 char *home, buf[4096];
87 FILE *cfg;
89 if (!config) {
90 config=buf;
91 if (!(home=getenv("HOME"))) return 1;
92 snprintf(buf, sizeof(buf), "%s/.wmsupermonrc", home);
94 cfg=fopen(config, "r");
95 if(!cfg) return 1;
97 while (fgets(buf, sizeof(buf), cfg)) {
98 line++;
99 if (buf[0] == '#') {
100 /* comment */
101 } else if (buf[0] == '[' && buf[1] == '[') {
102 char *s=buf+2;
103 while (s[0] && s[0] != '\n' && !(s[0] == ']' && s[1] == ']')) s++;
104 if (s[0] != ']' || s[1] != ']') error("Syntax error");
105 if (s-buf > WNAME_LEN+2)
106 error("Too long name %s", buf);
107 *s=0; s=buf+2;
108 if (++cur_wind >= wind_max)
109 error("Too many window definition, max is %i", wind_max);
110 strncpy(winds[cur_wind].name, *s ? s : "wmsupermon", WNAME_LEN);
111 winds[cur_wind].panes=panes+cur_pane;
112 cur_part=0;
113 } else if (buf[0] == '[') {
114 cur_part=-1;
115 if (cur_stat != -1) {
116 if (!stats[cur_stat].source)
117 error("Label [%s] has no source", stats[cur_stat].name);
119 if (++cur_stat >= stat_max)
120 error("Too many stat definition, max is %i", stat_max);
121 stats[cur_stat].scale=1;
122 for (i=1; buf[i] !=']' && i <= NAME_LEN && buf[i] && buf[i] != '\n'; i++)
123 stats[cur_stat].name[i-1]=buf[i];
124 if (buf[i] != ']')
125 error("Too long label %s", buf);
126 } else if (cur_stat >= 0 || cur_part >=0) {
127 char *s=buf, *keyword, *value;
128 if (*s == '\n') s=keyword=value=0;
129 else {
130 while (isspace(*s)) s++;
131 keyword=s;
132 while (isalnum(*s) || *s == '/' || *s == '-' || *s == '%') s++;
133 value=s;
134 while (isspace(*s)) s++;
135 if (*s++ != '=') error("Syntax error");
136 while (isspace(*s)) s++;
137 *value=0;
138 value=s;
139 s+=strlen(value)-1;
140 while (isspace(*s)) s--;
141 s[1]=0;
144 if (cur_part >=0) {
145 if (!s) {
146 if (panes[cur_pane][0].stat) { cur_pane++; winds[cur_wind].num_panes++; }
147 cur_part=0;
148 } else {
149 pane_part *widget=&panes[cur_pane][cur_part];
150 int possible_flags;
152 if (cur_pane >= max_pane)
153 error("Too many pane definition, max is %i", max_pane);
155 /* label */
156 for (i=0; i <= cur_stat; i++) {
157 if (streq(keyword, stats[i].name))
158 break;
160 if (i > cur_stat)
161 error("unknown label %s", keyword);
162 widget->stat=&stats[i];
163 stats[i].flags|=F_USED;
165 /* widget name */
166 s=next_token(value);
167 for (i=0; pane_defs[i].name; i++)
168 if (streq(value, pane_defs[i].name))
169 break;
170 if (!pane_defs[i].name)
171 error("unknown widget %s", value);
172 widget->type=i;
174 /* options */
175 possible_flags=pane_defs[widget->type].possible_flags;
176 for ( s=next_token(value=s); *value; s=next_token(value=s)) {
177 for (i=0; options[i].name; i++)
178 if (streq(value, options[i].name))
179 break;
180 if (!options[i].name)
181 error("Unknown option %s", value);
182 if (!(possible_flags & options[i].flag))
183 error("Widget %s does not support the option %s",
184 pane_defs[widget->type].name, value);
185 if (options[i].flag & P_SIZE && widget->flags & P_SIZE)
186 error("Duplicate size option (-small, -medium, -big)");
187 widget->flags|=options[i].flag;
190 if (widget->flags & P_SMALL)
191 widget->height=1;
192 else if (widget->flags & P_MEDIUM)
193 widget->height=2;
194 else if (widget->flags & P_BIG)
195 widget->height=4;
196 else
197 widget->height=pane_defs[widget->type].default_height;
199 if (widget->flags & P_SMOOTH && !widget->stat->smooth)
200 widget->stat->smooth=calloc(SMOOTH_SIZE-1, sizeof(double));
201 if (widget->type == PTGraph) {
202 history **x=&widget->stat->hist[widget->flags & P_HIST];
203 if (!*x) {
204 *x=calloc(1, sizeof(history));
205 (*x)->max=1;
209 cur_part++;
211 } else if (!s) continue;
212 else if (streq(keyword, "source")) {
213 if (stats[cur_stat].source) dup_keyword;
214 stats[cur_stat].source=strdup(value);
215 } else if (streq(keyword, "regex")) { const char *err;
216 if (stats[cur_stat].expr) dup_keyword;
217 err=parse_regex(&stats[cur_stat].regex, value, &stats[cur_stat].flags);
218 if (err)
219 error("Regex: %s\n", err);
220 stats[cur_stat].expr=yy_expr;
221 stats[cur_stat].diff_old=calloc(yy_ndiff, sizeof(double));
222 stats[cur_stat].diff_new=calloc(yy_ndiff, sizeof(double));
223 stats[cur_stat].sum_acc =calloc(yy_nsum, sizeof(double));
224 stats[cur_stat].nsum=yy_nsum;
225 } else if (streq(keyword, "action")) {
226 if (stats[cur_stat].action) dup_keyword;
227 stats[cur_stat].action=strdup(value);
228 } else if (streq(keyword, "interval")) {
229 stats[cur_stat].hist_update_interval=
230 stats[cur_stat].update_interval=atoi(value);
231 } else if (streq(keyword, "scale")) {
232 stats[cur_stat].scale=atof(value);
233 } else if (streq(keyword, "range")) {
234 if (sscanf(value, " %lf .. %lf", &stats[cur_stat].min, &stats[cur_stat].max) != 2)
235 error("Syntax error.\n");
236 if (!(stats[cur_stat].max-=stats[cur_stat].min))
237 error("Invalid range.\n");
238 } else error("Syntax error.\n");
239 } else if (*buf != '\n')
240 error("Syntax error.\n");
243 if (cur_wind < 0)
244 error("No window definitions.\n");
245 if (cur_pane < 0)
246 error("No pane definitions.\n");
247 if (cur_stat < 0)
248 error("No stat definitions.\n");
250 *pane_num=cur_pane;
251 *stat_num=cur_stat+1;
252 *wind_num=cur_wind+1;
253 return 0;
256 static char bracket(char c)
258 return c == '<' ? '>' :
259 c == '{' ? '}' :
260 c == '[' ? ']' :
261 c == '(' ? ')' : c;
264 static const char *parse_regex(regex_t *preg, char *re, unsigned *flags)
266 char bra, ket, *s, *subs;
267 int cflags=REG_EXTENDED, err;
268 static char error_buf[256];
270 bra=*re++;
271 ket=bracket(bra);
272 for (s=re; *s && *s != ket; s++);
273 if (*s != ket) return "Not terminated regex";
274 *s++=0;
275 if (bra != ket) {
276 bra=*s++;
277 if (!bra) return "Missing substitution";
278 ket=bracket(bra);
280 for (subs=s; *s && *s != ket; s++);
281 if (*s != ket) return s == subs ? "Missing substitution" : "Not terminated substitution";
282 for (*s++=0; *s; s++)
283 if (*s == 'i') cflags|=REG_ICASE; else
284 if (*s == 's') *flags|=F_SINGLE_LINE; else
285 if (*s == 'd') *flags|=F_DEBUG; else
286 return "Trailing characters";
287 err=regcomp(preg, re, cflags);
288 if (err) {
289 regerror(err, preg, error_buf, sizeof(error_buf));
290 regfree(preg);
291 return error_buf;
294 yy_str=subs; yy_nsum=yy_ndiff=0;
295 strcpy(error_buf, "Expression: ");
296 yy_err=error_buf+12;
297 if (yyparse()) return error_buf;
298 return 0;