Merge 'master' into 'psppsheet'.
[pspp] / src / data / session.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011, 2012 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/session.h"
20
21 #include <assert.h>
22 #include <stdlib.h>
23
24 #include "data/dataset.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/cast.h"
27 #include "libpspp/hash-functions.h"
28 #include "libpspp/i18n.h"
29 #include "libpspp/str.h"
30 #include "libpspp/hmapx.h"
31
32 #include "gl/xalloc.h"
33
34 struct session
35   {
36     struct hmapx datasets;
37     struct dataset *active;
38     char *syntax_encoding;      /* Default encoding for syntax files. */
39     unsigned int n_dataset_names; /* For session_generate_dataset_name(). */
40   };
41
42 static struct hmapx_node *session_lookup_dataset__ (const struct session *,
43                                                     const char *name);
44
45 struct session *
46 session_create (void)
47 {
48   struct session *s;
49
50   s = xmalloc (sizeof *s);
51   hmapx_init (&s->datasets);
52   s->active = NULL;
53   s->syntax_encoding = xstrdup ("Auto");
54   s->n_dataset_names = 0;
55   return s;
56 }
57
58 void
59 session_destroy (struct session *s)
60 {
61   if (s != NULL)
62     {
63       struct hmapx_node *node, *next;
64       struct dataset *ds;
65
66       s->active = NULL;
67       HMAPX_FOR_EACH_SAFE (ds, node, next, &s->datasets)
68         dataset_destroy (ds);
69       free (s->syntax_encoding);
70       free (s);
71     }
72 }
73
74 struct dataset *
75 session_active_dataset (struct session *s)
76 {
77   return s->active;
78 }
79
80 void
81 session_set_active_dataset (struct session *s, struct dataset *ds)
82 {
83   assert (ds == NULL || dataset_session (ds) == s);
84   s->active = ds;
85 }
86
87 void
88 session_add_dataset (struct session *s, struct dataset *ds)
89 {
90   struct dataset *old;
91
92   old = session_lookup_dataset (s, dataset_name (ds));
93   if (old == s->active)
94     s->active = ds;
95   if (old != NULL)
96     session_remove_dataset (s, old);
97
98   hmapx_insert (&s->datasets, ds,
99                 utf8_hash_case_string (dataset_name (ds), 0));
100   if (s->active == NULL)
101     s->active = ds;
102
103   dataset_set_session__ (ds, s);
104 }
105
106 void
107 session_remove_dataset (struct session *s, struct dataset *ds)
108 {
109   assert (ds != s->active);
110   hmapx_delete (&s->datasets, session_lookup_dataset__ (s, dataset_name (ds)));
111   dataset_set_session__ (ds, NULL);
112 }
113
114 struct dataset *
115 session_lookup_dataset (const struct session *s, const char *name)
116 {
117   struct hmapx_node *node = session_lookup_dataset__ (s, name);
118   return node != NULL ? node->data : NULL;
119 }
120
121 struct dataset *
122 session_lookup_dataset_assert (const struct session *s, const char *name)
123 {
124   struct dataset *ds = session_lookup_dataset (s, name);
125   assert (ds != NULL);
126   return ds;
127 }
128
129 void
130 session_set_default_syntax_encoding (struct session *s, const char *encoding)
131 {
132   free (s->syntax_encoding);
133   s->syntax_encoding = xstrdup (encoding);
134 }
135
136 const char *
137 session_get_default_syntax_encoding (const struct session *s)
138 {
139   return s->syntax_encoding;
140 }
141
142 size_t
143 session_n_datasets (const struct session *s)
144 {
145   return hmapx_count (&s->datasets);
146 }
147
148 void
149 session_for_each_dataset (const struct session *s,
150                           void (*cb) (struct dataset *, void *aux),
151                           void *aux)
152 {
153   struct hmapx_node *node, *next;
154   struct dataset *ds;
155
156   HMAPX_FOR_EACH_SAFE (ds, node, next, &s->datasets)
157     cb (ds, aux);
158 }
159
160 struct dataset *
161 session_get_dataset_by_seqno (const struct session *s, unsigned int seqno)
162 {
163   struct hmapx_node *node;
164   struct dataset *ds;
165
166   HMAPX_FOR_EACH (ds, node, &s->datasets)
167     if (dataset_seqno (ds) == seqno)
168       return ds;
169   return NULL;
170 }
171
172 /* Returns an identifier that is is not currently in use as a dataset name.
173    The caller must free the returned identifier, with free(). */
174 char *
175 session_generate_dataset_name (struct session *s)
176 {
177   for (;;)
178     {
179       char *name;
180
181       s->n_dataset_names++;
182       assert(s->n_dataset_names != 0);
183
184       name = xasprintf ("DataSet%u", s->n_dataset_names);
185       if (!session_lookup_dataset (s, name))
186         return name;
187       free (name);
188     }
189 }
190 \f
191 static struct hmapx_node *
192 session_lookup_dataset__ (const struct session *s_, const char *name)
193 {
194   struct session *s = CONST_CAST (struct session *, s_);
195   struct hmapx_node *node;
196   struct dataset *ds;
197
198   HMAPX_FOR_EACH_WITH_HASH (ds, node, utf8_hash_case_string (name, 0),
199                             &s->datasets)
200     if (!utf8_strcasecmp (dataset_name (ds), name))
201       return node;
202
203   return NULL;
204 }