1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <data/short-names.h>
21 #include <data/dictionary.h>
22 #include <data/sys-file-private.h>
23 #include <data/variable.h>
24 #include <libpspp/assertion.h>
25 #include <libpspp/compiler.h>
26 #include <libpspp/hash.h>
27 #include <libpspp/message.h>
28 #include <libpspp/str.h>
31 #define _(msgid) gettext (msgid)
33 /* Compares two strings. */
35 compare_strings (const void *a, const void *b, const void *aux UNUSED)
40 /* Hashes a string. */
42 do_hash_string (const void *s, const void *aux UNUSED)
44 return hash_string (s, 0);
47 /* Sets V's short name to BASE, followed by a suffix of the form
48 _A, _B, _C, ..., _AA, _AB, etc. according to the value of
49 SUFFIX_NUMBER. Truncates BASE as necessary to fit. */
51 set_var_short_name_suffix (struct variable *v, size_t i,
52 const char *base, int suffix_number)
54 char suffix[SHORT_NAME_LEN + 1];
55 char short_name[SHORT_NAME_LEN + 1];
58 assert (suffix_number >= 0);
61 var_set_short_name (v, i, base);
65 if (!str_format_26adic (suffix_number, &suffix[1], sizeof suffix - 1))
66 msg (SE, _("Variable suffix too large."));
67 len = strlen (suffix);
69 /* Append suffix to V's short name. */
70 str_copy_trunc (short_name, sizeof short_name, base);
71 if (strlen (short_name) + len > SHORT_NAME_LEN)
72 ofs = SHORT_NAME_LEN - len;
74 ofs = strlen (short_name);
75 strcpy (short_name + ofs, suffix);
78 var_set_short_name (v, i, short_name);
82 claim_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
84 const char *short_name = var_get_short_name (v, i);
85 if (short_name != NULL
86 && hsh_insert (short_names, (char *) short_name) != NULL)
87 var_set_short_name (v, i, NULL);
90 /* Form initial short_name from the variable name, then try _A,
91 _B, ... _AA, _AB, etc., if needed. */
93 assign_short_name (struct variable *v, size_t i, struct hsh_table *short_names)
97 if (var_get_short_name (v, i) != NULL)
100 for (trial = 0; ; trial++)
103 var_set_short_name (v, i, var_get_name (v));
105 set_var_short_name_suffix (v, i, var_get_name (v), trial);
107 if (hsh_insert (short_names, (char *) var_get_short_name (v, i)) == NULL)
112 /* Assigns a valid, unique short_name[] to each variable in D.
113 Each variable whose actual name is short has highest priority
114 for that short name. Otherwise, variables with an existing
115 short_name[] have the next highest priority for a given short
116 name; if it is already taken, then the variable is treated as
117 if short_name[] had been empty. Otherwise, long names are
118 truncated to form short names. If that causes conflicts,
119 variables are renamed as PREFIX_A, PREFIX_B, and so on. */
121 short_names_assign (struct dictionary *d)
123 size_t var_cnt = dict_get_var_cnt (d);
124 struct hsh_table *short_names;
127 /* Create hash used for detecting conflicts. The entries in
128 the hash table point to strings owned by dictionary
129 variables, not by us, so we don't need to provide a free
131 short_names = hsh_create (var_cnt, compare_strings, do_hash_string,
134 /* Clear short names that conflict with a variable name. */
135 for (i = 0; i < var_cnt; i++)
137 struct variable *v = dict_get_var (d, i);
138 int segment_cnt = sfm_width_to_segments (var_get_width (v));
139 for (j = 0; j < segment_cnt; j++)
141 const char *name = var_get_short_name (v, j);
144 struct variable *ov = dict_lookup_var (d, name);
145 if (ov != NULL && (ov != v || j > 0))
146 var_set_short_name (v, j, NULL);
151 /* Give variables whose names are short the corresponding short
153 for (i = 0; i < var_cnt; i++)
155 struct variable *v = dict_get_var (d, i);
156 if (strlen (var_get_name (v)) <= SHORT_NAME_LEN)
157 var_set_short_name (v, 0, var_get_name (v));
160 /* Each variable with an assigned short name for its first
161 segment now gets it unless there is a conflict. In case of
162 conflict, the claimant earlier in dictionary order wins.
163 Then similarly for additional segments of very long
165 for (i = 0; i < var_cnt; i++)
167 struct variable *v = dict_get_var (d, i);
168 claim_short_name (v, 0, short_names);
170 for (i = 0; i < var_cnt; i++)
172 struct variable *v = dict_get_var (d, i);
173 int segment_cnt = sfm_width_to_segments (var_get_width (v));
174 for (j = 1; j < segment_cnt; j++)
175 claim_short_name (v, j, short_names);
178 /* Assign short names to first segment of remaining variables,
179 then similarly for additional segments. */
180 for (i = 0; i < var_cnt; i++)
182 struct variable *v = dict_get_var (d, i);
183 assign_short_name (v, 0, short_names);
185 for (i = 0; i < var_cnt; i++)
187 struct variable *v = dict_get_var (d, i);
188 int segment_cnt = sfm_width_to_segments (var_get_width (v));
189 for (j = 1; j < segment_cnt; j++)
190 assign_short_name (v, j, short_names);
193 /* Get rid of hash table. */
194 hsh_destroy (short_names);