1/* -----------------------------------------------------------------------------
2 * file.c
3 *
4 *     This file implements a file-like object that can be built around an
5 *     ordinary FILE * or integer file descriptor.
6 *
7 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
8 *
9 * Copyright (C) 1999-2000.  The University of Chicago
10 * See the file LICENSE for information on usage and redistribution.
11 * ----------------------------------------------------------------------------- */
12
13char cvsroot_file_c[] = "$Id: file.c 10898 2008-11-03 12:51:45Z wsfulton $";
14
15#include "dohint.h"
16
17#ifdef DOH_INTFILE
18#include <unistd.h>
19#endif
20#include <errno.h>
21
22typedef struct {
23  FILE *filep;
24  int fd;
25  int closeondel;
26} DohFile;
27
28/* -----------------------------------------------------------------------------
29 * DelFile()
30 * ----------------------------------------------------------------------------- */
31
32static void DelFile(DOH *fo) {
33  DohFile *f = (DohFile *) ObjData(fo);
34  if (f->closeondel) {
35    if (f->filep) {
36      fclose(f->filep);
37    }
38#ifdef DOH_INTFILE
39    if (f->fd) {
40      close(f->fd);
41    }
42#endif
43  }
44  DohFree(f);
45}
46
47/* -----------------------------------------------------------------------------
48 * File_read()
49 * ----------------------------------------------------------------------------- */
50
51static int File_read(DOH *fo, void *buffer, int len) {
52  DohFile *f = (DohFile *) ObjData(fo);
53
54  if (f->filep) {
55    return fread(buffer, 1, len, f->filep);
56  } else if (f->fd) {
57#ifdef DOH_INTFILE
58    return read(f->fd, buffer, len);
59#endif
60  }
61  return -1;
62}
63
64/* -----------------------------------------------------------------------------
65 * File_write()
66 * ----------------------------------------------------------------------------- */
67
68static int File_write(DOH *fo, void *buffer, int len) {
69  DohFile *f = (DohFile *) ObjData(fo);
70  if (f->filep) {
71    int ret = (int) fwrite(buffer, 1, len, f->filep);
72    int err = (ret != len) ? ferror(f->filep) : 0;
73    return err ? -1 : ret;
74  } else if (f->fd) {
75#ifdef DOH_INTFILE
76    return write(f->fd, buffer, len);
77#endif
78  }
79  return -1;
80}
81
82/* -----------------------------------------------------------------------------
83 * File_seek()
84 * ----------------------------------------------------------------------------- */
85
86static int File_seek(DOH *fo, long offset, int whence) {
87  DohFile *f = (DohFile *) ObjData(fo);
88  if (f->filep) {
89    return fseek(f->filep, offset, whence);
90  } else if (f->fd) {
91#ifdef DOH_INTFILE
92    return lseek(f->fd, offset, whence);
93#endif
94  }
95  return -1;
96}
97
98/* -----------------------------------------------------------------------------
99 * File_tell()
100 * ----------------------------------------------------------------------------- */
101
102static long File_tell(DOH *fo) {
103  DohFile *f = (DohFile *) ObjData(fo);
104  if (f->filep) {
105    return ftell(f->filep);
106  } else if (f->fd) {
107#ifdef DOH_INTFILE
108    return lseek(f->fd, 0, SEEK_CUR);
109#endif
110  }
111  return -1;
112}
113
114/* -----------------------------------------------------------------------------
115 * File_putc()
116 * ----------------------------------------------------------------------------- */
117
118static int File_putc(DOH *fo, int ch) {
119  DohFile *f = (DohFile *) ObjData(fo);
120  if (f->filep) {
121    return fputc(ch, f->filep);
122  } else if (f->fd) {
123#ifdef DOH_INTFILE
124    char c;
125    c = (char) ch;
126    return write(f->fd, &c, 1);
127#endif
128  }
129  return -1;
130}
131
132/* -----------------------------------------------------------------------------
133 * File_getc()
134 * ----------------------------------------------------------------------------- */
135
136static int File_getc(DOH *fo) {
137  DohFile *f = (DohFile *) ObjData(fo);
138  if (f->filep) {
139    return fgetc(f->filep);
140  } else if (f->fd) {
141#ifdef DOH_INTFILE
142    unsigned char c;
143    if (read(f->fd, &c, 1) < 0)
144      return EOF;
145    return c;
146#endif
147  }
148  return EOF;
149}
150
151/* -----------------------------------------------------------------------------
152 * File_ungetc()
153 *
154 * Put a character back onto the input
155 * ----------------------------------------------------------------------------- */
156
157static int File_ungetc(DOH *fo, int ch) {
158  DohFile *f = (DohFile *) ObjData(fo);
159  if (f->filep) {
160    return ungetc(ch, f->filep);
161  } else if (f->fd) {
162#ifdef DOH_INTFILE
163    /* Not implemented yet */
164#endif
165  }
166  return -1;
167}
168
169/* -----------------------------------------------------------------------------
170 * File_close()
171 *
172 * Close the file
173 * ----------------------------------------------------------------------------- */
174
175static int File_close(DOH *fo) {
176  int ret = 0;
177  DohFile *f = (DohFile *) ObjData(fo);
178  if (f->filep) {
179    ret = fclose(f->filep);
180    f->filep = 0;
181  } else if (f->fd) {
182#ifdef DOH_INTFILE
183    ret = close(f->fd);
184    f->fd = 0;
185#endif
186  }
187  return ret;
188}
189
190static DohFileMethods FileFileMethods = {
191  File_read,
192  File_write,
193  File_putc,
194  File_getc,
195  File_ungetc,
196  File_seek,
197  File_tell,
198  File_close,			/* close */
199};
200
201static DohObjInfo DohFileType = {
202  "DohFile",			/* objname      */
203  DelFile,			/* doh_del      */
204  0,				/* doh_copy     */
205  0,				/* doh_clear    */
206  0,				/* doh_str      */
207  0,				/* doh_data     */
208  0,				/* doh_dump     */
209  0,				/* doh_len      */
210  0,				/* doh_hash     */
211  0,				/* doh_cmp      */
212  0,				/* doh_equal    */
213  0,				/* doh_first    */
214  0,				/* doh_next     */
215  0,				/* doh_setfile  */
216  0,				/* doh_getfile  */
217  0,				/* doh_setline  */
218  0,				/* doh_getline  */
219  0,				/* doh_mapping  */
220  0,				/* doh_sequence */
221  &FileFileMethods,		/* doh_file     */
222  0,				/* doh_string   */
223  0,				/* doh_callable */
224  0,				/* doh_position */
225};
226
227/* -----------------------------------------------------------------------------
228 * NewFile()
229 *
230 * Create a new file from a given filename and mode.
231 * If newfiles is non-zero, the filename is added to the list of new files.
232 * ----------------------------------------------------------------------------- */
233
234DOH *DohNewFile(DOH *filename, const char *mode, DOHList *newfiles) {
235  DohFile *f;
236  FILE *file;
237  char *filen;
238
239  filen = Char(filename);
240  file = fopen(filen, mode);
241  if (!file)
242    return 0;
243
244  f = (DohFile *) DohMalloc(sizeof(DohFile));
245  if (!f) {
246    fclose(file);
247    return 0;
248  }
249  if (newfiles)
250    Append(newfiles, filename);
251  f->filep = file;
252  f->fd = 0;
253  f->closeondel = 1;
254  return DohObjMalloc(&DohFileType, f);
255}
256
257/* -----------------------------------------------------------------------------
258 * NewFileFromFile()
259 *
260 * Create a file object from an already open FILE *.
261 * ----------------------------------------------------------------------------- */
262
263DOH *DohNewFileFromFile(FILE *file) {
264  DohFile *f;
265  f = (DohFile *) DohMalloc(sizeof(DohFile));
266  if (!f)
267    return 0;
268  f->filep = file;
269  f->fd = 0;
270  f->closeondel = 0;
271  return DohObjMalloc(&DohFileType, f);
272}
273
274/* -----------------------------------------------------------------------------
275 * NewFileFromFd()
276 *
277 * Create a file object from an already open FILE *.
278 * ----------------------------------------------------------------------------- */
279
280DOH *DohNewFileFromFd(int fd) {
281  DohFile *f;
282  f = (DohFile *) DohMalloc(sizeof(DohFile));
283  if (!f)
284    return 0;
285  f->filep = 0;
286  f->fd = fd;
287  f->closeondel = 0;
288  return DohObjMalloc(&DohFileType, f);
289}
290
291/* -----------------------------------------------------------------------------
292 * FileErrorDisplay()
293 *
294 * Display cause of one of the NewFile functions failing.
295 * ----------------------------------------------------------------------------- */
296
297void DohFileErrorDisplay(DOHString * filename) {
298  Printf(stderr, "Unable to open file %s: %s\n", filename, strerror(errno));
299}
300