/*
* Copyright (c) 2000-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
* $Id: io.h,v 1.95 2007/10/23 04:03:12 ca Exp $
*/
#ifndef SM_IO_H
#define SM_IO_H 1
#include "sm/generic.h"
#include "sm/types.h"
#include "sm/magic.h"
#include "sm/varargs.h"
#include "sm/error.h"
#include "sm/iostub.h"
#include "sm/rpool.h"
#include "sm/str.h"
#if !SM_NO_CSTR
# include "sm/cstr.h"
#endif
/* mode for sm io (exposed) */
/*
** XXX make this "compatible" with the internal flags to avoid
** tranlation function sm_flags
case SM_IO_RDONLY: open for reading
ret = SMRD;
case SM_IO_WRONLY: open for writing
ret = SMWR;
case SM_IO_APPEND: open for appending
ret = SMWR;
case SM_IO_RDWR: open for read and write
ret = SMRW;
default:
ret = 0;
use the last few bits to "hide" the SMxy code in the SM_IO_ values.
*/
#define SM_IO_RDWR 1 /* read-write */
#define SM_IO_RDONLY 2 /* read-only */
#define SM_IO_WRONLY 3 /* write-only */
#define SM_IO_APPEND 4 /* write-only from eof */
#define SM_IO_APPENDRW 5 /* read-write from eof */
#define SM_IO_RDWRTR 6 /* read-write with truncation indicated */
#define SM_IO_WREXCL 7 /* write-only, open with O_EXCL */
#define SM_IO_RDWRCR 8 /* read-write with creation */
#define SM_IO_RDWRCRX 9 /* read-write with creation, O_EXCL */
/* for sm_io_fseek, et al api's (exposed) */
#define SM_IO_SEEK_SET 0
#define SM_IO_SEEK_CUR 1
#define SM_IO_SEEK_END 2
/* default number of open files */
#define SM_IO_OPEN_MAX 20
/*
** Arguments for open/set/get XXX not yet...
**
** [O] means valid on open
** [S] means valid for set
** [G] means valid for get
**
** Question: should the value encode the size of the argument so
** functions can skip properly over unknown arguments?
*/
/* marker */
#define SM_IO_WHAT_END 0 /* end of list [O] */
/* flags for info what's with different types (exposed) */
#define SM_IO_WHAT_MODE 1
#define SM_IO_WHAT_VECTORS 2
#define SM_IO_WHAT_FD 3
#define SM_IO_WHAT_TYPE 4
#define SM_IO_WHAT_ISTYPE 5
#define SM_IO_IS_READABLE 6
#define SM_IO_WHAT_TIMEOUT 7
#define SM_IO_DOUBLE 8
#define SM_IO_WHAT_RD_FD 9
#define SM_IO_WHAT_WR_FD 10
#define SM_IO_WHAT_SIZE 11 /* file size, not buffer size */
#define SM_IO_WHAT_RPOOL 12 /* specify resource pool [OG] */
#define SM_IO_WHAT_FMODE 13 /* file mode (chmod(2))*/
#define SM_IO_WHAT_COMMIT 14 /* commit file to stable storage */
#define SM_IO_WHAT_ABORT 15 /* abort, rm file */
#define SM_IO_WHAT_IBSIZE 16 /* input buffer size [OSG] */
#define SM_IO_WHAT_OBSIZE 17 /* output buffer size [OSG] */
#define SM_IO_WHAT_IRBSIZE 18 /* input read buffer size [OSG] */
#define SM_IO_WHAT_ORBSIZE 19 /* output read buffer size [OSG] */
#define SM_IO_WHAT_IWBSIZE 18 /* input write buffer size [OSG] */
#define SM_IO_WHAT_OWBSIZE 19 /* output write buffer size [OSG] */
#define SM_IO_WHAT_BSIZE 20 /* buffer size [OSG] */
/* Look for SM_IO_WHAT_* in other include files! They can be "spread out"! */
#if 0
typedef int sm_file_arg_T; /* do we need this? */
#define SM_IO_WHAT_IRSIZE 2 /* specify record size [OSG] */
#define SM_IO_WHAT_ORSIZE 3 /* specify record size [OSG] */
#define SM_IO_WHAT_IBSIZE 4 /* specify buffer size [OSG] */
#define SM_IO_WHAT_OBSIZE 5 /* specify buffer size [OSG] */
#define SM_IO_WHAT_IRBASE 6 /* record base pointer [OSG] */
#define SM_IO_WHAT_ORBASE 7 /* record base pointer [OSG] */
#define SM_IO_WHAT_IBBASE 8 /* buffer base pointer [OSG] */
#define SM_IO_WHAT_OBBASE 9 /* buffer base pointer [OSG] */
#define SM_IO_WHAT_IRCNT 10 /* record remaining count [G] */
#define SM_IO_WHAT_ORCNT 11 /* record remaining count [G] */
#define SM_IO_WHAT_IBCNT 12 /* buffer remaining count [G] */
#define SM_IO_WHAT_OBCNT 13 /* buffer remaining count [G] */
#define SM_IO_WHAT_TIMEOUT 14 /* default I/O timeout [OSG] */
#define SM_IO_WHAT_LINEBUF 15 /* set/clr line buffering [OSG] */
/* constructor for other types */
#define SM_IO_WHAT(stype, i) (((stype) << 8) | ((i) & 0xff))
#endif /* 0 */
typedef uint sm_f_flags_T;
/*
** For internal buffers
** Notice: smb_r/smb_w could be one counter if we use <0, >0
**
** This implements a simple buffer.
** The buffer begins at smb_base and its size is smb_size.
** The current usage of the buffer is encoded in smb_flags.
** The interesting flags for the use as buffer are:
** SMRD: currently reading
** SMWR: currently writing
** SMRD and SMWR are never simultaneously asserted
** SMRW open for reading & writing, i.e., we can switch from one mode
** to the other
**
** The following always hold:
**
** if flags&SMRD, smb_w is 0
** if flags&SMWR, smb_r is 0
**
** This ensures that the getc and putc macros (or inline functions) never
** try to write or read from a file that is in `read' or `write' mode.
** (Moreover, they can, and do, automatically switch from read mode to
** write mode, and back, on "r+" and "w+" files.)
**
** smb_r/smb_w denote the number of bytes left to read/write.
** smb_p is the read/write pointer into the buffer, i.e., it points
** to the location in the buffer where to read/write the next byte.
**
** |<- smb_size ->|
** |----------------|--------|
** ^ ^ ^
** smb_base smb_p smb_base + smb_size
**
** if SMRD: smb_p + smb_r <= smb_base + smb_size
** if SMWR: smb_p + smb_w <= smb_base + smb_size
**
** The buffer acts as very simple queue between the producer and the consumer.
** "Simple" approach means:
** SMRD: the buffer is always completely read and then filled from
** the base (but maybe not completely filled since there
** might not be enough data).
** SMWR: the buffer is written and then completely flushed such
** that is empty again.
** "Real" queues would have different pointers to write/read for
** the producer and consumer such that the queue is entirely utilized.
** However, that causes problems at "wrap-around", esp. if more than just
** one item (byte) should be read/written: it must be done piecewise
** (or at least special care must be taken for the wrap-around cases).
** We can do something like that because smb_p + smb_r is our
** pointer to write more data into the buffer.
*/
struct smbuf
{
int smb_size; /* total size */
int smb_r; /* left to read */
int smb_w; /* left to write */
int smb_fd; /* fileno, if Unix fd, else -1 */
sm_f_flags_T smb_flags; /* flags, below */
#if SM_IO_ERR_VAL
sm_ret_T smb_error; /* error code; for logging etc */
#endif
uchar *smb_base; /* start of buffer */
uchar *smb_p; /* pointer into buffer */
};
#define SM_NULL_BUF {0, 0, 0, -1, (sm_f_flags_T) 0, (uchar *) 0, (uchar *) 0}
#define SM_INIT_BUF(fl, fd) {0, 0, 0, (fd), (fl), (uchar *) 0, (uchar *) 0}
typedef struct smbuf smbuf_T;
#if 0
/* in iostub.h */
typedef struct sm_file sm_file_T;
typedef struct sm_stream sm_stream_T;
#endif
/*
** note: we don't really need open() since it is immediately called
** by sm_io_open() anyways. instead a stacking function like in
** sfio would be sufficient. funopen() (from BSD) doesn't provide
** an open() function pointer either
*/
/* XXX specify these properly! */
typedef sm_ret_T (open_F)(sm_file_T *, const void *, int, va_list);
typedef sm_ret_T (close_F)(sm_file_T *, int);
/* use size_t also for output value instead of ssize_t? */
typedef sm_ret_T (read_F)(sm_file_T *, uchar *, size_t, ssize_t *);
typedef sm_ret_T (write_F)(sm_file_T *, const uchar *, size_t, ssize_t *);
typedef sm_ret_T (getbuf_F)(sm_file_T *, ssize_t *);
typedef sm_ret_T (putbuf_F)(sm_file_T *, size_t, ssize_t *);
typedef sm_ret_T (seek_F)(sm_file_T *, off_t, int);
typedef sm_ret_T (setinfo_F)(sm_file_T *, int , void *);
typedef sm_ret_T (getinfo_F)(sm_file_T *, int , void *);
/* add more functions? see README.IO */
#define f_open(fp) ((fp).f_stream.fs_open)
#define f_close(fp) ((fp).f_stream.fs_close)
#define f_read(fp) ((fp).f_stream.fs_read)
#define f_write(fp) ((fp).f_stream.fs_write)
#define f_seek(fp) ((fp).f_stream.fs_seek)
#define f_getbuf(fp) ((fp).f_stream.fs_getbuf)
#define f_putbuf(fp) ((fp).f_stream.fs_putbuf)
#define f_getinfo(fp) ((fp).f_stream.fs_getinfo)
#define f_setinfo(fp) ((fp).f_stream.fs_setinfo)
/* flags for close() */
#define SM_IO_CF_NONE 0x0000 /* default: "persistance" */
#define SM_IO_CF_SYNC 0x0001 /* "persistance" + sync */
#define SM_IO_CF_RM 0x0002 /* unlink (remove) at close */
/* if you change something here, change SM_STREAM_STRUCT too! */
struct sm_stream
{
sm_magic_T sm_magic;
/* operations */
open_F *fs_open;
close_F *fs_close;
read_F *fs_read;
write_F *fs_write;
#if SM_IO_GETPUTBUF
getbuf_F *fs_getbuf;
putbuf_F *fs_putbuf;
#endif
getinfo_F *fs_getinfo;
setinfo_F *fs_setinfo;
seek_F *fs_seek;
};
/*
** sm I/O state variables (internal only).
**
** Notes about double buffering:
** 1. the current buffer is always f_bf, it is
** a copy of f_rdbuf or f_wrbuf. Because it is a copy, the modifications
** only apply to f_bf, i.e., the data in f_rdbuf or f_wrbuf is NOT
** valid (unless the buffer is "inactive").
** 2. getc(), getb() etc do NOT switch the buffer to reading, i.e.,
** if the buffer is in WR mode, then getb() will return EOB..
** It might be useful to make f_bf a pointer to the correct buffer,
** but that complicates the single buffered case (unless some tricks
** are used, e.g., make f_bf a pointer and have at least one buffer
** in sm_file).
**
** XXX maybe need more cookies for statethread file descriptions,
** or maybe need something else than "int" for fd (void * ?).
*/
/* XXX if you change something here, change SM_FILE_STRUCT too! */
struct sm_file
{
sm_magic_T sm_magic; /* free <=> SM_MAGIC_NULL */
smbuf_T f_bf; /* the buffer (>= 1 byte, if !NULL) */
/* These can be used for any purpose by a file type implementation: */
void *f_cookie; /* should this be in f_bf? */
int f_ival;
sm_stream_T f_stream; /* XXX not a pointer right now! */
sm_intvl_T f_timeout; /* in seconds */
/* tricks to meet minimum requirements even when malloc() fails */
uchar f_nbuf[1]; /* guarantee a getc() buffer */
/* Unix stdio files get aligned to block boundaries on fseek() */
int f_blksize; /* st_blksize (may be != bf.size) */
off_t f_lseekoff; /* current lseek offset */
int f_dup_cnt; /* count file dup'd */
smbuf_T f_rdbuf;
smbuf_T f_wrbuf;
};
/* macros to abstract buffer management a bit */
#define f_r(fp) ((fp).f_bf.smb_r)
#define f_w(fp) ((fp).f_bf.smb_w)
#define f_p(fp) ((fp).f_bf.smb_p)
#define f_cookie(fp) ((fp).f_cookie)
#define f_fd(fp) ((fp).f_bf.smb_fd)
#define f_flags(fp) ((fp).f_bf.smb_flags)
#if SM_IO_ERR_VAL
# define f_error(fp) ((fp).f_bf.smb_error)
#endif
#define f_bf(fp) ((fp).f_bf)
#define f_bfbase(fp) ((fp).f_bf.smb_base)
#define f_bfsize(fp) ((fp).f_bf.smb_size)
#define f_blksize(fp) ((fp).f_blksize)
#define f_rd_r(fp) ((fp).f_rdbuf.smb_r)
#define f_rd_p(fp) ((fp).f_rdbuf.smb_p)
#define f_rd_fd(fp) ((fp).f_rdbuf.smb_fd)
#define f_wr_w(fp) ((fp).f_wrbuf.smb_w)
#define f_wr_p(fp) ((fp).f_wrbuf.smb_p)
#define f_wr_fd(fp) ((fp).f_wrbuf.smb_fd)
#define f_rd_bfbase(fp) ((fp).f_rdbuf.smb_base)
#define f_wr_bfbase(fp) ((fp).f_wrbuf.smb_base)
#define f_rd_bfsize(fp) ((fp).f_rdbuf.smb_size)
#define f_wr_bfsize(fp) ((fp).f_wrbuf.smb_size)
#define f_rd_flags(fp) ((fp).f_rdbuf.smb_flags)
#define f_wr_flags(fp) ((fp).f_wrbuf.smb_flags)
__BEGIN_DECLS
extern sm_file_T SmIoF[];
extern sm_file_T SmFtStdio_def;
extern sm_file_T SmFtStdiofd_def;
extern sm_file_T SmFtString_def;
extern sm_file_T SmFtSyslog_def;
extern sm_file_T SmFtRealStdio_def;
#define SMIOIN_FILENO 0
#define SMIOOUT_FILENO 1
#define SMIOERR_FILENO 2
#define SMIO_FILES 3
/* Common predefined and already (usually) open files (exposed) */
#define smioin (&SmIoF[SMIOIN_FILENO])
#define smioout (&SmIoF[SMIOOUT_FILENO])
#define smioerr (&SmIoF[SMIOERR_FILENO])
#define SmFtStdio (&SmFtStdio_def)
#define SmFtStdiofd (&SmFtStdiofd_def)
#define SmFtString (&SmFtString_def)
#define SmFtSyslog (&SmFtSyslog_def)
#define SmFtRealStdio (&SmFtRealStdio_def)
#define SmStStdio (&(SmFtStdio_def.f_stream))
#define SmStStdiofd (&(SmFtStdiofd_def.f_stream))
#define SmStString (&(SmFtString_def.f_stream))
#define SmStSyslog (&(SmFtSyslog_def.f_stream))
#define SmStRealStdio (&(SmFtRealStdio_def.f_stream))
#define SM_FILE_FUNCT_ASSIGN(dst, src) dst = src
#if SM_IO_GETPUTBUF
# define SM_IO_GPBUF_ASSIGN(f) \
f_getbuf(f) = (getbuf); \
f_putbuf(f) = (putbuf)
#else /* SM_IO_GETPUTBUF */
# define SM_IO_GPBUF_ASSIGN(f)
#endif /* SM_IO_GETPUTBUF */
#if SM_IO_GETPUTBUF
# define SM_STREAM_STRUCT(open, close, read, write, getbuf, putbuf, seek, get, set) \
{SM_STREAM_MAGIC, (open), (close), \
(read), (write), (getbuf), (putbuf), (get), (set), (seek) }
#else
# define SM_STREAM_STRUCT(open, close, read, write, getbuf, putbuf, seek, get, set) \
{SM_STREAM_MAGIC, (open), (close), \
(read), (write), (get), (set), (seek) }
#endif /* SM_IO_GETPUTBUF */
#define SM_FILE_STRUCT(name, fileno, open, close, read, write, getbuf, putbuf, seek, get, set, flags, timeout) \
{SM_FILE_MAGIC, SM_INIT_BUF(flags, fileno), \
(void *) 0, 0, \
SM_STREAM_STRUCT(open, close, read, write, getbuf, putbuf, seek, get, set), \
(timeout)}
#ifdef __STDC__
# define SM_IO_SET_TYPE(f, name, open, close, read, write, getbuf, putbuf, seek, get, set, timeout) \
(f) = SM_FILE_STRUCT(name, -1, open, close, read, write, getbuf, putbuf, seek, get, set, 0, timeout)
# define SM_IO_INIT_TYPE(f, name, open, close, read, write, getbuf, putbuf, seek, get, set, timeout)
#else /* __STDC__ */
# define SM_IO_SET_TYPE(f, name, open, close, read, write, getbuf, putbuf, seek, get, set, timeout) (f)
/* XXX fix these? abstract out buffer assignments! */
# define SM_IO_INIT_TYPE(f, name, open, close, read, write, getbuf, putbuf, seek, get, set, timeout) \
(f).sm_magic = SM_FILE_MAGIC; \
f_p(f) = (uchar *) 0; \
f_r(f) = 0; \
f_w(f) = 0; \
f_flags(f) = 0L; \
f_fd(f) = 0; \
f_bfbase(f) = (uchar *) 0; \
f_bfsize(f) = 0; \
(f).f_cookie = (void *) 0; \
(f).f_ival = 0; \
f_open(f) = (open); \
f_close(f) = (close); \
f_read(f) = (read); \
f_write(f) = (write); \
SM_IO_GPBUF_ASSIGN(f); \
f_seek(f) = (seek); \
f_setinfo(f) = (set); \
f_getinfo(f) = (get); \
(f).f_timeout = (timeout);
#endif /* __STDC__ */
__END_DECLS
#define SM_IS_FP(fp) SM_REQUIRE_ISA((fp), SM_FILE_MAGIC)
/* Internal flags */
/* XXX Order this differently so the masks down below are simpler */
/* XXX get rid of some of these, e.g., buffering */
/* read/write directions: */
#define SMRD 0x000001 /* OK to read */
#define SMWR 0x000002 /* OK to write */
/* RD and WR are never simultaneously asserted */
#define SMRW 0x000004 /* open for reading & writing */
#define SMMODEMASK 0x000007 /* read/write mode bits */
/* buffering: */
#define SMFBF 0x000010 /* fully buffered */
#define SMNBF 0x000020 /* unbuffered */
/* conditions: EOF/error */
#define SMFEOF 0x000040 /* found EOF */
#define SMERR 0x000080 /* found error */
/* add a flag for timeout? what about other I/O errors? */
/* misc */
#define SMMBF 0x000100 /* buf is from malloc */
#define SMAPP 0x000200 /* fdopen()ed in append mode */
#define SMSTR 0x000400 /* this is an snprintf string */
#define SMSTRSTR 0x000800 /* this is a str */
#define SMOPT 0x001000 /* do fseek() optimisation */
#define SMNPT 0x002000 /* do not do fseek() optimisation */
#define SMOFF 0x004000 /* set iff offset is in fact correct */
#define SMALC 0x010000 /* allocate string space dynamically */
#define SMDOUBLE 0x020000 /* double buffered */
#define SMRDBUF 0x040000 /* using rd buf */
#define SMWRBUF 0x080000 /* using wr buf */
#define SMBLOCK 0x100000 /* blocking mode */
#define sm_io_blocking(fp) (f_flags(*fp) & SMBLOCK)
#define sm_io_setblocking(fp) f_flags(*fp) |= SMBLOCK
#define sm_io_clrblocking(fp) f_flags(*fp) &= ~SMBLOCK
#define sm_io_double(fp) (f_flags(*fp) & SMDOUBLE)
#define sm_io_setdouble(fp) f_flags(*fp) |= SMDOUBLE
#define sm_io_clrdouble(fp) f_flags(*fp) &= ~SMDOUBLE
/* defines for timeout constants */
#define SM_TIME_IMMEDIATE ((sm_intvl_T) (0))
#define SM_TIME_FOREVER ((sm_intvl_T) (-1))
#define SM_TIME_DEFAULT ((sm_intvl_T) (-2))
/* Exposed buffering type flags */
#define SM_IO_FBF 0 /* setvbuf should set fully buffered */
#define SM_IO_NBF 1 /* setvbuf should set unbuffered */
/*
** size of buffer used by setbuf.
** If underlying filesystem blocksize is discoverable that is used instead
*/
#define SM_IO_BUFSIZ 4096
/*
** XXX how to return this properly from the functions?
** how does this fit into our error model
*/
#define SM_IO_EOF (-1)
#define SM_IO_EOB (-2)
__BEGIN_DECLS
void sm_io_clearerr(sm_file_T *_fp);
sm_ret_T sm_io_close(sm_file_T *_fp, int _flags);
sm_ret_T sm_io_dup(sm_file_T *_fp);
int sm_io_eof(sm_file_T *_fp);
int sm_io_error(sm_file_T *_fp);
char *sm_io_fgets(sm_file_T *_fp, int, char *_buf, int _n);
sm_ret_T sm_io_flush(sm_file_T *_fp);
sm_ret_T sm_fgetline(sm_file_T *_fp, sm_str_P _str);
sm_ret_T sm_fgetline0(sm_file_T *_fp, sm_str_P _str);
sm_ret_T sm_io_ffill(sm_file_T *_fp, size_t _n);
sm_ret_T sm_io_fgetuint32(sm_file_T *_fp, uint32_t *_n);
sm_ret_T sm_io_fgetn(sm_file_T *_fp, uchar *_s, size_t _l);
sm_ret_T sm_io_fskip(sm_file_T *_fp, size_t _l);
#if !SM_NO_CSTR
sm_ret_T sm_io_fgetncstr(sm_file_T *_fp, sm_cstr_P *_pcstr, uint _l);
#endif
int
#if SM_CHK_PRINTF
PRINTFLIKE(2, 3)
#endif
sm_io_fprintf(sm_file_T *_fp,const char *_fmt, ...);
sm_ret_T sm_io_fputs(sm_file_T *_fp, const uchar *_s);
sm_ret_T sm_io_fputuint32(sm_file_T *_fp, uint32_t _n);
sm_ret_T sm_io_fput2uint32(sm_file_T *_fp, uint32_t _n1, uint32_t _n2);
sm_ret_T sm_io_fput3uint32(sm_file_T *_fp, uint32_t _n1, uint32_t _n2, uint32_t _n3);
sm_ret_T sm_io_fputv(sm_file_T *_fp, ...);
sm_ret_T sm_io_fputstr(sm_file_T *_fp, const sm_str_P _s);
#if !SM_NO_CSTR
sm_ret_T sm_io_fputcstr(sm_file_T *_fp, const sm_cstr_P _cstr);
#endif
sm_ret_T sm_io_fputn(sm_file_T *_fp, const uchar *_s, size_t _l);
sm_ret_T sm_io_fpad(sm_file_T *_fp, size_t _len);
sm_ret_T sm_io_falign(sm_file_T *_fp, size_t _n);
int SCANFLIKE(2, 3)
sm_io_fscanf(sm_file_T *_fp, const char *_fmt, ...);
int sm_io_getc(sm_file_T *_fp);
int sm_io_getinfo(sm_file_T *_fp, int _what, void *_valp);
sm_ret_T sm_io_open(const sm_stream_T *_type, const void *_info,
int _flags, sm_file_T **_newfp, ...);
#if 0
sm_ret_T sm_io_reopen(const sm_stream_T *_type, const void *_info,
int _flags, sm_file_T *_fp, sm_file_T **_newfp,
sm_rpool_P _rpool);
#endif /* 0 */
int sm_io_purge(sm_file_T *_fp);
int sm_io_putc(sm_file_T *_fp, int _ch);
read_F sm_io_read;
int sm_io_seek(sm_file_T *_fp, long _offset, int _whence);
int sm_io_setinfo(sm_file_T *_fp, int _what, void *_valp);
sm_f_flags_T sm_whatbuf(sm_file_T *_fp, size_t *_bufsize);
sm_ret_T sm_io_setvbuf(sm_file_T *_fp, uchar *_buf, int _mode, size_t _size);
int SCANFLIKE(2, 3)
sm_io_sscanf(const char *_str, char const *_fmt, ...);
int sm_vsscanf(const char *_str, const char *_fmt, va_list _ap);
long sm_io_tell(sm_file_T *_fp);
int sm_io_ungetc(sm_file_T *_fp, int _c);
int sm_io_vfprintf(sm_file_T *_fp, const char *_fmt0, va_list _ap);
write_F sm_io_write;
sm_ret_T sm_io_fopen(char *_pathname, int _flags, sm_file_T **_newfp, ...);
#if 0
sm_file_T *sm_io_stdioopen(FILE *_stream, char *_mode);
#endif
int sm_vsnprintf(char *_str, size_t _n, const char *_fmt, va_list _ap);
int sm_asprintf(char **_str, const char *_fmt, ...);
int sm_vasprintf(char **_str, const char *_fmt, va_list _ap);
sm_ret_T sm_fd_nonblock(int _fd, bool _on);
sm_ret_T sm_fp_nonblock(sm_file_T *_fp, bool _on);
sm_ret_T sm_iotord(sm_file_T *_fp);
sm_ret_T sm_write_wait(int _fd, int _timeout);
#ifdef SMSTRSTR
int
#if SM_CHK_PRINTF
PRINTFLIKE(2, 3)
#endif
sm_strprintf(sm_str_P _str, const char *_fmt, ...);
int
sm_strvprintf(sm_str_P _str, const char *_fmt, va_list _ap);
sm_ret_T sm_str2file(sm_str_P _str, sm_file_T *_fp);
#endif /* SMSTRSTR */
__END_DECLS
/*
** Functions internal to the implementation.
*/
__BEGIN_DECLS
int sm_rget(sm_file_T *_fp);
int sm_vfscanf(sm_file_T *_fp, char const *_fmt0, va_list _ap);
int sm_wbuf(sm_file_T *_fp, int _c);
__END_DECLS
/*
** The macros are here so that we can
** define function versions in the library.
*/
#define sm_getc(f) \
(--f_r(*f) < 0 ? \
sm_rget(f) : \
(int)(*f_p(*(f))++))
/*
** return element out of buffer or SM_IO_EOB if buffer is empty
** Note: to do this properly (accessing the buffer almost directly)
** we should provide some form of locking. Currently it's up to
** the application to "ensure" that the buffer isn't modified, i.e.,
** the file must not be accessed in any other way inbetween.
*/
#define sm_getb(f) \
(f_r(*f) == 0 ? SM_IO_EOB : (--f_r(*f), (int)(*f_p(*(f))++)))
/*
** This has been tuned to generate reasonable code on the vax using pcc.
** (It also generates reasonable x86 code using gcc.)
*/
#define sm_putc(f, c) \
(--f_w(*f) < 0 ? \
sm_wbuf(f, (int)(c)) : \
(*f_p(*(f)) = (c), (int)*f_p(*(f))++))
#define sm_eof(p) ((f_flags(*p) & SMFEOF) != 0)
#define sm_error(p) ((f_flags(*p) & SMERR) != 0)
#define sm_clearerr(p) ((void)(f_flags(*p) &= ~(SMERR|SMFEOF)))
#define sm_io_eof(p) sm_eof(p)
#define sm_io_error(p) sm_error(p)
#define sm_io_clearerr(p) sm_clearerr(p)
#ifndef lint
/* # ifndef _POSIX_SOURCE * XXX WHY XXX */
# define sm_io_getc(fp) sm_getc(fp)
# if 0
# define sm_io_putc(fp, x) sm_putc(fp, x)
# endif
/* # endif * _POSIX_SOURCE */
#endif /* ! lint */
/* valid file description (very simple test) */
/* #define ISVALIDFD(fd) ((fd) >= 0) */
#define sm_io_fileno(fp) sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)
/* I/O descriptors for sm_fvwrite() */
struct sm_iov
{
void *iov_base;
size_t iov_len;
};
typedef struct sm_iov sm_iov_T;
struct sm_uio
{
sm_iov_T *uio_iov;
int uio_iovcnt; /* number of iov's */
int uio_resid;
};
typedef struct sm_uio sm_uio_T;
#ifndef FDSET_CAST
# define FDSET_CAST /* empty cast for fd_set arg to select */
#endif
/* minimum buffer size required? */
#if !HAVE_STBLKSZ_INET
# ifndef SM_IO_MIN_BUF
# define SM_IO_MIN_BUF SM_IO_BUFSIZ
# endif
#endif
#if !HAVE_ASPRINTF
int
#if SM_CHK_PRINTF
PRINTFLIKE(2, 3)
#endif
asprintf(char **_str, const char *_fmt, ...);
#endif /* !HAVE_ASPRINTF */
#endif /* SM_IO_H */
syntax highlighted by Code2HTML, v. 0.9.1