1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014,
3 2015, 2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "data/dictionary.h"
27 #include "data/attributes.h"
28 #include "data/case.h"
29 #include "data/identifier.h"
30 #include "data/mrset.h"
31 #include "data/settings.h"
32 #include "data/value-labels.h"
33 #include "data/vardict.h"
34 #include "data/variable.h"
35 #include "data/varset.h"
36 #include "data/vector.h"
37 #include "libpspp/array.h"
38 #include "libpspp/assertion.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/hash-functions.h"
41 #include "libpspp/hmap.h"
42 #include "libpspp/i18n.h"
43 #include "libpspp/message.h"
44 #include "libpspp/misc.h"
45 #include "libpspp/pool.h"
46 #include "libpspp/str.h"
47 #include "libpspp/string-array.h"
48 #include "libpspp/ll.h"
50 #include "gl/intprops.h"
51 #include "gl/minmax.h"
52 #include "gl/xalloc.h"
53 #include "gl/xmemdup0.h"
56 #define _(msgid) gettext (msgid)
62 struct vardict_info
*vars
; /* Variables. */
63 size_t n_vars
; /* Number of variables. */
64 size_t allocated_vars
; /* Allocated space in 'vars'. */
65 struct caseproto
*proto
; /* Prototype for dictionary cases
67 struct hmap name_map
; /* Variable index by name. */
68 const struct variable
**split
; /* SPLIT FILE vars. */
69 size_t n_splits
; /* SPLIT FILE count. */
70 enum split_type split_type
;
71 struct variable
*weight
; /* WEIGHT variable. */
72 struct variable
*filter
; /* FILTER variable. */
73 casenumber case_limit
; /* Current case limit (N command). */
74 char *label
; /* File label. */
75 struct string_array documents
; /* Documents. */
76 struct vector
**vector
; /* Vectors of variables. */
77 size_t n_vectors
; /* Number of vectors. */
78 struct attrset attributes
; /* Custom attributes. */
79 struct mrset
**mrsets
; /* Multiple response sets. */
80 size_t n_mrsets
; /* Number of multiple response sets. */
81 struct varset
**varsets
; /* Variable sets. */
82 size_t n_varsets
; /* Number of variable sets. */
84 /* Number of VAR### names created by dict_make_unique_var_name(), or
86 unsigned long int n_unique_names
;
88 /* Whether variable names must be valid identifiers. Normally, this is
89 true, but sometimes a dictionary is prepared for external use
90 (e.g. output to a CSV file) where names don't have to be valid. */
91 bool names_must_be_ids
;
93 char *encoding
; /* Character encoding of string data */
95 const struct dict_callbacks
*callbacks
; /* Callbacks on dictionary
97 void *cb_data
; /* Data passed to callbacks */
99 void (*changed
) (struct dictionary
*, void *); /* Generic change callback */
103 static void dict_unset_split_var (struct dictionary
*, struct variable
*, bool);
104 static void dict_unset_mrset_var (struct dictionary
*, struct variable
*);
105 static void dict_unset_varset_var (struct dictionary
*, struct variable
*);
107 /* Compares two double pointers to variables, which should point
108 to elements of a struct dictionary's `var' member array. */
110 compare_var_ptrs (const void *a_
, const void *b_
, const void *aux UNUSED
)
112 struct variable
*const *a
= a_
;
113 struct variable
*const *b
= b_
;
115 return *a
< *b
? -1 : *a
> *b
;
119 unindex_var (struct dictionary
*d
, struct vardict_info
*vardict
)
121 hmap_delete (&d
->name_map
, &vardict
->name_node
);
124 /* This function assumes that vardict->name_node.hash is valid, that is, that
125 its name has not changed since it was hashed (rename_var() updates this
126 hash along with the name itself). */
128 reindex_var (struct dictionary
*d
, struct vardict_info
*vardict
, bool skip_callbacks
)
130 struct variable
*old
= (d
->callbacks
&& d
->callbacks
->var_changed
131 ? var_clone (vardict
->var
)
134 struct variable
*var
= vardict
->var
;
135 var_set_vardict (var
, vardict
);
136 hmap_insert_fast (&d
->name_map
, &vardict
->name_node
,
137 vardict
->name_node
.hash
);
139 if (! skip_callbacks
)
141 if (d
->changed
) d
->changed (d
, d
->changed_data
);
144 d
->callbacks
->var_changed (d
, var_get_dict_index (var
), VAR_TRAIT_POSITION
, old
, d
->cb_data
);
150 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
153 unindex_vars (struct dictionary
*d
, size_t from
, size_t to
)
157 for (i
= from
; i
< to
; i
++)
158 unindex_var (d
, &d
->vars
[i
]);
161 /* Re-sets the dict_index in the dictionary variables with
162 indexes from FROM to TO (exclusive). */
164 reindex_vars (struct dictionary
*d
, size_t from
, size_t to
, bool skip_callbacks
)
168 for (i
= from
; i
< to
; i
++)
169 reindex_var (d
, &d
->vars
[i
], skip_callbacks
);
174 /* Returns the encoding for data in dictionary D. The return value is a
175 nonnull string that contains an IANA character set name. */
177 dict_get_encoding (const struct dictionary
*d
)
182 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
183 encoding for a variable in the classes in CLASSES. Returns true if it is,
184 otherwise an error message that the caller must free(). */
185 char * WARN_UNUSED_RESULT
186 dict_id_is_valid__ (const struct dictionary
*dict
, const char *id
,
187 enum dict_class classes
)
189 if (!dict
->names_must_be_ids
)
191 return id_is_valid__ (id
, dict
->encoding
, classes
);
195 error_to_bool (char *error
)
206 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
207 encoding for a variable in the classes in CLASSES, false otherwise. */
209 dict_id_is_valid (const struct dictionary
*dict
, const char *id
,
210 enum dict_class classes
)
212 return error_to_bool (dict_id_is_valid__ (dict
, id
, classes
));
216 dict_set_change_callback (struct dictionary
*d
,
217 void (*changed
) (struct dictionary
*, void*),
220 d
->changed
= changed
;
221 d
->changed_data
= data
;
224 /* Discards dictionary D's caseproto. (It will be regenerated
225 lazily, on demand.) */
227 invalidate_proto (struct dictionary
*d
)
229 caseproto_unref (d
->proto
);
233 /* Print a representation of dictionary D to stdout, for
234 debugging purposes. */
236 dict_dump (const struct dictionary
*d
)
238 for (size_t i
= 0; i
< d
->n_vars
; ++i
)
239 printf ("%zu: %s\n", i
, var_get_name (d
->vars
[i
].var
));
242 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
243 the dictionary or any of the variables it contains are modified.
244 Each callback will get passed CALLBACK_DATA.
245 Any callback may be NULL, in which case it'll be ignored.
248 dict_set_callbacks (struct dictionary
*dict
,
249 const struct dict_callbacks
*callbacks
,
252 dict
->callbacks
= callbacks
;
253 dict
->cb_data
= callback_data
;
256 /* Shallow copy the callbacks from SRC to DEST */
258 dict_copy_callbacks (struct dictionary
*dest
,
259 const struct dictionary
*src
)
261 dest
->callbacks
= src
->callbacks
;
262 dest
->cb_data
= src
->cb_data
;
265 /* Creates and returns a new dictionary with the specified ENCODING. */
267 dict_create (const char *encoding
)
269 struct dictionary
*d
= xmalloc (sizeof *d
);
271 *d
= (struct dictionary
) {
272 .encoding
= xstrdup (encoding
),
273 .names_must_be_ids
= true,
274 .name_map
= HMAP_INITIALIZER (d
->name_map
),
275 .attributes
= ATTRSET_INITIALIZER (d
->attributes
),
276 .split_type
= SPLIT_NONE
,
283 /* Creates and returns a (deep) copy of an existing
286 Callbacks are not cloned. */
288 dict_clone (const struct dictionary
*s
)
290 struct dictionary
*d
= dict_create (s
->encoding
);
291 dict_set_names_must_be_ids (d
, dict_get_names_must_be_ids (s
));
293 for (size_t i
= 0; i
< s
->n_vars
; i
++)
295 struct variable
*sv
= s
->vars
[i
].var
;
296 struct variable
*dv
= dict_clone_var_assert (d
, sv
);
298 for (size_t j
= 0; j
< var_get_n_short_names (sv
); j
++)
299 var_set_short_name (dv
, j
, var_get_short_name (sv
, j
));
302 d
->n_splits
= s
->n_splits
;
305 d
->split
= xnmalloc (d
->n_splits
, sizeof *d
->split
);
306 for (size_t i
= 0; i
< d
->n_splits
; i
++)
307 d
->split
[i
] = dict_lookup_var_assert (d
, var_get_name (s
->split
[i
]));
309 d
->split_type
= s
->split_type
;
311 if (s
->weight
!= NULL
)
312 dict_set_weight (d
, dict_lookup_var_assert (d
, var_get_name (s
->weight
)));
314 if (s
->filter
!= NULL
)
315 dict_set_filter (d
, dict_lookup_var_assert (d
, var_get_name (s
->filter
)));
317 d
->case_limit
= s
->case_limit
;
318 dict_set_label (d
, dict_get_label (s
));
319 dict_set_documents (d
, dict_get_documents (s
));
321 d
->n_vectors
= s
->n_vectors
;
322 d
->vector
= xnmalloc (d
->n_vectors
, sizeof *d
->vector
);
323 for (size_t i
= 0; i
< s
->n_vectors
; i
++)
324 d
->vector
[i
] = vector_clone (s
->vector
[i
], s
, d
);
326 dict_set_attributes (d
, dict_get_attributes (s
));
328 for (size_t i
= 0; i
< s
->n_mrsets
; i
++)
330 const struct mrset
*old
= s
->mrsets
[i
];
334 /* Clone old mrset, then replace vars from D by vars from S. */
335 new = mrset_clone (old
);
336 for (j
= 0; j
< new->n_vars
; j
++)
337 new->vars
[j
] = dict_lookup_var_assert (d
, var_get_name (new->vars
[j
]));
339 dict_add_mrset (d
, new);
342 for (size_t i
= 0; i
< s
->n_varsets
; i
++)
344 const struct varset
*old
= s
->varsets
[i
];
346 /* Clone old varset, then replace vars from D by vars from S. */
347 struct varset
*new = varset_clone (old
);
348 for (size_t j
= 0; j
< new->n_vars
; j
++)
349 new->vars
[j
] = dict_lookup_var_assert (d
, var_get_name (new->vars
[j
]));
351 dict_add_varset (d
, new);
357 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
358 dict_get_n_splits() to determine how many SPLIT FILE vars
359 there are. Returns a null pointer if and only if there are no
361 const struct variable
*const *
362 dict_get_split_vars (const struct dictionary
*d
)
367 /* Returns the number of SPLIT FILE vars. */
369 dict_get_n_splits (const struct dictionary
*d
)
374 /* Removes variable V, which must be in D, from D's set of split
377 dict_unset_split_var (struct dictionary
*d
, struct variable
*v
, bool skip_callbacks
)
381 assert (dict_contains_var (d
, v
));
383 orig_count
= d
->n_splits
;
384 d
->n_splits
= remove_equal (d
->split
, d
->n_splits
, sizeof *d
->split
,
385 &v
, compare_var_ptrs
, NULL
);
386 if (orig_count
!= d
->n_splits
&& !skip_callbacks
)
388 if (d
->changed
) d
->changed (d
, d
->changed_data
);
389 /* We changed the set of split variables so invoke the
391 if (d
->callbacks
&& d
->callbacks
->split_changed
)
392 d
->callbacks
->split_changed (d
, d
->cb_data
);
397 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
400 dict_set_split_vars__ (struct dictionary
*d
,
401 struct variable
*const *split
, size_t n
,
402 enum split_type type
, bool skip_callbacks
)
406 assert (n
== 0 || split
!= NULL
);
409 d
->split_type
= (n
== 0 ? SPLIT_NONE
410 : type
== SPLIT_NONE
? SPLIT_LAYERED
414 d
->split
= xnrealloc (d
->split
, n
, sizeof *d
->split
) ;
415 memcpy (d
->split
, split
, n
* sizeof *d
->split
);
425 if (d
->changed
) d
->changed (d
, d
->changed_data
);
426 if (d
->callbacks
&& d
->callbacks
->split_changed
)
427 d
->callbacks
->split_changed (d
, d
->cb_data
);
432 dict_get_split_type (const struct dictionary
*d
)
434 return d
->split_type
;
437 /* Sets N split vars SPLIT in dictionary D. */
439 dict_set_split_vars (struct dictionary
*d
,
440 struct variable
*const *split
, size_t n
,
441 enum split_type type
)
443 dict_set_split_vars__ (d
, split
, n
, type
, false);
447 dict_clear_split_vars (struct dictionary
*d
)
449 dict_set_split_vars (d
, NULL
, 0, SPLIT_NONE
);
453 /* Deletes variable V from dictionary D and frees V.
455 This is a very bad idea if there might be any pointers to V
456 from outside D. In general, no variable in the active dataset's
457 dictionary should be deleted when any transformations are
458 active on the dictionary's dataset, because those
459 transformations might reference the deleted variable. The
460 safest time to delete a variable is just after a procedure has
461 been executed, as done by DELETE VARIABLES.
463 Pointers to V within D are not a problem, because
464 dict_delete_var() knows to remove V from split variables,
465 weights, filters, etc. */
467 dict_delete_var__ (struct dictionary
*d
, struct variable
*v
, bool skip_callbacks
)
469 d
->n_unique_names
= 0;
471 int dict_index
= var_get_dict_index (v
);
473 assert (dict_contains_var (d
, v
));
475 dict_unset_split_var (d
, v
, skip_callbacks
);
476 dict_unset_mrset_var (d
, v
);
477 dict_unset_varset_var (d
, v
);
480 dict_set_weight (d
, NULL
);
483 dict_set_filter (d
, NULL
);
485 dict_clear_vectors (d
);
487 /* Remove V from var array. */
488 unindex_vars (d
, dict_index
, d
->n_vars
);
489 remove_element (d
->vars
, d
->n_vars
, sizeof *d
->vars
, dict_index
);
492 /* Update dict_index for each affected variable. */
493 reindex_vars (d
, dict_index
, d
->n_vars
, skip_callbacks
);
496 var_clear_vardict (v
);
498 if (! skip_callbacks
)
500 if (d
->changed
) d
->changed (d
, d
->changed_data
);
501 if (d
->callbacks
&& d
->callbacks
->vars_deleted
)
502 d
->callbacks
->vars_deleted (d
, dict_index
, 1, d
->cb_data
);
505 invalidate_proto (d
);
509 /* Deletes variable V from dictionary D and frees V.
511 This is a very bad idea if there might be any pointers to V
512 from outside D. In general, no variable in the active dataset's
513 dictionary should be deleted when any transformations are
514 active on the dictionary's dataset, because those
515 transformations might reference the deleted variable. The
516 safest time to delete a variable is just after a procedure has
517 been executed, as done by DELETE VARIABLES.
519 Pointers to V within D are not a problem, because
520 dict_delete_var() knows to remove V from split variables,
521 weights, filters, etc. */
523 dict_delete_var (struct dictionary
*d
, struct variable
*v
)
525 dict_delete_var__ (d
, v
, false);
526 invalidate_proto (d
);
530 /* Deletes the COUNT variables listed in VARS from D. This is
531 unsafe; see the comment on dict_delete_var() for details. */
533 dict_delete_vars (struct dictionary
*d
,
534 struct variable
*const *vars
, size_t count
)
536 /* FIXME: this can be done in O(count) time, but this algorithm
538 assert (count
== 0 || vars
!= NULL
);
541 dict_delete_var (d
, *vars
++);
542 invalidate_proto (d
);
545 /* Deletes the COUNT variables in D starting at index IDX. This
546 is unsafe; see the comment on dict_delete_var() for
547 details. Deleting consecutive vars will result in less callbacks
548 compared to iterating over dict_delete_var.
549 A simple while loop over dict_delete_var will
550 produce (d->n_vars - IDX) * COUNT variable changed callbacks
551 plus COUNT variable delete callbacks.
552 This here produces d->n_vars - IDX variable changed callbacks
553 plus COUNT variable delete callbacks. */
555 dict_delete_consecutive_vars (struct dictionary
*d
, size_t idx
, size_t count
)
557 assert (idx
+ count
<= d
->n_vars
);
559 struct variable
**vars
= xnmalloc (count
, sizeof *vars
);
561 for (size_t i
= 0; i
< count
; i
++)
563 struct variable
*v
= d
->vars
[idx
+ i
].var
;
566 dict_unset_split_var (d
, v
, false);
567 dict_unset_mrset_var (d
, v
);
568 dict_unset_varset_var (d
, v
);
571 dict_set_weight (d
, NULL
);
574 dict_set_filter (d
, NULL
);
577 dict_clear_vectors (d
);
579 /* Remove variables from var array. */
580 unindex_vars (d
, idx
, d
->n_vars
);
581 remove_range (d
->vars
, d
->n_vars
, sizeof *d
->vars
, idx
, count
);
584 /* Reindexing will result variable-changed callback */
585 reindex_vars (d
, idx
, d
->n_vars
, false);
587 invalidate_proto (d
);
588 if (d
->changed
) d
->changed (d
, d
->changed_data
);
590 /* Now issue the variable delete callbacks and delete
591 the variables. The vardict is not valid at this point
593 if (d
->callbacks
&& d
->callbacks
->vars_deleted
)
594 d
->callbacks
->vars_deleted (d
, idx
, count
, d
->cb_data
);
595 for (size_t i
= 0; i
< count
; i
++)
597 var_clear_vardict (vars
[i
]);
602 invalidate_proto (d
);
605 /* Deletes scratch variables from dictionary D. */
607 dict_delete_scratch_vars (struct dictionary
*d
)
611 /* FIXME: this can be done in O(count) time, but this algorithm
613 for (i
= 0; i
< d
->n_vars
;)
614 if (var_get_dict_class (d
->vars
[i
].var
) == DC_SCRATCH
)
615 dict_delete_var (d
, d
->vars
[i
].var
);
619 invalidate_proto (d
);
624 /* Clears the contents from a dictionary without destroying the
625 dictionary itself. */
627 dict_clear__ (struct dictionary
*d
, bool skip_callbacks
)
629 /* FIXME? Should we really clear case_limit, label, documents?
630 Others are necessarily cleared by deleting all the variables.*/
631 while (d
->n_vars
> 0)
632 dict_delete_var__ (d
, d
->vars
[d
->n_vars
- 1].var
, skip_callbacks
);
636 d
->n_vars
= d
->allocated_vars
= 0;
637 invalidate_proto (d
);
638 hmap_clear (&d
->name_map
);
639 dict_set_split_vars__ (d
, NULL
, 0, SPLIT_NONE
, skip_callbacks
);
648 dict_set_weight (d
, NULL
);
649 dict_set_filter (d
, NULL
);
654 string_array_clear (&d
->documents
);
655 dict_clear_vectors (d
);
656 attrset_clear (&d
->attributes
);
659 /* Clears the contents from a dictionary without destroying the
660 dictionary itself. */
662 dict_clear (struct dictionary
*d
)
664 dict_clear__ (d
, false);
667 /* Clears a dictionary and destroys it. */
669 _dict_destroy (struct dictionary
*d
)
671 /* In general, we don't want callbacks occurring, if the dictionary
672 is being destroyed */
673 d
->callbacks
= NULL
;
675 dict_clear__ (d
, true);
676 string_array_destroy (&d
->documents
);
677 hmap_destroy (&d
->name_map
);
678 attrset_destroy (&d
->attributes
);
679 dict_clear_mrsets (d
);
680 dict_clear_varsets (d
);
686 dict_ref (struct dictionary
*d
)
693 dict_unref (struct dictionary
*d
)
698 assert (d
->ref_cnt
>= 0);
703 /* Returns the number of variables in D. */
705 dict_get_n_vars (const struct dictionary
*d
)
710 /* Returns the variable in D with dictionary index IDX, which
711 must be between 0 and the count returned by
712 dict_get_n_vars(), exclusive. */
714 dict_get_var (const struct dictionary
*d
, size_t idx
)
716 assert (idx
< d
->n_vars
);
718 return d
->vars
[idx
].var
;
721 /* Sets *VARS to an array of pointers to variables in D and *N
722 to the number of variables in *D. All variables are returned
723 except for those, if any, in the classes indicated by EXCLUDE.
724 (There is no point in putting DC_SYSTEM in EXCLUDE as
725 dictionaries never include system variables.) */
727 dict_get_vars (const struct dictionary
*d
, const struct variable
***vars
,
728 size_t *n
, enum dict_class exclude
)
730 dict_get_vars_mutable (d
, (struct variable
***) vars
, n
, exclude
);
733 /* Sets *VARS to an array of pointers to variables in D and *N
734 to the number of variables in *D. All variables are returned
735 except for those, if any, in the classes indicated by EXCLUDE.
736 (There is no point in putting DC_SYSTEM in EXCLUDE as
737 dictionaries never include system variables.) */
739 dict_get_vars_mutable (const struct dictionary
*d
, struct variable
***vars
,
740 size_t *n
, enum dict_class exclude
)
745 assert (exclude
== (exclude
& DC_ALL
));
748 for (i
= 0; i
< d
->n_vars
; i
++)
750 enum dict_class
class = var_get_dict_class (d
->vars
[i
].var
);
751 if (!(class & exclude
))
755 *vars
= xnmalloc (count
, sizeof **vars
);
757 for (i
= 0; i
< d
->n_vars
; i
++)
759 enum dict_class
class = var_get_dict_class (d
->vars
[i
].var
);
760 if (!(class & exclude
))
761 (*vars
)[(*n
)++] = d
->vars
[i
].var
;
763 assert (*n
== count
);
766 static struct variable
*
767 add_var (struct dictionary
*d
, struct variable
*v
)
769 /* Update dictionary. */
770 if (d
->n_vars
>= d
->allocated_vars
)
774 d
->vars
= x2nrealloc (d
->vars
, &d
->allocated_vars
, sizeof *d
->vars
);
775 hmap_clear (&d
->name_map
);
776 for (i
= 0; i
< d
->n_vars
; i
++)
778 var_set_vardict (d
->vars
[i
].var
, &d
->vars
[i
]);
779 hmap_insert_fast (&d
->name_map
, &d
->vars
[i
].name_node
,
780 d
->vars
[i
].name_node
.hash
);
784 struct vardict_info
*vardict
= &d
->vars
[d
->n_vars
++];
785 *vardict
= (struct vardict_info
) {
789 hmap_insert (&d
->name_map
, &vardict
->name_node
,
790 utf8_hash_case_string (var_get_name (v
), 0));
791 var_set_vardict (v
, vardict
);
793 if (d
->changed
) d
->changed (d
, d
->changed_data
);
794 if (d
->callbacks
&& d
->callbacks
->var_added
)
795 d
->callbacks
->var_added (d
, var_get_dict_index (v
), d
->cb_data
);
797 invalidate_proto (d
);
802 /* Creates and returns a new variable in D with the given NAME
803 and WIDTH. Returns a null pointer if the given NAME would
804 duplicate that of an existing variable in the dictionary. */
806 dict_create_var (struct dictionary
*d
, const char *name
, int width
)
808 return (dict_lookup_var (d
, name
) == NULL
809 ? dict_create_var_assert (d
, name
, width
)
813 /* Creates and returns a new variable in D with the given NAME
814 and WIDTH. Assert-fails if the given NAME would duplicate
815 that of an existing variable in the dictionary. */
817 dict_create_var_assert (struct dictionary
*d
, const char *name
, int width
)
819 assert (dict_lookup_var (d
, name
) == NULL
);
820 return add_var (d
, var_create (name
, width
));
823 /* Creates and returns a new variable in D, as a copy of existing variable
824 OLD_VAR, which need not be in D or in any dictionary. Returns a null
825 pointer if OLD_VAR's name would duplicate that of an existing variable in
828 dict_clone_var (struct dictionary
*d
, const struct variable
*old_var
)
830 return dict_clone_var_as (d
, old_var
, var_get_name (old_var
));
833 /* Creates and returns a new variable in D, as a copy of existing variable
834 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
835 OLD_VAR's name would duplicate that of an existing variable in the
838 dict_clone_var_assert (struct dictionary
*d
, const struct variable
*old_var
)
840 return dict_clone_var_as_assert (d
, old_var
, var_get_name (old_var
));
843 /* Creates and returns a new variable in D with name NAME, as a copy of
844 existing variable OLD_VAR, which need not be in D or in any dictionary.
845 Returns a null pointer if the given NAME would duplicate that of an existing
846 variable in the dictionary. */
848 dict_clone_var_as (struct dictionary
*d
, const struct variable
*old_var
,
851 return (dict_lookup_var (d
, name
) == NULL
852 ? dict_clone_var_as_assert (d
, old_var
, name
)
856 /* Creates and returns a new variable in D with name NAME, as a copy of
857 existing variable OLD_VAR, which need not be in D or in any dictionary.
858 Assert-fails if the given NAME would duplicate that of an existing variable
859 in the dictionary. */
861 dict_clone_var_as_assert (struct dictionary
*d
, const struct variable
*old_var
,
864 struct variable
*new_var
= var_clone (old_var
);
865 assert (dict_lookup_var (d
, name
) == NULL
);
866 var_set_name (new_var
, name
);
867 return add_var (d
, new_var
);
870 /* Creates and returns a new variable in DICT with the given WIDTH. Uses HINT
871 as the variable name, if it is nonnull, not already in use in DICT, and a
872 valid name for a DC_ORDINARY variable; otherwise, chooses a unique name with
875 dict_create_var_with_unique_name (struct dictionary
*dict
, const char *hint
,
878 const char *name
= (hint
879 && dict_id_is_valid (dict
, hint
, DC_ORDINARY
)
880 && !dict_lookup_var (dict
, hint
)
882 : dict_make_unique_var_name (dict
, hint
));
883 struct variable
*var
= dict_create_var_assert (dict
, name
, width
);
885 free (CONST_CAST (char *, name
));
889 /* Returns the variable named NAME in D, or a null pointer if no
890 variable has that name. */
892 dict_lookup_var (const struct dictionary
*d
, const char *name
)
894 struct vardict_info
*vardict
;
896 HMAP_FOR_EACH_WITH_HASH (vardict
, struct vardict_info
, name_node
,
897 utf8_hash_case_string (name
, 0), &d
->name_map
)
899 struct variable
*var
= vardict
->var
;
900 if (!utf8_strcasecmp (var_get_name (var
), name
))
907 /* Returns the variable named NAME in D. Assert-fails if no
908 variable has that name. */
910 dict_lookup_var_assert (const struct dictionary
*d
, const char *name
)
912 struct variable
*v
= dict_lookup_var (d
, name
);
917 /* Returns true if variable V is in dictionary D,
920 dict_contains_var (const struct dictionary
*d
, const struct variable
*v
)
922 return (var_has_vardict (v
)
923 && vardict_get_dictionary (var_get_vardict (v
)) == d
);
926 /* Moves V to 0-based position IDX in D. Other variables in D,
927 if any, retain their relative positions. Runs in time linear
928 in the distance moved. */
930 dict_reorder_var (struct dictionary
*d
, struct variable
*v
, size_t new_index
)
932 assert (new_index
< d
->n_vars
);
934 size_t old_index
= var_get_dict_index (v
);
935 if (new_index
== old_index
)
938 unindex_vars (d
, MIN (old_index
, new_index
), MAX (old_index
, new_index
) + 1);
939 move_element (d
->vars
, d
->n_vars
, sizeof *d
->vars
, old_index
, new_index
);
940 reindex_vars (d
, MIN (old_index
, new_index
), MAX (old_index
, new_index
) + 1, false);
942 if (d
->callbacks
&& d
->callbacks
->var_moved
)
943 d
->callbacks
->var_moved (d
, new_index
, old_index
, d
->cb_data
);
946 /* Reorders the variables in D, placing the COUNT variables
947 listed in ORDER in that order at the beginning of D. The
948 other variables in D, if any, retain their relative
951 dict_reorder_vars (struct dictionary
*d
,
952 struct variable
*const *order
, size_t count
)
954 struct vardict_info
*new_var
;
957 assert (count
== 0 || order
!= NULL
);
958 assert (count
<= d
->n_vars
);
960 new_var
= xnmalloc (d
->allocated_vars
, sizeof *new_var
);
962 /* Add variables in ORDER to new_var. */
963 for (i
= 0; i
< count
; i
++)
965 struct vardict_info
*old_var
;
967 assert (dict_contains_var (d
, order
[i
]));
969 old_var
= var_get_vardict (order
[i
]);
970 new_var
[i
] = *old_var
;
971 old_var
->dict
= NULL
;
974 /* Add remaining variables to new_var. */
975 for (i
= 0; i
< d
->n_vars
; i
++)
976 if (d
->vars
[i
].dict
!= NULL
)
977 new_var
[count
++] = d
->vars
[i
];
978 assert (count
== d
->n_vars
);
980 /* Replace old vardicts by new ones. */
984 hmap_clear (&d
->name_map
);
985 reindex_vars (d
, 0, d
->n_vars
, false);
988 /* Changes the name of variable V that is currently in dictionary D to
991 rename_var (struct dictionary
*d
, struct variable
*v
, const char *new_name
)
993 d
->n_unique_names
= 0;
995 struct vardict_info
*vardict
= var_get_vardict (v
);
996 var_clear_vardict (v
);
997 var_set_name (v
, new_name
);
998 vardict
->name_node
.hash
= utf8_hash_case_string (new_name
, 0);
999 var_set_vardict (v
, vardict
);
1002 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
1003 successful, false if a variable (other than V) with the given name already
1006 dict_try_rename_var (struct dictionary
*d
, struct variable
*v
,
1007 const char *new_name
)
1009 struct variable
*conflict
= dict_lookup_var (d
, new_name
);
1010 if (conflict
&& v
!= conflict
)
1013 struct variable
*old
= var_clone (v
);
1014 unindex_var (d
, var_get_vardict (v
));
1015 rename_var (d
, v
, new_name
);
1016 reindex_var (d
, var_get_vardict (v
), false);
1018 if (settings_get_algorithm () == ENHANCED
)
1019 var_clear_short_names (v
);
1021 if (d
->changed
) d
->changed (d
, d
->changed_data
);
1022 if (d
->callbacks
&& d
->callbacks
->var_changed
)
1023 d
->callbacks
->var_changed (d
, var_get_dict_index (v
), VAR_TRAIT_NAME
, old
, d
->cb_data
);
1030 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1031 a variable named NEW_NAME is already in D, except that
1032 NEW_NAME may be the same as V's existing name. */
1034 dict_rename_var (struct dictionary
*d
, struct variable
*v
,
1035 const char *new_name
)
1037 bool ok UNUSED
= dict_try_rename_var (d
, v
, new_name
);
1041 /* Renames COUNT variables specified in VARS to the names given
1042 in NEW_NAMES within dictionary D. If the renaming would
1043 result in a duplicate variable name, returns false and stores a
1044 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1045 non-null). Otherwise, the renaming is successful, and true
1048 dict_rename_vars (struct dictionary
*d
,
1049 struct variable
**vars
, char **new_names
, size_t count
,
1056 assert (count
== 0 || vars
!= NULL
);
1057 assert (count
== 0 || new_names
!= NULL
);
1059 /* Save the names of the variables to be renamed. */
1060 pool
= pool_create ();
1061 old_names
= pool_nalloc (pool
, count
, sizeof *old_names
);
1062 for (i
= 0; i
< count
; i
++)
1063 old_names
[i
] = pool_strdup (pool
, var_get_name (vars
[i
]));
1065 /* Remove the variables to be renamed from the name hash,
1067 for (i
= 0; i
< count
; i
++)
1069 unindex_var (d
, var_get_vardict (vars
[i
]));
1070 rename_var (d
, vars
[i
], new_names
[i
]);
1073 /* Add the renamed variables back into the name hash,
1074 checking for conflicts. */
1075 for (i
= 0; i
< count
; i
++)
1077 if (dict_lookup_var (d
, var_get_name (vars
[i
])) != NULL
)
1079 /* There is a name conflict.
1080 Back out all the name changes that have already
1081 taken place, and indicate failure. */
1082 size_t fail_idx
= i
;
1083 if (err_name
!= NULL
)
1084 *err_name
= new_names
[i
];
1086 for (i
= 0; i
< fail_idx
; i
++)
1087 unindex_var (d
, var_get_vardict (vars
[i
]));
1089 for (i
= 0; i
< count
; i
++)
1091 rename_var (d
, vars
[i
], old_names
[i
]);
1092 reindex_var (d
, var_get_vardict (vars
[i
]), false);
1095 pool_destroy (pool
);
1098 reindex_var (d
, var_get_vardict (vars
[i
]), false);
1101 /* Clear short names. */
1102 if (settings_get_algorithm () == ENHANCED
)
1103 for (i
= 0; i
< count
; i
++)
1104 var_clear_short_names (vars
[i
]);
1106 pool_destroy (pool
);
1110 /* Returns true if a variable named NAME may be inserted in DICT;
1111 that is, if there is not already a variable with that name in
1112 DICT and if NAME is not a reserved word. (The caller's checks
1113 have already verified that NAME is otherwise acceptable as a
1116 var_name_is_insertable (const struct dictionary
*dict
, const char *name
)
1118 return (dict_lookup_var (dict
, name
) == NULL
1119 && lex_id_to_token (ss_cstr (name
)) == T_ID
);
1123 make_hinted_name (const struct dictionary
*dict
, const char *hint
)
1125 size_t hint_len
= strlen (hint
);
1126 bool dropped
= false;
1131 if (hint_len
> ID_MAX_LEN
)
1132 hint_len
= ID_MAX_LEN
;
1134 /* The allocation size here is OK: characters that are copied directly fit
1135 OK, and characters that are not copied directly are replaced by a single
1136 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1137 replaced by '_' too. */
1138 root
= rp
= xmalloc (hint_len
+ 1);
1139 for (ofs
= 0; ofs
< hint_len
; ofs
+= mblen
)
1143 mblen
= u8_mbtouc (&uc
, CHAR_CAST (const uint8_t *, hint
+ ofs
),
1146 ? lex_uc_is_id1 (uc
) && uc
!= '$' && uc
!= '#' && uc
!= '@'
1147 : lex_uc_is_idn (uc
))
1154 rp
+= u8_uctomb (CHAR_CAST (uint8_t *, rp
), uc
, 6);
1156 else if (rp
!= root
)
1161 if (root
[0] != '\0')
1163 unsigned long int i
;
1165 if (var_name_is_insertable (dict
, root
))
1168 for (i
= 0; i
< ULONG_MAX
; i
++)
1170 char suffix
[1 + F26ADIC_STRLEN_MAX
+ 1];
1173 str_format_26adic (i
+ 1, true, &suffix
[1], sizeof suffix
- 1);
1175 char *name
= utf8_encoding_concat (root
, suffix
, dict
->encoding
, 64);
1176 if (var_name_is_insertable (dict
, name
))
1191 make_numeric_name (struct dictionary
*dict
)
1193 while (dict
->n_unique_names
++ < ULONG_MAX
)
1195 char *name
= xasprintf ("VAR%03lu", dict
->n_unique_names
);
1196 if (dict_lookup_var (dict
, name
) == NULL
)
1204 /* Devises and returns a variable name unique within DICT. The variable name
1205 is owned by the caller, which must free it with free() when it is no longer
1206 needed. The variable name will not begin with '$' or '#' or '@'.
1208 HINT, if it is non-null, is used as a suggestion that will be
1209 modified for suitability as a variable name and for
1212 If HINT is null or entirely unsuitable, uses a name in the form "VAR%03d",
1213 using the smallest available integer. */
1215 dict_make_unique_var_name (const struct dictionary
*dict_
, const char *hint
)
1217 struct dictionary
*dict
= CONST_CAST (struct dictionary
*, dict_
);
1220 char *hinted_name
= make_hinted_name (dict
, hint
);
1221 if (hinted_name
!= NULL
)
1225 return make_numeric_name (dict
);
1228 /* Returns whether variable names must be valid identifiers. Normally, this is
1229 true, but sometimes a dictionary is prepared for external use (e.g. output
1230 to a CSV file) where names don't have to be valid. */
1232 dict_get_names_must_be_ids (const struct dictionary
*d
)
1234 return d
->names_must_be_ids
;
1237 /* Sets whether variable names must be valid identifiers. Normally, this is
1238 true, but sometimes a dictionary is prepared for external use (e.g. output
1239 to a CSV file) where names don't have to be valid.
1241 Changing this setting from false to true doesn't make the dictionary check
1242 all the existing variable names, so it can cause an invariant violation. */
1244 dict_set_names_must_be_ids (struct dictionary
*d
, bool names_must_be_ids
)
1246 d
->names_must_be_ids
= names_must_be_ids
;
1249 /* Returns the weighting variable in dictionary D, or a null
1250 pointer if the dictionary is unweighted. */
1252 dict_get_weight (const struct dictionary
*d
)
1254 assert (d
->weight
== NULL
|| dict_contains_var (d
, d
->weight
));
1259 /* Returns the value of D's weighting variable in case C, except
1260 that a negative or missing weight is returned as 0. Returns 1 if the
1261 dictionary is unweighted. Will warn about missing, negative,
1262 or zero values if *WARN_ON_INVALID is true. The function will
1263 set *WARN_ON_INVALID to false if an invalid weight is
1266 dict_get_case_weight (const struct dictionary
*d
, const struct ccase
*c
,
1267 bool *warn_on_invalid
)
1271 if (d
->weight
== NULL
)
1275 double w
= case_num (c
, d
->weight
);
1277 return var_force_valid_weight (d
->weight
, w
, warn_on_invalid
);
1281 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1284 dict_get_rounded_case_weight (const struct dictionary
*d
,
1285 const struct ccase
*c
, bool *warn_on_invalid
)
1287 return floor (dict_get_case_weight (d
, c
, warn_on_invalid
) + 0.5);
1290 /* Returns the format to use for weights. */
1292 dict_get_weight_format (const struct dictionary
*d
)
1294 return d
->weight
? var_get_print_format (d
->weight
) : F_8_0
;
1297 /* Sets the weighting variable of D to V, or turning off
1298 weighting if V is a null pointer. */
1300 dict_set_weight (struct dictionary
*d
, struct variable
*v
)
1302 assert (v
== NULL
|| dict_contains_var (d
, v
));
1303 assert (v
== NULL
|| var_is_numeric (v
));
1307 if (d
->changed
) d
->changed (d
, d
->changed_data
);
1308 if (d
->callbacks
&& d
->callbacks
->weight_changed
)
1309 d
->callbacks
->weight_changed (d
,
1310 v
? var_get_dict_index (v
) : -1,
1314 /* Returns the filter variable in dictionary D (see cmd_filter())
1315 or a null pointer if the dictionary is unfiltered. */
1317 dict_get_filter (const struct dictionary
*d
)
1319 assert (d
->filter
== NULL
|| dict_contains_var (d
, d
->filter
));
1324 /* Sets V as the filter variable for dictionary D. Passing a
1325 null pointer for V turn off filtering. */
1327 dict_set_filter (struct dictionary
*d
, struct variable
*v
)
1329 assert (v
== NULL
|| dict_contains_var (d
, v
));
1330 assert (v
== NULL
|| var_is_numeric (v
));
1334 if (d
->changed
) d
->changed (d
, d
->changed_data
);
1335 if (d
->callbacks
&& d
->callbacks
->filter_changed
)
1336 d
->callbacks
->filter_changed (d
,
1337 v
? var_get_dict_index (v
) : -1,
1341 /* Returns the case limit for dictionary D, or zero if the number
1342 of cases is unlimited. */
1344 dict_get_case_limit (const struct dictionary
*d
)
1346 return d
->case_limit
;
1349 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1350 0 for CASE_LIMIT to indicate no limit. */
1352 dict_set_case_limit (struct dictionary
*d
, casenumber case_limit
)
1354 d
->case_limit
= case_limit
;
1357 /* Returns the prototype used for cases created by dictionary D. */
1358 const struct caseproto
*
1359 dict_get_proto (const struct dictionary
*d_
)
1361 struct dictionary
*d
= CONST_CAST (struct dictionary
*, d_
);
1362 if (d
->proto
== NULL
)
1364 short int *widths
= xnmalloc (d
->n_vars
, sizeof *widths
);
1365 for (size_t i
= 0; i
< d
->n_vars
; i
++)
1366 widths
[i
] = var_get_width (d
->vars
[i
].var
);
1367 d
->proto
= caseproto_from_widths (widths
, d
->n_vars
);
1372 /* Returns the file label for D, or a null pointer if D is
1373 unlabeled (see cmd_file_label()). */
1375 dict_get_label (const struct dictionary
*d
)
1380 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1383 Removes D's label if LABEL is null or the empty string. */
1385 dict_set_label (struct dictionary
*d
, const char *label
)
1388 if (label
== NULL
|| label
[0] == '\0')
1391 d
->label
= utf8_encoding_trunc (label
, d
->encoding
, 60);
1394 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1395 return value is always nonnull; if there are no documents then the
1396 string_arary is empty.*/
1397 const struct string_array
*
1398 dict_get_documents (const struct dictionary
*d
)
1400 return &d
->documents
;
1403 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1405 dict_set_documents (struct dictionary
*d
, const struct string_array
*new_docs
)
1407 /* Swap out the old documents, instead of destroying them immediately, to
1408 allow the new documents to include pointers into the old ones. */
1409 struct string_array old_docs
= STRING_ARRAY_INITIALIZER
;
1410 string_array_swap (&d
->documents
, &old_docs
);
1412 for (size_t i
= 0; i
< new_docs
->n
; i
++)
1413 dict_add_document_line (d
, new_docs
->strings
[i
], false);
1415 string_array_destroy (&old_docs
);
1418 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1419 into individual lines at new-line characters. Each line is truncated to at
1420 most DOC_LINE_LENGTH bytes in D's encoding. */
1422 dict_set_documents_string (struct dictionary
*d
, const char *new_docs
)
1426 dict_clear_documents (d
);
1427 for (s
= new_docs
; *s
!= '\0';)
1429 size_t len
= strcspn (s
, "\n");
1430 char *line
= xmemdup0 (s
, len
);
1431 dict_add_document_line (d
, line
, false);
1440 /* Drops the documents from dictionary D. */
1442 dict_clear_documents (struct dictionary
*d
)
1444 string_array_clear (&d
->documents
);
1447 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1448 truncated so that it is no more than 80 bytes in the dictionary's
1449 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1450 then a warning will be issued. */
1452 dict_add_document_line (struct dictionary
*d
, const char *line
,
1458 trunc_len
= utf8_encoding_trunc_len (line
, d
->encoding
, DOC_LINE_LENGTH
);
1459 truncated
= line
[trunc_len
] != '\0';
1460 if (truncated
&& issue_warning
)
1462 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1463 msg (SW
, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH
);
1466 string_array_append_nocopy (&d
->documents
, xmemdup0 (line
, trunc_len
));
1471 /* Returns the number of document lines in dictionary D. */
1473 dict_get_document_n_lines (const struct dictionary
*d
)
1475 return d
->documents
.n
;
1478 /* Returns document line number IDX in dictionary D. The caller must not
1479 modify or free the returned string. */
1481 dict_get_document_line (const struct dictionary
*d
, size_t idx
)
1483 assert (idx
< d
->documents
.n
);
1484 return d
->documents
.strings
[idx
];
1487 /* Creates in D a vector named NAME that contains the N
1488 variables in VAR. Returns true if successful, or false if a
1489 vector named NAME already exists in D. */
1491 dict_create_vector (struct dictionary
*d
,
1493 struct variable
**var
, size_t n
)
1496 for (size_t i
= 0; i
< n
; i
++)
1497 assert (dict_contains_var (d
, var
[i
]));
1499 if (dict_lookup_vector (d
, name
) == NULL
)
1501 d
->vector
= xnrealloc (d
->vector
, d
->n_vectors
+ 1, sizeof *d
->vector
);
1502 d
->vector
[d
->n_vectors
++] = vector_create (name
, var
, n
);
1509 /* Creates in D a vector named NAME that contains the N
1510 variables in VAR. A vector named NAME must not already exist
1513 dict_create_vector_assert (struct dictionary
*d
,
1515 struct variable
**var
, size_t n
)
1517 assert (dict_lookup_vector (d
, name
) == NULL
);
1518 dict_create_vector (d
, name
, var
, n
);
1521 /* Returns the vector in D with index IDX, which must be less
1522 than dict_get_n_vectors (D). */
1523 const struct vector
*
1524 dict_get_vector (const struct dictionary
*d
, size_t idx
)
1526 assert (idx
< d
->n_vectors
);
1528 return d
->vector
[idx
];
1531 /* Returns the number of vectors in D. */
1533 dict_get_n_vectors (const struct dictionary
*d
)
1535 return d
->n_vectors
;
1538 /* Looks up and returns the vector within D with the given
1540 const struct vector
*
1541 dict_lookup_vector (const struct dictionary
*d
, const char *name
)
1544 for (i
= 0; i
< d
->n_vectors
; i
++)
1545 if (!utf8_strcasecmp (vector_get_name (d
->vector
[i
]), name
))
1546 return d
->vector
[i
];
1550 /* Deletes all vectors from D. */
1552 dict_clear_vectors (struct dictionary
*d
)
1556 for (i
= 0; i
< d
->n_vectors
; i
++)
1557 vector_destroy (d
->vector
[i
]);
1564 /* Multiple response sets. */
1566 /* Returns the multiple response set in DICT with index IDX, which must be
1567 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1568 const struct mrset
*
1569 dict_get_mrset (const struct dictionary
*dict
, size_t idx
)
1571 assert (idx
< dict
->n_mrsets
);
1572 return dict
->mrsets
[idx
];
1575 /* Returns the number of multiple response sets in DICT. */
1577 dict_get_n_mrsets (const struct dictionary
*dict
)
1579 return dict
->n_mrsets
;
1582 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1583 returns its index; otherwise, returns SIZE_MAX. */
1585 dict_lookup_mrset_idx (const struct dictionary
*dict
, const char *name
)
1589 for (i
= 0; i
< dict
->n_mrsets
; i
++)
1590 if (!utf8_strcasecmp (name
, dict
->mrsets
[i
]->name
))
1596 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1597 returns it; otherwise, returns NULL. */
1598 const struct mrset
*
1599 dict_lookup_mrset (const struct dictionary
*dict
, const char *name
)
1601 size_t idx
= dict_lookup_mrset_idx (dict
, name
);
1602 return idx
!= SIZE_MAX
? dict
->mrsets
[idx
] : NULL
;
1605 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1606 true if a set was replaced, false if none existed with the specified name.
1608 Ownership of MRSET is transferred to DICT. */
1610 dict_add_mrset (struct dictionary
*dict
, struct mrset
*mrset
)
1614 assert (mrset_ok (mrset
, dict
));
1616 idx
= dict_lookup_mrset_idx (dict
, mrset
->name
);
1617 if (idx
== SIZE_MAX
)
1619 dict
->mrsets
= xrealloc (dict
->mrsets
,
1620 (dict
->n_mrsets
+ 1) * sizeof *dict
->mrsets
);
1621 dict
->mrsets
[dict
->n_mrsets
++] = mrset
;
1626 mrset_destroy (dict
->mrsets
[idx
]);
1627 dict
->mrsets
[idx
] = mrset
;
1632 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1633 from DICT and returns true. If none is found, returns false without
1636 Deleting one multiple response set causes the indexes of other sets within
1639 dict_delete_mrset (struct dictionary
*dict
, const char *name
)
1641 size_t idx
= dict_lookup_mrset_idx (dict
, name
);
1642 if (idx
!= SIZE_MAX
)
1644 mrset_destroy (dict
->mrsets
[idx
]);
1645 dict
->mrsets
[idx
] = dict
->mrsets
[--dict
->n_mrsets
];
1652 /* Deletes all multiple response sets from DICT. */
1654 dict_clear_mrsets (struct dictionary
*dict
)
1658 for (i
= 0; i
< dict
->n_mrsets
; i
++)
1659 mrset_destroy (dict
->mrsets
[i
]);
1660 free (dict
->mrsets
);
1661 dict
->mrsets
= NULL
;
1665 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1667 dict_unset_mrset_var (struct dictionary
*dict
, struct variable
*var
)
1671 assert (dict_contains_var (dict
, var
));
1673 for (i
= 0; i
< dict
->n_mrsets
;)
1675 struct mrset
*mrset
= dict
->mrsets
[i
];
1678 for (j
= 0; j
< mrset
->n_vars
;)
1679 if (mrset
->vars
[j
] == var
)
1680 remove_element (mrset
->vars
, mrset
->n_vars
--,
1681 sizeof *mrset
->vars
, j
);
1685 if (mrset
->n_vars
< 2)
1687 mrset_destroy (mrset
);
1688 dict
->mrsets
[i
] = dict
->mrsets
[--dict
->n_mrsets
];
1696 /* Returns the variable set in DICT with index IDX, which must be between 0 and
1697 the count returned by dict_get_n_varsets(), exclusive. */
1698 const struct varset
*
1699 dict_get_varset (const struct dictionary
*dict
, size_t idx
)
1701 assert (idx
< dict
->n_varsets
);
1702 return dict
->varsets
[idx
];
1705 /* Returns the number of variable sets in DICT. */
1707 dict_get_n_varsets (const struct dictionary
*dict
)
1709 return dict
->n_varsets
;
1712 /* Looks for a variable set named NAME in DICT. If it finds one, returns its
1713 index; otherwise, returns SIZE_MAX. */
1715 dict_lookup_varset_idx (const struct dictionary
*dict
, const char *name
)
1717 for (size_t i
= 0; i
< dict
->n_varsets
; i
++)
1718 if (!utf8_strcasecmp (name
, dict
->varsets
[i
]->name
))
1724 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1725 returns it; otherwise, returns NULL. */
1726 const struct varset
*
1727 dict_lookup_varset (const struct dictionary
*dict
, const char *name
)
1729 size_t idx
= dict_lookup_varset_idx (dict
, name
);
1730 return idx
!= SIZE_MAX
? dict
->varsets
[idx
] : NULL
;
1733 /* Adds VARSET to DICT, replacing any existing set with the same name. Returns
1734 true if a set was replaced, false if none existed with the specified name.
1736 Ownership of VARSET is transferred to DICT. */
1738 dict_add_varset (struct dictionary
*dict
, struct varset
*varset
)
1740 size_t idx
= dict_lookup_varset_idx (dict
, varset
->name
);
1741 if (idx
== SIZE_MAX
)
1743 dict
->varsets
= xrealloc (dict
->varsets
,
1744 (dict
->n_varsets
+ 1) * sizeof *dict
->varsets
);
1745 dict
->varsets
[dict
->n_varsets
++] = varset
;
1750 varset_destroy (dict
->varsets
[idx
]);
1751 dict
->varsets
[idx
] = varset
;
1756 /* Deletes all variable sets from DICT. */
1758 dict_clear_varsets (struct dictionary
*dict
)
1760 for (size_t i
= 0; i
< dict
->n_varsets
; i
++)
1761 varset_destroy (dict
->varsets
[i
]);
1762 free (dict
->varsets
);
1763 dict
->varsets
= NULL
;
1764 dict
->n_varsets
= 0;
1767 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1769 dict_unset_varset_var (struct dictionary
*dict
, struct variable
*var
)
1771 assert (dict_contains_var (dict
, var
));
1773 for (size_t i
= 0; i
< dict
->n_varsets
; i
++)
1775 struct varset
*varset
= dict
->varsets
[i
];
1777 for (size_t j
= 0; j
< varset
->n_vars
;)
1778 if (varset
->vars
[j
] == var
)
1779 remove_element (varset
->vars
, varset
->n_vars
--,
1780 sizeof *varset
->vars
, j
);
1786 /* Returns D's attribute set. The caller may examine or modify
1787 the attribute set, but must not destroy it. Destroying D or
1788 calling dict_set_attributes for D will also destroy D's
1791 dict_get_attributes (const struct dictionary
*d
)
1793 return CONST_CAST (struct attrset
*, &d
->attributes
);
1796 /* Replaces D's attributes set by a copy of ATTRS. */
1798 dict_set_attributes (struct dictionary
*d
, const struct attrset
*attrs
)
1800 attrset_destroy (&d
->attributes
);
1801 attrset_clone (&d
->attributes
, attrs
);
1804 /* Returns true if D has at least one attribute in its attribute
1805 set, false if D's attribute set is empty. */
1807 dict_has_attributes (const struct dictionary
*d
)
1809 return attrset_count (&d
->attributes
) > 0;
1812 /* Called from variable.c to notify the dictionary that some property (indicated
1813 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1814 prior to the change. OLDVAR is destroyed by this function.
1817 dict_var_changed (const struct variable
*v
, unsigned int what
, struct variable
*oldvar
)
1819 if (var_has_vardict (v
))
1821 const struct vardict_info
*vardict
= var_get_vardict (v
);
1822 struct dictionary
*d
= vardict
->dict
;
1827 if (what
& (VAR_TRAIT_WIDTH
| VAR_TRAIT_POSITION
))
1828 invalidate_proto (d
);
1830 if (d
->changed
) d
->changed (d
, d
->changed_data
);
1831 if (d
->callbacks
&& d
->callbacks
->var_changed
)
1832 d
->callbacks
->var_changed (d
, var_get_dict_index (v
), what
, oldvar
, d
->cb_data
);
1840 vardict_get_dict_index (const struct vardict_info
*vardict
)
1842 return vardict
- vardict
->dict
->vars
;