Separated the abstraction of a file handle, from its implementation and
[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 "error.h"
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "alloc.h"
27 #include "filename.h"
28 #include "command.h"
29 #include "getl.h"
30 #include "error.h"
31 #include "magic.h"
32 #include "var.h"
33 #include "file-handle-def.h"
34
35 #include "gettext.h"
36
37 #define _(msgid) gettext (msgid)
38
39 /* (headers) */
40
41 /* File handle. */
42 struct file_handle 
43   {
44     struct file_handle *next;   /* Next in global list. */
45     char *name;                 /* File handle identifier. */
46     char *filename;             /* Filename as provided by user. */
47     struct file_identity *identity; /* For checking file identity. */
48     struct file_locator where;  /* Used for reporting error messages. */
49     enum file_handle_mode mode; /* File mode. */
50     size_t length;              /* Length of fixed-format records. */
51     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
52
53     int open_cnt;               /* 0=not open, otherwise # of openers. */
54     const char *type;           /* If open, type of file. */
55     char open_mode[3];          /* "[rw][se]". */
56     void *aux;                  /* Aux data pointer for owner if any. */
57   };
58
59
60 static struct file_handle *file_handles;
61
62
63 struct file_handle *
64 get_handle_with_name (const char *handle_name) 
65 {
66   struct file_handle *iter;
67
68   for (iter = file_handles; iter != NULL; iter = iter->next)
69     if (!strcasecmp (handle_name, iter->name))
70       return iter;
71   return NULL;
72 }
73
74 struct file_handle *
75 get_handle_for_filename (const char *filename)
76 {
77   struct file_identity *identity;
78   struct file_handle *iter;
79       
80   /* First check for a file with the same identity. */
81   identity = fn_get_identity (filename);
82   if (identity != NULL) 
83     {
84       for (iter = file_handles; iter != NULL; iter = iter->next)
85         if (iter->identity != NULL
86             && !fn_compare_file_identities (identity, iter->identity))
87           {
88             fn_free_identity (identity);
89             return iter; 
90           }
91       fn_free_identity (identity);
92     }
93
94   /* Then check for a file with the same name. */
95   for (iter = file_handles; iter != NULL; iter = iter->next)
96     if (!strcmp (filename, iter->filename))
97       return iter; 
98
99   return NULL;
100 }
101
102
103 /* File handle functions. */
104
105 struct file_handle *
106 create_file_handle_with_defaults (const char *handle_name, 
107                                   const char *filename)
108 {
109   return create_file_handle (handle_name, filename, 
110                              MODE_TEXT,1024, 4);
111 }
112
113
114 /* Creates and returns a new file handle with the given values
115    and defaults for other values.  Adds the created file handle
116    to the global list. */
117 struct file_handle *
118 create_file_handle (const char *handle_name, const char *filename,
119                     enum file_handle_mode mode,
120                     size_t length,
121                     size_t tab_width
122                     )
123 {
124   struct file_handle *handle;
125
126   /* Create and initialize file handle. */
127   handle = xmalloc (sizeof *handle);
128   handle->next = file_handles;
129   handle->name = xstrdup (handle_name);
130   handle->filename = xstrdup (filename);
131   handle->identity = fn_get_identity (filename);
132   handle->where.filename = handle->filename;
133   handle->where.line_number = 0;
134   handle->mode = mode;
135   handle->length = length;
136   handle->tab_width = tab_width;
137   handle->open_cnt = 0;
138   handle->type = NULL;
139   handle->aux = NULL;
140   file_handles = handle;
141
142   return handle;
143 }
144
145 void
146 destroy_file_handle(void *fh_, void *aux UNUSED)
147 {
148   struct file_handle *fh = fh_;
149   free (fh->name);
150   free (fh->filename);
151   fn_free_identity (fh->identity);
152   free (fh);
153 }
154
155 static const char *
156 mode_name (const char *mode) 
157 {
158   assert (mode != NULL);
159   assert (mode[0] == 'r' || mode[0] == 'w');
160
161   return mode[0] == 'r' ? "reading" : "writing";
162 }
163
164
165 /* Tries to open handle H with the given TYPE and MODE.
166
167    TYPE is the sort of file, e.g. "system file".  Only one given
168    type of access is allowed on a given file handle at once.
169
170    MODE combines the read or write mode with the sharing mode.
171    The first character is 'r' for read, 'w' for write.  The
172    second character is 's' to permit sharing, 'e' to require
173    exclusive access.
174
175    Returns the address of a void * that the caller can use for
176    data specific to the file handle if successful, or a null
177    pointer on failure.  For exclusive access modes the void *
178    will always be a null pointer at return.  In shared access
179    modes the void * will necessarily be null only if no other
180    sharers are active.
181
182    If successful, a reference to type is retained, so it should
183    probably be a string literal. */
184 void **
185 fh_open (struct file_handle *h, const char *type, const char *mode) 
186 {
187   assert (h != NULL);
188   assert (type != NULL);
189   assert (mode != NULL);
190   assert (mode[0] == 'r' || mode[0] == 'w');
191   assert (mode[1] == 's' || mode[1] == 'e');
192   assert (mode[2] == '\0');
193
194   if (h->open_cnt != 0) 
195     {
196       if (strcmp (h->type, type)) 
197         {
198           msg (SE, _("Can't open %s as a %s because it is "
199                      "already open as a %s"),
200                handle_get_name (h), type, h->type);
201           return NULL; 
202         }
203       else if (strcmp (h->open_mode, mode)) 
204         {
205           msg (SE, _("Can't open %s as a %s for %s because it is "
206                      "already open for %s"),
207                handle_get_name (h), type,
208                mode_name (mode), mode_name (h->open_mode));
209           return NULL;
210         }
211       else if (h->open_mode[1] == 'e')
212         {
213           msg (SE, _("Can't re-open %s as a %s for %s"),
214                handle_get_name (h), type, mode_name (mode));
215           return NULL;
216         }
217     }
218   else 
219     {
220       h->type = type;
221       strcpy (h->open_mode, mode);
222       assert (h->aux == NULL);
223     }
224   h->open_cnt++;
225
226   return &h->aux;
227 }
228
229 /* Closes file handle H, which must have been open for the
230    specified TYPE and MODE of access provided to fh_open().
231    Returns zero if the file is now closed, nonzero if it is still
232    open due to another reference. */
233 int
234 fh_close (struct file_handle *h, const char *type, const char *mode)
235 {
236   assert (h != NULL);
237   assert (h->open_cnt > 0);
238   assert (type != NULL);
239   assert (!strcmp (type, h->type));
240   assert (mode != NULL);
241   assert (!strcmp (mode, h->open_mode));
242
243   h->open_cnt--;
244   if (h->open_cnt == 0) 
245     {
246       h->type = NULL;
247       h->aux = NULL;
248     }
249   return h->open_cnt;
250 }
251
252
253
254
255 /* Returns the identifier of file HANDLE.  If HANDLE was created
256    by referring to a filename instead of a handle name, returns
257    the filename, enclosed in double quotes.  Return value is
258    owned by the file handle. 
259
260    Useful for printing error messages about use of file handles.  */
261 const char *
262 handle_get_name (const struct file_handle *handle)
263 {
264   assert (handle != NULL);
265   return handle->name;
266 }
267
268 /* Returns the name of the file associated with HANDLE. */
269 const char *
270 handle_get_filename (const struct file_handle *handle) 
271 {
272   assert (handle != NULL);
273   return handle->filename;
274 }
275
276 /* Returns the mode of HANDLE. */
277 enum file_handle_mode
278 handle_get_mode (const struct file_handle *handle) 
279 {
280   assert (handle != NULL);
281   return handle->mode;
282 }
283
284 /* Returns the width of a logical record on HANDLE. */
285 size_t
286 handle_get_record_width (const struct file_handle *handle)
287 {
288   assert (handle != NULL);
289   return handle->length;
290 }
291
292 /* Returns the number of characters per tab stop for HANDLE, or
293    zero if tabs are not to be expanded.  Applicable only to
294    MODE_TEXT files. */
295 size_t
296 handle_get_tab_width (const struct file_handle *handle) 
297 {
298   assert (handle != NULL);
299   return handle->tab_width;
300 }
301