Merge from vendor branch FILE:
[dragonfly.git] / contrib / sendmail / libsm / strio.c
1 /*
2  * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1990, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * By using this file, you agree to the terms and conditions set
11  * forth in the LICENSE file which can be found at the top level of
12  * the sendmail distribution.
13  */
14
15 #include <sm/gen.h>
16 SM_IDSTR(id, "@(#)$Id: strio.c,v 1.42 2002/02/11 23:05:50 gshapiro Exp $")
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <sm/rpool.h>
23 #include <sm/io.h>
24 #include <sm/heap.h>
25 #include <sm/conf.h>
26 #include "local.h"
27
28 /*
29 **  Cookie structure for the "strio" file type
30 */
31
32 struct sm_str_obj
33 {
34         char            *strio_base;
35         char            *strio_end;
36         size_t          strio_size;
37         size_t          strio_offset;
38         int             strio_flags;
39         const void      *strio_rpool;
40 };
41
42 typedef struct sm_str_obj SM_STR_OBJ_T;
43
44 /*
45 **  SM_STRGROW -- increase storage space for string
46 **
47 **      Parameters:
48 **              s -- current cookie
49 **              size -- new storage size request
50 **
51 **      Returns:
52 **              true iff successful.
53 */
54
55 static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
56
57 static bool
58 sm_strgrow(s, size)
59         SM_STR_OBJ_T *s;
60         size_t size;
61 {
62         register void *p;
63
64         if (s->strio_size >= size)
65                 return true;
66         p = sm_realloc(s->strio_base, size);
67         if (p == NULL)
68                 return false;
69         s->strio_base = p;
70         s->strio_end = s->strio_base + size;
71         s->strio_size = size;
72         return true;
73 }
74
75 /*
76 **  SM_STRREAD -- read a portion of the string
77 **
78 **      Parameters:
79 **              fp -- the file pointer
80 **              buf -- location to place read data
81 **              n -- number of bytes to read
82 **
83 **      Returns:
84 **              Failure: -1 and sets errno
85 **              Success: >=0, number of bytes read
86 */
87
88 ssize_t
89 sm_strread(fp, buf, n)
90         SM_FILE_T *fp;
91         char *buf;
92         size_t n;
93 {
94         register SM_STR_OBJ_T *s = fp->f_cookie;
95         int len;
96
97         if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW))
98         {
99                 errno = EBADF;
100                 return -1;
101         }
102         len = SM_MIN(s->strio_size - s->strio_offset, n);
103         (void) memmove(buf, s->strio_base + s->strio_offset, len);
104         s->strio_offset += len;
105         return len;
106 }
107
108 /*
109 **  SM_STRWRITE -- write a portion of the string
110 **
111 **      Parameters:
112 **              fp -- the file pointer
113 **              buf -- location of data for writing
114 **              n -- number of bytes to write
115 **
116 **      Returns:
117 **              Failure: -1 and sets errno
118 **              Success: >=0, number of bytes written
119 */
120
121 ssize_t
122 sm_strwrite(fp, buf, n)
123         SM_FILE_T *fp;
124         char const *buf;
125         size_t n;
126 {
127         register SM_STR_OBJ_T *s = fp->f_cookie;
128
129         if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW))
130         {
131                 errno = EBADF;
132                 return -1;
133         }
134         if (n + s->strio_offset > s->strio_size)
135         {
136                 if (!sm_strgrow(s, n + s->strio_offset))
137                         return 0;
138         }
139         (void) memmove(s->strio_base + s->strio_offset, buf, n);
140         s->strio_offset += n;
141         return n;
142 }
143
144 /*
145 **  SM_STRSEEK -- position the offset pointer for the string
146 **
147 **      Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid
148 **      values for whence.
149 **
150 **      Parameters:
151 **              fp -- the file pointer
152 **              offset -- number of bytes offset from "base"
153 **              whence -- determines "base" for 'offset'
154 **
155 **      Returns:
156 **              Failure: -1 and sets errno
157 **              Success: >=0, number of bytes read
158 */
159
160 off_t
161 sm_strseek(fp, offset, whence)
162         SM_FILE_T *fp;
163         off_t offset;
164         int whence;
165 {
166         register off_t ret;
167         register SM_STR_OBJ_T *s = fp->f_cookie;
168
169 reseek:
170         switch (whence)
171         {
172           case SM_IO_SEEK_SET:
173                 ret = offset;
174                 break;
175           case SM_IO_SEEK_CUR:
176                 ret = s->strio_offset + offset;
177                 break;
178           case SM_IO_SEEK_END:
179                 ret = s->strio_size;
180                 break;
181           default:
182                 errno = EINVAL;
183                 return -1;
184         }
185         if (ret < 0 || ret > (off_t)(size_t)(-1))       /* XXX ugly */
186                 return -1;
187         if ((size_t) ret > s->strio_size)
188         {
189                 if (sm_strgrow(s, (size_t)ret))
190                         goto reseek;
191
192                 /* errno set by sm_strgrow */
193                 return -1;
194         }
195         s->strio_offset = (size_t) ret;
196         return ret;
197 }
198
199 /*
200 **  SM_STROPEN -- open a string file type
201 **
202 **      Parameters:
203 **              fp -- file pointer open to be associated with
204 **              info -- initial contents (NULL for none)
205 **              flags -- flags for methods of access (was mode)
206 **              rpool -- resource pool to use memory from (if applicable)
207 **
208 **      Results:
209 **              Success: 0 (zero)
210 **              Failure: -1 and sets errno
211 */
212
213 int
214 sm_stropen(fp, info, flags, rpool)
215         SM_FILE_T *fp;
216         const void *info;
217         int flags;
218         const void *rpool;
219 {
220         register SM_STR_OBJ_T *s;
221
222 #if SM_RPOOL
223         s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
224 #else /* SM_RPOOL */
225         s = sm_malloc(sizeof(SM_STR_OBJ_T));
226         if (s == NULL)
227                 return -1;
228 #endif /* SM_RPOOL */
229
230         fp->f_cookie = s;
231         s->strio_rpool = rpool;
232         s->strio_offset = 0;
233         s->strio_size = 0;
234         s->strio_base = NULL;
235         s->strio_end = 0;
236
237         switch (flags)
238         {
239           case SM_IO_RDWR:
240                 s->strio_flags = SMRW;
241                 break;
242           case SM_IO_RDONLY:
243                 s->strio_flags = SMRD;
244                 break;
245           case SM_IO_WRONLY:
246                 s->strio_flags = SMWR;
247                 break;
248           case SM_IO_APPEND:
249                 if (s->strio_rpool == NULL)
250                         sm_free(s);
251                 errno = EINVAL;
252                 return -1;
253           default:
254                 if (s->strio_rpool == NULL)
255                         sm_free(s);
256                 errno = EINVAL;
257                 return -1;
258         }
259
260         if (info != NULL)
261         {
262                 s->strio_base = sm_strdup_x(info);
263                 if (s->strio_base == NULL)
264                 {
265                         int save_errno = errno;
266
267                         if (s->strio_rpool == NULL)
268                                 sm_free(s);
269                         errno = save_errno;
270                         return -1;
271                 }
272                 s->strio_size = strlen(info);
273                 s->strio_end = s->strio_base + s->strio_size;
274         }
275         return 0;
276 }
277
278 /*
279 **  SM_STRCLOSE -- close the string file type and free resources
280 **
281 **      Parameters:
282 **              fp -- file pointer
283 **
284 **      Results:
285 **              Success: 0 (zero)
286 */
287
288 int
289 sm_strclose(fp)
290         SM_FILE_T *fp;
291 {
292         SM_STR_OBJ_T *s = fp->f_cookie;
293
294 #if !SM_RPOOL
295         sm_free(s->strio_base);
296         s->strio_base = NULL;
297 #endif /* !SM_RPOOL */
298         return 0;
299 }
300
301 /*
302 **  SM_STRSETMODE -- set mode info for the file
303 **
304 **       Note: changing the mode can be a safe way to have the "parent"
305 **       set up a string that the "child" is not to modify
306 **
307 **      Parameters:
308 **              fp -- the file pointer
309 **              mode -- location of new mode to set
310 **
311 **      Results:
312 **              Success: 0 (zero)
313 **              Failure: -1 and sets errno
314 */
315
316 int
317 sm_strsetmode(fp, mode)
318         SM_FILE_T *fp;
319         const int *mode;
320 {
321         register SM_STR_OBJ_T *s = fp->f_cookie;
322         int flags;
323
324         switch (*mode)
325         {
326           case SM_IO_RDWR:
327                 flags = SMRW;
328                 break;
329           case SM_IO_RDONLY:
330                 flags = SMRD;
331                 break;
332           case SM_IO_WRONLY:
333                 flags = SMWR;
334                 break;
335           case SM_IO_APPEND:
336                 errno = EINVAL;
337                 return -1;
338           default:
339                 errno = EINVAL;
340                 return -1;
341         }
342         s->strio_flags &= ~SMMODEMASK;
343         s->strio_flags |= flags;
344         return 0;
345 }
346
347 /*
348 **  SM_STRGETMODE -- get mode info for the file
349 **
350 **      Parameters:
351 **              fp -- the file pointer
352 **              mode -- location to store current mode
353 **
354 **      Results:
355 **              Success: 0 (zero)
356 **              Failure: -1 and sets errno
357 */
358
359 int
360 sm_strgetmode(fp, mode)
361         SM_FILE_T *fp;
362         int *mode;
363 {
364         register SM_STR_OBJ_T *s = fp->f_cookie;
365
366         switch (s->strio_flags & SMMODEMASK)
367         {
368           case SMRW:
369                 *mode = SM_IO_RDWR;
370                 break;
371           case SMRD:
372                 *mode = SM_IO_RDONLY;
373                 break;
374           case SMWR:
375                 *mode = SM_IO_WRONLY;
376                 break;
377           default:
378                 errno = EINVAL;
379                 return -1;
380         }
381         return 0;
382 }
383
384 /*
385 **  SM_STRSETINFO -- set info for the file
386 **
387 **      Currently only SM_IO_WHAT_MODE is supported for 'what'.
388 **
389 **      Parameters:
390 **              fp -- the file pointer
391 **              what -- type of information to set
392 **              valp -- location to data for doing set
393 **
394 **      Results:
395 **              Failure: -1 and sets errno
396 **              Success: sm_strsetmode() return [0 (zero)]
397 */
398
399 int
400 sm_strsetinfo(fp, what, valp)
401         SM_FILE_T *fp;
402         int what;
403         void *valp;
404 {
405         switch(what)
406         {
407           case SM_IO_WHAT_MODE:
408                 return sm_strsetmode(fp, (int *) valp);
409           default:
410                 errno = EINVAL;
411                 return -1;
412         }
413 }
414
415 /*
416 **  SM_STRGETINFO -- get info for the file
417 **
418 **      Currently only SM_IO_WHAT_MODE is supported for 'what'.
419 **
420 **      Parameters:
421 **              fp -- the file pointer
422 **              what -- type of information requested
423 **              valp -- location to return information in
424 **
425 **      Results:
426 **              Failure: -1 and sets errno
427 **              Success: sm_strgetmode() return [0 (zero)]
428 */
429
430 int
431 sm_strgetinfo(fp, what, valp)
432         SM_FILE_T *fp;
433         int what;
434         void *valp;
435 {
436         switch(what)
437         {
438           case SM_IO_WHAT_MODE:
439                 return sm_strgetmode(fp, (int *) valp);
440           default:
441                 errno = EINVAL;
442                 return -1;
443         }
444 }
445
446 /*
447 **  SM_STRIO_INIT -- initializes a write-only string type
448 **
449 **  Original comments below. This function does not appear to be used anywhere.
450 **  The same functionality can be done by changing the mode of the file.
451 **  ------------
452 ** sm_strio_init initializes an SM_FILE_T structure as a write-only file
453 ** that writes into the specified buffer:
454 ** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer.
455 **   Attempts to write more than size-1 characters into the buffer will fail
456 **   silently (no error is reported).
457 ** - Use sm_io_fflush to nul terminate the string in the buffer
458 **   (the write pointer is not advanced).
459 ** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc.
460 **
461 **      Parameters:
462 **              fp -- file pointer
463 **              buf -- memory location for stored data
464 **              size -- size of 'buf'
465 **
466 **      Results:
467 **              none.
468 */
469
470 void
471 sm_strio_init(fp, buf, size)
472         SM_FILE_T *fp;
473         char *buf;
474         size_t size;
475 {
476         fp->sm_magic = SmFileMagic;
477         fp->f_flags = SMWR | SMSTR;
478         fp->f_file = -1;
479         fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf;
480         fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0);
481         fp->f_lbfsize = 0;
482         fp->f_r = 0;
483         fp->f_read = NULL;
484         fp->f_seek = NULL;
485         fp->f_getinfo = NULL;
486         fp->f_setinfo = NULL;
487 }