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