// -*-c++-*- /* $Id: rpctypes.h,v 1.40 2001/08/23 22:55:38 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _RPCTYPES_H_ #define _RPCTYPES_H_ 1 #include "str.h" #include "vec.h" #include "array.h" #include "union.h" #include "keyfunc.h" #include "err.h" struct rpcgen_table { const char *name; const std::type_info *type_arg; void *(*alloc_arg) (); xdrproc_t xdr_arg; void (*print_arg) (const void *, const strbuf *, int, const char *, const char *); const std::type_info *type_res; void *(*alloc_res) (); xdrproc_t xdr_res; void (*print_res) (const void *, const strbuf *, int, const char *, const char *); }; struct rpc_program { u_int32_t progno; u_int32_t versno; const struct rpcgen_table *tbl; size_t nproc; const char *name; }; enum { RPC_INFINITY = 0x7fffffff }; template class rpc_ptr { T *p; public: rpc_ptr () { p = NULL; } rpc_ptr (const rpc_ptr &rp) { p = rp ? New T (*rp) : NULL; } ~rpc_ptr () { delete p; } void clear () { delete p; p = NULL; } rpc_ptr &alloc () { if (!p) p = New T; return *this; } rpc_ptr &assign (T *tp) { clear (); p = tp; return *this; } T *release () { T *r = p; p = NULL; return r; } operator T *() const { return p; } T *operator-> () const { return p; } T &operator* () const { return *p; } rpc_ptr &operator= (const rpc_ptr &rp) { if (!rp.p) clear (); else if (p) *p = *rp.p; else p = New T (*rp.p); return *this; } void swap (rpc_ptr &a) { T *ap = a.p; a.p = p; p = ap; } }; template inline void swap (rpc_ptr &a, rpc_ptr &b) { a.swap (b); } struct freemode { enum freemode_t { NOFREE, DELARRAY, XFREE, DELETE }; freemode_t mode; }; template class rpc_vec : protected freemode { public: typedef toarray (T) elm_t; enum { maxsize = max }; private: size_t nelm; elm_t *vec; #ifdef CHECK_BOUNDS #define bcheck(i) assert (size_t (i) < nelm) #define mcheck(i) assert (size_t (i) <= maxsize) #else /* !CHECK_BOUNDS */ #define bcheck(i) #define mcheck(i) #endif /* !CHECK_BOUNDS */ #define assign(v) \ do { \ setsize (v.size ()); \ elm_t *d = vec; \ const elm_t *s = v.base (), *e = v.lim (); \ while (s < e) \ *d++ = *s++; \ } while (0) #define sassign(v) \ if (&v != this) \ assign (v) void init () { mode = NOFREE; nelm = 0; vec = NULL; } void del () { switch (mode) { case NOFREE: break; case DELARRAY: delete[] vec; break; case XFREE: xfree (vec); break; case DELETE: delete vec; break; } } public: rpc_vec () { init (); } rpc_vec (const rpc_vec &v) { init (); sassign (v); } #if 0 template rpc_vec (const rpc_vec &v) { init (); assign (v); } template rpc_vec (const array &v) { switch (0) case 0: case m <= max:; init (); assign (v); } #endif ~rpc_vec () { del (); } void clear () { del (); init (); } rpc_vec &operator= (const rpc_vec &v) { sassign (v); return *this; } template rpc_vec &operator= (const rpc_vec &v) { assign (v); return *this; } template rpc_vec &operator= (const ::vec &v) { assign (v); return *this; } template rpc_vec &operator= (const array &v) { switch (0) case 0: case m <= max:; assign (v); return *this; } #if 0 /* These were renamed operator=. operator= copies elements, while * set just sets the pointers. */ template rpc_vec &set (const rpc_vec &v) { assign (v); return *this; } template rpc_vec &set (const array &v) { switch (0) case 0: case m <= max:; assign (v); return *this; } #endif rpc_vec &set (elm_t *base, size_t len, freemode_t m = NOFREE) { mcheck (len); del (); mode = m; nelm = len; vec = base; return *this; } template rpc_vec &set (const ::vec &v) { set (v.base (), v.size ()); } void swap (rpc_vec &a) { freemode_t m = a.mode; a.mode = mode; mode = m; size_t n = a.nelm; a.nelm = nelm; nelm = n; elm_t *v = a.vec; a.vec = vec; vec = v; } void setsize (size_t n) { mcheck (n); #ifdef DMALLOC if (true) #else /* !DMALLOC */ if (mode != DELARRAY || n != nelm) #endif /* !DMALLOC */ { del (); if (n) { mode = DELARRAY; nelm = n; #ifndef DMALLOC vec = new elm_t[nelm]; #else /* DMALLOC */ vec = new (dmalloc, stktrace (__FILE__), __LINE__) elm_t[nelm]; #endif /* DMALLOC */ } else init (); } } size_t size () const { return nelm; } elm_t *base () { return vec; } const elm_t *base () const { return vec; } elm_t *lim () { return vec + nelm; } const elm_t *lim () const { return vec + nelm; } elm_t &operator[] (size_t i) { bcheck (i); return vec[i]; } const elm_t &operator[] (size_t i) const { bcheck (i); return vec[i]; } elm_t &at (size_t i) { bcheck (i); return vec[i]; } const elm_t &at (size_t i) const { bcheck (i); return vec[i]; } #undef bcheck #undef mcheck #undef assign #undef sassign }; template void swap (rpc_vec &a, rpc_vec &b) { a.swap (b); } template struct rpc_str : str { enum { maxsize = max }; private: void check () { assert (len () == strlen (cstr ())); assert (len () <= maxsize); } public: rpc_str () : str (rpc_emptystr) {} rpc_str (const rpc_str &s) : str (s) {} rpc_str (const str &s) : str (s) { check (); } rpc_str (const char *p) : str (p) { assert (len () <= maxsize); } rpc_str (const strbuf &b) : str (b) { check (); } rpc_str (const char *buf, size_t len) : str (buf, len) { check (); } rpc_str (const iovec *iov, int cnt) : str (iov, cnt) { check (); } rpc_str (mstr &m) : str (m) { check (); } rpc_str &operator= (const rpc_str &s) { str::operator= (s); return *this; } rpc_str &operator= (const char *p) { str::operator= (p); if (p) assert (len () <= maxsize); return *this; } template rpc_str &operator= (const T &t) { str::operator= (t); check (); return *this; } rpc_str &operator= (mstr &m) { str::operator= (m); check (); return *this; } rpc_str &setbuf (const char *buf, size_t len) { str::setbuf (buf, len); check (); return *this; } rpc_str &setiov (const iovec *iov, int cnt) { str::setiov (iov, cnt); check (); return *this; } }; template struct rpc_opaque : array { rpc_opaque () { bzero (base (), size ()); } }; template struct rpc_bytes : rpc_vec { void setstrmem (const str &s) { set (s.cstr (), s.len (), NOFREE); } rpc_bytes &operator= (const str &s) { setsize (s.len ()); memcpy (base (), s.cstr (), size ()); return *this; } template rpc_bytes &operator= (const rpc_vec &v) { rpc_vec::operator= (v); return *this; } template rpc_bytes &operator= (const array &v) { rpc_vec::operator= (v); return *this; } }; #if 0 template struct equals > { equals () {} bool operator() (const rpc_opaque &a, const rpc_opaque &b) const { return !memcmp (a.base (), b.base (), n); } }; template struct equals > { equals () {} bool operator() (const rpc_bytes &a, const rpc_bytes &b) const { return a.size () == b.size () && !memcmp (a.base (), b.base (), a.size ()); } }; #endif template inline bool operator== (const rpc_opaque &a, const rpc_opaque &b) { return !memcmp (a.base (), b.base (), n); } template inline bool operator== (const rpc_bytes &a, const rpc_bytes &b) { return a.size () == b.size () && !memcmp (a.base (), b.base (), a.size ()); } template inline bool operator!= (const rpc_opaque &a, const rpc_opaque &b) { return memcmp (a.base (), b.base (), n); } template inline bool operator!= (const rpc_bytes &a, const rpc_bytes &b) { return a.size () != b.size () || memcmp (a.base (), b.base (), a.size ()); } #if 0 template inline bool operator== (const rpc_bytes &a, const rpc_bytes &b) { return a.size () == b.size () && !memcmp (a.base (), b.base (), a.size ()); } template inline bool operator== (const rpc_bytes &a, const rpc_opaque &b) { return a.size () == b.size () && !memcmp (a.base (), b.base (), a.size ()); } template inline bool operator== (const rpc_opaque &a, const rpc_bytes &b) { return a.size () == b.size () && !memcmp (a.base (), b.base (), a.size ()); } template inline bool operator!= (const rpc_bytes &a, const rpc_bytes &b) { return a.size () != b.size () || memcmp (a.base (), b.base (), a.size ()); } template inline bool operator!= (const rpc_bytes &a, const rpc_opaque &b) { return a.size () != b.size () || memcmp (a.base (), b.base (), a.size ()); } template inline bool operator!= (const rpc_opaque &a, const rpc_bytes &b) { return a.size () != b.size () || memcmp (a.base (), b.base (), a.size ()); } #endif template struct hashfn > { hashfn () {} bool operator () (const rpc_opaque &a) const { return hash_bytes (a.base (), n); } }; template struct hashfn > { hashfn () {} bool operator () (const rpc_bytes &a) const { return hash_bytes (a.base (), a.size ()); } }; /* * Default traversal functions */ template inline bool rpc_traverse (T &t, array &obj) { typedef array::elm_t elm_t; elm_t *p = obj.base (); elm_t *e = obj.lim (); while (p < e) if (!rpc_traverse (t, *p++)) return false; return true; } template inline bool rpc_traverse (T &t, rpc_vec &obj) { typedef rpc_vec::elm_t elm_t; u_int32_t size = obj.size (); if (!rpc_traverse (t, size) || size > obj.maxsize) return false; if (size != obj.size ()) obj.setsize (size); elm_t *p = obj.base (); elm_t *e = obj.lim (); while (p < e) if (!rpc_traverse (t, *p++)) return false; return true; } template inline bool rpc_traverse (T &t, rpc_ptr &obj) { bool nonnil = obj; if (!rpc_traverse (t, nonnil)) return false; if (nonnil) return rpc_traverse (t, *obj.alloc ()); obj.clear (); return true; } template inline bool rpc_traverse (T &t, bool &obj) { u_int32_t val = obj; if (!rpc_traverse (t, val)) return false; obj = val; return true; } template inline bool rpc_traverse (T &t, u_int64_t &obj) { u_int32_t hi = obj >> 32; u_int32_t lo = obj; if (!rpc_traverse (t, hi) || !rpc_traverse (t, lo)) return false; obj = u_int64_t (hi) << 32 | lo; return true; } template inline bool rpc_traverse (T &t, int32_t &obj) { return rpc_traverse (t, reinterpret_cast (obj)); } template inline bool rpc_traverse (T &t, int64_t &obj) { return rpc_traverse (t, reinterpret_cast (obj)); } #define DUMBTRANS(T, type) \ inline bool \ rpc_traverse (T &, type &) \ { \ return true; \ } #define DUMBTRAVERSE(T) \ DUMBTRANS(T, char) \ DUMBTRANS(T, bool) \ DUMBTRANS(T, u_int32_t) \ DUMBTRANS(T, u_int64_t) \ template DUMBTRANS(T, rpc_str) \ template DUMBTRANS(T, rpc_opaque) \ template DUMBTRANS(T, rpc_bytes) /* * Stompcast support */ struct stompcast_t {}; extern const stompcast_t _stompcast; DUMBTRAVERSE(const stompcast_t) template inline bool stompcast (T &t) { return rpc_traverse (_stompcast, t); } /* * Clearing support */ struct rpc_clear_t {}; extern struct rpc_clear_t _rpcclear; extern const str rpc_emptystr; inline bool rpc_traverse (rpc_clear_t &, u_int32_t &obj) { obj = 0; return true; } template inline bool rpc_traverse (rpc_clear_t &, rpc_opaque &obj) { bzero (obj.base (), obj.size ()); return true; } template inline bool rpc_traverse (rpc_clear_t &, rpc_bytes &obj) { obj.setsize (0); return true; } template inline bool rpc_traverse (rpc_clear_t &, rpc_str &obj) { obj = rpc_emptystr; return true; } template inline bool rpc_traverse (rpc_clear_t &, rpc_ptr &obj) { obj.clear (); return true; } template inline bool rpc_traverse (rpc_clear_t &, rpc_vec &obj) { obj.setsize (0); return true; } template inline void rpc_clear (T &obj) { rpc_traverse (_rpcclear, obj); } /* * Pretty-printing functions */ #define RPC_PRINT_TYPE_DECL(type) \ void print_##type (const void *objp, const strbuf *, \ int recdepth = RPC_INFINITY, const char *name = "", \ const char *prefix = ""); #define RPC_PRINT_DECL(type) \ const strbuf &rpc_print (const strbuf &sb, const type &obj, \ int recdepth = RPC_INFINITY, const char *name = "", \ const char *prefix = ""); #define RPC_PRINT_DEFINE(T) \ void \ print_##T (const void *objp, const strbuf *sbp, int recdepth, \ const char *name, const char *prefix) \ { \ rpc_print (sbp ? *sbp : warnx, *static_cast (objp), \ recdepth, name, prefix); \ } #define print_void NULL #define print_false NULL template struct rpc_type2str { static const char *type () { return typeid (T).name (); } }; template<> struct rpc_type2str { static const char *type () { return "opaque"; } }; #define RPC_TYPE2STR_DECL(T) \ template<> struct rpc_type2str { \ static const char *type () { return #T; } \ }; #define RPC_PRINT_GEN(T, expr) \ const strbuf & \ rpc_print (const strbuf &sb, const T &obj, int recdepth, \ const char *name, const char *prefix) \ { \ if (name) { \ if (prefix) \ sb << prefix; \ sb << rpc_namedecl::decl (name) << " = "; \ } \ expr; \ if (prefix) \ sb << ";\n"; \ return sb; \ } RPC_TYPE2STR_DECL (bool) RPC_TYPE2STR_DECL (int32_t) RPC_TYPE2STR_DECL (u_int32_t) RPC_TYPE2STR_DECL (int64_t) RPC_TYPE2STR_DECL (u_int64_t) RPC_PRINT_TYPE_DECL (bool) RPC_PRINT_TYPE_DECL (int32_t) RPC_PRINT_TYPE_DECL (u_int32_t) RPC_PRINT_TYPE_DECL (int64_t) RPC_PRINT_TYPE_DECL (u_int64_t) RPC_PRINT_DECL (char); RPC_PRINT_DECL (int32_t); RPC_PRINT_DECL (u_int32_t); RPC_PRINT_DECL (int64_t); RPC_PRINT_DECL (u_int64_t); RPC_PRINT_DECL (bool); #ifdef MAINTAINER static inline str rpc_dynsize (size_t n) { if (n == (size_t) RPC_INFINITY) return "<>"; return strbuf () << "<" << n << ">"; } static inline str rpc_parenptr (const str &name) { if (name[0] == '*') return strbuf () << "(" << name << ")"; return name; } template struct rpc_namedecl { static str decl (const char *name) { return strbuf () << rpc_type2str::type () << " " << name; } }; template struct rpc_namedecl > { static str decl (const char *name) { return strbuf () << "string " << rpc_parenptr (name) << rpc_dynsize (n); } }; template struct rpc_namedecl > { static str decl (const char *name) { return rpc_namedecl::decl (str (strbuf () << "*" << name)); } }; template struct rpc_namedecl > { static str decl (const char *name) { return strbuf () << rpc_namedecl::decl (rpc_parenptr (name)) << rpc_dynsize (n); } }; template struct rpc_namedecl > { static str decl (const char *name) { return rpc_namedecl::decl (rpc_parenptr (name)) << "[" << n << "]"; } }; template struct rpc_namedecl > { static str decl (const char *name) { return rpc_namedecl >::decl (name); } }; template struct rpc_namedecl > { static str decl (const char *name) { return rpc_namedecl >::decl (name); } }; template const strbuf & rpc_print (const strbuf &sb, const rpc_str &obj, int recdepth = RPC_INFINITY, const char *name = NULL, const char *prefix = NULL) { if (prefix) sb << prefix; if (name) sb << rpc_namedecl >::decl (name) << " = "; if (obj) sb << "\"" << obj << "\""; // XXX should map " to \" in string else sb << "NULL"; if (prefix) sb << ";\n"; return sb; } template const strbuf & rpc_print (const strbuf &sb, const rpc_ptr &obj, int recdepth = RPC_INFINITY, const char *name = NULL, const char *prefix = NULL) { if (name) { if (prefix) sb << prefix; sb << rpc_namedecl >::decl (name) << " = "; } if (!obj) sb << "NULL;\n"; else if (!recdepth) sb << "...\n"; else { sb << "&"; rpc_print (sb, *obj, recdepth - 1, NULL, prefix); } return sb; } struct made_by_user_conversion { template made_by_user_conversion (const T &s) {} }; inline bool rpc_isstruct (const made_by_user_conversion &) { return true; } inline bool rpc_isstruct (u_int64_t) { return false; } template const strbuf & rpc_print_array_vec (const strbuf &sb, const T &obj, int recdepth = RPC_INFINITY, const char *name = NULL, const char *prefix = NULL) { if (name) { if (prefix) sb << prefix; sb << rpc_namedecl::decl (name) << " = "; } if (obj.size ()) { const char *sep; str npref; if (prefix) { npref = strbuf ("%s ", prefix); sep = ""; sb << "[" << obj.size () << "] {\n"; } else { sep = ", "; sb << "[" << obj.size () << "] { "; } if (rpc_isstruct (obj[0])) { size_t i; size_t n = min (obj.size (), recdepth); for (i = 0; i < n; i++) { if (i) sb << sep; if (npref) sb << npref; sb << "[" << i << "] = "; rpc_print (sb, obj[i], recdepth, NULL, npref); } if (i < obj.size ()) sb << (i ? sep : "") << npref << "..." << (npref ? "\n" : " "); } else { size_t i; size_t n = recdepth == RPC_INFINITY ? obj.size () : min ((size_t) recdepth * 8, obj.size ());; if (npref) sb << npref; for (i = 0; i < n; i++) { if (i & 7) sb << ", "; else if (i) { sb << ",\n"; if (npref) sb << npref; } rpc_print (sb, obj[i], recdepth, NULL, NULL); } if (i < obj.size ()) { if (i) { sb << ",\n"; if (npref) sb << npref; } sb << "..."; } sb << (npref ? "\n" : " "); } if (prefix) sb << prefix << "};\n"; else sb << " }"; } else if (prefix) sb << "[0] {};\n"; else sb << "[0] {}"; return sb; } #define RPC_ARRAYVEC_DECL(TEMP) \ template const strbuf & \ rpc_print (const strbuf &sb, const TEMP &obj, \ int recdepth = RPC_INFINITY, \ const char *name = NULL, const char *prefix = NULL) \ { \ return rpc_print_array_vec (sb, obj, recdepth, name, prefix); \ } RPC_ARRAYVEC_DECL (array) RPC_ARRAYVEC_DECL (rpc_vec) #undef RPC_ARRAYVEC_DECL #define RPC_ARRAYVEC_DECL(TEMP) \ template const strbuf & \ rpc_print (const strbuf &sb, const TEMP &obj, \ int recdepth = RPC_INFINITY, \ const char *name = NULL, const char *prefix = NULL) \ { \ return rpc_print_array_vec (sb, obj, recdepth, name, prefix); \ } RPC_ARRAYVEC_DECL (rpc_opaque) RPC_ARRAYVEC_DECL (rpc_bytes) #undef RPC_ARRAYVEC_DECL template RPC_PRINT_DECL (T); template RPC_PRINT_GEN (T, sb << "???"); #endif /* MAINTAINER */ #endif /* !_RPCTYPES_H_ */