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 */
18 WMgMon - Window Maker Generic Monitor
19 by Nicolas Chauvat <nico@caesium.fr>
27 #define _(S) S,sizeof(S)-1
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
},
47 { _("-float"), P_FLOAT
},
48 { _("-label"), P_LABEL
},
50 { _("-medium"), P_MEDIUM
},
51 { _("-scaledown"), P_SCALEDOWN
},
52 { _("-small"), P_SMALL
},
53 { _("-smooth"), P_SMOOTH
},
59 static const char *parse_regex(regex_t
*preg
, char *re
, unsigned *flags
);
61 /******************************************************************************/
63 /******************************************************************************/
65 #define streq(A,B) !strcasecmp((A),(B))
66 #define error(format, ...) \
68 fprintf(stderr, "Line %d: " format "\n", line, ## __VA_ARGS__); \
71 #define dup_keyword error("Duplicate keyword '%s'", keyword)
73 static char *next_token(char *s
)
76 while (*s
&& !isspace(*s
)) s
++; p
=s
;
77 while (*s
&& isspace(*s
)) s
++; *p
=0;
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];
91 if (!(home
=getenv("HOME"))) return 1;
92 snprintf(buf
, sizeof(buf
), "%s/.wmsupermonrc", home
);
94 cfg
=fopen(config
, "r");
97 while (fgets(buf
, sizeof(buf
), cfg
)) {
101 } else if (buf
[0] == '[' && buf
[1] == '[') {
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
);
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
;
113 } else if (buf
[0] == '[') {
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
];
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;
130 while (isspace(*s
)) s
++;
132 while (isalnum(*s
) || *s
== '/' || *s
== '-' || *s
== '%') s
++;
134 while (isspace(*s
)) s
++;
135 if (*s
++ != '=') error("Syntax error");
136 while (isspace(*s
)) s
++;
140 while (isspace(*s
)) s
--;
146 if (panes
[cur_pane
][0].stat
) { cur_pane
++; winds
[cur_wind
].num_panes
++; }
149 pane_part
*widget
=&panes
[cur_pane
][cur_part
];
152 if (cur_pane
>= max_pane
)
153 error("Too many pane definition, max is %i", max_pane
);
156 for (i
=0; i
<= cur_stat
; i
++) {
157 if (streq(keyword
, stats
[i
].name
))
161 error("unknown label %s", keyword
);
162 widget
->stat
=&stats
[i
];
163 stats
[i
].flags
|=F_USED
;
167 for (i
=0; pane_defs
[i
].name
; i
++)
168 if (streq(value
, pane_defs
[i
].name
))
170 if (!pane_defs
[i
].name
)
171 error("unknown widget %s", value
);
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
))
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
)
192 else if (widget
->flags
& P_MEDIUM
)
194 else if (widget
->flags
& P_BIG
)
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
];
204 *x
=calloc(1, sizeof(history
));
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
);
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");
244 error("No window definitions.\n");
246 error("No pane definitions.\n");
248 error("No stat definitions.\n");
251 *stat_num
=cur_stat
+1;
252 *wind_num
=cur_wind
+1;
256 static char bracket(char c
)
258 return 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];
272 for (s
=re
; *s
&& *s
!= ket
; s
++);
273 if (*s
!= ket
) return "Not terminated regex";
277 if (!bra
) return "Missing substitution";
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
);
289 regerror(err
, preg
, error_buf
, sizeof(error_buf
));
294 yy_str
=subs
; yy_nsum
=yy_ndiff
=0;
295 strcpy(error_buf
, "Expression: ");
297 if (yyparse()) return error_buf
;