[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Pspp-cvs] pspp src/data/ChangeLog src/data/dictionary.c s...
From: |
Ben Pfaff |
Subject: |
[Pspp-cvs] pspp src/data/ChangeLog src/data/dictionary.c s... |
Date: |
Sat, 02 Feb 2008 06:58:14 +0000 |
CVSROOT: /cvsroot/pspp
Module name: pspp
Changes by: Ben Pfaff <blp> 08/02/02 06:58:14
Modified files:
src/data : ChangeLog dictionary.c dictionary.h
gnumeric-reader.c short-names.c
src/libpspp : ChangeLog str.c str.h
tests : ChangeLog automake.mk
tests/command : get-data-gnm.sh
Added files:
tests/libpspp : str-test.c
Log message:
Patch #6386. Thanks to John Darrington for review and for the
updates to gnumeric-reader.c.
* dictionary.c (make_hinted_name): New function.
(make_numeric_name): New function.
(dict_make_unique_var_name): New function.
* gnumeric-reader.c (devise_name): Removed.
(munge_name): Removed.
(gnumeric_open_reader): Use new function
dict_make_unique_var_name.
* short-names.c (set_var_short_name_suffix): Use new function
str_format_26adic.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/ChangeLog?cvsroot=pspp&r1=1.178&r2=1.179
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/dictionary.c?cvsroot=pspp&r1=1.51&r2=1.52
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/dictionary.h?cvsroot=pspp&r1=1.22&r2=1.23
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/gnumeric-reader.c?cvsroot=pspp&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/short-names.c?cvsroot=pspp&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/ChangeLog?cvsroot=pspp&r1=1.86&r2=1.87
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/str.c?cvsroot=pspp&r1=1.25&r2=1.26
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/str.h?cvsroot=pspp&r1=1.23&r2=1.24
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/ChangeLog?cvsroot=pspp&r1=1.120&r2=1.121
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/automake.mk?cvsroot=pspp&r1=1.49&r2=1.50
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/command/get-data-gnm.sh?cvsroot=pspp&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/libpspp/str-test.c?cvsroot=pspp&rev=1.1
Patches:
Index: src/data/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/ChangeLog,v
retrieving revision 1.178
retrieving revision 1.179
diff -u -b -r1.178 -r1.179
--- src/data/ChangeLog 19 Jan 2008 06:58:04 -0000 1.178
+++ src/data/ChangeLog 2 Feb 2008 06:58:12 -0000 1.179
@@ -1,3 +1,20 @@
+2008-02-01 Ben Pfaff <address@hidden>
+
+ Patch #6386. Thanks to John Darrington for review and for the
+ updates to gnumeric-reader.c.
+
+ * dictionary.c (make_hinted_name): New function.
+ (make_numeric_name): New function.
+ (dict_make_unique_var_name): New function.
+
+ * gnumeric-reader.c (devise_name): Removed.
+ (munge_name): Removed.
+ (gnumeric_open_reader): Use new function
+ dict_make_unique_var_name.
+
+ * short-names.c (set_var_short_name_suffix): Use new function
+ str_format_26adic.
+
2008-01-19 John Darrington <address@hidden>
* settings.c settings.h: Moved static variables into a
Index: src/data/dictionary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/dictionary.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -b -r1.51 -r1.52
--- src/data/dictionary.c 19 Jan 2008 06:58:04 -0000 1.51
+++ src/data/dictionary.c 2 Feb 2008 06:58:12 -0000 1.52
@@ -23,12 +23,14 @@
#include "case.h"
#include "category.h"
+#include "identifier.h"
#include "settings.h"
#include "value-labels.h"
#include "vardict.h"
#include "variable.h"
#include "vector.h"
#include <libpspp/array.h>
+#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
#include <libpspp/hash.h>
#include <libpspp/message.h>
@@ -36,6 +38,7 @@
#include <libpspp/pool.h>
#include <libpspp/str.h>
+#include "intprops.h"
#include "minmax.h"
#include "xalloc.h"
@@ -726,6 +729,111 @@
return true;
}
+static bool
+make_hinted_name (const struct dictionary *dict, const char *hint,
+ char name[VAR_NAME_LEN + 1])
+{
+ bool dropped = false;
+ char *cp;
+
+ for (cp = name; *hint && cp < name + VAR_NAME_LEN; hint++)
+ {
+ if (cp == name
+ ? lex_is_id1 (*hint) && *hint != '$'
+ : lex_is_idn (*hint))
+ {
+ if (dropped)
+ {
+ *cp++ = '_';
+ dropped = false;
+ }
+ if (cp < name + VAR_NAME_LEN)
+ *cp++ = *hint;
+ }
+ else if (cp > name)
+ dropped = true;
+ }
+ *cp = '\0';
+
+ if (name[0] != '\0')
+ {
+ size_t len = strlen (name);
+ unsigned long int i;
+
+ if (dict_lookup_var (dict, name) == NULL)
+ return true;
+
+ for (i = 0; i < ULONG_MAX; i++)
+ {
+ char suffix[INT_BUFSIZE_BOUND (i) + 1];
+ int ofs;
+
+ suffix[0] = '_';
+ if (!str_format_26adic (i + 1, &suffix[1], sizeof suffix - 1))
+ NOT_REACHED ();
+
+ ofs = MIN (VAR_NAME_LEN - strlen (suffix), len);
+ strcpy (&name[ofs], suffix);
+
+ if (dict_lookup_var (dict, name) == NULL)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+make_numeric_name (const struct dictionary *dict, unsigned long int *num_start,
+ char name[VAR_NAME_LEN + 1])
+{
+ unsigned long int number;
+
+ for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
+ number < ULONG_MAX;
+ number++)
+ {
+ sprintf (name, "VAR%03lu", number);
+ if (dict_lookup_var (dict, name) == NULL)
+ {
+ if (num_start != NULL)
+ *num_start = number + 1;
+ return true;
+ }
+ }
+
+ if (num_start != NULL)
+ *num_start = ULONG_MAX;
+ return false;
+}
+
+
+/* Attempts to devise a variable name unique within DICT.
+ Returns true if successful, in which case the new variable
+ name is stored into NAME. Returns false if all names that can
+ be generated have already been taken. (Returning false is
+ quite unlikely: at least ULONG_MAX unique names can be
+ generated.)
+
+ HINT, if it is non-null, is used as a suggestion that will be
+ modified for suitability as a variable name and for
+ uniqueness.
+
+ If HINT is null or entirely unsuitable, a name in the form
+ "VAR%03d" will be generated, where the smallest unused integer
+ value is used. If NUM_START is non-null, then its value is
+ used as the minimum numeric value to check, and it is updated
+ to the next value to be checked.
+ */
+bool
+dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
+ unsigned long int *num_start,
+ char name[VAR_NAME_LEN + 1])
+{
+ return ((hint != NULL && make_hinted_name (dict, hint, name))
+ || make_numeric_name (dict, num_start, name));
+}
+
/* Returns the weighting variable in dictionary D, or a null
pointer if the dictionary is unweighted. */
struct variable *
Index: src/data/dictionary.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/dictionary.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -b -r1.22 -r1.23
--- src/data/dictionary.h 11 Nov 2007 05:51:41 -0000 1.22
+++ src/data/dictionary.h 2 Feb 2008 06:58:13 -0000 1.23
@@ -75,11 +75,14 @@
void dict_reorder_vars (struct dictionary *,
struct variable *const *, size_t count);
-/* Changing variable names. */
+/* Variable names. */
void dict_rename_var (struct dictionary *, struct variable *, const char *);
bool dict_rename_vars (struct dictionary *,
struct variable **, char **new_names,
size_t count, char **err_name);
+bool dict_make_unique_var_name (const struct dictionary *, const char *hint,
+ unsigned long int *num_start,
+ char name[]);
/* Weight variable. */
double dict_get_case_weight (const struct dictionary *,
Index: src/data/gnumeric-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/gnumeric-reader.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- src/data/gnumeric-reader.c 21 Dec 2007 23:49:36 -0000 1.5
+++ src/data/gnumeric-reader.c 2 Feb 2008 06:58:13 -0000 1.6
@@ -308,66 +308,6 @@
}
-
-/*
- Change SUGGESTION until it's a valid name that can be added to DICT.
-*/
-static void
-devise_name (const struct dictionary *dict, struct string *name, int *x)
-{
- struct string basename;
- if ( ds_is_empty (name))
- ds_init_cstr (&basename, "var");
- else
- ds_init_string (&basename, name);
- do
- {
- ds_clear (name);
- ds_put_format (name, "%s%d", ds_cstr (&basename), ++(*x));
- }
- while (NULL != dict_lookup_var (dict, ds_cstr (name)) );
-
- ds_destroy (&basename);
-}
-
-/*
- Mutate NAME of a variable, which is gauranteed to be valid for the
- dictionary DICT.
-*/
-static void
-munge_name (const struct dictionary *dict, struct string *name)
-{
- int x = 0;
-
- if (! ds_is_empty (name))
- {
- /* Change all the invalid characters to valid ones */
- char *s;
-
- s = ds_data (name);
-
- if ( !lex_is_id1 (*s))
- *s = '@';
-
- s++;
-
- while (s < ds_data (name) + ds_length (name))
- {
- if ( !lex_is_idn (*s))
- *s = '_';
- s++;
- }
-
- assert (var_is_valid_name (ds_cstr (name), false));
- }
-
- while (ds_is_empty (name) || NULL != dict_lookup_var (dict, ds_cstr (name)) )
- {
- devise_name (dict, name, &x);
- }
-}
-
-
/*
Sets the VAR of case C, to the value corresponding to the xml string XV
*/
@@ -410,6 +350,7 @@
struct casereader *
gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
{
+ unsigned long int vstart = 0;
int ret;
casenumber n_cases = CASENUMBER_MAX;
int i;
@@ -567,25 +508,23 @@
for (i = 0 ; i < n_var_specs ; ++i )
{
- struct string name;
+ char name[VAR_NAME_LEN + 1];
- /* Probably no data exists for this variable, so allocate a default
width */
+ /* Probably no data exists for this variable, so allocate a
+ default width */
if ( var_spec[i].width == -1 )
var_spec[i].width = MAX_SHORT_STRING;
r->value_cnt += value_cnt_from_width (var_spec[i].width);
- if (var_spec[i].name)
- ds_init_cstr (&name, var_spec[i].name);
- else
- ds_init_empty (&name);
-
- munge_name (r->dict, &name);
-
-
- dict_create_var (r->dict, ds_cstr (&name), var_spec[i].width);
+ if ( ! dict_make_unique_var_name (r->dict, var_spec[i].name,
+ &vstart, name))
+ {
+ msg (ME, _("Cannot create variable name from %s"), var_spec[i].name);
+ goto error;
+ }
- ds_destroy (&name);
+ dict_create_var (r->dict, name, var_spec[i].width);
}
/* Create the first case, and cache it */
Index: src/data/short-names.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/short-names.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- src/data/short-names.c 24 Nov 2007 22:14:43 -0000 1.2
+++ src/data/short-names.c 2 Feb 2008 06:58:13 -0000 1.3
@@ -53,7 +53,6 @@
{
char suffix[SHORT_NAME_LEN + 1];
char short_name[SHORT_NAME_LEN + 1];
- char *start, *end;
int len, ofs;
assert (suffix_number >= 0);
@@ -62,26 +61,18 @@
var_set_short_name (v, i, base);
/* Compose suffix. */
- start = end = suffix + sizeof suffix - 1;
- *end = '\0';
- do
- {
- *--start = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[suffix_number % 26];
- if (start <= suffix + 1)
+ suffix[0] = '_';
+ if (!str_format_26adic (suffix_number, &suffix[1], sizeof suffix - 1))
msg (SE, _("Variable suffix too large."));
- suffix_number /= 26;
- }
- while (suffix_number > 0);
- *--start = '_';
+ len = strlen (suffix);
/* Append suffix to V's short name. */
str_copy_trunc (short_name, sizeof short_name, base);
- len = end - start;
- if (len + strlen (short_name) > SHORT_NAME_LEN)
+ if (strlen (short_name) + len > SHORT_NAME_LEN)
ofs = SHORT_NAME_LEN - len;
else
ofs = strlen (short_name);
- strcpy (short_name + ofs, start);
+ strcpy (short_name + ofs, suffix);
/* Set name. */
var_set_short_name (v, i, short_name);
@@ -111,7 +102,7 @@
if (trial == 0)
var_set_short_name (v, i, var_get_name (v));
else
- set_var_short_name_suffix (v, i, var_get_name (v), trial - 1);
+ set_var_short_name_suffix (v, i, var_get_name (v), trial);
if (hsh_insert (short_names, (char *) var_get_short_name (v, i)) == NULL)
break;
Index: src/libpspp/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/ChangeLog,v
retrieving revision 1.86
retrieving revision 1.87
diff -u -b -r1.86 -r1.87
--- src/libpspp/ChangeLog 24 Dec 2007 03:54:38 -0000 1.86
+++ src/libpspp/ChangeLog 2 Feb 2008 06:58:13 -0000 1.87
@@ -1,3 +1,9 @@
+2008-02-01 Ben Pfaff <address@hidden>
+
+ Patch #6386. Thanks to John Darrington for review.
+
+ * str.c (str_format_26adic): New function.
+
2007-12-24 John Darrington <address@hidden>
* taint.c (taint_destroy): Return true if pointer is null.
Index: src/libpspp/str.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/str.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- src/libpspp/str.c 9 Nov 2007 03:06:29 -0000 1.25
+++ src/libpspp/str.c 2 Feb 2008 06:58:13 -0000 1.26
@@ -252,6 +252,41 @@
*s = tolower ((unsigned char) *s);
}
+/* Converts NUMBER into a string in 26-adic notation in BUFFER,
+ which has room for SIZE bytes. Returns true if successful,
+ false if NUMBER, plus a trailing null, is too large to fit in
+ the available space.
+
+ 26-adic notation is "spreadsheet column numbering": 1 = A, 2 =
+ B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ...
+
+ 26-adic notation is the special case of a k-adic numeration
+ system (aka bijective base-k numeration) with k=26. In k-adic
+ numeration, the digits are {1, 2, 3, ..., k} (there is no
+ digit 0), and integer 0 is represented by the empty string.
+ For more information, see
+ http://en.wikipedia.org/wiki/Bijective_numeration. */
+bool
+str_format_26adic (unsigned long int number, char buffer[], size_t size)
+{
+ size_t length = 0;
+
+ while (number-- > 0)
+ {
+ if (length >= size)
+ return false;
+ buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26];
+ number /= 26;
+ }
+
+ if (length >= size)
+ return false;
+ buffer[length] = '\0';
+
+ buf_reverse (buffer, length);
+ return true;
+}
+
/* Formats FORMAT into DST, as with sprintf(), and returns the
address of the terminating null written to DST. */
char *
Index: src/libpspp/str.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/str.h,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -b -r1.23 -r1.24
--- src/libpspp/str.h 9 Nov 2007 03:06:29 -0000 1.23
+++ src/libpspp/str.h 2 Feb 2008 06:58:13 -0000 1.24
@@ -46,6 +46,8 @@
void str_uppercase (char *);
void str_lowercase (char *);
+bool str_format_26adic (unsigned long int number, char buffer[], size_t);
+
char *spprintf (char *dst, const char *format, ...);
void *mempset (void *, int, size_t);
Index: tests/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/ChangeLog,v
retrieving revision 1.120
retrieving revision 1.121
diff -u -b -r1.120 -r1.121
--- tests/ChangeLog 5 Dec 2007 06:40:13 -0000 1.120
+++ tests/ChangeLog 2 Feb 2008 06:58:13 -0000 1.121
@@ -1,3 +1,12 @@
+2008-02-01 Ben Pfaff <address@hidden>
+
+ * automake.mk: Add new test.
+
+ * libpspp/str-test.c: New test.
+
+ * command/get-dat-gnm.sh: Update variable names to match new
+ naming scheme.
+
2007-12-04 Ben Pfaff <address@hidden>
* automake.mk: Add new tests.
Index: tests/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/automake.mk,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -b -r1.49 -r1.50
--- tests/automake.mk 21 Dec 2007 09:12:45 -0000 1.49
+++ tests/automake.mk 2 Feb 2008 06:58:13 -0000 1.50
@@ -163,6 +163,7 @@
tests/libpspp/range-map-test \
tests/libpspp/range-set-test \
tests/libpspp/sparse-array-test \
+ tests/libpspp/str-test \
tests/libpspp/tower-test
TESTS = $(dist_TESTS) $(nodist_TESTS)
@@ -228,6 +229,10 @@
tests_libpspp_range_set_test_LDADD = gl/libgl.la @LIBINTL@
tests_libpspp_range_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
+tests_libpspp_str_test_SOURCES = \
+ tests/libpspp/str-test.c
+tests_libpspp_str_test_LDADD = src/libpspp/libpspp.a gl/libgl.la @LIBINTL@
+
tests_libpspp_tower_test_SOURCES = \
src/libpspp/abt.c \
src/libpspp/abt.h \
Index: tests/command/get-data-gnm.sh
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/command/get-data-gnm.sh,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- tests/command/get-data-gnm.sh 3 Nov 2007 03:43:12 -0000 1.1
+++ tests/command/get-data-gnm.sh 2 Feb 2008 06:58:13 -0000 1.2
@@ -96,23 +96,23 @@
+--------+-------------------------------------------+--------+
|Variable|Description |Position|
#========#===========================================#========#
-|var1 |Format: F8.2 | 1|
+|VAR001 |Format: F8.2 | 1|
| |Measure: Scale | |
| |Display Alignment: Right | |
| |Display Width: 8 | |
+--------+-------------------------------------------+--------+
-|var2 |Format: A8 | 2|
+|VAR002 |Format: A8 | 2|
| |Measure: Nominal | |
| |Display Alignment: Left | |
| |Display Width: 8 | |
+--------+-------------------------------------------+--------+
-|var3 |Format: F8.2 | 3|
+|VAR003 |Format: F8.2 | 3|
| |Measure: Scale | |
| |Display Alignment: Right | |
| |Display Width: 8 | |
+--------+-------------------------------------------+--------+
- var1 var2 var3
+ VAR001 VAR002 VAR003
-------- -------- --------
.00 fred 20.00
1.00 11 21.00
@@ -134,13 +134,13 @@
| |Display Alignment: Left | |
| |Display Width: 8 | |
+--------+-------------------------------------------+--------+
-|var1 |Format: F8.2 | 3|
+|VAR001 |Format: F8.2 | 3|
| |Measure: Scale | |
| |Display Alignment: Right | |
| |Display Width: 8 | |
+--------+-------------------------------------------+--------+
- V1 V2 var1
+ V1 V2 VAR001
-------- -------- --------
.00 fred 20.00
1.00 11 21.00
Index: tests/libpspp/str-test.c
===================================================================
RCS file: tests/libpspp/str-test.c
diff -N tests/libpspp/str-test.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/libpspp/str-test.c 2 Feb 2008 06:58:13 -0000 1.1
@@ -0,0 +1,83 @@
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <libpspp/str.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Currently running test. */
+static const char *test_name;
+
+/* Exit with a failure code.
+ (Place a breakpoint on this function while debugging.) */
+static void
+check_die (void)
+{
+ exit (EXIT_FAILURE);
+}
+
+static void
+check_26adic (unsigned long int number, const char *expected_string)
+{
+ char string[8];
+ str_format_26adic (number, string, sizeof string);
+ if (strcmp (string, expected_string))
+ {
+ printf ("base-26 of %lu: expected \"%s\", got \"%s\"\n",
+ number, expected_string, string);
+ check_die ();
+ }
+}
+
+static void
+test_str_format_26adic (void)
+{
+ check_26adic (0, "");
+ check_26adic (1, "A");
+ check_26adic (2, "B");
+ check_26adic (26, "Z");
+ check_26adic (27, "AA");
+ check_26adic (28, "AB");
+ check_26adic (29, "AC");
+ check_26adic (18278, "ZZZ");
+ check_26adic (18279, "AAAA");
+ check_26adic (19010, "ABCD");
+}
+
+/* Main program. */
+
+/* Runs TEST_FUNCTION and prints a message about NAME. */
+static void
+run_test (void (*test_function) (void), const char *name)
+{
+ test_name = name;
+ putchar ('.');
+ fflush (stdout);
+ test_function ();
+}
+
+int
+main (void)
+{
+ run_test (test_str_format_26adic, "format 26-adic strings");
+ putchar ('\n');
+
+ return 0;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Pspp-cvs] pspp src/data/ChangeLog src/data/dictionary.c s...,
Ben Pfaff <=