xref: /dflybsd-src/usr.bin/evtranalyze/plotter.c (revision 24c607ef7e743004e64d531f3cc5c6b59aaaf2a5)
1807a01c2SAggelos Economopoulos #include <assert.h>
2807a01c2SAggelos Economopoulos #include <err.h>
3807a01c2SAggelos Economopoulos #include <errno.h>
4807a01c2SAggelos Economopoulos #include <libprop/proplib.h>
5807a01c2SAggelos Economopoulos #include <sys/stat.h>
6807a01c2SAggelos Economopoulos #include <sys/types.h>
7807a01c2SAggelos Economopoulos #include <sys/wait.h>
8807a01c2SAggelos Economopoulos #include <stdio.h>
9807a01c2SAggelos Economopoulos #include <stdlib.h>
10807a01c2SAggelos Economopoulos #include <string.h>
11807a01c2SAggelos Economopoulos #include <unistd.h>
12807a01c2SAggelos Economopoulos 
13807a01c2SAggelos Economopoulos #include "trivial.h"
14807a01c2SAggelos Economopoulos #include "plotter.h"
15807a01c2SAggelos Economopoulos 
16807a01c2SAggelos Economopoulos struct ploticus_plot {
17807a01c2SAggelos Economopoulos 	unsigned type;
18807a01c2SAggelos Economopoulos 	prop_dictionary_t params;
19807a01c2SAggelos Economopoulos 	FILE *fp;
20807a01c2SAggelos Economopoulos 	char *path;
21807a01c2SAggelos Economopoulos };
22807a01c2SAggelos Economopoulos 
23807a01c2SAggelos Economopoulos struct ploticus_plotter {
24807a01c2SAggelos Economopoulos 	int nr_plots;
25807a01c2SAggelos Economopoulos 	struct ploticus_plot **plots;
26807a01c2SAggelos Economopoulos 	const char *basepath;
27807a01c2SAggelos Economopoulos };
28807a01c2SAggelos Economopoulos 
29807a01c2SAggelos Economopoulos const char *plot_prefabs[] = {
30807a01c2SAggelos Economopoulos 	[PLOT_TYPE_HIST] = "dist",
31807a01c2SAggelos Economopoulos 	[PLOT_TYPE_LINE] = "lines",
32807a01c2SAggelos Economopoulos };
33807a01c2SAggelos Economopoulos 
34807a01c2SAggelos Economopoulos static
35807a01c2SAggelos Economopoulos void *
ploticus_init(const char * base)36807a01c2SAggelos Economopoulos ploticus_init(const char *base)
37807a01c2SAggelos Economopoulos {
38807a01c2SAggelos Economopoulos 	struct ploticus_plotter *ctx;
39807a01c2SAggelos Economopoulos 
40807a01c2SAggelos Economopoulos 	if (!(ctx = calloc(1, sizeof(*ctx))))
41807a01c2SAggelos Economopoulos 		return ctx;
42807a01c2SAggelos Economopoulos 	if (!(ctx->basepath = strdup(base)))
43807a01c2SAggelos Economopoulos 		goto free_ctx;
44807a01c2SAggelos Economopoulos 	return ctx;
45807a01c2SAggelos Economopoulos free_ctx:
46807a01c2SAggelos Economopoulos 	free(ctx);
47807a01c2SAggelos Economopoulos 	return NULL;
48807a01c2SAggelos Economopoulos }
49807a01c2SAggelos Economopoulos 
50807a01c2SAggelos Economopoulos static
51807a01c2SAggelos Economopoulos int
ploticus_new_plot_hist(struct ploticus_plot * plot)52807a01c2SAggelos Economopoulos ploticus_new_plot_hist(struct ploticus_plot *plot)
53807a01c2SAggelos Economopoulos {
54807a01c2SAggelos Economopoulos 	prop_dictionary_t params = plot->params;
55807a01c2SAggelos Economopoulos 	prop_string_t str;
56807a01c2SAggelos Economopoulos 
57807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring_nocopy("1")))
58807a01c2SAggelos Economopoulos 		return !0;
59807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "x", str)) {
60807a01c2SAggelos Economopoulos 		prop_object_release(str);
61807a01c2SAggelos Economopoulos 		return !0;
62807a01c2SAggelos Economopoulos 	}
63807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring_nocopy("yes")))
64807a01c2SAggelos Economopoulos 		return !0;
65807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "curve", str)) {
66807a01c2SAggelos Economopoulos 		prop_object_release(str);
67807a01c2SAggelos Economopoulos 		return !0;
68807a01c2SAggelos Economopoulos 	}
69807a01c2SAggelos Economopoulos 	return 0;
70807a01c2SAggelos Economopoulos }
71807a01c2SAggelos Economopoulos 
72807a01c2SAggelos Economopoulos static
73807a01c2SAggelos Economopoulos int
ploticus_new_plot_line(struct ploticus_plot * plot)74807a01c2SAggelos Economopoulos ploticus_new_plot_line(struct ploticus_plot *plot)
75807a01c2SAggelos Economopoulos {
76807a01c2SAggelos Economopoulos 	prop_dictionary_t params = plot->params;
77807a01c2SAggelos Economopoulos 	prop_string_t str;
78807a01c2SAggelos Economopoulos 
79807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring_nocopy("1")))
80807a01c2SAggelos Economopoulos 		return !0;
81807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "x", str)) {
82807a01c2SAggelos Economopoulos 		prop_object_release(str);
83807a01c2SAggelos Economopoulos 		return !0;
84807a01c2SAggelos Economopoulos 	}
85807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring_nocopy("2")))
86807a01c2SAggelos Economopoulos 		return !0;
87807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "y", str)) {
88807a01c2SAggelos Economopoulos 		prop_object_release(str);
89807a01c2SAggelos Economopoulos 		return !0;
90807a01c2SAggelos Economopoulos 	}
91807a01c2SAggelos Economopoulos 	return 0;
92807a01c2SAggelos Economopoulos }
93807a01c2SAggelos Economopoulos 
94807a01c2SAggelos Economopoulos int (*plot_type_initializers[])(struct ploticus_plot *) = {
95807a01c2SAggelos Economopoulos 	[PLOT_TYPE_HIST] = ploticus_new_plot_hist,
96807a01c2SAggelos Economopoulos 	[PLOT_TYPE_LINE] = ploticus_new_plot_line,
97807a01c2SAggelos Economopoulos };
98807a01c2SAggelos Economopoulos 
99807a01c2SAggelos Economopoulos static
100807a01c2SAggelos Economopoulos plotid_t
ploticus_new_plot(void * _ctx,enum plot_type type,const char * title)101807a01c2SAggelos Economopoulos ploticus_new_plot(void *_ctx, enum plot_type type, const char *title)
102807a01c2SAggelos Economopoulos {
103807a01c2SAggelos Economopoulos 	struct ploticus_plot *plot;
104807a01c2SAggelos Economopoulos 	prop_dictionary_t params;
105807a01c2SAggelos Economopoulos 	prop_string_t str;
106807a01c2SAggelos Economopoulos 	struct ploticus_plotter *ctx = _ctx;
107807a01c2SAggelos Economopoulos 	struct ploticus_plot **tmp;
108807a01c2SAggelos Economopoulos 	char *datapath;
109807a01c2SAggelos Economopoulos 
110807a01c2SAggelos Economopoulos 	if ((type <= PLOT_TYPE_START) || (type >= PLOT_TYPE_END))
111807a01c2SAggelos Economopoulos 		return -1;
112807a01c2SAggelos Economopoulos 	if (!(tmp = realloc(ctx->plots, sizeof(struct ploticus_plot *) *
113807a01c2SAggelos Economopoulos 			    (ctx->nr_plots + 1))))
114807a01c2SAggelos Economopoulos 		return -1;
115807a01c2SAggelos Economopoulos 	ctx->plots = tmp;
116807a01c2SAggelos Economopoulos 
117807a01c2SAggelos Economopoulos 	if (!(params = prop_dictionary_create()))
118807a01c2SAggelos Economopoulos 		return -1;
119807a01c2SAggelos Economopoulos 	if (!(plot = calloc(1, sizeof(*plot))))
120807a01c2SAggelos Economopoulos 		goto free_params;
121807a01c2SAggelos Economopoulos 	plot->params = params;
122807a01c2SAggelos Economopoulos 	plot->type = type;
123807a01c2SAggelos Economopoulos 
124807a01c2SAggelos Economopoulos 	if (asprintf(&plot->path, "%s-%d-%s", ctx->basepath, type,
125807a01c2SAggelos Economopoulos 		     title) < 0)
126807a01c2SAggelos Economopoulos 		goto free_plot;
127807a01c2SAggelos Economopoulos 	if (asprintf(&datapath, "%s.data", plot->path) < 0)
128807a01c2SAggelos Economopoulos 		goto free_path;
129807a01c2SAggelos Economopoulos 
130807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring(title)))
131807a01c2SAggelos Economopoulos 		goto free_datapath;
132807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "title", str)) {
133807a01c2SAggelos Economopoulos 		prop_object_release(str);
134807a01c2SAggelos Economopoulos 		goto free_datapath;
135807a01c2SAggelos Economopoulos 	}
136807a01c2SAggelos Economopoulos 	if (!(str = prop_string_create_cstring(datapath)))
137807a01c2SAggelos Economopoulos 		goto free_datapath;
138807a01c2SAggelos Economopoulos 	if (!prop_dictionary_set(params, "data", str)) {
139807a01c2SAggelos Economopoulos 		prop_object_release(str);
140807a01c2SAggelos Economopoulos 		goto free_datapath;
141807a01c2SAggelos Economopoulos 	}
142807a01c2SAggelos Economopoulos 
143807a01c2SAggelos Economopoulos 	if (plot_type_initializers[type](plot))
144807a01c2SAggelos Economopoulos 		goto free_datapath;
145807a01c2SAggelos Economopoulos 	if (!(plot->fp = fopen(datapath, "w"))) {
146807a01c2SAggelos Economopoulos 		goto free_datapath;
147807a01c2SAggelos Economopoulos 	}
148807a01c2SAggelos Economopoulos 	free(datapath);
149807a01c2SAggelos Economopoulos 	ctx->plots[ctx->nr_plots] = plot;
150807a01c2SAggelos Economopoulos 	return ctx->nr_plots++;
151807a01c2SAggelos Economopoulos 
152807a01c2SAggelos Economopoulos free_datapath:
153807a01c2SAggelos Economopoulos 	free(datapath);
154807a01c2SAggelos Economopoulos free_path:
155807a01c2SAggelos Economopoulos 	free(plot->path);
156807a01c2SAggelos Economopoulos free_plot:
157807a01c2SAggelos Economopoulos 	free(plot);
158807a01c2SAggelos Economopoulos free_params:
159807a01c2SAggelos Economopoulos 	prop_object_release(params);
160807a01c2SAggelos Economopoulos 	return -1;
161807a01c2SAggelos Economopoulos }
162807a01c2SAggelos Economopoulos 
163807a01c2SAggelos Economopoulos static
164807a01c2SAggelos Economopoulos int
ploticus_plot_histogram(void * _ctx,plotid_t id,double val)165807a01c2SAggelos Economopoulos ploticus_plot_histogram(void *_ctx, plotid_t id, double val)
166807a01c2SAggelos Economopoulos {
167807a01c2SAggelos Economopoulos 	struct ploticus_plotter *ctx = _ctx;
168807a01c2SAggelos Economopoulos 	struct ploticus_plot *plot;
169807a01c2SAggelos Economopoulos 
170807a01c2SAggelos Economopoulos 	if ((id < 0) || (id >= ctx->nr_plots))
171807a01c2SAggelos Economopoulos 		return ERANGE;
172807a01c2SAggelos Economopoulos 	plot = ctx->plots[id];
173807a01c2SAggelos Economopoulos 	assert(plot != NULL);
174807a01c2SAggelos Economopoulos 
175807a01c2SAggelos Economopoulos 	fprintf(plot->fp, "%lf\n", val);
176807a01c2SAggelos Economopoulos 
177807a01c2SAggelos Economopoulos 	return 0;
178807a01c2SAggelos Economopoulos }
179807a01c2SAggelos Economopoulos 
180807a01c2SAggelos Economopoulos static
181807a01c2SAggelos Economopoulos int
ploticus_plot_line(void * _ctx,plotid_t id,double x,double y)182807a01c2SAggelos Economopoulos ploticus_plot_line(void *_ctx, plotid_t id, double x, double y)
183807a01c2SAggelos Economopoulos {
184807a01c2SAggelos Economopoulos 	struct ploticus_plotter *ctx = _ctx;
185807a01c2SAggelos Economopoulos 	struct ploticus_plot *plot;
186807a01c2SAggelos Economopoulos 
187807a01c2SAggelos Economopoulos 	if ((id < 0) || (id >= ctx->nr_plots))
188807a01c2SAggelos Economopoulos 		return ERANGE;
189807a01c2SAggelos Economopoulos 	plot = ctx->plots[id];
190807a01c2SAggelos Economopoulos 	assert(plot != NULL);
191807a01c2SAggelos Economopoulos 
192807a01c2SAggelos Economopoulos 	fprintf(plot->fp, "%lf %lf\n", x, y);
193807a01c2SAggelos Economopoulos 
194807a01c2SAggelos Economopoulos 	return 0;
195807a01c2SAggelos Economopoulos }
196807a01c2SAggelos Economopoulos 
197807a01c2SAggelos Economopoulos extern char **environ;
198807a01c2SAggelos Economopoulos 
199807a01c2SAggelos Economopoulos static
200807a01c2SAggelos Economopoulos void
ploticus_run(struct ploticus_plot * plot)201807a01c2SAggelos Economopoulos ploticus_run(struct ploticus_plot *plot)
202807a01c2SAggelos Economopoulos {
203807a01c2SAggelos Economopoulos 	unsigned nr_params;
204807a01c2SAggelos Economopoulos 	const char **pl_argv;
205807a01c2SAggelos Economopoulos 	prop_object_iterator_t it;
206807a01c2SAggelos Economopoulos 	prop_object_t key, val;
207807a01c2SAggelos Economopoulos 	const char *keystr;
208807a01c2SAggelos Economopoulos 	const char *output_format = "-svg";
209807a01c2SAggelos Economopoulos 	int i;
210807a01c2SAggelos Economopoulos 
211807a01c2SAggelos Economopoulos 	printd(PLOT, "ploticus_run\n");
212807a01c2SAggelos Economopoulos 	nr_params = prop_dictionary_count(plot->params);
213807a01c2SAggelos Economopoulos 	if (!(pl_argv = calloc(nr_params +
214807a01c2SAggelos Economopoulos 			       1 +	/* progname */
215807a01c2SAggelos Economopoulos 			       1 +	/* trailing NULL */
216807a01c2SAggelos Economopoulos 			       1 +	/* -prefab */
217807a01c2SAggelos Economopoulos 			       1 +	/* dist */
218807a01c2SAggelos Economopoulos 			       1 +	/* output format */
219807a01c2SAggelos Economopoulos 			       1 +	/* -o */
220807a01c2SAggelos Economopoulos 			       1	/* outpath */
221807a01c2SAggelos Economopoulos 			       , sizeof(char *))))
222807a01c2SAggelos Economopoulos 		err(1, "can't allocate argv");
223807a01c2SAggelos Economopoulos 	if (!(it = prop_dictionary_iterator(plot->params)))
224807a01c2SAggelos Economopoulos 		err(1, "can't allocate dictionary iterator");
225807a01c2SAggelos Economopoulos 	pl_argv[0] = "ploticus";
226807a01c2SAggelos Economopoulos 	pl_argv[1] = "-prefab";
227807a01c2SAggelos Economopoulos 	pl_argv[2] = plot_prefabs[plot->type];
228807a01c2SAggelos Economopoulos 	pl_argv[2 + nr_params + 1] = output_format;
229807a01c2SAggelos Economopoulos 	pl_argv[2 + nr_params + 2] = "-o";
230807a01c2SAggelos Economopoulos 	if (asprintf(__DECONST(char **, &pl_argv[2 + nr_params + 3]),
231807a01c2SAggelos Economopoulos 		     "%s.svg", plot->path) < 0)
232807a01c2SAggelos Economopoulos 		err(1, "Can't allocate args");
233807a01c2SAggelos Economopoulos 	key = prop_object_iterator_next(it);
234807a01c2SAggelos Economopoulos 	for (i = 3; key; ++i, key = prop_object_iterator_next(it)) {
235807a01c2SAggelos Economopoulos 		keystr = prop_dictionary_keysym_cstring_nocopy(key);
236807a01c2SAggelos Economopoulos 		assert(keystr != NULL);
237807a01c2SAggelos Economopoulos 		val = prop_dictionary_get_keysym(plot->params, key);
238807a01c2SAggelos Economopoulos 		assert(val != NULL);
239807a01c2SAggelos Economopoulos 		printd(PLOT, "%s=%s\n", keystr,
240807a01c2SAggelos Economopoulos 		       prop_string_cstring_nocopy(val));
241807a01c2SAggelos Economopoulos 		if (asprintf(__DECONST(char **, &pl_argv[i]), "%s=%s", keystr,
242807a01c2SAggelos Economopoulos 			     prop_string_cstring_nocopy(val)) < 0)
243807a01c2SAggelos Economopoulos 			err(1, "can't allocate exec arguments");
244807a01c2SAggelos Economopoulos 	}
245807a01c2SAggelos Economopoulos 	prop_object_iterator_release(it);
246807a01c2SAggelos Economopoulos 	printd(PLOT, "about to exec with args:\n");
247807a01c2SAggelos Economopoulos 	for (i = 0; pl_argv[i]; ++i)
248807a01c2SAggelos Economopoulos 		printd(PLOT, "%s\n", pl_argv[i]);
249*24c607efSSascha Wildner 	execve("/usr/local/bin/ploticus", __DECONST(char * const *, pl_argv), environ);
250807a01c2SAggelos Economopoulos 	err(1, "failed to exec ploticus");
251807a01c2SAggelos Economopoulos }
252807a01c2SAggelos Economopoulos 
253807a01c2SAggelos Economopoulos static
254807a01c2SAggelos Economopoulos int
ploticus_plot_generate(struct ploticus_plot * plot)255807a01c2SAggelos Economopoulos ploticus_plot_generate(struct ploticus_plot *plot)
256807a01c2SAggelos Economopoulos {
257807a01c2SAggelos Economopoulos 	pid_t pid;
258807a01c2SAggelos Economopoulos 	int status;
259807a01c2SAggelos Economopoulos 
260807a01c2SAggelos Economopoulos 	fclose(plot->fp);
261807a01c2SAggelos Economopoulos 
262807a01c2SAggelos Economopoulos 	switch ((pid = fork())) {
263807a01c2SAggelos Economopoulos 	case -1:
264807a01c2SAggelos Economopoulos 		return -1;
265807a01c2SAggelos Economopoulos 	case 0:	/* child */
266807a01c2SAggelos Economopoulos 		ploticus_run(plot);
267807a01c2SAggelos Economopoulos 		assert(!"can't get here");
268807a01c2SAggelos Economopoulos 	}
269807a01c2SAggelos Economopoulos 	/* parent */
270807a01c2SAggelos Economopoulos 	if (waitpid(pid, &status, 0) != pid)
271807a01c2SAggelos Economopoulos 		err(1, "waitpid() failed");
272807a01c2SAggelos Economopoulos 	if (!WIFEXITED(status))
273807a01c2SAggelos Economopoulos 		warn("ploticus did not exit!");
274807a01c2SAggelos Economopoulos 	if (WEXITSTATUS(status))
275807a01c2SAggelos Economopoulos 		warn("ploticus did not run successfully");
276807a01c2SAggelos Economopoulos 	return 0;
277807a01c2SAggelos Economopoulos }
278807a01c2SAggelos Economopoulos 
279807a01c2SAggelos Economopoulos static
280807a01c2SAggelos Economopoulos int
ploticus_plot_finish(void * _ctx)281807a01c2SAggelos Economopoulos ploticus_plot_finish(void *_ctx)
282807a01c2SAggelos Economopoulos {
283807a01c2SAggelos Economopoulos 	struct ploticus_plotter *ctx = _ctx;
284807a01c2SAggelos Economopoulos 	int i;
285807a01c2SAggelos Economopoulos 
286807a01c2SAggelos Economopoulos 	for (i = 0; i < ctx->nr_plots; ++i) {
287807a01c2SAggelos Economopoulos 		if (ploticus_plot_generate(ctx->plots[i]))
288807a01c2SAggelos Economopoulos 			return -1;
289807a01c2SAggelos Economopoulos 	}
290807a01c2SAggelos Economopoulos 	return 0;
291807a01c2SAggelos Economopoulos }
292807a01c2SAggelos Economopoulos 
293807a01c2SAggelos Economopoulos static struct plotter ploticus_plotter = {
294807a01c2SAggelos Economopoulos 	.plot_init = ploticus_init,
295807a01c2SAggelos Economopoulos 	.plot_new = ploticus_new_plot,
296807a01c2SAggelos Economopoulos 	.plot_histogram = ploticus_plot_histogram,
297807a01c2SAggelos Economopoulos 	.plot_line = ploticus_plot_line,
298807a01c2SAggelos Economopoulos 	.plot_finish = ploticus_plot_finish,
299807a01c2SAggelos Economopoulos };
300807a01c2SAggelos Economopoulos 
301*24c607efSSascha Wildner static const char *ploticus_path = "/usr/local/bin/ploticus";
302807a01c2SAggelos Economopoulos 
303807a01c2SAggelos Economopoulos struct plotter *
plotter_factory(void)304807a01c2SAggelos Economopoulos plotter_factory(void)
305807a01c2SAggelos Economopoulos {
306807a01c2SAggelos Economopoulos 	struct stat st;
307807a01c2SAggelos Economopoulos 	if ((!stat(ploticus_path, &st)) &&
308807a01c2SAggelos Economopoulos 	    S_ISREG(st.st_mode) &&
309807a01c2SAggelos Economopoulos 	    (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
310807a01c2SAggelos Economopoulos 		return &ploticus_plotter;
311807a01c2SAggelos Economopoulos 	warnx("%s does not exist or is not an executable file", ploticus_path);
312807a01c2SAggelos Economopoulos 	return NULL;
313807a01c2SAggelos Economopoulos }
314