Doxyfy fileio.h and fileio.c.
[ircu2.10.12-pk.git] / ircd / fileio.c
1 /*
2  * IRC - Internet Relay Chat, ircd/fileio.c
3  * Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
4  * Copyright (C) 1990 Jarkko Oikarinen and
5  *                  University of Oulu, Co Center
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 1, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 /** @file
22  * @brief ANSI FILE* clone API implementation.
23  * @version $Id$
24  */
25 #include "config.h"
26
27 #include "fileio.h"
28 #include "ircd_alloc.h"         /* MyMalloc, MyFree */
29
30 #include <assert.h>             /* assert */
31 #include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
32 #include <stdio.h>              /* BUFSIZ, EOF */
33 #include <sys/stat.h>           /* struct stat */
34 #include <unistd.h>             /* read, write, open, close */
35 #include <string.h>
36
37 #define FB_EOF  0x01            /**< File has reached EOF. */
38 #define FB_FAIL 0x02            /**< File operation failed. */
39
40 /** Tracks status and buffer for a file on disk. */
41 struct FileBuf {
42   int fd;                       /**< file descriptor */
43   char *endp;                   /**< one past the end */
44   char *ptr;                    /**< current read pos */
45   int flags;                    /**< file state */
46   char buf[BUFSIZ];             /**< buffer */
47 };
48
49 /** Open a new FBFILE.
50  * @param[in] filename Name of file to open.
51  * @param[in] mode fopen()-style mode string.
52  * @return Pointer to newly allocated FBFILE.
53  */
54 FBFILE* fbopen(const char *filename, const char *mode)
55 {
56   int openmode = 0;
57   int pmode = 0;
58   FBFILE *fb = NULL;
59   int fd;
60   assert(filename);
61   assert(mode);
62
63   while (*mode) {
64     switch (*mode) {
65     case 'r':
66       openmode = O_RDONLY;
67       break;
68     case 'w':
69       openmode = O_WRONLY | O_CREAT | O_TRUNC;
70       pmode = S_IREAD | S_IWRITE;
71       break;
72     case 'a':
73       openmode = O_WRONLY | O_CREAT | O_APPEND;
74       pmode = S_IREAD | S_IWRITE;
75       break;
76     case '+':
77       openmode &= ~(O_RDONLY | O_WRONLY);
78       openmode |= O_RDWR;
79       break;
80     default:
81       break;
82     }
83     ++mode;
84   }
85   /*
86    * stop NFS hangs...most systems should be able to open a file in
87    * 3 seconds. -avalon (curtesy of wumpus)
88    */
89   alarm(3);
90   if ((fd = open(filename, openmode, pmode)) == -1) {
91     alarm(0);
92     return fb;
93   }
94   alarm(0);
95
96   if (NULL == (fb = fdbopen(fd, NULL)))
97     close(fd);
98   return fb;
99 }
100
101 /** Open a FBFILE from a file descriptor.
102  * @param[in] fd File descriptor to use.
103  * @param[in] mode fopen()-style mode string (ignored).
104  */
105 FBFILE* fdbopen(int fd, const char *mode)
106 {
107   /*
108    * ignore mode, if file descriptor hasn't been opened with the
109    * correct mode, the first use will fail
110    */
111   FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
112   assert(0 != fb);
113   fb->ptr   = fb->endp = fb->buf;
114   fb->fd    = fd;
115   fb->flags = 0;
116
117   return fb;
118 }
119
120 /** Close a FBFILE.
121  * @param[in] fb File buffer to close.
122  */
123 void fbclose(FBFILE* fb)
124 {
125   assert(fb);
126   close(fb->fd);
127   MyFree(fb);
128 }
129
130 /** Attempt to fill a file's buffer.
131  * @param[in] fb File to operate on.
132  * @return Number of bytes read into buffer, or a negative number on error.
133  */
134 static int fbfill(FBFILE * fb)
135 {
136   int n;
137   assert(fb);
138   if (fb->flags)
139     return -1;
140   n = read(fb->fd, fb->buf, BUFSIZ);
141   if (0 < n)
142   {
143     fb->ptr = fb->buf;
144     fb->endp = fb->buf + n;
145   }
146   else if (n < 0)
147     fb->flags |= FB_FAIL;
148   else
149     fb->flags |= FB_EOF;
150   return n;
151 }
152
153 /** Get a single character from a file.
154  * @param[in] fb File to fetch from.
155  * @return Character value read, or EOF on error or end-of-file.
156  */
157 int fbgetc(FBFILE * fb)
158 {
159   assert(fb);
160   if (fb->ptr < fb->endp || fbfill(fb) > 0)
161     return *fb->ptr++;
162   return EOF;
163 }
164
165 /** Get a line of input from a file.
166  * @param[out] buf Output buffer to read to.
167  * @param[in] len Maximum number of bytes to write to buffer
168  * (including terminating NUL).
169  * @param[in] fb File to read from.
170  */
171 char *fbgets(char *buf, size_t len, FBFILE * fb)
172 {
173   char *p = buf;
174   assert(buf);
175   assert(fb);
176   assert(0 < len);
177
178   if (fb->ptr == fb->endp && fbfill(fb) < 1)
179     return 0;
180   --len;
181   while (len--) {
182     *p = *fb->ptr++;
183     if ('\n' == *p)
184     {
185       ++p;
186       break;
187     }
188     /*
189      * deal with CR's
190      */
191     else if ('\r' == *p) {
192       if (fb->ptr < fb->endp || fbfill(fb) > 0) {
193         if ('\n' == *fb->ptr)
194           ++fb->ptr;
195       }
196       *p++ = '\n';
197       break;
198     }
199     ++p;
200     if (fb->ptr == fb->endp && fbfill(fb) < 1)
201       break;
202   }
203   *p = '\0';
204   return buf;
205 }
206
207 /** Write a string to a file.
208  * @param[in] str String to write to file.
209  * @param[in] fb File to write to.
210  * @return Number of bytes written, or -1 on error.
211  */
212 int fbputs(const char *str, FBFILE * fb)
213 {
214   int n = -1;
215   assert(str);
216   assert(fb);
217
218   if (0 == fb->flags) {
219     n = write(fb->fd, str, strlen(str));
220     if (-1 == n)
221       fb->flags |= FB_FAIL;
222   }
223   return n;
224 }
225
226 /** Get file status.
227  * @param[out] sb Receives file status.
228  * @param[in] fb File to get status for.
229  * @return Zero on success, -1 on error.
230  */
231 int fbstat(struct stat *sb, FBFILE * fb)
232 {
233   assert(sb);
234   assert(fb);
235   return fstat(fb->fd, sb);
236 }
237