1 /* PSPP - a program for statistical analysis. 2 Copyright (C) 2007, 2009, 2010, 2011, 2014 Free Software Foundation, Inc. 3 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. 8 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. 13 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/>. */ 16 17 #include <config.h> 18 19 #include "data/short-names.h" 20 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" 30 31 #include "gettext.h" 32 #define _(msgid) gettext (msgid) 33 34 static void 35 claim_short_name (struct variable *v, size_t i, 36 struct stringi_set *short_names) 37 { 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); 41 } 42 43 /* Form initial short_name from the variable name, then try _A, 44 _B, ... _AA, _AB, etc., if needed. */ 45 static void 46 assign_short_name (struct variable *v, size_t i, 47 struct stringi_set *short_names) 48 { 49 int trial; 50 51 if (var_get_short_name (v, i) != NULL) 52 return; 53 54 for (trial = 0; ; trial++) 55 { 56 char suffix[SHORT_NAME_LEN + 1]; 57 char *short_name; 58 59 /* Compose suffix. */ 60 if (trial == 0) 61 suffix[0] = '\0'; 62 else 63 { 64 suffix[0] = '_'; 65 str_format_26adic (trial, true, &suffix[1], sizeof suffix - 1); 66 } 67 68 /* Set name. */ 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)) 72 { 73 var_set_short_name (v, i, short_name); 74 free (short_name); 75 return; 76 } 77 free (short_name); 78 } 79 } 80 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. */ 89 void 90 short_names_assign (struct dictionary *d) 91 { 92 size_t var_cnt = dict_get_var_cnt (d); 93 struct stringi_set short_names; 94 size_t i, j; 95 96 stringi_set_init (&short_names); 97 98 /* Clear short names that conflict with a variable name. */ 99 for (i = 0; i < var_cnt; i++) 100 { 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++) 104 { 105 const char *name = var_get_short_name (v, j); 106 if (name != NULL) 107 { 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); 111 } 112 } 113 } 114 115 /* Give variables whose names are short the corresponding short 116 name. */ 117 for (i = 0; i < var_cnt; i++) 118 { 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); 124 } 125 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 130 strings. */ 131 for (i = 0; i < var_cnt; i++) 132 { 133 struct variable *v = dict_get_var (d, i); 134 claim_short_name (v, 0, &short_names); 135 } 136 for (i = 0; i < var_cnt; i++) 137 { 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); 142 } 143 144 /* Assign short names to first segment of remaining variables, 145 then similarly for additional segments. */ 146 for (i = 0; i < var_cnt; i++) 147 { 148 struct variable *v = dict_get_var (d, i); 149 assign_short_name (v, 0, &short_names); 150 } 151 for (i = 0; i < var_cnt; i++) 152 { 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); 157 } 158 159 stringi_set_destroy (&short_names); 160 } 161