605d1dd942a248f0fdc3bdda53ade1228ed79c15
[pspp-builds.git] / src / file-handle-def.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "file-handle.h"
22 #include "file-handle-def.h"
23 #include "error.h"
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "alloc.h"
28 #include "filename.h"
29 #include "command.h"
30 #include "getl.h"
31 #include "error.h"
32 #include "magic.h"
33 #include "var.h"
34 #include "file-handle-def.h"
35
36 #include "gettext.h"
37
38 #define _(msgid) gettext (msgid)
39
40 /* (headers) */
41
42 /* File handle. */
43 struct file_handle 
44   {
45     struct file_handle *next;   /* Next in global list. */
46     char *name;                 /* File handle identifier. */
47     char *filename;             /* Filename as provided by user. */
48     struct file_identity *identity; /* For checking file identity. */
49     struct file_locator where;  /* Used for reporting error messages. */
50     enum fh_mode mode;          /* File mode. */
51     size_t record_width;        /* Length of fixed-format records. */
52     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
53
54     int open_cnt;               /* 0=not open, otherwise # of openers. */
55     const char *type;           /* If open, type of file. */
56     char open_mode[3];          /* "[rw][se]". */
57     void *aux;                  /* Aux data pointer for owner if any. */
58   };
59
60 static struct file_handle *file_handles;
61
62 /* File handle initialization routine. */
63 void 
64 fh_init (void)
65 {
66   /* Currently nothing to do. */
67 }
68
69
70 /* Destroy file handle.
71    Normally needed only if a file_handle needs to be re-assigned.
72    Otherwise, just let fh_done clean destroy the handle.
73  */
74 void 
75 fh_free(struct file_handle *fh)
76 {
77   if ( !fh->name ) 
78     return ;
79
80   free (fh->name);
81   fh->name = 0;
82   free (fh->filename);
83   fn_free_identity (fh->identity);
84   free (fh);
85 }
86
87
88 /* Frees all the file handles. */
89 void 
90 fh_done (void)
91 {
92   struct file_handle *fh, *next;
93   
94   for (fh = file_handles; fh != NULL; fh = next)
95     {
96       next = fh->next;
97       fh_free(fh);
98     }
99   file_handles = NULL;
100 }
101
102 /* Returns the handle named HANDLE_NAME, or a null pointer if
103    there is none. */
104 struct file_handle *
105 fh_from_name (const char *handle_name) 
106 {
107   struct file_handle *iter;
108
109   for (iter = file_handles; iter != NULL; iter = iter->next)
110     if (!strcasecmp (handle_name, iter->name))
111       return iter;
112   return NULL;
113 }
114
115 /* Returns the handle for the file named FILENAME,
116    or a null pointer if none exists.
117    Different names for the same file (e.g. "x" and "./x") are
118    considered equivalent. */
119 struct file_handle *
120 fh_from_filename (const char *filename)
121 {
122   struct file_identity *identity;
123   struct file_handle *iter;
124       
125   /* First check for a file with the same identity. */
126   identity = fn_get_identity (filename);
127   if (identity != NULL) 
128     {
129       for (iter = file_handles; iter != NULL; iter = iter->next)
130         if (iter->identity != NULL
131             && !fn_compare_file_identities (identity, iter->identity))
132           {
133             fn_free_identity (identity);
134             return iter; 
135           }
136       fn_free_identity (identity);
137     }
138
139   /* Then check for a file with the same name. */
140   for (iter = file_handles; iter != NULL; iter = iter->next)
141     if (!strcmp (filename, iter->filename))
142       return iter; 
143
144   return NULL;
145 }
146
147 /* Creates and returns a new file handle with the given values
148    and defaults for other values.  Adds the created file handle
149    to the global list. */
150 struct file_handle *
151 fh_create (const char *handle_name, const char *filename,
152            const struct fh_properties *properties)
153 {
154   struct file_handle *handle;
155
156   assert(filename);
157   assert(handle_name);
158
159   /* Create and initialize file handle. */
160   handle = xmalloc (sizeof *handle);
161   handle->next = file_handles;
162   handle->name = xstrdup (handle_name);
163   handle->filename = xstrdup (filename);
164   handle->identity = fn_get_identity (filename);
165   handle->where.filename = handle->filename;
166   handle->where.line_number = 0;
167   handle->mode = properties->mode;
168   handle->record_width = properties->record_width;
169   handle->tab_width = properties->tab_width;
170   handle->open_cnt = 0;
171   handle->type = NULL;
172   handle->aux = NULL;
173   file_handles = handle;
174
175   return handle;
176 }
177
178 /* Returns a set of default properties for a file handle. */
179 const struct fh_properties *
180 fh_default_properties (void)
181 {
182   static const struct fh_properties default_properties = {MODE_TEXT, 1024, 4};
183   return &default_properties;
184 }
185
186 /* Returns an English description of MODE,
187    which is in the format of the MODE argument to fh_open(). */
188 static const char *
189 mode_name (const char *mode) 
190 {
191   assert (mode != NULL);
192   assert (mode[0] == 'r' || mode[0] == 'w');
193
194   return mode[0] == 'r' ? "reading" : "writing";
195 }
196
197 /* Tries to open handle H with the given TYPE and MODE.
198
199    TYPE is the sort of file, e.g. "system file".  Only one given
200    type of access is allowed on a given file handle at once.
201    If successful, a reference to TYPE is retained, so it should
202    probably be a string literal.
203
204    MODE combines the read or write mode with the sharing mode.
205    The first character is 'r' for read, 'w' for write.  The
206    second character is 's' to permit sharing, 'e' to require
207    exclusive access.
208
209    Returns the address of a void * that the caller can use for
210    data specific to the file handle if successful, or a null
211    pointer on failure.  For exclusive access modes the void *
212    will always be a null pointer at return.  In shared access
213    modes the void * will necessarily be null only if no other
214    sharers are active. */
215 void **
216 fh_open (struct file_handle *h, const char *type, const char *mode) 
217 {
218   assert (h != NULL);
219   assert (type != NULL);
220   assert (mode != NULL);
221   assert (mode[0] == 'r' || mode[0] == 'w');
222   assert (mode[1] == 's' || mode[1] == 'e');
223   assert (mode[2] == '\0');
224
225   if (h->open_cnt != 0) 
226     {
227       if (strcmp (h->type, type)) 
228         {
229           msg (SE, _("Can't open %s as a %s because it is "
230                      "already open as a %s"),
231                fh_get_name (h), type, h->type);
232           return NULL; 
233         }
234       else if (strcmp (h->open_mode, mode)) 
235         {
236           msg (SE, _("Can't open %s as a %s for %s because it is "
237                      "already open for %s"),
238                fh_get_name (h), type, mode_name (mode),
239                mode_name (h->open_mode));
240           return NULL;
241         }
242       else if (h->open_mode[1] == 'e')
243         {
244           msg (SE, _("Can't re-open %s as a %s for %s"),
245                fh_get_name (h), type, mode_name (mode));
246           return NULL;
247         }
248     }
249   else 
250     {
251       h->type = type;
252       strcpy (h->open_mode, mode);
253       assert (h->aux == NULL);
254     }
255   h->open_cnt++;
256
257   return &h->aux;
258 }
259
260 /* Closes file handle H, which must have been open for the
261    specified TYPE and MODE of access provided to fh_open().
262    Returns zero if the file is now closed, nonzero if it is still
263    open due to another reference. */
264 int
265 fh_close (struct file_handle *h, const char *type, const char *mode)
266 {
267   assert (h != NULL);
268   assert (h->open_cnt > 0);
269   assert (type != NULL);
270   assert (!strcmp (type, h->type));
271   assert (mode != NULL);
272   assert (!strcmp (mode, h->open_mode));
273
274   h->open_cnt--;
275   if (h->open_cnt == 0) 
276     {
277       h->type = NULL;
278       h->aux = NULL;
279     }
280   return h->open_cnt;
281 }
282
283 /* Returns the identifier of file HANDLE.  If HANDLE was created
284    by referring to a filename instead of a handle name, returns
285    the filename, enclosed in double quotes.  Return value is
286    owned by the file handle. 
287
288    Useful for printing error messages about use of file handles.  */
289 const char *
290 fh_get_name (const struct file_handle *handle)
291 {
292   assert (handle != NULL);
293   return handle->name;
294 }
295
296 /* Returns the name of the file associated with HANDLE. */
297 const char *
298 fh_get_filename (const struct file_handle *handle) 
299 {
300   assert (handle != NULL);
301   return handle->filename;
302 }
303
304 /* Returns the mode of HANDLE. */
305 enum fh_mode
306 fh_get_mode (const struct file_handle *handle) 
307 {
308   assert (handle != NULL);
309   return handle->mode;
310 }
311
312 /* Returns the width of a logical record on HANDLE. */
313 size_t
314 fh_get_record_width (const struct file_handle *handle)
315 {
316   assert (handle != NULL);
317   return handle->record_width;
318 }
319
320 /* Returns the number of characters per tab stop for HANDLE, or
321    zero if tabs are not to be expanded.  Applicable only to
322    MODE_TEXT files. */
323 size_t
324 fh_get_tab_width (const struct file_handle *handle) 
325 {
326   assert (handle != NULL);
327   return handle->tab_width;
328 }