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