+
+void
+output_driver_parse_option (const char *option, struct string_map *options)
+{
+ const char *equals = strchr (option, '=');
+ if (equals == NULL)
+ {
+ error (0, 0, _("%s: output option missing `='"), option);
+ return;
+ }
+
+ char *key = xmemdup0 (option, equals - option);
+ if (string_map_contains (options, key))
+ {
+ error (0, 0, _("%s: output option specified more than once"), key);
+ free (key);
+ return;
+ }
+
+ char *value = xmemdup0 (equals + 1, strlen (equals + 1));
+ string_map_insert_nocopy (options, key, value);
+}
+\f
+char *
+output_driver_substitute_heading_vars (const char *src, int page_number)
+{
+ struct output_engine *e = engine_stack_top ();
+ struct string dst = DS_EMPTY_INITIALIZER;
+ ds_extend (&dst, strlen (src));
+ for (const char *p = src; *p;)
+ {
+ if (!strncmp (p, "&[", 6))
+ {
+ if (page_number != INT_MIN)
+ {
+ const char *start = p + 6;
+ const char *end = strchr (start, ']');
+ if (end)
+ {
+ const char *value = string_map_find__ (&e->heading_vars,
+ start, end - start);
+ if (value)
+ ds_put_cstr (&dst, value);
+ else if (ss_equals (ss_buffer (start, end - start),
+ ss_cstr ("Page")))
+ ds_put_format (&dst, "%d", page_number);
+ p = end + 1;
+ continue;
+ }
+ }
+ ds_put_cstr (&dst, "&");
+ p += 5;
+ }
+ else
+ ds_put_byte (&dst, *p++);
+ }
+ return ds_steal_cstr (&dst);
+}