Replace numerous instances of xzalloc with XZALLOC
[pspp] / src / ui / gui / find-dialog.c
index 5a82b6c9ec2be9ee236455b190a43fd81a6279ae..16f5e365761a12ab3b13cec78ea4d91e42da3bce 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2009, 2011, 2012, 2015, 2020  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,35 +20,36 @@ which match particular strings */
 
 #include <config.h>
 
-#include "find-dialog.h"
-#include "psppire-selector.h"
-#include "psppire-dialog.h"
-#include "helper.h"
-#include "psppire-data-window.h"
-#include "dict-display.h"
-#include <data/value.h>
-#include <data/format.h>
-#include <data/datasheet.h>
-#include <data/data-in.h>
-#include "psppire-data-store.h"
 #include <ctype.h>
-#include <sys/types.h>
-#include <regex.h>
-#include <libpspp/message.h>
-
 #include <gtk/gtk.h>
+#include <regex.h>
 #include <stdlib.h>
-
-#include "xalloc.h"
+#include <sys/types.h>
+#include <math.h>
+
+#include "data/data-in.h"
+#include "data/datasheet.h"
+#include "data/format.h"
+#include "data/value.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "ui/gui/builder-wrapper.h"
+#include "ui/gui/dict-display.h"
+#include "ui/gui/find-dialog.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-selector.h"
+#include <ssw-sheet.h>
+
+#include "gl/xalloc.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 
-/* FIXME: These shouldn't be here */
-#include "psppire-var-store.h"
-
 struct find_dialog
 {
   GtkBuilder *xml;
@@ -100,29 +101,23 @@ refresh (GObject *obj, const struct find_dialog *fd)
 static void
 do_find (GObject *obj, const struct find_dialog *fd)
 {
+  SswSheet *sheet = SSW_SHEET (fd->de->data_editor->data_sheet);
   casenumber x = -1;
   gint column = -1;
-  glong row;
-
-  g_object_get (fd->de->data_editor, "current-case", &row, NULL);
-
-  if ( row < 0 )
-    row = 0;
+  gint unused;
+  gint row = 0;
+  ssw_sheet_get_active_cell (sheet, &unused, &row);
 
   find_value (fd, row, &x, &column);
 
-
-  if ( x != -1)
+  if (x != -1)
     {
       gtk_notebook_set_current_page (GTK_NOTEBOOK (fd->de->data_editor),
                                     PSPPIRE_DATA_EDITOR_DATA_VIEW);
 
-      g_object_set (fd->de->data_editor,
-                   "current-case", x,
-                   "current-variable", column,
-                   NULL);
+      ssw_sheet_scroll_to (sheet, column, x);
+      ssw_sheet_set_active_cell (sheet, column, x, NULL);
     }
-
 }
 
 /* Callback on the selector.
@@ -183,10 +178,8 @@ value_labels_toggled (GtkToggleButton *tb, gpointer data)
 /* Pops up the Find dialog box
  */
 void
-find_dialog (GObject *o, gpointer data)
+find_dialog (PsppireDataWindow *de)
 {
-  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
-
   struct find_dialog fd;
 
   GtkWidget *dialog ;
@@ -196,18 +189,17 @@ find_dialog (GObject *o, gpointer data)
 
   GtkWidget *buttonbox;
 
-  PsppireVarStore *vs ;
   PsppireDataStore *ds ;
 
   fd.xml = builder_new ("find.ui");
   fd.de = de;
 
-  find_button = gtk_button_new_from_stock  (GTK_STOCK_FIND);
+  find_button = gtk_button_new_with_label (_("Find"));
   gtk_widget_show (find_button);
 
   buttonbox = get_widget_assert (fd.xml, "find-buttonbox");
 
-  gtk_box_pack_start_defaults (GTK_BOX (buttonbox), find_button);
+  psppire_box_pack_start_defaults (GTK_BOX (buttonbox), find_button);
   gtk_box_reorder_child (GTK_BOX (buttonbox), find_button, 0);
 
   dialog = get_widget_assert (fd.xml, "find-dialog");
@@ -215,11 +207,10 @@ find_dialog (GObject *o, gpointer data)
   selector = get_widget_assert (fd.xml, "find-selector");
 
   g_object_get (de->data_editor,
-               "var-store", &vs,
+               "dictionary", &fd.dict,
                "data-store", &ds,
                NULL);
 
-  fd.dict = vs->dict;
   fd.data = ds->datasheet;
 
   fd.variable_entry        = get_widget_assert (fd.xml, "find-variable-entry");
@@ -241,17 +232,13 @@ find_dialog (GObject *o, gpointer data)
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
 
-  g_object_set (source, "dictionary", fd.dict,
+  g_object_set (source, "model", fd.dict,
        "selection-mode", GTK_SELECTION_SINGLE,
        NULL);
 
-  psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
-                                source,
-                                fd.variable_entry,
-                                insert_source_row_into_entry,
-                                is_currently_in_entry,
-                                NULL
-                                );
+
+  psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
+                                   is_currently_in_entry);
 
   g_signal_connect (dialog, "refresh", G_CALLBACK (refresh),  &fd);
 
@@ -285,7 +272,7 @@ forward (casenumber *i, struct datasheet *data UNUSED)
 static void
 forward_wrap (casenumber *i, struct datasheet *data)
 {
-  if ( ++*i >=  datasheet_get_row_cnt (data) ) *i = 0;
+  if (++*i >=  datasheet_get_n_rows (data)) *i = 0;
 }
 
 static void
@@ -298,8 +285,8 @@ backward (casenumber *i, struct datasheet *data UNUSED)
 static void
 backward_wrap (casenumber *i, struct datasheet *data)
 {
-  if ( --*i < 0 )
-    *i = datasheet_get_row_cnt (data) - 1;
+  if (--*i < 0)
+    *i = datasheet_get_n_rows (data) - 1;
 }
 
 
@@ -326,6 +313,9 @@ cp1c (casenumber current, struct datasheet *data)
 static casenumber
 cm1 (casenumber current, struct datasheet *data)
 {
+  if (current == 0)
+    return datasheet_get_n_rows (data) - 1;
+
   return current - 1;
 }
 
@@ -344,7 +334,7 @@ cm1c (casenumber current, struct datasheet *data)
 static casenumber
 last (casenumber current, struct datasheet *data)
 {
-  return datasheet_get_row_cnt (data) ;
+  return datasheet_get_n_rows (data) ;
 }
 
 static casenumber
@@ -374,11 +364,18 @@ enum iteration_type{
   n_iterators
 };
 
-static const struct casenum_iterator ip[n_iterators] =
+static const struct casenum_iterator case_iterator[n_iterators] =
   {
+   /* Forward iterator (linear) */
     {cp1, last, forward},
+
+    /* Forward iterator (circular) */
     {cp1c, cm1, forward_wrap},
+
+    /* Reverse iterator (linear) */
     {cm1, minus1, backward},
+
+    /* Reverse iterator (circular */
     {cm1c, cp1, backward_wrap}
   };
 
@@ -394,19 +391,19 @@ get_iteration_params (const struct find_dialog *fd)
   gboolean reverse = gtk_toggle_button_get_active
     (GTK_TOGGLE_BUTTON (get_widget_assert (fd->xml, "find-backwards")));
 
-  if ( wrap )
+  if (wrap)
     {
-      if ( reverse )
-       return &ip[REVERSE_WRAP];
+      if (reverse)
+       return &case_iterator[REVERSE_WRAP];
       else
-       return &ip[FORWARD_WRAP];
+       return &case_iterator[FORWARD_WRAP];
     }
   else
     {
-      if ( reverse )
-       return &ip[REVERSE];
+      if (reverse)
+       return &case_iterator[REVERSE];
       else
-       return &ip[FORWARD];
+       return &case_iterator[FORWARD];
     }
 }
 
@@ -435,11 +432,13 @@ struct comparator
 };
 
 
-/* A comparator which operates on the unadulterated union values */
-struct value_comparator
+/* A comparator which operates on the numerical values,
+   rounded to the number of decimal places indicated by
+   the variable's format.  */
+struct numeric_comparator
 {
   struct comparator parent;
-  union value *pattern;
+  double rounded_ref;
 };
 
 /* A comparator which matches string values or parts thereof */
@@ -456,13 +455,29 @@ struct regexp_comparator
   regex_t re;
 };
 
+/* Returns 10 raised to the power of X.
+   X must be a non-negative integer.  */
+static inline int
+int_pow10 (int x)
+{
+  int ret = 1;
+  assert (x >= 0);
+  while (x--)
+    ret *= 10;
+
+  return ret;
+}
 
 static bool
 value_compare (const struct comparator *cmptr,
               const union value *v)
 {
-  const struct value_comparator *vc = (const struct value_comparator *) cmptr;
-  return 0 == value_compare_3way (v, vc->pattern, var_get_width (cmptr->var));
+  const struct numeric_comparator *nc = (const struct numeric_comparator *) cmptr;
+  const struct fmt_spec *fs = var_get_print_format (cmptr->var);
+
+  double c = nearbyint (v->f * int_pow10 (fs->d));
+
+  return c == nc->rounded_ref;
 }
 
 
@@ -474,14 +489,19 @@ string_label_compare (const struct comparator *cmptr,
   const struct string_comparator *ssc =
     (const struct string_comparator *) cmptr;
 
+  int width;
+
   const char *text = var_lookup_value_label (cmptr->var, val);
-  int width = strlen (text);
+  if (text == NULL)
+    return false;
+
+  width = strlen (text);
 
-  assert ( cmptr->flags & STR_CMP_LABELS);
+  assert (cmptr->flags & STR_CMP_LABELS);
 
   g_return_val_if_fail (width > 0, false);
 
-  if ( cmptr->flags & STR_CMP_SUBSTR)
+  if (cmptr->flags & STR_CMP_SUBSTR)
     return (NULL != g_strstr_len (text, width, ssc->pattern));
   else
     return (0 == strncmp (text, ssc->pattern, width));
@@ -492,20 +512,24 @@ static bool
 string_value_compare (const struct comparator *cmptr,
                      const union value *val)
 {
+  bool found;
+  char *text;
   const struct string_comparator *ssc =
     (const struct string_comparator *) cmptr;
 
-  const char *text = val->s;
   int width = var_get_width (cmptr->var);
-
-  assert ( ! (cmptr->flags & STR_CMP_LABELS));
-
   g_return_val_if_fail (width > 0, false);
+  assert (! (cmptr->flags & STR_CMP_LABELS));
 
-  if ( cmptr->flags & STR_CMP_SUBSTR)
-    return (NULL != g_strstr_len (text, width, ssc->pattern));
+  text = value_to_text (*val, cmptr->var);
+
+  if (cmptr->flags & STR_CMP_SUBSTR)
+    found =  (NULL != g_strstr_len (text, width, ssc->pattern));
   else
-    return (0 == strncmp (text, ssc->pattern, width));
+    found = (0 == strncmp (text, ssc->pattern, width));
+
+  free (text);
+  return found;
 }
 
 
@@ -522,13 +546,13 @@ regexp_value_compare (const struct comparator *cmptr,
 
   int width = var_get_width (cmptr->var);
 
-  assert  ( ! (cmptr->flags & STR_CMP_LABELS) );
+  assert  (! (cmptr->flags & STR_CMP_LABELS));
 
   g_return_val_if_fail (width > 0, false);
 
+  text = value_to_text (*val, cmptr->var);
   /* We must remove trailing whitespace, otherwise $ will not match where
      one would expect */
-  text = g_strndup (val->s, width);
   g_strchomp (text);
 
   retval = (0 == regexec (&rec->re, text, 0, 0, 0));
@@ -549,7 +573,7 @@ regexp_label_compare (const struct comparator *cmptr,
 
   int width ;
 
-  assert ( cmptr->flags & STR_CMP_LABELS);
+  assert (cmptr->flags & STR_CMP_LABELS);
 
   text = var_lookup_value_label (cmptr->var, val);
   width = strlen (text);
@@ -564,46 +588,27 @@ regexp_label_compare (const struct comparator *cmptr,
 static void
 regexp_destroy (struct comparator *cmptr)
 {
-  struct regexp_comparator *rec = (struct regexp_comparator *) cmptr;
+  struct regexp_comparator *rec
+    = UP_CAST (cmptr, struct regexp_comparator, parent);
 
   regfree (&rec->re);
 }
 
-static void
-value_destroy (struct comparator *cmptr)
-{
-  struct value_comparator *vc = (struct value_comparator *) cmptr;
-  free (vc->pattern);
-}
-
-
 static struct comparator *
-value_comparator_create (const struct variable *var, const char *target)
+numeric_comparator_create (const struct variable *var, const char *target)
 {
-  const struct fmt_spec *fmt;
-  int width ;
-  struct value_comparator *vc = xzalloc (sizeof (*vc));
-  struct comparator *cmptr = (struct comparator *) vc;
+  struct numeric_comparator *nc = XZALLOC (struct numeric_comparator);
+  struct comparator *cmptr = &nc->parent;
 
   cmptr->flags = 0;
   cmptr->var = var;
-  cmptr->compare  = value_compare ;
-  cmptr->destroy = value_destroy;
+  cmptr->compare  = value_compare;
+  const struct fmt_spec *fs = var_get_write_format (var);
 
-  width = var_get_width (var);
-  fmt = var_get_write_format (var);
-
-  vc->pattern = value_create (width);
-
-  if ( ! data_in (ss_cstr (target),
-                  LEGACY_NATIVE,
-                 fmt->type,
-                 0, 0, 0,
-                 vc->pattern, width) )
-    {
-      free (vc);
-      return NULL;
-    }
+  union value val;
+  text_to_value (target, var, &val);
+  nc->rounded_ref = nearbyint (val.f * int_pow10 (fs->d));
+  value_destroy (&val, var_get_width (var));
 
   return cmptr;
 }
@@ -612,13 +617,13 @@ static struct comparator *
 string_comparator_create (const struct variable *var, const char *target,
                          enum string_cmp_flags flags)
 {
-  struct string_comparator *ssc = xzalloc (sizeof (*ssc));
-  struct comparator *cmptr = (struct comparator *) ssc;
+  struct string_comparator *ssc = XZALLOC (struct string_comparator);
+  struct comparator *cmptr = &ssc->parent;
 
   cmptr->flags = flags;
   cmptr->var = var;
 
-  if ( flags & STR_CMP_LABELS)
+  if (flags & STR_CMP_LABELS)
     cmptr->compare = string_label_compare;
   else
     cmptr->compare = string_value_compare;
@@ -634,8 +639,8 @@ regexp_comparator_create (const struct variable *var, const char *target,
                          enum string_cmp_flags flags)
 {
   int code;
-  struct regexp_comparator *rec = xzalloc (sizeof (*rec));
-  struct comparator *cmptr = (struct comparator *) rec;
+  struct regexp_comparator *rec = XZALLOC (struct regexp_comparator);
+  struct comparator *cmptr = &rec->parent;
 
   cmptr->flags = flags;
   cmptr->var = var;
@@ -645,7 +650,7 @@ regexp_comparator_create (const struct variable *var, const char *target,
   cmptr->destroy  = regexp_destroy;
 
   code = regcomp (&rec->re, target, 0);
-  if ( code != 0 )
+  if (code != 0)
     {
       char *errbuf = NULL;
       size_t errbuf_size = regerror (code, &rec->re, errbuf,  0);
@@ -656,7 +661,7 @@ regexp_comparator_create (const struct variable *var, const char *target,
 
       msg (ME, _("Bad regular expression: %s"), errbuf);
 
-      free ( cmptr);
+      free (cmptr);
       free (errbuf);
       return NULL;
     }
@@ -677,10 +682,10 @@ comparator_compare (const struct comparator *cmptr,
 static void
 comparator_destroy (struct comparator *cmptr)
 {
-  if ( ! cmptr )
+  if (! cmptr)
     return ;
 
-  if ( cmptr->destroy )
+  if (cmptr->destroy)
     cmptr->destroy (cmptr);
 
   free (cmptr);
@@ -691,13 +696,13 @@ static struct comparator *
 comparator_factory (const struct variable *var, const char *str,
                    enum string_cmp_flags flags)
 {
-  if ( flags & STR_CMP_REGEXP )
+  if (flags & STR_CMP_REGEXP)
     return regexp_comparator_create (var, str, flags);
 
-  if ( flags & (STR_CMP_SUBSTR | STR_CMP_LABELS) )
+  if (flags & (STR_CMP_SUBSTR | STR_CMP_LABELS))
     return string_comparator_create (var, str, flags);
 
-  return value_comparator_create (var, str);
+  return numeric_comparator_create (var, str);
 }
 
 
@@ -715,10 +720,9 @@ find_value (const struct find_dialog *fd, casenumber current_row,
   const char *target_string = gtk_entry_get_text (GTK_ENTRY (fd->value_entry));
 
   enum string_cmp_flags flags = 0;
-  g_assert (current_row >= 0);
 
   var = dict_lookup_var (fd->dict->dict, var_name);
-  if ( ! var )
+  if (! var)
     return ;
 
   width = var_get_width (var);
@@ -726,36 +730,36 @@ find_value (const struct find_dialog *fd, casenumber current_row,
   *column = var_get_dict_index (var);
   *row = -1;
 
-  if ( gtk_toggle_button_get_active
+  if (gtk_toggle_button_get_active
        (GTK_TOGGLE_BUTTON (fd->match_substring_checkbox)))
     flags |= STR_CMP_SUBSTR;
 
-  if ( gtk_toggle_button_get_active
+  if (gtk_toggle_button_get_active
        (GTK_TOGGLE_BUTTON (fd->match_regexp_checkbox)))
     flags |= STR_CMP_REGEXP;
 
-  if ( gtk_toggle_button_get_active
+  if (gtk_toggle_button_get_active
        (GTK_TOGGLE_BUTTON (fd->value_labels_checkbox)))
     flags |= STR_CMP_LABELS;
 
   {
-    union value *val = value_create (width);
+    union value val;
     casenumber i;
     const struct casenum_iterator *ip = get_iteration_params (fd);
     struct comparator *cmptr =
       comparator_factory (var, target_string, flags);
 
-    if ( ! cmptr)
+    value_init (&val, width);
+    if (! cmptr)
       goto finish;
 
     for (i = ip->start (current_row, fd->data);
         i != ip->end (current_row, fd->data);
         ip->next (&i, fd->data))
       {
-       datasheet_get_value (fd->data, i, var_get_case_index (var),
-                            val, width);
+       datasheet_get_value (fd->data, i, var_get_case_index (var), &val);
 
-       if ( comparator_compare (cmptr, val))
+       if (comparator_compare (cmptr, &val))
          {
            *row = i;
            break;
@@ -764,6 +768,6 @@ find_value (const struct find_dialog *fd, casenumber current_row,
 
   finish:
     comparator_destroy (cmptr);
-    free (val);
+    value_destroy (&val, width);
   }
 }