+static bool
+output_driver_should_show (const struct output_driver *d,
+ const struct output_item *item)
+{
+ enum settings_output_type type = SETTINGS_OUTPUT_RESULT;
+ switch (item->type)
+ {
+ case OUTPUT_ITEM_MESSAGE:
+ type = (item->message->severity == MSG_S_NOTE
+ ? SETTINGS_OUTPUT_NOTE
+ : SETTINGS_OUTPUT_ERROR);
+ break;
+
+ case OUTPUT_ITEM_TEXT:
+ if (item->text.subtype == TEXT_ITEM_SYNTAX)
+ type = SETTINGS_OUTPUT_SYNTAX;
+ break;
+
+ case OUTPUT_ITEM_CHART:
+ case OUTPUT_ITEM_GROUP:
+ case OUTPUT_ITEM_IMAGE:
+ case OUTPUT_ITEM_PAGE_BREAK:
+ case OUTPUT_ITEM_TABLE:
+ break;
+ }
+
+ return (settings_get_output_routing (type) & d->device_type) != 0;
+}
+
+/* Adds to OUT the subset of IN that driver D should show, considering routing
+ and visibility of each item, and flattening groups for drivers that don't
+ handle them internally. */
+static void
+make_driver_output_subset (const struct output_item *in,
+ const struct output_driver *d,
+ struct output_item *out)
+{
+ if (in->type == OUTPUT_ITEM_GROUP)
+ {
+ /* If we should include the group itself, then clone IN inside OUT, and
+ add any children to the clone instead to OUT directly. */
+ if (output_driver_should_show (d, in) && d->class->handles_groups)
+ {
+ struct output_item *group = group_item_clone_empty (in);
+ group_item_add_child (out, group);
+ out = group;
+ }
+
+ for (size_t i = 0; i < in->group.n_children; i++)
+ make_driver_output_subset (in->group.children[i], d, out);
+ }
+ else
+ {
+ if (output_driver_should_show (d, in)
+ && (in->show || d->class->handles_show))
+ group_item_add_child (out, output_item_ref (in));
+ }
+}
+