Separate settings and the SET command, for modularity.
[pspp-builds.git] / src / sort.c
index a16055f971725953ade58241b1f8f8ea67e30bb9..8dad3566ccdcca1ad8e9fabf63ace81b42d7019f 100644 (file)
@@ -26,7 +26,7 @@
 #include <errno.h>
 #include "algorithm.h"
 #include "alloc.h"
-#include "bool.h"
+#include <stdbool.h>
 #include "case.h"
 #include "casefile.h"
 #include "command.h"
 #include "lexer.h"
 #include "misc.h"
 #include "settings.h"
+#include "sort-prs.h"
 #include "str.h"
 #include "var.h"
 #include "vfm.h"
 #include "vfmP.h"
 
-#include "debug-print.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
-/* Sort direction. */
-enum sort_direction
-  {
-    SRT_ASCEND,                        /* A, B, C, ..., X, Y, Z. */
-    SRT_DESCEND                        /* Z, Y, X, ..., C, B, A. */
-  };
-
-/* A sort criterion. */
-struct sort_criterion
-  {
-    int fv;                     /* Variable data index. */
-    int width;                  /* 0=numeric, otherwise string widthe. */
-    enum sort_direction dir;    /* Sort direction. */
-  };
-
-/* A set of sort criteria. */
-struct sort_criteria 
-  {
-    struct sort_criterion *crits;
-    size_t crit_cnt;
-  };
+#include "debug-print.h"
 
 /* These should only be changed for testing purposes. */
 static int min_buffers = 64;
@@ -86,11 +68,11 @@ cmd_sort_cases (void)
 
   lex_match (T_BY);
 
-  criteria = sort_parse_criteria (default_dict, NULL, NULL, NULL);
+  criteria = sort_parse_criteria (default_dict, NULL, NULL, NULL, NULL);
   if (criteria == NULL)
     return CMD_FAILURE;
 
-  if (test_mode && lex_match ('/')) 
+  if (get_testing_mode () && lex_match ('/')) 
     {
       if (!lex_force_match_id ("BUFFERS") || !lex_match ('=')
           || !lex_force_int ())
@@ -169,101 +151,6 @@ sort_active_file_to_casefile (const struct sort_criteria *criteria)
   return sort_execute (casefile_get_reader (src), criteria);
 }
 
-/* Parses a list of sort keys and returns a struct sort_criteria
-   based on it.  Returns a null pointer on error.
-   If SAW_DIRECTION is nonnull, sets *SAW_DIRECTION to true if at
-   least one parenthesized sort direction was specified, false
-   otherwise. */
-struct sort_criteria *
-sort_parse_criteria (const struct dictionary *dict,
-                     struct variable ***vars, int *var_cnt,
-                     bool *saw_direction)
-{
-  struct sort_criteria *criteria;
-  struct variable **local_vars = NULL;
-  size_t local_var_cnt;
-
-  assert ((vars == NULL) == (var_cnt == NULL));
-  if (vars == NULL) 
-    {
-      vars = &local_vars;
-      var_cnt = &local_var_cnt;
-    }
-
-  criteria = xmalloc (sizeof *criteria);
-  criteria->crits = NULL;
-  criteria->crit_cnt = 0;
-
-  *vars = NULL;
-  *var_cnt = 0;
-  if (saw_direction != NULL)
-    *saw_direction = false;
-
-  do
-    {
-      int prev_var_cnt = *var_cnt;
-      enum sort_direction direction;
-
-      /* Variables. */
-      if (!parse_variables (dict, vars, var_cnt,
-                           PV_NO_DUPLICATE | PV_APPEND | PV_NO_SCRATCH))
-        goto error;
-
-      /* Sort direction. */
-      if (lex_match ('('))
-       {
-         if (lex_match_id ("D") || lex_match_id ("DOWN"))
-           direction = SRT_DESCEND;
-         else if (lex_match_id ("A") || lex_match_id ("UP"))
-            direction = SRT_ASCEND;
-          else
-           {
-             msg (SE, _("`A' or `D' expected inside parentheses."));
-              goto error;
-           }
-         if (!lex_match (')'))
-           {
-             msg (SE, _("`)' expected."));
-              goto error;
-           }
-          if (saw_direction != NULL)
-            *saw_direction = true;
-       }
-      else
-        direction = SRT_ASCEND;
-
-      criteria->crits = xrealloc (criteria->crits,
-                                  sizeof *criteria->crits * *var_cnt);
-      criteria->crit_cnt = *var_cnt;
-      for (; prev_var_cnt < criteria->crit_cnt; prev_var_cnt++) 
-        {
-          struct sort_criterion *c = &criteria->crits[prev_var_cnt];
-          c->fv = (*vars)[prev_var_cnt]->fv;
-          c->width = (*vars)[prev_var_cnt]->width;
-          c->dir = direction;
-        }
-    }
-  while (token != '.' && token != '/');
-
-  free (local_vars);
-  return criteria;
-
- error:
-  free (local_vars);
-  sort_destroy_criteria (criteria);
-  return NULL;
-}
-
-/* Destroys a SORT CASES program. */
-void
-sort_destroy_criteria (struct sort_criteria *criteria) 
-{
-  if (criteria != NULL) 
-    {
-      free (criteria->crits);
-      free (criteria);
-    }
-}
 
 /* Reads all the cases from READER, which is destroyed.  Sorts
    the cases according to CRITERIA.  Returns the sorted cases in
@@ -308,7 +195,7 @@ do_internal_sort (struct casereader *reader,
   dst = casefile_create (casefile_get_value_cnt (src));
   if (case_cnt != 0) 
     {
-      struct indexed_case *cases = malloc (sizeof *cases * case_cnt);
+      struct indexed_case *cases = nmalloc (sizeof *cases, case_cnt);
       if (cases != NULL) 
         {
           unsigned long i;
@@ -391,7 +278,7 @@ do_external_sort (struct casereader *reader,
   xsrt->value_cnt = casefile_get_value_cnt (casereader_get_casefile (reader));
   xsrt->run_cap = 512;
   xsrt->run_cnt = 0;
-  xsrt->runs = xmalloc (sizeof *xsrt->runs * xsrt->run_cap);
+  xsrt->runs = xnmalloc (xsrt->run_cap, sizeof *xsrt->runs);
   if (write_runs (xsrt, reader))
     {
       struct casefile *output = merge (xsrt);
@@ -556,16 +443,17 @@ allocate_cases (struct initial_run_state *irs)
   approx_case_cost = (sizeof *irs->records
                       + irs->xsrt->value_cnt * sizeof (union value)
                       + 4 * sizeof (void *));
-  max_cases = get_max_workspace() / approx_case_cost;
+  max_cases = get_workspace() / approx_case_cost;
   if (max_cases > max_buffers)
     max_cases = max_buffers;
-  irs->records = malloc (sizeof *irs->records * max_cases);
-  for (i = 0; i < max_cases; i++)
-    if (!case_try_create (&irs->records[i].record, irs->xsrt->value_cnt))
-      {
-        max_cases = i;
-        break;
-      }
+  irs->records = nmalloc (sizeof *irs->records, max_cases);
+  if (irs->records != NULL)
+    for (i = 0; i < max_cases; i++)
+      if (!case_try_create (&irs->records[i].record, irs->xsrt->value_cnt))
+        {
+          max_cases = i;
+          break;
+        }
   irs->record_cap = max_cases;
 
   /* Fail if we didn't allocate an acceptable number of cases. */
@@ -574,7 +462,7 @@ allocate_cases (struct initial_run_state *irs)
       msg (SE, _("Out of memory.  Could not allocate room for minimum of %d "
                 "cases of %d bytes each.  (PSPP workspace is currently "
                 "restricted to a maximum of %d KB.)"),
-          min_buffers, approx_case_cost, get_max_workspace() / 1024);
+          min_buffers, approx_case_cost, get_workspace() / 1024);
       return 0;
     }
   return 1;
@@ -661,8 +549,8 @@ end_run (struct initial_run_state *irs)
       if (xsrt->run_cnt >= xsrt->run_cap) 
         {
           xsrt->run_cap *= 2;
-          xsrt->runs = xrealloc (xsrt->runs,
-                                 sizeof *xsrt->runs * xsrt->run_cap);
+          xsrt->runs = xnrealloc (xsrt->runs,
+                                  xsrt->run_cap, sizeof *xsrt->runs);
         }
       xsrt->runs[xsrt->run_cnt++] = irs->casefile;
       irs->casefile = NULL; 
@@ -787,7 +675,7 @@ merge_once (struct external_sort *xsrt,
   int i;
 
   /* Open input files. */
-  runs = xmalloc (sizeof *runs * run_cnt);
+  runs = xnmalloc (run_cnt, sizeof *runs);
   for (i = 0; i < run_cnt; i++) 
     {
       struct run *r = &runs[i];