412c3e7aa8eedc5c7245abde094949102c6cf1fa
[pspp] / 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 /* Frees all the file handles. */
70 void 
71 fh_done (void)
72 {
73   struct file_handle *fh, *next;
74   
75   for (fh = file_handles; fh != NULL; fh = next)
76     {
77       next = fh->next;
78       free (fh->name);
79       free (fh->filename);
80       fn_free_identity (fh->identity);
81       free (fh);
82     }
83   file_handles = NULL;
84 }
85
86 /* Returns the handle named HANDLE_NAME, or a null pointer if
87    there is none. */
88 struct file_handle *
89 fh_from_name (const char *handle_name) 
90 {
91   struct file_handle *iter;
92
93   for (iter = file_handles; iter != NULL; iter = iter->next)
94     if (!strcasecmp (handle_name, iter->name))
95       return iter;
96   return NULL;
97 }
98
99 /* Returns the handle for the file named FILENAME,
100    or a null pointer if none exists.
101    Different names for the same file (e.g. "x" and "./x") are
102    considered equivalent. */
103 struct file_handle *
104 fh_from_filename (const char *filename)
105 {
106   struct file_identity *identity;
107   struct file_handle *iter;
108       
109   /* First check for a file with the same identity. */
110   identity = fn_get_identity (filename);
111   if (identity != NULL) 
112     {
113       for (iter = file_handles; iter != NULL; iter = iter->next)
114         if (iter->identity != NULL
115             && !fn_compare_file_identities (identity, iter->identity))
116           {
117             fn_free_identity (identity);
118             return iter; 
119           }
120       fn_free_identity (identity);
121     }
122
123   /* Then check for a file with the same name. */
124   for (iter = file_handles; iter != NULL; iter = iter->next)
125     if (!strcmp (filename, iter->filename))
126       return iter; 
127
128   return NULL;
129 }
130
131 /* Creates and returns a new file handle with the given values
132    and defaults for other values.  Adds the created file handle
133    to the global list. */
134 struct file_handle *
135 fh_create (const char *handle_name, const char *filename,
136            const struct fh_properties *properties)
137 {
138   struct file_handle *handle;
139
140   /* Create and initialize file handle. */
141   handle = xmalloc (sizeof *handle);
142   handle->next = file_handles;
143   handle->name = xstrdup (handle_name);
144   handle->filename = xstrdup (filename);
145   handle->identity = fn_get_identity (filename);
146   handle->where.filename = handle->filename;
147   handle->where.line_number = 0;
148   handle->mode = properties->mode;
149   handle->record_width = properties->record_width;
150   handle->tab_width = properties->tab_width;
151   handle->open_cnt = 0;
152   handle->type = NULL;
153   handle->aux = NULL;
154   file_handles = handle;
155
156   return handle;
157 }
158
159 /* Returns a set of default properties for a file handle. */
160 const struct fh_properties *
161 fh_default_properties (void)
162 {
163   static const struct fh_properties default_properties = {MODE_TEXT, 1024, 4};
164   return &default_properties;
165 }
166
167 /* Returns an English description of MODE,
168    which is in the format of the MODE argument to fh_open(). */
169 static const char *
170 mode_name (const char *mode) 
171 {
172   assert (mode != NULL);
173   assert (mode[0] == 'r' || mode[0] == 'w');
174
175   return mode[0] == 'r' ? "reading" : "writing";
176 }
177
178 /* Tries to open handle H with the given TYPE and MODE.
179
180    TYPE is the sort of file, e.g. "system file".  Only one given
181    type of access is allowed on a given file handle at once.
182
183    MODE combines the read or write mode with the sharing mode.
184    The first character is 'r' for read, 'w' for write.  The
185    second character is 's' to permit sharing, 'e' to require
186    exclusive access.
187
188    Returns the address of a void * that the caller can use for
189    data specific to the file handle if successful, or a null
190    pointer on failure.  For exclusive access modes the void *
191    will always be a null pointer at return.  In shared access
192    modes the void * will necessarily be null only if no other
193    sharers are active.
194
195    If successful, a reference to type is retained, so it should
196    probably be a string literal. */
197 void **
198 fh_open (struct file_handle *h, const char *type, const char *mode) 
199 {
200   assert (h != NULL);
201   assert (type != NULL);
202   assert (mode != NULL);
203   assert (mode[0] == 'r' || mode[0] == 'w');
204   assert (mode[1] == 's' || mode[1] == 'e');
205   assert (mode[2] == '\0');
206
207   if (h->open_cnt != 0) 
208     {
209       if (strcmp (h->type, type)) 
210         {
211           msg (SE, _("Can't open %s as a %s because it is "
212                      "already open as a %s"),
213                fh_get_name (h), type, h->type);
214           return NULL; 
215         }
216       else if (strcmp (h->open_mode, mode)) 
217         {
218           msg (SE, _("Can't open %s as a %s for %s because it is "
219                      "already open for %s"),
220                fh_get_name (h), type, mode_name (mode),
221                mode_name (h->open_mode));
222           return NULL;
223         }
224       else if (h->open_mode[1] == 'e')
225         {
226           msg (SE, _("Can't re-open %s as a %s for %s"),
227                fh_get_name (h), type, mode_name (mode));
228           return NULL;
229         }
230     }
231   else 
232     {
233       h->type = type;
234       strcpy (h->open_mode, mode);
235       assert (h->aux == NULL);
236     }
237   h->open_cnt++;
238
239   return &h->aux;
240 }
241
242 /* Closes file handle H, which must have been open for the
243    specified TYPE and MODE of access provided to fh_open().
244    Returns zero if the file is now closed, nonzero if it is still
245    open due to another reference. */
246 int
247 fh_close (struct file_handle *h, const char *type, const char *mode)
248 {
249   assert (h != NULL);
250   assert (h->open_cnt > 0);
251   assert (type != NULL);
252   assert (!strcmp (type, h->type));
253   assert (mode != NULL);
254   assert (!strcmp (mode, h->open_mode));
255
256   h->open_cnt--;
257   if (h->open_cnt == 0) 
258     {
259       h->type = NULL;
260       h->aux = NULL;
261     }
262   return h->open_cnt;
263 }
264
265 /* Returns the identifier of file HANDLE.  If HANDLE was created
266    by referring to a filename instead of a handle name, returns
267    the filename, enclosed in double quotes.  Return value is
268    owned by the file handle. 
269
270    Useful for printing error messages about use of file handles.  */
271 const char *
272 fh_get_name (const struct file_handle *handle)
273 {
274   assert (handle != NULL);
275   return handle->name;
276 }
277
278 /* Returns the name of the file associated with HANDLE. */
279 const char *
280 fh_get_filename (const struct file_handle *handle) 
281 {
282   assert (handle != NULL);
283   return handle->filename;
284 }
285
286 /* Returns the mode of HANDLE. */
287 enum fh_mode
288 fh_get_mode (const struct file_handle *handle) 
289 {
290   assert (handle != NULL);
291   return handle->mode;
292 }
293
294 /* Returns the width of a logical record on HANDLE. */
295 size_t
296 fh_get_record_width (const struct file_handle *handle)
297 {
298   assert (handle != NULL);
299   return handle->record_width;
300 }
301
302 /* Returns the number of characters per tab stop for HANDLE, or
303    zero if tabs are not to be expanded.  Applicable only to
304    MODE_TEXT files. */
305 size_t
306 fh_get_tab_width (const struct file_handle *handle) 
307 {
308   assert (handle != NULL);
309   return handle->tab_width;
310 }