[hackers] [libixp] Doc updates and minor API changes. || Kris Maglione

From: <hg_AT_suckless.org>
Date: Wed, 16 Jun 2010 19:48:59 +0000 (UTC)

changeset: 127:dbda92c4b3b4
tag: tip
user: Kris Maglione <kris_AT_suckless.org>
date: Wed Jun 16 15:48:34 2010 -0400
files: NEWS include/ixp.h include/ixp_local.h include/ixp_srvutil.h lib/libixp/client.c lib/libixp/convert.c lib/libixp/error.c lib/libixp/map.c lib/libixp/message.c lib/libixp/request.c lib/libixp/server.c lib/libixp/srv_util.c lib/libixp/timer.c lib/libixp/transport.c lib/libixp/util.c man/Ixp9Srv.3 man/IxpFcall.3 man/IxpFid.3 man/IxpMsg.3 man/IxpThread.3 man/ixp_close.3 man/ixp_dial.3 man/ixp_emalloc.3 man/ixp_eprint.3 man/ixp_errbuf.3 man/ixp_fcall2msg.3 man/ixp_freestat.3 man/ixp_hangup.3 man/ixp_listen.3 man/ixp_mount.3 man/ixp_msec.3 man/ixp_namespace.3 man/ixp_nexttimer.3 man/ixp_open.3 man/ixp_pdata.3 man/ixp_pending_write.3 man/ixp_pfcall.3 man/ixp_print.3 man/ixp_printfcall.3 man/ixp_pstring.3 man/ixp_pstrings.3 man/ixp_pu8.3 man/ixp_read.3 man/ixp_remove.3 man/ixp_respond.3 man/ixp_sendmsg.3 man/ixp_serverloop.3 man/ixp_settimer.3 man/ixp_smprint.3 man/ixp_srv_clonefiles.3 man/ixp_srv_data2cstring.3 man/ixp_srv_freefile.3 man/ixp_srv_getfile.3 man/ixp_srv_readbuf.3 man/ixp_srv_walkandclone.
3 man/ixp_srv_writectl.3 man/ixp_stat.3 man/ixp_unmount.3 man/ixp_unsettimer.3 man/ixp_vprint.3 man/ixp_write.3 man/targets.mk util/grepdoc util/link
description:
Doc updates and minor API changes.

diff -r ffbf3797fde8 -r dbda92c4b3b4 NEWS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/NEWS Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,7 @@
+
+0.6:
+ Add API documentation and manual pages.
+ Now fully MIT licensed.
+ Fix build problems on case insensitive filesystems.
+ Change ixp_srv_clonefiles specification.
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 include/ixp.h
--- a/include/ixp.h Tue Jun 15 14:26:31 2010 -0400
+++ b/include/ixp.h Wed Jun 16 15:48:34 2010 -0400
@@ -4,10 +4,11 @@
  */
 
 #include <stdarg.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <sys/select.h>
 
-#define IXP_API 116
+#define IXP_API 127
 
 /* Gunk */
 #if defined(IXP_NEEDAPI) && IXP_API < IXP_NEEDAPI
@@ -17,18 +18,29 @@
 # warning This version of libixp has a newer API than this compilation requires.
 #endif
 
+#if defined(IXP_NEEDAPI) && IXP_NEEDAPI < 127
+# undef ushort
+# undef ulong
+# undef vlong
+# undef uvlong
+# define ushort _ixpushort
+# define ulong _ixpulong
+# define vlong _ixpvlong
+# define uvlong _ixpuvlong
+
+typedef uint16_t ushort;
+typedef uint32_t ulong;
+typedef uint64_t uvlong;
+
+typedef int64_t vlong;
+#endif
+
 #undef uchar
-#undef ushort
 #undef uint
-#undef ulong
-#undef vlong
-#undef uvlong
-#define uchar _ixpuchar
-#define ushort _ixpushort
-#define uint _ixpuint
-#define ulong _ixpulong
-#define vlong _ixpvlong
-#define uvlong _ixpuvlong
+#define uchar _ixpuchar
+#define uint _ixpuint
+typedef unsigned char uchar;
+typedef unsigned int uint;
 
 #ifdef KENC
 # define STRUCT(x) struct {x};
@@ -36,23 +48,11 @@
 #elif defined(__GNUC__)
 # define STRUCT(x) __extension__ struct {x};
 # define UNION(x) __extension__ union {x};
-#else
-# define IXP_NEEDAPI 89
-# define STRUCT(x) x
-# define UNION(x) x
 #endif
 /* End Gunk */
 
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned long long uvlong;
-
-typedef long long vlong;
-
 #define IXP_VERSION "9P2000"
-#define IXP_NOTAG ((ushort)~0) /* Dummy tag */
+#define IXP_NOTAG ((uint16_t)~0) /* Dummy tag */
 #define IXP_NOFID (~0U)
 
 enum {
@@ -244,44 +244,47 @@
 };
 
 struct IxpMutex {
- void* aux;
+ void* aux;
+};
+
+struct IxpRendez {
+ IxpMutex* mutex;
+ void* aux;
 };
 
 struct IxpRWLock {
- void* aux;
-};
-
-struct IxpRendez {
- IxpMutex* mutex;
         void* aux;
 };
 
-enum { MsgPack, MsgUnpack, };
+enum IxpMsgMode {
+ MsgPack,
+ MsgUnpack,
+};
 struct IxpMsg {
- char* data;
- char* pos;
- char* end;
- uint size;
- uint mode;
+ char* data; /* Begining of buffer. */
+ char* pos; /* Current position in buffer. */
+ char* end; /* End of message. */
+ uint size; /* Size of buffer. */
+ uint mode; /* MsgPack or MsgUnpack. */
 };
 
 struct IxpQid {
- uchar type;
- ulong version;
- uvlong path;
+ uint8_t type;
+ uint32_t version;
+ uint64_t path;
         /* Private members */
- uchar dir_type;
+ uint8_t dir_type;
 };
 
 /* stat structure */
 struct IxpStat {
- ushort type;
- ulong dev;
- IxpQid qid;
- ulong mode;
- ulong atime;
- ulong mtime;
- uvlong length;
+ uint16_t type;
+ uint32_t dev;
+ IxpQid qid;
+ uint32_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
         char* name;
         char* uid;
         char* gid;
@@ -313,122 +316,122 @@
 typedef struct IxpFVersion IxpFVersion;
 
 struct IxpFHdr {
- uchar type;
- ushort tag;
- ulong fid;
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
 };
 struct IxpFVersion {
- IxpFHdr hdr;
- ulong msize;
- char* version;
+ IxpFHdr hdr;
+ uint32_t msize;
+ char* version;
 };
 struct IxpFTFlush {
- IxpFHdr hdr;
- ushort oldtag;
+ IxpFHdr hdr;
+ uint16_t oldtag;
 };
 struct IxpFError {
- IxpFHdr hdr;
- char* ename;
+ IxpFHdr hdr;
+ char* ename;
 };
 struct IxpFROpen {
- IxpFHdr hdr;
- IxpQid qid; /* +Rattach */
- ulong iounit;
+ IxpFHdr hdr;
+ IxpQid qid; /* +Rattach */
+ uint32_t iounit;
 };
 struct IxpFRAuth {
- IxpFHdr hdr;
- IxpQid aqid;
+ IxpFHdr hdr;
+ IxpQid aqid;
 };
 struct IxpFAttach {
- IxpFHdr hdr;
- ulong afid;
- char* uname;
- char* aname;
+ IxpFHdr hdr;
+ uint32_t afid;
+ char* uname;
+ char* aname;
 };
 struct IxpFTCreate {
- IxpFHdr hdr;
- ulong perm;
- char* name;
- uchar mode; /* +Topen */
+ IxpFHdr hdr;
+ uint32_t perm;
+ char* name;
+ uint8_t mode; /* +Topen */
 };
 struct IxpFTWalk {
         IxpFHdr hdr;
- ulong newfid;
- ushort nwname;
- char* wname[IXP_MAX_WELEM];
+ uint32_t newfid;
+ uint16_t nwname;
+ char* wname[IXP_MAX_WELEM];
 };
 struct IxpFRWalk {
- IxpFHdr hdr;
- ushort nwqid;
- IxpQid wqid[IXP_MAX_WELEM];
+ IxpFHdr hdr;
+ uint16_t nwqid;
+ IxpQid wqid[IXP_MAX_WELEM];
 };
 struct IxpFIO {
- IxpFHdr hdr;
- uvlong offset; /* Tread, Twrite */
- ulong count; /* Tread, Twrite, Rread */
- char* data; /* Twrite, Rread */
+ IxpFHdr hdr;
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
+ char* data; /* Twrite, Rread */
 };
 struct IxpFRStat {
- IxpFHdr hdr;
- ushort nstat;
- uchar* stat;
+ IxpFHdr hdr;
+ uint16_t nstat;
+ uchar* stat;
 };
 struct IxpFTWStat {
- IxpFHdr hdr;
- IxpStat stat;
+ IxpFHdr hdr;
+ IxpStat stat;
 };
 #if defined(IXP_NEEDAPI) && IXP_NEEDAPI <= 89
 /* from fcall(3) in plan9port */
 typedef struct IxpFcall IxpFcall; /* Deprecated */
 struct IxpFcall { /* Deprecated */
- uchar type;
- ushort tag;
- ulong fid;
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
 
         UNION (
                 STRUCT ( /* Tversion, Rversion */
- ulong msize;
+ uint32_t msize;
                         char *version;
                 )
                 STRUCT ( /* Tflush */
- ushort oldtag;
+ uint16_t oldtag;
                 )
                 STRUCT ( /* Rerror */
                         char *ename;
                 )
                 STRUCT ( /* Ropen, Rcreate */
                         IxpQid qid; /* +Rattach */
- ulong iounit;
+ uint32_t iounit;
                 )
                 STRUCT ( /* Rauth */
                         IxpQid aqid;
                 )
                 STRUCT ( /* Tauth, Tattach */
- ulong afid;
+ uint32_t afid;
                         char *uname;
                         char *aname;
                 )
                 STRUCT ( /* Tcreate */
- ulong perm;
+ uint32_t perm;
                         char *name;
- uchar mode; /* +Topen */
+ uint8_t mode; /* +Topen */
                 )
                 STRUCT ( /* Twalk */
- ulong newfid;
- ushort nwname;
+ uint32_t newfid;
+ uint16_t nwname;
                         char *wname[IXP_MAX_WELEM];
                 )
                 STRUCT ( /* Rwalk */
- ushort nwqid;
+ uint16_t nwqid;
                         IxpQid wqid[IXP_MAX_WELEM];
                 )
                 STRUCT (
- uvlong offset; /* Tread, Twrite */
- ulong count; /* Tread, Twrite, Rread */
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
                         char *data; /* Twrite, Rread */
                 )
                 STRUCT ( /* Rstat */
- ushort nstat;
+ uint16_t nstat;
                         uchar *stat;
                 )
                 STRUCT ( /* Twstat */
@@ -437,7 +440,41 @@
         )
 };
 #else
-typedef union IxpFcall IxpFcall;
+/**
+ * Type: IxpFcall
+ * Type: IxpFType
+ * Type: IxpFAttach
+ * Type: IxpFError
+ * Type: IxpFHdr
+ * Type: IxpFIO
+ * Type: IxpFRAuth
+ * Type: IxpFROpen
+ * Type: IxpFRStat
+ * Type: IxpFRWalk
+ * Type: IxpFTCreate
+ * Type: IxpFTFlush
+ * Type: IxpFTWStat
+ * Type: IxpFTWalk
+ * Type: IxpFVersion
+ *
+ * The IxpFcall structure represents a 9P protocol message. The
+ * P<hdr> element is common to all Fcall types, and may be used to
+ * determine the type and tag of the message. The IxpFcall type is
+ * used heavily in server applications, where it both presents a
+ * request to handler functions and returns a response to the
+ * client.
+ *
+ * Each member of the IxpFcall structure represents a certain
+ * message type, which can be discerned from the P<hdr.type> field.
+ * This value corresponds to one of the IxpFType constants. Types
+ * with significant overlap use the same structures, thus TRead and
+ * RWrite are both represented by IxpFIO and can be accessed via the
+ * P<io> member as well as P<tread> and P<rwrite> respectively.
+ *
+ * See also:
+ * T<Ixp9Srv>, T<Ixp9Req>
+ */
+typedef union IxpFcall IxpFcall;
 union IxpFcall {
         IxpFHdr hdr;
         IxpFVersion version;
@@ -467,11 +504,11 @@
 
 struct IxpConn {
         IxpServer* srv;
- void* aux;
- int fd;
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ int fd; /* The file descriptor of the connection. */
         void (*read)(IxpConn *);
         void (*close)(IxpConn *);
- char closed;
+ char closed; /* Non-zero when P<fd> has been closed. */
 
         /* Private members */
         IxpConn *next;
@@ -523,12 +560,12 @@
 };
 
 struct IxpCFid {
- uint fid;
+ uint32_t fid;
         IxpQid qid;
- uchar mode;
+ uint8_t mode;
         uint open;
         uint iounit;
- uvlong offset;
+ uint32_t offset;
         IxpClient* client;
 
         /* Private members */
@@ -536,13 +573,26 @@
         IxpMutex iolock;
 };
 
+/**
+ * Type: IxpFid
+ *
+ * Represents an open file for a 9P connection. The same
+ * structure persists as long as the file remains open, and is
+ * installed in the T<Ixp9Req> structure for any request Fcall
+ * which references it. Handlers may use the P<aux> member to
+ * store any data which must persist for the life of the open
+ * file.
+ *
+ * See also:
+ * T<Ixp9Req>, T<IxpQid>, T<IxpOMode>
+ */
 struct IxpFid {
- char* uid;
- void* aux;
- ulong fid;
- IxpQid qid;
- signed char omode;
- uint iounit;
+ char* uid; /* The uid of the file opener. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ uint32_t fid; /* The ID number of the fid. */
+ IxpQid qid; /* The filesystem-unique QID of the file. */
+ signed char omode; /* The open mode of the file. */
+ uint iounit; /* The maximum size of any IO request. */
 
         /* Private members */
         Ixp9Conn* conn;
@@ -551,12 +601,12 @@
 
 struct Ixp9Req {
         Ixp9Srv* srv;
- IxpFid* fid;
- IxpFid* newfid;
- Ixp9Req* oldreq;
- IxpFcall ifcall;
- IxpFcall ofcall;
- void* aux;
+ IxpFid* fid; /* Fid structure corresponding to IxpFHdr.fid */
+ IxpFid* newfid; /* Corresponds to IxpFTWStat.newfid */
+ Ixp9Req* oldreq; /* For TFlush requests, the original request. */
+ IxpFcall ifcall; /* The incoming request fcall. */
+ IxpFcall ofcall; /* The response fcall, to be filled by handler. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
 
         /* Private members */
         Ixp9Conn *conn;
@@ -564,22 +614,44 @@
 
 struct Ixp9Srv {
         void* aux;
- void (*attach)(Ixp9Req *r);
- void (*clunk)(Ixp9Req *r);
- void (*create)(Ixp9Req *r);
- void (*flush)(Ixp9Req *r);
- void (*open)(Ixp9Req *r);
- void (*read)(Ixp9Req *r);
- void (*remove)(Ixp9Req *r);
- void (*stat)(Ixp9Req *r);
- void (*walk)(Ixp9Req *r);
- void (*write)(Ixp9Req *r);
- void (*wstat)(Ixp9Req *r);
- void (*freefid)(IxpFid *f);
+ void (*attach)(Ixp9Req*);
+ void (*clunk)(Ixp9Req*);
+ void (*create)(Ixp9Req*);
+ void (*flush)(Ixp9Req*);
+ void (*open)(Ixp9Req*);
+ void (*read)(Ixp9Req*);
+ void (*remove)(Ixp9Req*);
+ void (*stat)(Ixp9Req*);
+ void (*walk)(Ixp9Req*);
+ void (*write)(Ixp9Req*);
+ void (*wstat)(Ixp9Req*);
+ void (*freefid)(IxpFid*);
 };
 
+/**
+ * Type: IxpThread
+ * Type: IxpMutex
+ * Type: IxpRWLock
+ * Type: IxpRendez
+ * Variable: ixp_thread
+ *
+ * The IxpThread structure is used to adapt libixp to any of the
+ * myriad threading systems it may be used with. Before any
+ * other of libixp's functions is called, ixp_thread may be set
+ * to a structure filled with implementations of various locking
+ * primitives, along with primitive IO functions which may
+ * perform context switches until data is available.
+ *
+ * The names of the functions should be fairly self-explanitory.
+ * Read/write locks should allow multiple readers and a single
+ * writer of a shared resource, but should not allow new readers
+ * while a writer is waitng for a lock. Mutexes should allow
+ * only one accessor at a time. Rendezvous points are similar to
+ * pthread condition types. P<errbuf> should return a
+ * thread-local buffer or the size IXP_ERRMAX.
+ */
 struct IxpThread {
- /* RWLock */
+ /* Read/write lock */
         int (*initrwlock)(IxpRWLock*);
         void (*rlock)(IxpRWLock*);
         int (*canrlock)(IxpRWLock*);
@@ -594,23 +666,23 @@
         int (*canlock)(IxpMutex*);
         void (*unlock)(IxpMutex*);
         void (*mdestroy)(IxpMutex*);
- /* Rendez */
+ /* Rendezvous point */
         int (*initrendez)(IxpRendez*);
         void (*sleep)(IxpRendez*);
         int (*wake)(IxpRendez*);
         int (*wakeall)(IxpRendez*);
         void (*rdestroy)(IxpRendez*);
         /* Other */
- char *(*errbuf)(void);
+ char* (*errbuf)(void);
         ssize_t (*read)(int, void*, size_t);
         ssize_t (*write)(int, const void*, size_t);
         int (*select)(int, fd_set*, fd_set*, fd_set*, struct timeval*);
 };
 
-extern IxpThread *ixp_thread;
-extern int (*ixp_vsnprint)(char*, int, const char*, va_list);
-extern char* (*ixp_vsmprint)(const char*, va_list);
-extern void (*ixp_printfcall)(IxpFcall*);
+extern IxpThread* ixp_thread;
+extern int (*ixp_vsnprint)(char *buf, int nbuf, const char *fmt, va_list);
+extern char* (*ixp_vsmprint)(const char *fmt, va_list);
+extern void (*ixp_printfcall)(IxpFcall*);
 
 /* thread_*.c */
 int ixp_taskinit(void);
@@ -624,15 +696,15 @@
 #endif
 
 /* client.c */
-int ixp_close(IxpCFid*);
-long ixp_pread(IxpCFid*, void*, long, vlong);
-int ixp_print(IxpCFid*, const char*, ...);
-long ixp_pwrite(IxpCFid*, const void*, long, vlong);
-long ixp_read(IxpCFid*, void*, long);
-int ixp_remove(IxpClient*, const char*);
-void ixp_unmount(IxpClient*);
-int ixp_vprint(IxpCFid*, const char*, va_list);
-long ixp_write(IxpCFid*, const void*, long);
+int ixp_close(IxpCFid*);
+long ixp_pread(IxpCFid*, void*, long, int64_t);
+int ixp_print(IxpCFid*, const char*, ...);
+long ixp_pwrite(IxpCFid*, const void*, long, int64_t);
+long ixp_read(IxpCFid*, void*, long);
+int ixp_remove(IxpClient*, const char*);
+void ixp_unmount(IxpClient*);
+int ixp_vprint(IxpCFid*, const char*, va_list);
+long ixp_write(IxpCFid*, const void*, long);
 IxpCFid* ixp_create(IxpClient*, const char*, uint perm, uchar mode);
 IxpStat* ixp_fstat(IxpCFid*);
 IxpClient* ixp_mount(const char*);
@@ -642,15 +714,15 @@
 IxpStat* ixp_stat(IxpClient*, const char*);
 
 /* convert.c */
-void ixp_pu8(IxpMsg*, uchar*);
-void ixp_pu16(IxpMsg*, ushort*);
-void ixp_pu32(IxpMsg*, ulong*);
-void ixp_pu64(IxpMsg*, uvlong*);
+void ixp_pu8(IxpMsg*, uint8_t*);
+void ixp_pu16(IxpMsg*, uint16_t*);
+void ixp_pu32(IxpMsg*, uint32_t*);
+void ixp_pu64(IxpMsg*, uint64_t*);
 void ixp_pdata(IxpMsg*, char**, uint);
 void ixp_pstring(IxpMsg*, char**);
-void ixp_pstrings(IxpMsg*, ushort*, char**);
+void ixp_pstrings(IxpMsg*, uint16_t*, char**, uint);
 void ixp_pqid(IxpMsg*, IxpQid*);
-void ixp_pqids(IxpMsg*, ushort*, IxpQid*);
+void ixp_pqids(IxpMsg*, uint16_t*, IxpQid*, uint);
 void ixp_pstat(IxpMsg*, IxpStat*);
 void ixp_pfcall(IxpMsg*, IxpFcall*);
 
@@ -661,11 +733,16 @@
 void ixp_werrstr(const char*, ...);
 
 /* request.c */
-void respond(Ixp9Req*, const char *err);
-void serve_9pcon(IxpConn*);
+void ixp_respond(Ixp9Req*, const char *err);
+void ixp_serve9conn(IxpConn*);
+
+#if defined(IXP_NEEDAPI) && IXP_NEEDAPI < 127
+# define respond ixp_respond
+# define serve_9pcon ixp_serve9pconn
+#endif
 
 /* message.c */
-ushort ixp_sizeof_stat(IxpStat*);
+uint16_t ixp_sizeof_stat(IxpStat*);
 IxpMsg ixp_message(char*, uint len, uint mode);
 void ixp_freestat(IxpStat*);
 void ixp_freefcall(IxpFcall*);
diff -r ffbf3797fde8 -r dbda92c4b3b4 include/ixp_local.h
--- a/include/ixp_local.h Tue Jun 15 14:26:31 2010 -0400
+++ b/include/ixp_local.h Wed Jun 16 15:48:34 2010 -0400
@@ -3,6 +3,16 @@
 #include <ixp.h>
 #include <stdbool.h>
 
+#undef ulong
+#define ulong _ixpulong
+typedef unsigned long ulong;
+
+#ifdef CPROTO
+# undef bool
+typedef int bool;
+typedef char* va_list;
+#endif
+
 char *argv0;
 #define ARGBEGIN \
                 int _argtmp=0, _inargv=0; char *_argv=nil; \
@@ -66,20 +76,20 @@
 };
 
 struct IxpTimer {
- Timer* link;
- long msec;
- long id;
- void (*fn)(long, void*);
- void* aux;
+ Timer* link;
+ uint32_t msec;
+ long id;
+ void (*fn)(long, void*);
+ void* aux;
 };
 
 /* map.c */
-void ixp_mapfree(Map*, void(*)(void*));
-void ixp_mapexec(Map*, void(*)(void*, void*), void*);
-void ixp_mapinit(Map*, MapEnt**, int);
-bool ixp_mapinsert(Map*, ulong, void*, bool);
-void* ixp_mapget(Map*, ulong);
-void* ixp_maprm(Map*, ulong);
+void ixp_mapfree(IxpMap*, void(*)(void*));
+void ixp_mapexec(IxpMap*, void(*)(void*, void*), void*);
+void ixp_mapinit(IxpMap*, MapEnt**, int);
+bool ixp_mapinsert(IxpMap*, ulong, void*, bool);
+void* ixp_mapget(IxpMap*, ulong);
+void* ixp_maprm(IxpMap*, ulong);
 
 /* mux.c */
 void muxfree(IxpClient*);
diff -r ffbf3797fde8 -r dbda92c4b3b4 include/ixp_srvutil.h
--- a/include/ixp_srvutil.h Tue Jun 15 14:26:31 2010 -0400
+++ b/include/ixp_srvutil.h Wed Jun 16 15:48:34 2010 -0400
@@ -9,6 +9,7 @@
 typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*);
 
 struct IxpPendingLink {
+ /* Private members */
         IxpPendingLink* next;
         IxpPendingLink* prev;
         IxpFid* fid;
@@ -17,12 +18,14 @@
 };
 
 struct IxpRequestLink {
+ /* Private members */
         IxpRequestLink* next;
         IxpRequestLink* prev;
         Ixp9Req* req;
 };
 
 struct IxpPending {
+ /* Private members */
         IxpRequestLink req;
         IxpPendingLink fids;
 };
@@ -42,7 +45,7 @@
         uint id;
         uint index;
         IxpDirtab tab;
- ushort nref;
+ uint nref;
         uchar volatil;
 };
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/client.c
--- a/lib/libixp/client.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/client.c Wed Jun 16 15:48:34 2010 -0400
@@ -504,7 +504,7 @@
 }
 
 static long
-_pread(IxpCFid *f, char *buf, long count, vlong offset) {
+_pread(IxpCFid *f, char *buf, long count, int64_t offset) {
         Fcall fcall;
         int n, len;
 
@@ -567,7 +567,7 @@
 }
 
 long
-ixp_pread(IxpCFid *fid, void *buf, long count, vlong offset) {
+ixp_pread(IxpCFid *fid, void *buf, long count, int64_t offset) {
         int n;
 
         thread->lock(&fid->iolock);
@@ -577,7 +577,7 @@
 }
 
 static long
-_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
+_pwrite(IxpCFid *f, const void *buf, long count, int64_t offset) {
         Fcall fcall;
         int n, len;
 
@@ -638,7 +638,7 @@
 }
 
 long
-ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset) {
+ixp_pwrite(IxpCFid *fid, const void *buf, long count, int64_t offset) {
         int n;
 
         thread->lock(&fid->iolock);
@@ -648,8 +648,8 @@
 }
 
 /**
+ * Function: ixp_print
  * Function: ixp_vprint
- * Function: ixp_print
  * Variable: ixp_vsmprint
  *
  * Params:
@@ -666,10 +666,7 @@
  * V<ixp_vsmprint> may be set to a function which will
  * format its arguments and return a nul-terminated string
  * allocated by malloc(3). The default formats its arguments as
- * printf(3). The function must format '%s' as a nul-terminated
- * string and may not consume any arguments not specified by a
- * %-prefixed format specifier, but may otherwise behave in any
- * manner chosen by the user.
+ * printf(3).
  *
  * Returns:
  * These functions return the number of bytes written.
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/convert.c
--- a/lib/libixp/convert.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/convert.c Wed Jun 16 15:48:34 2010 -0400
@@ -14,7 +14,7 @@
 };
 
 static void
-ixp_puint(IxpMsg *msg, uint size, ulong *val) {
+ixp_puint(IxpMsg *msg, uint size, uint32_t *val) {
         uchar *pos;
         int v;
 
@@ -51,40 +51,80 @@
         msg->pos += size;
 }
 
+/**
+ * Function: ixp_pu8
+ * Function: ixp_pu16
+ * Function: ixp_pu32
+ * Function: ixp_pu64
+ *
+ * These functions pack or unpack an unsigned integer of the
+ * specified size.
+ *
+ * If P<msg>->mode is MsgPack, the value pointed to by P<val> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the packed value at P<msg>->pos is loaded into the
+ * location pointed to by P<val>. In both cases, P<msg>->pos is
+ * advanced by the number of bytes read or written. If the call
+ * would advance P<msg>->pos beyond P<msg>->end, P<msg>->pos is
+ * advanced, but nothing is modified.
+ *
+ * See also:
+ * T<IxpMsg>
+ */
 void
-ixp_pu32(IxpMsg *msg, ulong *val) {
+ixp_pu32(IxpMsg *msg, uint32_t *val) {
         ixp_puint(msg, SDWord, val);
 }
 void
 ixp_pu8(IxpMsg *msg, uchar *val) {
- ulong v;
+ uint32_t v;
 
         v = *val;
         ixp_puint(msg, SByte, &v);
         *val = (uchar)v;
 }
 void
-ixp_pu16(IxpMsg *msg, ushort *val) {
- ulong v;
+ixp_pu16(IxpMsg *msg, uint16_t *val) {
+ uint32_t v;
 
         v = *val;
         ixp_puint(msg, SWord, &v);
- *val = (ushort)v;
+ *val = (uint16_t)v;
 }
 void
-ixp_pu64(IxpMsg *msg, uvlong *val) {
- ulong vl, vb;
+ixp_pu64(IxpMsg *msg, uint64_t *val) {
+ uint32_t vl, vb;
 
         vl = (uint)*val;
         vb = (uint)(*val>>32);
         ixp_puint(msg, SDWord, &vl);
         ixp_puint(msg, SDWord, &vb);
- *val = vl | ((uvlong)vb<<32);
+ *val = vl | ((uint64_t)vb<<32);
 }
 
+/**
+ * Function: ixp_pstring
+ *
+ * Packs or unpacks a UTF-8 encoded string. The packed
+ * representation of the string consists of a 16-bit unsigned
+ * integer followed by the contents of the string. The unpacked
+ * representation is a nul-terminated character array.
+ *
+ * If P<msg>->mode is MsgPack, the string pointed to by P<s> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the address pointed to by P<s> is loaded with a
+ * malloc(3) allocated, nul-terminated representation of the
+ * string packed at P<msg>->pos. In either case, P<msg>->pos is
+ * advanced by the number of bytes read or written. If the
+ * action would advance P<msg>->pos beyond P<msg>->end,
+ * P<msg>->pos is still advanced but no other action is taken.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pstrings>, F<ixp_pdata>
+ */
 void
 ixp_pstring(IxpMsg *msg, char **s) {
- ushort len;
+ uint16_t len;
 
         if(msg->mode == MsgPack)
                 len = strlen(*s);
@@ -101,14 +141,38 @@
         msg->pos += len;
 }
 
+/**
+ * Function: ixp_pstrings
+ *
+ * Packs or unpacks an array of UTF-8 encoded strings. The packed
+ * representation consists of a 16-bit element count followed by
+ * an array of strings as packed by F<ixp_pstring>. The unpacked
+ * representation is an array of nul-terminated character arrays.
+ *
+ * If P<msg>->mode is MsgPack, P<*num> strings in the array
+ * pointed to by P<strings> are packed into the buffer at
+ * P<msg>->pos. If P<msg>->mode is MsgUnpack, P<*num> is loaded
+ * with the number of strings unpacked, the array at
+ * P<*strings> is loaded with pointers to the unpacked strings,
+ * and P<(*strings)[0]> must be freed by the user. In either
+ * case, P<msg>->pos is advanced by the number of bytes read or
+ * written. If the action would advance P<msg>->pos beyond
+ * P<msg>->end, P<msg>->pos is still advanced, but no other
+ * action is taken. If P<*num> is greater than P<max>,
+ * P<msg>->pos is set beyond P<msg>->end and no other action is
+ * taken.
+ *
+ * See also:
+ * P<IxpMsg>, P<ixp_pstring>, P<ixp_pdata>
+ */
 void
-ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
+ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings[], uint max) {
         char *s;
         uint i, size;
- ushort len;
+ uint16_t len;
 
         ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
+ if(*num > max) {
                 msg->pos = msg->end+1;
                 return;
         }
@@ -145,6 +209,23 @@
         }
 }
 
+/**
+ * Function: ixp_pdata
+ *
+ * Packs or unpacks a raw character buffer of size P<len>.
+ *
+ * If P<msg>->mode is MsgPack, buffer pointed to by P<data> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the address pointed to by P<s> is loaded with a
+ * malloc(3) allocated buffer with the contents of the buffer at
+ * P<msg>->pos. In either case, P<msg>->pos is advanced by the
+ * number of bytes read or written. If the action would advance
+ * P<msg>->pos beyond P<msg>->end, P<msg>->pos is still advanced
+ * but no other action is taken.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pstring>
+ */
 void
 ixp_pdata(IxpMsg *msg, char **data, uint len) {
         if(msg->pos + len <= msg->end) {
@@ -157,19 +238,40 @@
         msg->pos += len;
 }
 
+/**
+ * Function: ixp_pfcall
+ * Function: ixp_pqid
+ * Function: ixp_pqids
+ * Function: ixp_pstat
+ * Function: ixp_sizeof_stat
+ *
+ * These convenience functions pack or unpack the contents of
+ * libixp structures into their wire format. They behave as if
+ * F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, F<ixp_pu64>, and
+ * F<ixp_pstring> were called for each member of the structure
+ * in question. ixp_pqid is to ixp_pqid as F<ixp_pstrings> is to
+ * ixp_pstring.
+ *
+ * ixp_sizeof_stat returns the size of the packed represention
+ * of P<stat>.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>,
+ * F<ixp_pu64>, F<ixp_pstring>, F<ixp_pstrings>
+ */
 void
-ixp_pqid(IxpMsg *msg, Qid *qid) {
+ixp_pqid(IxpMsg *msg, IxpQid *qid) {
         ixp_pu8(msg, &qid->type);
         ixp_pu32(msg, &qid->version);
         ixp_pu64(msg, &qid->path);
 }
 
 void
-ixp_pqids(IxpMsg *msg, ushort *num, Qid qid[]) {
+ixp_pqids(IxpMsg *msg, uint16_t *num, IxpQid qid[], uint max) {
         int i;
 
         ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
+ if(*num > max) {
                 msg->pos = msg->end+1;
                 return;
         }
@@ -179,8 +281,8 @@
 }
 
 void
-ixp_pstat(IxpMsg *msg, Stat *stat) {
- ushort size;
+ixp_pstat(IxpMsg *msg, IxpStat *stat) {
+ uint16_t size;
 
         if(msg->mode == MsgPack)
                 size = ixp_sizeof_stat(stat) - 2;
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/error.c
--- a/lib/libixp/error.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/error.c Wed Jun 16 15:48:34 2010 -0400
@@ -7,8 +7,8 @@
 #include "ixp_local.h"
 
 static int
-_vsnprint(char *buf, int n, const char *fmt, va_list ap) {
- return vsnprintf(buf, n, fmt, ap);
+_vsnprint(char *buf, int nbuf, const char *fmt, va_list ap) {
+ return vsnprintf(buf, nbuf, fmt, ap);
 }
 
 static char*
@@ -40,10 +40,11 @@
  * Function: ixp_errstr
  * Function: ixp_rerrstr
  * Function: ixp_werrstr
+ * Variable: ixp_vsnprint
  *
  * Params:
  * buf: The buffer to read and/or fill.
- * size: The size of the buffer.
+ * nbuf: The size of the buffer.
  * fmt: A format string with which to write the errstr.
  * ...: Arguments to P<fmt>.
  *
@@ -56,12 +57,16 @@
  * the current thread's error buffer, while F<ixp_errstr>
  * exchanges P<buf>'s contents with those of the current
  * thread's error buffer. F<ixp_werrstr> formats the given
- * format string, P<fmt>, via V<ixp_vsmprint> and writes it to
+ * format string, P<fmt>, via V<ixp_vsnprint> and writes it to
  * the error buffer.
  *
- * Returns:
- * F<ixp_errbuf> returns the current thread's error
- * string buffer.
+ * V<ixp_vsnprint> may be set to a function which will format
+ * its arguments write the result to the P<nbuf> length buffer
+ * V<buf>. The default value is F<vsnprintf>. The function must
+ * format '%s' as a nul-terminated string and may not consume
+ * any arguments not indicated by a %-prefixed format specifier,
+ * but may otherwise behave in any manner chosen by the user.
+ *
  * See also:
  * V<ixp_vsmprint>
  */
@@ -78,18 +83,18 @@
 }
 
 void
-errstr(char *buf, int size) {
+errstr(char *buf, int nbuf) {
         char tmp[IXP_ERRMAX];
 
         strncpy(tmp, buf, sizeof tmp);
- rerrstr(buf, size);
+ rerrstr(buf, nbuf);
         strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
         errno = EPLAN9;
 }
 
 void
-rerrstr(char *buf, int size) {
- strncpy(buf, ixp_errbuf(), size);
+rerrstr(char *buf, int nbuf) {
+ strncpy(buf, ixp_errbuf(), nbuf);
 }
 
 void
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/map.c
--- a/lib/libixp/map.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/map.c Wed Jun 16 15:48:34 2010 -0400
@@ -26,7 +26,7 @@
 }
 
 static MapEnt**
-map_getp(Map *map, ulong val, bool create, bool *exists) {
+map_getp(IxpMap *map, ulong val, bool create, bool *exists) {
         MapEnt **e;
 
         e = &map->bucket[val%map->nhash];
@@ -45,7 +45,7 @@
 }
 
 void
-ixp_mapfree(Map *map, void (*destroy)(void*)) {
+ixp_mapfree(IxpMap *map, void (*destroy)(void*)) {
         int i;
         MapEnt *e;
 
@@ -62,7 +62,7 @@
 }
 
 void
-ixp_mapexec(Map *map, void (*run)(void*, void*), void *context) {
+ixp_mapexec(IxpMap *map, void (*run)(void*, void*), void *context) {
         int i;
         MapEnt *e;
 
@@ -74,7 +74,7 @@
 }
 
 void
-ixp_mapinit(Map *map, MapEnt **buckets, int nbuckets) {
+ixp_mapinit(IxpMap *map, MapEnt **buckets, int nbuckets) {
 
         map->bucket = buckets;
         map->nhash = nbuckets;
@@ -83,7 +83,7 @@
 }
 
 bool
-ixp_mapinsert(Map *map, ulong key, void *val, bool overwrite) {
+ixp_mapinsert(IxpMap *map, ulong key, void *val, bool overwrite) {
         MapEnt *e;
         bool existed, res;
         
@@ -99,7 +99,7 @@
 }
 
 void*
-ixp_mapget(Map *map, ulong val) {
+ixp_mapget(IxpMap *map, ulong val) {
         MapEnt *e;
         void *res;
         
@@ -111,7 +111,7 @@
 }
 
 void*
-ixp_maprm(Map *map, ulong val) {
+ixp_maprm(IxpMap *map, ulong val) {
         MapEnt **e, *te;
         void *ret;
         
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/message.c
--- a/lib/libixp/message.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/message.c Wed Jun 16 15:48:34 2010 -0400
@@ -18,6 +18,31 @@
         SQid = SByte + SDWord + SQWord,
 };
 
+/**
+ * Type: IxpMsg
+ * Type: IxpMsgMode
+ * Function: ixp_message
+ *
+ * The IxpMsg struct represents a binary message, and is used
+ * extensively by libixp for converting messages to and from
+ * wire format. The location and size of a buffer are stored in
+ * P<data> and P<size>, respectively. P<pos> points to the
+ * location in the message currently being packed or unpacked,
+ * while P<end> points to the end of the message. The packing
+ * functions advance P<pos> as they go, always ensuring that
+ * they don't read or write past P<end>. When a message is
+ * entirely packed or unpacked, P<pos> whould be less than or
+ * equal to P<end>. Any other state indicates error.
+ *
+ * ixp_message is a convenience function to pack a construct an
+ * IxpMsg from a buffer of a given P<length> and a given
+ * P<mode>. P<pos> and P<data> are set to P<data> and P<end> is
+ * set to P<data> + P<length>.
+ *
+ * See also:
+ * F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, F<ixp_pu64>,
+ * F<ixp_pstring>, F<ixp_pstrings>
+ */
 IxpMsg
 ixp_message(char *data, uint length, uint mode) {
         IxpMsg m;
@@ -30,8 +55,16 @@
         return m;
 }
 
+/**
+ * Function: ixp_freestat
+ * Function: ixp_freefcall
+ *
+ * These functions free malloc(3) allocated data in the members
+ * of the passed structures and set those members to nil. They
+ * do not free the structures themselves.
+ */
 void
-ixp_freestat(Stat *s) {
+ixp_freestat(IxpStat *s) {
         free(s->name);
         free(s->uid);
         free(s->gid);
@@ -40,7 +73,7 @@
 }
 
 void
-ixp_freefcall(Fcall *fcall) {
+ixp_freefcall(IxpFcall *fcall) {
         switch(fcall->hdr.type) {
         case RStat:
                 free(fcall->rstat.stat);
@@ -61,8 +94,8 @@
         }
 }
 
-ushort
-ixp_sizeof_stat(Stat * stat) {
+uint16_t
+ixp_sizeof_stat(IxpStat *stat) {
         return SWord /* size */
                 + SWord /* type */
                 + SDWord /* dev */
@@ -76,7 +109,7 @@
 }
 
 void
-ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
+ixp_pfcall(IxpMsg *msg, IxpFcall *fcall) {
         ixp_pu8(msg, &fcall->hdr.type);
         ixp_pu16(msg, &fcall->hdr.tag);
 
@@ -112,10 +145,10 @@
         case TWalk:
                 ixp_pu32(msg, &fcall->hdr.fid);
                 ixp_pu32(msg, &fcall->twalk.newfid);
- ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname);
+ ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname, nelem(fcall->twalk.wname));
                 break;
         case RWalk:
- ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
+ ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid, nelem(fcall->rwalk.wqid));
                 break;
         case TOpen:
                 ixp_pu32(msg, &fcall->hdr.fid);
@@ -160,7 +193,7 @@
                 ixp_pdata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat);
                 break;
         case TWStat: {
- ushort size;
+ uint16_t size;
                 ixp_pu32(msg, &fcall->hdr.fid);
                 ixp_pu16(msg, &size);
                 ixp_pstat(msg, &fcall->twstat.stat);
@@ -169,9 +202,23 @@
         }
 }
 
+/**
+ * Function: ixp_fcall2msg
+ * Function: ixp_msg2fcall
+ *
+ * These functions pack or unpack a 9P protocol message. The
+ * message is set to the appropriate mode and its position is
+ * set to the begining of its buffer.
+ *
+ * Returns:
+ * These functions return the size of the message on
+ * success and 0 on failure.
+ * See also:
+ * F<IxpMsg>, F<ixp_pfcall>
+ */
 uint
 ixp_fcall2msg(IxpMsg *msg, Fcall *fcall) {
- ulong size;
+ uint32_t size;
 
         msg->end = msg->data + msg->size;
         msg->pos = msg->data + SDWord;
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/request.c
--- a/lib/libixp/request.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/request.c Wed Jun 16 15:48:34 2010 -0400
@@ -10,11 +10,18 @@
 
 static void handlereq(Ixp9Req *r);
 
-static void
-_printfcall(Fcall *f) {
- USED(f);
-}
-void (*ixp_printfcall)(Fcall*) = _printfcall;
+/**
+ * Variable: ixp_printfcall
+ *
+ * When set to a non-null value, ixp_printfcall is called once for
+ * every incoming and outgoing Fcall. It is intended to simplify the
+ * writing of debugging code for clients, but may be used for any
+ * arbitrary purpose.
+ *
+ * See also:
+ * F<ixp_respond>, F<ixp_serve9conn>
+ */
+void (*ixp_printfcall)(Fcall*);
 
 static int
 min(int a, int b) {
@@ -79,7 +86,7 @@
 
 static void*
 createfid(Map *map, int fid, Ixp9Conn *p9conn) {
- Fid *f;
+ IxpFid *f;
 
         f = emallocz(sizeof *f);
         p9conn->ref++;
@@ -95,7 +102,7 @@
 
 static int
 destroyfid(Ixp9Conn *p9conn, ulong fid) {
- Fid *f;
+ IxpFid *f;
 
         f = ixp_maprm(&p9conn->fidmap, fid);
         if(f == nil)
@@ -132,7 +139,7 @@
         p9conn->conn = c;
 
         if(!ixp_mapinsert(&p9conn->tagmap, fcall.hdr.tag, req, false)) {
- respond(req, Eduptag);
+ ixp_respond(req, Eduptag);
                 return;
         }
 
@@ -153,11 +160,12 @@
         p9conn = r->conn;
         srv = p9conn->srv;
 
- ixp_printfcall(&r->ifcall);
+ if(ixp_printfcall)
+ ixp_printfcall(&r->ifcall);
 
         switch(r->ifcall.hdr.type) {
         default:
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                 break;
         case TVersion:
                 if(!strcmp(r->ifcall.version.version, "9P"))
@@ -167,11 +175,11 @@
                 else
                         r->ofcall.version.version = "unknown";
                 r->ofcall.version.msize = r->ifcall.version.msize;
- respond(r, nil);
+ ixp_respond(r, nil);
                 break;
         case TAttach:
                 if(!(r->fid = createfid(&p9conn->fidmap, r->ifcall.hdr.fid, p9conn))) {
- respond(r, Edupfid);
+ ixp_respond(r, Edupfid);
                         return;
                 }
                 /* attach is a required function */
@@ -179,166 +187,166 @@
                 break;
         case TClunk:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(!srv->clunk) {
- respond(r, nil);
+ ixp_respond(r, nil);
                         return;
                 }
                 srv->clunk(r);
                 break;
         case TFlush:
                 if(!(r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag))) {
- respond(r, Enotag);
+ ixp_respond(r, Enotag);
                         return;
                 }
                 if(!srv->flush) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 srv->flush(r);
                 break;
         case TCreate:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(r->fid->omode != -1) {
- respond(r, Eopen);
+ ixp_respond(r, Eopen);
                         return;
                 }
                 if(!(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
+ ixp_respond(r, Enotdir);
                         return;
                 }
                 if(!p9conn->srv->create) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->create(r);
                 break;
         case TOpen:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if((r->fid->qid.type&QTDIR) && (r->ifcall.topen.mode|P9_ORCLOSE) != (P9_OREAD|P9_ORCLOSE)) {
- respond(r, Eisdir);
+ ixp_respond(r, Eisdir);
                         return;
                 }
                 r->ofcall.ropen.qid = r->fid->qid;
                 if(!p9conn->srv->open) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->open(r);
                 break;
         case TRead:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(r->fid->omode == -1 || r->fid->omode == P9_OWRITE) {
- respond(r, Enoread);
+ ixp_respond(r, Enoread);
                         return;
                 }
                 if(!p9conn->srv->read) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->read(r);
                 break;
         case TRemove:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(!p9conn->srv->remove) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->remove(r);
                 break;
         case TStat:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(!p9conn->srv->stat) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->stat(r);
                 break;
         case TWalk:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if(r->fid->omode != -1) {
- respond(r, "cannot walk from an open fid");
+ ixp_respond(r, "cannot walk from an open fid");
                         return;
                 }
                 if(r->ifcall.twalk.nwname && !(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
+ ixp_respond(r, Enotdir);
                         return;
                 }
                 if((r->ifcall.hdr.fid != r->ifcall.twalk.newfid)) {
                         if(!(r->newfid = createfid(&p9conn->fidmap, r->ifcall.twalk.newfid, p9conn))) {
- respond(r, Edupfid);
+ ixp_respond(r, Edupfid);
                                 return;
                         }
                 }else
                         r->newfid = r->fid;
                 if(!p9conn->srv->walk) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->walk(r);
                 break;
         case TWrite:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
                 if((r->fid->omode&3) != P9_OWRITE && (r->fid->omode&3) != P9_ORDWR) {
- respond(r, "write on fid not opened for writing");
+ ixp_respond(r, "write on fid not opened for writing");
                         return;
                 }
                 if(!p9conn->srv->write) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->write(r);
                 break;
         case TWStat:
                 if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
                         return;
                 }
- if((ushort)~r->ifcall.twstat.stat.type) {
- respond(r, "wstat of type");
+ if(~r->ifcall.twstat.stat.type) {
+ ixp_respond(r, "wstat of type");
                         return;
                 }
- if((uint)~r->ifcall.twstat.stat.dev) {
- respond(r, "wstat of dev");
+ if(~r->ifcall.twstat.stat.dev) {
+ ixp_respond(r, "wstat of dev");
                         return;
                 }
- if((uchar)~r->ifcall.twstat.stat.qid.type || (ulong)~r->ifcall.twstat.stat.qid.version || (uvlong)~r->ifcall.twstat.stat.qid.path) {
- respond(r, "wstat of qid");
+ if(~r->ifcall.twstat.stat.qid.type || (ulong)~r->ifcall.twstat.stat.qid.version || ~r->ifcall.twstat.stat.qid.path) {
+ ixp_respond(r, "wstat of qid");
                         return;
                 }
                 if(r->ifcall.twstat.stat.muid && r->ifcall.twstat.stat.muid[0]) {
- respond(r, "wstat of muid");
+ ixp_respond(r, "wstat of muid");
                         return;
                 }
- if((ulong)~r->ifcall.twstat.stat.mode && ((r->ifcall.twstat.stat.mode&DMDIR)>>24) != r->fid->qid.type&QTDIR) {
- respond(r, "wstat on DMDIR bit");
+ if(~r->ifcall.twstat.stat.mode && ((r->ifcall.twstat.stat.mode&DMDIR)>>24) != r->fid->qid.type&QTDIR) {
+ ixp_respond(r, "wstat on DMDIR bit");
                         return;
                 }
                 if(!p9conn->srv->wstat) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
                         return;
                 }
                 p9conn->srv->wstat(r);
@@ -347,80 +355,93 @@
         }
 }
 
+/**
+ * Function: ixp_respond
+ *
+ * Sends a response to the given request. The response is
+ * constructed from the P<ofcall> member of the P<req> parameter, or
+ * from the P<error> parameter if it is non-null. In the latter
+ * case, the response is of type RError, while in any other case it
+ * is of the same type as P<req>->P<ofcall>, which must match the
+ * request type in P<req>->P<ifcall>.
+ *
+ * See also:
+ * T<Ixp9Req>, V<ixp_printfcall>
+ */
 void
-respond(Ixp9Req *r, const char *error) {
+ixp_respond(Ixp9Req *req, const char *error) {
         Ixp9Conn *p9conn;
         int msize;
 
- p9conn = r->conn;
+ p9conn = req->conn;
 
- switch(r->ifcall.hdr.type) {
+ switch(req->ifcall.hdr.type) {
         default:
                 if(!error)
                         assert(!"Respond called on unsupported fcall type");
                 break;
         case TVersion:
                 assert(error == nil);
- free(r->ifcall.version.version);
+ free(req->ifcall.version.version);
 
                 thread->lock(&p9conn->rlock);
                 thread->lock(&p9conn->wlock);
- msize = min(r->ofcall.version.msize, IXP_MAX_MSG);
+ msize = min(req->ofcall.version.msize, IXP_MAX_MSG);
                 p9conn->rmsg.data = erealloc(p9conn->rmsg.data, msize);
                 p9conn->wmsg.data = erealloc(p9conn->wmsg.data, msize);
                 p9conn->rmsg.size = msize;
                 p9conn->wmsg.size = msize;
                 thread->unlock(&p9conn->wlock);
                 thread->unlock(&p9conn->rlock);
- r->ofcall.version.msize = msize;
+ req->ofcall.version.msize = msize;
                 break;
         case TAttach:
                 if(error)
- destroyfid(p9conn, r->fid->fid);
- free(r->ifcall.tattach.uname);
- free(r->ifcall.tattach.aname);
+ destroyfid(p9conn, req->fid->fid);
+ free(req->ifcall.tattach.uname);
+ free(req->ifcall.tattach.aname);
                 break;
         case TOpen:
         case TCreate:
                 if(!error) {
- r->ofcall.ropen.iounit = p9conn->rmsg.size - 24;
- r->fid->iounit = r->ofcall.ropen.iounit;
- r->fid->omode = r->ifcall.topen.mode;
- r->fid->qid = r->ofcall.ropen.qid;
+ req->ofcall.ropen.iounit = p9conn->rmsg.size - 24;
+ req->fid->iounit = req->ofcall.ropen.iounit;
+ req->fid->omode = req->ifcall.topen.mode;
+ req->fid->qid = req->ofcall.ropen.qid;
                 }
- free(r->ifcall.tcreate.name);
+ free(req->ifcall.tcreate.name);
                 break;
         case TWalk:
- if(error || r->ofcall.rwalk.nwqid < r->ifcall.twalk.nwname) {
- if(r->ifcall.hdr.fid != r->ifcall.twalk.newfid && r->newfid)
- destroyfid(p9conn, r->newfid->fid);
- if(!error && r->ofcall.rwalk.nwqid == 0)
+ if(error || req->ofcall.rwalk.nwqid < req->ifcall.twalk.nwname) {
+ if(req->ifcall.hdr.fid != req->ifcall.twalk.newfid && req->newfid)
+ destroyfid(p9conn, req->newfid->fid);
+ if(!error && req->ofcall.rwalk.nwqid == 0)
                                 error = Enofile;
                 }else{
- if(r->ofcall.rwalk.nwqid == 0)
- r->newfid->qid = r->fid->qid;
+ if(req->ofcall.rwalk.nwqid == 0)
+ req->newfid->qid = req->fid->qid;
                         else
- r->newfid->qid = r->ofcall.rwalk.wqid[r->ofcall.rwalk.nwqid-1];
+ req->newfid->qid = req->ofcall.rwalk.wqid[req->ofcall.rwalk.nwqid-1];
                 }
- free(*r->ifcall.twalk.wname);
+ free(*req->ifcall.twalk.wname);
                 break;
         case TWrite:
- free(r->ifcall.twrite.data);
+ free(req->ifcall.twrite.data);
                 break;
         case TRemove:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
+ if(req->fid)
+ destroyfid(p9conn, req->fid->fid);
                 break;
         case TClunk:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
+ if(req->fid)
+ destroyfid(p9conn, req->fid->fid);
                 break;
         case TFlush:
- if((r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag)))
- respond(r->oldreq, Eintr);
+ if((req->oldreq = ixp_mapget(&p9conn->tagmap, req->ifcall.tflush.oldtag)))
+ ixp_respond(req->oldreq, Eintr);
                 break;
         case TWStat:
- ixp_freestat(&r->ifcall.twstat.stat);
+ ixp_freestat(&req->ifcall.twstat.stat);
                 break;
         case TRead:
         case TStat:
@@ -428,36 +449,37 @@
         /* Still to be implemented: auth */
         }
 
- r->ofcall.hdr.tag = r->ifcall.hdr.tag;
+ req->ofcall.hdr.tag = req->ifcall.hdr.tag;
 
         if(error == nil)
- r->ofcall.hdr.type = r->ifcall.hdr.type + 1;
+ req->ofcall.hdr.type = req->ifcall.hdr.type + 1;
         else {
- r->ofcall.hdr.type = RError;
- r->ofcall.error.ename = (char*)error;
+ req->ofcall.hdr.type = RError;
+ req->ofcall.error.ename = (char*)error;
         }
 
- ixp_printfcall(&r->ofcall);
+ if(ixp_printfcall)
+ ixp_printfcall(&req->ofcall);
 
- ixp_maprm(&p9conn->tagmap, r->ifcall.hdr.tag);;
+ ixp_maprm(&p9conn->tagmap, req->ifcall.hdr.tag);;
 
         if(p9conn->conn) {
                 thread->lock(&p9conn->wlock);
- msize = ixp_fcall2msg(&p9conn->wmsg, &r->ofcall);
+ msize = ixp_fcall2msg(&p9conn->wmsg, &req->ofcall);
                 if(ixp_sendmsg(p9conn->conn->fd, &p9conn->wmsg) != msize)
                         ixp_hangup(p9conn->conn);
                 thread->unlock(&p9conn->wlock);
         }
 
- switch(r->ofcall.hdr.type) {
+ switch(req->ofcall.hdr.type) {
         case RStat:
- free(r->ofcall.rstat.stat);
+ free(req->ofcall.rstat.stat);
                 break;
         case RRead:
- free(r->ofcall.rread.data);
+ free(req->ofcall.rread.data);
                 break;
         }
- free(r);
+ free(req);
         decref_p9conn(p9conn);
 }
 
@@ -481,12 +503,12 @@
         *(void**)context = flush_req;
 }
 
-/* Clunk an open Fid */
+/* Clunk an open IxpFid */
 static void
 voidfid(void *context, void *arg) {
         Ixp9Conn *p9conn;
         Ixp9Req *clunk_req;
- Fid *fid;
+ IxpFid *fid;
 
         fid = arg;
         p9conn = fid->conn;
@@ -524,8 +546,33 @@
 }
 
 /* Handle incoming 9P connections */
+/**
+ * Type: Ixp9Srv
+ * Type: Ixp9Req
+ * Function: ixp_serve9conn
+ *
+ * The ixp_serve9conn handles incoming 9P connections. It is
+ * ordinarily passed as the P<read> member to F<ixp_listen> with an
+ * Ixp9Srv structure passed as the P<aux> member. The handlers
+ * defined in the Ixp9Srv structure are called whenever a matching
+ * Fcall type is received. The handlers are expected to call
+ * F<ixp_respond> at some point, whether before they return or at
+ * some undefined point in the future. Whenever a client
+ * disconnects, libixp generates whatever flush and clunk events are
+ * required to leave the connection in a clean state and waits for
+ * all responses before freeing the connections associated data
+ * structures.
+ *
+ * Whenever a file is closed and an T<IxpFid> is about to be freed,
+ * the P<freefid> member is called to perform any necessary cleanup
+ * and to free any associated resources.
+ *
+ * See also:
+ * F<ixp_listen>, F<ixp_respond>, F<ixp_printfcall>,
+ * F<IxpFcall>, F<IxpFid>
+ */
 void
-serve_9pcon(IxpConn *c) {
+ixp_serve9conn(IxpConn *c) {
         Ixp9Conn *p9conn;
         int fd;
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/server.c
--- a/lib/libixp/server.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/server.c Wed Jun 16 15:48:34 2010 -0400
@@ -17,19 +17,18 @@
  * Params:
  * fs: The file descriptor on which to listen.
  * aux: A piece of data to store in the connection's
- * S<IxpConn> data structure.
- * read: The function to call when the connection has
+ * P<aux> member of the IxpConn data structure.
+ * read: The function called when the connection has
  * data available to read.
- * close: A cleanup function to call when the
+ * close: A cleanup function called when the
  * connection is closed.
  *
  * Starts the server P<srv> listening on P<fd>. The optional
- * callbacks are called as described, with the connections
- * S<IxpConn> data structure as their arguments.
+ * P<read> and P<close> callbacks are called with the IxpConn
+ * structure for the connection as their sole argument.
  *
  * Returns:
- * Returns the connection's new S<IxpConn> data
- * structure.
+ * Returns the connection's new IxpConn data structure.
  */
 IxpConn*
 ixp_listen(IxpServer *srv, int fd, void *aux,
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/srv_util.c
--- a/lib/libixp/srv_util.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/srv_util.c Wed Jun 16 15:48:34 2010 -0400
@@ -1,4 +1,4 @@
-/* Copyright ©2006-2010 Kris Maglione <fbsdaemon at gmail dot com>
+/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
  * See LICENSE file for license details.
  */
 #include <assert.h>
@@ -24,14 +24,10 @@
         long len;
 };
 
-/* Macros */
-#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
+#define QID(t, i) (((int64_t)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
 
-/* Global Vars */
-/***************/
 static IxpFileId* free_fileid;
 
-/* Utility Functions */
 /**
  * Function: ixp_srv_getfile
  * Type: IxpFileId
@@ -104,6 +100,28 @@
         return r;
 }
 
+/**
+ * Function: ixp_srv_readbuf
+ * Function: ixp_srv_writebuf
+ *
+ * Utility functions for handling TRead and TWrite requests for
+ * files backed by in-memory buffers. For both functions, P<buf>
+ * points to a buffer and P<len> specifies the length of the
+ * buffer. In the case of ixp_srv_writebuf, these values add a
+ * level of pointer indirection, and updates the values if they
+ * change.
+ *
+ * If P<max> has a value other than 0, ixp_srv_writebuf will
+ * truncate any writes to that point in the buffer. Otherwise,
+ * P<*buf> is assumed to be malloc(3) allocated, and is
+ * reallocated to fit the new data as necessary. The buffer is
+ * is always left nul-terminated.
+ *
+ * Bugs:
+ * ixp_srv_writebuf always truncates its buffer to the end
+ * of the most recent write.
+ */
+
 void
 ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len) {
 
@@ -176,6 +194,18 @@
         req->ifcall.io.data = p;
 }
 
+/**
+ * Function: ixp_srv_writectl
+ *
+ * This utility function is meant to simplify the writing of
+ * pseudo files to which single-lined commands are written.
+ * In order to use this function, the P<aux> member of
+ * P<req>->fid must be nul or an S<IxpFileId>. Each line of the
+ * written data is stripped of its trailing newline,
+ * nul-terminated, and stored in an S<IxpMsg>. For each line
+ * thus prepared, P<fn> is called with the IxpMsg pointer and
+ * the the P<p> member of the IxpFileId.
+ */
 char*
 ixp_srv_writectl(Ixp9Req *req, char* (*fn)(void*, IxpMsg*)) {
         char *err, *s, *p, c;
@@ -207,6 +237,41 @@
         return err;
 }
 
+/**
+ * Function: ixp_pending_write
+ * Function: ixp_pending_pushfid
+ * Function: ixp_pending_clunk
+ * Function: ixp_pending_flush
+ * Function: ixp_pending_respond
+ * Type: IxpPending
+ *
+ * These functions aid in writing virtual files used for
+ * broadcasting events or writing data when it becomes
+ * available. When a file to be used with these functions is
+ * opened, ixp_pending_pushfid should be called with its
+ * S<IxpFid> as an argument. This sets the IxpFid's P<pending>
+ * member to true. Thereafter, for each file with its
+ * P<pending> member set, ixp_pending_respond should be called
+ * for each TRead request, ixp_pending_clunk for each TClunk
+ * request, and ixp_pending_flush for each TFlush request.
+ *
+ * ixp_pending_write queues the data in P<dat> of length P<ndat>
+ * to be written to each currently pending fid in P<pending>. If
+ * there is a read request pending for a given fid, the data is
+ * written immediately. Otherwise, it is written the next time
+ * ixp_pending_respond is called. Likewise, if there is data
+ * queued when ixp_pending_respond is called, it is written
+ * immediately, otherwise the request is queued.
+ *
+ * The IxpPending data structure is opaque and should be
+ * initialized zeroed before using these functions for the first
+ * time.
+ *
+ * Returns:
+ * ixp_pending_clunk returns true if P<pending> has any
+ * more pending IxpFids.
+ */
+
 void
 ixp_pending_respond(Ixp9Req *req) {
         IxpFileId *file;
@@ -228,7 +293,7 @@
                         req_link->prev->next = req_link->next;
                         free(req_link);
                 }
- respond(req, nil);
+ ixp_respond(req, nil);
                 free(queue);
         }else {
                 req_link = emallocz(sizeof *req_link);
@@ -242,13 +307,13 @@
 }
 
 void
-ixp_pending_write(IxpPending *pending, char *dat, long n) {
+ixp_pending_write(IxpPending *pending, char *dat, long ndat) {
         IxpRequestLink req_link;
         IxpQueue **qp, *queue;
         IxpPendingLink *pp;
         IxpRequestLink *rp;
 
- if(n == 0)
+ if(ndat == 0)
                 return;
 
         if(pending->req.next == nil) {
@@ -262,9 +327,9 @@
                 for(qp=&pp->queue; *qp; qp=&qp[0]->link)
                         ;
                 queue = emallocz(sizeof *queue);
- queue->dat = emalloc(n);
- memcpy(queue->dat, dat, n);
- queue->len = n;
+ queue->dat = emalloc(ndat);
+ memcpy(queue->dat, dat, ndat);
+ queue->len = ndat;
                 *qp = queue;
         }
 
@@ -348,7 +413,7 @@
                 req_link = req_link->next;
                 if(r->fid == pend_link->fid) {
                         pending_flush(r);
- respond(r, "interrupted");
+ ixp_respond(r, "interrupted");
                 }
         }
 
@@ -362,10 +427,45 @@
         }
         more = (pend_link->pending->fids.next == &pend_link->pending->fids);
         free(pend_link);
- respond(req, nil);
+ ixp_respond(req, nil);
         return more;
 }
 
+/**
+ * Function: ixp_srv_walkandclone
+ * Function: ixp_srv_readdir
+ * Function: ixp_srv_verifyfile
+ * Type: IxpLookupFn
+ *
+ * These convenience functions simplify the writing of basic and
+ * static file servers. They use a generic file lookup function
+ * to simplify the process of walking, cloning, and returning
+ * directory listings. Given the S<IxpFileId> of a directory and a
+ * filename name should return a new IxpFileId (allocated via
+ * F<ixp_srv_getfile>) for the matching directory entry, or null
+ * if there is no match. If the passed name is null, P<lookup>
+ * should return a linked list of IxpFileIds, one for each child
+ * directory entry.
+ *
+ * ixp_srv_walkandclone handles the moderately complex process
+ * of walking from a directory entry and cloning fids, and calls
+ * F<ixp_respond>. It should be called in response to a TWalk
+ * request.
+ *
+ * ixp_srv_readdir should be called to handle read requests on
+ * directories. It prepares a stat for each child of the
+ * directory, taking into account the requested offset, and
+ * calls F<ixp_respond>. The P<dostat> parameter must be a
+ * function which fills the passed S<IxpStat> pointer based on
+ * the contents of the passed IxpFileId.
+ *
+ * ixp_srv_verifyfile returns whether a file still exists in the
+ * filesystem, and should be used by filesystems that invalidate
+ * files once they have been deleted.
+ *
+ * See also:
+ * S<IxpFileId>, S<ixp_getfile>, S<ixp_freefile>
+ */
 bool
 ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup) {
         IxpFileId *tfile;
@@ -393,7 +493,7 @@
         IxpStat stat;
         char *buf;
         ulong size, n;
- uvlong offset;
+ uint64_t offset;
 
         file = req->fid->aux;
 
@@ -424,7 +524,7 @@
         }
         req->ofcall.io.count = msg.pos - msg.data;
         req->ofcall.io.data = msg.data;
- respond(req, nil);
+ ixp_respond(req, nil);
 }
 
 void
@@ -436,8 +536,8 @@
         for(i=0; i < req->ifcall.twalk.nwname; i++) {
                 if(!strcmp(req->ifcall.twalk.wname[i], "..")) {
                         if(file->next) {
- tfile=file;
- file=file->next;
+ tfile = file;
+ file = file->next;
                                 ixp_srv_freefile(tfile);
                         }
                 }else{
@@ -459,7 +559,7 @@
                         file=file->next;
                         ixp_srv_freefile(tfile);
                 }
- respond(req, Enofile);
+ ixp_respond(req, Enofile);
                 return;
         }
         /* Remove refs for req->fid if no new fid */
@@ -473,6 +573,6 @@
         }else
                 req->newfid->aux = file;
         req->ofcall.rwalk.nwqid = i;
- respond(req, nil);
+ ixp_respond(req, nil);
 }
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/timer.c
--- a/lib/libixp/timer.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/timer.c Wed Jun 16 15:48:34 2010 -0400
@@ -51,7 +51,7 @@
 ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void*), void *aux) {
         Timer **tp;
         Timer *t;
- long time;
+ uint32_t time;
 
         time = ixp_msec();
         if(time == -1)
@@ -105,7 +105,7 @@
         return t != nil;
 }
 
-/**
+/*
  * Function: ixp_nexttimer
  *
  * Triggers any timers whose timeouts have ellapsed. This is
@@ -121,7 +121,7 @@
 long
 ixp_nexttimer(IxpServer *srv) {
         Timer *t;
- long time, ret;
+ uint32_t time, ret;
 
         SET(time);
         thread->lock(&srv->lk);
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/transport.c
--- a/lib/libixp/transport.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/transport.c Wed Jun 16 15:48:34 2010 -0400
@@ -49,6 +49,27 @@
         return count - num;
 }
 
+/**
+ * Function: ixp_sendmsg
+ * Function: ixp_recvmsg
+ *
+ * These functions read and write messages to and from the given
+ * file descriptors.
+ *
+ * ixp_sendmsg writes the data at P<msg>->pos upto P<msg>->end.
+ * If the call returns non-zero, all data is assured to have
+ * been written.
+ *
+ * ixp_recvmsg first reads a 32 bit, little-endian length from
+ * P<fd> and then reads a message of that length (including the
+ * 4 byte size specifier) into the buffer at P<msg>->data, so
+ * long as the size is less than P<msg>->size.
+ *
+ * Returns:
+ * These functions return the number of bytes read or
+ * written, or 0 on error. Errors are stored in
+ * F<ixp_errbuf>.
+ */
 uint
 ixp_sendmsg(int fd, IxpMsg *msg) {
         int r;
@@ -70,7 +91,7 @@
 uint
 ixp_recvmsg(int fd, IxpMsg *msg) {
         enum { SSize = 4 };
- ulong msize, size;
+ uint32_t msize, size;
 
         msg->mode = MsgUnpack;
         msg->pos = msg->data;
diff -r ffbf3797fde8 -r dbda92c4b3b4 lib/libixp/util.c
--- a/lib/libixp/util.c Tue Jun 15 14:26:31 2010 -0400
+++ b/lib/libixp/util.c Wed Jun 16 15:48:34 2010 -0400
@@ -11,6 +11,12 @@
 #include <pwd.h>
 #include "ixp_local.h"
 
+/**
+ * Function: ixp_smprint
+ *
+ * This function formats its arguments as F<printf> and returns
+ * a F<malloc> allocated string containing the result.
+ */
 char*
 ixp_smprint(const char *fmt, ...) {
         va_list ap;
@@ -125,8 +131,14 @@
         return namespace;
 }
 
+/**
+ * Function: ixp_eprint
+ *
+ * libixp calls this function on error. It formats its arguments
+ * as F<printf> and exits the program.
+ */
 void
-eprint(const char *fmt, ...) {
+ixp_eprint(const char *fmt, ...) {
         va_list ap;
         int err;
 
@@ -170,8 +182,19 @@
         exit(1);
 }
 
+/**
+ * Function: ixp_emalloc
+ * Function: ixp_emallocz
+ * Function: ixp_erealloc
+ * Function: ixp_estrdup
+ *
+ * These functions act like their stdlib counterparts, but print
+ * an error message and exit the program if allocation fails.
+ * ixp_emallocz acts like ixp_emalloc but additionally zeros the
+ * result of the allocation.
+ */
 void*
-emalloc(uint size) {
+ixp_emalloc(uint size) {
         void *ret = malloc(size);
         if(!ret)
                 mfatal("malloc", size);
@@ -179,14 +202,14 @@
 }
 
 void*
-emallocz(uint size) {
+ixp_emallocz(uint size) {
         void *ret = emalloc(size);
         memset(ret, 0, size);
         return ret;
 }
 
 void*
-erealloc(void *ptr, uint size) {
+ixp_erealloc(void *ptr, uint size) {
         void *ret = realloc(ptr, size);
         if(!ret)
                 mfatal("realloc", size);
@@ -194,7 +217,7 @@
 }
 
 char*
-estrdup(const char *str) {
+ixp_estrdup(const char *str) {
         void *ret = strdup(str);
         if(!ret)
                 mfatal("strdup", strlen(str));
@@ -202,7 +225,7 @@
 }
 
 uint
-tokenize(char *res[], uint reslen, char *str, char delim) {
+ixp_tokenize(char *res[], uint reslen, char *str, char delim) {
         char *s;
         uint i;
 
@@ -220,7 +243,7 @@
 }
 
 uint
-strlcat(char *dst, const char *src, uint size) {
+ixp_strlcat(char *dst, const char *src, uint size) {
         const char *s;
         char *d;
         int n, len;
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/Ixp9Srv.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/Ixp9Srv.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,72 @@
+.TH "IXP9SRV" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+Ixp9Srv, Ixp9Req, ixp_serve9conn
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct Ixp9Srv Ixp9Srv;
+ struct Ixp9Srv {
+ void* aux;
+ void (*attach)(Ixp9Req*);
+ void (*clunk)(Ixp9Req*);
+ void (*create)(Ixp9Req*);
+ void (*flush)(Ixp9Req*);
+ void (*open)(Ixp9Req*);
+ void (*read)(Ixp9Req*);
+ void (*remove)(Ixp9Req*);
+ void (*stat)(Ixp9Req*);
+ void (*walk)(Ixp9Req*);
+ void (*write)(Ixp9Req*);
+ void (*wstat)(Ixp9Req*);
+ void (*freefid)(IxpFid*);
+ }
+
+ typedef struct Ixp9Req Ixp9Req;
+ struct Ixp9Req {
+ Ixp9Srv* srv;
+ IxpFid* fid; /* Fid structure corresponding to IxpFHdr.fid */
+ IxpFid* newfid; /* Corresponds to IxpFTWStat.newfid */
+ Ixp9Req* oldreq; /* For TFlush requests, the original request. */
+ IxpFcall ifcall; /* The incoming request fcall. */
+ IxpFcall ofcall; /* The response fcall, to be filled by handler. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+
+ /* Private members */
+ ...
+ }
+
+ void ixp_serve9conn(IxpConn *c);
+.fi
+
+.SH DESCRIPTION
+.P
+The ixp_serve9conn handles incoming 9P connections. It is
+ordinarily passed as the \fIread\fR member to \fBixp_listen(3)\fR with an
+Ixp9Srv structure passed as the \fIaux\fR member. The handlers
+defined in the Ixp9Srv structure are called whenever a matching
+Fcall type is received. The handlers are expected to call
+\fBixp_respond(3)\fR at some point, whether before they return or at
+some undefined point in the future. Whenever a client
+disconnects, libixp generates whatever flush and clunk events are
+required to leave the connection in a clean state and waits for
+all responses before freeing the connections associated data
+structures.
+
+.P
+Whenever a file is closed and an \fBIxpFid(3)\fR is about to be freed,
+the \fIfreefid\fR member is called to perform any necessary cleanup
+and to free any associated resources.
+
+.SH SEE ALSO
+.P
+ixp_listen(3), ixp_respond(3), ixp_printfcall(3),
+IxpFcall(3), IxpFid(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- Ixp9Srv.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/IxpFcall.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/IxpFcall.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,186 @@
+.TH "IXPFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpFcall, IxpFType, IxpFAttach, IxpFError, IxpFHdr, IxpFIO, IxpFRAuth, IxpFROpen, IxpFRStat, IxpFRWalk, IxpFTCreate, IxpFTFlush, IxpFTWStat, IxpFTWalk, IxpFVersion
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpFcall IxpFcall;
+ typedef union IxpFcall IxpFcall;
+ union IxpFcall {
+ IxpFHdr hdr;
+ IxpFVersion version;
+ IxpFVersion tversion;
+ IxpFVersion rversion;
+ IxpFTFlush tflush;
+ IxpFROpen ropen;
+ IxpFROpen rcreate;
+ IxpFROpen rattach;
+ IxpFError error;
+ IxpFRAuth rauth;
+ IxpFAttach tattach;
+ IxpFAttach tauth;
+ IxpFTCreate tcreate;
+ IxpFTCreate topen;
+ IxpFTWalk twalk;
+ IxpFRWalk rwalk;
+ IxpFTWStat twstat;
+ IxpFRStat rstat;
+ IxpFIO twrite;
+ IxpFIO rwrite;
+ IxpFIO tread;
+ IxpFIO rread;
+ IxpFIO io;
+ }
+
+ enum IxpFType {
+ P9_TVersion = 100,
+ P9_RVersion,
+ P9_TAuth = 102,
+ P9_RAuth,
+ P9_TAttach = 104,
+ P9_RAttach,
+ P9_TError = 106, /* illegal */
+ P9_RError,
+ P9_TFlush = 108,
+ P9_RFlush,
+ P9_TWalk = 110,
+ P9_RWalk,
+ P9_TOpen = 112,
+ P9_ROpen,
+ P9_TCreate = 114,
+ P9_RCreate,
+ P9_TRead = 116,
+ P9_RRead,
+ P9_TWrite = 118,
+ P9_RWrite,
+ P9_TClunk = 120,
+ P9_RClunk,
+ P9_TRemove = 122,
+ P9_RRemove,
+ P9_TStat = 124,
+ P9_RStat,
+ P9_TWStat = 126,
+ P9_RWStat,
+ }
+
+ typedef struct IxpFAttach IxpFAttach;
+ struct IxpFAttach {
+ IxpFHdr hdr;
+ uint32_t afid;
+ char* uname;
+ char* aname;
+ }
+
+ typedef struct IxpFError IxpFError;
+ struct IxpFError {
+ IxpFHdr hdr;
+ char* ename;
+ }
+
+ typedef struct IxpFHdr IxpFHdr;
+ struct IxpFHdr {
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
+ }
+
+ typedef struct IxpFIO IxpFIO;
+ struct IxpFIO {
+ IxpFHdr hdr;
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
+ char* data; /* Twrite, Rread */
+ }
+
+ typedef struct IxpFRAuth IxpFRAuth;
+ struct IxpFRAuth {
+ IxpFHdr hdr;
+ IxpQid aqid;
+ }
+
+ typedef struct IxpFROpen IxpFROpen;
+ struct IxpFROpen {
+ IxpFHdr hdr;
+ IxpQid qid; /* +Rattach */
+ uint32_t iounit;
+ }
+
+ typedef struct IxpFRStat IxpFRStat;
+ struct IxpFRStat {
+ IxpFHdr hdr;
+ uint16_t nstat;
+ uchar* stat;
+ }
+
+ typedef struct IxpFRWalk IxpFRWalk;
+ struct IxpFRWalk {
+ IxpFHdr hdr;
+ uint16_t nwqid;
+ IxpQid wqid\fI[IXP_MAX_WELEM]\fR;
+ }
+
+ typedef struct IxpFTCreate IxpFTCreate;
+ struct IxpFTCreate {
+ IxpFHdr hdr;
+ uint32_t perm;
+ char* name;
+ uint8_t mode; /* +Topen */
+ }
+
+ typedef struct IxpFTFlush IxpFTFlush;
+ struct IxpFTFlush {
+ IxpFHdr hdr;
+ uint16_t oldtag;
+ }
+
+ typedef struct IxpFTWStat IxpFTWStat;
+ struct IxpFTWStat {
+ IxpFHdr hdr;
+ IxpStat stat;
+ }
+
+ typedef struct IxpFTWalk IxpFTWalk;
+ struct IxpFTWalk {
+ IxpFHdr hdr;
+ uint32_t newfid;
+ uint16_t nwname;
+ char* wname\fI[IXP_MAX_WELEM]\fR;
+ }
+
+ typedef struct IxpFVersion IxpFVersion;
+ struct IxpFVersion {
+ IxpFHdr hdr;
+ uint32_t msize;
+ char* version;
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpFcall structure represents a 9P protocol message. The
+\fIhdr\fR element is common to all Fcall types, and may be used to
+determine the type and tag of the message. The IxpFcall type is
+used heavily in server applications, where it both presents a
+request to handler functions and returns a response to the
+client.
+
+.P
+Each member of the IxpFcall structure represents a certain
+message type, which can be discerned from the \fIhdr.type\fR field.
+This value corresponds to one of the IxpFType constants. Types
+with significant overlap use the same structures, thus TRead and
+RWrite are both represented by IxpFIO and can be accessed via the
+\fIio\fR member as well as \fItread\fR and \fIrwrite\fR respectively.
+
+.SH SEE ALSO
+.P
+Ixp9Srv(3), Ixp9Req(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpFcall.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/IxpFid.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/IxpFid.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,41 @@
+.TH "IXPFID" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpFid
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpFid IxpFid;
+ struct IxpFid {
+ char* uid; /* The uid of the file opener. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ uint32_t fid; /* The ID number of the fid. */
+ IxpQid qid; /* The filesystem-unique QID of the file. */
+ signed char omode; /* The open mode of the file. */
+ uint iounit; /* The maximum size of any IO request. */
+
+ /* Private members */
+ ...
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+Represents an open file for a 9P connection. The same
+structure persists as long as the file remains open, and is
+installed in the \fBIxp9Req(3)\fR structure for any request Fcall
+which references it. Handlers may use the \fIaux\fR member to
+store any data which must persist for the life of the open
+file.
+
+.SH SEE ALSO
+.P
+Ixp9Req(3), IxpQid(3), IxpOMode(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpFid.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/IxpMsg.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/IxpMsg.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,55 @@
+.TH "IXPMSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpMsg, IxpMsgMode, ixp_message
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpMsg IxpMsg;
+ struct IxpMsg {
+ char* data; /* Begining of buffer. */
+ char* pos; /* Current position in buffer. */
+ char* end; /* End of message. */
+ uint size; /* Size of buffer. */
+ uint mode; /* MsgPack or MsgUnpack. */
+ }
+
+ enum IxpMsgMode {
+ MsgPack,
+ MsgUnpack,
+ }
+
+ IxpMsg ixp_message(char *data, uint length, uint mode);
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpMsg struct represents a binary message, and is used
+extensively by libixp for converting messages to and from
+wire format. The location and size of a buffer are stored in
+\fIdata\fR and \fIsize\fR, respectively. \fIpos\fR points to the
+location in the message currently being packed or unpacked,
+while \fIend\fR points to the end of the message. The packing
+functions advance \fIpos\fR as they go, always ensuring that
+they don't read or write past \fIend\fR. When a message is
+entirely packed or unpacked, \fIpos\fR whould be less than or
+equal to \fIend\fR. Any other state indicates error.
+
+.P
+ixp_message is a convenience function to pack a construct an
+IxpMsg from a buffer of a given \fIlength\fR and a given
+\fImode\fR. \fIpos\fR and \fIdata\fR are set to \fIdata\fR and \fIend\fR is
+set to \fIdata\fR + \fIlength\fR.
+
+.SH SEE ALSO
+.P
+ixp_pu8(3), ixp_pu16(3), ixp_pu32(3), ixp_pu64(3),
+ixp_pstring(3), ixp_pstrings(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpMsg.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/IxpThread.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/IxpThread.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,81 @@
+.TH "IXPTHREAD" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpThread, IxpMutex, IxpRWLock, IxpRendez, ixp_thread
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpThread IxpThread;
+ struct IxpThread {
+ /* Read/write lock */
+ int (*initrwlock)(IxpRWLock*);
+ void (*rlock)(IxpRWLock*);
+ int (*canrlock)(IxpRWLock*);
+ void (*runlock)(IxpRWLock*);
+ void (*wlock)(IxpRWLock*);
+ int (*canwlock)(IxpRWLock*);
+ void (*wunlock)(IxpRWLock*);
+ void (*rwdestroy)(IxpRWLock*);
+ /* Mutex */
+ int (*initmutex)(IxpMutex*);
+ void (*lock)(IxpMutex*);
+ int (*canlock)(IxpMutex*);
+ void (*unlock)(IxpMutex*);
+ void (*mdestroy)(IxpMutex*);
+ /* Rendezvous point */
+ int (*initrendez)(IxpRendez*);
+ void (*sleep)(IxpRendez*);
+ int (*wake)(IxpRendez*);
+ int (*wakeall)(IxpRendez*);
+ void (*rdestroy)(IxpRendez*);
+ /* Other */
+ char* (*errbuf)(void);
+ ssize_t (*read)(int, void*, size_t);
+ ssize_t (*write)(int, const void*, size_t);
+ int (*select)(int, fd_set*, fd_set*, fd_set*, struct timeval*);
+ }
+
+ typedef struct IxpMutex IxpMutex;
+ struct IxpMutex {
+ void* aux;
+ }
+
+ typedef struct IxpRWLock IxpRWLock;
+ struct IxpRWLock {
+ void* aux;
+ }
+
+ typedef struct IxpRendez IxpRendez;
+ struct IxpRendez {
+ IxpMutex* mutex;
+ void* aux;
+ }
+
+ IxpThread* ixp_thread;
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpThread structure is used to adapt libixp to any of the
+myriad threading systems it may be used with. Before any
+other of libixp's functions is called, ixp_thread may be set
+to a structure filled with implementations of various locking
+primitives, along with primitive IO functions which may
+perform context switches until data is available.
+
+.P
+The names of the functions should be fairly self\-explanitory.
+Read/write locks should allow multiple readers and a single
+writer of a shared resource, but should not allow new readers
+while a writer is waitng for a lock. Mutexes should allow
+only one accessor at a time. Rendezvous points are similar to
+pthread condition types. \fIerrbuf\fR should return a
+thread\-local buffer or the size IXP_ERRMAX.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpThread.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_close.3
--- a/man/ixp_close.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_close.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   int ixp_close(IxpCFid *f);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_dial.3
--- a/man/ixp_dial.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_dial.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   int ixp_dial(const char *address);
   
   int ixp_announce(const char *address);
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_emalloc.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_emalloc.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,30 @@
+.TH "IXP_EMALLOC" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_emalloc, ixp_emallocz, ixp_erealloc, ixp_estrdup
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void *ixp_emalloc(uint size);
+
+ void *ixp_emallocz(uint size);
+
+ void *ixp_erealloc(void *ptr, uint size);
+
+ char *ixp_estrdup(const char *str);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions act like their stdlib counterparts, but print
+an error message and exit the program if allocation fails.
+ixp_emallocz acts like ixp_emalloc but additionally zeros the
+result of the allocation.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_emalloc.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_eprint.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_eprint.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,22 @@
+.TH "IXP_EPRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_eprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_eprint(const char *fmt, ...);
+.fi
+
+.SH DESCRIPTION
+.P
+libixp calls this function on error. It formats its arguments
+as \fBprintf(3)\fR and exits the program.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_eprint.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_errbuf.3
--- a/man/ixp_errbuf.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_errbuf.3 Wed Jun 16 15:48:34 2010 -0400
@@ -2,17 +2,21 @@
 
 .SH NAME
 .P
-ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr
+ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr, ixp_vsnprint
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   char *ixp_errbuf(void);
   
- void ixp_errstr(char *buf, int size);
+ void ixp_errstr(char *buf, int nbuf);
   
- void ixp_rerrstr(char *buf, int size);
+ void ixp_rerrstr(char *buf, int nbuf);
   
   void ixp_werrstr(const char *fmt, ...);
+
+ int (*ixp_vsnprint)(char *buf, int nbuf, const char *fmt, va_list);
 .fi
 
 .SH PARAMETERS
@@ -20,7 +24,7 @@
 buf
 The buffer to read and/or fill.
 .TP
-size
+nbuf
 The size of the buffer.
 .TP
 fmt
@@ -41,13 +45,16 @@
 the current thread's error buffer, while \fBixp_errstr(3)\fR
 exchanges \fIbuf\fR's contents with those of the current
 thread's error buffer. \fBixp_werrstr(3)\fR formats the given
-format string, \fIfmt\fR, via \fBixp_vsmprint(3)\fR and writes it to
+format string, \fIfmt\fR, via \fBixp_vsnprint(3)\fR and writes it to
 the error buffer.
 
-.SH RETURN VALUE
 .P
-\fBixp_errbuf(3)\fR returns the current thread's error
-string buffer.
+\fBixp_vsnprint(3)\fR may be set to a function which will format
+its arguments write the result to the \fInbuf\fR length buffer
+\fBbuf(3)\fR. The default value is \fBvsnprintf(3)\fR. The function must
+format '%s' as a nul\-terminated string and may not consume
+any arguments not indicated by a %\-prefixed format specifier,
+but may otherwise behave in any manner chosen by the user.
 
 .SH SEE ALSO
 .P
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_fcall2msg.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_fcall2msg.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,34 @@
+.TH "IXP_FCALL2MSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_fcall2msg, ixp_msg2fcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ uint ixp_fcall2msg(IxpMsg *msg, Fcall *fcall);
+
+ uint ixp_msg2fcall(IxpMsg *msg, Fcall *fcall);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions pack or unpack a 9P protocol message. The
+message is set to the appropriate mode and its position is
+set to the begining of its buffer.
+
+.SH RETURN VALUE
+.P
+These functions return the size of the message on
+success and 0 on failure.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pfcall(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_fcall2msg.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_freestat.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_freestat.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,25 @@
+.TH "IXP_FREESTAT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_freestat, ixp_freefcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_freestat(Stat *s);
+
+ void ixp_freefcall(Fcall *fcall);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions free malloc(3) allocated data in the members
+of the passed structures and set those members to nil. They
+do not free the structures themselves.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_freestat.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_hangup.3
--- a/man/ixp_hangup.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_hangup.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   void ixp_hangup(IxpConn *c);
   
   void ixp_server_close(IxpServer *s);
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_listen.3
--- a/man/ixp_listen.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_listen.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,16 +6,18 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   IxpConn *ixp_listen(IxpServer *srv, int fd, void *aux, void (*read)(IxpConn *), void (*close)(IxpConn *));
   
   typedef struct IxpConn IxpConn;
   struct IxpConn {
           IxpServer* srv;
- void* aux;
- int fd;
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ int fd; /* The file descriptor of the connection. */
           void (*read)(IxpConn *);
           void (*close)(IxpConn *);
- char closed;
+ char closed; /* Non-zero when //fd// has been closed. */
   
           /* Private members */
           ...
@@ -29,26 +31,25 @@
 .TP
 aux
 A piece of data to store in the connection's
-\fBIxpConn(3)\fR data structure.
+\fIaux\fR member of the IxpConn data structure.
 .TP
 read
-The function to call when the connection has
+The function called when the connection has
 data available to read.
 .TP
 close
-A cleanup function to call when the
+A cleanup function called when the
 connection is closed.
 
 .SH DESCRIPTION
 .P
 Starts the server \fIsrv\fR listening on \fIfd\fR. The optional
-callbacks are called as described, with the connections
-\fBIxpConn(3)\fR data structure as their arguments.
+\fIread\fR and \fIclose\fR callbacks are called with the IxpConn
+structure for the connection as their sole argument.
 
 .SH RETURN VALUE
 .P
-Returns the connection's new \fBIxpConn(3)\fR data
-structure.
+Returns the connection's new IxpConn data structure.
 
 
 .\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_mount.3
--- a/man/ixp_mount.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_mount.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   IxpClient *ixp_mount(const char *address);
   
   IxpClient *ixp_mountfd(int fd);
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_msec.3
--- a/man/ixp_msec.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_msec.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   long ixp_msec(void);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_namespace.3
--- a/man/ixp_namespace.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_namespace.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   char *ixp_namespace(void);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_nexttimer.3
--- a/man/ixp_nexttimer.3 Tue Jun 15 14:26:31 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-.TH "IXP_NEXTTIMER" 3 "2010 Jun" "libixp Manual"
-
-.SH NAME
-.P
-ixp_nexttimer
-
-.SH SYNOPSIS
-.nf
- long ixp_nexttimer(IxpServer *srv);
-.fi
-
-.SH DESCRIPTION
-.P
-Triggers any timers whose timeouts have ellapsed. This is
-primarily intended to be called from libixp's select
-loop.
-
-.SH RETURN VALUE
-.P
-Returns the number of milliseconds until the next
-timer's timeout.
-
-.SH SEE ALSO
-.P
-ixp_settimer(3), ixp_serverloop(3)
-
-
-.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
-.\" cmdline: txt2tags -o- ixp_nexttimer.man3
-
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_open.3
--- a/man/ixp_open.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_open.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,18 +6,20 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   IxpCFid *ixp_open(IxpClient *c, const char *path, uchar mode);
   
   IxpCFid *ixp_create(IxpClient *c, const char *path, uint perm, uchar mode);
   
   typedef struct IxpCFid IxpCFid;
   struct IxpCFid {
- uint fid;
+ uint32_t fid;
           IxpQid qid;
- uchar mode;
+ uint8_t mode;
           uint open;
           uint iounit;
- uvlong offset;
+ uint32_t offset;
           IxpClient* client;
   
           /* Private members */
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pdata.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pdata.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,35 @@
+.TH "IXP_PDATA" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pdata
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pdata(IxpMsg *msg, char **data, uint len);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks a raw character buffer of size \fIlen\fR.
+
+.P
+If \fImsg\fR\->mode is MsgPack, buffer pointed to by \fIdata\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the address pointed to by \fIs\fR is loaded with a
+malloc(3) allocated buffer with the contents of the buffer at
+\fImsg\fR\->pos. In either case, \fImsg\fR\->pos is advanced by the
+number of bytes read or written. If the action would advance
+\fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is still advanced
+but no other action is taken.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pstring(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pdata.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pending_write.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pending_write.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,62 @@
+.TH "IXP_PENDING_WRITE" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pending_write, ixp_pending_pushfid, ixp_pending_clunk, ixp_pending_flush, ixp_pending_respond, IxpPending
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_pending_write(IxpPending *pending, char *dat, long ndat);
+
+ void ixp_pending_pushfid(IxpPending *pending, Fid *fid);
+
+ bool ixp_pending_clunk(Ixp9Req *req);
+
+ void ixp_pending_flush(Ixp9Req *req);
+
+ void ixp_pending_respond(Ixp9Req *req);
+
+ typedef struct IxpPending IxpPending;
+ struct IxpPending {
+ /* Private members */
+ ...
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+These functions aid in writing virtual files used for
+broadcasting events or writing data when it becomes
+available. When a file to be used with these functions is
+opened, ixp_pending_pushfid should be called with its
+\fBIxpFid(3)\fR as an argument. This sets the IxpFid's \fIpending\fR
+member to true. Thereafter, for each file with its
+\fIpending\fR member set, ixp_pending_respond should be called
+for each TRead request, ixp_pending_clunk for each TClunk
+request, and ixp_pending_flush for each TFlush request.
+
+.P
+ixp_pending_write queues the data in \fIdat\fR of length \fIndat\fR
+to be written to each currently pending fid in \fIpending\fR. If
+there is a read request pending for a given fid, the data is
+written immediately. Otherwise, it is written the next time
+ixp_pending_respond is called. Likewise, if there is data
+queued when ixp_pending_respond is called, it is written
+immediately, otherwise the request is queued.
+
+.P
+The IxpPending data structure is opaque and should be
+initialized zeroed before using these functions for the first
+time.
+
+.SH RETURN VALUE
+.P
+ixp_pending_clunk returns true if \fIpending\fR has any
+more pending IxpFids.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pending_write.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pfcall.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pfcall.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,43 @@
+.TH "IXP_PFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pfcall, ixp_pqid, ixp_pqids, ixp_pstat, ixp_sizeof_stat
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pfcall(IxpMsg *msg, Fcall *fcall);
+
+ void ixp_pqid(IxpMsg *msg, Qid *qid);
+
+ void ixp_pqids(IxpMsg *msg, uint16_t *num, Qid qid\fI[]\fR, uint max);
+
+ void ixp_pstat(IxpMsg *msg, Stat *stat);
+
+ uint16_t ixp_sizeof_stat(Stat *stat);
+.fi
+
+.SH DESCRIPTION
+.P
+These convenience functions pack or unpack the contents of
+libixp structures into their wire format. They behave as if
+\fBixp_pu8(3)\fR, \fBixp_pu16(3)\fR, \fBixp_pu32(3)\fR, \fBixp_pu64(3)\fR, and
+\fBixp_pstring(3)\fR were called for each member of the structure
+in question. ixp_pqid is to ixp_pqid as \fBixp_pstrings(3)\fR is to
+ixp_pstring.
+
+.P
+ixp_sizeof_stat returns the size of the packed represention
+of \fIstat\fR.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pu8(3), ixp_pu16(3), ixp_pu32(3),
+ixp_pu64(3), ixp_pstring(3), ixp_pstrings(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pfcall.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_print.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_print.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,57 @@
+.TH "IXP_PRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_print, ixp_vprint, ixp_vsmprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ int ixp_print(IxpCFid *fid, const char *fmt, ...);
+
+ int ixp_vprint(IxpCFid *fid, const char *fmt, va_list args);
+
+ char* (*ixp_vsmprint)(const char *fmt, va_list);
+.fi
+
+.SH PARAMETERS
+.TP
+fid
+An open IxpCFid to which to write the result.
+.TP
+fmt
+The string with which to format the data.
+.TP
+args
+A va_list holding the arguments to the format
+string.
+.TP
+.RB ...
+The arguments to the format string.
+
+.SH DESCRIPTION
+.P
+These functions act like the standard formatted IO
+functions. They write the result of the formatting to the
+file pointed to by C<fid>.
+
+.P
+\fBixp_vsmprint(3)\fR may be set to a function which will
+format its arguments and return a nul\-terminated string
+allocated by malloc(3). The default formats its arguments as
+printf(3).
+
+.SH RETURN VALUE
+.P
+These functions return the number of bytes written.
+There is currently no way to detect failure.
+
+.SH SEE ALSO
+.P
+ixp_mount(3), ixp_open(3), printf(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_print.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_printfcall.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_printfcall.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,28 @@
+.TH "IXP_PRINTFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_printfcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void (*ixp_printfcall)(IxpFcall*);
+.fi
+
+.SH DESCRIPTION
+.P
+When set to a non\-null value, ixp_printfcall is called once for
+every incoming and outgoing Fcall. It is intended to simplify the
+writing of debugging code for clients, but may be used for any
+arbitrary purpose.
+
+.SH SEE ALSO
+.P
+ixp_respond(3), ixp_serve9conn(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_printfcall.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pstring.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pstring.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,38 @@
+.TH "IXP_PSTRING" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pstring
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pstring(IxpMsg *msg, char **s);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks a UTF\-8 encoded string. The packed
+representation of the string consists of a 16\-bit unsigned
+integer followed by the contents of the string. The unpacked
+representation is a nul\-terminated character array.
+
+.P
+If \fImsg\fR\->mode is MsgPack, the string pointed to by \fIs\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the address pointed to by \fIs\fR is loaded with a
+malloc(3) allocated, nul\-terminated representation of the
+string packed at \fImsg\fR\->pos. In either case, \fImsg\fR\->pos is
+advanced by the number of bytes read or written. If the
+action would advance \fImsg\fR\->pos beyond \fImsg\fR\->end,
+\fImsg\fR\->pos is still advanced but no other action is taken.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pstrings(3), ixp_pdata(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pstring.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pstrings.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pstrings.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,42 @@
+.TH "IXP_PSTRINGS" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pstrings
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings\fI[]\fR, uint max);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks an array of UTF\-8 encoded strings. The packed
+representation consists of a 16\-bit element count followed by
+an array of strings as packed by \fBixp_pstring(3)\fR. The unpacked
+representation is an array of nul\-terminated character arrays.
+
+.P
+If \fImsg\fR\->mode is MsgPack, \fI*num\fR strings in the array
+pointed to by \fIstrings\fR are packed into the buffer at
+\fImsg\fR\->pos. If \fImsg\fR\->mode is MsgUnpack, \fI*num\fR is loaded
+with the number of strings unpacked, the array at
+\fI*strings\fR is loaded with pointers to the unpacked strings,
+and \fI(*strings)\fI[0]\fR\fR must be freed by the user. In either
+case, \fImsg\fR\->pos is advanced by the number of bytes read or
+written. If the action would advance \fImsg\fR\->pos beyond
+\fImsg\fR\->end, \fImsg\fR\->pos is still advanced, but no other
+action is taken. If \fI*num\fR is greater than \fImax\fR,
+\fImsg\fR\->pos is set beyond \fImsg\fR\->end and no other action is
+taken.
+
+.SH SEE ALSO
+.P
+\fIIxpMsg\fR, \fIixp_pstring\fR, \fIixp_pdata\fR
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pstrings.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_pu8.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_pu8.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,41 @@
+.TH "IXP_PU8" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pu8, ixp_pu16, ixp_pu32, ixp_pu64
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pu8(IxpMsg *msg, uchar *val);
+
+ void ixp_pu16(IxpMsg *msg, uint16_t *val);
+
+ void ixp_pu32(IxpMsg *msg, uint32_t *val);
+
+ void ixp_pu64(IxpMsg *msg, uint64_t *val);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions pack or unpack an unsigned integer of the
+specified size.
+
+.P
+If \fImsg\fR\->mode is MsgPack, the value pointed to by \fIval\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the packed value at \fImsg\fR\->pos is loaded into the
+location pointed to by \fIval\fR. In both cases, \fImsg\fR\->pos is
+advanced by the number of bytes read or written. If the call
+would advance \fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is
+advanced, but nothing is modified.
+
+.SH SEE ALSO
+.P
+IxpMsg(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pu8.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_read.3
--- a/man/ixp_read.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_read.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,9 +6,11 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   long ixp_read(IxpCFid *fid, void *buf, long count);
   
- long ixp_pread(IxpCFid *fid, void *buf, long count, vlong offset);
+ long ixp_pread(IxpCFid *fid, void *buf, long count, int64_t offset);
 .fi
 
 .SH PARAMETERS
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_remove.3
--- a/man/ixp_remove.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_remove.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   int ixp_remove(IxpClient *c, const char *path);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_respond.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_respond.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,30 @@
+.TH "IXP_RESPOND" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_respond
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_respond(Ixp9Req *req, const char *error);
+.fi
+
+.SH DESCRIPTION
+.P
+Sends a response to the given request. The response is
+constructed from the \fIofcall\fR member of the \fIreq\fR parameter, or
+from the \fIerror\fR parameter if it is non\-null. In the latter
+case, the response is of type RError, while in any other case it
+is of the same type as \fIreq\fR\->\fIofcall\fR, which must match the
+request type in \fIreq\fR\->\fIifcall\fR.
+
+.SH SEE ALSO
+.P
+Ixp9Req(3), ixp_printfcall(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_respond.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_sendmsg.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_sendmsg.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,41 @@
+.TH "IXP_SENDMSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_sendmsg, ixp_recvmsg
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ uint ixp_sendmsg(int fd, IxpMsg *msg);
+
+ uint ixp_recvmsg(int fd, IxpMsg *msg);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions read and write messages to and from the given
+file descriptors.
+
+.P
+ixp_sendmsg writes the data at \fImsg\fR\->pos upto \fImsg\fR\->end.
+If the call returns non\-zero, all data is assured to have
+been written.
+
+.P
+ixp_recvmsg first reads a 32 bit, little\-endian length from
+\fIfd\fR and then reads a message of that length (including the
+4 byte size specifier) into the buffer at \fImsg\fR\->data, so
+long as the size is less than \fImsg\fR\->size.
+
+.SH RETURN VALUE
+.P
+These functions return the number of bytes read or
+written, or 0 on error. Errors are stored in
+\fBixp_errbuf(3)\fR.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_sendmsg.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_serverloop.3
--- a/man/ixp_serverloop.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_serverloop.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   int ixp_serverloop(IxpServer *srv);
   
   typedef struct IxpServer IxpServer;
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_settimer.3
--- a/man/ixp_settimer.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_settimer.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   long ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void *), void *aux);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_smprint.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_smprint.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,22 @@
+.TH "IXP_SMPRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_smprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ char *ixp_smprint(const char *fmt, ...);
+.fi
+
+.SH DESCRIPTION
+.P
+This function formats its arguments as \fBprintf(3)\fR and returns
+a \fBmalloc(3)\fR allocated string containing the result.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_smprint.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_clonefiles.3
--- a/man/ixp_srv_clonefiles.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_srv_clonefiles.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp_srvutil.h>
+
   IxpFileId *ixp_srv_clonefiles(IxpFileId *fileid);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_data2cstring.3
--- a/man/ixp_srv_data2cstring.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_srv_data2cstring.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp_srvutil.h>
+
   void ixp_srv_data2cstring(Ixp9Req *req);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_freefile.3
--- a/man/ixp_srv_freefile.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_srv_freefile.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp_srvutil.h>
+
   void ixp_srv_freefile(IxpFileId *fileid);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_getfile.3
--- a/man/ixp_srv_getfile.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_srv_getfile.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp_srvutil.h>
+
   IxpFileId *ixp_srv_getfile(void);
   
   typedef struct IxpFileId IxpFileId;
@@ -16,7 +18,7 @@
           uint id;
           uint index;
           IxpDirtab tab;
- ushort nref;
+ uint nref;
           uchar volatil;
   }
 .fi
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_readbuf.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_srv_readbuf.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,40 @@
+.TH "IXP_SRV_READBUF" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_readbuf, ixp_srv_writebuf
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len);
+
+ void ixp_srv_writebuf(Ixp9Req *req, char **buf, uint *len, uint max);
+.fi
+
+.SH DESCRIPTION
+.P
+Utility functions for handling TRead and TWrite requests for
+files backed by in\-memory buffers. For both functions, \fIbuf\fR
+points to a buffer and \fIlen\fR specifies the length of the
+buffer. In the case of ixp_srv_writebuf, these values add a
+level of pointer indirection, and updates the values if they
+change.
+
+.P
+If \fImax\fR has a value other than 0, ixp_srv_writebuf will
+truncate any writes to that point in the buffer. Otherwise,
+\fI*buf\fR is assumed to be malloc(3) allocated, and is
+reallocated to fit the new data as necessary. The buffer is
+is always left nul\-terminated.
+
+.SH BUGS
+.P
+ixp_srv_writebuf always truncates its buffer to the end
+of the most recent write.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_readbuf.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_walkandclone.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_srv_walkandclone.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,58 @@
+.TH "IXP_SRV_WALKANDCLONE" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_walkandclone, ixp_srv_readdir, ixp_srv_verifyfile, IxpLookupFn
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup);
+
+ void ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(Stat *, IxpFileId *));
+
+ bool ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup);
+
+ typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*);
+.fi
+
+.SH DESCRIPTION
+.P
+These convenience functions simplify the writing of basic and
+static file servers. They use a generic file lookup function
+to simplify the process of walking, cloning, and returning
+directory listings. Given the \fBIxpFileId(3)\fR of a directory and a
+filename name should return a new IxpFileId (allocated via
+\fBixp_srv_getfile(3)\fR) for the matching directory entry, or null
+if there is no match. If the passed name is null, \fIlookup\fR
+should return a linked list of IxpFileIds, one for each child
+directory entry.
+
+.P
+ixp_srv_walkandclone handles the moderately complex process
+of walking from a directory entry and cloning fids, and calls
+\fBixp_respond(3)\fR. It should be called in response to a TWalk
+request.
+
+.P
+ixp_srv_readdir should be called to handle read requests on
+directories. It prepares a stat for each child of the
+directory, taking into account the requested offset, and
+calls \fBixp_respond(3)\fR. The \fIdostat\fR parameter must be a
+function which fills the passed \fBIxpStat(3)\fR pointer based on
+the contents of the passed IxpFileId.
+
+.P
+ixp_srv_verifyfile returns whether a file still exists in the
+filesystem, and should be used by filesystems that invalidate
+files once they have been deleted.
+
+.SH SEE ALSO
+.P
+IxpFileId(3), ixp_getfile(3), ixp_freefile(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_walkandclone.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_srv_writectl.3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/man/ixp_srv_writectl.3 Wed Jun 16 15:48:34 2010 -0400
@@ -0,0 +1,28 @@
+.TH "IXP_SRV_WRITECTL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_writectl
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ char *ixp_srv_writectl(Ixp9Req *req, char *(*fn)(void *, IxpMsg *));
+.fi
+
+.SH DESCRIPTION
+.P
+This utility function is meant to simplify the writing of
+pseudo files to which single\-lined commands are written.
+In order to use this function, the \fIaux\fR member of
+\fIreq\fR\->fid must be nul or an \fBIxpFileId(3)\fR. Each line of the
+written data is stripped of its trailing newline,
+nul\-terminated, and stored in an \fBIxpMsg(3)\fR. For each line
+thus prepared, \fIfn\fR is called with the IxpMsg pointer and
+the the \fIp\fR member of the IxpFileId.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_writectl.man3
+
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_stat.3
--- a/man/ixp_stat.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_stat.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,19 +6,21 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   Stat *ixp_stat(IxpClient *c, const char *path);
   
   Stat *ixp_fstat(IxpCFid *fid);
   
   typedef struct IxpStat IxpStat;
   struct IxpStat {
- ushort type;
- ulong dev;
- IxpQid qid;
- ulong mode;
- ulong atime;
- ulong mtime;
- uvlong length;
+ uint16_t type;
+ uint32_t dev;
+ IxpQid qid;
+ uint32_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
           char* name;
           char* uid;
           char* gid;
@@ -27,9 +29,9 @@
   
   typedef struct IxpQid IxpQid;
   struct IxpQid {
- uchar type;
- ulong version;
- uvlong path;
+ uint8_t type;
+ uint32_t version;
+ uint64_t path;
           /* Private members */
           ...
   }
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_unmount.3
--- a/man/ixp_unmount.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_unmount.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   void ixp_unmount(IxpClient *client);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_unsettimer.3
--- a/man/ixp_unsettimer.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_unsettimer.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,6 +6,8 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   int ixp_unsettimer(IxpServer *srv, long id);
 .fi
 
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_vprint.3
--- a/man/ixp_vprint.3 Tue Jun 15 14:26:31 2010 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-.TH "IXP_VPRINT" 3 "2010 Jun" "libixp Manual"
-
-.SH NAME
-.P
-ixp_vprint, ixp_print, ixp_vsmprint
-
-.SH SYNOPSIS
-.nf
- ixp_vprint
-
- int ixp_print(IxpCFid *fid, const char *fmt, ...);
-
- ixp_vsmprint
-.fi
-
-.SH PARAMETERS
-.TP
-fid
-An open IxpCFid to which to write the result.
-.TP
-fmt
-The string with which to format the data.
-.TP
-args
-A va_list holding the arguments to the format
-string.
-.TP
-.RB ...
-The arguments to the format string.
-
-.SH DESCRIPTION
-.P
-These functions act like the standard formatted IO
-functions. They write the result of the formatting to the
-file pointed to by C<fid>.
-
-.P
-\fBixp_vsmprint(3)\fR may be set to a function which will
-format its arguments and return a nul\-terminated string
-allocated by malloc(3). The default formats its arguments as
-printf(3). The function must format '%s' as a nul\-terminated
-string and may not consume any arguments not specified by a
-manner chosen by the user.
-
-.SH RETURN VALUE
-.P
-These functions return the number of bytes written.
-There is currently no way to detect failure.
-
-.SH SEE ALSO
-.P
-ixp_mount(3), ixp_open(3), printf(3)
-
-
-.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
-.\" cmdline: txt2tags -o- ixp_vprint.man3
-
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/ixp_write.3
--- a/man/ixp_write.3 Tue Jun 15 14:26:31 2010 -0400
+++ b/man/ixp_write.3 Wed Jun 16 15:48:34 2010 -0400
@@ -6,9 +6,11 @@
 
 .SH SYNOPSIS
 .nf
+ #include <ixp.h>
+
   long ixp_write(IxpCFid *fid, const void *buf, long count);
   
- long ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset);
+ long ixp_pwrite(IxpCFid *fid, const void *buf, long count, int64_t offset);
 .fi
 
 .SH PARAMETERS
diff -r ffbf3797fde8 -r dbda92c4b3b4 man/targets.mk
--- a/man/targets.mk Tue Jun 15 14:26:31 2010 -0400
+++ b/man/targets.mk Wed Jun 16 15:48:34 2010 -0400
@@ -1,4 +1,7 @@
 MANPAGES = \
+ 'IxpFcall.3 IxpFType.3 IxpFAttach.3 IxpFError.3 IxpFHdr.3 IxpFIO.3 IxpFRAuth.3 IxpFROpen.3 IxpFRStat.3 IxpFRWalk.3 IxpFTCreate.3 IxpFTFlush.3 IxpFTWStat.3 IxpFTWalk.3 IxpFVersion.3' \
+ 'IxpFid.3' \
+ 'IxpThread.3 IxpMutex.3 IxpRWLock.3 IxpRendez.3 ixp_thread.3' \
         'ixp_unmount.3' \
         'ixp_mount.3 ixp_mountfd.3 ixp_nsmount.3 IxpClient.3' \
         'ixp_remove.3' \
@@ -7,8 +10,19 @@
         'ixp_stat.3 ixp_fstat.3 IxpStat.3 IxpQid.3 IxpQType.3 IxpDMode.3' \
         'ixp_read.3 ixp_pread.3' \
         'ixp_write.3 ixp_pwrite.3' \
- 'ixp_vprint.3 ixp_print.3 ixp_vsmprint.3' \
- 'ixp_errbuf.3 ixp_errstr.3 ixp_rerrstr.3 ixp_werrstr.3' \
+ 'ixp_print.3 ixp_vprint.3 ixp_vsmprint.3' \
+ 'ixp_pu8.3 ixp_pu16.3 ixp_pu32.3 ixp_pu64.3' \
+ 'ixp_pstring.3' \
+ 'ixp_pstrings.3' \
+ 'ixp_pdata.3' \
+ 'ixp_pfcall.3 ixp_pqid.3 ixp_pqids.3 ixp_pstat.3 ixp_sizeof_stat.3' \
+ 'ixp_errbuf.3 ixp_errstr.3 ixp_rerrstr.3 ixp_werrstr.3 ixp_vsnprint.3' \
+ 'IxpMsg.3 IxpMsgMode.3 ixp_message.3' \
+ 'ixp_freestat.3 ixp_freefcall.3' \
+ 'ixp_fcall2msg.3 ixp_msg2fcall.3' \
+ 'ixp_printfcall.3' \
+ 'ixp_respond.3' \
+ 'Ixp9Srv.3 Ixp9Req.3 ixp_serve9conn.3' \
         'ixp_listen.3 IxpConn.3' \
         'ixp_hangup.3 ixp_server_close.3' \
         'ixp_serverloop.3 IxpServer.3' \
@@ -16,9 +30,16 @@
         'ixp_srv_getfile.3 IxpFileId.3' \
         'ixp_srv_freefile.3' \
         'ixp_srv_clonefiles.3' \
+ 'ixp_srv_readbuf.3 ixp_srv_writebuf.3' \
         'ixp_srv_data2cstring.3' \
+ 'ixp_srv_writectl.3' \
+ 'ixp_pending_write.3 ixp_pending_pushfid.3 ixp_pending_clunk.3 ixp_pending_flush.3 ixp_pending_respond.3 IxpPending.3' \
+ 'ixp_srv_walkandclone.3 ixp_srv_readdir.3 ixp_srv_verifyfile.3 IxpLookupFn.3' \
         'ixp_msec.3' \
         'ixp_settimer.3' \
         'ixp_unsettimer.3' \
- 'ixp_nexttimer.3' \
- 'ixp_namespace.3'
+ 'ixp_sendmsg.3 ixp_recvmsg.3' \
+ 'ixp_smprint.3' \
+ 'ixp_namespace.3' \
+ 'ixp_eprint.3' \
+ 'ixp_emalloc.3 ixp_emallocz.3 ixp_erealloc.3 ixp_estrdup.3'
diff -r ffbf3797fde8 -r dbda92c4b3b4 util/grepdoc
--- a/util/grepdoc Tue Jun 15 14:26:31 2010 -0400
+++ b/util/grepdoc Wed Jun 16 15:48:34 2010 -0400
@@ -20,10 +20,11 @@
 my @h = grep /\.h$/, @ARGV;
 
 my %protos;
+my %headers;
 open(my $stderr, '>&', \*STDERR);
 open STDERR, '>', '/dev/null';
 
-open my $fd, '-|', 'cproto', '-I./include', @c;
+open my $fd, '-|', 'cproto', '-DCPROTO', '-I./include', @c, '/dev/null';
 for(<$fd>) {
     chomp;
     s/\b_ixp//g;
@@ -33,20 +34,41 @@
 }
 open STDERR, '>&', $stderr;
 
-_AT_ARGV = @h;
-$_ = join "", map detab, <>;
+my @txt;
+@ARGV = (@h, '/dev/null');
+for my $f(@h) {
+ open my $fd, '<', $f;
+ $_ = join "", map detab, <$fd>;
+ push @txt, $_;
 
-while(m/^typedef\b.*?(\w+);/gm) {
- push @{$protos{$1}}, $& unless $& =~ m{\Q/* Deprecated */};
-}
-while(m/^(?:enum|struct)\s+(\w+).*?^\}/gsm) {
- my $proto = \@{$protos{$1}};
- push @$proto, subst {"$1$2$1..."} qr[(^ +)(\Q/* Private members */\E\n).*(?=\n\})]sm, $&
- unless $& =~ m{\Q/* Deprecated */};
+ $f =~ s|^(\./)?include/||;
+
+ my $junk = qr/(?:\[.*\]|\)\(.*\))?/;
+ while(m/^extern\s+(.*\b(\w+)$junk;)$/gm) {
+ $headers{$2} = $f;
+ push @{$protos{$2}}, $1;
+ }
+ while(m/^(?!extern)[a-z][^(]+\b(\w+)\(/gmi) {
+ my $id = $1;
+ $headers{$id} = $f unless $& =~ m{^\s*(?:#|//|/\*|\*)};
+ }
+ while(m/^typedef\b.*?\b(\w+)$junk;/gm) {
+ $headers{$1} = $f;
+ push @{$protos{$1}}, $& unless $& =~ m{\Q/* Deprecated */};
+ }
+ while(m/^(?:enum|struct|union)\s+(\w+).*?^\}/gsm) {
+ $headers{$1} = $f;
+ my $proto = \@{$protos{$1}};
+ push @$proto, subst {"$1$2$1..."} qr[(^ +)(\Q/* Private members */\E\n).*(?=\n\})]sm, $&
+ unless $& =~ m{\Q/* Deprecated */};
+ }
 }
 
-_AT_ARGV = @c;
-$_ .= join "", map detab, <>;
+# print Data::Dumper->Dump([\%protos], ['%protos']);
+# print Data::Dumper->Dump([\%headers], ['%headers']);
+
+@ARGV = (@c, '/dev/null');
+$_ = join "", @txt, map detab, <>;
 
 sub section($$) {
     my ($sect, $text) = @_;
@@ -79,6 +101,10 @@
         next;
     }
 
+ my %hdrs = map {($headers{$_}, "")} @names;
+ my $includes = join "", map {"#include <$_>\n"} sort keys %hdrs;
+ $header = "$includes\n$header" if $includes;
+
     sub despace {
         my ($space) = m/^(\s*)/;
         s/^$space//gm;
diff -r ffbf3797fde8 -r dbda92c4b3b4 util/link
--- a/util/link Tue Jun 15 14:26:31 2010 -0400
+++ b/util/link Wed Jun 16 15:48:34 2010 -0400
@@ -27,7 +27,7 @@
 [ -n "$noisycc" ] && echo $LD -o $outfile $ofiles $LDFLAGS $args
 $LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1
 status=$?
-[ $status -eq 0 ] || $LD -o $outfile $ofiles $LDFLAGS $args >&2
+[ $status -eq 0 ] || echo $LD -o $outfile $ofiles $LDFLAGS $args >&2
 
 sed 's/.*: In function `[^:]*: *//' $xtmp | egrep . |
 egrep -v 'is almost always misused|is dangerous, better use|in statically linked applications requires at runtime'
Received on Wed Jun 16 2010 - 19:48:59 UTC

This archive was generated by hypermail 2.2.0 : Wed Jun 16 2010 - 20:00:08 UTC