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