02110-1301, USA. */
#include <config.h>
+
#include "repeat.h"
-#include "message.h"
+
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
-#include "alloc.h"
-#include "command.h"
-#include "dictionary.h"
-#include "message.h"
-#include "line-buffer.h"
-#include "lexer.h"
-#include "misc.h"
-#include "pool.h"
-#include "settings.h"
-#include "str.h"
-#include "variable.h"
+
+#include <data/dictionary.h>
+#include <data/procedure.h>
+#include <data/settings.h>
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <language/line-buffer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
+#include <libpspp/misc.h>
+#include <libpspp/pool.h>
+#include <libpspp/str.h>
+#include <data/variable.h>
+
+#include "intprops.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
-#include "debug-print.h"
-
/* Defines a list of lines used by DO REPEAT. */
struct line_list
{
static bool parse_lines (struct repeat_block *);
static void create_vars (struct repeat_block *);
-static int parse_ids (struct repeat_entry *);
-static int parse_numbers (struct repeat_entry *);
-static int parse_strings (struct repeat_entry *);
+static int parse_ids (struct repeat_entry *, struct pool *);
+static int parse_numbers (struct repeat_entry *, struct pool *);
+static int parse_strings (struct repeat_entry *, struct pool *);
static void do_repeat_filter (struct string *line, void *block);
static bool do_repeat_read (struct string *line, char **file_name,
/* Get the details of the variable's possible values. */
if (token == T_ID)
- count = parse_ids (e);
+ count = parse_ids (e, block->pool);
else if (lex_is_number ())
- count = parse_numbers (e);
+ count = parse_numbers (e, block->pool);
else if (token == T_STRING)
- count = parse_strings (e);
+ count = parse_strings (e, block->pool);
else
{
lex_error (NULL);
}
if (count == 0)
return false;
+ if (token != '/' && token != '.')
+ {
+ lex_error (NULL);
+ return false;
+ }
/* If this is the first variable then it defines how many
replacements there must be; otherwise enforce this number of
|| !strcmp (cur_file_name, previous_file_name))
previous_file_name = pool_strdup (block->pool, cur_file_name);
- ds_rtrim_spaces (&getl_buf);
+ ds_rtrim (&getl_buf, ss_cstr (CC_SPACES));
dot = ds_chomp (&getl_buf, get_endcmd ());
- if (recognize_do_repeat (ds_c_str (&getl_buf)))
+ if (recognize_do_repeat (ds_cstr (&getl_buf)))
nesting_level++;
- else if (recognize_end_repeat (ds_c_str (&getl_buf), &block->print))
+ else if (recognize_end_repeat (ds_cstr (&getl_buf), &block->print))
{
if (nesting_level-- == 0)
{
}
}
if (dot)
- ds_putc (&getl_buf, get_endcmd ());
+ ds_put_char (&getl_buf, get_endcmd ());
line = *last_line = pool_alloc (block->pool, sizeof *line);
line->next = NULL;
line->file_name = previous_file_name;
line->line_number = cur_line_number;
- line->line = pool_strdup (block->pool, ds_c_str (&getl_buf));
+ line->line = pool_strdup (block->pool, ds_cstr (&getl_buf));
last_line = &line->next;
}
/* Parses a set of ids for DO REPEAT. */
static int
-parse_ids (struct repeat_entry *e)
+parse_ids (struct repeat_entry *e, struct pool *pool)
{
- size_t i;
size_t n = 0;
-
e->type = VAR_NAMES;
- e->replacement = NULL;
-
- do
- {
- char **names;
- size_t nnames;
-
- if (!parse_mixed_vars (&names, &nnames, PV_NONE))
- return 0;
-
- e->replacement = xnrealloc (e->replacement,
- nnames + n, sizeof *e->replacement);
- for (i = 0; i < nnames; i++)
- {
- e->replacement[n + i] = xstrdup (names[i]);
- free (names[i]);
- }
- free (names);
- n += nnames;
- }
- while (token != '/' && token != '.');
-
- return n;
+ return parse_mixed_vars_pool (pool, &e->replacement, &n, PV_NONE) ? n : 0;
}
-/* Stores VALUE into *REPL. */
-static inline void
-store_numeric (char **repl, long value)
+/* Adds STRING to E's list of replacements, which has *USED
+ elements and has room for *ALLOCATED. Allocates memory from
+ POOL. */
+static void
+add_replacement (char *string,
+ struct repeat_entry *e, struct pool *pool,
+ size_t *used, size_t *allocated)
{
- *repl = xmalloc (INT_DIGITS + 1);
- sprintf (*repl, "%ld", value);
+ if (*used == *allocated)
+ e->replacement = pool_2nrealloc (pool, e->replacement, allocated,
+ sizeof *e->replacement);
+ e->replacement[(*used)++] = string;
}
/* Parses a list of numbers for DO REPEAT. */
static int
-parse_numbers (struct repeat_entry *e)
+parse_numbers (struct repeat_entry *e, struct pool *pool)
{
- /* First and last numbers for TO, plus the step factor. */
- long a, b;
-
- /* Alias to e->replacement. */
- char **array;
-
- /* Number of entries in array; maximum number for this allocation
- size. */
- int n, m;
-
- n = m = 0;
+ size_t used = 0;
+ size_t allocated = 0;
+
e->type = OTHER;
- e->replacement = array = NULL;
+ e->replacement = NULL;
do
{
+ long a, b, i;
+
/* Parse A TO B into a, b. */
if (!lex_force_int ())
return 0;
if (!lex_force_int ())
return 0;
b = lex_integer ();
-
+ if (b < a)
+ {
+ msg (SE, _("%ld TO %ld is an invalid range."), a, b);
+ return 0;
+ }
lex_get ();
}
- else b = a;
+ else
+ b = a;
- if (n + (abs (b - a) + 1) > m)
- {
- m = n + (abs (b - a) + 1) + 16;
- e->replacement = array = xnrealloc (array,
- m, sizeof *e->replacement);
- }
+ for (i = a; i <= b; i++)
+ add_replacement (pool_asprintf (pool, "%ld", i),
+ e, pool, &used, &allocated);
- if (a == b)
- store_numeric (&array[n++], a);
- else
- {
- long iter;
-
- if (a < b)
- for (iter = a; iter <= b; iter++)
- store_numeric (&array[n++], iter);
- else
- for (iter = a; iter >= b; iter--)
- store_numeric (&array[n++], iter);
- }
lex_match (',');
}
while (token != '/' && token != '.');
- e->replacement = xrealloc (array, n * sizeof *e->replacement);
- return n;
+ return used;
}
/* Parses a list of strings for DO REPEAT. */
int
-parse_strings (struct repeat_entry *e)
+parse_strings (struct repeat_entry *e, struct pool *pool)
{
- char **string;
- int n, m;
-
+ size_t used = 0;
+ size_t allocated = 0;
+
e->type = OTHER;
- string = e->replacement = NULL;
- n = m = 0;
+ e->replacement = NULL;
do
{
+ char *string;
+
if (token != T_STRING)
{
- int i;
msg (SE, _("String expected."));
- for (i = 0; i < n; i++)
- free (string[i]);
- free (string);
return 0;
}
- if (n + 1 > m)
- {
- m += 16;
- e->replacement = string = xnrealloc (string,
- m, sizeof *e->replacement);
- }
- string[n++] = lex_token_representation ();
- lex_get ();
+ string = lex_token_representation ();
+ pool_register (pool, free, string);
+ add_replacement (string, e, pool, &used, &allocated);
+ lex_get ();
lex_match (',');
}
while (token != '/' && token != '.');
- e->replacement = xnrealloc (string, n, sizeof *e->replacement);
- return n;
+ return used;
}
\f
int
struct string output;
bool dot;
- ds_init (&output, ds_capacity (line));
+ ds_init_empty (&output);
/* Strip trailing whitespace, check for & remove terminal dot. */
while (isspace (ds_last (line)))
dot = ds_chomp (line, get_endcmd ());
in_apos = in_quote = false;
- for (cp = ds_c_str (line); cp < ds_end (line); )
+ for (cp = ds_cstr (line); cp < ds_end (line); )
{
if (*cp == '\'' && !in_quote)
in_apos = !in_apos;
in_quote = !in_quote;
if (in_quote || in_apos || !lex_is_id1 (*cp))
- ds_putc (&output, *cp++);
+ ds_put_char (&output, *cp++);
else
{
const char *start = cp;
const char *substitution = find_substitution (block,
start, end - start);
if (substitution != NULL)
- ds_puts (&output, substitution);
+ ds_put_cstr (&output, substitution);
else
- ds_concat (&output, start, end - start);
+ ds_put_substring (&output, ss_buffer (start, end - start));
cp = end;
}
}
if (dot)
- ds_putc (&output, get_endcmd ());
+ ds_put_char (&output, get_endcmd ());
ds_swap (line, &output);
ds_destroy (&output);
}
line = block->cur_line;
- ds_replace (output, line->line);
+ ds_assign_cstr (output, line->line);
*file_name = line->file_name;
*line_number = -line->line_number;
block->cur_line = line->next;