diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3cd05d96..65e1bc5983 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,11 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev.csh "setenv BROPATH `${CMAKE_CURRENT_BINARY_DIR}/bro-path-dev`\n") 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") @@ -162,8 +167,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(src) add_subdirectory(policy) -#add_subdirectory(scripts) -#add_subdirectory(doc) +add_subdirectory(doc) include(CheckOptionalBuildSources) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000000..a5a97d5c3b --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,40 @@ +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) + +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) +# TODO: add dependency that's a check for `python`, `sphinx-build`, etc. + +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) diff --git a/doc/conf.py.in b/doc/conf.py.in new file mode 100644 index 0000000000..67e06abfb3 --- /dev/null +++ b/doc/conf.py.in @@ -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 +# " v 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 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) +] diff --git a/doc/example.bro b/doc/example.bro new file mode 100644 index 0000000000..6deab87f45 --- /dev/null +++ b/doc/example.bro @@ -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 `_ +##! (reST) document's summary section. +##! +##! .. tip:: You can embed directives and roles within ``##``-stylized comments +##! +##! :Author: Jon Siwek + +# 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; +}; diff --git a/doc/scripts/generate_reST_docs.py.in b/doc/scripts/generate_reST_docs.py.in new file mode 100755 index 0000000000..1d83cc01fb --- /dev/null +++ b/doc/scripts/generate_reST_docs.py.in @@ -0,0 +1,121 @@ +#! /usr/bin/env python + +import os +import subprocess +import shutil +import glob +import string + +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: + bro_src_file = "" + doc_src_file = "" + load_via_stdin = False + + def __init__(self, src_file, load_method=False, src_dir="@POLICY_SRC_DIR@"): + self.bro_src_file = os.path.join(src_dir, src_file) + self.load_via_stdin = load_method + + # 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 + + def GenDoc(self): + 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) + + for leftover in glob.glob("*.rst"): + os.remove(leftover) + +def GenDocs(doc_list, load_method=False): + for f in doc_list: + doc = BroToReST(f, load_method) + print "Generating reST document for " + f + doc.GenDoc() + +# search BROPATH for the script and return the absolute path to it +def FindBroScript(src_file): + for path in string.split(BROPATH, ":"): + abs_path = os.path.join(path, src_file) + if os.path.exists(abs_path): + return abs_path + +# Scripts that can be loaded by bro via command line argument +# TODO: generate docs for more scripts +docs = [ + "alarm.bro", + "arp.bro", + "conn.bro", + "dhcp.bro", + "dns.bro", + "ftp.bro", + "http.bro", + "http-reply.bro", + "http-request.bro", + "irc.bro", + "smtp.bro", + "ssl.bro", + "ssl-ciphers.bro", + "ssl-errors.bro", + "synflood.bro", + "tcp.bro", + "udp.bro", + "weird.bro", +] + +# 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", +] + +GenDocs(docs) +GenDocs(stdin_docs, True) + +BroToReST("example.bro", False, "@PROJECT_SOURCE_DIR@/doc").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 == ".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) + os.remove(doc) diff --git a/doc/source/_static/showhide.js b/doc/source/_static/showhide.js new file mode 100644 index 0000000000..d6a8923143 --- /dev/null +++ b/doc/source/_static/showhide.js @@ -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(''+showText+''); + + // 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
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(''+showText+''); + + // wrap all sub-sections in a new div that can be hidden/shown + $('#private-interface').children(".section").wrapAll('
'); + + // 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; + }); +}); diff --git a/doc/source/_templates/layout.html b/doc/source/_templates/layout.html new file mode 100644 index 0000000000..5685e1dc37 --- /dev/null +++ b/doc/source/_templates/layout.html @@ -0,0 +1,5 @@ +{% extends "!layout.html" %} +{% block extrahead %} + + {{ super() }} +{% endblock %} diff --git a/doc/source/builtins.rst b/doc/source/builtins.rst new file mode 100644 index 0000000000..886edab7c7 --- /dev/null +++ b/doc/source/builtins.rst @@ -0,0 +1,121 @@ +Builtins +======== + +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) diff --git a/doc/source/common.rst b/doc/source/common.rst new file mode 100644 index 0000000000..6105585b2c --- /dev/null +++ b/doc/source/common.rst @@ -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). diff --git a/doc/source/ext/bro.py b/doc/source/ext/bro.py new file mode 100644 index 0000000000..7ec02f76a8 --- /dev/null +++ b/doc/source/ext/bro.py @@ -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 diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000000..ac74c36d4d --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,20 @@ +.. Bro documentation master file + +Welcome to Bro's documentation! +=============================== + +Contents: + +.. toctree:: + :maxdepth: 1 + :glob: + + common + builtins + policy/index + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/doc/source/policy/index.rst b/doc/source/policy/index.rst new file mode 100644 index 0000000000..46345a67af --- /dev/null +++ b/doc/source/policy/index.rst @@ -0,0 +1,8 @@ +Policy Files +============ + +.. toctree:: + :maxdepth: 1 + :glob: + + *