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/local/bin/ploticus", __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/local/bin/ploticus";
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
);