xref: /freebsd/contrib/sendmail/include/sm/io.h (revision eacee0ff7ec955b32e09515246bd97b6edcd2b0f)
1 /*
2  * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1990
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  *	$Id: io.h,v 1.19 2001/07/10 21:56:46 gshapiro Exp $
15  */
16 
17 /*-
18  *	@(#)stdio.h	5.17 (Berkeley) 6/3/91
19  */
20 
21 #ifndef	SM_IO_H
22 #define SM_IO_H
23 
24 #include <stdio.h>
25 #include <sm/gen.h>
26 #include <sm/varargs.h>
27 
28 /* mode for sm io (exposed) */
29 #define SM_IO_RDWR	1	/* read-write */
30 #define SM_IO_RDONLY	2	/* read-only */
31 #define SM_IO_WRONLY	3	/* write-only */
32 #define SM_IO_APPEND	4	/* write-only from eof */
33 #define SM_IO_APPENDRW	5	/* read-write from eof */
34 #define SM_IO_RDWRTR	6	/* read-write with truncation indicated */
35 
36 /* for sm_io_fseek, et al api's (exposed) */
37 #define SM_IO_SEEK_SET	0
38 #define SM_IO_SEEK_CUR	1
39 #define SM_IO_SEEK_END	2
40 
41 /* flags for info what's with different types (exposed) */
42 #define SM_IO_WHAT_MODE		1
43 #define SM_IO_WHAT_VECTORS	2
44 #define SM_IO_WHAT_FD		3
45 #define SM_IO_WHAT_TYPE		4
46 #define SM_IO_WHAT_ISTYPE	5
47 #define SM_IO_IS_READABLE	6
48 #define SM_IO_WHAT_TIMEOUT	7
49 
50 /* info flags (exposed) */
51 #define SM_IO_FTYPE_CREATE	1
52 #define SM_IO_FTYPE_MODIFY	2
53 #define SM_IO_FTYPE_DELETE	3
54 
55 #define SM_IO_SL_PRIO		1
56 
57 #define SM_IO_OPEN_MAX		20
58 
59 /* for internal buffers */
60 struct smbuf
61 {
62 	unsigned char	*smb_base;
63 	int		smb_size;
64 };
65 
66 /*
67 **  sm I/O state variables (internal only).
68 **
69 **	The following always hold:
70 **
71 **		if (flags&(SMLBF|SMWR)) == (SMLBF|SMWR),
72 **			lbfsize is -bf.size, else lbfsize is 0
73 **		if flags&SMRD, w is 0
74 **		if flags&SMWR, r is 0
75 **
76 **	This ensures that the getc and putc macros (or inline functions) never
77 **	try to write or read from a file that is in `read' or `write' mode.
78 **	(Moreover, they can, and do, automatically switch from read mode to
79 **	write mode, and back, on "r+" and "w+" files.)
80 **
81 **	lbfsize is used only to make the inline line-buffered output stream
82 **	code as compact as possible.
83 **
84 **	ub, up, and ur are used when ungetc() pushes back more characters
85 **	than fit in the current bf, or when ungetc() pushes back a character
86 **	that does not match the previous one in bf.  When this happens,
87 **	ub.base becomes non-nil (i.e., a stream has ungetc() data iff
88 **	ub.base!=NULL) and up and ur save the current values of p and r.
89 */
90 
91 typedef struct sm_file SM_FILE_T;
92 
93 struct sm_file
94 {
95 	const char	*sm_magic;	/* This SM_FILE_T is free when NULL */
96 	unsigned char	*f_p;		/* current position in (some) buffer */
97 	int		f_r;		/* read space left for getc() */
98 	int		f_w;		/* write space left for putc() */
99 	long		f_flags;	/* flags, below */
100 	short		f_file;		/* fileno, if Unix fd, else -1 */
101 	struct smbuf	f_bf;		/* the buffer (>= 1 byte, if !NULL) */
102 	int		f_lbfsize;	/* 0 or -bf.size, for inline putc */
103 
104 	/* These can be used for any purpose by a file type implementation: */
105 	void		*f_cookie;
106 	int		f_ival;
107 
108 	/* operations */
109 	int		(*f_close) __P((SM_FILE_T *));
110 	ssize_t		(*f_read)  __P((SM_FILE_T *, char *, size_t));
111 	off_t		(*f_seek)  __P((SM_FILE_T *, off_t, int));
112 	ssize_t		(*f_write) __P((SM_FILE_T *, const char *, size_t));
113 	int		(*f_open) __P((SM_FILE_T *, const void *, int,
114 				const void *));
115 	int		(*f_setinfo) __P((SM_FILE_T *, int , void *));
116 	int		(*f_getinfo) __P((SM_FILE_T *, int , void *));
117 	int		f_timeout;
118 	int		f_timeoutstate;   /* either blocking or non-blocking */
119 	char		*f_type;	/* for by-type lookups */
120 	void		*f_self;	/* self for reference */
121 	struct sm_file	*f_flushfp;	/* flush this before reading parent */
122 	struct sm_file	*f_modefp;	/* sync mode with this fp */
123 
124 	/* separate buffer for long sequences of ungetc() */
125 	struct smbuf	f_ub;	/* ungetc buffer */
126 	unsigned char	*f_up;	/* saved f_p when f_p is doing ungetc */
127 	int		f_ur;	/* saved f_r when f_r is counting ungetc */
128 
129 	/* tricks to meet minimum requirements even when malloc() fails */
130 	unsigned char	f_ubuf[3];	/* guarantee an ungetc() buffer */
131 	unsigned char	f_nbuf[1];	/* guarantee a getc() buffer */
132 
133 	/* separate buffer for fgetln() when line crosses buffer boundary */
134 	struct smbuf	f_lb;		/* buffer for fgetln() */
135 
136 	/* Unix stdio files get aligned to block boundaries on fseek() */
137 	int		f_blksize;	/* stat.st_blksize (may be != bf.size) */
138 	off_t		f_lseekoff;	/* current lseek offset */
139 	int		f_dup_cnt;	/* count file dup'd */
140 };
141 
142 __BEGIN_DECLS
143 extern SM_FILE_T	SmIoF[];
144 extern const char	SmFileMagic[];
145 extern SM_FILE_T	SmFtStdio_def;
146 extern SM_FILE_T	SmFtStdiofd_def;
147 extern SM_FILE_T	SmFtString_def;
148 extern SM_FILE_T	SmFtSyslog_def;
149 extern SM_FILE_T	SmFtRealStdio_def;
150 
151 #define SMIOIN_FILENO		0
152 #define SMIOOUT_FILENO		1
153 #define SMIOERR_FILENO		2
154 #define SMIOSTDIN_FILENO	3
155 #define SMIOSTDOUT_FILENO	4
156 #define SMIOSTDERR_FILENO	5
157 
158 /* Common predefined and already (usually) open files (exposed) */
159 #define smioin		(&SmIoF[SMIOIN_FILENO])
160 #define smioout		(&SmIoF[SMIOOUT_FILENO])
161 #define smioerr		(&SmIoF[SMIOERR_FILENO])
162 #define smiostdin	(&SmIoF[SMIOSTDIN_FILENO])
163 #define smiostdout	(&SmIoF[SMIOSTDOUT_FILENO])
164 #define smiostderr	(&SmIoF[SMIOSTDERR_FILENO])
165 
166 #define SmFtStdio	(&SmFtStdio_def)
167 #define SmFtStdiofd	(&SmFtStdiofd_def)
168 #define SmFtString	(&SmFtString_def)
169 #define SmFtSyslog	(&SmFtSyslog_def)
170 #define SmFtRealStdio	(&SmFtRealStdio_def)
171 
172 #ifdef __STDC__
173 # define SM_IO_SET_TYPE(f, name, open, close, read, write, seek, get, set, timeout) \
174     (f) = {SmFileMagic, (unsigned char *) 0, 0, 0, 0L, -1, {0}, 0, (void *) 0,\
175 	0, (close), (read), (seek), (write), (open), (set), (get), (timeout),\
176 	0, (name)}
177 # define SM_IO_INIT_TYPE(f, name, open, close, read, write, seek, get, set, timeout)
178 
179 #else /* __STDC__ */
180 # define SM_IO_SET_TYPE(f, name, open, close, read, write, seek, get, set, timeout) (f)
181 # define SM_IO_INIT_TYPE(f, name, open, close, read, write, seek, get, set, timeout) \
182 	(f).sm_magic = SmFileMagic;	\
183 	(f).f_p = (unsigned char *) 0;	\
184 	(f).f_r = 0;	\
185 	(f).f_w = 0;	\
186 	(f).f_flags = 0L;	\
187 	(f).f_file = 0;	\
188 	(f).f_bf.smb_base = (unsigned char *) 0;	\
189 	(f).f_bf.smb_size = 0;	\
190 	(f).f_lbfsize = 0;	\
191 	(f).f_cookie = (void *) 0;	\
192 	(f).f_ival = 0;	\
193 	(f).f_close = (close);	\
194 	(f).f_read = (read);	\
195 	(f).f_seek = (seek);	\
196 	(f).f_write = (write);	\
197 	(f).f_open = (open);	\
198 	(f).f_setinfo = (set);	\
199 	(f).f_getinfo = (get);	\
200 	(f).f_timeout = (timeout);	\
201 	(f).f_timeoutstate = 0;	\
202 	(f).f_type = (name);
203 
204 #endif /* __STDC__ */
205 
206 __END_DECLS
207 
208 /* Internal flags */
209 #define SMFBF		0x000001	/* XXXX fully buffered */
210 #define SMLBF		0x000002	/* line buffered */
211 #define SMNBF		0x000004	/* unbuffered */
212 #define SMNOW		0x000008	/* Flush each write; take read now */
213 #define SMRD		0x000010	/* OK to read */
214 #define SMWR		0x000020	/* OK to write */
215 	/* RD and WR are never simultaneously asserted */
216 #define SMRW		0x000040	/* open for reading & writing */
217 #define SMFEOF		0x000080	/* found EOF */
218 #define SMERR		0x000100	/* found error */
219 #define SMMBF		0x000200	/* buf is from malloc */
220 #define SMAPP		0x000400	/* fdopen()ed in append mode */
221 #define SMSTR		0x000800	/* this is an snprintf string */
222 #define SMOPT		0x001000	/* do fseek() optimisation */
223 #define SMNPT		0x002000	/* do not do fseek() optimisation */
224 #define SMOFF		0x004000	/* set iff offset is in fact correct */
225 #define SMALC		0x010000	/* allocate string space dynamically */
226 
227 #define SMACCESSMASK	0x0070
228 #define SMMODEMASK	0x011C
229 
230 /* defines for timeout constants */
231 #define SM_TIME_IMMEDIATE	(0)
232 #define SM_TIME_FOREVER		(-1)
233 #define SM_TIME_DEFAULT		(-2)
234 
235 /* timeout state for blocking */
236 #define SM_TIME_BLOCK		(0)	/* XXX just bool? */
237 #define SM_TIME_NONBLOCK	(1)
238 
239 /* Exposed buffering type flags */
240 #define SM_IO_FBF	0	/* setvbuf should set fully buffered */
241 #define SM_IO_LBF	1	/* setvbuf should set line buffered */
242 #define SM_IO_NBF	2	/* setvbuf should set unbuffered */
243 
244 /* setvbuf buffered, but through at lower file type layers */
245 #define SM_IO_NOW	3
246 
247 /*
248 **  size of buffer used by setbuf.
249 **  If underlying filesystem blocksize is discoverable that is used instead
250 */
251 
252 #define SM_IO_BUFSIZ	4096
253 
254 #define SM_IO_EOF	(-1)
255 
256 /* Functions defined in ANSI C standard.  */
257 __BEGIN_DECLS
258 SM_FILE_T *sm_io_autoflush __P((SM_FILE_T *, SM_FILE_T *));
259 void	 sm_io_automode __P((SM_FILE_T *, SM_FILE_T *));
260 void	 sm_io_clearerr __P((SM_FILE_T *));
261 int	 sm_io_close __P((SM_FILE_T *, int SM_NONVOLATILE));
262 SM_FILE_T *sm_io_dup __P((SM_FILE_T *));
263 int	 sm_io_eof __P((SM_FILE_T *));
264 int	 sm_io_error __P((SM_FILE_T *));
265 char	*sm_io_fgets __P((SM_FILE_T *, int, char *, int));
266 int	 sm_io_flush __P((SM_FILE_T *, int SM_NONVOLATILE));
267 
268 int PRINTFLIKE(3, 4)
269 sm_io_fprintf __P((SM_FILE_T *, int, const char *, ...));
270 
271 int	 sm_io_fputs __P((SM_FILE_T *, int, const char *));
272 
273 int SCANFLIKE(3, 4)
274 sm_io_fscanf __P((SM_FILE_T *, int, const char *, ...));
275 
276 int	 sm_io_getc __P((SM_FILE_T *, int));
277 int	 sm_io_getinfo __P((SM_FILE_T *, int, void *));
278 SM_FILE_T *sm_io_open __P((const SM_FILE_T *, int SM_NONVOLATILE, const void *,
279 			   int, const void *));
280 int	 sm_io_purge __P((SM_FILE_T *));
281 int	 sm_io_putc __P((SM_FILE_T *, int, int));
282 size_t	 sm_io_read __P((SM_FILE_T *, int, void *, size_t));
283 SM_FILE_T *sm_io_reopen __P((const SM_FILE_T *, int SM_NONVOLATILE,
284 			     const void *, int, const void *, SM_FILE_T *));
285 void	 sm_io_rewind __P((SM_FILE_T *, int));
286 int	 sm_io_seek __P((SM_FILE_T *, int SM_NONVOLATILE, long SM_NONVOLATILE,
287 			 int SM_NONVOLATILE));
288 int	 sm_io_setinfo __P((SM_FILE_T *, int, void *));
289 int	 sm_io_setvbuf __P((SM_FILE_T *, int, char *, int, size_t));
290 
291 int SCANFLIKE(2, 3)
292 sm_io_sscanf __P((const char *, char const *, ...));
293 
294 long	 sm_io_tell __P((SM_FILE_T *, int SM_NONVOLATILE));
295 int	 sm_io_ungetc __P((SM_FILE_T *, int, int));
296 int	 sm_io_vfprintf __P((SM_FILE_T *, int, const char *, va_list));
297 size_t	 sm_io_write __P((SM_FILE_T *, int, const void *, size_t));
298 
299 void	 sm_strio_init __P((SM_FILE_T *, char *, size_t));
300 
301 extern SM_FILE_T *
302 sm_io_fopen __P((
303 	char *_pathname,
304 	int _flags,
305 	...));
306 
307 extern SM_FILE_T *
308 sm_io_stdioopen __P((
309 	FILE *_stream,
310 	char *_mode));
311 
312 extern int
313 sm_vasprintf __P((
314 	char **_str,
315 	const char *_fmt,
316 	va_list _ap));
317 
318 extern int
319 sm_vsnprintf __P((
320 	char *,
321 	size_t,
322 	const char *,
323 	va_list));
324 
325 extern void
326 sm_perror __P((
327 	const char *));
328 
329 __END_DECLS
330 
331 /*
332 ** Functions internal to the implementation.
333 */
334 
335 __BEGIN_DECLS
336 int	sm_rget __P((SM_FILE_T *, int));
337 int	sm_vfscanf __P((SM_FILE_T *, int SM_NONVOLATILE, const char *,
338 			va_list SM_NONVOLATILE));
339 int	sm_wbuf __P((SM_FILE_T *, int, int));
340 __END_DECLS
341 
342 /*
343 **  The macros are here so that we can
344 **  define function versions in the library.
345 */
346 
347 #define sm_getc(f, t) \
348 	(--(f)->f_r < 0 ? \
349 		sm_rget(f, t) : \
350 		(int)(*(f)->f_p++))
351 
352 /*
353 **  This has been tuned to generate reasonable code on the vax using pcc.
354 **  (It also generates reasonable x86 code using gcc.)
355 */
356 
357 #define sm_putc(f, t, c) \
358 	(--(f)->f_w < 0 ? \
359 		(f)->f_w >= (f)->f_lbfsize ? \
360 			(*(f)->f_p = (c)), *(f)->f_p != '\n' ? \
361 				(int)*(f)->f_p++ : \
362 				sm_wbuf(f, t, '\n') : \
363 			sm_wbuf(f, t, (int)(c)) : \
364 		(*(f)->f_p = (c), (int)*(f)->f_p++))
365 
366 #define sm_eof(p)	(((p)->f_flags & SMFEOF) != 0)
367 #define sm_error(p)	(((p)->f_flags & SMERR) != 0)
368 #define sm_clearerr(p)	((void)((p)->f_flags &= ~(SMERR|SMFEOF)))
369 
370 #define sm_io_eof(p)	sm_eof(p)
371 #define sm_io_error(p)	sm_error(p)
372 
373 #define sm_io_clearerr(p)	sm_clearerr(p)
374 
375 #ifndef lint
376 # ifndef _POSIX_SOURCE
377 #  define sm_io_getc(fp, t)	sm_getc(fp, t)
378 #  define sm_io_putc(fp, t, x)	sm_putc(fp, t, x)
379 # endif /* _POSIX_SOURCE */
380 #endif /* lint */
381 
382 #endif /* SM_IO_H */
383