1
2 static char rcsid[] = "@(#)$Id: mailfile.c,v 1.4 1998/02/11 22:02:14 wfp5p Exp $";
3
4 /*******************************************************************************
5 * The Elm Mail System - $Revision: 1.4 $ $State: Exp $
6 *
7 * Copyright (c) 1988-1995 USENET Community Trust
8 *******************************************************************************
9 * Bug reports, patches, comments, suggestions should be sent to:
10 *
11 * Bill Pemberton, Elm Coordinator
12 * flash@virginia.edu
13 *
14 *******************************************************************************
15 * $Log: mailfile.c,v $
16 * Revision 1.4 1998/02/11 22:02:14 wfp5p
17 * Beta 2
18 *
19 * Revision 1.3 1995/09/29 17:41:16 wfp5p
20 * Alpha 8 (Chip's big changes)
21 *
22 * Revision 1.2 1995/09/11 15:18:55 wfp5p
23 * Alpha 7
24 *
25 * Revision 1.1 1995/06/22 14:48:36 wfp5p
26 * Performance enhancements from Paul Close
27 *
28 * Revision 1.1.1.1 1995/04/19 20:38:32 wfp5p
29 * Initial import of elm 2.4 PL0 as base for elm 2.5.
30 *
31 ******************************************************************************/
32
33 /**
34
35 A few stdio-type functions reimplemented for performance. This is pretty
36 well tailored to read_headers() in newmbox.c, but it is used a few other
37 places as well.
38
39 mailFile_attach
40 Takes a stdio file descriptor and attaches it to a mailFile.
41
42 mailFile_copy
43 Indicates that a copy is to be made of the input stream into the
44 specified stdio file descriptor. This uses fwrite on large blocks,
45 so it is much more efficient than using fputs on each input line.
46 This is only usable if you want an exact copy, all the way to end
47 of file.
48
49 mailFile_gets
50 Reads a \n terminated string from mailFile, returning the length.
51 Unlike fgets, besides returning the length, this routine returns
52 a pointer into its internal buffer (when possible), avoiding a copy.
53
54 mailFile_tell
55 Returns the current file position.
56
57 mailFile_seek
58 Does an absolute seek to the specified offset. If 'copy' is
59 non-NULL, fseeks there as well. If offset is in the current
60 mailFile buffer, only internal pointers are updated.
61
62 mailFile_detach
63 flushes and frees all buffers, returns control of the file
64 descriptors to stdio. Stdio file position should be treated as
65 undefined after this call.
66
67 internal:
68
69 refill
70 Refills the mailFile buffer, and writes the buffer to 'copy',
71 if non-NULL.
72
73 **/
74
75 #include "elm_defs.h"
76 #include "mailfile.h"
77
78 static int refill();
79
80 void
mailFile_attach(mailfile,filedes)81 mailFile_attach(mailfile, filedes)
82 struct mailFile *mailfile;
83 FILE *filedes;
84 {
85 mailfile->filedes = filedes;
86 mailfile->buffer = malloc(MAILFILE_BSIZE+1);
87 mailfile->offset = NULL;
88 mailfile->remain = 0;
89 mailfile->savechar = -1;
90 mailfile->charsaved = 0;
91 mailfile->copy = NULL;
92 mailfile->error = NULL;
93 }
94
95 void
mailFile_copy(mailfile,filedes,error)96 mailFile_copy(mailfile, filedes, error)
97 struct mailFile *mailfile;
98 FILE *filedes;
99 void (*error)();
100 {
101 mailfile->copy = filedes;
102 mailfile->error = error;
103 }
104
105 int
mailFile_gets(buffer,mailfile)106 mailFile_gets(buffer, mailfile)
107 char **buffer;
108 struct mailFile *mailfile;
109 {
110 register char *c;
111 register int n, loops, m;
112 char *p;
113 int size;
114 /* static char vlongstring[VERY_LONG_STRING];*/
115 static char vlongstring[MAILFILE_BSIZE];
116
117
118 if (mailfile->charsaved) {
119 *(mailfile->offset) = mailfile->savechar;
120 mailfile->charsaved = 0;
121 }
122 if (mailfile->remain <= 0)
123 if (refill(mailfile) == 0)
124 return 0;
125
126 /* search for '\n', but allow '\0' (so can't use index) */
127 p = mailfile->offset;
128 n = mailfile->remain-1;
129 loops = n / 4;
130 if (loops > 0) {
131 do {
132 if (p[0] == '\n') break;
133 if (p[1] == '\n') {p++; break;}
134 if (p[2] == '\n') {p+=2; break;}
135 if (p[3] == '\n') {p+=3; break;}
136 p += 4;
137 } while (--loops != 0);
138 }
139 if (*p != '\n' && (m=n%4)) {
140 do {
141 if (*p == '\n') break;
142 p++;
143 } while (--m != 0);
144 }
145
146 if (*p == '\n') {
147 p++;
148 mailfile->savechar = *p;
149 mailfile->charsaved = 1;
150 *p = '\0';
151 n = p - mailfile->offset;
152 (*buffer) = mailfile->offset;
153 mailfile->offset += n;
154 mailfile->remain -= n;
155 return n;
156 }
157
158 /* else string spans buffer; must copy */
159
160 size = VERY_LONG_STRING - mailfile->remain;
161 (*buffer) = vlongstring;
162 memcpy(vlongstring, mailfile->offset, mailfile->remain);
163 size = VERY_LONG_STRING - mailfile->remain;
164 c = vlongstring + mailfile->remain;
165 mailfile->offset += mailfile->remain;
166 mailfile->remain = 0;
167
168 size--; /* allow room for zero terminator on end, just in case */
169
170 while (size > 0) {
171 if (mailfile->remain <= 0) { /* empty buffer */
172 if (refill(mailfile) == 0) { /* EOF or error */
173 if (c > (*buffer) && *c != '\n')
174 *++c = '\n';
175 c++;
176 break;
177 }
178 }
179 n = mailfile->remain;
180 if (size < n)
181 n = size;
182 /* search for '\n' while copying to c; no more than n bytes */
183 p = memccpy(c, mailfile->offset, '\n', n);
184 if (p != NULL)
185 n = p - c;
186 size -= n;
187 c += n;
188 mailfile->remain -= n;
189 mailfile->offset += n;
190 if (p != 0) /* '\n' found */
191 break;
192 }
193 *c = '\0';
194 return (c - (*buffer));
195 }
196
197 static int
refill(mailfile)198 refill(mailfile)
199 struct mailFile *mailfile;
200 {
201 mailfile->remain =
202 fread(mailfile->buffer, 1, MAILFILE_BSIZE, mailfile->filedes);
203 if (mailfile->copy && mailfile->remain > 0) {
204 if (fwrite(mailfile->buffer, 1, mailfile->remain, mailfile->copy)
205 != mailfile->remain) {
206 mailfile->error();
207 }
208 }
209 mailfile->offset = mailfile->buffer;
210 mailfile->buffer[mailfile->remain] = '\0';
211 return mailfile->remain;
212 }
213
214 long
mailFile_tell(mailfile)215 mailFile_tell(mailfile)
216 struct mailFile *mailfile;
217 {
218 return ftell(mailfile->filedes) - mailfile->remain;
219 }
220
221 int
mailFile_seek(mailfile,offset)222 mailFile_seek(mailfile, offset)
223 struct mailFile *mailfile;
224 long offset;
225 {
226 int ret;
227 long top, bot, curpos;
228
229 if (mailfile->charsaved) {
230 *(mailfile->offset) = mailfile->savechar;
231 mailfile->charsaved = 0;
232 }
233
234 curpos = ftell(mailfile->filedes) - mailfile->remain;
235 top = curpos - (mailfile->offset - mailfile->buffer);
236 bot = curpos + mailfile->remain - 1;
237 if (offset >= top && offset <= bot) {
238 /* just reposition */
239 mailfile->offset += (offset - curpos);
240 mailfile->remain -= (offset - curpos);
241 return 0;
242 }
243 /* else punt */
244 ret = fseek(mailfile->filedes, offset, 0);
245 if (mailfile->copy != NULL && ret == 0)
246 ret = fseek(mailfile->copy, offset, 0);
247 refill(mailfile);
248 return ret;
249 }
250
251 void
mailFile_detach(mailfile)252 mailFile_detach(mailfile)
253 struct mailFile *mailfile;
254 {
255 if (mailfile->filedes);
256 fflush(mailfile->filedes);
257 if (mailfile->copy)
258 fflush(mailfile->copy);
259 if (mailfile->buffer)
260 free(mailfile->buffer);
261 mailfile->filedes = NULL;
262 mailfile->copy = NULL;
263 mailfile->buffer = NULL;
264 mailfile->offset = NULL;
265 mailfile->remain = 0;
266 mailfile->savechar = -1;
267 mailfile->charsaved = 0;
268 }
269