Replace numerous instances of xzalloc with XZALLOC
[pspp] / src / ui / gui / find-dialog.c
index 07b73fe84c93d6cdb9e52f51c60a694f4ba0b0dd..16f5e365761a12ab3b13cec78ea4d91e42da3bce 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  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,12 +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);
 
-  g_object_get (vs, "dictionary", &fd.dict, NULL);
-
   fd.data = ds->datasheet;
 
   fd.variable_entry        = get_widget_assert (fd.xml, "find-variable-entry");
@@ -246,10 +236,6 @@ find_dialog (GObject *o, gpointer data)
        "selection-mode", GTK_SELECTION_SINGLE,
        NULL);
 
-  psppire_selector_set_select_func (PSPPIRE_SELECTOR (selector),
-                                   insert_source_row_into_entry,
-                                   NULL
-                                   );
 
   psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
                                    is_currently_in_entry);
@@ -286,7 +272,7 @@ forward (casenumber *i, struct datasheet *data UNUSED)
 static void
 forward_wrap (casenumber *i, struct datasheet *data)
 {
-  if ( ++*i >=  datasheet_get_n_rows (data) ) *i = 0;
+  if (++*i >=  datasheet_get_n_rows (data)) *i = 0;
 }
 
 static void
@@ -299,7 +285,7 @@ backward (casenumber *i, struct datasheet *data UNUSED)
 static void
 backward_wrap (casenumber *i, struct datasheet *data)
 {
-  if ( --*i < 0 )
+  if (--*i < 0)
     *i = datasheet_get_n_rows (data) - 1;
 }
 
@@ -327,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;
 }
 
@@ -375,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}
   };
 
@@ -395,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];
     }
 }
 
@@ -428,7 +424,6 @@ struct comparator
 {
   const struct variable *var;
   enum string_cmp_flags flags;
-  const PsppireDict *dict;
 
   bool (*compare) (const struct comparator *,
                   const union value *);
@@ -437,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 */
@@ -458,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;
 }
 
 
@@ -476,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;
 
-  assert ( cmptr->flags & STR_CMP_LABELS);
+  width = strlen (text);
+
+  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));
@@ -501,11 +519,11 @@ string_value_compare (const struct comparator *cmptr,
 
   int width = var_get_width (cmptr->var);
   g_return_val_if_fail (width > 0, false);
-  assert ( ! (cmptr->flags & STR_CMP_LABELS));
+  assert (! (cmptr->flags & STR_CMP_LABELS));
 
-  text = value_to_text (*val, cmptr->dict, *var_get_write_format (cmptr->var));
+  text = value_to_text (*val, cmptr->var);
 
-  if ( cmptr->flags & STR_CMP_SUBSTR)
+  if (cmptr->flags & STR_CMP_SUBSTR)
     found =  (NULL != g_strstr_len (text, width, ssc->pattern));
   else
     found = (0 == strncmp (text, ssc->pattern, width));
@@ -528,11 +546,11 @@ 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->dict, *var_get_write_format (cmptr->var));
+  text = value_to_text (*val, cmptr->var);
   /* We must remove trailing whitespace, otherwise $ will not match where
      one would expect */
   g_strchomp (text);
@@ -555,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);
@@ -570,49 +588,42 @@ 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
-cmptr_value_destroy (struct comparator *cmptr)
-{
-  struct value_comparator *vc = (struct value_comparator *) cmptr;
-  value_destroy (&vc->pattern, var_get_width (cmptr->var));
-}
-
-
 static struct comparator *
-value_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target)
+numeric_comparator_create (const struct variable *var, const char *target)
 {
-  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 = cmptr_value_destroy;
-  cmptr->dict = dict;
+  cmptr->compare  = value_compare;
+  const struct fmt_spec *fs = var_get_write_format (var);
 
-  text_to_value (target, dict, var, &vc->pattern);
+  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;
 }
 
 static struct comparator *
-string_comparator_create (const struct variable *var, const PsppireDict *dict, 
-                         const char *target,
+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;
-  cmptr->dict = dict;
 
-  if ( flags & STR_CMP_LABELS)
+  if (flags & STR_CMP_LABELS)
     cmptr->compare = string_label_compare;
   else
     cmptr->compare = string_value_compare;
@@ -624,23 +635,22 @@ string_comparator_create (const struct variable *var, const PsppireDict *dict,
 
 
 static struct comparator *
-regexp_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target,
+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;
-  cmptr->dict = dict;
   cmptr->compare  = (flags & STR_CMP_LABELS)
     ? regexp_label_compare : regexp_value_compare ;
 
   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);
@@ -651,7 +661,7 @@ regexp_comparator_create (const struct variable *var, const PsppireDict *dict, c
 
       msg (ME, _("Bad regular expression: %s"), errbuf);
 
-      free ( cmptr);
+      free (cmptr);
       free (errbuf);
       return NULL;
     }
@@ -672,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);
@@ -683,16 +693,16 @@ comparator_destroy (struct comparator *cmptr)
 
 
 static struct comparator *
-comparator_factory (const struct variable *var, const PsppireDict *dict, const char *str,
+comparator_factory (const struct variable *var, const char *str,
                    enum string_cmp_flags flags)
 {
-  if ( flags & STR_CMP_REGEXP )
-    return regexp_comparator_create (var, dict, str, flags);
+  if (flags & STR_CMP_REGEXP)
+    return regexp_comparator_create (var, str, flags);
 
-  if ( flags & (STR_CMP_SUBSTR | STR_CMP_LABELS) )
-    return string_comparator_create (var, dict, str, flags);
+  if (flags & (STR_CMP_SUBSTR | STR_CMP_LABELS))
+    return string_comparator_create (var, str, flags);
 
-  return value_comparator_create (var, dict, str);
+  return numeric_comparator_create (var, str);
 }
 
 
@@ -710,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);
@@ -721,15 +730,15 @@ 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;
 
@@ -738,10 +747,10 @@ find_value (const struct find_dialog *fd, casenumber current_row,
     casenumber i;
     const struct casenum_iterator *ip = get_iteration_params (fd);
     struct comparator *cmptr =
-      comparator_factory (var, fd->dict, target_string, flags);
+      comparator_factory (var, target_string, flags);
 
     value_init (&val, width);
-    if ( ! cmptr)
+    if (! cmptr)
       goto finish;
 
     for (i = ip->start (current_row, fd->data);
@@ -750,7 +759,7 @@ find_value (const struct find_dialog *fd, casenumber current_row,
       {
        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;