4 #include <libprop/proplib.h>
16 struct ploticus_plot {
18 prop_dictionary_t params;
23 struct ploticus_plotter {
25 struct ploticus_plot **plots;
29 const char *plot_prefabs[] = {
30 [PLOT_TYPE_HIST] = "dist",
31 [PLOT_TYPE_LINE] = "lines",
36 ploticus_init(const char *base)
38 struct ploticus_plotter *ctx;
40 if (!(ctx = calloc(1, sizeof(*ctx))))
42 if (!(ctx->basepath = strdup(base)))
52 ploticus_new_plot_hist(struct ploticus_plot *plot)
54 prop_dictionary_t params = plot->params;
57 if (!(str = prop_string_create_cstring_nocopy("1")))
59 if (!prop_dictionary_set(params, "x", str)) {
60 prop_object_release(str);
63 if (!(str = prop_string_create_cstring_nocopy("yes")))
65 if (!prop_dictionary_set(params, "curve", str)) {
66 prop_object_release(str);
74 ploticus_new_plot_line(struct ploticus_plot *plot)
76 prop_dictionary_t params = plot->params;
79 if (!(str = prop_string_create_cstring_nocopy("1")))
81 if (!prop_dictionary_set(params, "x", str)) {
82 prop_object_release(str);
85 if (!(str = prop_string_create_cstring_nocopy("2")))
87 if (!prop_dictionary_set(params, "y", str)) {
88 prop_object_release(str);
94 int (*plot_type_initializers[])(struct ploticus_plot *) = {
95 [PLOT_TYPE_HIST] = ploticus_new_plot_hist,
96 [PLOT_TYPE_LINE] = ploticus_new_plot_line,
101 ploticus_new_plot(void *_ctx, enum plot_type type, const char *title)
103 struct ploticus_plot *plot;
104 prop_dictionary_t params;
106 struct ploticus_plotter *ctx = _ctx;
107 struct ploticus_plot **tmp;
110 if ((type <= PLOT_TYPE_START) || (type >= PLOT_TYPE_END))
112 if (!(tmp = realloc(ctx->plots, sizeof(struct ploticus_plot *) *
113 (ctx->nr_plots + 1))))
117 if (!(params = prop_dictionary_create()))
119 if (!(plot = calloc(1, sizeof(*plot))))
121 plot->params = params;
124 if (asprintf(&plot->path, "%s-%d-%s", ctx->basepath, type,
127 if (asprintf(&datapath, "%s.data", plot->path) < 0)
130 if (!(str = prop_string_create_cstring(title)))
132 if (!prop_dictionary_set(params, "title", str)) {
133 prop_object_release(str);
136 if (!(str = prop_string_create_cstring(datapath)))
138 if (!prop_dictionary_set(params, "data", str)) {
139 prop_object_release(str);
143 if (plot_type_initializers[type](plot))
145 if (!(plot->fp = fopen(datapath, "w"))) {
149 ctx->plots[ctx->nr_plots] = plot;
150 return ctx->nr_plots++;
159 prop_object_release(params);
165 ploticus_plot_histogram(void *_ctx, plotid_t id, double val)
167 struct ploticus_plotter *ctx = _ctx;
168 struct ploticus_plot *plot;
170 if ((id < 0) || (id >= ctx->nr_plots))
172 plot = ctx->plots[id];
173 assert(plot != NULL);
175 fprintf(plot->fp, "%lf\n", val);
182 ploticus_plot_line(void *_ctx, plotid_t id, double x, double y)
184 struct ploticus_plotter *ctx = _ctx;
185 struct ploticus_plot *plot;
187 if ((id < 0) || (id >= ctx->nr_plots))
189 plot = ctx->plots[id];
190 assert(plot != NULL);
192 fprintf(plot->fp, "%lf %lf\n", x, y);
197 extern char **environ;
201 ploticus_run(struct ploticus_plot *plot)
204 const char **pl_argv;
205 prop_object_iterator_t it;
206 prop_object_t key, val;
208 const char *output_format = "-svg";
211 printd(PLOT, "ploticus_run\n");
212 nr_params = prop_dictionary_count(plot->params);
213 if (!(pl_argv = calloc(nr_params +
215 1 + /* trailing NULL */
218 1 + /* output format */
222 err(1, "can't allocate argv");
223 if (!(it = prop_dictionary_iterator(plot->params)))
224 err(1, "can't allocate dictionary iterator");
225 pl_argv[0] = "ploticus";
226 pl_argv[1] = "-prefab";
227 pl_argv[2] = plot_prefabs[plot->type];
228 pl_argv[2 + nr_params + 1] = output_format;
229 pl_argv[2 + nr_params + 2] = "-o";
230 if (asprintf(__DECONST(char **, &pl_argv[2 + nr_params + 3]),
231 "%s.svg", plot->path) < 0)
232 err(1, "Can't allocate args");
233 key = prop_object_iterator_next(it);
234 for (i = 3; key; ++i, key = prop_object_iterator_next(it)) {
235 keystr = prop_dictionary_keysym_cstring_nocopy(key);
236 assert(keystr != NULL);
237 val = prop_dictionary_get_keysym(plot->params, key);
239 printd(PLOT, "%s=%s\n", keystr,
240 prop_string_cstring_nocopy(val));
241 if (asprintf(__DECONST(char **, &pl_argv[i]), "%s=%s", keystr,
242 prop_string_cstring_nocopy(val)) < 0)
243 err(1, "can't allocate exec arguments");
245 prop_object_iterator_release(it);
246 printd(PLOT, "about to exec with args:\n");
247 for (i = 0; pl_argv[i]; ++i)
248 printd(PLOT, "%s\n", pl_argv[i]);
249 execve("/usr/pkg/bin/pl", __DECONST(char * const *, pl_argv), environ);
250 err(1, "failed to exec ploticus");
255 ploticus_plot_generate(struct ploticus_plot *plot)
262 switch ((pid = fork())) {
267 assert(!"can't get here");
270 if (waitpid(pid, &status, 0) != pid)
271 err(1, "waitpid() failed");
272 if (!WIFEXITED(status))
273 warn("ploticus did not exit!");
274 if (WEXITSTATUS(status))
275 warn("ploticus did not run successfully");
281 ploticus_plot_finish(void *_ctx)
283 struct ploticus_plotter *ctx = _ctx;
286 for (i = 0; i < ctx->nr_plots; ++i) {
287 if (ploticus_plot_generate(ctx->plots[i]))
293 static struct plotter ploticus_plotter = {
294 .plot_init = ploticus_init,
295 .plot_new = ploticus_new_plot,
296 .plot_histogram = ploticus_plot_histogram,
297 .plot_line = ploticus_plot_line,
298 .plot_finish = ploticus_plot_finish,
301 static const char *ploticus_path = "/usr/pkg/bin/pl";
304 plotter_factory(void)
307 if ((!stat(ploticus_path, &st)) &&
308 S_ISREG(st.st_mode) &&
309 (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
310 return &ploticus_plotter;
311 warnx("%s does not exist or is not an executable file", ploticus_path);