Added API reference generator script.

Formatted the public APIs with Sphinx syntax.
This commit is contained in:
Tatsuhiro Tsujikawa 2012-03-14 00:32:52 +09:00
parent 1c09a69d58
commit 07b02404c3
11 changed files with 1502 additions and 293 deletions

View File

@ -20,6 +20,6 @@
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = lib examples tests
SUBDIRS = lib examples tests doc
ACLOCAL_AMFLAGS = -I m4

View File

@ -131,6 +131,8 @@ AC_CONFIG_FILES([
lib/includes/spdylay/spdylayver.h
tests/Makefile
examples/Makefile
doc/Makefile
doc/conf.py
])
AC_OUTPUT

3
doc/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
apiref.rst
conf.py
manual

158
doc/Makefile.am Normal file
View File

@ -0,0 +1,158 @@
# Spdylay - SPDY Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = manual
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
apiref.rst: $(top_builddir)/lib/includes/spdylay/spdylayver.h \
$(top_builddir)/lib/includes/spdylay/spdylay.h
$(builddir)/mkapiref.py --header apiref-header.rst $^ > $@
clean:
-rm apiref.rst
-rm -rf $(BUILDDIR)/*
html: apiref.rst
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Spdylay.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Spdylay.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Spdylay"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Spdylay"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

160
doc/README.rst Normal file
View File

@ -0,0 +1,160 @@
Spdylay Documentation
=====================
The documentation of Spdylay is generated using Sphinx. This
directory contains the source files to be processed by Sphinx. The
source file for API reference is generated using a script called
``mkapiref.py`` from the Spdylay C source code.
Generating API reference
------------------------
As described earlier, we use ``mkapiref.py`` to generate rst formatted
text of API reference from C source code. The ``mkapiref.py`` is not
so flexible and it requires that C source code is formatted in rather
strict rules.
To generate API reference, just run ``make html``. It runs
``mkapiref.py`` and then run Sphinx to build the entire document.
The ``mkapiref.py`` reads C source code and searches the comment block
starts with ``/**``. In other words, it only processes the comment
block starting ``/**``. The comment block must end with ``*/``. The
``mkapiref.py`` requires that which type of the object this comment
block refers to. To specify the type of the object, the next line
must contain the so-caled action keyword. Currently, the following
action keywords are supported: ``@function``, ``@functypedef``,
``@enum``, ``@struct`` and ``@union``. The following sections
describes each action keyword.
@function
#########
``@function`` is used to refer to the function. The comment block is
used for the document for the function. After the script sees the end
of the comment block, it consumes the lines as the function
declaration until the line which ends with ``;`` is encountered.
In Sphinx doc, usually the function argument is formatted like
``*this*``. But in C, ``*`` is used for dereferencing a pointer and
we must escape ``*`` with a back slash. To avoid this, we format the
argument like ``|this|``. The ``mkapiref.py`` translates it with
``*this*``, as escaping ``*`` inside ``|`` and ``|`` as necessary.
Note that this shadows the substitution feature of Sphinx.
The example follows::
/**
* @function
*
* Submits PING frame to the |session|.
*/
int spdylay_submit_ping(spdylay_session *session);
@functypedef
############
``@functypedef`` is used to refer to the typedef of the function
pointer. The formatting rule is pretty much the same with
``@function``, but this outputs ``type`` domain, rather than
``function`` domain.
The example follows::
/**
* @functypedef
*
* Callback function invoked when |session| wants to send data to
* remote peer.
*/
typedef ssize_t (*spdylay_send_callback)
(spdylay_session *session,
const uint8_t *data, size_t length, int flags, void *user_data);
@enum
#####
``@enum`` is used to refer to the enum. Currently, only enum typedefs
are supported. The comment block is used for the document for the
enum type itself. To document each values, put comment block starting
with the line ``/**`` and ending with the ``*/`` just before the enum
value. When the line starts with ``}`` is encountered, the
``mkapiref.py`` extracts strings next to ``}`` as the name of enum.
At the time of this writing, Sphinx does not support enum type. So we
use ``type`` domain for enum it self and ``macro`` domain for each
value. To refer to the enum value, use ``:enum:`` pseudo role. The
``mkapiref.py`` replaces it with ``:macro:``. By doing this, when
Sphinx will support enum officially, we can replace ``:enum:`` with
the official role easily.
The example follows::
/**
* @enum
* Error codes used in the Spdylay library.
*/
typedef enum {
/**
* Invalid argument passed.
*/
SPDYLAY_ERR_INVALID_ARGUMENT = -501,
/**
* Zlib error.
*/
SPDYLAY_ERR_ZLIB = -502,
} spdylay_error;
@struct
#######
``@struct`` is used to refer to the struct. Currently, only struct
typedefs are supported. The comment block is used for the document for
the struct type itself.To document each member, put comment block
starting with the line ``/**`` and ending with the ``*/`` just before
the member. When the line starts with ``}`` is encountered, the
``mkapiref.py`` extracts strings next to ``}`` as the name of struct.
The block-less typedef is also supported. In this case, typedef
declaration must be all in one line and the ``mkapiref.py`` uses last
word as the name of struct.
Some examples follow::
/**
* @struct
* The control frame header.
*/
typedef struct {
/**
* SPDY protocol version.
*/
uint16_t version;
/**
* The type of this control frame.
*/
uint16_t type;
/**
* The control frame flags.
*/
uint8_t flags;
/**
* The length field of this control frame.
*/
int32_t length;
} spdylay_ctrl_hd;
/**
* @struct
*
* The primary structure to hold the resources needed for a SPDY
* session. The details of this structure is hidden from the public
* API.
*/
typedef struct spdylay_session spdylay_session;
@union
======
``@union`` is used to refer to the union. Currently, ``@union`` is an
alias of ``@struct``.

9
doc/apiref-header.rst Normal file
View File

@ -0,0 +1,9 @@
API Reference
=============
Includes
--------
To use the public APIs, include ``spdylay/spdylay.h``::
#include <spdylay/spdylay.h>

View File

@ -1,4 +1,27 @@
# -*- coding: utf-8 -*-
# Spdylay - SPDY Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Spdylay documentation build configuration file, created by
# sphinx-quickstart on Sun Mar 11 22:57:49 2012.
@ -48,9 +71,9 @@ copyright = u'2012, Tatsuhiro Tsujikawa'
# built documents.
#
# The short X.Y version.
version = '0.1.0'
version = '@PACKAGE_VERSION@'
# The full version, including alpha/beta/rc tags.
release = '0.1.0'
release = '@PACKAGE_VERSION@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -64,7 +87,7 @@ release = '0.1.0'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ['manual', 'README.rst', '*-header.rst']
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = 'c:func'
@ -81,6 +104,9 @@ primary_domain = 'c'
# output. They are ignored by default.
#show_authors = False
# The default language to highlight source code in. The default is 'python'.
highlight_language = 'c'
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

View File

@ -6,15 +6,20 @@
Welcome to Spdylay's documentation!
===================================
This is an experimental implementation of Google's SPDY protocol
version 2 and 3 in C.
This library provides SPDY framing layer implementation. It does not
perform any I/O operations. When the library needs them, it calls the
callback functions provided by the application. It also does not
include any event polling mechanism, so the application can freely
choose the way of handling events. This library code does not depend
on any particular SSL library (except for example programs which
depend on OpenSSL 1.0.1 or later).
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
apiref

205
doc/mkapiref.py Executable file
View File

@ -0,0 +1,205 @@
#!/usr/bin/env python
# Spdylay - SPDY Library
# Copyright (c) 2012 Tatsuhiro Tsujikawa
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Generates API reference from C source code.
import re, sys, argparse
class FunctionDoc:
def __init__(self, name, content, domain):
self.name = name
self.content = content
self.domain = domain
def write(self, out):
print '''.. {}:: {}'''.format(self.domain, self.name)
print ''
for line in self.content:
print ' {}'.format(line)
class StructDoc:
def __init__(self, name, content, members, member_domain):
self.name = name
self.content = content
self.members = members
self.member_domain = member_domain
def write(self, out):
if self.name:
print '''.. type:: {}'''.format(self.name)
print ''
for line in self.content:
print ' {}'.format(line)
print ''
for name, content in self.members:
print ''' .. {}:: {}'''.format(self.member_domain, name)
print ''
for line in content:
print ''' {}'''.format(line)
print ''
class MacroDoc:
def __init__(self, name, content):
self.name = name
self.content = content
def write(self, out):
print '''.. macro:: {}'''.format(self.name)
print ''
for line in self.content:
print ' {}'.format(line)
def make_api_ref(infiles):
macros = []
enums = []
types = []
functions = []
for infile in infiles:
while True:
line = infile.readline()
if not line:
break
elif line == '/**\n':
line = infile.readline()
doctype = line.split()[1]
if doctype == '@function':
functions.append(process_function('function', infile))
elif doctype == '@functypedef':
types.append(process_function('type', infile))
elif doctype == '@struct' or doctype == '@union':
types.append(process_struct(infile))
elif doctype == '@enum':
enums.append(process_enum(infile))
elif doctype == '@macro':
macros.append(process_macro(infile))
alldocs = [('Macros', macros),
('Enums', enums),
('Types (structs, unions and typedefs)', types),
('Functions', functions)]
for title, docs in alldocs:
if not docs:
continue
print title
print '-'*len(title)
for doc in docs:
doc.write(sys.stdout)
print ''
print ''
def process_macro(infile):
content = read_content(infile)
line = infile.readline()
macro_name = line.split()[1]
return MacroDoc(macro_name, content)
def process_enum(infile):
members = []
enum_name = None
content = read_content(infile)
while True:
line = infile.readline()
if not line:
break
elif re.match(r'\s*/\*\*\n', line):
member_content = read_content(infile)
line = infile.readline()
member_name = line.split()[0]
members.append((member_name, member_content))
elif line.startswith('}'):
enum_name = line.rstrip().split()[1]
enum_name = re.sub(r';$', '', enum_name)
break
return StructDoc(enum_name, content, members, 'macro')
def process_struct(infile):
members = []
struct_name = None
content = read_content(infile)
while True:
line = infile.readline()
if not line:
break
elif re.match(r'\s*/\*\*\n', line):
member_content = read_content(infile)
line = infile.readline()
member_name = line.rstrip().rstrip(';')
members.append((member_name, member_content))
elif line.startswith('}') or\
(line.startswith('typedef ') and line.endswith(';\n')):
if line.startswith('}'):
index = 1
else:
index = 3
struct_name = line.rstrip().split()[index]
struct_name = re.sub(r';$', '', struct_name)
break
return StructDoc(struct_name, content, members, 'member')
def process_function(domain, infile):
content = read_content(infile)
func_proto = []
while True:
line = infile.readline()
if not line:
break
elif line == '\n':
break
else:
func_proto.append(line)
func_proto = ''.join(func_proto)
func_proto = re.sub(r';\n$', '', func_proto)
func_proto = re.sub(r'\s+', ' ', func_proto)
return FunctionDoc(func_proto, content, domain)
def read_content(infile):
content = []
while True:
line = infile.readline()
if not line:
break
if re.match(r'\s*\*/\n', line):
break
else:
content.append(transform_content(line.rstrip()))
return content
def arg_repl(matchobj):
return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
def transform_content(content):
content = re.sub(r'^\s+\* ?', '', content)
content = re.sub(r'\|([^\s|]+)\|', arg_repl, content)
content = re.sub(r':enum:', ':macro:', content)
return content
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Generate API reference")
parser.add_argument('--header', type=argparse.FileType('rb', 0),
help='header inserted at the top of the page')
parser.add_argument('files', nargs='+', type=argparse.FileType('rb', 0),
help='source file')
args = parser.parse_args()
if args.header:
print args.header.read()
for infile in args.files:
make_api_ref(args.files)

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,10 @@
#ifndef SPDYLAYVER_H
#define SPDYLAYVER_H
/* Version number of spdylay release */
/**
* @macro
* Version number of spdylay release
*/
#define SPDYLAY_VERSION "@PACKAGE_VERSION@"
#endif /* SPDYLAYVER_H */