1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011, 2014 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/i18n.h"
27 #include "libpspp/message.h"
28 #include "libpspp/str.h"
29 #include "libpspp/stringi-set.h"
32 #define _(msgid) gettext (msgid)
35 claim_short_name (struct variable
*v
, size_t i
,
36 struct stringi_set
*short_names
)
38 const char *short_name
= var_get_short_name (v
, i
);
39 if (short_name
!= NULL
&& !stringi_set_insert (short_names
, short_name
))
40 var_set_short_name (v
, i
, NULL
);
43 /* Form initial short_name from the variable name, then try _A,
44 _B, ... _AA, _AB, etc., if needed. */
46 assign_short_name (struct variable
*v
, size_t i
,
47 struct stringi_set
*short_names
)
51 if (var_get_short_name (v
, i
) != NULL
)
54 for (trial
= 0; ; trial
++)
56 char suffix
[SHORT_NAME_LEN
+ 1];
65 str_format_26adic (trial
, true, &suffix
[1], sizeof suffix
- 1);
69 short_name
= utf8_encoding_concat (var_get_name (v
), suffix
,
70 var_get_encoding (v
), SHORT_NAME_LEN
);
71 if (stringi_set_insert (short_names
, short_name
))
73 var_set_short_name (v
, i
, short_name
);
81 /* Assigns a valid, unique short_name[] to each variable in D.
82 Each variable whose actual name is short has highest priority
83 for that short name. Otherwise, variables with an existing
84 short_name[] have the next highest priority for a given short
85 name; if it is already taken, then the variable is treated as
86 if short_name[] had been empty. Otherwise, long names are
87 truncated to form short names. If that causes conflicts,
88 variables are renamed as PREFIX_A, PREFIX_B, and so on. */
90 short_names_assign (struct dictionary
*d
)
92 size_t var_cnt
= dict_get_var_cnt (d
);
93 struct stringi_set short_names
;
96 stringi_set_init (&short_names
);
98 /* Clear short names that conflict with a variable name. */
99 for (i
= 0; i
< var_cnt
; i
++)
101 struct variable
*v
= dict_get_var (d
, i
);
102 int segment_cnt
= sfm_width_to_segments (var_get_width (v
));
103 for (j
= 0; j
< segment_cnt
; j
++)
105 const char *name
= var_get_short_name (v
, j
);
108 struct variable
*ov
= dict_lookup_var (d
, name
);
109 if (ov
!= NULL
&& (ov
!= v
|| j
> 0))
110 var_set_short_name (v
, j
, NULL
);
115 /* Give variables whose names are short the corresponding short
117 for (i
= 0; i
< var_cnt
; i
++)
119 struct variable
*v
= dict_get_var (d
, i
);
120 const char *name
= var_get_name (v
);
121 int len
= recode_string_len (var_get_encoding (v
), "UTF-8", name
, -1);
122 if (len
<= SHORT_NAME_LEN
)
123 var_set_short_name (v
, 0, name
);
126 /* Each variable with an assigned short name for its first
127 segment now gets it unless there is a conflict. In case of
128 conflict, the claimant earlier in dictionary order wins.
129 Then similarly for additional segments of very long
131 for (i
= 0; i
< var_cnt
; i
++)
133 struct variable
*v
= dict_get_var (d
, i
);
134 claim_short_name (v
, 0, &short_names
);
136 for (i
= 0; i
< var_cnt
; i
++)
138 struct variable
*v
= dict_get_var (d
, i
);
139 int segment_cnt
= sfm_width_to_segments (var_get_width (v
));
140 for (j
= 1; j
< segment_cnt
; j
++)
141 claim_short_name (v
, j
, &short_names
);
144 /* Assign short names to first segment of remaining variables,
145 then similarly for additional segments. */
146 for (i
= 0; i
< var_cnt
; i
++)
148 struct variable
*v
= dict_get_var (d
, i
);
149 assign_short_name (v
, 0, &short_names
);
151 for (i
= 0; i
< var_cnt
; i
++)
153 struct variable
*v
= dict_get_var (d
, i
);
154 int segment_cnt
= sfm_width_to_segments (var_get_width (v
));
155 for (j
= 1; j
< segment_cnt
; j
++)
156 assign_short_name (v
, j
, &short_names
);
159 stringi_set_destroy (&short_names
);