mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote branch 'origin/topic/jsiwek/doc-framework'
This commit is contained in:
commit
e7bde27f2d
54 changed files with 4006 additions and 62 deletions
22
CHANGES
22
CHANGES
|
@ -1,3 +1,25 @@
|
||||||
|
1.6-dev.80 Mon Apr 18 14:50:54 PDT 2011
|
||||||
|
|
||||||
|
- New framework for generating documentation from Bro scripts. (Jon
|
||||||
|
Siwek)
|
||||||
|
|
||||||
|
This includes:
|
||||||
|
|
||||||
|
- Changes to Bro's scanner/parser to facilitate automatic
|
||||||
|
generation of Bro policy script documentation in
|
||||||
|
reStructuredText format.
|
||||||
|
|
||||||
|
- New command line flags -Z/--doc-scripts to enable the new doc
|
||||||
|
generation mode.
|
||||||
|
|
||||||
|
- Changes to bifcl to pass comments starting with "##" through
|
||||||
|
into the generated .bro script.
|
||||||
|
|
||||||
|
- A "doc" build target for the top-level Makefile to first
|
||||||
|
generate reStructuredText for a defined set of Bro policy
|
||||||
|
scripts, and then run that through Sphinx to create HTML
|
||||||
|
documentation.
|
||||||
|
|
||||||
1.6-dev.78 Mon Apr 18 12:52:55 PDT 2011
|
1.6-dev.78 Mon Apr 18 12:52:55 PDT 2011
|
||||||
|
|
||||||
- Adding files to CMake build targets so they show up in generated IDE
|
- Adding files to CMake build targets so they show up in generated IDE
|
||||||
|
|
|
@ -51,6 +51,11 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh
|
||||||
"setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n")
|
"setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n")
|
||||||
|
|
||||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1)
|
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION LIMIT_COUNT 1)
|
||||||
|
string(REPLACE "." " " version_numbers ${VERSION})
|
||||||
|
separate_arguments(version_numbers)
|
||||||
|
list(GET version_numbers 0 VERSION_MAJOR)
|
||||||
|
list(GET version_numbers 1 VERSION_MINOR)
|
||||||
|
set(VERSION_MAJ_MIN "${VERSION_MAJOR}.${VERSION_MINOR}")
|
||||||
|
|
||||||
set(EXTRA_COMPILE_FLAGS "-Wall -Wno-unused")
|
set(EXTRA_COMPILE_FLAGS "-Wall -Wno-unused")
|
||||||
|
|
||||||
|
@ -170,8 +175,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(policy)
|
add_subdirectory(policy)
|
||||||
#add_subdirectory(scripts)
|
add_subdirectory(doc)
|
||||||
#add_subdirectory(doc)
|
|
||||||
|
|
||||||
include(CheckOptionalBuildSources)
|
include(CheckOptionalBuildSources)
|
||||||
|
|
||||||
|
|
7
Makefile
7
Makefile
|
@ -23,6 +23,13 @@ install: configured
|
||||||
|
|
||||||
clean: configured
|
clean: configured
|
||||||
( cd $(BUILD) && make clean )
|
( cd $(BUILD) && make clean )
|
||||||
|
( cd $(BUILD) && make doc-clean )
|
||||||
|
|
||||||
|
doc: configured
|
||||||
|
( cd $(BUILD) && make doc )
|
||||||
|
|
||||||
|
doc-clean: configured
|
||||||
|
( cd $(BUILD) && make doc-clean )
|
||||||
|
|
||||||
dist: cmake_version
|
dist: cmake_version
|
||||||
# Minimum Bro source package
|
# Minimum Bro source package
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
1.6-dev.78
|
1.6-dev.80
|
||||||
|
|
42
doc/CMakeLists.txt
Normal file
42
doc/CMakeLists.txt
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
set(POLICY_SRC_DIR ${PROJECT_SOURCE_DIR}/policy)
|
||||||
|
set(DOC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/out)
|
||||||
|
set(DOC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/source)
|
||||||
|
set(DOC_SOURCE_WORKDIR ${CMAKE_CURRENT_BINARY_DIR}/source)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE DOC_SOURCES FOLLOW_SYMLINKS "*")
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/conf.py
|
||||||
|
@ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_reST_docs.py.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/generate_reST_docs.py
|
||||||
|
@ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/BroToReST.py.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/BroToReST.py
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
add_custom_target(doc
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||||
|
${DOC_SOURCE_DIR}
|
||||||
|
${DOC_SOURCE_WORKDIR}
|
||||||
|
COMMAND python generate_reST_docs.py
|
||||||
|
COMMAND sphinx-build
|
||||||
|
-b html
|
||||||
|
-c ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
-d ${DOC_OUTPUT_DIR}/doctrees
|
||||||
|
${DOC_SOURCE_WORKDIR}
|
||||||
|
${DOC_OUTPUT_DIR}/html
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "[Sphinx] Generating Script Documentation"
|
||||||
|
VERBATIM
|
||||||
|
# SOURCES just adds stuff to IDE projects as a convienience
|
||||||
|
SOURCES ${DOC_SOURCES})
|
||||||
|
|
||||||
|
add_dependencies(doc bro doc-clean)
|
||||||
|
|
||||||
|
add_custom_target(doc-clean
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E remove_directory
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/source
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E remove_directory
|
||||||
|
${DOC_OUTPUT_DIR}
|
||||||
|
VERBATIM)
|
45
doc/README
45
doc/README
|
@ -1 +1,44 @@
|
||||||
TODO.
|
This directory contains scripts and templates that can be used to automate
|
||||||
|
the generation of Bro script documentation. Two build targets are defined
|
||||||
|
by CMake:
|
||||||
|
|
||||||
|
``make doc``
|
||||||
|
|
||||||
|
This target depends on a Python interpreter (>=2.5) and
|
||||||
|
`Sphinx <http://sphinx.pocoo.org/>`_ being installed. Sphinx can be
|
||||||
|
installed like::
|
||||||
|
|
||||||
|
> sudo easy_install sphinx
|
||||||
|
|
||||||
|
This target will also first build the bro binary if it is not already
|
||||||
|
since the generation of reStructuredText (reST) documentation from
|
||||||
|
Bro scripts is integrated within the parsing process.
|
||||||
|
|
||||||
|
After completion, HTML documentation can be located inside the CMake
|
||||||
|
``build/`` directory as ``build/doc/out/html``. The generated reST
|
||||||
|
documentation will be located in ``build/doc/source/policy``.
|
||||||
|
|
||||||
|
``make doc-clean``
|
||||||
|
|
||||||
|
This target removes Sphinx inputs and outputs from the CMake ``build/`` dir.
|
||||||
|
|
||||||
|
To schedule a script to be documented, edit ``scripts/generate_reST_docs.py.in``
|
||||||
|
and try adding the name of the script along with an optional script group to
|
||||||
|
the ``docs`` dictionary. That python script also shows other, more specialized
|
||||||
|
methods for generating documentation for some types of corner-cases.
|
||||||
|
|
||||||
|
When adding a new logical grouping for generated scripts, create a new
|
||||||
|
reST document in ``source/policy/<group_name>.rst`` and add some default
|
||||||
|
documentation. References to (and summaries of) documents associated with
|
||||||
|
the group get appended to this file during the ``make doc`` process.
|
||||||
|
|
||||||
|
The Sphinx source tree template in ``source/`` can be modified to add more
|
||||||
|
common/general documentation, style sheets, JavaScript, etc. The Sphinx
|
||||||
|
config file is produced from ``conf.py.in``, so that can be edited to change
|
||||||
|
various Sphinx options, like setting the default HTML rendering theme.
|
||||||
|
There is also a custom Sphinx domain implemented in ``source/ext/bro.py``
|
||||||
|
which adds some reST directives and roles that aid in generating useful
|
||||||
|
index entries and cross-references.
|
||||||
|
|
||||||
|
See ``example.bro`` for an example of how to document a Bro script such that
|
||||||
|
``make doc`` will be able to produce reST/HTML documentation for it.
|
||||||
|
|
215
doc/conf.py.in
Normal file
215
doc/conf.py.in
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Bro documentation build configuration file, created by sphinx-quickstart
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
sys.path.insert(0, os.path.abspath('source/ext'))
|
||||||
|
|
||||||
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = ['bro']
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['source/_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'Bro'
|
||||||
|
copyright = u'2011, Jon Siwek'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '@VERSION_MAJ_MIN@'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '@VERSION@'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
show_authors = True
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
html_theme = 'default'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
#html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['source/_static']
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'Brodoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
|
# The paper size ('letter' or 'a4').
|
||||||
|
#latex_paper_size = 'letter'
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#latex_font_size = '10pt'
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'Bro.tex', u'Bro Documentation',
|
||||||
|
u'Jon Siwek', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#latex_preamble = ''
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
('index', 'bro', u'Bro Documentation',
|
||||||
|
[u'Jon Siwek'], 1)
|
||||||
|
]
|
178
doc/example.bro
Normal file
178
doc/example.bro
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
##! This is an example script that demonstrates how to document. Comments
|
||||||
|
##! of the form ``##!`` are for the script summary. The contents of
|
||||||
|
##! these comments are transferred directly into the auto-generated
|
||||||
|
##! `reStructuredText <http://docutils.sourceforge.net/rst.html>`_
|
||||||
|
##! (reST) document's summary section.
|
||||||
|
##!
|
||||||
|
##! .. tip:: You can embed directives and roles within ``##``-stylized comments
|
||||||
|
##!
|
||||||
|
##! :Author: Jon Siwek <jsiwek@ncsa.illinois.edu>
|
||||||
|
|
||||||
|
# Comments that use a single pound sign (#) are not significant to
|
||||||
|
# a script's auto-generated documentation, but ones that use a
|
||||||
|
# double pound sign (##) do matter. In some cases, like record
|
||||||
|
# field comments, it's necessary to disambiguate the field with
|
||||||
|
# which a comment associates: e.g. "##<" can be used on the same line
|
||||||
|
# as a field to signify the comment relates to it and not the
|
||||||
|
# following field. "##<" is not meant for general use, just
|
||||||
|
# record/enum fields.
|
||||||
|
#
|
||||||
|
# Generally, the auto-doc comments (##) are associated with the
|
||||||
|
# next declaration/identifier found in the script, but the doc framework
|
||||||
|
# will track/render identifiers regardless of whether they have any
|
||||||
|
# of these special comments associated with them.
|
||||||
|
#
|
||||||
|
# The first sentence contained within the "##"-stylized comments for
|
||||||
|
# a given identifier is special in that it will be used as summary
|
||||||
|
# text in a table containing all such identifiers and short summaries.
|
||||||
|
# If there are no sentences (text terminated with '.'), then everything
|
||||||
|
# in the "##"-stylized comments up until the first empty comment
|
||||||
|
# is taken as the summary text for a given identifier.
|
||||||
|
|
||||||
|
# @load directives are self-documenting
|
||||||
|
@load notice
|
||||||
|
|
||||||
|
# "module" statements are self-documenting
|
||||||
|
module Example;
|
||||||
|
|
||||||
|
# redefinitions of "capture_filters" are self-documenting and
|
||||||
|
# go into the generated documentation's "Packet Filter" section
|
||||||
|
redef capture_filters += {
|
||||||
|
["ssl"] = "tcp port 443",
|
||||||
|
["nntps"] = "tcp port 563",
|
||||||
|
};
|
||||||
|
|
||||||
|
global example_ports = {
|
||||||
|
443/tcp, 563/tcp,
|
||||||
|
} &redef;
|
||||||
|
|
||||||
|
# redefinitions of "dpd_config" are self-documenting and
|
||||||
|
# go into the generated doc's "Port Analysis" section
|
||||||
|
redef dpd_config += {
|
||||||
|
[ANALYZER_SSL] = [$ports = example_ports]
|
||||||
|
};
|
||||||
|
|
||||||
|
# redefinitions of "Notice::Type" are self-documenting, but
|
||||||
|
# more information can be supplied in two different ways
|
||||||
|
redef enum Notice += {
|
||||||
|
## any number of this type of comment
|
||||||
|
## will document "Notice_One"
|
||||||
|
Notice_One,
|
||||||
|
Notice_Two, ##< any number of this type of comment
|
||||||
|
##< will document "Notice_Two"
|
||||||
|
Notice_Three,
|
||||||
|
Notice_Four,
|
||||||
|
};
|
||||||
|
|
||||||
|
# Anything declared in the export section will show up in the rendered
|
||||||
|
# documentation's "public interface" section
|
||||||
|
|
||||||
|
export {
|
||||||
|
|
||||||
|
# these headings don't mean anything special to the
|
||||||
|
# doc framework right now, I'm just including them
|
||||||
|
# to make it more clear to the reader how the doc
|
||||||
|
# framework will actually categorize a script's identifiers
|
||||||
|
|
||||||
|
############## types ################
|
||||||
|
|
||||||
|
# Note that I'm just mixing the "##" and "##<"
|
||||||
|
# types of comments in the following declarations
|
||||||
|
# as a demonstration. Normally, it would be good style
|
||||||
|
# to pick one and be consistent.
|
||||||
|
|
||||||
|
## documentation for "SimpleEnum"
|
||||||
|
## goes here.
|
||||||
|
type SimpleEnum: enum {
|
||||||
|
## and more specific info for "ONE"
|
||||||
|
## can span multiple lines
|
||||||
|
ONE,
|
||||||
|
TWO, ##< or more info like this for "TWO"
|
||||||
|
##< can span multiple lines
|
||||||
|
THREE,
|
||||||
|
};
|
||||||
|
|
||||||
|
## document the "SimpleEnum" redef here
|
||||||
|
redef enum SimpleEnum += {
|
||||||
|
FOUR, ##< and some documentation for "FOUR"
|
||||||
|
## also "FIVE" for good measure
|
||||||
|
FIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
## general documentation for a type "SimpleRecord"
|
||||||
|
## goes here.
|
||||||
|
type SimpleRecord: record {
|
||||||
|
## counts something
|
||||||
|
field1: count;
|
||||||
|
field2: bool; ##< toggles something
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
## general documentation for a type "ComplexRecord" goes here
|
||||||
|
type ComplexRecord: record {
|
||||||
|
field1: count; ##< counts something
|
||||||
|
field2: bool; ##< toggles something
|
||||||
|
field3: SimpleRecord;
|
||||||
|
msg: string &default="blah"; ##< attributes are self-documenting
|
||||||
|
} &redef;
|
||||||
|
|
||||||
|
############## options ################
|
||||||
|
# right now, I'm just defining an option as
|
||||||
|
# any const with &redef (something that can
|
||||||
|
# change at parse time, but not at run time.
|
||||||
|
|
||||||
|
## add documentation for "an_option" here
|
||||||
|
const an_option: set[addr, addr, string] &redef;
|
||||||
|
|
||||||
|
# default initialization will be self-documenting
|
||||||
|
const option_with_init = 0.01 secs &redef;
|
||||||
|
|
||||||
|
############## state variables ############
|
||||||
|
# right now, I'm defining this as any global
|
||||||
|
# that's not a function/event. doesn't matter
|
||||||
|
# if &redef attribute is present
|
||||||
|
|
||||||
|
## put some documentation for "a_var" here
|
||||||
|
global a_var: bool;
|
||||||
|
|
||||||
|
# attributes are self-documenting
|
||||||
|
global var_with_attr: count &persistent;
|
||||||
|
|
||||||
|
# it's fine if the type is inferred, that information is self-documenting
|
||||||
|
global var_without_explicit_type = "this works";
|
||||||
|
|
||||||
|
############## functions/events ############
|
||||||
|
|
||||||
|
## Summarize purpose of "a_function" here.
|
||||||
|
## Give more details about "a_function" here.
|
||||||
|
## Separating the documentation of the params/return values with
|
||||||
|
## empty comments is optional, but improves readability of script.
|
||||||
|
##
|
||||||
|
## tag: function arguments can be described
|
||||||
|
## like this
|
||||||
|
## msg: another param
|
||||||
|
##
|
||||||
|
## Returns: describe the return type here
|
||||||
|
global a_function: function(tag: string, msg: string): string;
|
||||||
|
|
||||||
|
## Summarize "an_event" here.
|
||||||
|
## Give more details about "an_event" here.
|
||||||
|
## name: describe the argument here
|
||||||
|
global an_event: event(name: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
# this function is documented in the "private interface" section
|
||||||
|
# of generated documentation and any "##"-stylized comments would also
|
||||||
|
# be rendered there
|
||||||
|
function function_without_proto(tag: string): string
|
||||||
|
{
|
||||||
|
return "blah";
|
||||||
|
}
|
||||||
|
|
||||||
|
# this record type is documented in the "private interface" section
|
||||||
|
# of generated documentation and any "##"-stylized comments would also
|
||||||
|
# be rendered there
|
||||||
|
type PrivateRecord: record {
|
||||||
|
field1: bool;
|
||||||
|
field2: count;
|
||||||
|
};
|
152
doc/scripts/BroToReST.py.in
Executable file
152
doc/scripts/BroToReST.py.in
Executable file
|
@ -0,0 +1,152 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
|
BRO = "@CMAKE_BINARY_DIR@/src/bro"
|
||||||
|
BROPATHDEV = "`@CMAKE_BINARY_DIR@/bro-path-dev`"
|
||||||
|
BRO_ARGS = "--doc-scripts"
|
||||||
|
DOC_DST_DIR = "@DOC_SOURCE_WORKDIR@/policy"
|
||||||
|
BROPATH = subprocess.Popen("@CMAKE_BINARY_DIR@/bro-path-dev", shell=True,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.readline()
|
||||||
|
|
||||||
|
class BroToReST:
|
||||||
|
"""A class to encapsulate the the generation of reST documentation from
|
||||||
|
a given Bro script.
|
||||||
|
"""
|
||||||
|
|
||||||
|
bro_src_file = None
|
||||||
|
doc_src_file = None
|
||||||
|
load_via_stdin = False
|
||||||
|
group = None
|
||||||
|
|
||||||
|
def __init__(self, src_file, load_method=False, search_dir=None, group=None):
|
||||||
|
"""
|
||||||
|
:param src_file: the file name of a Bro script (not a path)
|
||||||
|
:param load_method: T if script must be loaded by Bro via a stdin
|
||||||
|
redirection of "@load <script>", F if script can be loaded as
|
||||||
|
a command line argument to Bro
|
||||||
|
:param search_dir: a list of directories in which to search for
|
||||||
|
src_file. If None, the default BROPATH is used.
|
||||||
|
:param group: a string representing a logical group that the script's
|
||||||
|
documentation should belong to. A corresponding <group>.rst
|
||||||
|
document must be pre-existing in the policy/ dir of the source tree
|
||||||
|
used by Sphinx.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.bro_src_file = FindBroScript(src_file, search_dir)
|
||||||
|
self.load_via_stdin = load_method
|
||||||
|
self.group = group
|
||||||
|
|
||||||
|
# formulate doc_src_file from src_file
|
||||||
|
filename = os.path.basename(src_file)
|
||||||
|
basename, ext = os.path.splitext(filename)
|
||||||
|
if ext == ".bro":
|
||||||
|
self.doc_src_file = basename + ".rst"
|
||||||
|
else:
|
||||||
|
self.doc_src_file = filename + ".rst"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "bro_src_file: " + self.bro_src_file \
|
||||||
|
+ "\ndoc_src_file: " + self.doc_src_file \
|
||||||
|
+ "\ndoc_dst_file: " + os.path.join(DOC_DST_DIR, self.doc_src_file) \
|
||||||
|
+ "\nstdin_load: %s" % self.load_via_stdin \
|
||||||
|
+ "\ngroup: %s" % self.group
|
||||||
|
|
||||||
|
def GenDoc(self):
|
||||||
|
"""Generates the reST documentation for a Bro script and copies
|
||||||
|
both the documentation and original script into Sphinx source tree.
|
||||||
|
If the documentation belongs to a group, the necessary modifications
|
||||||
|
to add it to the group's documentation are done. Afterwards, any
|
||||||
|
files with a ".rst" suffix are removed for the working directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
bro_src_basename = os.path.basename(self.bro_src_file)
|
||||||
|
|
||||||
|
if self.load_via_stdin:
|
||||||
|
cmd = "echo '@load %s' | %s %s" % (bro_src_basename, BRO, BRO_ARGS)
|
||||||
|
else:
|
||||||
|
cmd = "%s %s %s" % (BRO, BRO_ARGS, self.bro_src_file)
|
||||||
|
|
||||||
|
p = subprocess.Popen(cmd, shell=True, env={"BROPATH": BROPATH})
|
||||||
|
|
||||||
|
if p.wait() == 0:
|
||||||
|
shutil.copy(self.doc_src_file, DOC_DST_DIR)
|
||||||
|
shutil.copy(self.bro_src_file, DOC_DST_DIR)
|
||||||
|
AppendToDocGroup(self.group, self.bro_src_file, self.doc_src_file)
|
||||||
|
|
||||||
|
for leftover in glob.glob("*.rst"):
|
||||||
|
os.remove(leftover)
|
||||||
|
|
||||||
|
def GenDocs(doc_dict, load_method=False):
|
||||||
|
"""Generates reST documentation for all scripts in the given dictionary.
|
||||||
|
|
||||||
|
:param doc_dict: a dictionary whose keys are file names of Bro scripts
|
||||||
|
(not paths), and whose value is the logical documentation group
|
||||||
|
it belongs to
|
||||||
|
:param load_method: T if script must be loaded by Bro via a stdin
|
||||||
|
redirection of "@load <script>", F if script can be loaded as
|
||||||
|
a command line argument to Bro
|
||||||
|
"""
|
||||||
|
|
||||||
|
for k, v in doc_dict.iteritems():
|
||||||
|
doc = BroToReST(k, load_method, group=v)
|
||||||
|
print "Generating reST document for " + k
|
||||||
|
doc.GenDoc()
|
||||||
|
|
||||||
|
def FindBroScript(src_file, search_dir=None):
|
||||||
|
"""Search a set of paths for a given Bro script and return the absolute
|
||||||
|
path to it.
|
||||||
|
|
||||||
|
:param src_file: the file name of a Bro script (not a path)
|
||||||
|
:param search_dir: a list of directories in which to search for
|
||||||
|
src_file. If None, the default BROPATH is used.
|
||||||
|
"""
|
||||||
|
if search_dir is None:
|
||||||
|
search_dir = string.split(BROPATH, ":")
|
||||||
|
for path in search_dir:
|
||||||
|
abs_path = os.path.join(path, src_file)
|
||||||
|
if os.path.exists(abs_path):
|
||||||
|
return abs_path
|
||||||
|
print >> sys.stderr, "Couldn't find '%s'" % src_file
|
||||||
|
return None
|
||||||
|
|
||||||
|
def AppendToDocGroup(group, src_file, doc_file):
|
||||||
|
"""Adds a reference to the given documentation for a Bro script
|
||||||
|
to the documentation file for it's associated group. Also, associated
|
||||||
|
summary text (comments marked up like "##!" in the original Bro script
|
||||||
|
source) are added.
|
||||||
|
|
||||||
|
:param group: a string representing a logical group that the script's
|
||||||
|
documentation should belong to. A corresponding <group>.rst
|
||||||
|
document must be pre-existing in the policy/ dir of the source tree
|
||||||
|
used by Sphinx.
|
||||||
|
:param src_file: a path to the original Bro script source file
|
||||||
|
:param doc_file: the file name of a script's generated reST document
|
||||||
|
"""
|
||||||
|
if group is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
group_file = os.path.join(DOC_DST_DIR, group + ".rst")
|
||||||
|
if not os.path.exists(group_file):
|
||||||
|
print >> sys.stderr, "Group file doesn't exist: " + group_file
|
||||||
|
return
|
||||||
|
|
||||||
|
summary_comments = []
|
||||||
|
|
||||||
|
with open(src_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
sum_pos = string.find(line, "##!")
|
||||||
|
if sum_pos != -1:
|
||||||
|
summary_comments.append(line[(sum_pos+3):])
|
||||||
|
|
||||||
|
doc_name, ext = os.path.splitext(doc_file)
|
||||||
|
|
||||||
|
with open(group_file, 'a') as f:
|
||||||
|
f.write("\n:doc:`%s`\n" % doc_name)
|
||||||
|
for line in summary_comments:
|
||||||
|
f.write(line)
|
71
doc/scripts/generate_reST_docs.py.in
Executable file
71
doc/scripts/generate_reST_docs.py.in
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
from BroToReST import *
|
||||||
|
|
||||||
|
# TODO: generate docs for more scripts
|
||||||
|
# TODO: the groups are just made up to test the functionality, fix them
|
||||||
|
|
||||||
|
# Scripts that can be loaded by bro via command line argument:
|
||||||
|
docs = {
|
||||||
|
"alarm.bro": "internal",
|
||||||
|
"arp.bro": "user",
|
||||||
|
"conn.bro": "internal",
|
||||||
|
"dhcp.bro": "user",
|
||||||
|
"dns.bro": "user",
|
||||||
|
"ftp.bro": "user",
|
||||||
|
"http.bro": "user",
|
||||||
|
"http-reply.bro": None,
|
||||||
|
"http-request.bro": None,
|
||||||
|
"irc.bro": "user",
|
||||||
|
"smtp.bro": "user",
|
||||||
|
"ssl.bro": "user",
|
||||||
|
"ssl-ciphers.bro": None,
|
||||||
|
"ssl-errors.bro": None,
|
||||||
|
"synflood.bro": "user",
|
||||||
|
"tcp.bro": "user",
|
||||||
|
"udp.bro": "user",
|
||||||
|
"weird.bro": "internal",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scripts that can't be loaded by bro via command line argument (possible
|
||||||
|
# due to dependency issues), but can be loaded via an @load on stdin:
|
||||||
|
stdin_docs = {
|
||||||
|
"notice.bro": "internal",
|
||||||
|
}
|
||||||
|
|
||||||
|
GenDocs(docs)
|
||||||
|
GenDocs(stdin_docs, True)
|
||||||
|
|
||||||
|
# The example documentation script doesn't live on the BROPATH, so
|
||||||
|
# explicitly generate the docs for it like this:
|
||||||
|
BroToReST("example.bro", False, ["@PROJECT_SOURCE_DIR@/doc"], group="internal").GenDoc()
|
||||||
|
|
||||||
|
# Generate documentation for stuff that's always loaded into bro by default:
|
||||||
|
cmd = "echo '' | %s %s" % (BRO, BRO_ARGS)
|
||||||
|
p = subprocess.Popen(cmd, shell=True, env={"BROPATH": BROPATH})
|
||||||
|
if p.wait() == 0:
|
||||||
|
for doc in glob.glob("*.rst"):
|
||||||
|
if doc == "<stdin>.rst":
|
||||||
|
os.remove(doc)
|
||||||
|
continue
|
||||||
|
|
||||||
|
basename, ext = os.path.splitext(doc)
|
||||||
|
basename2, ext = os.path.splitext(basename)
|
||||||
|
if ext == ".init":
|
||||||
|
src_file = basename
|
||||||
|
else:
|
||||||
|
src_file = basename + ".bro"
|
||||||
|
src_file = FindBroScript(src_file)
|
||||||
|
shutil.copy(src_file, DOC_DST_DIR)
|
||||||
|
shutil.copy(doc, DOC_DST_DIR)
|
||||||
|
if ext == ".bif":
|
||||||
|
AppendToDocGroup("bifs", src_file, doc)
|
||||||
|
else:
|
||||||
|
AppendToDocGroup("default", src_file, doc)
|
||||||
|
os.remove(doc)
|
64
doc/source/_static/showhide.js
Normal file
64
doc/source/_static/showhide.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// make literal blocks corresponding to identifier initial values
|
||||||
|
// hidden by default
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
var showText='(Show Value)';
|
||||||
|
var hideText='(Hide Value)';
|
||||||
|
|
||||||
|
var is_visible = false;
|
||||||
|
|
||||||
|
// select field-list tables that come before a literal block
|
||||||
|
tables = $('.highlight-python').prev('table.docutils.field-list');
|
||||||
|
|
||||||
|
tables.find('th.field-name').filter(function(index) {
|
||||||
|
return $(this).html() == "Default :";
|
||||||
|
}).next().append('<a href="#" class="toggleLink">'+showText+'</a>');
|
||||||
|
|
||||||
|
// hide all literal blocks that follow a field-list table
|
||||||
|
tables.next('.highlight-python').hide();
|
||||||
|
|
||||||
|
// register handler for clicking a "toggle" link
|
||||||
|
$('a.toggleLink').click(function() {
|
||||||
|
is_visible = !is_visible;
|
||||||
|
|
||||||
|
$(this).html( (!is_visible) ? showText : hideText);
|
||||||
|
|
||||||
|
// the link is inside a <table><tbody><tr><td> and the next
|
||||||
|
// literal block after the table is the literal block that we want
|
||||||
|
// to show/hide
|
||||||
|
$(this).parent().parent().parent().parent().next('.highlight-python').slideToggle('fast');
|
||||||
|
|
||||||
|
// override default link behavior
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// make "Private Interface" sections hidden by default
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
var showText='Show Private Interface (for internal use)';
|
||||||
|
var hideText='Hide Private Interface';
|
||||||
|
|
||||||
|
var is_visible = false;
|
||||||
|
|
||||||
|
// insert show/hide links
|
||||||
|
$('#private-interface').children(":first-child").after('<a href="#" class="privateToggle">'+showText+'</a>');
|
||||||
|
|
||||||
|
// wrap all sub-sections in a new div that can be hidden/shown
|
||||||
|
$('#private-interface').children(".section").wrapAll('<div class="private" />');
|
||||||
|
|
||||||
|
// hide the given class
|
||||||
|
$('.private').hide();
|
||||||
|
|
||||||
|
// register handler for clicking a "toggle" link
|
||||||
|
$('a.privateToggle').click(function() {
|
||||||
|
is_visible = !is_visible;
|
||||||
|
|
||||||
|
$(this).html( (!is_visible) ? showText : hideText);
|
||||||
|
|
||||||
|
$('.private').slideToggle('fast');
|
||||||
|
|
||||||
|
// override default link behavior
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
5
doc/source/_templates/layout.html
Normal file
5
doc/source/_templates/layout.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "!layout.html" %}
|
||||||
|
{% block extrahead %}
|
||||||
|
<script type="text/javascript" src="{{ pathto('_static/showhide.js', 1) }}"></script>
|
||||||
|
{{ super() }}
|
||||||
|
{% endblock %}
|
121
doc/source/builtins.rst
Normal file
121
doc/source/builtins.rst
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
Builtin Types and Attributes
|
||||||
|
============================
|
||||||
|
|
||||||
|
Types
|
||||||
|
-----
|
||||||
|
|
||||||
|
The Bro scripting language supports the following built-in types.
|
||||||
|
|
||||||
|
.. TODO: add documentation
|
||||||
|
|
||||||
|
.. bro:type:: void
|
||||||
|
|
||||||
|
.. bro:type:: bool
|
||||||
|
|
||||||
|
.. bro:type:: int
|
||||||
|
|
||||||
|
.. bro:type:: count
|
||||||
|
|
||||||
|
.. bro:type:: counter
|
||||||
|
|
||||||
|
.. bro:type:: double
|
||||||
|
|
||||||
|
.. bro:type:: time
|
||||||
|
|
||||||
|
.. bro:type:: interval
|
||||||
|
|
||||||
|
.. bro:type:: string
|
||||||
|
|
||||||
|
.. bro:type:: pattern
|
||||||
|
|
||||||
|
.. bro:type:: enum
|
||||||
|
|
||||||
|
.. bro:type:: timer
|
||||||
|
|
||||||
|
.. bro:type:: port
|
||||||
|
|
||||||
|
.. bro:type:: addr
|
||||||
|
|
||||||
|
.. bro:type:: net
|
||||||
|
|
||||||
|
.. bro:type:: subnet
|
||||||
|
|
||||||
|
.. bro:type:: any
|
||||||
|
|
||||||
|
.. bro:type:: table
|
||||||
|
|
||||||
|
.. bro:type:: union
|
||||||
|
|
||||||
|
.. bro:type:: record
|
||||||
|
|
||||||
|
.. bro:type:: types
|
||||||
|
|
||||||
|
.. bro:type:: func
|
||||||
|
|
||||||
|
.. bro:type:: file
|
||||||
|
|
||||||
|
.. bro:type:: vector
|
||||||
|
|
||||||
|
.. TODO: below are kind of "special cases" that bro knows about?
|
||||||
|
|
||||||
|
.. bro:type:: set
|
||||||
|
|
||||||
|
.. bro:type:: function
|
||||||
|
|
||||||
|
.. bro:type:: event
|
||||||
|
|
||||||
|
.. TODO: Notice will get documented as part of notice.bro, which can eventually
|
||||||
|
be referenced here once that documentation is auto-generated.
|
||||||
|
|
||||||
|
.. bro:type:: Notice
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
|
||||||
|
The Bro scripting language supports the following built-in attributes.
|
||||||
|
|
||||||
|
.. TODO: add documentation
|
||||||
|
|
||||||
|
.. bro:attr:: &optional
|
||||||
|
|
||||||
|
.. bro:attr:: &default
|
||||||
|
|
||||||
|
.. bro:attr:: &redef
|
||||||
|
|
||||||
|
.. bro:attr:: &rotate_interval
|
||||||
|
|
||||||
|
.. bro:attr:: &rotate_size
|
||||||
|
|
||||||
|
.. bro:attr:: &add_func
|
||||||
|
|
||||||
|
.. bro:attr:: &delete_func
|
||||||
|
|
||||||
|
.. bro:attr:: &expire_func
|
||||||
|
|
||||||
|
.. bro:attr:: &read_expire
|
||||||
|
|
||||||
|
.. bro:attr:: &write_expire
|
||||||
|
|
||||||
|
.. bro:attr:: &create_expire
|
||||||
|
|
||||||
|
.. bro:attr:: &persistent
|
||||||
|
|
||||||
|
.. bro:attr:: &synchronized
|
||||||
|
|
||||||
|
.. bro:attr:: &postprocessor
|
||||||
|
|
||||||
|
.. bro:attr:: &encrypt
|
||||||
|
|
||||||
|
.. bro:attr:: &match
|
||||||
|
|
||||||
|
.. bro:attr:: &disable_print_hook
|
||||||
|
|
||||||
|
.. bro:attr:: &raw_output
|
||||||
|
|
||||||
|
.. bro:attr:: &mergeable
|
||||||
|
|
||||||
|
.. bro:attr:: &priority
|
||||||
|
|
||||||
|
.. bro:attr:: &group
|
||||||
|
|
||||||
|
.. bro:attr:: (&tracked)
|
19
doc/source/common.rst
Normal file
19
doc/source/common.rst
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Common Documentation
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. _common_port_analysis_doc:
|
||||||
|
|
||||||
|
Port Analysis
|
||||||
|
-------------
|
||||||
|
|
||||||
|
TODO: add some stuff here
|
||||||
|
|
||||||
|
.. _common_packet_filter_doc:
|
||||||
|
|
||||||
|
Packet Filter
|
||||||
|
-------------
|
||||||
|
|
||||||
|
TODO: add some stuff here
|
||||||
|
|
||||||
|
.. note:: Filters are only relevant when dynamic protocol detection (DPD)
|
||||||
|
is explicitly turned off (Bro release 1.6 enabled DPD by default).
|
167
doc/source/ext/bro.py
Normal file
167
doc/source/ext/bro.py
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
"""
|
||||||
|
The Bro domain for Sphinx.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setup(Sphinx):
|
||||||
|
Sphinx.add_domain(BroDomain)
|
||||||
|
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.domains import Domain, ObjType, Index
|
||||||
|
from sphinx.locale import l_, _
|
||||||
|
from sphinx.directives import ObjectDescription
|
||||||
|
from sphinx.roles import XRefRole
|
||||||
|
from sphinx.util.nodes import make_refnode
|
||||||
|
import string
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from docutils.parsers.rst import Directive
|
||||||
|
from docutils.parsers.rst import directives
|
||||||
|
from docutils.parsers.rst.roles import set_classes
|
||||||
|
|
||||||
|
class BroGeneric(ObjectDescription):
|
||||||
|
def add_target_and_index(self, name, sig, signode):
|
||||||
|
targetname = self.objtype + '-' + name
|
||||||
|
if targetname not in self.state.document.ids:
|
||||||
|
signode['names'].append(targetname)
|
||||||
|
signode['ids'].append(targetname)
|
||||||
|
signode['first'] = (not self.names)
|
||||||
|
self.state.document.note_explicit_target(signode)
|
||||||
|
|
||||||
|
objects = self.env.domaindata['bro']['objects']
|
||||||
|
key = (self.objtype, name)
|
||||||
|
# this is commented out mostly just to avoid having a special directive
|
||||||
|
# for events in order to avoid the duplicate warnings in that case
|
||||||
|
"""
|
||||||
|
if key in objects:
|
||||||
|
self.env.warn(self.env.docname,
|
||||||
|
'duplicate description of %s %s, ' %
|
||||||
|
(self.objtype, name) +
|
||||||
|
'other instance in ' +
|
||||||
|
self.env.doc2path(objects[key]),
|
||||||
|
self.lineno)
|
||||||
|
"""
|
||||||
|
objects[key] = self.env.docname
|
||||||
|
indextext = self.get_index_text(self.objtype, name)
|
||||||
|
if indextext:
|
||||||
|
self.indexnode['entries'].append(('single', indextext,
|
||||||
|
targetname, targetname))
|
||||||
|
|
||||||
|
def get_index_text(self, objectname, name):
|
||||||
|
return _('%s (%s)') % (name, self.objtype)
|
||||||
|
|
||||||
|
def handle_signature(self, sig, signode):
|
||||||
|
signode += addnodes.desc_name("", sig)
|
||||||
|
return sig
|
||||||
|
|
||||||
|
class BroNamespace(BroGeneric):
|
||||||
|
def add_target_and_index(self, name, sig, signode):
|
||||||
|
targetname = self.objtype + '-' + name
|
||||||
|
if targetname not in self.state.document.ids:
|
||||||
|
signode['names'].append(targetname)
|
||||||
|
signode['ids'].append(targetname)
|
||||||
|
signode['first'] = (not self.names)
|
||||||
|
self.state.document.note_explicit_target(signode)
|
||||||
|
|
||||||
|
objects = self.env.domaindata['bro']['objects']
|
||||||
|
key = (self.objtype, name)
|
||||||
|
objects[key] = self.env.docname
|
||||||
|
indextext = self.get_index_text(self.objtype, name)
|
||||||
|
self.indexnode['entries'].append(('single', indextext,
|
||||||
|
targetname, targetname))
|
||||||
|
self.indexnode['entries'].append(('single',
|
||||||
|
"namespaces; %s" % (sig),
|
||||||
|
targetname, targetname))
|
||||||
|
|
||||||
|
def get_index_text(self, objectname, name):
|
||||||
|
return _('%s (namespace); %s') % (name, self.env.docname)
|
||||||
|
|
||||||
|
def handle_signature(self, sig, signode):
|
||||||
|
signode += addnodes.desc_name("", sig)
|
||||||
|
return sig
|
||||||
|
|
||||||
|
class BroEnum(BroGeneric):
|
||||||
|
def add_target_and_index(self, name, sig, signode):
|
||||||
|
targetname = self.objtype + '-' + name
|
||||||
|
if targetname not in self.state.document.ids:
|
||||||
|
signode['names'].append(targetname)
|
||||||
|
signode['ids'].append(targetname)
|
||||||
|
signode['first'] = (not self.names)
|
||||||
|
self.state.document.note_explicit_target(signode)
|
||||||
|
|
||||||
|
objects = self.env.domaindata['bro']['objects']
|
||||||
|
key = (self.objtype, name)
|
||||||
|
objects[key] = self.env.docname
|
||||||
|
indextext = self.get_index_text(self.objtype, name)
|
||||||
|
#self.indexnode['entries'].append(('single', indextext,
|
||||||
|
# targetname, targetname))
|
||||||
|
m = sig.split()
|
||||||
|
self.indexnode['entries'].append(('single',
|
||||||
|
"%s (enum values); %s" % (m[1], m[0]),
|
||||||
|
targetname, targetname))
|
||||||
|
|
||||||
|
def handle_signature(self, sig, signode):
|
||||||
|
m = sig.split()
|
||||||
|
name = m[0]
|
||||||
|
signode += addnodes.desc_name("", name)
|
||||||
|
return name
|
||||||
|
|
||||||
|
class BroIdentifier(BroGeneric):
|
||||||
|
def get_index_text(self, objectname, name):
|
||||||
|
return name
|
||||||
|
|
||||||
|
class BroAttribute(BroGeneric):
|
||||||
|
def get_index_text(self, objectname, name):
|
||||||
|
return _('%s (attribute)') % (name)
|
||||||
|
|
||||||
|
class BroDomain(Domain):
|
||||||
|
"""Bro domain."""
|
||||||
|
name = 'bro'
|
||||||
|
label = 'Bro'
|
||||||
|
|
||||||
|
object_types = {
|
||||||
|
'type': ObjType(l_('type'), 'type'),
|
||||||
|
'namespace': ObjType(l_('namespace'), 'namespace'),
|
||||||
|
'id': ObjType(l_('id'), 'id'),
|
||||||
|
'enum': ObjType(l_('enum'), 'enum'),
|
||||||
|
'attr': ObjType(l_('attr'), 'attr'),
|
||||||
|
}
|
||||||
|
|
||||||
|
directives = {
|
||||||
|
'type': BroGeneric,
|
||||||
|
'namespace': BroNamespace,
|
||||||
|
'id': BroIdentifier,
|
||||||
|
'enum': BroEnum,
|
||||||
|
'attr': BroAttribute,
|
||||||
|
}
|
||||||
|
|
||||||
|
roles = {
|
||||||
|
'type': XRefRole(),
|
||||||
|
'namespace': XRefRole(),
|
||||||
|
'id': XRefRole(),
|
||||||
|
'enum': XRefRole(),
|
||||||
|
'attr': XRefRole(),
|
||||||
|
}
|
||||||
|
|
||||||
|
initial_data = {
|
||||||
|
'objects': {}, # fullname -> docname, objtype
|
||||||
|
}
|
||||||
|
|
||||||
|
def clear_doc(self, docname):
|
||||||
|
for (typ, name), doc in self.data['objects'].items():
|
||||||
|
if doc == docname:
|
||||||
|
del self.data['objects'][typ, name]
|
||||||
|
|
||||||
|
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
|
||||||
|
contnode):
|
||||||
|
objects = self.data['objects']
|
||||||
|
objtypes = self.objtypes_for_role(typ)
|
||||||
|
for objtype in objtypes:
|
||||||
|
if (objtype, target) in objects:
|
||||||
|
return make_refnode(builder, fromdocname,
|
||||||
|
objects[objtype, target],
|
||||||
|
objtype + '-' + target,
|
||||||
|
contnode, target + ' ' + objtype)
|
||||||
|
|
||||||
|
def get_objects(self):
|
||||||
|
for (typ, name), docname in self.data['objects'].iteritems():
|
||||||
|
yield name, name, typ, docname, typ + '-' + name, 1
|
24
doc/source/index.rst
Normal file
24
doc/source/index.rst
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
.. Bro documentation master file
|
||||||
|
|
||||||
|
Welcome to Bro's documentation!
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
common
|
||||||
|
builtins
|
||||||
|
policy/default
|
||||||
|
policy/user
|
||||||
|
policy/bifs
|
||||||
|
policy/internal
|
||||||
|
policy/index
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
4
doc/source/policy/bifs.rst
Normal file
4
doc/source/policy/bifs.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Built-In Functions (BIFs)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Here's a list of all documentation for BIFs that Bro provides:
|
3
doc/source/policy/default.rst
Normal file
3
doc/source/policy/default.rst
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Bro Scripts Loaded by Default
|
||||||
|
=============================
|
||||||
|
|
10
doc/source/policy/index.rst
Normal file
10
doc/source/policy/index.rst
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Index of All Policy Script Documentation
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
*
|
3
doc/source/policy/internal.rst
Normal file
3
doc/source/policy/internal.rst
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Internal Policy Scripts
|
||||||
|
=======================
|
||||||
|
|
3
doc/source/policy/user.rst
Normal file
3
doc/source/policy/user.rst
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
User-Facing Policy Scripts
|
||||||
|
==========================
|
||||||
|
|
42
src/Attr.cc
42
src/Attr.cc
|
@ -49,6 +49,37 @@ void Attr::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Attr::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(":bro:attr:`");
|
||||||
|
AddTag(d);
|
||||||
|
d->Add("`");
|
||||||
|
|
||||||
|
if ( expr )
|
||||||
|
{
|
||||||
|
d->SP();
|
||||||
|
d->Add("=");
|
||||||
|
d->SP();
|
||||||
|
|
||||||
|
if ( expr->Type()->Tag() == TYPE_FUNC )
|
||||||
|
d->Add(":bro:type:`func`");
|
||||||
|
|
||||||
|
else if ( expr->Type()->Tag() == TYPE_ENUM )
|
||||||
|
{
|
||||||
|
d->Add(":bro:enum:`");
|
||||||
|
expr->Describe(d);
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->Add("``");
|
||||||
|
expr->Describe(d);
|
||||||
|
d-> Add("``");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Attr::AddTag(ODesc* d) const
|
void Attr::AddTag(ODesc* d) const
|
||||||
{
|
{
|
||||||
if ( d->IsBinary() )
|
if ( d->IsBinary() )
|
||||||
|
@ -161,6 +192,17 @@ void Attributes::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Attributes::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
loop_over_list(*attrs, i)
|
||||||
|
{
|
||||||
|
if ( i > 0 )
|
||||||
|
d->Add(" ");
|
||||||
|
|
||||||
|
(*attrs)[i]->DescribeReST(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Attributes::CheckAttr(Attr* a)
|
void Attributes::CheckAttr(Attr* a)
|
||||||
{
|
{
|
||||||
switch ( a->Tag() ) {
|
switch ( a->Tag() ) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
{ return tag == ATTR_REDEF || tag == ATTR_OPTIONAL; }
|
{ return tag == ATTR_REDEF || tag == ATTR_OPTIONAL; }
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void AddTag(ODesc* d) const;
|
void AddTag(ODesc* d) const;
|
||||||
|
@ -73,6 +74,7 @@ public:
|
||||||
void RemoveAttr(attr_tag t);
|
void RemoveAttr(attr_tag t);
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
attr_list* Attrs() { return attrs; }
|
attr_list* Attrs() { return attrs; }
|
||||||
|
|
||||||
|
|
16
src/BroBifDoc.cc
Normal file
16
src/BroBifDoc.cc
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "BroDoc.h"
|
||||||
|
#include "BroBifDoc.h"
|
||||||
|
|
||||||
|
BroBifDoc::BroBifDoc(const std::string& sourcename) : BroDoc(sourcename)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This needs to do something different than parent class's version.
|
||||||
|
void BroBifDoc::WriteDocFile() const
|
||||||
|
{
|
||||||
|
BroDoc::WriteDocFile();
|
||||||
|
}
|
18
src/BroBifDoc.h
Normal file
18
src/BroBifDoc.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef brobifdoc_h
|
||||||
|
#define brobifdoc_h
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "BroDoc.h"
|
||||||
|
|
||||||
|
class BroBifDoc : public BroDoc {
|
||||||
|
public:
|
||||||
|
BroBifDoc(const std::string& sourcename);
|
||||||
|
virtual ~BroBifDoc() { }
|
||||||
|
|
||||||
|
void WriteDocFile() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
361
src/BroDoc.cc
Normal file
361
src/BroDoc.cc
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "BroDoc.h"
|
||||||
|
#include "BroDocObj.h"
|
||||||
|
|
||||||
|
BroDoc::BroDoc(const std::string& sourcename)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stdout, "Documenting source: %s\n", sourcename.c_str());
|
||||||
|
#endif
|
||||||
|
source_filename = sourcename.substr(sourcename.find_last_of('/') + 1);
|
||||||
|
|
||||||
|
size_t ext_pos = source_filename.find_last_of('.');
|
||||||
|
std::string ext = source_filename.substr(ext_pos + 1);
|
||||||
|
|
||||||
|
if ( ext_pos == std::string::npos || ext != "bro" )
|
||||||
|
{
|
||||||
|
if ( source_filename != "bro.init" && source_filename != "<stdin>" )
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: documenting file without .bro extension: %s\n",
|
||||||
|
sourcename.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Force the reST documentation file to be "bro.init.rst".
|
||||||
|
ext_pos = std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reST_filename = source_filename.substr(0, ext_pos);
|
||||||
|
reST_filename += ".rst";
|
||||||
|
reST_file = fopen(reST_filename.c_str(), "w");
|
||||||
|
|
||||||
|
if ( ! reST_file )
|
||||||
|
fprintf(stderr, "Failed to open %s", reST_filename.c_str());
|
||||||
|
#ifdef DEBUG
|
||||||
|
else
|
||||||
|
fprintf(stdout, "Created reST document: %s\n", reST_filename.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
BroDoc::~BroDoc()
|
||||||
|
{
|
||||||
|
if ( reST_file && fclose( reST_file ) )
|
||||||
|
fprintf(stderr, "Failed to close %s", reST_filename.c_str());
|
||||||
|
|
||||||
|
FreeBroDocObjPtrList(all);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::AddImport(const std::string& s)
|
||||||
|
{
|
||||||
|
size_t ext_pos = s.find_last_of('.');
|
||||||
|
|
||||||
|
if ( ext_pos == std::string::npos )
|
||||||
|
imports.push_back(s);
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( s.substr(ext_pos + 1) == "bro" )
|
||||||
|
imports.push_back(s.substr(0, ext_pos));
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Warning: skipped documenting @load of file "
|
||||||
|
"without .bro extension: %s\n", s.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::SetPacketFilter(const std::string& s)
|
||||||
|
{
|
||||||
|
packet_filter = s;
|
||||||
|
size_t pos1 = s.find("{\n");
|
||||||
|
size_t pos2 = s.find("}");
|
||||||
|
|
||||||
|
if ( pos1 != std::string::npos && pos2 != std::string::npos )
|
||||||
|
packet_filter = s.substr(pos1 + 2, pos2 - 2);
|
||||||
|
|
||||||
|
bool has_non_whitespace = false;
|
||||||
|
|
||||||
|
for ( std::string::const_iterator it = packet_filter.begin();
|
||||||
|
it != packet_filter.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( *it != ' ' && *it != '\t' && *it != '\n' && *it != '\r' )
|
||||||
|
{
|
||||||
|
has_non_whitespace = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! has_non_whitespace )
|
||||||
|
packet_filter.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::AddPortAnalysis(const std::string& analyzer,
|
||||||
|
const std::string& ports)
|
||||||
|
{
|
||||||
|
std::string reST_string = analyzer + "::\n" + ports + "\n\n";
|
||||||
|
port_analysis.push_back(reST_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteDocFile() const
|
||||||
|
{
|
||||||
|
WriteToDoc(".. Automatically generated. Do not edit.\n\n");
|
||||||
|
|
||||||
|
WriteSectionHeading(source_filename.c_str(), '=');
|
||||||
|
|
||||||
|
WriteToDoc("\n:download:`Original Source File <%s>`\n\n",
|
||||||
|
source_filename.c_str());
|
||||||
|
|
||||||
|
WriteSectionHeading("Overview", '-');
|
||||||
|
WriteStringList("%s\n", "%s\n\n", summary);
|
||||||
|
|
||||||
|
if ( ! imports.empty() )
|
||||||
|
{
|
||||||
|
WriteToDoc(":Imports: ");
|
||||||
|
WriteStringList(":doc:`%s`, ", ":doc:`%s`\n", imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteToDoc("\n");
|
||||||
|
|
||||||
|
WriteInterface("Summary", '~', '#', true, true);
|
||||||
|
|
||||||
|
if ( ! modules.empty() )
|
||||||
|
{
|
||||||
|
WriteSectionHeading("Namespaces", '~');
|
||||||
|
WriteStringList(".. bro:namespace:: %s\n", modules);
|
||||||
|
WriteToDoc("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! notices.empty() )
|
||||||
|
WriteBroDocObjList(notices, "Notices", '~');
|
||||||
|
|
||||||
|
WriteInterface("Public Interface", '-', '~', true, false);
|
||||||
|
|
||||||
|
if ( ! port_analysis.empty() )
|
||||||
|
{
|
||||||
|
WriteSectionHeading("Port Analysis", '-');
|
||||||
|
WriteToDoc(":ref:`More Information <common_port_analysis_doc>`\n\n");
|
||||||
|
WriteStringList("%s", port_analysis);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! packet_filter.empty() )
|
||||||
|
{
|
||||||
|
WriteSectionHeading("Packet Filter", '-');
|
||||||
|
WriteToDoc(":ref:`More Information <common_packet_filter_doc>`\n\n");
|
||||||
|
WriteToDoc("Filters added::\n\n");
|
||||||
|
WriteToDoc("%s\n", packet_filter.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
BroDocObjList::const_iterator it;
|
||||||
|
bool hasPrivateIdentifiers = false;
|
||||||
|
|
||||||
|
for ( it = all.begin(); it != all.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( ! IsPublicAPI(*it) )
|
||||||
|
{
|
||||||
|
hasPrivateIdentifiers = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hasPrivateIdentifiers )
|
||||||
|
WriteInterface("Private Interface", '-', '~', false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteInterface(const char* heading, char underline,
|
||||||
|
char sub, bool isPublic, bool isShort) const
|
||||||
|
{
|
||||||
|
WriteSectionHeading(heading, underline);
|
||||||
|
WriteBroDocObjList(options, isPublic, "Options", sub, isShort);
|
||||||
|
WriteBroDocObjList(constants, isPublic, "Constants", sub, isShort);
|
||||||
|
WriteBroDocObjList(state_vars, isPublic, "State Variables", sub, isShort);
|
||||||
|
WriteBroDocObjList(types, isPublic, "Types", sub, isShort);
|
||||||
|
WriteBroDocObjList(events, isPublic, "Events", sub, isShort);
|
||||||
|
WriteBroDocObjList(functions, isPublic, "Functions", sub, isShort);
|
||||||
|
WriteBroDocObjList(redefs, isPublic, "Redefinitions", sub, isShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteStringList(const char* format, const char* last_format,
|
||||||
|
const std::list<std::string>& l) const
|
||||||
|
{
|
||||||
|
if ( l.empty() )
|
||||||
|
{
|
||||||
|
WriteToDoc("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::string>::const_iterator it;
|
||||||
|
std::list<std::string>::const_iterator last = l.end();
|
||||||
|
last--;
|
||||||
|
|
||||||
|
for ( it = l.begin(); it != last; ++it )
|
||||||
|
WriteToDoc(format, it->c_str());
|
||||||
|
|
||||||
|
WriteToDoc(last_format, last->c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjTable(const BroDocObjList& l) const
|
||||||
|
{
|
||||||
|
int max_id_col = 0;
|
||||||
|
int max_com_col = 0;
|
||||||
|
BroDocObjList::const_iterator it;
|
||||||
|
|
||||||
|
for ( it = l.begin(); it != l.end(); ++it )
|
||||||
|
{
|
||||||
|
int c = (*it)->ColumnSize();
|
||||||
|
|
||||||
|
if ( c > max_id_col )
|
||||||
|
max_id_col = c;
|
||||||
|
|
||||||
|
c = (*it)->LongestShortDescLen();
|
||||||
|
|
||||||
|
if ( c > max_com_col )
|
||||||
|
max_com_col = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start table.
|
||||||
|
WriteRepeatedChar('=', max_id_col);
|
||||||
|
WriteToDoc(" ");
|
||||||
|
|
||||||
|
if ( max_com_col == 0 )
|
||||||
|
WriteToDoc("=");
|
||||||
|
else
|
||||||
|
WriteRepeatedChar('=', max_com_col);
|
||||||
|
|
||||||
|
WriteToDoc("\n");
|
||||||
|
|
||||||
|
for ( it = l.begin(); it != l.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( it != l.begin() )
|
||||||
|
WriteToDoc("\n\n");
|
||||||
|
(*it)->WriteReSTCompact(reST_file, max_id_col);
|
||||||
|
}
|
||||||
|
|
||||||
|
// End table.
|
||||||
|
WriteToDoc("\n");
|
||||||
|
WriteRepeatedChar('=', max_id_col);
|
||||||
|
WriteToDoc(" ");
|
||||||
|
|
||||||
|
if ( max_com_col == 0 )
|
||||||
|
WriteToDoc("=");
|
||||||
|
else
|
||||||
|
WriteRepeatedChar('=', max_com_col);
|
||||||
|
|
||||||
|
WriteToDoc("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjList(const BroDocObjList& l, bool wantPublic,
|
||||||
|
const char* heading, char underline, bool isShort) const
|
||||||
|
{
|
||||||
|
if ( l.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
BroDocObjList::const_iterator it;
|
||||||
|
bool (*f_ptr)(const BroDocObj* o) = 0;
|
||||||
|
|
||||||
|
if ( wantPublic )
|
||||||
|
f_ptr = IsPublicAPI;
|
||||||
|
else
|
||||||
|
f_ptr = IsPrivateAPI;
|
||||||
|
|
||||||
|
it = std::find_if(l.begin(), l.end(), f_ptr);
|
||||||
|
|
||||||
|
if ( it == l.end() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
WriteSectionHeading(heading, underline);
|
||||||
|
|
||||||
|
BroDocObjList filtered_list;
|
||||||
|
|
||||||
|
while ( it != l.end() )
|
||||||
|
{
|
||||||
|
filtered_list.push_back(*it);
|
||||||
|
it = find_if(++it, l.end(), f_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isShort )
|
||||||
|
WriteBroDocObjTable(filtered_list);
|
||||||
|
else
|
||||||
|
WriteBroDocObjList(filtered_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjList(const BroDocObjMap& m, bool wantPublic,
|
||||||
|
const char* heading, char underline, bool isShort) const
|
||||||
|
{
|
||||||
|
BroDocObjMap::const_iterator it;
|
||||||
|
BroDocObjList l;
|
||||||
|
|
||||||
|
for ( it = m.begin(); it != m.end(); ++it )
|
||||||
|
l.push_back(it->second);
|
||||||
|
|
||||||
|
WriteBroDocObjList(l, wantPublic, heading, underline, isShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjList(const BroDocObjList& l, const char* heading,
|
||||||
|
char underline) const
|
||||||
|
{
|
||||||
|
WriteSectionHeading(heading, underline);
|
||||||
|
WriteBroDocObjList(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjList(const BroDocObjList& l) const
|
||||||
|
{
|
||||||
|
for ( BroDocObjList::const_iterator it = l.begin(); it != l.end(); ++it )
|
||||||
|
(*it)->WriteReST(reST_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteBroDocObjList(const BroDocObjMap& m, const char* heading,
|
||||||
|
char underline) const
|
||||||
|
{
|
||||||
|
BroDocObjMap::const_iterator it;
|
||||||
|
BroDocObjList l;
|
||||||
|
|
||||||
|
for ( it = m.begin(); it != m.end(); ++it )
|
||||||
|
l.push_back(it->second);
|
||||||
|
|
||||||
|
WriteBroDocObjList(l, heading, underline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteToDoc(const char* format, ...) const
|
||||||
|
{
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, format);
|
||||||
|
vfprintf(reST_file, format, argp);
|
||||||
|
va_end(argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteSectionHeading(const char* heading, char underline) const
|
||||||
|
{
|
||||||
|
WriteToDoc("%s\n", heading);
|
||||||
|
WriteRepeatedChar(underline, strlen(heading));
|
||||||
|
WriteToDoc("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::WriteRepeatedChar(char c, size_t n) const
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < n; ++i )
|
||||||
|
WriteToDoc("%c", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::FreeBroDocObjPtrList(BroDocObjList& l)
|
||||||
|
{
|
||||||
|
for ( BroDocObjList::const_iterator it = l.begin(); it != l.end(); ++it )
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
l.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDoc::AddFunction(BroDocObj* o)
|
||||||
|
{
|
||||||
|
BroDocObjMap::const_iterator it = functions.find(o->Name());
|
||||||
|
if ( it == functions.end() )
|
||||||
|
{
|
||||||
|
functions[o->Name()] = o;
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
functions[o->Name()]->Combine(o);
|
||||||
|
}
|
362
src/BroDoc.h
Normal file
362
src/BroDoc.h
Normal file
|
@ -0,0 +1,362 @@
|
||||||
|
#ifndef brodoc_h
|
||||||
|
#define brodoc_h
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "BroDocObj.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to gather all data relevant to the automatic generation
|
||||||
|
* of a reStructuredText (reST) document from a given Bro script.
|
||||||
|
*/
|
||||||
|
class BroDoc {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* BroDoc constructor
|
||||||
|
* Given a Bro script, opens new file in the current working directory
|
||||||
|
* that will contain reST documentation generated from the parsing
|
||||||
|
* of the Bro script. The new reST file will be named similar to
|
||||||
|
* the filename of the Bro script that generates it, except any
|
||||||
|
* ".bro" file extension is stripped and ".rst" takes it place.
|
||||||
|
* If the filename doesn't end in ".bro", then ".rst" is just appended.
|
||||||
|
* @param sourcename The name of the Bro script for which to generate
|
||||||
|
* documentation. May contain a path.
|
||||||
|
*/
|
||||||
|
BroDoc(const std::string& sourcename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BroDoc destructor
|
||||||
|
* Closes the file that was opened by the constructor and frees up
|
||||||
|
* memory taken by BroDocObj objects.
|
||||||
|
*/
|
||||||
|
virtual ~BroDoc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write out full reST documentation for the Bro script that was parsed.
|
||||||
|
* BroDoc's default implementation of this function will care
|
||||||
|
* about whether declarations made in the Bro script are part of
|
||||||
|
* the public versus private interface (whether things are declared in
|
||||||
|
* the export section).
|
||||||
|
*/
|
||||||
|
virtual void WriteDocFile() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules some summarizing text to be output directly into the reST doc.
|
||||||
|
* This should be called whenever the scanner sees a line in the Bro script
|
||||||
|
* starting with "##!"
|
||||||
|
* @param s The summary text to add to the reST doc.
|
||||||
|
*/
|
||||||
|
void AddSummary(const std::string& s) { summary.push_back(s); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules an import (@load) to be documented.
|
||||||
|
* If the script being loaded has a .bro suffix, it is internally stripped.
|
||||||
|
* This should be called whenever the scanner sees an @load.
|
||||||
|
* @param s The name of the imported script.
|
||||||
|
*/
|
||||||
|
void AddImport(const std::string& s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules a namespace (module) to be documented.
|
||||||
|
* This should be called whenever the parser sees a TOK_MODULE.
|
||||||
|
* @param s The namespace (module) identifier's name.
|
||||||
|
*/
|
||||||
|
void AddModule(const std::string& s) { modules.push_back(s); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the way the script changes the "capture_filters" table.
|
||||||
|
* This is determined by the scanner checking for changes to
|
||||||
|
* the "capture_filters" table after each of Bro's input scripts
|
||||||
|
* (given as command line arguments to Bro) are finished being parsed.
|
||||||
|
* @param s The value "capture_filters" as given by TableVal::Describe()
|
||||||
|
*/
|
||||||
|
void SetPacketFilter(const std::string& s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a given set of ports being associated
|
||||||
|
* with a particular analyzer as a result of the current script
|
||||||
|
* being loaded -- the way the "dpd_config" table is changed.
|
||||||
|
* @param analyzer An analyzer that changed the "dpd_config" table.
|
||||||
|
* @param ports The set of ports assigned to the analyzer in table.
|
||||||
|
*/
|
||||||
|
void AddPortAnalysis(const std::string& analyzer, const std::string& ports);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a script option. An option is
|
||||||
|
* defined as any variable in the script that is declared 'const'
|
||||||
|
* and has the '&redef' attribute.
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script option and
|
||||||
|
* also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddOption(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
options.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a script constant. An option is
|
||||||
|
* defined as any variable in the script that is declared 'const'
|
||||||
|
* and does *not* have the '&redef' attribute.
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script constant and
|
||||||
|
* also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddConstant(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
constants.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a script state variable. A state variable
|
||||||
|
* is defined as any variable in the script that is declared 'global'
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script state variable
|
||||||
|
* and also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddStateVar(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
state_vars.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a type declared by the script.
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script option and
|
||||||
|
* also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddType(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
types.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a Notice (enum redef) declared by script
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the Notice and also
|
||||||
|
* any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddNotice(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
notices.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of an event declared by the script.
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script event and
|
||||||
|
* also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddEvent(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
events.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a function declared by the script.
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script function and
|
||||||
|
* also any associated comments about it.
|
||||||
|
*/
|
||||||
|
void AddFunction(BroDocObj* o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules documentation of a redef done by the script
|
||||||
|
* @param o A pointer to a BroDocObj which contains the internal
|
||||||
|
* Bro language representation of the script identifier
|
||||||
|
* that was redefined and also any associated comments.
|
||||||
|
*/
|
||||||
|
void AddRedef(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
redefs.push_back(o);
|
||||||
|
all.push_back(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the Bro script source file for which reST
|
||||||
|
* documentation is being generated.
|
||||||
|
* @return A char* to the start of the source file's name.
|
||||||
|
*/
|
||||||
|
const char* GetSourceFileName() const
|
||||||
|
{
|
||||||
|
return source_filename.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the generated reST documentation file.
|
||||||
|
* @return A char* to the start of the generated reST file's name.
|
||||||
|
*/
|
||||||
|
const char* GetOutputFileName() const
|
||||||
|
{
|
||||||
|
return reST_filename.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FILE* reST_file;
|
||||||
|
std::string reST_filename;
|
||||||
|
std::string source_filename;
|
||||||
|
std::string packet_filter;
|
||||||
|
|
||||||
|
std::list<std::string> modules;
|
||||||
|
std::list<std::string> summary;
|
||||||
|
std::list<std::string> imports;
|
||||||
|
std::list<std::string> port_analysis;
|
||||||
|
|
||||||
|
typedef std::list<const BroDocObj*> BroDocObjList;
|
||||||
|
typedef std::map<std::string, BroDocObj*> BroDocObjMap;
|
||||||
|
|
||||||
|
BroDocObjList options;
|
||||||
|
BroDocObjList constants;
|
||||||
|
BroDocObjList state_vars;
|
||||||
|
BroDocObjList types;
|
||||||
|
BroDocObjList notices;
|
||||||
|
BroDocObjList events;
|
||||||
|
BroDocObjMap functions;
|
||||||
|
BroDocObjList redefs;
|
||||||
|
|
||||||
|
BroDocObjList all;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a list of strings to the reST document.
|
||||||
|
* If the list is empty, prints a newline character.
|
||||||
|
* @param format A printf style format string for elements of the list
|
||||||
|
* except for the last one in the list
|
||||||
|
* @param last_format A printf style format string to use for the last
|
||||||
|
* element of the list
|
||||||
|
* @param l A reference to a list of strings
|
||||||
|
*/
|
||||||
|
void WriteStringList(const char* format, const char* last_format,
|
||||||
|
const std::list<std::string>& l) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see WriteStringList(const char*, const char*,
|
||||||
|
* const std::list<std::string>&>)
|
||||||
|
*/
|
||||||
|
void WriteStringList(const char* format,
|
||||||
|
const std::list<std::string>& l) const
|
||||||
|
{
|
||||||
|
WriteStringList(format, format, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a table of BroDocObj's to the reST document
|
||||||
|
* @param l A list of BroDocObj pointers
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjTable(const BroDocObjList& l) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a list of BroDocObj objects to the reST document
|
||||||
|
* @param l A list of BroDocObj pointers
|
||||||
|
* @param wantPublic If true, filter out objects that are not declared
|
||||||
|
* in the global scope. If false, filter out those that are in
|
||||||
|
* the global scope.
|
||||||
|
* @param heading The title of the section to create in the reST doc.
|
||||||
|
* @param underline The character to use to underline the reST
|
||||||
|
* section heading.
|
||||||
|
* @param isShort Whether to write the full documentation or a "short"
|
||||||
|
* version (a single sentence)
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjList(const BroDocObjList& l, bool wantPublic,
|
||||||
|
const char* heading, char underline,
|
||||||
|
bool isShort) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the BroDocObjMap into a BroDocObjList and the writes that list
|
||||||
|
* to the reST document
|
||||||
|
* @see WriteBroDocObjList(const BroDocObjList&, bool, const char*, char,
|
||||||
|
bool)
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjList(const BroDocObjMap& m, bool wantPublic,
|
||||||
|
const char* heading, char underline,
|
||||||
|
bool isShort) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a list of BroDocObj objects to the reST document
|
||||||
|
* @param l A list of BroDocObj pointers
|
||||||
|
* @param heading The title of the section to create in the reST doc.
|
||||||
|
* @param underline The character to use to underline the reST
|
||||||
|
* section heading.
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjList(const BroDocObjList& l, const char* heading,
|
||||||
|
char underline) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a list of BroDocObj objects to the reST document
|
||||||
|
* @param l A list of BroDocObj pointers
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjList(const BroDocObjList& l) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the BroDocObjMap into a BroDocObjList and the writes that list
|
||||||
|
* to the reST document
|
||||||
|
* @see WriteBroDocObjList(const BroDocObjList&, const char*, char)
|
||||||
|
*/
|
||||||
|
void WriteBroDocObjList(const BroDocObjMap& m, const char* heading,
|
||||||
|
char underline) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper to fprintf() that always uses the reST document
|
||||||
|
* for the FILE* argument.
|
||||||
|
* @param format A printf style format string.
|
||||||
|
*/
|
||||||
|
void WriteToDoc(const char* format, ...) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out a reST section heading
|
||||||
|
* @param heading The title of the heading to create
|
||||||
|
* @param underline The character to use to underline the section title
|
||||||
|
* within the reST document
|
||||||
|
*/
|
||||||
|
void WriteSectionHeading(const char* heading, char underline) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out given number of characters to reST document
|
||||||
|
* @param c the character to write
|
||||||
|
* @param n the number of characters to write
|
||||||
|
*/
|
||||||
|
void WriteRepeatedChar(char c, size_t n) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out the reST for either the script's public or private interface
|
||||||
|
* @param heading The title of the interfaces section heading
|
||||||
|
* @param underline The underline character to use for the interface
|
||||||
|
* section
|
||||||
|
* @param subunderline The underline character to use for interface
|
||||||
|
* sub-sections
|
||||||
|
* @param isPublic Whether to write out the public or private script
|
||||||
|
* interface
|
||||||
|
* @param isShort Whether to write out the full documentation or a "short"
|
||||||
|
* description (a single sentence)
|
||||||
|
*/
|
||||||
|
void WriteInterface(const char* heading, char underline, char subunderline,
|
||||||
|
bool isPublic, bool isShort) const;
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees memory allocated to BroDocObj's objects in a given list.
|
||||||
|
* @param a reference to a list of BroDocObj pointers
|
||||||
|
*/
|
||||||
|
void FreeBroDocObjPtrList(BroDocObjList& l);
|
||||||
|
|
||||||
|
static bool IsPublicAPI(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
return o->IsPublicAPI();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsPrivateAPI(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
return ! o->IsPublicAPI();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
168
src/BroDocObj.cc
Normal file
168
src/BroDocObj.cc
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include "ID.h"
|
||||||
|
#include "BroDocObj.h"
|
||||||
|
|
||||||
|
BroDocObj::BroDocObj(const ID* id, std::list<std::string>*& reST,
|
||||||
|
bool is_fake)
|
||||||
|
{
|
||||||
|
broID = id;
|
||||||
|
reST_doc_strings = reST;
|
||||||
|
reST = 0;
|
||||||
|
is_fake_id = is_fake;
|
||||||
|
use_role = 0;
|
||||||
|
FormulateShortDesc();
|
||||||
|
}
|
||||||
|
|
||||||
|
BroDocObj::~BroDocObj()
|
||||||
|
{
|
||||||
|
if ( reST_doc_strings )
|
||||||
|
delete reST_doc_strings;
|
||||||
|
|
||||||
|
if ( is_fake_id )
|
||||||
|
delete broID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDocObj::WriteReSTCompact(FILE* file, int max_col) const
|
||||||
|
{
|
||||||
|
ODesc desc;
|
||||||
|
desc.SetQuotes(1);
|
||||||
|
broID->DescribeReSTShort(&desc);
|
||||||
|
|
||||||
|
fprintf(file, "%s", desc.Description());
|
||||||
|
|
||||||
|
std::list<std::string>::const_iterator it;
|
||||||
|
|
||||||
|
for ( it = short_desc.begin(); it != short_desc.end(); ++it )
|
||||||
|
{
|
||||||
|
int start_col;
|
||||||
|
|
||||||
|
if ( it == short_desc.begin() )
|
||||||
|
start_col = max_col - desc.Len() + 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start_col = max_col + 1;
|
||||||
|
fprintf(file, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < start_col; ++i )
|
||||||
|
fprintf(file, " ");
|
||||||
|
|
||||||
|
fprintf(file, "%s", it->c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BroDocObj::LongestShortDescLen() const
|
||||||
|
{
|
||||||
|
size_t max = 0;
|
||||||
|
|
||||||
|
std::list<std::string>::const_iterator it;
|
||||||
|
|
||||||
|
for ( it = short_desc.begin(); it != short_desc.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( it->size() > max )
|
||||||
|
max = it->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDocObj::FormulateShortDesc()
|
||||||
|
{
|
||||||
|
if ( ! reST_doc_strings )
|
||||||
|
return;
|
||||||
|
|
||||||
|
short_desc.clear();
|
||||||
|
std::list<std::string>::const_iterator it;
|
||||||
|
|
||||||
|
for ( it = reST_doc_strings->begin();
|
||||||
|
it != reST_doc_strings->end(); ++it )
|
||||||
|
{
|
||||||
|
// The short description stops at the first sentence or the
|
||||||
|
// first empty comment.
|
||||||
|
size_t end = it->find_first_of(".");
|
||||||
|
|
||||||
|
if ( end == string::npos )
|
||||||
|
{
|
||||||
|
std::string::const_iterator s;
|
||||||
|
bool empty = true;
|
||||||
|
|
||||||
|
for ( s = it->begin(); s != it->end(); ++s )
|
||||||
|
{
|
||||||
|
if ( *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' )
|
||||||
|
{
|
||||||
|
empty = false;
|
||||||
|
short_desc.push_back(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
short_desc.push_back(it->substr(0, end + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDocObj::WriteReST(FILE* file) const
|
||||||
|
{
|
||||||
|
int indent_spaces = 3;
|
||||||
|
ODesc desc;
|
||||||
|
desc.SetIndentSpaces(indent_spaces);
|
||||||
|
desc.SetQuotes(1);
|
||||||
|
|
||||||
|
broID->DescribeReST(&desc, use_role);
|
||||||
|
|
||||||
|
fprintf(file, "%s", desc.Description());
|
||||||
|
|
||||||
|
if ( HasDocumentation() )
|
||||||
|
{
|
||||||
|
fprintf(file, "\n");
|
||||||
|
std::list<std::string>::const_iterator it;
|
||||||
|
|
||||||
|
for ( it = reST_doc_strings->begin();
|
||||||
|
it != reST_doc_strings->end(); ++it)
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < indent_spaces; ++i )
|
||||||
|
fprintf(file, " ");
|
||||||
|
|
||||||
|
fprintf(file, "%s\n", it->c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(file, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int BroDocObj::ColumnSize() const
|
||||||
|
{
|
||||||
|
ODesc desc;
|
||||||
|
desc.SetQuotes(1);
|
||||||
|
broID->DescribeReSTShort(&desc);
|
||||||
|
return desc.Len();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BroDocObj::IsPublicAPI() const
|
||||||
|
{
|
||||||
|
return (broID->Scope() == SCOPE_GLOBAL) ||
|
||||||
|
(broID->Scope() == SCOPE_MODULE && broID->IsExport());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroDocObj::Combine(const BroDocObj* o)
|
||||||
|
{
|
||||||
|
if ( o->reST_doc_strings )
|
||||||
|
{
|
||||||
|
if ( ! reST_doc_strings )
|
||||||
|
reST_doc_strings = new std::list<std::string>();
|
||||||
|
|
||||||
|
reST_doc_strings->splice(reST_doc_strings->end(),
|
||||||
|
*(o->reST_doc_strings));
|
||||||
|
}
|
||||||
|
|
||||||
|
delete o;
|
||||||
|
FormulateShortDesc();
|
||||||
|
}
|
123
src/BroDocObj.h
Normal file
123
src/BroDocObj.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#ifndef brodocobj_h
|
||||||
|
#define brodocobj_h
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "ID.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class wraps a Bro script identifier, providing methods relevant
|
||||||
|
* to automatic generation of reStructuredText (reST) documentation for it.
|
||||||
|
*/
|
||||||
|
class BroDocObj {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* BroDocObj constructor
|
||||||
|
* @param id a pointer to an identifier that is to be documented
|
||||||
|
* @param reST a reference to a pointer of a list of strings that
|
||||||
|
* represent the reST documentation for the ID. The pointer
|
||||||
|
* will be set to 0 after this constructor finishes.
|
||||||
|
* @param is_fake whether the ID* is a dummy just for doc purposes
|
||||||
|
*/
|
||||||
|
BroDocObj(const ID* id, std::list<std::string>*& reST,
|
||||||
|
bool is_fake = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BroDocObj destructor
|
||||||
|
* Deallocates the memory associated with the list of reST strings
|
||||||
|
*/
|
||||||
|
~BroDocObj();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the reST representation of this object which includes
|
||||||
|
* 1) a reST friendly description of the ID
|
||||||
|
* 2) "##" or "##<" stylized comments.
|
||||||
|
* Anything after these style of comments is inserted as-is into
|
||||||
|
* the reST document.
|
||||||
|
* @param file The (already opened) file to write the reST to.
|
||||||
|
*/
|
||||||
|
void WriteReST(FILE* file) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a compact version of the ID and associated documentation
|
||||||
|
* for insertion into a table.
|
||||||
|
* @param file The (already opened) file to write the reST to.
|
||||||
|
* @param max_col The maximum length of the first table column
|
||||||
|
*/
|
||||||
|
void WriteReSTCompact(FILE* file, int max_col) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the column size required by the reST representation of the ID
|
||||||
|
*/
|
||||||
|
int ColumnSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether this documentation is part of the public API. In
|
||||||
|
* other words, this means that the identifier is declared as part of
|
||||||
|
* the global scope (has GLOBAL namespace or is exported from another
|
||||||
|
* namespace).
|
||||||
|
* @return true if the identifier is part of the script's public API
|
||||||
|
*/
|
||||||
|
bool IsPublicAPI() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this object has documentation (## comments)
|
||||||
|
* @return true if the ID has comments associated with it
|
||||||
|
*/
|
||||||
|
bool HasDocumentation() const
|
||||||
|
{
|
||||||
|
return reST_doc_strings && reST_doc_strings->size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether this object will use reST role (T) or directive (F)
|
||||||
|
* notation for the wrapped identifier. Roles are usually used
|
||||||
|
* for cross-referencing.
|
||||||
|
*/
|
||||||
|
bool UseRole() const { return use_role; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b whether this object will use reST role (T) or directive (F)
|
||||||
|
* notation for the wrapped identifier. Roles are usually used
|
||||||
|
* for cross-referencing.
|
||||||
|
*/
|
||||||
|
void SetRole(bool b) { use_role = b; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append any reST documentation strings in a given BroDocObj to this
|
||||||
|
* object's list and then delete the given BroDocObj
|
||||||
|
* @param o a pointer to a BroDocObj to subsume
|
||||||
|
*/
|
||||||
|
void Combine(const BroDocObj* o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the wrapped identifier
|
||||||
|
*/
|
||||||
|
const char* Name() const { return broID->Name(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the longest string element of the short description's list of
|
||||||
|
* strings
|
||||||
|
*/
|
||||||
|
int LongestShortDescLen() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<std::string>* reST_doc_strings;
|
||||||
|
std::list<std::string> short_desc;
|
||||||
|
const ID* broID;
|
||||||
|
bool is_fake_id; /**< Whether the ID* is a dummy just for doc purposes */
|
||||||
|
bool use_role; /**< Whether to use a reST role or directive for the ID */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the short_desc member to be a subset of reST_doc_strings.
|
||||||
|
* Specifically, short_desc will be everything in reST_doc_strings
|
||||||
|
* up until the first period or first empty string list element found.
|
||||||
|
*/
|
||||||
|
void FormulateShortDesc();
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -285,6 +285,9 @@ set(bro_SRCS
|
||||||
BitTorrent.cc
|
BitTorrent.cc
|
||||||
BitTorrentTracker.cc
|
BitTorrentTracker.cc
|
||||||
BPF_Program.cc
|
BPF_Program.cc
|
||||||
|
BroBifDoc.cc
|
||||||
|
BroDoc.cc
|
||||||
|
BroDocObj.cc
|
||||||
BroString.cc
|
BroString.cc
|
||||||
CCL.cc
|
CCL.cc
|
||||||
ChunkedIO.cc
|
ChunkedIO.cc
|
||||||
|
|
20
src/Desc.cc
20
src/Desc.cc
|
@ -41,6 +41,7 @@ ODesc::ODesc(desc_type t, BroFile* arg_f)
|
||||||
want_quotes = 0;
|
want_quotes = 0;
|
||||||
do_flush = 1;
|
do_flush = 1;
|
||||||
include_stats = 0;
|
include_stats = 0;
|
||||||
|
indent_with_spaces = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ODesc::~ODesc()
|
ODesc::~ODesc()
|
||||||
|
@ -67,6 +68,12 @@ void ODesc::PopIndent()
|
||||||
NL();
|
NL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ODesc::PopIndentNoNL()
|
||||||
|
{
|
||||||
|
if ( --indent_level < 0 )
|
||||||
|
internal_error("ODesc::PopIndent underflow");
|
||||||
|
}
|
||||||
|
|
||||||
void ODesc::Add(const char* s, int do_indent)
|
void ODesc::Add(const char* s, int do_indent)
|
||||||
{
|
{
|
||||||
unsigned int n = strlen(s);
|
unsigned int n = strlen(s);
|
||||||
|
@ -179,8 +186,17 @@ void ODesc::AddBytes(const BroString* s)
|
||||||
|
|
||||||
void ODesc::Indent()
|
void ODesc::Indent()
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < indent_level; ++i )
|
if ( indent_with_spaces > 0 )
|
||||||
Add("\t", 0);
|
{
|
||||||
|
for ( int i = 0; i < indent_level; ++i )
|
||||||
|
for ( int j = 0; j < indent_with_spaces; ++j )
|
||||||
|
Add(" ", 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < indent_level; ++i )
|
||||||
|
Add("\t", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,12 @@ public:
|
||||||
|
|
||||||
void PushIndent();
|
void PushIndent();
|
||||||
void PopIndent();
|
void PopIndent();
|
||||||
|
void PopIndentNoNL();
|
||||||
int GetIndentLevel() const { return indent_level; }
|
int GetIndentLevel() const { return indent_level; }
|
||||||
|
|
||||||
|
int IndentSpaces() const { return indent_with_spaces; }
|
||||||
|
void SetIndentSpaces(int i) { indent_with_spaces = i; }
|
||||||
|
|
||||||
void Add(const char* s, int do_indent=1);
|
void Add(const char* s, int do_indent=1);
|
||||||
void AddN(const char* s, int len) { AddBytes(s, len); }
|
void AddN(const char* s, int len) { AddBytes(s, len); }
|
||||||
void Add(int i);
|
void Add(int i);
|
||||||
|
@ -135,6 +139,7 @@ protected:
|
||||||
int want_quotes;
|
int want_quotes;
|
||||||
int do_flush;
|
int do_flush;
|
||||||
int include_stats;
|
int include_stats;
|
||||||
|
int indent_with_spaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
129
src/ID.cc
129
src/ID.cc
|
@ -607,6 +607,135 @@ void ID::DescribeExtended(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ID::DescribeReSTShort(ODesc* d) const
|
||||||
|
{
|
||||||
|
if ( is_type )
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
else
|
||||||
|
d->Add(":bro:id:`");
|
||||||
|
|
||||||
|
d->Add(name);
|
||||||
|
d->Add("`");
|
||||||
|
|
||||||
|
if ( type )
|
||||||
|
{
|
||||||
|
d->Add(": ");
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
|
||||||
|
if ( ! is_type && type->GetTypeID() )
|
||||||
|
d->Add(type->GetTypeID());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TypeTag t = type->Tag();
|
||||||
|
|
||||||
|
switch ( t ) {
|
||||||
|
case TYPE_TABLE:
|
||||||
|
d->Add(type->IsSet() ? "set" : type_name(t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_FUNC:
|
||||||
|
d->Add(type->AsFuncType()->IsEvent() ? "event" : type_name(t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
d->Add(type_name(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( attrs )
|
||||||
|
{
|
||||||
|
d->SP();
|
||||||
|
attrs->DescribeReST(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ID::DescribeReST(ODesc* d, bool is_role) const
|
||||||
|
{
|
||||||
|
if ( is_role )
|
||||||
|
{
|
||||||
|
if ( is_type )
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
else
|
||||||
|
d->Add(":bro:id:`");
|
||||||
|
d->Add(name);
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( is_type )
|
||||||
|
d->Add(".. bro:type:: ");
|
||||||
|
else
|
||||||
|
d->Add(".. bro:id:: ");
|
||||||
|
d->Add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->PushIndent();
|
||||||
|
d->NL();
|
||||||
|
|
||||||
|
if ( type )
|
||||||
|
{
|
||||||
|
d->Add(":Type: ");
|
||||||
|
|
||||||
|
if ( ! is_type && type->GetTypeID() )
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(type->GetTypeID());
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
type->DescribeReST(d);
|
||||||
|
|
||||||
|
d->NL();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( attrs )
|
||||||
|
{
|
||||||
|
d->Add(":Attributes: ");
|
||||||
|
attrs->DescribeReST(d);
|
||||||
|
d->NL();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( val && type &&
|
||||||
|
type->Tag() != TYPE_FUNC &&
|
||||||
|
type->InternalType() != TYPE_INTERNAL_VOID )
|
||||||
|
{
|
||||||
|
d->Add(":Default:");
|
||||||
|
|
||||||
|
if ( type->InternalType() == TYPE_INTERNAL_OTHER )
|
||||||
|
{
|
||||||
|
switch ( type->Tag() ) {
|
||||||
|
case TYPE_TABLE:
|
||||||
|
if ( val->AsTable()->Length() == 0 )
|
||||||
|
{
|
||||||
|
d->Add(" ``{}``");
|
||||||
|
d->NL();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Fall-through.
|
||||||
|
|
||||||
|
default:
|
||||||
|
d->NL();
|
||||||
|
d->NL();
|
||||||
|
d->Add("::");
|
||||||
|
d->NL();
|
||||||
|
d->PushIndent();
|
||||||
|
val->DescribeReST(d);
|
||||||
|
d->PopIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->SP();
|
||||||
|
val->DescribeReST(d);
|
||||||
|
d->NL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void ID::UpdateValID()
|
void ID::UpdateValID()
|
||||||
{
|
{
|
||||||
|
|
3
src/ID.h
3
src/ID.h
|
@ -84,6 +84,9 @@ public:
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
// Adds type and value to description.
|
// Adds type and value to description.
|
||||||
void DescribeExtended(ODesc* d) const;
|
void DescribeExtended(ODesc* d) const;
|
||||||
|
// Produces a description that's reST-ready.
|
||||||
|
void DescribeReST(ODesc* d, bool is_role=false) const;
|
||||||
|
void DescribeReSTShort(ODesc* d) const;
|
||||||
|
|
||||||
bool Serialize(SerialInfo* info) const;
|
bool Serialize(SerialInfo* info) const;
|
||||||
static ID* Unserialize(UnserialInfo* info);
|
static ID* Unserialize(UnserialInfo* info);
|
||||||
|
|
|
@ -330,6 +330,29 @@ public:
|
||||||
dst = 0; \
|
dst = 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UNSERIALIZE_OPTIONAL_STR_DEL(dst, del) \
|
||||||
|
{ \
|
||||||
|
bool has_it; \
|
||||||
|
if ( ! info->s->Read(&has_it, "has_" #dst) ) \
|
||||||
|
{ \
|
||||||
|
delete del; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if ( has_it ) \
|
||||||
|
{ \
|
||||||
|
info->s->Read(&dst, 0, "has_" #dst); \
|
||||||
|
if ( ! dst ) \
|
||||||
|
{ \
|
||||||
|
delete del; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
else \
|
||||||
|
dst = 0; \
|
||||||
|
}
|
||||||
|
|
||||||
#define UNSERIALIZE_OPTIONAL_STATIC(dst, unserialize, del) \
|
#define UNSERIALIZE_OPTIONAL_STATIC(dst, unserialize, del) \
|
||||||
{ \
|
{ \
|
||||||
bool has_it; \
|
bool has_it; \
|
||||||
|
|
279
src/Type.cc
279
src/Type.cc
|
@ -10,6 +10,12 @@
|
||||||
#include "Scope.h"
|
#include "Scope.h"
|
||||||
#include "Serializer.h"
|
#include "Serializer.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
extern int generate_documentation;
|
||||||
|
|
||||||
const char* type_name(TypeTag t)
|
const char* type_name(TypeTag t)
|
||||||
{
|
{
|
||||||
static char errbuf[512];
|
static char errbuf[512];
|
||||||
|
@ -44,6 +50,7 @@ BroType::BroType(TypeTag t, bool arg_base_type)
|
||||||
tag = t;
|
tag = t;
|
||||||
is_network_order = 0;
|
is_network_order = 0;
|
||||||
base_type = arg_base_type;
|
base_type = arg_base_type;
|
||||||
|
type_id = 0;
|
||||||
|
|
||||||
switch ( tag ) {
|
switch ( tag ) {
|
||||||
case TYPE_VOID:
|
case TYPE_VOID:
|
||||||
|
@ -105,6 +112,12 @@ BroType::BroType(TypeTag t, bool arg_base_type)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BroType::~BroType()
|
||||||
|
{
|
||||||
|
if ( type_id )
|
||||||
|
delete [] type_id;
|
||||||
|
}
|
||||||
|
|
||||||
int BroType::MatchesIndex(ListExpr*& /* index */) const
|
int BroType::MatchesIndex(ListExpr*& /* index */) const
|
||||||
{
|
{
|
||||||
return DOES_NOT_MATCH_INDEX;
|
return DOES_NOT_MATCH_INDEX;
|
||||||
|
@ -139,6 +152,13 @@ void BroType::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BroType::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(type_name(Tag()));
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
|
||||||
void BroType::SetError()
|
void BroType::SetError()
|
||||||
{
|
{
|
||||||
tag = TYPE_ERROR;
|
tag = TYPE_ERROR;
|
||||||
|
@ -195,8 +215,9 @@ BroType* BroType::Unserialize(UnserialInfo* info, TypeTag want)
|
||||||
if ( ! t )
|
if ( ! t )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// For base types, we return our current instance.
|
// For base types, we return our current instance
|
||||||
if ( t->base_type )
|
// if not in "documentation mode".
|
||||||
|
if ( t->base_type && ! generate_documentation )
|
||||||
{
|
{
|
||||||
BroType* t2 = ::base_type(TypeTag(t->tag));
|
BroType* t2 = ::base_type(TypeTag(t->tag));
|
||||||
Unref(t);
|
Unref(t);
|
||||||
|
@ -230,6 +251,11 @@ bool BroType::DoSerialize(SerialInfo* info) const
|
||||||
void* null = NULL;
|
void* null = NULL;
|
||||||
SERIALIZE(null);
|
SERIALIZE(null);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
SERIALIZE_OPTIONAL_STR(type_id);
|
||||||
|
}
|
||||||
|
|
||||||
info->s->WriteCloseTag("Type");
|
info->s->WriteCloseTag("Type");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -260,6 +286,11 @@ bool BroType::DoUnserialize(UnserialInfo* info)
|
||||||
// attributes_type" for backwards compatibility.
|
// attributes_type" for backwards compatibility.
|
||||||
UNSERIALIZE_OPTIONAL(not_used_either, BroType::Unserialize(info, TYPE_RECORD));
|
UNSERIALIZE_OPTIONAL(not_used_either, BroType::Unserialize(info, TYPE_RECORD));
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
UNSERIALIZE_OPTIONAL_STR(type_id);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,6 +444,52 @@ void IndexType::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IndexType::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
|
||||||
|
if ( IsSet() )
|
||||||
|
d->Add("set");
|
||||||
|
else
|
||||||
|
d->Add(type_name(Tag()));
|
||||||
|
|
||||||
|
d->Add("` ");
|
||||||
|
d->Add("[");
|
||||||
|
|
||||||
|
loop_over_list(*IndexTypes(), i)
|
||||||
|
{
|
||||||
|
if ( i > 0 )
|
||||||
|
d->Add(", ");
|
||||||
|
|
||||||
|
const BroType* t = (*IndexTypes())[i];
|
||||||
|
|
||||||
|
if ( t->GetTypeID() )
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(t->GetTypeID());
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t->DescribeReST(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Add("]");
|
||||||
|
|
||||||
|
if ( yield_type )
|
||||||
|
{
|
||||||
|
d->Add(" of ");
|
||||||
|
|
||||||
|
if ( yield_type->GetTypeID() )
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(yield_type->GetTypeID());
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield_type->DescribeReST(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool IndexType::IsSubNetIndex() const
|
bool IndexType::IsSubNetIndex() const
|
||||||
{
|
{
|
||||||
const type_list* types = indices->Types();
|
const type_list* types = indices->Types();
|
||||||
|
@ -647,6 +724,30 @@ void FuncType::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FuncType::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(is_event ? "event" : "function");
|
||||||
|
d->Add("`");
|
||||||
|
d->Add(" (");
|
||||||
|
args->DescribeFieldsReST(d, true);
|
||||||
|
d->Add(")");
|
||||||
|
|
||||||
|
if ( yield )
|
||||||
|
{
|
||||||
|
d->AddSP(" :");
|
||||||
|
|
||||||
|
if ( yield->GetTypeID() )
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(yield->GetTypeID());
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yield->DescribeReST(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_SERIAL(FuncType, SER_FUNC_TYPE);
|
IMPLEMENT_SERIAL(FuncType, SER_FUNC_TYPE);
|
||||||
|
|
||||||
bool FuncType::DoSerialize(SerialInfo* info) const
|
bool FuncType::DoSerialize(SerialInfo* info) const
|
||||||
|
@ -701,7 +802,10 @@ bool TypeDecl::Serialize(SerialInfo* info) const
|
||||||
|
|
||||||
SERIALIZE_OPTIONAL(attrs);
|
SERIALIZE_OPTIONAL(attrs);
|
||||||
|
|
||||||
return type->Serialize(info) && SERIALIZE(id);
|
if ( ! (type->Serialize(info) && SERIALIZE(id)) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDecl* TypeDecl::Unserialize(UnserialInfo* info)
|
TypeDecl* TypeDecl::Unserialize(UnserialInfo* info)
|
||||||
|
@ -720,6 +824,58 @@ TypeDecl* TypeDecl::Unserialize(UnserialInfo* info)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeDecl::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(id);
|
||||||
|
d->Add(": ");
|
||||||
|
|
||||||
|
if ( type->GetTypeID() )
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(type->GetTypeID());
|
||||||
|
d->Add("`");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
type->DescribeReST(d);
|
||||||
|
|
||||||
|
if ( attrs )
|
||||||
|
{
|
||||||
|
d->SP();
|
||||||
|
attrs->DescribeReST(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentedTypeDecl::CommentedTypeDecl(BroType* t, const char* i,
|
||||||
|
attr_list* attrs, std::list<std::string>* cmnt_list)
|
||||||
|
: TypeDecl(t, i, attrs)
|
||||||
|
{
|
||||||
|
comments = cmnt_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentedTypeDecl::~CommentedTypeDecl()
|
||||||
|
{
|
||||||
|
if ( comments ) delete comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommentedTypeDecl::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
TypeDecl::DescribeReST(d);
|
||||||
|
|
||||||
|
if ( comments )
|
||||||
|
{
|
||||||
|
d->PushIndent();
|
||||||
|
std::list<std::string>::const_iterator i;
|
||||||
|
|
||||||
|
for ( i = comments->begin(); i != comments->end(); ++i)
|
||||||
|
{
|
||||||
|
if ( i != comments->begin() ) d->NL();
|
||||||
|
d->Add(i->c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
d->PopIndentNoNL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RecordField::RecordField(int arg_base, int arg_offset, int arg_total_offset)
|
RecordField::RecordField(int arg_base, int arg_offset, int arg_total_offset)
|
||||||
{
|
{
|
||||||
base = arg_base;
|
base = arg_base;
|
||||||
|
@ -736,7 +892,7 @@ RecordType::RecordType(type_decl_list* arg_types) : BroType(TYPE_RECORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordType::RecordType(TypeList* arg_base, type_decl_list* refinements)
|
RecordType::RecordType(TypeList* arg_base, type_decl_list* refinements)
|
||||||
: BroType(TYPE_RECORD)
|
: BroType(TYPE_RECORD)
|
||||||
{
|
{
|
||||||
if ( refinements )
|
if ( refinements )
|
||||||
arg_base->Append(new RecordType(refinements));
|
arg_base->Append(new RecordType(refinements));
|
||||||
|
@ -755,9 +911,11 @@ void RecordType::Init(TypeList* arg_base)
|
||||||
types = 0;
|
types = 0;
|
||||||
|
|
||||||
type_list* t = base->Types();
|
type_list* t = base->Types();
|
||||||
|
|
||||||
loop_over_list(*t, i)
|
loop_over_list(*t, i)
|
||||||
{
|
{
|
||||||
BroType* ti = (*t)[i];
|
BroType* ti = (*t)[i];
|
||||||
|
|
||||||
if ( ti->Tag() != TYPE_RECORD )
|
if ( ti->Tag() != TYPE_RECORD )
|
||||||
(*t)[i]->Error("non-record in base type list");
|
(*t)[i]->Error("non-record in base type list");
|
||||||
|
|
||||||
|
@ -767,6 +925,7 @@ void RecordType::Init(TypeList* arg_base)
|
||||||
for ( int j = 0; j < n; ++j )
|
for ( int j = 0; j < n; ++j )
|
||||||
{
|
{
|
||||||
const TypeDecl* tdij = rti->FieldDecl(j);
|
const TypeDecl* tdij = rti->FieldDecl(j);
|
||||||
|
|
||||||
if ( fields->Lookup(tdij->id) )
|
if ( fields->Lookup(tdij->id) )
|
||||||
{
|
{
|
||||||
error("duplicate field", tdij->id);
|
error("duplicate field", tdij->id);
|
||||||
|
@ -774,6 +933,7 @@ void RecordType::Init(TypeList* arg_base)
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordField* rf = new RecordField(i, j, fields->Length());
|
RecordField* rf = new RecordField(i, j, fields->Length());
|
||||||
|
|
||||||
if ( fields->Insert(tdij->id, rf) )
|
if ( fields->Insert(tdij->id, rf) )
|
||||||
Internal("duplicate field when constructing record");
|
Internal("duplicate field when constructing record");
|
||||||
}
|
}
|
||||||
|
@ -788,6 +948,7 @@ RecordType::~RecordType()
|
||||||
{
|
{
|
||||||
loop_over_list(*types, i)
|
loop_over_list(*types, i)
|
||||||
delete (*types)[i];
|
delete (*types)[i];
|
||||||
|
|
||||||
delete types;
|
delete types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,6 +1059,13 @@ void RecordType::Describe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordType::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
d->Add(":bro:type:`record`");
|
||||||
|
d->NL();
|
||||||
|
DescribeFieldsReST(d, false);
|
||||||
|
}
|
||||||
|
|
||||||
void RecordType::DescribeFields(ODesc* d) const
|
void RecordType::DescribeFields(ODesc* d) const
|
||||||
{
|
{
|
||||||
if ( d->IsReadable() )
|
if ( d->IsReadable() )
|
||||||
|
@ -937,6 +1105,29 @@ void RecordType::DescribeFields(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordType::DescribeFieldsReST(ODesc* d, bool func_args) const
|
||||||
|
{
|
||||||
|
if ( ! func_args )
|
||||||
|
d->PushIndent();
|
||||||
|
|
||||||
|
for ( int i = 0; i < num_fields; ++i )
|
||||||
|
{
|
||||||
|
if ( i > 0 )
|
||||||
|
if ( func_args )
|
||||||
|
d->Add(", ");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->NL();
|
||||||
|
d->NL();
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldDecl(i)->DescribeReST(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! func_args )
|
||||||
|
d->PopIndentNoNL();
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_SERIAL(RecordType, SER_RECORD_TYPE)
|
IMPLEMENT_SERIAL(RecordType, SER_RECORD_TYPE)
|
||||||
|
|
||||||
bool RecordType::DoSerialize(SerialInfo* info) const
|
bool RecordType::DoSerialize(SerialInfo* info) const
|
||||||
|
@ -1094,6 +1285,15 @@ EnumType::~EnumType()
|
||||||
delete [] iter->first;
|
delete [] iter->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CommentedEnumType::~CommentedEnumType()
|
||||||
|
{
|
||||||
|
for ( CommentMap::iterator iter = comments.begin(); iter != comments.end(); ++iter )
|
||||||
|
{
|
||||||
|
delete [] iter->first;
|
||||||
|
delete iter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note, we use error() here (not Error()) to include the current script
|
// Note, we use error() here (not Error()) to include the current script
|
||||||
// location in the error message, rather than the one where the type was
|
// location in the error message, rather than the one where the type was
|
||||||
// originally defined.
|
// originally defined.
|
||||||
|
@ -1123,6 +1323,26 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va
|
||||||
AddNameInternal(module_name, name, val, is_export);
|
AddNameInternal(module_name, name, val, is_export);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommentedEnumType::AddComment(const string& module_name, const char* name,
|
||||||
|
std::list<std::string>* new_comments)
|
||||||
|
{
|
||||||
|
if ( ! new_comments )
|
||||||
|
return;
|
||||||
|
|
||||||
|
string fullname = make_full_var_name(module_name.c_str(), name);
|
||||||
|
|
||||||
|
CommentMap::iterator it = comments.find(fullname.c_str());
|
||||||
|
|
||||||
|
if ( it == comments.end() )
|
||||||
|
comments[copy_string(fullname.c_str())] = new_comments;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
comments[fullname.c_str()]->splice(comments[fullname.c_str()]->end(),
|
||||||
|
*new_comments);
|
||||||
|
delete new_comments;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export)
|
void EnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export)
|
||||||
{
|
{
|
||||||
ID *id;
|
ID *id;
|
||||||
|
@ -1151,6 +1371,12 @@ void EnumType::AddNameInternal(const string& module_name, const char* name, bro_
|
||||||
names[copy_string(fullname.c_str())] = val;
|
names[copy_string(fullname.c_str())] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommentedEnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export)
|
||||||
|
{
|
||||||
|
string fullname = make_full_var_name(module_name.c_str(), name);
|
||||||
|
names[copy_string(fullname.c_str())] = val;
|
||||||
|
}
|
||||||
|
|
||||||
bro_int_t EnumType::Lookup(const string& module_name, const char* name)
|
bro_int_t EnumType::Lookup(const string& module_name, const char* name)
|
||||||
{
|
{
|
||||||
NameMap::iterator pos =
|
NameMap::iterator pos =
|
||||||
|
@ -1172,6 +1398,51 @@ const char* EnumType::Lookup(bro_int_t value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommentedEnumType::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
// create temporary, reverse name map so that enums can be documented
|
||||||
|
// in ascending order of their actual integral value instead of by name
|
||||||
|
typedef std::map< bro_int_t, const char* > RevNameMap;
|
||||||
|
RevNameMap rev;
|
||||||
|
for ( NameMap::const_iterator it = names.begin(); it != names.end(); ++it )
|
||||||
|
rev[it->second] = it->first;
|
||||||
|
|
||||||
|
d->Add(":bro:type:`");
|
||||||
|
d->Add(type_name(Tag()));
|
||||||
|
d->Add("`");
|
||||||
|
d->PushIndent();
|
||||||
|
d->NL();
|
||||||
|
|
||||||
|
for ( RevNameMap::const_iterator it = rev.begin(); it != rev.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( it != rev.begin() )
|
||||||
|
{
|
||||||
|
d->NL();
|
||||||
|
d->NL();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Add(".. bro:enum:: ");
|
||||||
|
d->AddSP(it->second);
|
||||||
|
d->Add(GetTypeID());
|
||||||
|
|
||||||
|
CommentMap::const_iterator cmnt_it = comments.find(it->second);
|
||||||
|
if ( cmnt_it != comments.end() )
|
||||||
|
{
|
||||||
|
d->PushIndent();
|
||||||
|
d->NL();
|
||||||
|
std::list<std::string>::const_iterator i;
|
||||||
|
const std::list<std::string>* cmnt_list = cmnt_it->second;
|
||||||
|
for ( i = cmnt_list->begin(); i != cmnt_list->end(); ++i)
|
||||||
|
{
|
||||||
|
if ( i != cmnt_list->begin() ) d->NL();
|
||||||
|
d->Add(i->c_str());
|
||||||
|
}
|
||||||
|
d->PopIndentNoNL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d->PopIndentNoNL();
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_SERIAL(EnumType, SER_ENUM_TYPE);
|
IMPLEMENT_SERIAL(EnumType, SER_ENUM_TYPE);
|
||||||
|
|
||||||
bool EnumType::DoSerialize(SerialInfo* info) const
|
bool EnumType::DoSerialize(SerialInfo* info) const
|
||||||
|
|
55
src/Type.h
55
src/Type.h
|
@ -6,6 +6,7 @@
|
||||||
#define type_h
|
#define type_h
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Obj.h"
|
#include "Obj.h"
|
||||||
|
@ -67,6 +68,7 @@ const int MATCHES_INDEX_VECTOR = 2;
|
||||||
class BroType : public BroObj {
|
class BroType : public BroObj {
|
||||||
public:
|
public:
|
||||||
BroType(TypeTag tag, bool base_type = false);
|
BroType(TypeTag tag, bool base_type = false);
|
||||||
|
~BroType();
|
||||||
|
|
||||||
TypeTag Tag() const { return tag; }
|
TypeTag Tag() const { return tag; }
|
||||||
InternalTypeTag InternalType() const { return internal_tag; }
|
InternalTypeTag InternalType() const { return internal_tag; }
|
||||||
|
@ -200,14 +202,18 @@ public:
|
||||||
BroType* Ref() { ::Ref(this); return this; }
|
BroType* Ref() { ::Ref(this); return this; }
|
||||||
|
|
||||||
virtual void Describe(ODesc* d) const;
|
virtual void Describe(ODesc* d) const;
|
||||||
|
virtual void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
virtual unsigned MemoryAllocation() const;
|
virtual unsigned MemoryAllocation() const;
|
||||||
|
|
||||||
bool Serialize(SerialInfo* info) const;
|
bool Serialize(SerialInfo* info) const;
|
||||||
static BroType* Unserialize(UnserialInfo* info, TypeTag want = TYPE_ANY);
|
static BroType* Unserialize(UnserialInfo* info, TypeTag want = TYPE_ANY);
|
||||||
|
|
||||||
|
void SetTypeID(const char* id) { type_id = id; }
|
||||||
|
const char* GetTypeID() const { return type_id; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BroType() { }
|
BroType() { type_id = 0; }
|
||||||
|
|
||||||
void SetError();
|
void SetError();
|
||||||
|
|
||||||
|
@ -218,6 +224,10 @@ private:
|
||||||
InternalTypeTag internal_tag;
|
InternalTypeTag internal_tag;
|
||||||
bool is_network_order;
|
bool is_network_order;
|
||||||
bool base_type;
|
bool base_type;
|
||||||
|
|
||||||
|
// This type_id field is only used by the documentation framework to
|
||||||
|
// track the names of declared types.
|
||||||
|
const char* type_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeList : public BroType {
|
class TypeList : public BroType {
|
||||||
|
@ -273,6 +283,7 @@ public:
|
||||||
BroType* YieldType();
|
BroType* YieldType();
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
// Returns true if this table is solely indexed by subnet.
|
// Returns true if this table is solely indexed by subnet.
|
||||||
bool IsSubNetIndex() const;
|
bool IsSubNetIndex() const;
|
||||||
|
@ -347,6 +358,7 @@ public:
|
||||||
ID* GetReturnValueID() const;
|
ID* GetReturnValueID() const;
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FuncType() { args = 0; arg_types = 0; yield = 0; return_value = 0; }
|
FuncType() { args = 0; arg_types = 0; yield = 0; return_value = 0; }
|
||||||
|
@ -362,7 +374,7 @@ protected:
|
||||||
class TypeDecl {
|
class TypeDecl {
|
||||||
public:
|
public:
|
||||||
TypeDecl(BroType* t, const char* i, attr_list* attrs = 0);
|
TypeDecl(BroType* t, const char* i, attr_list* attrs = 0);
|
||||||
~TypeDecl();
|
virtual ~TypeDecl();
|
||||||
|
|
||||||
const Attr* FindAttr(attr_tag a) const
|
const Attr* FindAttr(attr_tag a) const
|
||||||
{ return attrs ? attrs->FindAttr(a) : 0; }
|
{ return attrs ? attrs->FindAttr(a) : 0; }
|
||||||
|
@ -370,11 +382,24 @@ public:
|
||||||
bool Serialize(SerialInfo* info) const;
|
bool Serialize(SerialInfo* info) const;
|
||||||
static TypeDecl* Unserialize(UnserialInfo* info);
|
static TypeDecl* Unserialize(UnserialInfo* info);
|
||||||
|
|
||||||
|
virtual void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
BroType* type;
|
BroType* type;
|
||||||
Attributes* attrs;
|
Attributes* attrs;
|
||||||
const char* id;
|
const char* id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CommentedTypeDecl : public TypeDecl {
|
||||||
|
public:
|
||||||
|
CommentedTypeDecl(BroType* t, const char* i, attr_list* attrs = 0,
|
||||||
|
std::list<std::string>* cmnt_list = 0);
|
||||||
|
virtual ~CommentedTypeDecl();
|
||||||
|
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
|
std::list<std::string>* comments;
|
||||||
|
};
|
||||||
|
|
||||||
class RecordField {
|
class RecordField {
|
||||||
public:
|
public:
|
||||||
RecordField(int arg_base, int arg_offset, int arg_total_offset);
|
RecordField(int arg_base, int arg_offset, int arg_total_offset);
|
||||||
|
@ -410,7 +435,9 @@ public:
|
||||||
int NumFields() const { return num_fields; }
|
int NumFields() const { return num_fields; }
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
void DescribeFields(ODesc* d) const;
|
void DescribeFields(ODesc* d) const;
|
||||||
|
void DescribeFieldsReST(ODesc* d, bool func_args) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RecordType() { fields = 0; base = 0; types = 0; }
|
RecordType() { fields = 0; base = 0; types = 0; }
|
||||||
|
@ -471,7 +498,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
DECLARE_SERIAL(EnumType)
|
DECLARE_SERIAL(EnumType)
|
||||||
|
|
||||||
void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export);
|
virtual void AddNameInternal(const string& module_name,
|
||||||
|
const char* name, bro_int_t val, bool is_export);
|
||||||
|
|
||||||
typedef std::map< const char*, bro_int_t, ltstr > NameMap;
|
typedef std::map< const char*, bro_int_t, ltstr > NameMap;
|
||||||
NameMap names;
|
NameMap names;
|
||||||
|
@ -485,6 +513,27 @@ protected:
|
||||||
bro_int_t counter;
|
bro_int_t counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CommentedEnumType: public EnumType {
|
||||||
|
public:
|
||||||
|
CommentedEnumType() {}
|
||||||
|
~CommentedEnumType();
|
||||||
|
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
void AddComment(const string& module_name, const char* name,
|
||||||
|
std::list<std::string>* comments);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// This overriden method does not install the given ID name into a
|
||||||
|
// scope and it also does not do any kind of checking that the
|
||||||
|
// provided name already exists.
|
||||||
|
void AddNameInternal(const string& module_name, const char* name,
|
||||||
|
bro_int_t val, bool is_export);
|
||||||
|
|
||||||
|
// Comments are only filled when in "documentation mode".
|
||||||
|
typedef std::map< const char*, std::list<std::string>*, ltstr > CommentMap;
|
||||||
|
CommentMap comments;
|
||||||
|
};
|
||||||
|
|
||||||
class VectorType : public BroType {
|
class VectorType : public BroType {
|
||||||
public:
|
public:
|
||||||
VectorType(BroType* t);
|
VectorType(BroType* t);
|
||||||
|
|
47
src/Val.cc
47
src/Val.cc
|
@ -574,6 +574,11 @@ void Val::Describe(ODesc* d) const
|
||||||
Val::ValDescribe(d);
|
Val::ValDescribe(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Val::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
ValDescribeReST(d);
|
||||||
|
}
|
||||||
|
|
||||||
void Val::ValDescribe(ODesc* d) const
|
void Val::ValDescribe(ODesc* d) const
|
||||||
{
|
{
|
||||||
if ( d->IsReadable() && type->Tag() == TYPE_BOOL )
|
if ( d->IsReadable() && type->Tag() == TYPE_BOOL )
|
||||||
|
@ -615,6 +620,20 @@ void Val::ValDescribe(ODesc* d) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Val::ValDescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
switch ( type->InternalType() ) {
|
||||||
|
case TYPE_INTERNAL_OTHER:
|
||||||
|
Describe(d);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
d->Add("``");
|
||||||
|
ValDescribe(d);
|
||||||
|
d->Add("``");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MutableVal::~MutableVal()
|
MutableVal::~MutableVal()
|
||||||
{
|
{
|
||||||
for ( list<ID*>::iterator i = aliases.begin(); i != aliases.end(); ++i )
|
for ( list<ID*>::iterator i = aliases.begin(); i != aliases.end(); ++i )
|
||||||
|
@ -2929,6 +2948,34 @@ void RecordVal::Describe(ODesc* d) const
|
||||||
d->Add("]");
|
d->Add("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecordVal::DescribeReST(ODesc* d) const
|
||||||
|
{
|
||||||
|
const val_list* vl = AsRecord();
|
||||||
|
int n = vl->length();
|
||||||
|
|
||||||
|
d->Add("{");
|
||||||
|
d->PushIndent();
|
||||||
|
|
||||||
|
loop_over_list(*vl, i)
|
||||||
|
{
|
||||||
|
if ( i > 0 )
|
||||||
|
d->NL();
|
||||||
|
|
||||||
|
d->Add(record_type->FieldName(i));
|
||||||
|
d->Add("=");
|
||||||
|
|
||||||
|
Val* v = (*vl)[i];
|
||||||
|
|
||||||
|
if ( v )
|
||||||
|
v->Describe(d);
|
||||||
|
else
|
||||||
|
d->Add("<uninitialized>");
|
||||||
|
}
|
||||||
|
|
||||||
|
d->PopIndent();
|
||||||
|
d->Add("}");
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_SERIAL(RecordVal, SER_RECORD_VAL);
|
IMPLEMENT_SERIAL(RecordVal, SER_RECORD_VAL);
|
||||||
|
|
||||||
bool RecordVal::DoSerialize(SerialInfo* info) const
|
bool RecordVal::DoSerialize(SerialInfo* info) const
|
||||||
|
|
|
@ -313,6 +313,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Describe(ODesc* d) const;
|
void Describe(ODesc* d) const;
|
||||||
|
virtual void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
bool Serialize(SerialInfo* info) const;
|
bool Serialize(SerialInfo* info) const;
|
||||||
static Val* Unserialize(UnserialInfo* info, TypeTag type = TYPE_ANY)
|
static Val* Unserialize(UnserialInfo* info, TypeTag type = TYPE_ANY)
|
||||||
|
@ -347,6 +348,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void ValDescribe(ODesc* d) const;
|
virtual void ValDescribe(ODesc* d) const;
|
||||||
|
virtual void ValDescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
Val(TypeTag t)
|
Val(TypeTag t)
|
||||||
{
|
{
|
||||||
|
@ -902,6 +904,7 @@ public:
|
||||||
BroObj* GetOrigin() const { return origin; }
|
BroObj* GetOrigin() const { return origin; }
|
||||||
|
|
||||||
unsigned int MemoryAllocation() const;
|
unsigned int MemoryAllocation() const;
|
||||||
|
void DescribeReST(ODesc* d) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Val;
|
friend class Val;
|
||||||
|
|
39
src/Var.cc
39
src/Var.cc
|
@ -12,6 +12,8 @@
|
||||||
#include "RemoteSerializer.h"
|
#include "RemoteSerializer.h"
|
||||||
#include "EventRegistry.h"
|
#include "EventRegistry.h"
|
||||||
|
|
||||||
|
extern int generate_documentation;
|
||||||
|
|
||||||
static Val* init_val(Expr* init, const BroType* t, Val* aggr)
|
static Val* init_val(Expr* init, const BroType* t, Val* aggr)
|
||||||
{
|
{
|
||||||
return init->InitVal(t, aggr);
|
return init->InitVal(t, aggr);
|
||||||
|
@ -217,11 +219,44 @@ extern Expr* add_and_assign_local(ID* id, Expr* init, Val* val)
|
||||||
|
|
||||||
void add_type(ID* id, BroType* t, attr_list* attr, int /* is_event */)
|
void add_type(ID* id, BroType* t, attr_list* attr, int /* is_event */)
|
||||||
{
|
{
|
||||||
id->SetType(t);
|
BroType* tnew = t;
|
||||||
|
|
||||||
|
// In "documentation mode", we'd like to to be able to associate
|
||||||
|
// an identifier name with a declared type. Dealing with declared
|
||||||
|
// types that are "aliases" to a builtin type requires that the BroType
|
||||||
|
// is cloned before setting the identifier name that resolves to it.
|
||||||
|
// And still this is not enough to document cases where the declared type
|
||||||
|
// is an alias for another declared type -- but that's not a natural/common
|
||||||
|
// practice. If documenting that corner case is desired, one way
|
||||||
|
// is to add an ID* to class ID that tracks aliases and set it here if
|
||||||
|
// t->GetTypeID() is true.
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
SerializationFormat* form = new BinarySerializationFormat();
|
||||||
|
form->StartWrite();
|
||||||
|
CloneSerializer ss(form);
|
||||||
|
SerialInfo sinfo(&ss);
|
||||||
|
sinfo.cache = false;
|
||||||
|
|
||||||
|
t->Serialize(&sinfo);
|
||||||
|
char* data;
|
||||||
|
uint32 len = form->EndWrite(&data);
|
||||||
|
form->StartRead(data, len);
|
||||||
|
|
||||||
|
UnserialInfo uinfo(&ss);
|
||||||
|
uinfo.cache = false;
|
||||||
|
tnew = t->Unserialize(&uinfo);
|
||||||
|
|
||||||
|
delete [] data;
|
||||||
|
|
||||||
|
tnew->SetTypeID(copy_string(id->Name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
id->SetType(tnew);
|
||||||
id->MakeType();
|
id->MakeType();
|
||||||
|
|
||||||
if ( attr )
|
if ( attr )
|
||||||
id->SetAttrs(new Attributes(attr, t));
|
id->SetAttrs(new Attributes(attr, tnew));
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
||||||
|
|
|
@ -296,7 +296,12 @@ builtin_lang: definitions
|
||||||
|
|
||||||
|
|
||||||
definitions: definitions definition opt_ws
|
definitions: definitions definition opt_ws
|
||||||
{ fprintf(fp_func_def, "%s", $3); }
|
{
|
||||||
|
if ( in_c_code )
|
||||||
|
fprintf(fp_func_def, "%s", $3);
|
||||||
|
else
|
||||||
|
fprintf(fp_bro_init, "%s", $3);
|
||||||
|
}
|
||||||
| opt_ws
|
| opt_ws
|
||||||
{
|
{
|
||||||
int n = 1024 + strlen(input_filename);
|
int n = 1024 + strlen(input_filename);
|
||||||
|
@ -695,7 +700,12 @@ opt_ws: opt_ws TOK_WS
|
||||||
if ( in_c_code )
|
if ( in_c_code )
|
||||||
$$ = concat($1, $2);
|
$$ = concat($1, $2);
|
||||||
else
|
else
|
||||||
$$ = $1;
|
if ( $2[1] == '#' )
|
||||||
|
// This is a special type of comment that is used to
|
||||||
|
// generate bro script documentation, so pass it through.
|
||||||
|
$$ = concat($1, $2);
|
||||||
|
else
|
||||||
|
$$ = $1;
|
||||||
}
|
}
|
||||||
| /* empty */
|
| /* empty */
|
||||||
{ $$ = ""; }
|
{ $$ = ""; }
|
||||||
|
|
|
@ -30,6 +30,8 @@ extern void do_atifdef(const char* id);
|
||||||
extern void do_atifndef(const char* id);
|
extern void do_atifndef(const char* id);
|
||||||
extern void do_atelse();
|
extern void do_atelse();
|
||||||
extern void do_atendif();
|
extern void do_atendif();
|
||||||
|
extern void do_doc_token_start();
|
||||||
|
extern void do_doc_token_stop();
|
||||||
|
|
||||||
extern int line_number;
|
extern int line_number;
|
||||||
extern const char* filename;
|
extern const char* filename;
|
||||||
|
|
|
@ -91,6 +91,7 @@ int optimize = 0;
|
||||||
int do_notice_analysis = 0;
|
int do_notice_analysis = 0;
|
||||||
int rule_bench = 0;
|
int rule_bench = 0;
|
||||||
int print_loaded_scripts = 0;
|
int print_loaded_scripts = 0;
|
||||||
|
int generate_documentation = 0;
|
||||||
SecondaryPath* secondary_path = 0;
|
SecondaryPath* secondary_path = 0;
|
||||||
ConnCompressor* conn_compressor = 0;
|
ConnCompressor* conn_compressor = 0;
|
||||||
extern char version[];
|
extern char version[];
|
||||||
|
@ -142,6 +143,7 @@ void usage()
|
||||||
fprintf(stderr, " -h|--help|-? | command line help\n");
|
fprintf(stderr, " -h|--help|-? | command line help\n");
|
||||||
fprintf(stderr, " -i|--iface <interface> | read from given interface\n");
|
fprintf(stderr, " -i|--iface <interface> | read from given interface\n");
|
||||||
fprintf(stderr, " -l|--print-scripts | print all loaded scripts\n");
|
fprintf(stderr, " -l|--print-scripts | print all loaded scripts\n");
|
||||||
|
fprintf(stderr, " -Z|--doc-scripts | generate documentation for all loaded scripts\n");
|
||||||
fprintf(stderr, " -p|--prefix <prefix> | add given prefix to policy file resolution\n");
|
fprintf(stderr, " -p|--prefix <prefix> | add given prefix to policy file resolution\n");
|
||||||
fprintf(stderr, " -r|--readfile <readfile> | read from given tcpdump file\n");
|
fprintf(stderr, " -r|--readfile <readfile> | read from given tcpdump file\n");
|
||||||
fprintf(stderr, " -y|--flowfile <file>[=<ident>] | read from given flow file\n");
|
fprintf(stderr, " -y|--flowfile <file>[=<ident>] | read from given flow file\n");
|
||||||
|
@ -360,6 +362,7 @@ int main(int argc, char** argv)
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"iface", required_argument, 0, 'i'},
|
{"iface", required_argument, 0, 'i'},
|
||||||
{"print-scripts", no_argument, 0, 'l'},
|
{"print-scripts", no_argument, 0, 'l'},
|
||||||
|
{"doc-scripts", no_argument, 0, 'Z'},
|
||||||
{"prefix", required_argument, 0, 'p'},
|
{"prefix", required_argument, 0, 'p'},
|
||||||
{"readfile", required_argument, 0, 'r'},
|
{"readfile", required_argument, 0, 'r'},
|
||||||
{"flowfile", required_argument, 0, 'y'},
|
{"flowfile", required_argument, 0, 'y'},
|
||||||
|
@ -432,7 +435,7 @@ int main(int argc, char** argv)
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
char opts[256];
|
char opts[256];
|
||||||
safe_strncpy(opts, "B:D:e:f:I:i:K:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGHLOPSWdghlv",
|
safe_strncpy(opts, "B:D:e:f:I:i:K:n:p:R:r:s:T:t:U:w:x:X:y:Y:z:CFGHLOPSWdghlvZ",
|
||||||
sizeof(opts));
|
sizeof(opts));
|
||||||
|
|
||||||
#ifdef USE_PERFTOOLS
|
#ifdef USE_PERFTOOLS
|
||||||
|
@ -611,6 +614,10 @@ int main(int argc, char** argv)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case 'Z':
|
||||||
|
generate_documentation = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
#ifdef USE_IDMEF
|
#ifdef USE_IDMEF
|
||||||
case 'n':
|
case 'n':
|
||||||
fprintf(stderr, "Using IDMEF XML DTD from %s\n", optarg);
|
fprintf(stderr, "Using IDMEF XML DTD from %s\n", optarg);
|
||||||
|
|
344
src/parse.y
344
src/parse.y
|
@ -3,7 +3,7 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%expect 71
|
%expect 81
|
||||||
|
|
||||||
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ALARM TOK_ANY
|
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ALARM TOK_ANY
|
||||||
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
|
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
|
||||||
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
%token TOK_DEBUG
|
%token TOK_DEBUG
|
||||||
|
|
||||||
|
%token TOK_DOC TOK_POST_DOC
|
||||||
|
|
||||||
%left ',' '|'
|
%left ',' '|'
|
||||||
%right '=' TOK_ADD_TO TOK_REMOVE_FROM
|
%right '=' TOK_ADD_TO TOK_REMOVE_FROM
|
||||||
%right '?' ':' TOK_USING
|
%right '?' ':' TOK_USING
|
||||||
|
@ -41,7 +43,8 @@
|
||||||
%right '!'
|
%right '!'
|
||||||
%left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR
|
%left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR
|
||||||
|
|
||||||
%type <str> TOK_ID TOK_PATTERN_TEXT single_pattern
|
%type <str> TOK_ID TOK_PATTERN_TEXT single_pattern TOK_DOC TOK_POST_DOC
|
||||||
|
%type <str_l> opt_doc_list opt_post_doc_list
|
||||||
%type <id> local_id global_id event_id global_or_event_id resolve_id begin_func
|
%type <id> local_id global_id event_id global_or_event_id resolve_id begin_func
|
||||||
%type <id_l> local_id_list
|
%type <id_l> local_id_list
|
||||||
%type <ic> init_class
|
%type <ic> init_class
|
||||||
|
@ -75,6 +78,15 @@
|
||||||
#include "DNS.h"
|
#include "DNS.h"
|
||||||
#include "RE.h"
|
#include "RE.h"
|
||||||
#include "Scope.h"
|
#include "Scope.h"
|
||||||
|
#include "BroDoc.h"
|
||||||
|
#include "BroDocObj.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern BroDoc* current_reST_doc;
|
||||||
|
extern int generate_documentation;
|
||||||
|
extern std::list<std::string>* reST_doc_comments;
|
||||||
|
|
||||||
YYLTYPE GetCurrentLocation();
|
YYLTYPE GetCurrentLocation();
|
||||||
extern int yyerror(const char[]);
|
extern int yyerror(const char[]);
|
||||||
|
@ -105,12 +117,22 @@ bool resolving_global_ID = false;
|
||||||
|
|
||||||
ID* func_id = 0;
|
ID* func_id = 0;
|
||||||
EnumType *cur_enum_type = 0;
|
EnumType *cur_enum_type = 0;
|
||||||
|
CommentedEnumType *cur_enum_type_doc = 0;
|
||||||
|
const char* cur_enum_elem_id = 0;
|
||||||
|
|
||||||
|
type_decl_list* fake_type_decl_list = 0;
|
||||||
|
TypeDecl* last_fake_type_decl = 0;
|
||||||
|
|
||||||
static void parser_new_enum (void)
|
static void parser_new_enum (void)
|
||||||
{
|
{
|
||||||
/* Starting a new enum definition. */
|
/* Starting a new enum definition. */
|
||||||
assert(cur_enum_type == NULL);
|
assert(cur_enum_type == NULL);
|
||||||
cur_enum_type = new EnumType();
|
cur_enum_type = new EnumType();
|
||||||
|
|
||||||
|
// For documentation purposes, a separate type object is created
|
||||||
|
// in order to avoid overlap that can be caused by redefs.
|
||||||
|
if ( generate_documentation )
|
||||||
|
cur_enum_type_doc = new CommentedEnumType();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parser_redef_enum (ID *id)
|
static void parser_redef_enum (ID *id)
|
||||||
|
@ -126,12 +148,52 @@ static void parser_redef_enum (ID *id)
|
||||||
if ( ! cur_enum_type )
|
if ( ! cur_enum_type )
|
||||||
id->Error("not an enum");
|
id->Error("not an enum");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
cur_enum_type_doc = new CommentedEnumType();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_enum_comment (std::list<std::string>* comments)
|
||||||
|
{
|
||||||
|
cur_enum_type_doc->AddComment(current_module, cur_enum_elem_id, comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ID* create_dummy_id (ID* id, BroType* type)
|
||||||
|
{
|
||||||
|
ID* fake_id = new ID(copy_string(id->Name()), (IDScope) id->Scope(),
|
||||||
|
is_export);
|
||||||
|
|
||||||
|
fake_id->SetType(type);
|
||||||
|
|
||||||
|
if ( id->AsType() )
|
||||||
|
{
|
||||||
|
type->SetTypeID(copy_string(id->Name()));
|
||||||
|
fake_id->MakeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fake_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::list<std::string>* concat_opt_docs (std::list<std::string>* pre,
|
||||||
|
std::list<std::string>* post)
|
||||||
|
{
|
||||||
|
if ( ! pre && ! post ) return 0;
|
||||||
|
|
||||||
|
if ( pre && ! post ) return pre;
|
||||||
|
|
||||||
|
if ( ! pre && post ) return post;
|
||||||
|
|
||||||
|
pre->splice(pre->end(), *post);
|
||||||
|
delete post;
|
||||||
|
|
||||||
|
return pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
char* str;
|
char* str;
|
||||||
|
std::list<std::string>* str_l;
|
||||||
ID* id;
|
ID* id;
|
||||||
id_list* id_l;
|
id_list* id_l;
|
||||||
init_class ic;
|
init_class ic;
|
||||||
|
@ -546,11 +608,6 @@ opt_expr_list:
|
||||||
{ $$ = new ListExpr(); }
|
{ $$ = new ListExpr(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_comma:
|
|
||||||
','
|
|
||||||
|
|
|
||||||
;
|
|
||||||
|
|
||||||
pattern:
|
pattern:
|
||||||
pattern '|' single_pattern
|
pattern '|' single_pattern
|
||||||
{
|
{
|
||||||
|
@ -571,17 +628,46 @@ single_pattern:
|
||||||
;
|
;
|
||||||
|
|
||||||
enum_body:
|
enum_body:
|
||||||
enum_body_list opt_comma
|
enum_body_list opt_post_doc_list
|
||||||
{
|
{
|
||||||
$$ = cur_enum_type;
|
$$ = cur_enum_type;
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
add_enum_comment($2);
|
||||||
|
cur_enum_elem_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_enum_type = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
| enum_body_list ',' opt_post_doc_list
|
||||||
|
{
|
||||||
|
$$ = cur_enum_type;
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
add_enum_comment($3);
|
||||||
|
cur_enum_elem_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
cur_enum_type = NULL;
|
cur_enum_type = NULL;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
enum_body_list:
|
enum_body_list:
|
||||||
enum_body_elem /* No action */
|
enum_body_elem opt_post_doc_list
|
||||||
| enum_body_list ',' enum_body_elem /* no action */
|
{
|
||||||
;
|
if ( generate_documentation )
|
||||||
|
add_enum_comment($2);
|
||||||
|
}
|
||||||
|
|
||||||
|
| enum_body_list ',' opt_post_doc_list
|
||||||
|
{
|
||||||
|
if ( generate_documentation )
|
||||||
|
add_enum_comment($3);
|
||||||
|
} enum_body_elem
|
||||||
|
;
|
||||||
|
|
||||||
enum_body_elem:
|
enum_body_elem:
|
||||||
/* TODO: We could also define this as TOK_ID '=' expr, (or
|
/* TODO: We could also define this as TOK_ID '=' expr, (or
|
||||||
|
@ -589,17 +675,25 @@ enum_body_elem:
|
||||||
error messages if someboy tries to use constant variables as
|
error messages if someboy tries to use constant variables as
|
||||||
enumerator.
|
enumerator.
|
||||||
*/
|
*/
|
||||||
TOK_ID '=' TOK_CONSTANT
|
opt_doc_list TOK_ID '=' TOK_CONSTANT
|
||||||
{
|
{
|
||||||
set_location(@1, @3);
|
set_location(@2, @4);
|
||||||
assert(cur_enum_type);
|
assert(cur_enum_type);
|
||||||
if ( $3->Type()->Tag() != TYPE_COUNT )
|
|
||||||
|
if ( $4->Type()->Tag() != TYPE_COUNT )
|
||||||
error("enumerator is not a count constant");
|
error("enumerator is not a count constant");
|
||||||
else
|
else
|
||||||
cur_enum_type->AddName(current_module, $1, $3->InternalUnsigned(), is_export);
|
cur_enum_type->AddName(current_module, $2, $4->InternalUnsigned(), is_export);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
cur_enum_type_doc->AddName(current_module, $2, $4->InternalUnsigned(), is_export);
|
||||||
|
cur_enum_elem_id = $2;
|
||||||
|
add_enum_comment($1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_ID '=' '-' TOK_CONSTANT
|
| opt_doc_list TOK_ID '=' '-' TOK_CONSTANT
|
||||||
{
|
{
|
||||||
/* We only accept counts as enumerator, but we want to return a nice
|
/* We only accept counts as enumerator, but we want to return a nice
|
||||||
error message if users triy to use a negative integer (will also
|
error message if users triy to use a negative integer (will also
|
||||||
|
@ -608,11 +702,18 @@ enum_body_elem:
|
||||||
error("enumerator is not a count constant");
|
error("enumerator is not a count constant");
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_ID
|
| opt_doc_list TOK_ID
|
||||||
{
|
{
|
||||||
set_location(@1);
|
set_location(@2);
|
||||||
assert(cur_enum_type);
|
assert(cur_enum_type);
|
||||||
cur_enum_type->AddName(current_module, $1, is_export);
|
cur_enum_type->AddName(current_module, $2, is_export);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
cur_enum_type_doc->AddName(current_module, $2, is_export);
|
||||||
|
cur_enum_elem_id = $2;
|
||||||
|
add_enum_comment($1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -704,10 +805,11 @@ type:
|
||||||
$$ = new SetType($3, 0);
|
$$ = new SetType($3, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_RECORD '{' type_decl_list '}'
|
| TOK_RECORD '{' { do_doc_token_start(); } type_decl_list '}'
|
||||||
{
|
{
|
||||||
set_location(@1, @4);
|
do_doc_token_stop();
|
||||||
$$ = new RecordType($3);
|
set_location(@1, @5);
|
||||||
|
$$ = new RecordType($4);
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_UNION '{' type_list '}'
|
| TOK_UNION '{' type_list '}'
|
||||||
|
@ -717,8 +819,9 @@ type:
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_ENUM '{' { set_location(@1); parser_new_enum(); } enum_body '}'
|
| TOK_ENUM '{' { set_location(@1); parser_new_enum(); do_doc_token_start(); } enum_body '}'
|
||||||
{
|
{
|
||||||
|
do_doc_token_stop();
|
||||||
set_location(@1, @5);
|
set_location(@1, @5);
|
||||||
$4->UpdateLocationEndInfo(@5);
|
$4->UpdateLocationEndInfo(@5);
|
||||||
$$ = $4;
|
$$ = $4;
|
||||||
|
@ -796,16 +899,46 @@ type_list:
|
||||||
|
|
||||||
type_decl_list:
|
type_decl_list:
|
||||||
type_decl_list type_decl
|
type_decl_list type_decl
|
||||||
{ $1->append($2); }
|
{
|
||||||
|
$1->append($2);
|
||||||
|
|
||||||
|
if ( generate_documentation && last_fake_type_decl )
|
||||||
|
{
|
||||||
|
fake_type_decl_list->append(last_fake_type_decl);
|
||||||
|
last_fake_type_decl = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
|
||||||
{ $$ = new type_decl_list(); }
|
{
|
||||||
|
$$ = new type_decl_list();
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
fake_type_decl_list = new type_decl_list();
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
type_decl:
|
type_decl:
|
||||||
TOK_ID ':' type opt_attr ';'
|
opt_doc_list TOK_ID ':' type opt_attr ';' opt_post_doc_list
|
||||||
{
|
{
|
||||||
set_location(@1, @5);
|
set_location(@2, @6);
|
||||||
$$ = new TypeDecl($3, $1, $4);
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
attr_list* a = $5;
|
||||||
|
attr_list* a_copy = 0;
|
||||||
|
|
||||||
|
if ( a )
|
||||||
|
{
|
||||||
|
a_copy = new attr_list;
|
||||||
|
loop_over_list(*a, i)
|
||||||
|
a_copy->append((*a)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_fake_type_decl = new CommentedTypeDecl(
|
||||||
|
$4, $2, a_copy, concat_opt_docs($1, $7));
|
||||||
|
}
|
||||||
|
|
||||||
|
$$ = new TypeDecl($4, $2, $5);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -837,31 +970,128 @@ formal_args_decl:
|
||||||
|
|
||||||
decl:
|
decl:
|
||||||
TOK_MODULE TOK_ID ';'
|
TOK_MODULE TOK_ID ';'
|
||||||
{ current_module = $2; }
|
{
|
||||||
|
current_module = $2;
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
current_reST_doc->AddModule(current_module);
|
||||||
|
}
|
||||||
|
|
||||||
| TOK_EXPORT '{' { is_export = true; } decl_list '}'
|
| TOK_EXPORT '{' { is_export = true; } decl_list '}'
|
||||||
{ is_export = false; }
|
{ is_export = false; }
|
||||||
|
|
||||||
| TOK_GLOBAL global_id opt_type init_class opt_init opt_attr ';'
|
| TOK_GLOBAL global_id opt_type init_class opt_init opt_attr ';'
|
||||||
{ add_global($2, $3, $4, $5, $6, VAR_REGULAR); }
|
{
|
||||||
|
add_global($2, $3, $4, $5, $6, VAR_REGULAR);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
ID* id = $2;
|
||||||
|
if ( id->Type()->Tag() == TYPE_FUNC )
|
||||||
|
{
|
||||||
|
if ( id->Type()->AsFuncType()->IsEvent() )
|
||||||
|
current_reST_doc->AddEvent(
|
||||||
|
new BroDocObj(id, reST_doc_comments));
|
||||||
|
else
|
||||||
|
current_reST_doc->AddFunction(
|
||||||
|
new BroDocObj(id, reST_doc_comments));
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_reST_doc->AddStateVar(
|
||||||
|
new BroDocObj(id, reST_doc_comments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
| TOK_CONST global_id opt_type init_class opt_init opt_attr ';'
|
| TOK_CONST global_id opt_type init_class opt_init opt_attr ';'
|
||||||
{ add_global($2, $3, $4, $5, $6, VAR_CONST); }
|
{
|
||||||
|
add_global($2, $3, $4, $5, $6, VAR_CONST);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
if ( $2->FindAttr(ATTR_REDEF) )
|
||||||
|
current_reST_doc->AddOption(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
|
else
|
||||||
|
current_reST_doc->AddConstant(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
| TOK_REDEF global_id opt_type init_class opt_init opt_attr ';'
|
| TOK_REDEF global_id opt_type init_class opt_init opt_attr ';'
|
||||||
{ add_global($2, $3, $4, $5, $6, VAR_REDEF); }
|
{
|
||||||
|
add_global($2, $3, $4, $5, $6, VAR_REDEF);
|
||||||
|
|
||||||
|
if ( generate_documentation &&
|
||||||
|
! streq("capture_filters", $2->Name()) &&
|
||||||
|
! streq("dpd_config", $2->Name()) )
|
||||||
|
{
|
||||||
|
ID* fake_id = create_dummy_id($2, $2->Type());
|
||||||
|
BroDocObj* o = new BroDocObj(fake_id, reST_doc_comments, true);
|
||||||
|
o->SetRole(true);
|
||||||
|
current_reST_doc->AddRedef(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
| TOK_REDEF TOK_ENUM global_id TOK_ADD_TO
|
| TOK_REDEF TOK_ENUM global_id TOK_ADD_TO
|
||||||
'{' { parser_redef_enum($3); } enum_body '}' ';'
|
'{' { parser_redef_enum($3); do_doc_token_start(); } enum_body '}' ';'
|
||||||
{ /* no action */ }
|
{
|
||||||
|
do_doc_token_stop();
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
ID* fake_id = create_dummy_id($3, cur_enum_type_doc);
|
||||||
|
cur_enum_type_doc = 0;
|
||||||
|
BroDocObj* o = new BroDocObj(fake_id, reST_doc_comments, true);
|
||||||
|
o->SetRole(true);
|
||||||
|
|
||||||
|
if ( streq(fake_id->Name(), "Notice" ) )
|
||||||
|
current_reST_doc->AddNotice(o);
|
||||||
|
else
|
||||||
|
current_reST_doc->AddRedef(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
| TOK_TYPE global_id ':' refined_type opt_attr ';'
|
| TOK_TYPE global_id ':' refined_type opt_attr ';'
|
||||||
{
|
{
|
||||||
add_type($2, $4, $5, 0);
|
add_type($2, $4, $5, 0);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
TypeTag t = $2->AsType()->Tag();
|
||||||
|
if ( t == TYPE_ENUM && cur_enum_type_doc )
|
||||||
|
{
|
||||||
|
ID* fake = create_dummy_id($2, cur_enum_type_doc);
|
||||||
|
cur_enum_type_doc = 0;
|
||||||
|
current_reST_doc->AddType(
|
||||||
|
new BroDocObj(fake, reST_doc_comments, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( t == TYPE_RECORD && fake_type_decl_list )
|
||||||
|
{
|
||||||
|
BroType* fake_record = new RecordType(fake_type_decl_list);
|
||||||
|
ID* fake = create_dummy_id($2, fake_record);
|
||||||
|
fake_type_decl_list = 0;
|
||||||
|
current_reST_doc->AddType(
|
||||||
|
new BroDocObj(fake, reST_doc_comments, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
current_reST_doc->AddType(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
| TOK_EVENT event_id ':' refined_type opt_attr ';'
|
| TOK_EVENT event_id ':' refined_type opt_attr ';'
|
||||||
{ add_type($2, $4, $5, 1); }
|
{
|
||||||
|
add_type($2, $4, $5, 1);
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
current_reST_doc->AddEvent(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
|
}
|
||||||
|
|
||||||
| func_hdr func_body
|
| func_hdr func_body
|
||||||
{ }
|
{ }
|
||||||
|
@ -886,14 +1116,20 @@ func_hdr:
|
||||||
TOK_FUNCTION global_id func_params
|
TOK_FUNCTION global_id func_params
|
||||||
{
|
{
|
||||||
begin_func($2, current_module.c_str(),
|
begin_func($2, current_module.c_str(),
|
||||||
FUNC_FLAVOR_FUNCTION, 0, $3);
|
FUNC_FLAVOR_FUNCTION, 0, $3);
|
||||||
$$ = $3;
|
$$ = $3;
|
||||||
|
if ( generate_documentation )
|
||||||
|
current_reST_doc->AddFunction(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
}
|
}
|
||||||
| TOK_EVENT event_id func_params
|
| TOK_EVENT event_id func_params
|
||||||
{
|
{
|
||||||
begin_func($2, current_module.c_str(),
|
begin_func($2, current_module.c_str(),
|
||||||
FUNC_FLAVOR_EVENT, 0, $3);
|
FUNC_FLAVOR_EVENT, 0, $3);
|
||||||
$$ = $3;
|
$$ = $3;
|
||||||
|
if ( generate_documentation )
|
||||||
|
current_reST_doc->AddEvent(
|
||||||
|
new BroDocObj($2, reST_doc_comments));
|
||||||
}
|
}
|
||||||
| TOK_REDEF TOK_EVENT event_id func_params
|
| TOK_REDEF TOK_EVENT event_id func_params
|
||||||
{
|
{
|
||||||
|
@ -1302,12 +1538,48 @@ resolve_id:
|
||||||
{
|
{
|
||||||
set_location(@1);
|
set_location(@1);
|
||||||
$$ = lookup_ID($1, current_module.c_str());
|
$$ = lookup_ID($1, current_module.c_str());
|
||||||
|
|
||||||
if ( ! $$ )
|
if ( ! $$ )
|
||||||
error("identifier not defined:", $1);
|
error("identifier not defined:", $1);
|
||||||
|
|
||||||
delete [] $1;
|
delete [] $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opt_post_doc_list:
|
||||||
|
opt_post_doc_list TOK_POST_DOC
|
||||||
|
{
|
||||||
|
$1->push_back($2);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
TOK_POST_DOC
|
||||||
|
{
|
||||||
|
$$ = new std::list<std::string>();
|
||||||
|
$$->push_back($1);
|
||||||
|
delete [] $1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
{ $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
|
opt_doc_list:
|
||||||
|
opt_doc_list TOK_DOC
|
||||||
|
{
|
||||||
|
$1->push_back($2);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
TOK_DOC
|
||||||
|
{
|
||||||
|
$$ = new std::list<std::string>();
|
||||||
|
$$->push_back($1);
|
||||||
|
delete [] $1;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
{ $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int yyerror(const char msg[])
|
int yyerror(const char msg[])
|
||||||
|
|
259
src/scan.l
259
src/scan.l
|
@ -15,11 +15,18 @@
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "PolicyFile.h"
|
#include "PolicyFile.h"
|
||||||
#include "broparse.h"
|
#include "broparse.h"
|
||||||
|
#include "BroDoc.h"
|
||||||
|
#include "BroBifDoc.h"
|
||||||
|
#include "Analyzer.h"
|
||||||
|
#include "AnalyzerTags.h"
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
extern YYLTYPE yylloc; // holds start line and column of token
|
extern YYLTYPE yylloc; // holds start line and column of token
|
||||||
extern int print_loaded_scripts;
|
extern int print_loaded_scripts;
|
||||||
|
extern int generate_documentation;
|
||||||
|
|
||||||
int nwarn = 0;
|
int nwarn = 0;
|
||||||
int nerr = 0;
|
int nerr = 0;
|
||||||
|
@ -28,13 +35,13 @@ int nruntime = 0;
|
||||||
// Track the @if... depth.
|
// Track the @if... depth.
|
||||||
ptr_compat_int current_depth = 0;
|
ptr_compat_int current_depth = 0;
|
||||||
|
|
||||||
declare(List,ptr_compat_int);
|
|
||||||
typedef List(ptr_compat_int) int_list;
|
|
||||||
int_list if_stack;
|
int_list if_stack;
|
||||||
|
|
||||||
int line_number = 1;
|
int line_number = 1;
|
||||||
int include_level = 0;
|
int include_level = 0;
|
||||||
const char* filename = 0;
|
const char* filename = 0;
|
||||||
|
BroDoc* current_reST_doc = 0;
|
||||||
|
static BroDoc* last_reST_doc = 0;
|
||||||
|
|
||||||
char last_tok[128];
|
char last_tok[128];
|
||||||
|
|
||||||
|
@ -50,6 +57,33 @@ char last_tok[128];
|
||||||
// Files we have already scanned (or are in the process of scanning).
|
// Files we have already scanned (or are in the process of scanning).
|
||||||
static PList(char) files_scanned;
|
static PList(char) files_scanned;
|
||||||
|
|
||||||
|
// reST documents that we've created (or have at least opened so far).
|
||||||
|
static std::list<BroDoc*> docs_generated;
|
||||||
|
|
||||||
|
// reST comments (those starting with ##) seen so far.
|
||||||
|
std::list<std::string>* reST_doc_comments = 0;
|
||||||
|
|
||||||
|
// Print current contents of reST_doc_comments list to stderr.
|
||||||
|
void print_current_reST_doc_comments();
|
||||||
|
|
||||||
|
// Delete the reST_doc_comments list object.
|
||||||
|
void clear_reST_doc_comments();
|
||||||
|
|
||||||
|
// Adds changes to capture_filter to the current script's reST documentation.
|
||||||
|
static void check_capture_filter_changes();
|
||||||
|
|
||||||
|
// Adds changes to dpd_config to the current script's reST documentation.
|
||||||
|
static void check_dpd_config_changes();
|
||||||
|
|
||||||
|
static const char* canon_doc_comment(const char* comment)
|
||||||
|
{
|
||||||
|
// "##Text" and "## Text" are treated the same in order to be able
|
||||||
|
// to still preserve indentation level, but not unintentionally
|
||||||
|
// signify an indentation level for all the text when using
|
||||||
|
// the "## Text" style.
|
||||||
|
return ( comment[0] == ' ' ) ? comment + 1 : comment;
|
||||||
|
}
|
||||||
|
|
||||||
class FileInfo {
|
class FileInfo {
|
||||||
public:
|
public:
|
||||||
FileInfo(string restore_module = "");
|
FileInfo(string restore_module = "");
|
||||||
|
@ -60,6 +94,7 @@ public:
|
||||||
const char* name;
|
const char* name;
|
||||||
int line;
|
int line;
|
||||||
int level;
|
int level;
|
||||||
|
BroDoc* doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A stack of input buffers we're scanning. file_stack[len-1] is the
|
// A stack of input buffers we're scanning. file_stack[len-1] is the
|
||||||
|
@ -87,6 +122,7 @@ static void report_file();
|
||||||
|
|
||||||
%x RE
|
%x RE
|
||||||
%x IGNORE
|
%x IGNORE
|
||||||
|
%s DOC
|
||||||
|
|
||||||
OWS [ \t]*
|
OWS [ \t]*
|
||||||
WS [ \t]+
|
WS [ \t]+
|
||||||
|
@ -102,11 +138,75 @@ ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+))
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
##!.* {
|
||||||
|
// Add this format of comments to the script documentation's "summary".
|
||||||
|
if ( generate_documentation )
|
||||||
|
current_reST_doc->AddSummary(canon_doc_comment(yytext + 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
<DOC>##<.* {
|
||||||
|
yylval.str = copy_string(canon_doc_comment(yytext + 3));
|
||||||
|
return TOK_POST_DOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
<DOC>##.* {
|
||||||
|
if ( yytext[2] != '#' )
|
||||||
|
{
|
||||||
|
yylval.str = copy_string(canon_doc_comment(yytext + 2));
|
||||||
|
return TOK_DOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
##{OWS}{ID}:.* {
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
// Comment is documenting either a function parameter or return type,
|
||||||
|
// so appropriate reST markup substitutions are automatically made
|
||||||
|
// in order to distinguish them from other comments.
|
||||||
|
const char* id_start = skip_whitespace(yytext + 2);
|
||||||
|
size_t id_len = strcspn(id_start, ":");
|
||||||
|
char* id_name = new char[id_len + 1];
|
||||||
|
strncpy(id_name, id_start, id_len);
|
||||||
|
id_name[id_len] = '\0';
|
||||||
|
const char* comment = id_start + id_len + 1;
|
||||||
|
|
||||||
|
std::string doc;
|
||||||
|
|
||||||
|
if ( streq(id_name, "Returns") )
|
||||||
|
doc.append(":returns:").append(comment);
|
||||||
|
else
|
||||||
|
doc.append(":param ").append(id_name).append(":").append(comment);
|
||||||
|
|
||||||
|
if ( ! reST_doc_comments )
|
||||||
|
reST_doc_comments = new std::list<std::string>();
|
||||||
|
|
||||||
|
// always insert a blank line so that this param/return markup
|
||||||
|
// 1) doesn't show up in the summary section in the case that it's
|
||||||
|
// the first comment for the function/event
|
||||||
|
// 2) has a blank line between it and non-field-list reST markup,
|
||||||
|
// which is required for correct HTML rendering by Sphinx
|
||||||
|
reST_doc_comments->push_back("");
|
||||||
|
reST_doc_comments->push_back(doc);
|
||||||
|
|
||||||
|
delete [] id_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
##.* {
|
||||||
|
if ( generate_documentation && (yytext[2] != '#') )
|
||||||
|
{
|
||||||
|
if ( ! reST_doc_comments )
|
||||||
|
reST_doc_comments = new std::list<std::string>();
|
||||||
|
|
||||||
|
reST_doc_comments->push_back(canon_doc_comment(yytext + 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#.* /* eat comments */
|
#.* /* eat comments */
|
||||||
|
|
||||||
{WS} /* eat whitespace */
|
{WS} /* eat whitespace */
|
||||||
|
|
||||||
<INITIAL,IGNORE>\n {
|
<INITIAL,IGNORE,DOC>\n {
|
||||||
report_file();
|
report_file();
|
||||||
++line_number;
|
++line_number;
|
||||||
++yylloc.first_line;
|
++yylloc.first_line;
|
||||||
|
@ -211,6 +311,18 @@ when return TOK_WHEN;
|
||||||
|
|
||||||
@load{WS}{FILE} {
|
@load{WS}{FILE} {
|
||||||
const char* new_file = skip_whitespace(yytext + 5); // Skip "@load".
|
const char* new_file = skip_whitespace(yytext + 5); // Skip "@load".
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
current_reST_doc->AddImport(new_file);
|
||||||
|
|
||||||
|
if ( reST_doc_comments )
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Warning: unconsumed reST documentation is being "
|
||||||
|
"discarded before doing '@load %s' in %s:\n",
|
||||||
|
new_file, current_reST_doc->GetSourceFileName());
|
||||||
|
clear_reST_doc_comments();
|
||||||
|
}
|
||||||
|
}
|
||||||
(void) load_files_with_prefix(new_file);
|
(void) load_files_with_prefix(new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +558,6 @@ static int load_files_with_prefix(const char* orig_file)
|
||||||
strcpy(new_filename, file);
|
strcpy(new_filename, file);
|
||||||
|
|
||||||
f = search_for_file(new_filename, "bro", &full_filename);
|
f = search_for_file(new_filename, "bro", &full_filename);
|
||||||
|
|
||||||
delete [] new_filename;
|
delete [] new_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,6 +607,21 @@ static int load_files_with_prefix(const char* orig_file)
|
||||||
// Don't delete the old filename - it's pointed to by
|
// Don't delete the old filename - it's pointed to by
|
||||||
// every BroObj created when parsing it.
|
// every BroObj created when parsing it.
|
||||||
yylloc.filename = filename = full_filename;
|
yylloc.filename = filename = full_filename;
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
char* bifExtStart = strstr(full_filename, ".bif.bro");
|
||||||
|
BroDoc* reST_doc;
|
||||||
|
|
||||||
|
if ( bifExtStart )
|
||||||
|
reST_doc = new BroBifDoc(full_filename);
|
||||||
|
else
|
||||||
|
reST_doc = new BroDoc(full_filename);
|
||||||
|
|
||||||
|
docs_generated.push_back(reST_doc);
|
||||||
|
|
||||||
|
current_reST_doc = reST_doc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -589,6 +715,18 @@ void do_atendif()
|
||||||
--current_depth;
|
--current_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_doc_token_start()
|
||||||
|
{
|
||||||
|
if ( generate_documentation )
|
||||||
|
BEGIN(DOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_doc_token_stop()
|
||||||
|
{
|
||||||
|
if ( generate_documentation )
|
||||||
|
BEGIN(INITIAL);
|
||||||
|
}
|
||||||
|
|
||||||
// Be careful to never delete things from this list, as the strings
|
// Be careful to never delete things from this list, as the strings
|
||||||
// are referred to (in order to save the locations of tokens and statements,
|
// are referred to (in order to save the locations of tokens and statements,
|
||||||
// for error reporting and debugging).
|
// for error reporting and debugging).
|
||||||
|
@ -655,6 +793,9 @@ int yywrap()
|
||||||
// Stack is now empty.
|
// Stack is now empty.
|
||||||
while ( input_files.length() > 0 )
|
while ( input_files.length() > 0 )
|
||||||
{
|
{
|
||||||
|
check_capture_filter_changes();
|
||||||
|
check_dpd_config_changes();
|
||||||
|
|
||||||
if ( load_files_with_prefix(input_files[0]) )
|
if ( load_files_with_prefix(input_files[0]) )
|
||||||
{
|
{
|
||||||
// Don't delete the filename - it's pointed to by
|
// Don't delete the filename - it's pointed to by
|
||||||
|
@ -668,6 +809,9 @@ int yywrap()
|
||||||
(void) input_files.remove_nth(0);
|
(void) input_files.remove_nth(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_capture_filter_changes();
|
||||||
|
check_dpd_config_changes();
|
||||||
|
|
||||||
// Add redef statements for any X=Y command line parameters.
|
// Add redef statements for any X=Y command line parameters.
|
||||||
if ( params.size() > 0 )
|
if ( params.size() > 0 )
|
||||||
{
|
{
|
||||||
|
@ -731,6 +875,20 @@ int yywrap()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( generate_documentation )
|
||||||
|
{
|
||||||
|
std::list<BroDoc*>::iterator it;
|
||||||
|
|
||||||
|
for ( it = docs_generated.begin(); it != docs_generated.end(); ++it )
|
||||||
|
{
|
||||||
|
(*it)->WriteDocFile();
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
docs_generated.clear();
|
||||||
|
clear_reST_doc_comments();
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, we are done.
|
// Otherwise, we are done.
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -742,6 +900,7 @@ FileInfo::FileInfo(string arg_restore_module)
|
||||||
name = ::filename;
|
name = ::filename;
|
||||||
line = ::line_number;
|
line = ::line_number;
|
||||||
level = ::include_level;
|
level = ::include_level;
|
||||||
|
doc = ::current_reST_doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInfo::~FileInfo()
|
FileInfo::~FileInfo()
|
||||||
|
@ -753,6 +912,8 @@ FileInfo::~FileInfo()
|
||||||
yylloc.filename = filename = name;
|
yylloc.filename = filename = name;
|
||||||
yylloc.first_line = yylloc.last_line = line_number = line;
|
yylloc.first_line = yylloc.last_line = line_number = line;
|
||||||
include_level = level;
|
include_level = level;
|
||||||
|
last_reST_doc = current_reST_doc;
|
||||||
|
current_reST_doc = doc;
|
||||||
|
|
||||||
if ( restore_module != "" )
|
if ( restore_module != "" )
|
||||||
current_module = restore_module;
|
current_module = restore_module;
|
||||||
|
@ -779,3 +940,93 @@ static void report_file()
|
||||||
files_reported.append(copy_string(filename));
|
files_reported.append(copy_string(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_capture_filter_changes()
|
||||||
|
{
|
||||||
|
if ( ! generate_documentation )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Lookup the "capture_filters" identifier, if it has any defined
|
||||||
|
// value, add it to the script's reST documentation, and finally
|
||||||
|
// clear the table so it doesn't taint the documentation for
|
||||||
|
// subsequent scripts.
|
||||||
|
|
||||||
|
ID* capture_filters = global_scope()->Lookup("capture_filters");
|
||||||
|
|
||||||
|
if ( capture_filters )
|
||||||
|
{
|
||||||
|
ODesc desc;
|
||||||
|
desc.SetIndentSpaces(4);
|
||||||
|
capture_filters->ID_Val()->Describe(&desc);
|
||||||
|
last_reST_doc->SetPacketFilter(desc.Description());
|
||||||
|
capture_filters->ID_Val()->AsTableVal()->RemoveAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_dpd_config_changes()
|
||||||
|
{
|
||||||
|
if ( ! generate_documentation )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Lookup the "dpd_config" identifier, if it has any defined value,
|
||||||
|
// add it to the script's documentation, and clear the table so that
|
||||||
|
// it doesn't taint the documentation for subsequent scripts.
|
||||||
|
ID* dpd_config = global_scope()->Lookup("dpd_config");
|
||||||
|
if ( ! dpd_config )
|
||||||
|
return;
|
||||||
|
|
||||||
|
TableVal* dpd_table = dpd_config->ID_Val()->AsTableVal();
|
||||||
|
ListVal* dpd_list = dpd_table->ConvertToList();
|
||||||
|
|
||||||
|
for ( int i = 0; i < dpd_list->Length(); ++i )
|
||||||
|
{
|
||||||
|
Val* key = dpd_list->Index(i);
|
||||||
|
if ( ! key )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Val* v = dpd_table->Lookup(key);
|
||||||
|
if ( ! v )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int tag = key->AsListVal()->Index(0)->AsCount();
|
||||||
|
ODesc valdesc;
|
||||||
|
valdesc.SetIndentSpaces(4);
|
||||||
|
valdesc.PushIndent();
|
||||||
|
v->Describe(&valdesc);
|
||||||
|
|
||||||
|
if ( tag < AnalyzerTag::Error || tag > AnalyzerTag::LastAnalyzer )
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Warning: skipped bad analyzer tag: %i\n", tag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_reST_doc->AddPortAnalysis(
|
||||||
|
Analyzer::GetTagName((AnalyzerTag::Tag)tag),
|
||||||
|
valdesc.Description());
|
||||||
|
}
|
||||||
|
|
||||||
|
dpd_table->RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_current_reST_doc_comments()
|
||||||
|
{
|
||||||
|
if ( ! reST_doc_comments )
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<std::string>::iterator it;
|
||||||
|
|
||||||
|
for ( it = reST_doc_comments->begin(); it != reST_doc_comments->end(); ++it )
|
||||||
|
fprintf(stderr, "##%s\n", it->c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_reST_doc_comments()
|
||||||
|
{
|
||||||
|
if ( ! reST_doc_comments )
|
||||||
|
return;
|
||||||
|
|
||||||
|
fprintf(stderr, "Warning: %lu unconsumed reST comments:\n",
|
||||||
|
reST_doc_comments->size());
|
||||||
|
|
||||||
|
print_current_reST_doc_comments();
|
||||||
|
delete reST_doc_comments;
|
||||||
|
reST_doc_comments = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
.. Automatically generated. Do not edit.
|
||||||
|
|
||||||
|
autogen-reST-enums.bro
|
||||||
|
======================
|
||||||
|
|
||||||
|
:download:`Original Source File <autogen-reST-enums.bro>`
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
|
||||||
|
Summary
|
||||||
|
~~~~~~~
|
||||||
|
Types
|
||||||
|
#####
|
||||||
|
======================================= ======================================
|
||||||
|
:bro:type:`TestEnum1`: :bro:type:`enum` There's tons of ways an enum can look.
|
||||||
|
|
||||||
|
:bro:type:`TestEnum2`: :bro:type:`enum` The final comma is optional
|
||||||
|
======================================= ======================================
|
||||||
|
|
||||||
|
Redefinitions
|
||||||
|
#############
|
||||||
|
======================================= =======================
|
||||||
|
:bro:type:`TestEnum1`: :bro:type:`enum` redefs should also work
|
||||||
|
|
||||||
|
:bro:type:`TestEnum1`: :bro:type:`enum` now with a comma
|
||||||
|
======================================= =======================
|
||||||
|
|
||||||
|
Public Interface
|
||||||
|
----------------
|
||||||
|
Types
|
||||||
|
~~~~~
|
||||||
|
.. bro:type:: TestEnum1
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: ONE TestEnum1
|
||||||
|
|
||||||
|
like this
|
||||||
|
|
||||||
|
.. bro:enum:: TWO TestEnum1
|
||||||
|
|
||||||
|
or like this
|
||||||
|
|
||||||
|
.. bro:enum:: THREE TestEnum1
|
||||||
|
|
||||||
|
multiple
|
||||||
|
comments
|
||||||
|
and even
|
||||||
|
more comments
|
||||||
|
|
||||||
|
There's tons of ways an enum can look...
|
||||||
|
|
||||||
|
.. bro:type:: TestEnum2
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: A TestEnum2
|
||||||
|
|
||||||
|
like this
|
||||||
|
|
||||||
|
.. bro:enum:: B TestEnum2
|
||||||
|
|
||||||
|
or like this
|
||||||
|
|
||||||
|
.. bro:enum:: C TestEnum2
|
||||||
|
|
||||||
|
multiple
|
||||||
|
comments
|
||||||
|
and even
|
||||||
|
more comments
|
||||||
|
|
||||||
|
The final comma is optional
|
||||||
|
|
||||||
|
Redefinitions
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
:bro:type:`TestEnum1`
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: FOUR TestEnum1
|
||||||
|
|
||||||
|
adding another
|
||||||
|
value
|
||||||
|
|
||||||
|
redefs should also work
|
||||||
|
|
||||||
|
:bro:type:`TestEnum1`
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: FIVE TestEnum1
|
||||||
|
|
||||||
|
adding another
|
||||||
|
value
|
||||||
|
|
||||||
|
now with a comma
|
||||||
|
|
282
testing/btest/Baseline/doc.autogen-reST-example/example.rst
Normal file
282
testing/btest/Baseline/doc.autogen-reST-example/example.rst
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
.. Automatically generated. Do not edit.
|
||||||
|
|
||||||
|
example.bro
|
||||||
|
===========
|
||||||
|
|
||||||
|
:download:`Original Source File <example.bro>`
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
This is an example script that demonstrates how to document. Comments
|
||||||
|
of the form ``##!`` are for the script summary. The contents of
|
||||||
|
these comments are transferred directly into the auto-generated
|
||||||
|
`reStructuredText <http://docutils.sourceforge.net/rst.html>`_
|
||||||
|
(reST) document's summary section.
|
||||||
|
|
||||||
|
.. tip:: You can embed directives and roles within ``##``-stylized comments
|
||||||
|
|
||||||
|
:Author: Jon Siwek <jsiwek@ncsa.illinois.edu>
|
||||||
|
|
||||||
|
:Imports: :doc:`notice`
|
||||||
|
|
||||||
|
Summary
|
||||||
|
~~~~~~~
|
||||||
|
Options
|
||||||
|
#######
|
||||||
|
============================================================================ ======================================
|
||||||
|
:bro:id:`Example::an_option`: :bro:type:`set` :bro:attr:`&redef` add documentation for "an_option" here
|
||||||
|
|
||||||
|
:bro:id:`Example::option_with_init`: :bro:type:`interval` :bro:attr:`&redef`
|
||||||
|
============================================================================ ======================================
|
||||||
|
|
||||||
|
State Variables
|
||||||
|
###############
|
||||||
|
=========================================================================== =======================================
|
||||||
|
:bro:id:`Example::a_var`: :bro:type:`bool` put some documentation for "a_var" here
|
||||||
|
|
||||||
|
:bro:id:`Example::var_with_attr`: :bro:type:`count` :bro:attr:`&persistent`
|
||||||
|
|
||||||
|
:bro:id:`Example::var_without_explicit_type`: :bro:type:`string`
|
||||||
|
=========================================================================== =======================================
|
||||||
|
|
||||||
|
Types
|
||||||
|
#####
|
||||||
|
====================================================== ==========================================================
|
||||||
|
:bro:type:`Example::SimpleEnum`: :bro:type:`enum` documentation for "SimpleEnum"
|
||||||
|
goes here.
|
||||||
|
|
||||||
|
:bro:type:`Example::SimpleRecord`: :bro:type:`record` general documentation for a type "SimpleRecord"
|
||||||
|
goes here.
|
||||||
|
|
||||||
|
:bro:type:`Example::ComplexRecord`: :bro:type:`record` general documentation for a type "ComplexRecord" goes here
|
||||||
|
====================================================== ==========================================================
|
||||||
|
|
||||||
|
Events
|
||||||
|
######
|
||||||
|
============================================== ==========================
|
||||||
|
:bro:id:`Example::an_event`: :bro:type:`event` Summarize "an_event" here.
|
||||||
|
============================================== ==========================
|
||||||
|
|
||||||
|
Functions
|
||||||
|
#########
|
||||||
|
=============================================== =======================================
|
||||||
|
:bro:id:`Example::a_function`: :bro:type:`func` Summarize purpose of "a_function" here.
|
||||||
|
=============================================== =======================================
|
||||||
|
|
||||||
|
Redefinitions
|
||||||
|
#############
|
||||||
|
================================================= ====================================
|
||||||
|
:bro:type:`Example::SimpleEnum`: :bro:type:`enum` document the "SimpleEnum" redef here
|
||||||
|
================================================= ====================================
|
||||||
|
|
||||||
|
Namespaces
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. bro:namespace:: Example
|
||||||
|
|
||||||
|
Notices
|
||||||
|
~~~~~~~
|
||||||
|
:bro:type:`Notice`
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: Example::Notice_One Notice
|
||||||
|
|
||||||
|
any number of this type of comment
|
||||||
|
will document "Notice_One"
|
||||||
|
|
||||||
|
.. bro:enum:: Example::Notice_Two Notice
|
||||||
|
|
||||||
|
any number of this type of comment
|
||||||
|
will document "Notice_Two"
|
||||||
|
|
||||||
|
.. bro:enum:: Example::Notice_Three Notice
|
||||||
|
|
||||||
|
.. bro:enum:: Example::Notice_Four Notice
|
||||||
|
|
||||||
|
Public Interface
|
||||||
|
----------------
|
||||||
|
Options
|
||||||
|
~~~~~~~
|
||||||
|
.. bro:id:: Example::an_option
|
||||||
|
|
||||||
|
:Type: :bro:type:`set` [:bro:type:`addr`, :bro:type:`addr`, :bro:type:`string`]
|
||||||
|
:Attributes: :bro:attr:`&redef`
|
||||||
|
:Default: ``{}``
|
||||||
|
|
||||||
|
add documentation for "an_option" here
|
||||||
|
|
||||||
|
.. bro:id:: Example::option_with_init
|
||||||
|
|
||||||
|
:Type: :bro:type:`interval`
|
||||||
|
:Attributes: :bro:attr:`&redef`
|
||||||
|
:Default: ``10.0 msecs``
|
||||||
|
|
||||||
|
State Variables
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
.. bro:id:: Example::a_var
|
||||||
|
|
||||||
|
:Type: :bro:type:`bool`
|
||||||
|
|
||||||
|
put some documentation for "a_var" here
|
||||||
|
|
||||||
|
.. bro:id:: Example::var_with_attr
|
||||||
|
|
||||||
|
:Type: :bro:type:`count`
|
||||||
|
:Attributes: :bro:attr:`&persistent`
|
||||||
|
|
||||||
|
.. bro:id:: Example::var_without_explicit_type
|
||||||
|
|
||||||
|
:Type: :bro:type:`string`
|
||||||
|
:Default: ``"this works"``
|
||||||
|
|
||||||
|
Types
|
||||||
|
~~~~~
|
||||||
|
.. bro:type:: Example::SimpleEnum
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: Example::ONE Example::SimpleEnum
|
||||||
|
|
||||||
|
and more specific info for "ONE"
|
||||||
|
can span multiple lines
|
||||||
|
|
||||||
|
.. bro:enum:: Example::TWO Example::SimpleEnum
|
||||||
|
|
||||||
|
or more info like this for "TWO"
|
||||||
|
can span multiple lines
|
||||||
|
|
||||||
|
.. bro:enum:: Example::THREE Example::SimpleEnum
|
||||||
|
|
||||||
|
documentation for "SimpleEnum"
|
||||||
|
goes here.
|
||||||
|
|
||||||
|
.. bro:type:: Example::SimpleRecord
|
||||||
|
|
||||||
|
:Type: :bro:type:`record`
|
||||||
|
|
||||||
|
field1: :bro:type:`count`
|
||||||
|
counts something
|
||||||
|
|
||||||
|
field2: :bro:type:`bool`
|
||||||
|
toggles something
|
||||||
|
|
||||||
|
general documentation for a type "SimpleRecord"
|
||||||
|
goes here.
|
||||||
|
|
||||||
|
.. bro:type:: Example::ComplexRecord
|
||||||
|
|
||||||
|
:Type: :bro:type:`record`
|
||||||
|
|
||||||
|
field1: :bro:type:`count`
|
||||||
|
counts something
|
||||||
|
|
||||||
|
field2: :bro:type:`bool`
|
||||||
|
toggles something
|
||||||
|
|
||||||
|
field3: :bro:type:`Example::SimpleRecord`
|
||||||
|
|
||||||
|
msg: :bro:type:`string` :bro:attr:`&default` = ``"blah"`` :bro:attr:`&optional`
|
||||||
|
attributes are self-documenting
|
||||||
|
|
||||||
|
general documentation for a type "ComplexRecord" goes here
|
||||||
|
|
||||||
|
Events
|
||||||
|
~~~~~~
|
||||||
|
.. bro:id:: Example::an_event
|
||||||
|
|
||||||
|
:Type: :bro:type:`event` (name: :bro:type:`string`)
|
||||||
|
|
||||||
|
Summarize "an_event" here.
|
||||||
|
Give more details about "an_event" here.
|
||||||
|
|
||||||
|
:param name: describe the argument here
|
||||||
|
|
||||||
|
Functions
|
||||||
|
~~~~~~~~~
|
||||||
|
.. bro:id:: Example::a_function
|
||||||
|
|
||||||
|
:Type: :bro:type:`function` (tag: :bro:type:`string`, msg: :bro:type:`string`) : :bro:type:`string`
|
||||||
|
|
||||||
|
Summarize purpose of "a_function" here.
|
||||||
|
Give more details about "a_function" here.
|
||||||
|
Separating the documentation of the params/return values with
|
||||||
|
empty comments is optional, but improves readability of script.
|
||||||
|
|
||||||
|
|
||||||
|
:param tag: function arguments can be described
|
||||||
|
like this
|
||||||
|
|
||||||
|
:param msg: another param
|
||||||
|
|
||||||
|
|
||||||
|
:returns: describe the return type here
|
||||||
|
|
||||||
|
Redefinitions
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
:bro:type:`Example::SimpleEnum`
|
||||||
|
|
||||||
|
:Type: :bro:type:`enum`
|
||||||
|
|
||||||
|
.. bro:enum:: Example::FOUR Example::SimpleEnum
|
||||||
|
|
||||||
|
and some documentation for "FOUR"
|
||||||
|
|
||||||
|
.. bro:enum:: Example::FIVE Example::SimpleEnum
|
||||||
|
|
||||||
|
also "FIVE" for good measure
|
||||||
|
|
||||||
|
document the "SimpleEnum" redef here
|
||||||
|
|
||||||
|
Port Analysis
|
||||||
|
-------------
|
||||||
|
:ref:`More Information <common_port_analysis_doc>`
|
||||||
|
|
||||||
|
SSL::
|
||||||
|
|
||||||
|
[ports={
|
||||||
|
563/tcp,
|
||||||
|
443/tcp
|
||||||
|
}]
|
||||||
|
|
||||||
|
Packet Filter
|
||||||
|
-------------
|
||||||
|
:ref:`More Information <common_packet_filter_doc>`
|
||||||
|
|
||||||
|
Filters added::
|
||||||
|
|
||||||
|
[nntps] = tcp port 563,
|
||||||
|
[ssl] = tcp port 443
|
||||||
|
|
||||||
|
Private Interface
|
||||||
|
-----------------
|
||||||
|
State Variables
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
.. bro:id:: Example::example_ports
|
||||||
|
|
||||||
|
:Type: :bro:type:`set` [:bro:type:`port`]
|
||||||
|
:Attributes: :bro:attr:`&redef`
|
||||||
|
:Default:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
563/tcp,
|
||||||
|
443/tcp
|
||||||
|
}
|
||||||
|
|
||||||
|
Types
|
||||||
|
~~~~~
|
||||||
|
.. bro:type:: Example::PrivateRecord
|
||||||
|
|
||||||
|
:Type: :bro:type:`record`
|
||||||
|
|
||||||
|
field1: :bro:type:`bool`
|
||||||
|
|
||||||
|
field2: :bro:type:`count`
|
||||||
|
|
||||||
|
Functions
|
||||||
|
~~~~~~~~~
|
||||||
|
.. bro:id:: Example::function_without_proto
|
||||||
|
|
||||||
|
:Type: :bro:type:`function` (tag: :bro:type:`string`) : :bro:type:`string`
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
.. Automatically generated. Do not edit.
|
||||||
|
|
||||||
|
autogen-reST-records.bro
|
||||||
|
========================
|
||||||
|
|
||||||
|
:download:`Original Source File <autogen-reST-records.bro>`
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
|
||||||
|
Summary
|
||||||
|
~~~~~~~
|
||||||
|
Types
|
||||||
|
#####
|
||||||
|
============================================ ============================================================
|
||||||
|
:bro:type:`SimpleRecord`: :bro:type:`record`
|
||||||
|
|
||||||
|
:bro:type:`TestRecord`: :bro:type:`record` Here's the ways records and record fields can be documented.
|
||||||
|
============================================ ============================================================
|
||||||
|
|
||||||
|
Public Interface
|
||||||
|
----------------
|
||||||
|
Types
|
||||||
|
~~~~~
|
||||||
|
.. bro:type:: SimpleRecord
|
||||||
|
|
||||||
|
:Type: :bro:type:`record`
|
||||||
|
|
||||||
|
field1: :bro:type:`bool`
|
||||||
|
|
||||||
|
field2: :bro:type:`count`
|
||||||
|
|
||||||
|
.. bro:type:: TestRecord
|
||||||
|
|
||||||
|
:Type: :bro:type:`record`
|
||||||
|
|
||||||
|
A: :bro:type:`count`
|
||||||
|
document ``A``
|
||||||
|
|
||||||
|
B: :bro:type:`bool`
|
||||||
|
document ``B``
|
||||||
|
|
||||||
|
C: :bro:type:`SimpleRecord`
|
||||||
|
and now ``C``
|
||||||
|
is a declared type
|
||||||
|
|
||||||
|
D: :bro:type:`set` [:bro:type:`count`, :bro:type:`bool`]
|
||||||
|
sets/tables should show the index types
|
||||||
|
|
||||||
|
Here's the ways records and record fields can be documented.
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
.. Automatically generated. Do not edit.
|
||||||
|
|
||||||
|
autogen-reST-type-aliases.bro
|
||||||
|
=============================
|
||||||
|
|
||||||
|
:download:`Original Source File <autogen-reST-type-aliases.bro>`
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
|
||||||
|
Summary
|
||||||
|
~~~~~~~
|
||||||
|
State Variables
|
||||||
|
###############
|
||||||
|
======================================= =======================================================
|
||||||
|
:bro:id:`a`: :bro:type:`TypeAlias` But this should reference a type of ``TypeAlias``.
|
||||||
|
|
||||||
|
:bro:id:`b`: :bro:type:`OtherTypeAlias` And this should reference a type of ``OtherTypeAlias``.
|
||||||
|
======================================= =======================================================
|
||||||
|
|
||||||
|
Types
|
||||||
|
#####
|
||||||
|
============================================ ==========================================================================
|
||||||
|
:bro:type:`TypeAlias`: :bro:type:`bool` This is just an alias for a builtin type ``bool``.
|
||||||
|
|
||||||
|
:bro:type:`OtherTypeAlias`: :bro:type:`bool` We decided that creating alias "chains" might now be so useful to document
|
||||||
|
so this type just creates a cross reference to ``bool``.
|
||||||
|
============================================ ==========================================================================
|
||||||
|
|
||||||
|
Public Interface
|
||||||
|
----------------
|
||||||
|
State Variables
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
.. bro:id:: a
|
||||||
|
|
||||||
|
:Type: :bro:type:`TypeAlias`
|
||||||
|
|
||||||
|
But this should reference a type of ``TypeAlias``.
|
||||||
|
|
||||||
|
.. bro:id:: b
|
||||||
|
|
||||||
|
:Type: :bro:type:`OtherTypeAlias`
|
||||||
|
|
||||||
|
And this should reference a type of ``OtherTypeAlias``.
|
||||||
|
|
||||||
|
Types
|
||||||
|
~~~~~
|
||||||
|
.. bro:type:: TypeAlias
|
||||||
|
|
||||||
|
:Type: :bro:type:`bool`
|
||||||
|
|
||||||
|
This is just an alias for a builtin type ``bool``.
|
||||||
|
|
||||||
|
.. bro:type:: OtherTypeAlias
|
||||||
|
|
||||||
|
:Type: :bro:type:`bool`
|
||||||
|
|
||||||
|
We decided that creating alias "chains" might now be so useful to document
|
||||||
|
so this type just creates a cross reference to ``bool``.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
[btest]
|
[btest]
|
||||||
TestDirs =
|
TestDirs = doc
|
||||||
TmpDir = %(testbase)s/.tmp
|
TmpDir = %(testbase)s/.tmp
|
||||||
BaselineDir = %(testbase)s/Baseline
|
BaselineDir = %(testbase)s/Baseline
|
||||||
IgnoreDirs = .svn CVS .tmp
|
IgnoreDirs = .svn CVS .tmp
|
||||||
|
|
36
testing/btest/doc/autogen-reST-enums.bro
Normal file
36
testing/btest/doc/autogen-reST-enums.bro
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# @TEST-EXEC: bro --doc-scripts %INPUT
|
||||||
|
# @TEST-EXEC: btest-diff autogen-reST-enums.rst
|
||||||
|
|
||||||
|
## There's tons of ways an enum can look...
|
||||||
|
type TestEnum1: enum {
|
||||||
|
## like this
|
||||||
|
ONE,
|
||||||
|
TWO, ##< or like this
|
||||||
|
## multiple
|
||||||
|
## comments
|
||||||
|
THREE, ##< and even
|
||||||
|
##< more comments
|
||||||
|
};
|
||||||
|
|
||||||
|
## The final comma is optional
|
||||||
|
type TestEnum2: enum {
|
||||||
|
## like this
|
||||||
|
A,
|
||||||
|
B, ##< or like this
|
||||||
|
## multiple
|
||||||
|
## comments
|
||||||
|
C ##< and even
|
||||||
|
##< more comments
|
||||||
|
};
|
||||||
|
|
||||||
|
## redefs should also work
|
||||||
|
redef enum TestEnum1 += {
|
||||||
|
## adding another
|
||||||
|
FOUR ##< value
|
||||||
|
};
|
||||||
|
|
||||||
|
## now with a comma
|
||||||
|
redef enum TestEnum1 += {
|
||||||
|
## adding another
|
||||||
|
FIVE, ##< value
|
||||||
|
};
|
2
testing/btest/doc/autogen-reST-example
Normal file
2
testing/btest/doc/autogen-reST-example
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@TEST-EXEC: bro --doc-scripts $DIST/doc/example.bro
|
||||||
|
@TEST-EXEC: btest-diff example.rst
|
22
testing/btest/doc/autogen-reST-records.bro
Normal file
22
testing/btest/doc/autogen-reST-records.bro
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# @TEST-EXEC: bro --doc-scripts %INPUT
|
||||||
|
# @TEST-EXEC: btest-diff autogen-reST-records.rst
|
||||||
|
|
||||||
|
# undocumented record
|
||||||
|
type SimpleRecord: record {
|
||||||
|
field1: bool;
|
||||||
|
field2: count;
|
||||||
|
};
|
||||||
|
|
||||||
|
## Here's the ways records and record fields can be documented.
|
||||||
|
type TestRecord: record {
|
||||||
|
## document ``A``
|
||||||
|
A: count;
|
||||||
|
|
||||||
|
B: bool; ##< document ``B``
|
||||||
|
|
||||||
|
## and now ``C``
|
||||||
|
C: SimpleRecord; ##< is a declared type
|
||||||
|
|
||||||
|
## sets/tables should show the index types
|
||||||
|
D: set[count, bool];
|
||||||
|
};
|
15
testing/btest/doc/autogen-reST-type-aliases.bro
Normal file
15
testing/btest/doc/autogen-reST-type-aliases.bro
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# @TEST-EXEC: bro --doc-scripts %INPUT
|
||||||
|
# @TEST-EXEC: btest-diff autogen-reST-type-aliases.rst
|
||||||
|
|
||||||
|
## This is just an alias for a builtin type ``bool``.
|
||||||
|
type TypeAlias: bool;
|
||||||
|
|
||||||
|
## We decided that creating alias "chains" might now be so useful to document
|
||||||
|
## so this type just creates a cross reference to ``bool``.
|
||||||
|
type OtherTypeAlias: TypeAlias;
|
||||||
|
|
||||||
|
## But this should reference a type of ``TypeAlias``.
|
||||||
|
global a: TypeAlias;
|
||||||
|
|
||||||
|
## And this should reference a type of ``OtherTypeAlias``.
|
||||||
|
global b: OtherTypeAlias;
|
Loading…
Add table
Add a link
Reference in a new issue