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