1 /* Mini MCMS :: renamed to 'spp'? */
2
3 #ifndef INCLUDE_P_SPP_H
4 #define INCLUDE_P_SPP_H
5
6 #if __UNIX__
7 #include <unistd.h>
8 #endif
9
spp_var_get(char * var)10 static char *spp_var_get(char *var) {
11 return r_sys_getenv (var);
12 }
13
spp_var_set(const char * var,const char * val)14 static int spp_var_set(const char *var, const char *val) {
15 return r_sys_setenv (var, val);
16 }
17
18 #if HAVE_SYSTEM
19 /* Should be dynamic buffer */
cmd_to_str(const char * cmd)20 static char *cmd_to_str(const char *cmd) {
21 char *out = (char *)calloc (4096, 1);
22 char *tout;
23 int ret = 0, len = 0, outlen = 4096;
24 FILE *fd = popen (cmd, "r");
25 while (fd) {
26 len += ret;
27 ret = fread (out + len, 1, 1023, fd);
28 if (ret < 1) {
29 pclose (fd);
30 fd = NULL;
31 }
32 if (ret + 1024 > outlen) {
33 outlen += 4096;
34 tout = realloc (out, outlen);
35 if (!tout) {
36 if (fd) {
37 pclose (fd);
38 fd = NULL;
39 }
40 fprintf (stderr, "Out of memory.\n");
41 break;
42 }
43 out = tout;
44 }
45 }
46 out[len] = '\0';
47 return out;
48 }
49 #endif
50
TAG_CALLBACK(spp_set)51 static TAG_CALLBACK(spp_set) {
52 char *eq, *val = "";
53 if (!state->echo[state->ifl]) {
54 return 0;
55 }
56 for (eq=buf; eq[0]; eq++) {
57 switch (eq[0]) {
58 case '-':
59 case '.':
60 eq[0] = '_';
61 break;
62 }
63 }
64 eq = strchr (buf, ' ');
65 if (eq) {
66 *eq = '\0';
67 val = eq + 1;
68 }
69 if (spp_var_set (buf, val) == -1) {
70 fprintf (stderr, "Invalid variable name '%s' at line %d\n", buf, state->lineno);
71 }
72 return 0;
73 }
74
TAG_CALLBACK(spp_get)75 static TAG_CALLBACK(spp_get) {
76 char *var;
77 if (!state->echo[state->ifl]) {
78 return 0;
79 }
80 var = spp_var_get (buf);
81 if (var) {
82 out_printf (out, "%s", var);
83 }
84 return 0;
85 }
86
TAG_CALLBACK(spp_getrandom)87 static TAG_CALLBACK(spp_getrandom) {
88 int max;
89 if (!state->echo[state->ifl]) {
90 return 0;
91 }
92 // XXX srsly? this is pretty bad random
93 srandom (r_sys_getpid ()); // TODO: change this to be portable
94 max = atoi (buf);
95 if (max > 0) {
96 max = (int)(rand () % max);
97 }
98 out_printf (out, "%d", max);
99 return 0;
100 }
101
TAG_CALLBACK(spp_add)102 static TAG_CALLBACK(spp_add) {
103 char res[32];
104 char *var, *eq = strchr (buf, ' ');
105 int ret = 0;
106 if (!state->echo[state->ifl]) {
107 return 0;
108 }
109 if (eq) {
110 *eq = '\0';
111 var = spp_var_get (buf);
112 if (var) {
113 ret = atoi (var);
114 }
115 ret += atoi (eq + 1);
116 snprintf (res, sizeof (res), "%d", ret);
117 r_sys_setenv (buf, res);
118 } else {
119 /* syntax error */
120 }
121 return 0;
122 }
123
TAG_CALLBACK(spp_sub)124 static TAG_CALLBACK(spp_sub) {
125 char *eq = strchr(buf, ' ');
126 char *var;
127 int ret = 0;
128 if (!state->echo[state->ifl]) {
129 return 0;
130 }
131 if (eq) {
132 *eq = '\0';
133 var = spp_var_get (buf);
134 ret = var? atoi (var): 0;
135 ret -= atoi (eq + 1);
136 r_sys_setenv (buf, eq + 1);
137 } else {
138 /* syntax error */
139 }
140 return ret;
141 }
142
TAG_CALLBACK(spp_trace)143 static TAG_CALLBACK(spp_trace) {
144 if (state->echo[state->ifl]) {
145 fprintf (stderr, "%.1000s\n", buf);
146 }
147 return 0;
148 }
149
150 /* TODO: deprecate */
TAG_CALLBACK(spp_echo)151 static TAG_CALLBACK(spp_echo) {
152 if (state->echo[state->ifl]) {
153 out_printf (out, "%s", buf);
154 }
155 // TODO: add variable replacement here?? not necessary, done by {{get}}
156 return 0;
157 }
158
TAG_CALLBACK(spp_error)159 static TAG_CALLBACK(spp_error) {
160 if (!state->echo[state->ifl]) {
161 return 0;
162 }
163 fprintf (stderr, "ERROR: %s (line=%d)\n", buf, state->lineno);
164 return -1;
165 }
166
TAG_CALLBACK(spp_warning)167 static TAG_CALLBACK(spp_warning) {
168 if (!state->echo[state->ifl]) {
169 return 0;
170 }
171 fprintf (stderr, "WARNING: %s (line=%d)\n", buf, state->lineno);
172 return 0;
173 }
174
TAG_CALLBACK(spp_system)175 static TAG_CALLBACK(spp_system) {
176 if (!state->echo[state->ifl]) {
177 return 0;
178 }
179 #if HAVE_SYSTEM
180 char *str = cmd_to_str (buf);
181 out_printf (out, "%s", str);
182 free(str);
183 #endif
184 return 0;
185 }
186
TAG_CALLBACK(spp_include)187 static TAG_CALLBACK(spp_include) {
188 char *incdir;
189 if (!state->echo[state->ifl]) {
190 return 0;
191 }
192 incdir = getenv("SPP_INCDIR");
193 if (incdir) {
194 char *b = strdup (incdir);
195 char *p = realloc (b, strlen (b) + strlen (buf) + 3);
196 if (p) {
197 b = p;
198 strcat (b, "/");
199 strcat (b, buf);
200 spp_file (b, out);
201 }
202 free (b);
203 } else {
204 spp_file(buf, out);
205 }
206 return 0;
207 }
208
TAG_CALLBACK(spp_if)209 static TAG_CALLBACK(spp_if) {
210 char *var = spp_var_get(buf);
211 state->echo[state->ifl + 1] = (var && *var != '0' && *var != '\0') ? 1 : 0;
212 return 1;
213 }
214
215 /* {{ ifeq $path / }} */
TAG_CALLBACK(spp_ifeq)216 static TAG_CALLBACK(spp_ifeq) {
217 char *value = buf;
218 char *eq = strchr(buf, ' ');
219 if (eq) {
220 *eq = '\0';
221 value = spp_var_get(value);
222 if (value && !strcmp(value, eq+1)) {
223 state->echo[state->ifl + 1] = 1;
224 } else state->echo[state->ifl + 1] = 0;
225 //fprintf(stderr, "IFEQ(%s)(%s)=%d\n", buf, eq+1, echo[ifl]);
226 } else {
227 value = spp_var_get(buf);
228 if (!value || *value=='\0')
229 state->echo[state->ifl + 1] = 1;
230 else state->echo[state->ifl + 1] = 0;
231 //fprintf(stderr, "IFEQ(%s)(%s)=%d\n", buf, value, echo[ifl]);
232 }
233 return 1;
234 }
235
TAG_CALLBACK(spp_hex)236 static TAG_CALLBACK(spp_hex) {
237 int i;
238 for(i = 0; buf[i]; i++) {
239 if (buf[i] >= '0' && buf[i] <= '9') {
240 int b;
241 unsigned int ch;
242 b = buf[i + 2];
243 buf[i + 2] = '\0';
244 sscanf(buf + i, "%02x", &ch);
245 out_printf (out, "%c", ch);
246 buf[i + 2] = b;
247 buf = buf + 2;
248 }
249 }
250 return 0;
251 }
252
TAG_CALLBACK(spp_grepline)253 static TAG_CALLBACK(spp_grepline) {
254 FILE *fd;
255 char b[1024];
256 char *ptr;
257 int line;
258
259 if (!state->echo[state->ifl]) return 1;
260 ptr = strchr(buf, ' ');
261 if (ptr) {
262 *ptr= '\0';
263 fd = fopen (buf, "r");
264 line = atoi (ptr+1);
265 if (fd) {
266 while (!feof (fd) && line--) {
267 if (!fgets (b, 1023, fd)) {
268 break;
269 }
270 }
271 fclose (fd);
272 out_printf (out, "%s", b);
273 } else {
274 fprintf(stderr, "Unable to open '%s'\n", buf);
275 }
276 }
277 return 0;
278 }
279
TAG_CALLBACK(spp_else)280 static TAG_CALLBACK(spp_else) {
281 state->echo[state->ifl] = state->echo[state->ifl] ? 0 : 1;
282 return 0;
283 }
284
TAG_CALLBACK(spp_ifnot)285 static TAG_CALLBACK(spp_ifnot) {
286 spp_if (state, out, buf);
287 spp_else (state, out, buf);
288 return 1;
289 }
290
TAG_CALLBACK(spp_ifin)291 static TAG_CALLBACK(spp_ifin) {
292 char *var, *ptr;
293 if (!state->echo[state->ifl]) {
294 return 1;
295 }
296 ptr = strchr (buf, ' ');
297 state->echo[state->ifl + 1] = 0;
298 if (ptr) {
299 *ptr='\0';
300 var = getenv(buf);
301 if (strstr (ptr + 1, var)) {
302 state->echo[state->ifl + 1] = 1;
303 }
304 }
305 return 1;
306 }
307
TAG_CALLBACK(spp_endif)308 static TAG_CALLBACK(spp_endif) {
309 return -1;
310 }
311
TAG_CALLBACK(spp_default)312 static TAG_CALLBACK(spp_default) {
313 if (!state->echo[state->ifl]) {
314 return 0;
315 }
316 if (buf[-1] != ';') { /* commented tag */
317 fprintf (stderr, "WARNING: invalid command: '%s' at line %d\n", buf, state->lineno);
318 }
319 return 0;
320 }
321
322 #if HAVE_SYSTEM
323 static FILE *spp_pipe_fd = NULL;
324 #endif
325
TAG_CALLBACK(spp_pipe)326 static TAG_CALLBACK(spp_pipe) {
327 #if HAVE_SYSTEM
328 spp_pipe_fd = popen (buf, "w");
329 #endif
330 return 0;
331 }
332
333 static char *spp_switch_str = NULL;
334
TAG_CALLBACK(spp_switch)335 static TAG_CALLBACK(spp_switch) {
336 char *var = spp_var_get (buf);
337 if (var) {
338 spp_switch_str = strdup (var);
339 } else {
340 spp_switch_str = strdup ("");
341 }
342 return 1;
343 }
344
TAG_CALLBACK(spp_case)345 static TAG_CALLBACK(spp_case) {
346 state->echo[state->ifl] = strcmp (buf, spp_switch_str)?0:1;
347 return 0;
348 }
349
TAG_CALLBACK(spp_endswitch)350 static TAG_CALLBACK(spp_endswitch) {
351 free (spp_switch_str);
352 spp_switch_str = NULL;
353 return -1;
354 }
355
TAG_CALLBACK(spp_endpipe)356 static TAG_CALLBACK(spp_endpipe) {
357 #if HAVE_SYSTEM
358 /* TODO: Get output here */
359 int ret = 0, len = 0;
360 int outlen = 4096;
361 char *str = (char *)malloc (4096);
362 char *tstr;
363 do {
364 len += ret;
365 ret = fread (str + len, 1, 1023, spp_pipe_fd);
366 if (ret + 1024 > outlen) {
367 outlen += 4096;
368 tstr = realloc (str, outlen);
369 if (!tstr) {
370 fprintf (stderr, "Out of memory.\n");
371 break;
372 }
373 str = tstr;
374 }
375 } while (ret > 0);
376 str[len] = '\0';
377 out_printf (out, "%s", str);
378 if (spp_pipe_fd) {
379 pclose (spp_pipe_fd);
380 }
381 spp_pipe_fd = NULL;
382 free (str);
383 #endif
384 return 0;
385 }
386
PUT_CALLBACK(spp_fputs)387 static PUT_CALLBACK(spp_fputs) {
388 #if HAVE_SYSTEM
389 if (spp_pipe_fd) {
390 fprintf (spp_pipe_fd, "%s", buf);
391 } else
392 #endif
393 {
394 out_printf (out, "%s", buf);
395 }
396 return 0;
397 }
398
399 static struct Tag spp_tags[] = {
400 { "get", spp_get },
401 { "hex", spp_hex },
402 { "getrandom", spp_getrandom },
403 { "grepline", spp_grepline },
404 { "set", spp_set },
405 { "add", spp_add },
406 { "sub", spp_sub },
407 { "switch", spp_switch },
408 { "case", spp_case },
409 { "endswitch", spp_endswitch },
410 { "echo", spp_echo },
411 { "error", spp_error },
412 { "warning", spp_warning },
413 { "trace", spp_trace },
414 { "ifin", spp_ifin },
415 { "ifnot", spp_ifnot },
416 { "ifeq", spp_ifeq },
417 { "if", spp_if },
418 { "else", spp_else },
419 { "endif", spp_endif },
420 { "pipe", spp_pipe },
421 { "endpipe", spp_endpipe },
422 { "include", spp_include },
423 { "system", spp_system },
424 { NULL, spp_default },
425 { NULL }
426 };
427
ARG_CALLBACK(spp_arg_i)428 static ARG_CALLBACK(spp_arg_i) {
429 r_sys_setenv ("SPP_INCDIR", arg);
430 return 0;
431 }
432
ARG_CALLBACK(spp_arg_d)433 static ARG_CALLBACK(spp_arg_d) {
434 /* TODO: Handle error */
435 char *eq = strchr (arg, '=');
436 if (eq) {
437 *eq = '\0';
438 spp_var_set (arg, eq+1);
439 } else {
440 spp_var_set (arg, "");
441 }
442 return 0;
443 }
444
445 static struct Arg spp_args[] = {
446 { "-I", "add include directory", 1, spp_arg_i },
447 { "-D", "define value of variable", 1, spp_arg_d },
448 { NULL }
449 };
450
451 DLL_LOCAL struct Proc spp_proc = {
452 .name = "spp",
453 .tags = (struct Tag **)spp_tags,
454 .args = (struct Arg **)spp_args,
455 .token = " ",
456 .eof = NULL,
457 .tag_pre = "<{",
458 .tag_post = "}>",
459 .chop = 1,
460 .fputs = spp_fputs,
461 .multiline = NULL,
462 .default_echo = 1,
463 .tag_begin = 0,
464 };
465 #endif
466