Skip to content
Browse files

Generating documentation now

  • Loading branch information...
1 parent 38873e1 commit 8fa6eb3bee5e1a5bfcb8e661cfaf1d2a7b010e7e @hintjens hintjens committed Mar 24, 2011
Showing with 1,304 additions and 219 deletions.
  1. +1 −0 .gitignore
  2. +11 −0 NEWS
  3. +1 −1 configure.in
  4. +1 −0 doc/Makefile.am
  5. +20 −0 doc/_template.wd
  6. +99 −0 doc/mkman
  7. +68 −0 doc/mksite
  8. +43 −0 doc/wdput
  9. +228 −0 doc/xml2wd.pl
  10. +5 −3 doc/zapi.txt
  11. +6 −1 doc/zclock.txt
  12. +7 −0 doc/zctx.txt
  13. +55 −0 doc/zframe.txt
  14. +100 −6 doc/zhash.txt
  15. +82 −3 doc/zlist.txt
  16. +35 −0 doc/zloop.txt
  17. +114 −0 doc/zmsg.txt
  18. +33 −0 doc/zstr.txt
  19. +6 −2 include/zclock.h
  20. +9 −0 include/zctx.h
  21. +17 −0 include/zframe.h
  22. +27 −6 include/zhash.h
  23. +26 −3 include/zlist.h
  24. +17 −0 include/zloop.h
  25. +37 −0 include/zmsg.h
  26. +9 −0 include/zstr.h
  27. +14 −0 mkdoc
  28. +5 −5 src/zclock.c
  29. +103 −100 src/zctx.c
  30. +12 −2 src/zframe.c
  31. +57 −56 src/zhash.c
  32. +29 −28 src/zlist.c
  33. +9 −1 src/zloop.c
  34. +8 −1 src/zmsg.c
  35. +10 −1 src/zstr.c
View
1 .gitignore
@@ -23,6 +23,7 @@ src/mtrace.txt
src/outbin
src/zapi_selftest
doc/*.7
+doc/*.xml
src/.libs/
src/libzapi.la
src/platform.h
View
11 NEWS
@@ -1,3 +1,14 @@
+zapi version 1.2.0 (beta), released on 2011/03/24
+=================================================
+
+Changes
+-------
+
+* Added zclock class for portable millisecond timers and delays.
+
+* Expanded documentation significantly.
+
+
zapi version 1.1.0 (beta), released on 2011/03/23
=================================================
View
2 configure.in
@@ -6,7 +6,7 @@ AC_PREREQ(2.61)
# The version in git should reflect the *next* version planned.
# Version must be MAJOR.MINOR.PATCH otherwise things will break.
#
-AC_INIT([zapi],[1.1.1],[zeromq-dev@lists.zeromq.org])
+AC_INIT([zapi],[1.2.0],[zeromq-dev@lists.zeromq.org])
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_MACRO_DIR(config)
View
1 doc/Makefile.am
@@ -29,6 +29,7 @@ if BUILD_DOC
SUFFIXES=.txt .xml .1 .3 .7
.txt.xml:
+ ./mkman $<
asciidoc -d manpage -b docbook -f asciidoc.conf \
-azapi_version=@PACKAGE_VERSION@ $<
.xml.1:
View
20 doc/_template.wd
@@ -0,0 +1,20 @@
+[!-- live template used for API pages --]
+
+[[module CSS]]
+.foldedtoc #toc #toc-action-bar {
+ display: none
+}
+.foldedtoc #toc .title{
+ display: none;
+ border: 0px solid black;
+}
+.foldedtoc #toc {
+ border: 0px solid black;
+ margin: 0 0 0 -0,9em;
+}
+.foldedtoc .collapsible-block-link {
+ text-decoration:none
+}
+[[/module]]
+[[include include:print-css]]
+%%content%%
View
99 doc/mkman
@@ -0,0 +1,99 @@
+#! /usr/bin/perl
+#
+# mkman - Generates man pages from C source and header files.
+#
+# Syntax: 'mkman classname', in doc subdirectory.
+#
+# Copyright (c) 1996-2011 iMatix Corporation
+#
+# This is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# This software is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABIL-
+# ITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+# License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+use File::Basename;
+
+$class = $ARGV [0];
+$class = $1 if $class =~ /(\w+)\.\w+/;
+
+# Look for class title in 2nd line of source
+# If there's no class file, leave hand-written man page alone
+exit unless open (SOURCE, "../src/$class.c");
+$_ = <SOURCE>;
+$_ = <SOURCE>;
+$title = "no title found";
+$title = $1 if (/ \w+ - (.*)/);
+close (SOURCE);
+
+# Open output file
+die "Can't create $class.txt: $!"
+ unless open (OUTPUT, ">$class.txt");
+
+printf "Generating $class.txt...\n";
+
+
+$template = <<"END";
+$class(7)
+=========
+
+NAME
+----
+$class - $title
+
+SYNOPSIS
+--------
+----
+pull ../include/$class.h\@interface
+----
+
+DESCRIPTION
+-----------
+
+pull ../src/$class.c\@header,left
+
+pull ../src/$class.c\@discuss,left
+
+EXAMPLE
+-------
+.From $class\_test method
+----
+pull ../src/$class.c\@selftest
+----
+
+SEE ALSO
+--------
+linkzapi:zapi[7]
+END
+
+# Now process template
+for (split /^/, $template) {
+ if (/^pull (.*)(@[a-zA-Z0-9]+)(,(.*)\s*)?/) {
+ $source = $1;
+ $tag = $2;
+ $opts = $4;
+ die "Can't read $source: $!"
+ unless open (SOURCE, $source);
+ while (<SOURCE>) {
+ if (/$tag/) {
+ while (<SOURCE>) {
+ last if /@[a-zA-Z0-9]+/;
+ $_ = " $_" if ($opts eq "code");
+ s/^ // if ($opts eq "left");
+ print OUTPUT $_;
+ }
+ }
+ }
+ close (SOURCE);
+ }
+ else {
+ print OUTPUT $_;
+ }
+}
View
68 doc/mksite
@@ -0,0 +1,68 @@
+#! /bin/bash
+#
+# mksite - Upload zapi manual to zapi.zeromq.org/manual:
+#
+# Author: Pieter Hintjens <ph@imatix.com>
+# License: public domain
+#
+# syntax: mksite
+#
+
+# Export so child scripts can access these
+export UPLOAD=1 # If 0, don't actually upload
+export CATEGORY=manual # Category to receive man pages
+export WEBSITE=zapi # Wikidot website prefix
+
+# This function uploads a file to wikidot
+# Error in upload will cause the script to exit with non-zero status
+
+function do_upload {
+ ./wdput $WEBSITE $CATEGORY $1 $2
+ if [ $? != 0 ]; then
+ echo "Error uploading file to wikidot"
+ exit 1
+ fi
+}
+
+echo "Building docs..."
+make --quiet
+rm -f *.xml # Makefile does not detect version differences for XML
+for FILE in *.txt; do
+ ./mkman $FILE
+ make `basename $FILE .txt`.xml
+done
+
+echo "Generating XML pages for manual..."
+FILES=
+for FILE in z*.txt; do
+ BASE=`basename $FILE .txt`
+ make --quiet $BASE.xml;
+ FILES="$FILES $BASE"
+done
+
+echo "Generating Wikidot pages..."
+for FILE in $FILES; do
+ perl ./xml2wd.pl $FILE.xml > $FILE.wd
+done
+
+if [ $UPLOAD -eq 1 ]; then
+ echo "Uploading to $CATEGORY..."
+
+ # Send table of contents as category:_start
+ do_upload "_start" "zapi Documentation"
+
+ # Send template as category:_template
+ do_upload "_template" "Category template - generated"
+
+ # Now send individual man pages
+ for FILE in $FILES; do
+ TITLE=`egrep --after-context 1 PAGE_TITLE $FILE.wd | egrep $FILE`
+ do_upload $FILE $TITLE
+ done
+fi
+
+# Cleanup generated files
+rm _start.wd
+for FILE in $FILES; do
+ rm $FILE.wd
+done
View
43 doc/wdput
@@ -0,0 +1,43 @@
+#! /usr/bin/python
+#
+# wdput - Send one Wikidot page to api.zero.mq
+# Part of the ztools/apisite toolkit. Install into any directory on PATH.
+#
+# Author: Pieter Hintjens <ph@imatix.com>
+# License: public domain
+#
+# syntax: wdput sitename category page title
+#
+# Wikidot text must be in page + '.wd'
+#
+# Supply your Wikidot user name as an environment variable APISITE_USER
+# Supply your Wikidot API key as an environment variable APISITE_KEY
+
+# Get script arguments
+import sys
+sitename = sys.argv [1]
+category = sys.argv [2]
+name = sys.argv [3]
+title = sys.argv [4]
+
+# Get authentication credentials
+import os
+user = os.environ ['APISITE_USER']
+key = os.environ ['APISITE_KEY']
+
+# Create XML/RPC connection to Wikidot
+from xmlrpclib import ServerProxy
+server = ServerProxy ('https://' + user + ':' + key + '@www.wikidot.com/xml-rpc-api.php')
+
+# Send page content (create or update)
+file = open (name + ".wd", "r")
+content = ""
+for line in file:
+ content = content + line
+
+print " - " + category + ":" + name
+server.pages.save_one ({
+ "site": sitename,
+ "page": category + ":" + name,
+ "title": title,
+ "content": content})
View
228 doc/xml2wd.pl
@@ -0,0 +1,228 @@
+#! /bin/perl
+#
+# xml2wd.pl - Convert docbook XML to Wikidot syntax
+# Part of the ztools/apisite toolkit. Modified for zapi.
+#
+# Author: Pieter Hintjens <ph@imatix.com>
+# License: public domain
+#
+# This is a very hacky tool that turns a docbook XML file into Wikidot
+# content ready for upload via the Wikidot API. It would be better to
+# do this conversion using an XML stylesheet but I'm too lazy for that.
+#
+# syntax: perl xml2wd.pl < inputfile > outputfile
+#
+# Supply the Wikidot page category as an environment variable CATEGORY.
+
+$category = $ENV{'CATEGORY'} || "page";
+
+while (<>) {
+ $output = "";
+ s/\[/@@[@@/g;
+ s/\]/@@]@@/g;
+
+ $title = $1 if (/<refentrytitle>(.*)<\/refentrytitle>/);
+ $volume = $1 if (/<manvolnum>(.*)<\/manvolnum>/);
+ $source = $1 if (/<refmiscinfo class="source">(.*)<\/refmiscinfo>/);
+ $version = $1 if (/<refmiscinfo class="version">(.*)<\/refmiscinfo>/);
+ $manual = $1 if (/<refmiscinfo class="manual">(.*)<\/refmiscinfo>/);
+ $name = $1 if (/<refname>(.*)<\/refname>/);
+ $purpose = $1 if (/<refpurpose>(.*)<\/refpurpose>/);
+ if (/<\/refmeta>/) {
+ $output = <<"END";
+[!-- PAGE_TITLE
+$title($volume)
+--]
+[[div style="width:30%; float:left;"]]
+$title($volume)
+[[/div]]
+[[div style="width:40%; float:left;; text-align:center"]]
+[/$category:_start Back to Contents]
+[[/div]]
+[[div style="width:30%; float:left; text-align:right"]]
+$manual - $source/$version
+[[/div]]
+END
+ if ($title eq "zapi") {
+ open (TOC, ">_start.wd");
+ print TOC "[[image http://zapi.zeromq.org/local--files/admin:css/logo.gif]]\n\n";
+ print TOC "++ zapi/$version reference\n\n";
+ close (TOC);
+ }
+ }
+ elsif (/<\/refnamediv>/) {
+ $output = <<"END";
+[[div class="foldedtoc" style="margin:10px"]]
+[[collapsible show="+ Table of Contents" hide="- Table of Contents"]]
+[[toc]]
+[[/collapsible]]
+[[/div]]
+
+++ Name
+
+$name - $purpose
+END
+ open (TOC, ">>_start.wd");
+ print TOC "* [/$category:$name $name] - $purpose\n";
+ close (TOC);
+ }
+ if (/<refsynopsisdiv id="_synopsis">/) {
+ $_ = load_tag ("refsynopsisdiv");
+ $output = "\n++ Synopsis\n\n[[div class=\"synopsis\"]]\n$_\n[[/div]]\n";
+ }
+ elsif (/<refsect1/) {
+ $header = "++";
+ }
+ elsif (/<refsect2/) {
+ $header = "+++";
+ }
+ elsif (/<refsect3/) {
+ $header = "++++";
+ }
+ elsif (/<variablelist>/) {
+ $variable_list = 1;
+ }
+ elsif (/<\/variablelist>/) {
+ $variable_list = 0;
+ }
+
+ if (/<table.*<title>(.*)<\/title>/) {
+ $output = "\n||||~ $1 ||\n";
+ }
+ elsif (/<entry>/) {
+ $_ = load_tag ("entry");
+ $output = "|| $_";
+ }
+ elsif (/<\/row>/) {
+ $output = "||\n";
+ }
+ elsif (/<formalpara>/) {
+ $_ = load_tag ("formalpara");
+ if (/<title>(.*)<\/title><para>\s*(.*)<\/para>/s) {
+ $output = "\n**". title_case ($1) ."**\n\n$2\n";
+ }
+ }
+ elsif (/<title>(.*)<\/title>/) {
+ $output = "\n$header ". title_case ($1) ."\n";
+ }
+ elsif (/<note>/) {
+ $_ = load_tag ("note");
+ $output = "\n[[note]]\n$_\n[[/note]]\n";
+ }
+ elsif (/<simpara>/) {
+ $_ = load_tag ("simpara");
+ $output = "\n$_\n";
+ }
+ elsif (/<literallayout>/) {
+ $_ = load_tag ("literallayout");
+ $output = "\n> {{$_}}\n";
+ }
+ elsif (/<literallayout class="monospaced">/) {
+ $_ = $';
+ chop while /\s$/;
+ $line = $_;
+ while (<>) {
+ chop while /\s$/;
+ $line .= "\n$_";
+ if ($line =~ /(.*)<\/literallayout>/s) {
+ $_ = $1;
+ last;
+ }
+ }
+ $output = "\n[[code]]\n$_\n[[/code]]\n";
+ }
+
+ if (/<term>/) {
+ $term = load_tag ("term");
+ }
+ if (/<listitem>/) {
+ $_ = load_tag ("listitem");
+ #print "---- $_\n";
+ # Sometimes tables end up inside list items
+ s/<informal.*?<tbody valign="top">/\n/s;
+ s/\s*<\/tbody><\/tgroup><\/informaltable>//s;
+ while (/\s*<entry>\s*(.*?)\s*<\/entry>\s*/s) {
+ $_ = $` . "$1 ||" . $';
+ }
+ while (/\s*<row>\s*(.*?)\s*<\/row>/) {
+ $_ = $` . "\n|| $1\n" . $';
+ }
+ if ($variable_list) {
+ die "Missing term in $name:$.\n" unless $term;
+ $output = "\n: $term:$_\n";
+ $term = "";
+ }
+ else {
+ $output = "* $_\n";
+ }
+ }
+
+ # General substitutions
+ $output =~ s/\/\//@@\/\/@@/g;
+ $output =~ s/\\\/\\\//\/\//g; # // in code blocks was escaped
+ $output =~ s/http:@@\/\/@@/http:\/\//g;
+
+ $output =~ s/0MQ/ØMQ/g;
+ $output =~ s/<emphasis>([^<]*)<\/emphasis>/\/\/$1\/\//g;
+ $output =~ s/<emphasis role="strong">([^<]*)<\/emphasis>/**$1**/g;
+ $output =~ s/<literal>([^<]*)<\/literal>/{{ $1}}/g;
+ $output =~ s/<manvolnum>([^<]*)<\/manvo>/{{$1}}/g;
+ $output =~ s/<citerefentry>\s*<refentrytitle>([^<]*)<\/refentrytitle><manvolnum>([^<]*)<\/manvolnum>\s*<\/citerefentry>/\[\/$category:$1 $1($2)\]/g;
+ $output =~ s/<ulink url="[^"]*">([^<]*)<\/ulink>/$1/g;
+ $output =~ s/<simpara>([^<]*)<\/simpara>/$1/g;
+ $output =~ s/&lt;/</g;
+ $output =~ s/&gt;/>/g;
+ $output =~ s/&amp;/&/g;
+ $output =~ s/&#8217;/'/g;
+ $output =~ s/&#8230;/.../g;
+
+ print $output if $output;
+}
+
+
+sub load_tag {
+ local ($tag) = @_;
+ if (/<$tag[^>]*>(.*)<\/$tag>/) {
+ return $1;
+ }
+ else {
+ chop while /\s$/;
+ /<$tag[^>]*>/;
+ $line = $';
+ while (<>) {
+ chop while /\s$/;
+ if (/<screen>/) {
+ $_ = "[[code]]\n$'";
+ s/\/\//\\\/\\\//g;
+ $code = 1;
+ }
+ elsif (/<\/screen>/) {
+ $_ = "\n$`\n[[/code]]";
+ s/\/\//\\\/\\\//g;
+ $code = 0;
+ }
+ if ($code) {
+ s/\/\//\\\/\\\//g;
+ $line .= "\n$_";
+ }
+ else {
+ $line .= " " if $line;
+ $line .= $_;
+ }
+ if ($line =~ /(.*)<\/$tag>/s) {
+ return $1;
+ last;
+ }
+ }
+ }
+}
+
+sub title_case {
+ local ($_) = @_;
+ if (!/^ZMQ_/) {
+ tr/[A-Z]/[a-z]/;
+ s/(\w+)/\u\L$1/;
+ s/Zapi_/zapi_/g;
+ }
+ return $_;
+}
View
8 doc/zapi.txt
@@ -9,9 +9,11 @@ zapi - 0MQ C Binding
SYNOPSIS
--------
-*#include <zapi.h>*
+----
+#include <zapi.h>
-*cc* ['flags'] 'files' *-lzmq* *-lzapi* ['libraries']
+cc ['flags'] 'files' -lzmq -lzapi ['libraries']
+----
DESCRIPTION
@@ -36,7 +38,7 @@ The authors of zapi grant you free use of this software under the terms of the G
Contributing
~~~~~~~~~~~~
-To submit an issue use the [issue tracker](http://github.com/zeromq/zapi/issues). All discussion happens on the [zeromq-dev](zeromq-dev@lists.zeromq.org) list or #zeromq IRC channel at irc.freenode.net.
+To submit an issue use the issue tracker at http://github.com/zeromq/zapi/issues. All discussion happens on the zeromq-dev list or #zeromq IRC channel at irc.freenode.net.
The proper way to submit patches is to clone this repository, make your changes, and use git to create a patch or a pull request. See http://www.zeromq.org/docs:contributing. All contributors are listed in AUTHORS.
View
7 doc/zclock.txt
@@ -11,10 +11,12 @@ SYNOPSIS
// Sleep for a number of milliseconds
void
zclock_sleep (int msecs);
+
// Return current system clock as milliseconds
int64_t
zclock_time (void);
-// Selftest
+
+// Self test of this class
int
zclock_test (Bool verbose);
----
@@ -40,6 +42,9 @@ EXAMPLE
-------
.From zclock_test method
----
+ int64_t start = zclock_time ();
+ zclock_sleep (10);
+ assert ((zclock_time () - start) >= 10);
----
SEE ALSO
View
7 doc/zctx.txt
@@ -18,26 +18,33 @@ typedef struct {
// Create new context, returns context object, replaces zmq_init
zctx_t *
zctx_new (void);
+
// Destroy context and all sockets in it, replaces zmq_term
void
zctx_destroy (zctx_t **self_p);
+
// Raise default I/O threads from 1, for crazy heavy applications
void
zctx_set_iothreads (zctx_t *self, int iothreads);
+
// Set msecs to flush sockets when closing them
void
zctx_set_linger (zctx_t *self, int linger);
+
// Create socket within this context, replaces zmq_socket
void *
zctx_socket_new (zctx_t *self, int type);
+
// Destroy socket, replaces zmq_close
void
zctx_socket_destroy (zctx_t *self, void *socket);
+
// Create thread, return PAIR socket to talk to thread. The child thread
// receives a (zthread_t *) object including a zctx, a pipe back to the
// creating thread, and the arg passed in this call.
void *
zctx_thread_new (zctx_t *self, void *(*thread_fn) (void *), void *arg);
+
// Self test of this class
int
zctx_test (Bool verbose);
View
55 doc/zframe.txt
@@ -11,20 +11,35 @@ SYNOPSIS
#define ZFRAME_MORE 1
#define ZFRAME_REUSE 2
+// Create a new frame with optional size, and optional data
zframe_t *
zframe_new (const void *data, size_t size);
+
+// Destroy a frame
void
zframe_destroy (zframe_t **self_p);
+
+// Receive a new frame off the socket
zframe_t *
zframe_recv (void *socket);
+
+// Send a frame to a socket, destroy frame after sending
void
zframe_send (zframe_t **self_p, void *socket, int flags);
+
+// Return number of bytes in frame data
size_t
zframe_size (zframe_t *self);
+
+// Return address of frame data
void *
zframe_data (zframe_t *self);
+
+// Return frame 'more' property
int
zframe_more (zframe_t *self);
+
+// Self test of this class
int
zframe_test (Bool verbose);
----
@@ -45,6 +60,46 @@ EXAMPLE
-------
.From zframe_test method
----
+ zctx_t *ctx = zctx_new ();
+
+ void *output = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_bind (output, "inproc://zframe.test");
+ void *input = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_connect (input, "inproc://zframe.test");
+
+ // Send five different frames, test ZFRAME_MORE
+ int frame_nbr;
+ for (frame_nbr = 0; frame_nbr < 5; frame_nbr++) {
+ zframe_t *frame = zframe_new ("Hello", 5);
+ zframe_send (&frame, output, ZFRAME_MORE);
+ }
+ // Send same frame five times, test ZFRAME_REUSE
+ zframe_t *frame = zframe_new ("Hello", 5);
+ for (frame_nbr = 0; frame_nbr < 5; frame_nbr++) {
+ zframe_send (&frame, output, ZFRAME_MORE + ZFRAME_REUSE);
+ }
+ assert (frame);
+ zframe_destroy (&frame);
+
+ // Send END frame
+ frame = zframe_new ("END", 3);
+ zframe_send (&frame, output, 0);
+
+ // Read and count until we receive END
+ frame_nbr = 0;
+ for (frame_nbr = 0;; frame_nbr++) {
+ zframe_t *frame = zframe_recv (input);
+ if (zframe_size (frame) == 3
+ && memcmp (zframe_data (frame), "END", 3) == 0) {
+ zframe_destroy (&frame);
+ break;
+ }
+ assert (zframe_more (frame));
+ zframe_destroy (&frame);
+ }
+ assert (frame_nbr == 10);
+
+ zctx_destroy (&ctx);
----
SEE ALSO
View
106 doc/zhash.txt
@@ -9,31 +9,47 @@ SYNOPSIS
--------
----
// Callback function for zhash_foreach method
-typedef int (zhash_foreach_fn) (char *key, void *value, void *argument);
+typedef int (zhash_foreach_fn) (char *key, void *item, void *argument);
// Callback function for zhash_freefn method
typedef void (zhash_free_fn) (void *data);
-// Opaque class structure
-typedef struct _zhash zhash_t;
-
+// Create a new, empty hash container
zhash_t *
zhash_new (void);
+
+// Destroy a hash container and all items in it
void
zhash_destroy (zhash_t **self_p);
+
+// Insert an item into the hash container using the specified key
int
- zhash_insert (zhash_t *self, char *key, void *value);
+ zhash_insert (zhash_t *self, char *key, void *item);
+
+// Insert or update the item for the specified key
void
- zhash_update (zhash_t *self, char *key, void *value);
+ zhash_update (zhash_t *self, char *key, void *item);
+
+// Destroy the item at the specified key, if any
void
zhash_delete (zhash_t *self, char *key);
+
+// Return the item at the specified key, or null
void *
zhash_lookup (zhash_t *self, char *key);
+
+// Set a free function for the item at the specified key
void *
zhash_freefn (zhash_t *self, char *key, zhash_free_fn *free_fn);
+
+// Return the number of keys/items in the hash table
size_t
zhash_size (zhash_t *self);
+
+// Iterate over the hash table and apply the function to each item
int
zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument);
+
+// Self test of this class
void
zhash_test (int verbose);
----
@@ -51,6 +67,84 @@ EXAMPLE
-------
.From zhash_test method
----
+ zhash_t *hash = zhash_new ();
+ assert (hash);
+ assert (zhash_size (hash) == 0);
+
+ // Insert some items
+ int rc;
+ rc = zhash_insert (hash, "DEADBEEF", (void *) 0xDEADBEEF);
+ assert (rc == 0);
+ rc = zhash_insert (hash, "ABADCAFE", (void *) 0xABADCAFE);
+ assert (rc == 0);
+ rc = zhash_insert (hash, "C0DEDBAD", (void *) 0xC0DEDBAD);
+ assert (rc == 0);
+ rc = zhash_insert (hash, "DEADF00D", (void *) 0xDEADF00D);
+ assert (rc == 0);
+ assert (zhash_size (hash) == 4);
+
+ // Look for existing items
+ void *item;
+ item = zhash_lookup (hash, "DEADBEEF");
+ assert (item == (void *) 0xDEADBEEF);
+ item = zhash_lookup (hash, "ABADCAFE");
+ assert (item == (void *) 0xABADCAFE);
+ item = zhash_lookup (hash, "C0DEDBAD");
+ assert (item == (void *) 0xC0DEDBAD);
+ item = zhash_lookup (hash, "DEADF00D");
+ assert (item == (void *) 0xDEADF00D);
+
+ // Look for non-existent items
+ item = zhash_lookup (hash, "0xF0000000");
+ assert (item == NULL);
+
+ // Try to insert duplicate items
+ rc = zhash_insert (hash, "DEADBEEF", (void *) 0xF0000000);
+ assert (rc == -1);
+ item = zhash_lookup (hash, "DEADBEEF");
+ assert (item == (void *) 0xDEADBEEF);
+
+ // Delete a item
+ zhash_delete (hash, "DEADBEEF");
+ item = zhash_lookup (hash, "DEADBEEF");
+ assert (item == NULL);
+ assert (zhash_size (hash) == 3);
+
+ // Check that the queue is robust against random usage
+ struct {
+ char name [100];
+ Bool exists;
+ } testset [200];
+ memset (testset, 0, sizeof (testset));
+
+ int
+ testmax = 200,
+ testnbr,
+ iteration;
+
+ srandom ((unsigned) time (NULL));
+ for (iteration = 0; iteration < 25000; iteration++) {
+ testnbr = randof (testmax);
+ if (testset [testnbr].exists) {
+ item = zhash_lookup (hash, testset [testnbr].name);
+ assert (item);
+ zhash_delete (hash, testset [testnbr].name);
+ testset [testnbr].exists = FALSE;
+ }
+ else {
+ sprintf (testset [testnbr].name, "%x-%x", rand (), rand ());
+ if (zhash_insert (hash, testset [testnbr].name, "") == 0)
+ testset [testnbr].exists = TRUE;
+ }
+ }
+ // Test 10K lookups
+ for (iteration = 0; iteration < 10000; iteration++)
+ item = zhash_lookup (hash, "DEADBEEFABADCAFE");
+
+ // Destructor should be safe to call twice
+ zhash_destroy (&hash);
+ zhash_destroy (&hash);
+ assert (hash == NULL);
----
SEE ALSO
View
85 doc/zlist.txt
@@ -8,26 +8,47 @@ zlist - no title found
SYNOPSIS
--------
----
+// Create a new list container
zlist_t *
zlist_new (void);
+
+// Destroy a list container
void
zlist_destroy (zlist_t **self_p);
+
+// Return first item in the list, or null
void *
zlist_first (zlist_t *self);
+
+// Return next item in the list, or null
void *
zlist_next (zlist_t *self);
+
+// Append an item to the end of the list
void
- zlist_append (zlist_t *self, void *value);
+ zlist_append (zlist_t *self, void *item);
+
+// Push an item to the start of the list
void
- zlist_push (zlist_t *self, void *value);
+ zlist_push (zlist_t *self, void *item);
+
+// Pop the item off the start of the list, if any
void *
zlist_pop (zlist_t *self);
+
+// Remove the specified item from the list if present
void
- zlist_remove (zlist_t *self, void *value);
+ zlist_remove (zlist_t *self, void *item);
+
+// Copy the entire list, return the copy
zlist_t *
zlist_copy (zlist_t *self);
+
+// Return number of items in the list
size_t
zlist_size (zlist_t *self);
+
+// Self test of this class
void
zlist_test (int verbose);
----
@@ -44,6 +65,64 @@ EXAMPLE
-------
.From zlist_test method
----
+ zlist_t *list = zlist_new ();
+ assert (list);
+ assert (zlist_size (list) == 0);
+
+ // Three items we'll use as test data
+ // List items are void *, not particularly strings
+ char *cheese = "boursin";
+ char *bread = "baguette";
+ char *wine = "bordeaux";
+
+ zlist_append (list, cheese);
+ assert (zlist_size (list) == 1);
+ zlist_append (list, bread);
+ assert (zlist_size (list) == 2);
+ zlist_append (list, wine);
+ assert (zlist_size (list) == 3);
+
+ assert (zlist_first (list) == cheese);
+ assert (zlist_next (list) == bread);
+ assert (zlist_next (list) == wine);
+ assert (zlist_size (list) == 3);
+
+ zlist_remove (list, wine);
+ assert (zlist_size (list) == 2);
+
+ assert (zlist_first (list) == cheese);
+ zlist_remove (list, cheese);
+ assert (zlist_size (list) == 1);
+ assert (zlist_first (list) == bread);
+
+ zlist_remove (list, bread);
+ assert (zlist_size (list) == 0);
+
+ zlist_push (list, cheese);
+ assert (zlist_size (list) == 1);
+ assert (zlist_first (list) == cheese);
+
+ zlist_push (list, bread);
+ assert (zlist_size (list) == 2);
+ assert (zlist_first (list) == bread);
+
+ zlist_append (list, wine);
+ assert (zlist_size (list) == 3);
+ assert (zlist_first (list) == bread);
+
+ char *item;
+ item = zlist_pop (list);
+ assert (item == bread);
+ item = zlist_pop (list);
+ assert (item == cheese);
+ item = zlist_pop (list);
+ assert (item == wine);
+ assert (zlist_size (list) == 0);
+
+ // Destructor should be safe to call twice
+ zlist_destroy (&list);
+ zlist_destroy (&list);
+ assert (list == NULL);
----
SEE ALSO
View
35 doc/zloop.txt
@@ -11,18 +11,33 @@ SYNOPSIS
// Callback function for reactor events
typedef int (zloop_fn) (zloop_t *loop, void *socket, void *args);
+// Create a new zloop reactor
zloop_t *
zloop_new (void);
+
+// Destroy a reactor
void
zloop_destroy (zloop_t **self_p);
+
+// Register a socket reader, on one socket
int
zloop_reader (zloop_t *self, void *socket, zloop_fn handler, void *args);
+
+// Cancel the reader on the specified socket, if any
void
zloop_cancel (zloop_t *self, void *socket);
+
+// Register a timer that will go off after 'delay' msecs, and will
+// repeat 'times' times, unless 'times' is zero, meaning repeat forever.
int
zloop_timer (zloop_t *self, size_t delay, size_t times, zloop_fn handler, void *args);
+
+// Start the reactor, ends if a callback function returns -1, or the process
+// received SIGINT or SIGTERM.
int
zloop_start (zloop_t *self);
+
+// Self test of this class
int
zloop_test (Bool verbose);
----
@@ -40,6 +55,26 @@ EXAMPLE
-------
.From zloop_test method
----
+ zctx_t *ctx = zctx_new ();
+
+ void *output = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_bind (output, "inproc://zloop.test");
+ void *input = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_connect (input, "inproc://zloop.test");
+
+ zloop_t *loop = zloop_new ();
+ assert (loop);
+
+ // After 10 msecs, send a ping message to output
+ zloop_timer (loop, 10, 1, s_timer_event, output);
+ // When we get the ping message, end the reactor
+ zloop_reader (loop, input, s_socket_event, NULL);
+ zloop_start (loop);
+
+ zloop_destroy (&loop);
+ assert (loop == NULL);
+
+ zctx_destroy (&ctx);
----
SEE ALSO
View
114 doc/zmsg.txt
@@ -8,40 +8,75 @@ zmsg - working with multipart messages
SYNOPSIS
--------
----
+// Create a new empty message object
zmsg_t *
zmsg_new (void);
+
+// Destroy a message object and all frames it contains
void
zmsg_destroy (zmsg_t **self_p);
+
+// Read 1 or more frames off the socket, into a new message object
zmsg_t *
zmsg_recv (void *socket);
+
+// Send a message to the socket, and then destroy it
void
zmsg_send (zmsg_t **self_p, void *socket);
+
+// Return number of frames in message
size_t
zmsg_size (zmsg_t *self);
+
+// Push frame to front of message, before first frame
void
zmsg_push (zmsg_t *self, zframe_t *frame);
+
+// Append frame to end of message, after last frame
void
zmsg_append (zmsg_t *self, zframe_t *frame);
+
+// Push block of memory as new frame to front of message
void
zmsg_pushmem (zmsg_t *self, const void *src, size_t size);
+
+// Push block of memory as new frame to end of message
void
zmsg_appendmem (zmsg_t *self, const void *src, size_t size);
+
+// Pop frame off front of message, caller now owns frame
zframe_t *
zmsg_pop (zmsg_t *self);
+
+// Remove frame from message, at any position, caller owns it
void
zmsg_remove (zmsg_t *self, zframe_t *frame);
+
+// Return first frame in message, or null
zframe_t *
zmsg_first (zmsg_t *self);
+
+// Return next frame in message, or null
zframe_t *
zmsg_next (zmsg_t *self);
+
+// Return first body frame, i.e. after first null frame
zframe_t *
zmsg_body (zmsg_t *self);
+
+// Save message to an open file
void
zmsg_save (zmsg_t *self, FILE *file);
+
+// Load a message from an open file
zmsg_t *
zmsg_load (FILE *file);
+
+// Print message to stderr, for debugging
void
zmsg_dump (zmsg_t *self);
+
+// Self test of this class
int
zmsg_test (Bool verbose);
----
@@ -59,6 +94,85 @@ EXAMPLE
-------
.From zmsg_test method
----
+ zctx_t *ctx = zctx_new ();
+
+ void *output = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_bind (output, "inproc://zmsg.test");
+ void *input = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_connect (input, "inproc://zmsg.test");
+
+ // Test send and receive of single-frame message
+ zmsg_t *msg = zmsg_new ();
+ zframe_t *frame = zframe_new ("Hello", 5);
+ zmsg_push (msg, frame);
+ assert (zmsg_size (msg) == 1);
+ zmsg_send (&msg, output);
+ assert (msg == NULL);
+
+ msg = zmsg_recv (input);
+ assert (msg);
+ assert (zmsg_size (msg) == 1);
+ zmsg_destroy (&msg);
+
+ // Test send and receive of multi-frame message
+ msg = zmsg_new ();
+ zmsg_appendmem (msg, "Frame0", 6);
+ zmsg_appendmem (msg, "Frame1", 6);
+ zmsg_appendmem (msg, "Frame2", 6);
+ zmsg_appendmem (msg, "Frame3", 6);
+ zmsg_appendmem (msg, "Frame4", 6);
+ zmsg_appendmem (msg, "Frame5", 6);
+ zmsg_appendmem (msg, "Frame6", 6);
+ zmsg_appendmem (msg, "Frame7", 6);
+ zmsg_appendmem (msg, "Frame8", 6);
+ zmsg_appendmem (msg, "Frame9", 6);
+ zmsg_send (&msg, output);
+
+ msg = zmsg_recv (input);
+ assert (msg);
+ assert (zmsg_size (msg) == 10);
+ if (verbose)
+ zmsg_dump (msg);
+
+ // Save to a file, read back
+ FILE *file = fopen ("zmsg.test", "w");
+ assert (file);
+ zmsg_save (msg, file);
+ zmsg_destroy (&msg);
+ fclose (file);
+
+ file = fopen ("zmsg.test", "r");
+ msg = zmsg_load (file);
+ fclose (file);
+ remove ("zmsg.test");
+ assert (zmsg_size (msg) == 10);
+
+ // Remove all frames except first and last
+ int frame_nbr;
+ for (frame_nbr = 0; frame_nbr < 8; frame_nbr++) {
+ zmsg_first (msg);
+ frame = zmsg_next (msg);
+ zmsg_remove (msg, frame);
+ zframe_destroy (&frame);
+ }
+ assert (zmsg_size (msg) == 2);
+ zmsg_pushmem (msg, "", 0);
+ zmsg_pushmem (msg, "Address", 7);
+ assert (zmsg_size (msg) == 4);
+ frame = zmsg_body (msg);
+ assert (memcmp (zframe_data (frame), "Frame0", 6) == 0);
+ zmsg_destroy (&msg);
+
+ // Now try methods on an empty message
+ msg = zmsg_new ();
+ assert (zmsg_size (msg) == 0);
+ assert (zmsg_body (msg) == NULL);
+ assert (zmsg_first (msg) == NULL);
+ assert (zmsg_next (msg) == NULL);
+ assert (zmsg_pop (msg) == NULL);
+ zmsg_destroy (&msg);
+
+ zctx_destroy (&ctx);
----
SEE ALSO
View
33 doc/zstr.txt
@@ -8,12 +8,19 @@ zstr - sending and receiving strings
SYNOPSIS
--------
----
+// Receive a string off a socket, caller must free it
char *
zstr_recv (void *socket);
+
+// Send a string to a socket in 0MQ string format
int
zstr_send (void *socket, const char *string);
+
+// Send a formatted string to a socket
int
zstr_sendf (void *socket, const char *format, ...);
+
+// Self test of this class
int
zstr_test (Bool verbose);
----
@@ -31,6 +38,32 @@ EXAMPLE
-------
.From zstr_test method
----
+ zctx_t *ctx = zctx_new ();
+
+ void *output = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_bind (output, "inproc://zstr.test");
+ void *input = zctx_socket_new (ctx, ZMQ_PAIR);
+ zmq_connect (input, "inproc://zstr.test");
+
+ // Send ten strings and then END
+ int string_nbr;
+ for (string_nbr = 0; string_nbr < 10; string_nbr++)
+ zstr_sendf (output, "this is string %d", string_nbr);
+ zstr_send (output, "END");
+
+ // Read and count until we receive END
+ string_nbr = 0;
+ for (string_nbr = 0;; string_nbr++) {
+ char *string = zstr_recv (input);
+ if (streq (string, "END")) {
+ free (string);
+ break;
+ }
+ free (string);
+ }
+ assert (string_nbr == 10);
+
+ zctx_destroy (&ctx);
----
SEE ALSO
View
8 include/zclock.h
@@ -29,16 +29,20 @@
extern "C" {
#endif
+// @interface
// Sleep for a number of milliseconds
void
zclock_sleep (int msecs);
+
// Return current system clock as milliseconds
int64_t
zclock_time (void);
-// Selftest
+
+// Self test of this class
int
zclock_test (Bool verbose);
-
+// @end
+
#ifdef __cplusplus
}
#endif
View
9 include/zctx.h
@@ -32,6 +32,7 @@ extern "C" {
// Opaque class structure
typedef struct _zctx_t zctx_t;
+// @interface
// Structure passed to threads created via this class
typedef struct {
zctx_t *ctx; // Context shared with parent thread
@@ -42,33 +43,41 @@ typedef struct {
// Create new context, returns context object, replaces zmq_init
zctx_t *
zctx_new (void);
+
// Destroy context and all sockets in it, replaces zmq_term
void
zctx_destroy (zctx_t **self_p);
+
// Raise default I/O threads from 1, for crazy heavy applications
void
zctx_set_iothreads (zctx_t *self, int iothreads);
+
// Set msecs to flush sockets when closing them
void
zctx_set_linger (zctx_t *self, int linger);
+
// Create socket within this context, replaces zmq_socket
void *
zctx_socket_new (zctx_t *self, int type);
+
// Destroy socket, replaces zmq_close
void
zctx_socket_destroy (zctx_t *self, void *socket);
+
// Create thread, return PAIR socket to talk to thread. The child thread
// receives a (zthread_t *) object including a zctx, a pipe back to the
// creating thread, and the arg passed in this call.
void *
zctx_thread_new (zctx_t *self, void *(*thread_fn) (void *), void *arg);
+
// Self test of this class
int
zctx_test (Bool verbose);
// Global signal indicator, TRUE when user presses Ctrl-C or the process
// gets a SIGTERM signal.
extern int zctx_interrupted;
+// @end
#ifdef __cplusplus
}
View
17 include/zframe.h
@@ -32,25 +32,42 @@ extern "C" {
// Opaque class structure
typedef struct _zframe_t zframe_t;
+// @interface
#define ZFRAME_MORE 1
#define ZFRAME_REUSE 2
+// Create a new frame with optional size, and optional data
zframe_t *
zframe_new (const void *data, size_t size);
+
+// Destroy a frame
void
zframe_destroy (zframe_t **self_p);
+
+// Receive a new frame off the socket
zframe_t *
zframe_recv (void *socket);
+
+// Send a frame to a socket, destroy frame after sending
void
zframe_send (zframe_t **self_p, void *socket, int flags);
+
+// Return number of bytes in frame data
size_t
zframe_size (zframe_t *self);
+
+// Return address of frame data
void *
zframe_data (zframe_t *self);
+
+// Return frame 'more' property
int
zframe_more (zframe_t *self);
+
+// Self test of this class
int
zframe_test (Bool verbose);
+// @end
#ifdef __cplusplus
}
View
33 include/zhash.h
@@ -29,34 +29,55 @@
extern "C" {
#endif
+// Opaque class structure
+typedef struct _zhash zhash_t;
+
+// @interface
// Callback function for zhash_foreach method
-typedef int (zhash_foreach_fn) (char *key, void *value, void *argument);
+typedef int (zhash_foreach_fn) (char *key, void *item, void *argument);
// Callback function for zhash_freefn method
typedef void (zhash_free_fn) (void *data);
-// Opaque class structure
-typedef struct _zhash zhash_t;
-
+// Create a new, empty hash container
zhash_t *
zhash_new (void);
+
+// Destroy a hash container and all items in it
void
zhash_destroy (zhash_t **self_p);
+
+// Insert an item into the hash container using the specified key
int
- zhash_insert (zhash_t *self, char *key, void *value);
+ zhash_insert (zhash_t *self, char *key, void *item);
+
+// Insert or update the item for the specified key
void
- zhash_update (zhash_t *self, char *key, void *value);
+ zhash_update (zhash_t *self, char *key, void *item);
+
+// Destroy the item at the specified key, if any
void
zhash_delete (zhash_t *self, char *key);
+
+// Return the item at the specified key, or null
void *
zhash_lookup (zhash_t *self, char *key);
+
+// Set a free function for the item at the specified key
void *
zhash_freefn (zhash_t *self, char *key, zhash_free_fn *free_fn);
+
+// Return the number of keys/items in the hash table
size_t
zhash_size (zhash_t *self);
+
+// Iterate over the hash table and apply the function to each item
int
zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument);
+
+// Self test of this class
void
zhash_test (int verbose);
+// @end
#ifdef __cplusplus
}
View
29 include/zlist.h
@@ -32,28 +32,51 @@ extern "C" {
// Opaque class structure
typedef struct _zlist zlist_t;
+// @interface
+// Create a new list container
zlist_t *
zlist_new (void);
+
+// Destroy a list container
void
zlist_destroy (zlist_t **self_p);
+
+// Return first item in the list, or null
void *
zlist_first (zlist_t *self);
+
+// Return next item in the list, or null
void *
zlist_next (zlist_t *self);
+
+// Append an item to the end of the list
void
- zlist_append (zlist_t *self, void *value);
+ zlist_append (zlist_t *self, void *item);
+
+// Push an item to the start of the list
void
- zlist_push (zlist_t *self, void *value);
+ zlist_push (zlist_t *self, void *item);
+
+// Pop the item off the start of the list, if any
void *
zlist_pop (zlist_t *self);
+
+// Remove the specified item from the list if present
void
- zlist_remove (zlist_t *self, void *value);
+ zlist_remove (zlist_t *self, void *item);
+
+// Copy the entire list, return the copy
zlist_t *
zlist_copy (zlist_t *self);
+
+// Return number of items in the list
size_t
zlist_size (zlist_t *self);
+
+// Self test of this class
void
zlist_test (int verbose);
+// @end
#ifdef __cplusplus
}
View
17 include/zloop.h
@@ -32,23 +32,40 @@ extern "C" {
// Opaque class structure
typedef struct _zloop_t zloop_t;
+// @interface
// Callback function for reactor events
typedef int (zloop_fn) (zloop_t *loop, void *socket, void *args);
+// Create a new zloop reactor
zloop_t *
zloop_new (void);
+
+// Destroy a reactor
void
zloop_destroy (zloop_t **self_p);
+
+// Register a socket reader, on one socket
int
zloop_reader (zloop_t *self, void *socket, zloop_fn handler, void *args);
+
+// Cancel the reader on the specified socket, if any
void
zloop_cancel (zloop_t *self, void *socket);
+
+// Register a timer that will go off after 'delay' msecs, and will
+// repeat 'times' times, unless 'times' is zero, meaning repeat forever.
int
zloop_timer (zloop_t *self, size_t delay, size_t times, zloop_fn handler, void *args);
+
+// Start the reactor, ends if a callback function returns -1, or the process
+// received SIGINT or SIGTERM.
int
zloop_start (zloop_t *self);
+
+// Self test of this class
int
zloop_test (Bool verbose);
+// @end
#ifdef __cplusplus
}
View
37 include/zmsg.h
@@ -32,42 +32,79 @@ extern "C" {
// Opaque class structure
typedef struct _zmsg_t zmsg_t;
+// @interface
+// Create a new empty message object
zmsg_t *
zmsg_new (void);
+
+// Destroy a message object and all frames it contains
void
zmsg_destroy (zmsg_t **self_p);
+
+// Read 1 or more frames off the socket, into a new message object
zmsg_t *
zmsg_recv (void *socket);
+
+// Send a message to the socket, and then destroy it
void
zmsg_send (zmsg_t **self_p, void *socket);
+
+// Return number of frames in message
size_t
zmsg_size (zmsg_t *self);
+
+// Push frame to front of message, before first frame
void
zmsg_push (zmsg_t *self, zframe_t *frame);
+
+// Append frame to end of message, after last frame
void
zmsg_append (zmsg_t *self, zframe_t *frame);
+
+// Push block of memory as new frame to front of message
void
zmsg_pushmem (zmsg_t *self, const void *src, size_t size);
+
+// Push block of memory as new frame to end of message
void
zmsg_appendmem (zmsg_t *self, const void *src, size_t size);
+
+// Pop frame off front of message, caller now owns frame
zframe_t *
zmsg_pop (zmsg_t *self);
+
+// Remove frame from message, at any position, caller owns it
void
zmsg_remove (zmsg_t *self, zframe_t *frame);
+
+// Return first frame in message, or null
zframe_t *
zmsg_first (zmsg_t *self);
+
+// Return next frame in message, or null
zframe_t *
zmsg_next (zmsg_t *self);
+
+// Return first body frame, i.e. after first null frame
zframe_t *
zmsg_body (zmsg_t *self);
+
+// Save message to an open file
void
zmsg_save (zmsg_t *self, FILE *file);
+
+// Load a message from an open file
zmsg_t *
zmsg_load (FILE *file);
+
+// Print message to stderr, for debugging
void
zmsg_dump (zmsg_t *self);
+
+// Self test of this class
int
zmsg_test (Bool verbose);
+// @end
#ifdef __cplusplus
}
View
9 include/zstr.h
@@ -29,14 +29,23 @@
extern "C" {
#endif
+// @interface
+// Receive a string off a socket, caller must free it
char *
zstr_recv (void *socket);
+
+// Send a string to a socket in 0MQ string format
int
zstr_send (void *socket, const char *string);
+
+// Send a formatted string to a socket
int
zstr_sendf (void *socket, const char *format, ...);
+
+// Self test of this class
int
zstr_test (Bool verbose);
+// @end
#ifdef __cplusplus
}
View
14 mkdoc
@@ -0,0 +1,14 @@
+#! /bin/bash
+#
+# Generate zapi documentation
+
+# Generate man pages and website manual
+cd doc
+./mksite
+cd ..
+
+# Generate README.md and upload to git
+gitdown README.txt
+git add README.* images
+git commit -m "Generated documentation"
+git push origin master
View
10 src/zclock.c
@@ -22,14 +22,11 @@
=========================================================================
*/
/*
-@overview
-
+@header
The zclock class provides essential sleep and system time functions, used
to slow down threads for testing, and calculate timers for polling. Wraps
the non-portable system calls in a simple portable API.
-
@discuss
-
This class contains some small surprises. Most amazing, win32 did an API
better than POSIX. The win32 Sleep() call is not only a neat 1-liner, it
also sleeps for milliseconds, whereas the POSIX call asks us to think in
@@ -39,6 +36,7 @@ are a concept we can deal with. Seconds are too fat, nanoseconds too
tiny, but milliseconds are just right for slices of time we want to work
with at the 0MQ scale. zclock doesn't give you objects to work with, we
like the zapi class model but we're not insane. There, got it in again.
+@end
*/
#include "../include/zapi_prelude.h"
@@ -88,10 +86,12 @@ zclock_test (Bool verbose)
{
printf (" * zclock: ");
+ // @selftest
int64_t start = zclock_time ();
zclock_sleep (10);
assert ((zclock_time () - start) >= 10);
-
+ // @end
+
printf ("OK\n");
return 0;
}
View
203 src/zctx.c
@@ -23,106 +23,104 @@
*/
/*
-@overview
-
-The zctx class wraps 0MQ contexts. It manages open sockets in the context
-and automatically closes these before terminating the context. It provides
-a simple way to set the linger timeout on sockets, and configure contexts
-for number of I/O threads. Sets-up signal (interrrupt) handling for the
-process.
-
-The zctx class has these main features:
-
-* Tracks all open sockets and automatically closes them before calling
- zmq_term(). This avoids an infinite wait on open sockets.
-
-* Automatically configures sockets with a ZMQ_LINGER timeout you can
- define, and which defaults to zero. The default behavior of zctx is
- therefore like 0MQ/2.0, immediate termination with loss of any pending
- messages. You can set any linger timeout you like by calling the
- zctx_set_linger() method.
-
-* Moves the iothreads configuration to a separate method, so that default
- usage is 1 I/O thread. Lets you configure this value.
-
-* Sets up signal (SIGINT and SIGTERM) handling so that blocking calls
- such as zmq_recv() and zmq_poll() will return when the user presses
- Ctrl-C.
-
-* Provides API to create child threads with a pipe (PAIR socket) to talk
- to them.
-
-@discussion
-
-This class is an example of how to create a thread-safe object using
-0MQ. Actually it's a little more work than it sounded at first. Let's
-start by agreeing on the problem here. We have a context wrapper, zctx,
-which does some neat work for us such as managing sockets automatically
-so we can just shut down without having to manually close each and
-every damn socket. All good, until we need to build a multithreaded
-application. Which is about 80% of interesting 0MQ applications. It is
-not safe to share a single object from multiple threads. They'll try to
-mess with the data structures concurrently, and it'll break nastily.
-
-OK, the classic solution would be exclusion using semaphores, critical
-sections, etc. We're 0MQ fanatics so that's not even an option. Instead,
-we want to eat our own dogfood and do this using 0MQ.
-
-The basic concept, which you'll see in this class, is that the real work
-is not done by the object we own, but by a separate object, running in
-its own thread. I call this the "agent". This is a nice pattern, and we
-see it in a few places, such as the flcliapi example from the Guide.
-
-The slight difficulty here is bootstrapping. We have a separate agent
-thread, which we talk to over inproc, and which manages our context and
-sockets. This is problem number one, I'll get to problem two in a sec.
-
-Part of zctx's magic is delaying the zmq_init call until it's really
-needed. This lets us first configure iothreads if needed. It's the agent
-that will create the 0MQ context by calling zmq_init. However we need
-sockets to talk to the agent. Solution: use two contexts, one for the
-pipes to/from the agent, and one for the application itself. Not many
-0MQ applications create multiple contexts, but it's a valid and useful
-technique.
-
-So we create a private context, two sockets, and then we pass one of
-those sockets to the agent. We can then talk to the agent by sending
-simple commands like IOTHREADS=100, SOCKET, CLOSE=0xff33344, and
-TERMINATE. BTW, do not set IOTHREADS to 100, that is insane. Anything
-above 1 is actually insane unless you know what you're doing.
-
-Next problem is when our application needs child threads. If we simply
-use pthreads_create() we're faced with several issues. First, it's not
-portable to legacy OSes like win32. Second, how can a child thread get
-access to our zctx object? If we just pass it around, we'll end up
-sharing the pipe socket (which we use to talk to the agent) between
-threads, and that will then crash 0MQ. Sockets cannot be used from more
-than one thread at a time.
-
-So each child thread needs its own pipe to the agent. For the agent,
-this is fine, it can talk to a million threads. But how do we create
-those pipes in the child thread? We can't, not without help from the
-main thread. The solution is to wrap thread creation, like we wrap
-socket creation. To create a new thread, the app calls zctx_thread_new()
-and this method creates a dedicated zctx object, with a pipe, and then
-it passes that object to the newly minted child thread.
-
-The neat thing is we can hide non-portable aspects. Windows is really a
-mess when it comes to threads. Three different APIs, none of which is
-really right, so you have to do rubbish like manually cleaning up when
-a thread finishes. Anyhow, it's hidden in this class so you don't need
-to worry.
-
-Second neat thing about wrapping thread creation is we can make it a
-more enriching experience for all involved. One thing I do often is use
-a PAIR-PAIR pipe to talk from a thread to/from its parent. So this class
-will automatically create such a pair for each thread you start.
-
-That's it. We have a multithreaded class that is thread safe and also
-gives you major power for creating multithreaded applications, with a
-really simple API.
-
-Now that's what I call a language binding.
+@header
+ The zctx class wraps 0MQ contexts. It manages open sockets in the context
+ and automatically closes these before terminating the context. It provides
+ a simple way to set the linger timeout on sockets, and configure contexts
+ for number of I/O threads. Sets-up signal (interrrupt) handling for the
+ process.
+
+ The zctx class has these main features:
+
+ * Tracks all open sockets and automatically closes them before calling
+ zmq_term(). This avoids an infinite wait on open sockets.
+
+ * Automatically configures sockets with a ZMQ_LINGER timeout you can
+ define, and which defaults to zero. The default behavior of zctx is
+ therefore like 0MQ/2.0, immediate termination with loss of any pending
+ messages. You can set any linger timeout you like by calling the
+ zctx_set_linger() method.
+
+ * Moves the iothreads configuration to a separate method, so that default
+ usage is 1 I/O thread. Lets you configure this value.
+
+ * Sets up signal (SIGINT and SIGTERM) handling so that blocking calls
+ such as zmq_recv() and zmq_poll() will return when the user presses
+ Ctrl-C.
+
+ * Provides API to create child threads with a pipe (PAIR socket) to talk
+ to them.
+@discuss
+ This class is an example of how to create a thread-safe object using
+ 0MQ. Actually it's a little more work than it sounded at first. Let's
+ start by agreeing on the problem here. We have a context wrapper, zctx,
+ which does some neat work for us such as managing sockets automatically
+ so we can just shut down without having to manually close each and
+ every damn socket. All good, until we need to build a multithreaded
+ application. Which is about 80% of interesting 0MQ applications. It is
+ not safe to share a single object from multiple threads. They'll try to
+ mess with the data structures concurrently, and it'll break nastily.
+
+ OK, the classic solution would be exclusion using semaphores, critical
+ sections, etc. We're 0MQ fanatics so that's not even an option. Instead,
+ we want to eat our own dogfood and do this using 0MQ.
+
+ The basic concept, which you'll see in this class, is that the real work
+ is not done by the object we own, but by a separate object, running in
+ its own thread. I call this the "agent". This is a nice pattern, and we
+ see it in a few places, such as the flcliapi example from the Guide.
+
+ The slight difficulty here is bootstrapping. We have a separate agent
+ thread, which we talk to over inproc, and which manages our context and
+ sockets. This is problem number one, I'll get to problem two in a sec.
+
+ Part of zctx's magic is delaying the zmq_init call until it's really
+ needed. This lets us first configure iothreads if needed. It's the agent
+ that will create the 0MQ context by calling zmq_init. However we need
+ sockets to talk to the agent. Solution: use two contexts, one for the
+ pipes to/from the agent, and one for the application itself. Not many
+ 0MQ applications create multiple contexts, but it's a valid and useful
+ technique.
+
+ So we create a private context, two sockets, and then we pass one of
+ those sockets to the agent. We can then talk to the agent by sending
+ simple commands like IOTHREADS=100, SOCKET, CLOSE=0xff33344, and
+ TERMINATE. BTW, do not set IOTHREADS to 100, that is insane. Anything
+ above 1 is actually insane unless you know what you're doing.
+
+ Next problem is when our application needs child threads. If we simply
+ use pthreads_create() we're faced with several issues. First, it's not
+ portable to legacy OSes like win32. Second, how can a child thread get
+ access to our zctx object? If we just pass it around, we'll end up
+ sharing the pipe socket (which we use to talk to the agent) between
+ threads, and that will then crash 0MQ. Sockets cannot be used from more
+ than one thread at a time.
+
+ So each child thread needs its own pipe to the agent. For the agent,
+ this is fine, it can talk to a million threads. But how do we create
+ those pipes in the child thread? We can't, not without help from the
+ main thread. The solution is to wrap thread creation, like we wrap
+ socket creation. To create a new thread, the app calls zctx_thread_new()
+ and this method creates a dedicated zctx object, with a pipe, and then
+ it passes that object to the newly minted child thread.
+
+ The neat thing is we can hide non-portable aspects. Windows is really a
+ mess when it comes to threads. Three different APIs, none of which is
+ really right, so you have to do rubbish like manually cleaning up when
+ a thread finishes. Anyhow, it's hidden in this class so you don't need
+ to worry.
+
+ Second neat thing about wrapping thread creation is we can make it a
+ more enriching experience for all involved. One thing I do often is use
+ a PAIR-PAIR pipe to talk from a thread to/from its parent. So this class
+ will automatically create such a pair for each thread you start.
+
+ That's it. We have a multithreaded class that is thread safe and also
+ gives you major power for creating multithreaded applications, with a
+ really simple API.
+
+ Now that's what I call a language binding.
+@end
*/
#include "../include/zapi_prelude.h"
@@ -487,6 +485,7 @@ zctx_socket_destroy (zctx_t *self, void *socket)
// --------------------------------------------------------------------------
// Selftest
+// @selftest
static void *
s_test_thread (void *args_ptr)
{
@@ -502,12 +501,15 @@ s_test_thread (void *args_ptr)
return NULL;
}
+// @end
+
int
zctx_test (Bool verbose)
{
printf (" * zctx: ");
+ // @selftest
// Create and destroy a context without using it
zctx_t *ctx = zctx_new ();
assert (ctx);
@@ -540,6 +542,7 @@ zctx_test (Bool verbose)
// Everything should be cleanly closed now
zctx_destroy (&ctx);
+ // @end
printf ("OK\n");
return 0;
View
14 src/zframe.c
@@ -23,8 +23,16 @@
*/
/*
-@overview
+@header
+ The zframe class provides methods to send and receive single message
+ frames across 0MQ sockets. A 'frame' corresponds to one zmq_msg_t. When
+ you read a frame from a socket, the zframe_more() method indicates if the
+ frame is part of an unfinished multipart message. The zframe_send method
+ normally destroys the frame, but with the ZFRAME_REUSE flag, you can send
+ the same frame many times. Frames are binary, and this class has no
+ special support for text data.
@discuss
+@end
*/
#include "../include/zapi_prelude.h"
@@ -167,6 +175,7 @@ zframe_test (Bool verbose)
{
printf (" * zframe: ");
+ // @selftest
zctx_t *ctx = zctx_new ();
void *output = zctx_socket_new (ctx, ZMQ_PAIR);
@@ -205,8 +214,9 @@ zframe_test (Bool verbose)
zframe_destroy (&frame);
}
assert (frame_nbr == 10);
-
+
zctx_destroy (&ctx);
+ // @end
printf ("OK\n");
return 0;
}
View
113 src/zhash.c
@@ -5,7 +5,7 @@
Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com>
Copyright other contributors as noted in the AUTHORS file.
- This file is part of the ZeroMQ Function Library: http://zfl.zeromq.org
+ This file is part of zapi, the C binding for 0MQ: http://zapi.zeromq.org.
This is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free
@@ -23,15 +23,13 @@
*/
/*
-@overview
-
-Expandable hash table container
-
+@header
+ Expandable hash table container
@discuss
-
-Note that it's relatively slow (~50k insertions/deletes per second), so
-don't do inserts/updates on the critical path for message I/O. It can
-do ~2.5M lookups per second for 16-char keys. Timed on a 1.6GHz CPU.
+ Note that it's relatively slow (~50k insertions/deletes per second), so
+ don't do inserts/updates on the critical path for message I/O. It can
+ do ~2.5M lookups per second for 16-char keys. Timed on a 1.6GHz CPU.
+@end
*/
#include "../include/zapi_prelude.h"
@@ -49,7 +47,7 @@ do ~2.5M lookups per second for 16-char keys. Timed on a 1.6GHz CPU.
typedef struct _item_t item_t;
struct _item_t {
void
- *value; // Opaque item value
+ *item; // Opaque item
item_t
*next; // Next item in the hash slot
qbyte
@@ -120,14 +118,14 @@ s_item_lookup (zhash_t *self, char *key)
// If item already existed, returns NULL
static item_t *
-s_item_insert (zhash_t *self, char *key, void *value)
+s_item_insert (zhash_t *self, char *key, void *item)
{
// Check that item does not already exist in hash table
- // Leaves self->cached_index with calculated hash value
+ // Leaves self->cached_index with calculated hash item
item_t *item = s_item_lookup (self, key);
if (item == NULL) {
item = (item_t *) zmalloc (sizeof (item_t));
- item->value = value;
+ item->item = item;
item->key = strdup (key);
item->index = self->cached_index;
// Insert into start of bucket list
@@ -161,7 +159,7 @@ s_item_destroy (zhash_t *self, item_t *item)
*prev_item = item->next;
self->size--;
if (item->free_fn)
- (item->free_fn) (item->value);
+ (item->free_fn) (item->item);
free (item->key);
free (item);
}
@@ -209,12 +207,12 @@ zhash_destroy (zhash_t **self_p)
// --------------------------------------------------------------------------
-// Insert item into hash table with specified key and value
+// Insert item into hash table with specified key and item
// If key is already present returns -1 and leaves existing item unchanged
// Returns 0 on success.
int
-zhash_insert (zhash_t *self, char *key, void *value)
+zhash_insert (zhash_t *self, char *key, void *item)
{
assert (self);
assert (key);
@@ -255,28 +253,28 @@ zhash_insert (zhash_t *self, char *key, void *value)
self->items = new_items;
self->limit = new_limit;
}
- return s_item_insert (self, key, value)? 0: -1;
+ return s_item_insert (self, key, item)? 0: -1;
}
// --------------------------------------------------------------------------
-// Update item into hash table with specified key and value.
-// If key is already present, destroys old value and inserts new one.
-// Use free_fn method to ensure deallocator is properly called on value.
+// Update item into hash table with specified key and item.
+// If key is already present, destroys old item and inserts new one.
+// Use free_fn method to ensure deallocator is properly called on item.
void
-zhash_update (zhash_t *self, char *key, void *value)
+zhash_update (zhash_t *self, char *key, void *item)
{
assert (self);
assert (key);
item_t *item = s_item_lookup (self, key);
if (item) {
if (item->free_fn)
- (item->free_fn) (item->value);
- item->value = value;
+ (item->free_fn) (item->item);
+ item->item = item;
}
else
- zhash_insert (self, key, value);
+ zhash_insert (self, key, item);
}
@@ -297,7 +295,7 @@ zhash_delete (zhash_t *self, char *key)
// --------------------------------------------------------------------------
-// Look for item in hash table and return its value, or NULL
+// Look for item in hash table and return its item, or NULL
void *
zhash_lookup (zhash_t *self, char *key)
@@ -307,18 +305,18 @@ zhash_lookup (zhash_t *self, char *key)
item_t *item = s_item_lookup (self, key);
if (item)
- return item->value;
+ return item->item;
else
return NULL;
}
// --------------------------------------------------------------------------
// Set a free function for the specified hash table item. When the item is
-// destroyed, the free function, if any, is called on that item value.
-// Use this when hash item values are dynamically allocated, to ensure that
+// destroyed, the free function, if any, is called on that item.
+// Use this when hash items are dynamically allocated, to ensure that
// you don't have memory leaks. You can pass 'free' or NULL as a free_fn.
-// Returns the item value, or NULL if there is no such item.
+// Returns the item, or NULL if there is no such item.
void *
zhash_freefn (zhash_t *self, char *key, zhash_free_fn *free_fn)
@@ -329,7 +327,7 @@ zhash_freefn (zhash_t *self, char *key, zhash_free_fn *free_fn)
item_t *item = s_item_lookup (self, key);
if (item) {
item->free_fn = free_fn;
- return item->value;
+ return item->item;
}
else
return NULL;
@@ -367,7 +365,7 @@ zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument)
item = self->items [index];
while (item) {
// Invoke callback, passing item properties and argument
- rc = callback (item->key, item->value, argument);
+ rc = callback (item->key, item->item, argument);
if (rc)
break; // End if non-zero return code
item = item->next;
@@ -379,17 +377,19 @@ zhash_foreach (zhash_t *self, zhash_foreach_fn *callback, void *argument)
// --------------------------------------------------------------------------
// Runs selftest of class
+// TODO: add unit test for free_fn, foreach
void
zhash_test (int verbose)
{
printf (" * zhash: ");
+ // @selftest
zhash_t *hash = zhash_new ();
assert (hash);
assert (zhash_size (hash) == 0);
- // Insert some values
+ // Insert some items
int rc;
rc = zhash_insert (hash, "DEADBEEF", (void *) 0xDEADBEEF);
assert (rc == 0);
@@ -401,31 +401,31 @@ zhash_test (int verbose)
assert (rc == 0);
assert (zhash_size (hash) == 4);
- // Look for existing values
- void *value;
- value = zhash_lookup (hash, "DEADBEEF");
- assert (value == (void *) 0xDEADBEEF);
- value = zhash_lookup (hash, "ABADCAFE");
- assert (value == (void *) 0xABADCAFE);
- value = zhash_lookup (hash, "C0DEDBAD");
- assert (value == (void *) 0xC0DEDBAD);
- value = zhash_lookup (hash, "DEADF00D");
- assert (value == (void *) 0xDEADF00D);
-
- // Look for non-existent values
- value = zhash_lookup (hash, "0xF0000000");
- assert (value == NULL);
-
- // Try to insert duplicate values
+ // Look for existing items
+ void *item;
+ item = zhash_lookup (hash, "DEADBEEF");
+ assert (item == (void *) 0xDEADBEEF);
+ item = zhash_lookup (hash, "ABADCAFE");
+ assert (item == (void *) 0xABADCAFE);
+ item = zhash_lookup (hash, "C0DEDBAD");
+ assert (item == (void *) 0xC0DEDBAD);
+ item = zhash_lookup (hash, "DEADF00D");
+ assert (item == (void *) 0xDEADF00D);
+
+ // Look for non-existent items
+ item = zhash_lookup (hash, "0xF0000000");
+ assert (item == NULL);
+
+ // Try to insert duplicate items
rc = zhash_insert (hash, "DEADBEEF", (void *) 0xF0000000);
assert (rc == -1);
- value = zhash_lookup (hash, "DEADBEEF");
- assert (value == (void *) 0xDEADBEEF);
+ item = zhash_lookup (hash, "DEADBEEF");
+ assert (item == (void *) 0xDEADBEEF);
- // Delete a value
+ // Delete a item
zhash_delete (hash, "DEADBEEF");
- value = zhash_lookup (hash, "DEADBEEF");
- assert (value == NULL);