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