Improve comment.
[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 /* 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    If successful, a reference to TYPE is retained, so it should
183    probably be a string literal.
184
185    MODE combines the read or write mode with the sharing mode.
186    The first character is 'r' for read, 'w' for write.  The
187    second character is 's' to permit sharing, 'e' to require
188    exclusive access.
189
190    Returns the address of a void * that the caller can use for
191    data specific to the file handle if successful, or a null
192    pointer on failure.  For exclusive access modes the void *
193    will always be a null pointer at return.  In shared access
194    modes the void * will necessarily be null only if no other
195    sharers are active. */
196 void **
197 fh_open (struct file_handle *h, const char *type, const char *mode) 
198 {
199   assert (h != NULL);
200   assert (type != NULL);
201   assert (mode != NULL);
202   assert (mode[0] == 'r' || mode[0] == 'w');
203   assert (mode[1] == 's' || mode[1] == 'e');
204   assert (mode[2] == '\0');
205
206   if (h->open_cnt != 0) 
207     {
208       if (strcmp (h->type, type)) 
209         {
210           msg (SE, _("Can't open %s as a %s because it is "
211                      "already open as a %s"),
212                fh_get_name (h), type, h->type);
213           return NULL; 
214         }
215       else if (strcmp (h->open_mode, mode)) 
216         {
217           msg (SE, _("Can't open %s as a %s for %s because it is "
218                      "already open for %s"),
219                fh_get_name (h), type, mode_name (mode),
220                mode_name (h->open_mode));
221           return NULL;
222         }
223       else if (h->open_mode[1] == 'e')
224         {
225           msg (SE, _("Can't re-open %s as a %s for %s"),
226                fh_get_name (h), type, mode_name (mode));
227           return NULL;
228         }
229     }
230   else 
231     {
232       h->type = type;
233       strcpy (h->open_mode, mode);
234       assert (h->aux == NULL);
235     }
236   h->open_cnt++;
237
238   return &h->aux;
239 }
240
241 /* Closes file handle H, which must have been open for the
242    specified TYPE and MODE of access provided to fh_open().
243    Returns zero if the file is now closed, nonzero if it is still
244    open due to another reference. */
245 int
246 fh_close (struct file_handle *h, const char *type, const char *mode)
247 {
248   assert (h != NULL);
249   assert (h->open_cnt > 0);
250   assert (type != NULL);
251   assert (!strcmp (type, h->type));
252   assert (mode != NULL);
253   assert (!strcmp (mode, h->open_mode));
254
255   h->open_cnt--;
256   if (h->open_cnt == 0) 
257     {
258       h->type = NULL;
259       h->aux = NULL;
260     }
261   return h->open_cnt;
262 }
263
264 /* Returns the identifier of file HANDLE.  If HANDLE was created
265    by referring to a filename instead of a handle name, returns
266    the filename, enclosed in double quotes.  Return value is
267    owned by the file handle. 
268
269    Useful for printing error messages about use of file handles.  */
270 const char *
271 fh_get_name (const struct file_handle *handle)
272 {
273   assert (handle != NULL);
274   return handle->name;
275 }
276
277 /* Returns the name of the file associated with HANDLE. */
278 const char *
279 fh_get_filename (const struct file_handle *handle) 
280 {
281   assert (handle != NULL);
282   return handle->filename;
283 }
284
285 /* Returns the mode of HANDLE. */
286 enum fh_mode
287 fh_get_mode (const struct file_handle *handle) 
288 {
289   assert (handle != NULL);
290   return handle->mode;
291 }
292
293 /* Returns the width of a logical record on HANDLE. */
294 size_t
295 fh_get_record_width (const struct file_handle *handle)
296 {
297   assert (handle != NULL);
298   return handle->record_width;
299 }
300
301 /* Returns the number of characters per tab stop for HANDLE, or
302    zero if tabs are not to be expanded.  Applicable only to
303    MODE_TEXT files. */
304 size_t
305 fh_get_tab_width (const struct file_handle *handle) 
306 {
307   assert (handle != NULL);
308   return handle->tab_width;
309 }