# '|code|' - literal string
# match expressions used to find embedded type information
-$type_constant = "\\\%(\\w+)";
+$type_constant = "(?<![|])\\\%(\\w+)";
$type_func = "(\\w+\\(\\))";
$type_param = "\\\@(\\w+)";
$type_struct = "\\\&(\\w+)";
# generate a sequence of code that will splice in highlighting information
# using the s// operator.
$dohighlight = "";
-foreach $pattern (keys %highlights) {
+foreach $pattern (sort keys %highlights) {
# print "scanning pattern $pattern ($highlights{$pattern})\n";
$dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
}
# print out each section
$lineprefix=" ";
foreach $section (@{$args{'sectionlist'}}) {
- print "<sect>$section\n<p>\n";
+ my $lbl = lc $section;
+ $lbl =~ tr/ /-/;
+ print "<sect>$section\n<label id=\"$lbl\"><p>\n";
output_highlight($args{'sections'}{$section});
}
<chapt>BIRD Design
+<label id="bird-design">
<sect>Introduction
+<label id="bird-design-introduction">
<p>This document describes the internal workings of BIRD, its architecture,
design decisions and rationale behind them. It also contains documentation on
by the program source itself together with comments contained therein.
<sect>Design goals
+<label id="bird-design-goals">
<p>When planning the architecture of BIRD, we've taken a close look at the other existing routing
daemons and also at some of the operating systems used on dedicated routers, gathered all important
</itemize>
<sect>Architecture
+<label id="bird-design-architecture">
<p>The requirements set above have lead to a simple modular architecture containing
the following types of modules:
</descrip>
<sect>Implementation
+<label id="bird-design-implementation">
<p>BIRD has been written in GNU C. We've considered using C++, but we've
preferred the simplicity and straightforward nature of C which gives us fine
-->
<chapt>Resources
+<label id="resources">
<sect>Introduction
+<label id="resources-introduction">
<p>Most large software projects implemented in classical procedural
programming languages usually end up with lots of code taking care
-->
<sect>Routing protocols
+<label id="routing-protocols">
<sect1>Introduction
+<label id="routing-protocols-introduction">
<p>The routing protocols are the bird's heart and a fine amount of code
is dedicated to their management and for providing support functions to them.
to the description of the <func/proto_commit/ function.
<sect1>Protocol states
+<label id="routing-protocols-states">
<p>As startup and shutdown of each protocol are complex processes which can be affected
by lots of external events (user's actions, reconfigurations, behavior of neighboring routers etc.),
<p>At any time, the core code can ask the protocol to shut itself down by calling its stop() hook.
<sect1>Functions of the protocol module
+<label id="routing-protocols-functions">
<p>The protocol module provides the following functions:
* transport. Transport is a way how to wrap a communication with a cache
* server. There is supported an unprotected TCP transport and an encrypted
* SSHv2 transport. The SSH transport requires LibSSH library. LibSSH is
- * loading dynamically using |dlopen()| function. SSH support is integrated in
+ * loading dynamically using dlopen() function. SSH support is integrated in
* |sysdep/unix/io.c|. Each transport must implement an initialization
* function, an open function and a socket identification function. That's all.
*
* |tcp_transport.c| and |ssh_transport.c| from RTRlib.
*
* A RPKI-RTR connection is described by a structure &rpki_cache. The main
- * logic is located in |rpki_cache_change_state()| function. There is a state
+ * logic is located in rpki_cache_change_state() function. There is a state
* machine. The standard starting state flow looks like |Down| ~> |Connecting|
* ~> |Sync-Start| ~> |Sync-Running| ~> |Established| and then the last three
* states are periodically repeated.
*
* |Connecting| state establishes the transport connection. The state from a
- * call |rpki_cache_change_state(CONNECTING)| to a call |rpki_connected_hook()|
+ * call rpki_cache_change_state(CONNECTING) to a call rpki_connected_hook()
*
* |Sync-Start| state starts with sending |Reset Query| or |Serial Query| and
- * then waits for |Cache Response|. The state from |rpki_connected_hook()| to
- * |rpki_handle_cache_response_pdu()|
+ * then waits for |Cache Response|. The state from rpki_connected_hook() to
+ * rpki_handle_cache_response_pdu()
*
* During |Sync-Running| BIRD receives data with IPv4/IPv6 Prefixes from cache
- * server. The state starts from |rpki_handle_cache_response_pdu()| and ends
- * in |rpki_handle_end_of_data_pdu()|.
+ * server. The state starts from rpki_handle_cache_response_pdu() and ends
+ * in rpki_handle_end_of_data_pdu().
*
* |Established| state means that BIRD has synced all data with cache server.
* Schedules a refresh timer event that invokes |Sync-Start|. Schedules Expire
*
* The RPKI-RTR protocol (RFC 6810 bis) defines configurable refresh, retry and
* expire intervals. For maintaining a connection are used timer events that
- * are scheduled by |rpki_schedule_next_refresh()|,
- * |rpki_schedule_next_retry()| and |rpki_schedule_next_expire()| functions.
+ * are scheduled by rpki_schedule_next_refresh(),
+ * rpki_schedule_next_retry() and rpki_schedule_next_expire() functions.
*
* A Refresh timer event performs a sync of |Established| connection. So it
* shifts state to |Sync-Start|. If at the beginning of second call of a
-->
<chapt>System dependent parts
+<label id="sysdep">
<sect>Introduction
+<label id="sysdep-intro">
<p>We've tried to make BIRD as portable as possible, but unfortunately
communication with the network stack differs from one OS to another,
so we need at least some OS specific code. The good news is that this
code is isolated in a small set of modules:
-<descrip>
+<p><descrip>
<tagp><tt/config.h/</tagp> is a header file with configuration information,
definition of the standard set of types and so on.
<tagp/Startup module/ controls BIRD startup. Common for a family of OS's (e.g.,
{%- set template_part = "header" %}
{%- set authors = [ $for(author-meta)$ "$author-meta$", $endfor$ ] %}
{%- set meta_additional = { "author": authors, } %}
+{%- set ns = namespace(progdoc=False) %}
+{%- for v in releases -%}
+ {%- if "$bird_version$" == v.version -%}
+ {%- set ns.progdoc = ("progdoc" in v) -%}
+ {%- endif -%}
+{%- endfor -%}
{%- include "main.html.j2" %}
<!--<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>-->
<section class="bg-light bird-documentation">
<div class="col-12 col-xl-6 col-lg-7">
<h1 class="title">{{ title }}</h1>
<div class="version-info pb-20 mb-20 border-bottom border-primary">
- <h4>Version $bird_version$ | <a href="/download/bird-doc-$bird_version$.tar.gz">TGZ</a></h4>
+ <h4>Version $bird_version$ | <a href="/download/bird-doc-$bird_version$.tar.gz">TGZ</a>{% if ns.progdoc %} | <a href="/doc/prog-$bird_version$.html">ProgDoc</a>{% endif %}</h4>
Available versions:
{% for v in releases | reverse -%}
{% if (v.type == 'current') or 'show_doc' in v %}
- <a href="
- {%- if "$bird_version$" == v.version -%}
- #
- {%- else -%}
- /doc/bird-{{ v.version }}.html
- {%- endif -%}
- " style="{% if v.type == 'current' %}font-weight: bold;{% endif %}">
+ <a href="/doc/bird-{{ v.version }}.html" style="{% if v.type == 'current' %}font-weight: bold;{% endif %}">
{{- v.version -}}
</a>
{%- if not loop.last %} | {% endif -%}
tilde = "~";
amp = "&";
verbar = "|";
+ latex = "LaTeX";
+ tex = "TeX";
}
local entity = P"&" * C(P(1 - S"&;")^1) * P";" / function (t)
local e = entitytab[t]
end;
BookInside = V"Comment" + V"BookIgnored" + V"Title" + V"Author" + V"Date" + V"DocumentID" + V"Abstract" + V"Chapter" + blankchar + V"ParseFail";
- BookIgnored = P"<toc>";
+ BookIgnored = P"<toc>" + P"<progdoc>";
Book = P"<book>" * Ct(V"BookInside"^1) * P"</book>" / mergetables;
Title = P"<title>" * inelement / function (t)
})
end;
Sect1Inside =
+ V"FunctionBlock" +
V"Sect2" +
V"Sect2Inside";
V"DescripList" +
V"CodeBlock" +
V"TableBlock" +
+ V"Comment" +
blankchar + V"ParseFail";
Para = P"<p>" * Ct(V"InPara") * P"</p>"^-1 / function (t)
V"FilePathShort" +
V"RFCRef" +
V"InternalRef" +
+ V"CodeStruct" +
+ V"CodeFunc" +
+ V"CodeConst" +
+ V"CodeType" +
+ V"CodeParam" +
V"Comment" +
(V"Label" / function (e) return pandoc.Span({}, { id = e }) end);
Emph = P"<em/" * ininline * P"/" / pandoc.Strong;
Bold = P"<bf/" * ininline * P"/" / pandoc.Strong;
- It = P"<it/" * ininline * P"/" / pandoc.Emph;
+ It = (
+ P"<it/" * ininline * P"/" +
+ P"<it>" * V"InPara" * P"</it>"
+ ) / pandoc.Emph;
InlineCodeIt = (P"<m/" + P"<M/") * ininline * P"/" / function (e)
return pandoc.Emph(e, { class = "code" })
end;
return pandoc.Code(e, { class = "filepath" })
end;
+ CodeStruct = P'<struct/' * ininline * P'/' / function (e)
+ return pandoc.Code("struct " .. e, { class = "ccode struct" })
+ end;
+
+ CodeFunc = P'<func/' * ininline * P'/' / function (e)
+ return pandoc.Code(e, { class = "ccode func" })
+ end;
+
+ CodeConst = (P'<const/' * ininline * P'/' + P'<const>' * inelement * P'</const>') / function (e)
+ return pandoc.Code(e, { class = "ccode const" })
+ end;
+
+ CodeType = P'<type>' * inelement * P'</type>' / function (t)
+ return pandoc.Code(t, { class = "ccode ctype" })
+ end;
+
+ CodeParam = (P'<param/' * ininline * P'/' + P'<param>' * inelement * P'</param>') / function (p)
+ return pandoc.Code(p, { class = "ccode cparam" })
+ end;
+
Label = P'<label id="' * C((1 - P('"'))^0) * P'">';
ItemList = P"<itemize>" * Ct((V"ItemListItem" + blankchar)^1) * P"</itemize>" / pandoc.BulletList;
ItemListItem = P"<item>" * V"InPara";
- DescripList = P"<descrip>" * Ct((V"DescripListItem" + blankchar)^1) * P"</descrip>" / pandoc.DefinitionList;
+ DescripList = P"<descrip>" * Ct((
+ V"DescripListItem" +
+ V"DescripListProgItem" +
+ V"DescripListShortItem" +
+ V"DescripListShortProgItem" +
+ blankchar)^1)
+ * P"</descrip>" / pandoc.DefinitionList;
+
DescripListItem = P"<tag>" * V"Label" * V"InPara" * "</tag>" * (V"InDescrip" - P"<tag>" - P"</descrip>") / function (l,t,u)
-- logging.temp("dli", t,u)
return { pandoc.Span(t, { class = "code", id = l }), { u }}
end;
+ DescripListProgItem = P"<tagp>" * V"InPara" * "</tagp>" * (V"InDescrip" - P"<tagp>" - P"</descrip>") / function (t,u)
+-- logging.temp("dli", t,u)
+ return { pandoc.Span(t, { class = "code" }), { u }}
+ end;
+
+ DescripListShortItem = P"<tag/" * ininline * "/" * (V"InDescrip" - P"<tag" - P"</descrip>") / function (t,u)
+-- logging.temp("dli", t,u)
+ return { pandoc.Span(t, { class = "code" }), { u }}
+ end;
+
+ DescripListShortProgItem = P"<tagp/" * ininline * "/" * (V"InDescrip" - P"<tag" - P"</descrip>") / function (t,u)
+-- logging.temp("dli", t,u)
+ return { pandoc.Span(t, { class = "code" }), { u }}
+ end;
+
CodeBlock = P'<code>' * C((1 - P'</code>')^0) * P'</code>' / pandoc.CodeBlock;
TableBlockIgnoreBf = P'<bf/' * ininline * '/';
)
end;
+-- FunctionBlock = P'<function><p>' * V"CodeType" * blankmore * V"FunctionName" * blankmore * '(' * V"FunctionHeaderArgs" * ')' * inelement / function (t, n, h, inside)
+ FunctionBlock = P'<function><p>' * V"CodeType" * blankmore
+ * '<funcdef>' * inelement * '</funcdef>' * blankmore
+ * V"FunctionHeaderArgs" * P' --'^0 * Ct(V"InPara") * V"FunctionDescription" * "</function>" / function (t, n, ha, hshort, desc)
+-- logging.temp(t, n, ha, hshort, desc)
+-- logging.temp("desc is", desc)
+ return pandoc.Div(mergetables({
+ pandoc.Header(4, {t, " ", n, ha}, { id = "function-" .. n }),
+ pandoc.Span(mergetables(hshort), { class = "functionshortdesc" }),
+ mergetables(desc)
+ }), { class = "function" }
+ )
+ end;
+
+ FunctionName = P'<funcdef>' * ininline * P'</funcdef>' / pandoc.Str;
+
+ FunctionHeaderArg = V"CodeType"^0 * blankmore * V"CodeParam" / function (t, p)
+ ts = tostring(t)
+ if ts[#ts-1] == "*" then
+ return pandoc.Span({ t, p }, { class = "functionargument" })
+ else
+ return pandoc.Span({ t, " ", p }, { class = "functionargument" })
+ end
+-- if #t then return pandoc.Span({ t[0], p }) else return pandoc.Span({ p }) end
+ end;
+
+ FunctionHeaderArgs = P'(' * Ct(( V"FunctionHeaderArg" * (P',' * blankmore)^0)^0) * P')' / function (a)
+ args = {}
+ for k,v in ipairs(a) do
+ table.insert(args, v)
+ if k < #a then
+ table.insert(args, ", ")
+ end
+ end
+ return pandoc.Span(mergetables({"(", args, ")"}), { class = "functionheaderargs" })
+ end;
+
+ FunctionDescription = Ct(V"FunctionDescSect"^0) / function (inside)
+ return mergetables(inside)
+ end;
+
+ FunctionDescSect = P'<funcsect>' * inelement * Ct((V"Sect3Inside" - P"<funcsect>" - P"</function>")^0) / function (name, inside)
+ return mergetables({
+ pandoc.Header(5, name, {}),
+ mergetables(inside),
+-- "meow end of " .. name,
+ })
+ end;
+
ParseFail = (1 - P"<sect>" - P"<chapt>" - P"</book>") / function (t) return pandoc.CodeBlock("PARSER FAILED " .. t) end;
}
if ($cmd eq "C") { process("$dir/$arg", "Doc"); }
elsif ($cmd eq "H") {
push @stack, "H";
- print OUT "<chapt>$arg\n";
+ my $lbl = lc $arg;
+ $lbl =~ tr/ /-/;
+ print OUT "<chapt>$arg\n<label id=\"$lbl\">\n";
} elsif ($cmd eq "S") {
print " $arg\n";
my @files = map("$dir/$_", split(' ', $arg));