以下使unix网络编程中的五个打印函数,主要是学习一下可变参数的函数的编写
//err.cpp
#include"unp.h"
#include<stdarg.h>
#include<syslog.h>
int daemon_proc;
static void err_doit(int,int,const char*,va_list);
void err_dump(const char *, ...);
void err_msg(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
//-----------------------------------------
// Nonfatal error related to system callergraph
// Print message and return
//-----------------------------------------
void
err_ret(const char* fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,LOG_INFO,fmt,ap);
va_end(ap);
return ;
}
//-----------------------------------------
// fatal error related to system callergraph
// Print message ,and terminate
//-----------------------------------------
void
err_sys(const char*fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,LOG_ERR,fmt,ap);
va_end(ap);
exit(1);
}
//-----------------------------------------
// fatal error related to system callergraph
// Print message ,dump core ,and terminate
//-----------------------------------------
void
err_dump(const char* fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,LOG_ERR,fmt,ap);
va_end(ap);
abort();
exit(1);
}
//-----------------------------------------
// Nonfatal error unrelated to system callergraph
// Print message and return
//-----------------------------------------
void
err_msg(const char* fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(0,LOG_INFO,fmt,ap);
va_end(ap);
return ;
}
//-----------------------------------------
// fatal error unrelated to system callergraph
// Print message and return
//-----------------------------------------
void
err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(0,LOG_ERR,fmt,ap);
va_end(ap);
exit(1);
}
//-----------------------------------------
// print message and return to caller
// caller specifile "errnoflag" and "level"
//-----------------------------------------
static void
err_doit(int errnoflag,int level,const char *fmt,va_list ap)
{
int errno_save,n;
char buf[MAXLINE+1];
errno_save = errno; //value caller might want printed
#ifdef HAVE_VSNPRINTF
vsnprintf(buf,fmt,ap); //safe
#else
vsprintf(buf,fmt,ap); //not safe
#endif
n =strlen(buf);
if(errnoflag)
snprintf(buf+n,MAXLINE-n,":%s",strerror(errno_save));
strcat(buf,"\n");
if(daemon_proc)
{
syslog(level,buf);
}
else{
fflush(stdout); //in case stdout and stderr are the same
fputs(buf,stderr);
fflush(stderr);
}
return;
}
va_list 数据结构 va_list ap; va_start(ap,fmt); va_end(ap); int val=va_arg(vl,int);
int vsprintf (char * s, const char * format, va_list arg );
void
err_ret(const char* fmt, ...)
{
va_list ap;
va_start(ap,fmt);
err_doit(1,LOG_INFO,fmt,ap);
va_end(ap);
return ;
}
在这里 va_arg没有提到。用法和例子 http://www.cplusplus.com/reference/cstdarg/
用到的头文件 做了一些简化
/* include unph */
/* Our own header. Tabs are set for 4 spaces, not 8 */
#ifndef __unp_h
#define __unp_h
//#include "../config.h" /* configuration options for current OS */
/* "../config.h" is generated by configure */
/* If anything changes in the following list of #includes, must change
acsite.m4 also, for configure's tests. */
#include <sys/types.h> /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <fcntl.h> /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h> /* for convenience */
#endif
#ifdef HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
#ifdef HAVE_POLL_H
# include <poll.h> /* for convenience */
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h> /* for convenience */
#endif
/* Three headers are normally needed for socket/file ioctl's:
* <sys/ioctl.h>, <sys/filio.h>, and <sys/sockio.h>.
*/
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#ifdef HAVE_NET_IF_DL_H
# include <net/if_dl.h>
#endif
/* OSF/1 actually disables recv() and send() in <sys/socket.h> */
#ifdef __osf__
#undef recv
#undef send
#define recv(a,b,c,d) recvfrom(a,b,c,d,0,0)
#define send(a,b,c,d) sendto(a,b,c,d,0,0)
#endif
#ifndef INADDR_NONE
/* $$.Ic INADDR_NONE$$ */
#define INADDR_NONE 0xffffffff /* should have been in <netinet/in.h> */
#endif
#ifndef SHUT_RD /* these three Posix.1g names are quite new */
#define SHUT_RD 0 /* shutdown for reading */
#define SHUT_WR 1 /* shutdown for writing */
#define SHUT_RDWR 2 /* shutdown for reading and writing */
/* $$.Ic SHUT_RD$$ */
/* $$.Ic SHUT_WR$$ */
/* $$.Ic SHUT_RDWR$$ */
#endif
/* *INDENT-OFF* */
#ifndef INET_ADDRSTRLEN
/* $$.Ic INET_ADDRSTRLEN$$ */
#define INET_ADDRSTRLEN 16 /* "ddd.ddd.ddd.ddd\0"
1234567890123456 */
#endif
/* Define following even if IPv6 not supported, so we can always allocate
an adequately-sized buffer, without #ifdefs in the code. */
#ifndef INET6_ADDRSTRLEN
/* $$.Ic INET6_ADDRSTRLEN$$ */
#define INET6_ADDRSTRLEN 46 /* max size of IPv6 address string:
"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" or
"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd\0"
1234567890123456789012345678901234567890123456 */
#endif
/* *INDENT-ON* */
/* Define bzero() as a macro if it's not in standard C library. */
#ifndef HAVE_BZERO
#define bzero(ptr,n) memset(ptr, 0, n)
/* $$.If bzero$$ */
/* $$.If memset$$ */
#endif
/* Older resolvers do not have gethostbyname2() */
#ifndef HAVE_GETHOSTBYNAME2
#define gethostbyname2(host,family) gethostbyname((host))
#endif
/* The structure returned by recvfrom_flags() */
//struct in_pktinfo {
// struct in_addr ipi_addr; /* dst IPv4 address */
//int ipi_ifindex;/* received interface index */
//};
/* $$.It in_pktinfo$$ */
/* $$.Ib ipi_addr$$ */
/* $$.Ib ipi_ifindex$$ */
/* We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few
implementations support them today. These two macros really need
an ALIGN() macro, but each implementation does this differently. */
#ifndef CMSG_LEN
/* $$.Ic CMSG_LEN$$ */
#define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size))
#endif
#ifndef CMSG_SPACE
/* $$.Ic CMSG_SPACE$$ */
#define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
#endif
/* Posix.1g requires the SUN_LEN() macro but not all implementations DefinE
it (yet). Note that this 4.4BSD macro works regardless whether there is
a length field or not. */
#ifndef SUN_LEN
/* $$.Im SUN_LEN$$ */
# define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
/* Posix.1g renames "Unix domain" as "local IPC".
But not all systems DefinE AF_LOCAL and PF_LOCAL (yet). */
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif
#ifndef PF_LOCAL
#define PF_LOCAL PF_UNIX
#endif
/* Posix.1g requires that an #include of <poll.h> DefinE INFTIM, but many
systems still DefinE it in <sys/stropts.h>. We don't want to include
all the streams stuff if it's not needed, so we just DefinE INFTIM here.
This is the standard value, but there's no guarantee it is -1. */
#ifndef INFTIM
#define INFTIM (-1) /* infinite poll timeout */
/* $$.Ic INFTIM$$ */
#ifdef HAVE_POLL_H
#define INFTIM_UNPH /* tell unpxti.h we defined it */
#endif
#endif
/* Following could be derived from SOMAXCONN in <sys/socket.h>, but many
kernels still #define it as 5, while actually supporting many more */
#define LISTENQ 1024 /* 2nd argument to listen() */
/* Miscellaneous constants */
#define MAXLINE 4096 /* max text line length */
#define MAXSOCKADDR 128 /* max socket address structure size */
#define BUFFSIZE 8192 /* buffer size for reads and writes */
/* Define some port number that can be used for client-servers */
#define SERV_PORT 9877 /* TCP and UDP client-servers */
#define SERV_PORT_STR "9877" /* TCP and UDP client-servers */
#define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream cli-serv */
#define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram cli-serv */
/* $$.ix [LISTENQ]~constant,~definition~of$$ */
/* $$.ix [MAXLINE]~constant,~definition~of$$ */
/* $$.ix [MAXSOCKADDR]~constant,~definition~of$$ */
/* $$.ix [BUFFSIZE]~constant,~definition~of$$ */
/* $$.ix [SERV_PORT]~constant,~definition~of$$ */
/* $$.ix [UNIXSTR_PATH]~constant,~definition~of$$ */
/* $$.ix [UNIXDG_PATH]~constant,~definition~of$$ */
/* Following shortens all the type casts of pointer arguments */
#define SA struct sockaddr
//#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* default file access permissions for new files */
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
/* default permissions for new directories */
typedef void Sigfunc(int); /* for signal handlers */
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
#ifndef HAVE_ADDRINFO_STRUCT
//# include "../lib/addrinfo.h"
#endif
#ifndef HAVE_IF_NAMEINDEX_STRUCT
struct if_nameindex {
unsigned int if_index; /* 1, 2, ... */
char *if_name; /* null terminated name: "le0", ... */
};
/* $$.It if_nameindex$$ */
/* $$.Ib if_index$$ */
/* $$.Ib if_name$$ */
#endif
#ifndef HAVE_TIMESPEC_STRUCT
//struct timespec {
// time_t tv_sec; /* seconds */
// long tv_nsec; /* and nanoseconds */
//};
/* $$.It timespec$$ */
/* $$.Ib tv_sec$$ */
/* $$.Ib tv_nsec$$ */
#endif
/* end unph */
/* prototypes for our own library functions */
void err_dump(const char *, ...);
void err_msg(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
#endif /* __unp_h */