output: Rename page-eject-item to page-break-item.
[pspp] / src / output / spv / spv-select.c
index dacd53ec91b34d4a0375a1a45d030707f8486fae..10f35a1811d98480ee7aaf00971fc2b33b0fac6c 100644 (file)
 #include "gl/c-ctype.h"
 #include "gl/xalloc.h"
 
+/* Returns true if ITEM represents a command, false otherwise.
+
+   The root item and each of its immediate children are considered to be
+   command items. */
+static bool
+is_command_item (const struct spv_item *item)
+{
+  return !item->parent || !item->parent->parent;
+}
+
 static struct spv_item *
 find_command_item (struct spv_item *item)
 {
-  /* A command item itself does not have a command item. */
-  if (!item->parent || !item->parent->parent)
-    return NULL;
-
-  do
-    {
-      item = item->parent;
-    }
-  while (item->parent && item->parent->parent);
+  while (!is_command_item (item))
+    item = item->parent;
   return item;
 }
 
@@ -97,21 +100,36 @@ match_instance (const int *instances, size_t n_instances,
   return retval;
 }
 
+static bool
+match_command (size_t nth_command, size_t *commands, size_t n_commands)
+{
+  for (size_t i = 0; i < n_commands; i++)
+    if (nth_command == commands[i])
+      return true;
+  return false;
+}
+
 static void
 select_matches (const struct spv_reader *spv, const struct spv_criteria *c,
                 unsigned long int *include)
 {
-  struct spv_item *item;
-  struct spv_item *command_item = NULL;
+  /* Counting instances within a command. */
+  struct spv_item *instance_command_item = NULL;
   int instance_within_command = 0;
   int last_instance = -1;
+
+  /* Counting commands. */
+  struct spv_item *command_command_item = NULL;
+  size_t nth_command = 0;
+
+  struct spv_item *item;
   ssize_t index = -1;
   SPV_ITEM_FOR_EACH_SKIP_ROOT (item, spv_get_root (spv))
     {
       index++;
 
       struct spv_item *new_command_item = find_command_item (item);
-      if (new_command_item != command_item)
+      if (new_command_item != instance_command_item)
         {
           if (last_instance >= 0)
             {
@@ -119,7 +137,7 @@ select_matches (const struct spv_reader *spv, const struct spv_criteria *c,
               last_instance = -1;
             }
 
-          command_item = new_command_item;
+          instance_command_item = new_command_item;
           instance_within_command = 0;
         }
 
@@ -140,6 +158,18 @@ select_matches (const struct spv_reader *spv, const struct spv_criteria *c,
                   &c->include.commands, &c->exclude.commands))
         continue;
 
+      if (c->n_commands)
+        {
+          if (new_command_item != command_command_item)
+            {
+              command_command_item = new_command_item;
+              nth_command++;
+            }
+
+          if (!match_command (nth_command, c->commands, c->n_commands))
+            continue;
+        }
+
       if (!match (spv_item_get_subtype (item),
                   &c->include.subtypes, &c->exclude.subtypes))
         continue;
@@ -148,16 +178,29 @@ select_matches (const struct spv_reader *spv, const struct spv_criteria *c,
                   &c->include.labels, &c->exclude.labels))
         continue;
 
-      if (c->members.n
-          && !((item->xml_member
-                && string_array_matches (item->xml_member, &c->members)) ||
-               (item->bin_member
-                && string_array_matches (item->bin_member, &c->members))))
-        continue;
+      if (c->members.n)
+        {
+          char *members[] = {
+            item->structure_member,
+            item->xml_member,
+            item->bin_member,
+            item->png_member
+          };
+
+          bool found = false;
+          for (size_t i = 0; i < sizeof members / sizeof *members; i++)
+            if (string_array_matches (members[i], &c->members) == true)
+              {
+                found = true;
+                break;
+              }
+          if (!found)
+            continue;
+        }
 
       if (c->n_instances)
         {
-          if (!command_item)
+          if (is_command_item (item))
             continue;
           instance_within_command++;