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