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