1#   BSD LICENSE
2#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
3#   All rights reserved.
4#
5#   Redistribution and use in source and binary forms, with or without
6#   modification, are permitted provided that the following conditions
7#   are met:
8#
9#   * Redistributions of source code must retain the above copyright
10#   notice, this list of conditions and the following disclaimer.
11#   * Redistributions in binary form must reproduce the above copyright
12#   notice, this list of conditions and the following disclaimer in
13#   the documentation and/or other materials provided with the
14#   distribution.
15#   * Neither the name of Intel Corporation nor the names of its
16#   contributors may be used to endorse or promote products derived
17#   from this software without specific prior written permission.
18#
19#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31from __future__ import print_function
32import subprocess
33from docutils import nodes
34from distutils.version import LooseVersion
35from sphinx import __version__ as sphinx_version
36from sphinx.highlighting import PygmentsBridge
37from pygments.formatters.latex import LatexFormatter
38from os import listdir
39from os.path import basename
40from os.path import dirname
41from os.path import join as path_join
42
43try:
44    # Python 2.
45    import ConfigParser as configparser
46except:
47    # Python 3.
48    import configparser
49
50
51project = 'Data Plane Development Kit'
52
53if LooseVersion(sphinx_version) >= LooseVersion('1.3.1'):
54    html_theme = "sphinx_rtd_theme"
55html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
56latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
57html_add_permalinks = ""
58html_show_copyright = False
59highlight_language = 'none'
60
61version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion']).decode('utf-8').rstrip()
62release = version
63
64master_doc = 'index'
65
66# Figures, tables and code-blocks automatically numbered if they have caption
67numfig = True
68
69latex_documents = [
70    ('index',
71     'doc.tex',
72     '',
73     '',
74     'manual')
75]
76
77# Latex directives to be included directly in the latex/pdf docs.
78latex_preamble = r"""
79\usepackage[utf8]{inputenc}
80\usepackage[T1]{fontenc}
81\usepackage{helvet}
82\renewcommand{\familydefault}{\sfdefault}
83\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
84"""
85
86# Configuration for the latex/pdf docs.
87latex_elements = {
88    'papersize': 'a4paper',
89    'pointsize': '11pt',
90    # remove blank pages
91    'classoptions': ',openany,oneside',
92    'babel': '\\usepackage[english]{babel}',
93    # customize Latex formatting
94    'preamble': latex_preamble
95}
96
97# Override the default Latex formatter in order to modify the
98# code/verbatim blocks.
99class CustomLatexFormatter(LatexFormatter):
100    def __init__(self, **options):
101        super(CustomLatexFormatter, self).__init__(**options)
102        # Use the second smallest font size for code/verbatim blocks.
103        self.verboptions = r'formatcom=\footnotesize'
104
105# Replace the default latex formatter.
106PygmentsBridge.latex_formatter = CustomLatexFormatter
107
108# Configuration for man pages
109man_pages = [("testpmd_app_ug/run_app", "testpmd",
110              "tests for dpdk pmds", "", 1),
111             ("tools/pdump", "dpdk-pdump",
112              "enable packet capture on dpdk ports", "", 1),
113             ("tools/proc_info", "dpdk-procinfo",
114              "access dpdk port stats and memory info", "", 1),
115             ("tools/pmdinfo", "dpdk-pmdinfo",
116              "dump a PMDs hardware support info", "", 1),
117             ("tools/devbind", "dpdk-devbind",
118              "check device status and bind/unbind them from drivers", "", 8)]
119
120######## :numref: fallback ########
121# The following hook functions add some simple handling for the :numref:
122# directive for Sphinx versions prior to 1.3.1. The functions replace the
123# :numref: reference with a link to the target (for all Sphinx doc types).
124# It doesn't try to label figures/tables.
125
126def numref_role(reftype, rawtext, text, lineno, inliner):
127    """
128    Add a Sphinx role to handle numref references. Note, we can't convert
129    the link here because the doctree isn't build and the target information
130    isn't available.
131    """
132    # Add an identifier to distinguish numref from other references.
133    newnode = nodes.reference('',
134                              '',
135                              refuri='_local_numref_#%s' % text,
136                              internal=True)
137    return [newnode], []
138
139def process_numref(app, doctree, from_docname):
140    """
141    Process the numref nodes once the doctree has been built and prior to
142    writing the files. The processing involves replacing the numref with a
143    link plus text to indicate if it is a Figure or Table link.
144    """
145
146    # Iterate over the reference nodes in the doctree.
147    for node in doctree.traverse(nodes.reference):
148        target = node.get('refuri', '')
149
150        # Look for numref nodes.
151        if target.startswith('_local_numref_#'):
152            target = target.replace('_local_numref_#', '')
153
154            # Get the target label and link information from the Sphinx env.
155            data = app.builder.env.domains['std'].data
156            docname, label, _ = data['labels'].get(target, ('', '', ''))
157            relative_url = app.builder.get_relative_uri(from_docname, docname)
158
159            # Add a text label to the link.
160            if target.startswith('figure'):
161                caption = 'Figure'
162            elif target.startswith('table'):
163                caption = 'Table'
164            else:
165                caption = 'Link'
166
167            # New reference node with the updated link information.
168            newnode = nodes.reference('',
169                                      caption,
170                                      refuri='%s#%s' % (relative_url, label),
171                                      internal=True)
172            node.replace_self(newnode)
173
174
175def generate_nic_overview_table(output_filename):
176    """
177    Function to generate the NIC Overview Table from the ini files that define
178    the features for each NIC.
179
180    The default features for the table and their order is defined by the
181    'default.ini' file.
182
183    """
184    # Default worning string.
185    warning = 'Warning generate_nic_overview_table()'
186
187    # Get the default features and order from the 'default.ini' file.
188    ini_path = path_join(dirname(output_filename), 'features')
189    config = configparser.ConfigParser()
190    config.optionxform = str
191    config.read(path_join(ini_path, 'default.ini'))
192    default_section = 'Features'
193    default_features = config.items(default_section)
194
195    # Create a dict of the valid features to validate the other ini files.
196    valid_features = {}
197    max_feature_length = 0
198    for feature in default_features:
199        key = feature[0]
200        valid_features[key] = ' '
201        max_feature_length = max(max_feature_length, len(key))
202
203    # Get a list of NIC ini files, excluding 'default.ini'.
204    ini_files = [basename(file) for file in listdir(ini_path)
205                 if file.endswith('.ini') and file != 'default.ini']
206    ini_files.sort()
207
208    # Build up a list of the table header names from the ini filenames.
209    header_names = []
210    for ini_filename in ini_files:
211        name = ini_filename[:-4]
212        name = name.replace('_vf', 'vf')
213
214        # Pad the table header names to match the existing format.
215        if '_vec' in name:
216            pmd, vec = name.split('_')
217            name = '{0:{fill}{align}7}vec'.format(pmd, fill='.', align='<')
218        else:
219            name = '{0:{fill}{align}10}'.format(name, fill=' ', align='<')
220
221        header_names.append(name)
222
223    # Create a dict of the defined features for each NIC from the ini files.
224    ini_data = {}
225    for ini_filename in ini_files:
226        config = configparser.ConfigParser()
227        config.optionxform = str
228        config.read(path_join(ini_path, ini_filename))
229
230        # Initialize the dict with the default.ini value.
231        ini_data[ini_filename] = valid_features.copy()
232
233        # Check for a valid ini section.
234        if not config.has_section(default_section):
235            print("{}: File '{}' has no [{}] secton".format(warning,
236                                                            ini_filename,
237                                                            default_section))
238            continue
239
240        # Check for valid features names.
241        for name, value in config.items(default_section):
242            if name not in valid_features:
243                print("{}: Unknown feature '{}' in '{}'".format(warning,
244                                                                name,
245                                                                ini_filename))
246                continue
247
248            if value is not '':
249                # Get the first letter only.
250                ini_data[ini_filename][name] = value[0]
251
252    # Print out the RST NIC Overview table from the ini file data.
253    outfile = open(output_filename, 'w')
254    num_cols = len(header_names)
255
256    print('.. table:: Features availability in networking drivers\n',
257          file=outfile)
258
259    print_table_header(outfile, num_cols, header_names)
260    print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
261
262
263def print_table_header(outfile, num_cols, header_names):
264    """ Print the RST table header. The header names are vertical. """
265    print_table_divider(outfile, num_cols)
266
267    line = ''
268    for name in header_names:
269        line += ' ' + name[0]
270
271    print_table_row(outfile, 'Feature', line)
272
273    for i in range(1, 10):
274        line = ''
275        for name in header_names:
276            line += ' ' + name[i]
277
278        print_table_row(outfile, '', line)
279
280    print_table_divider(outfile, num_cols)
281
282
283def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
284    """ Print out the body of the table. Each row is a NIC feature. """
285
286    for feature, _ in default_features:
287        line = ''
288
289        for ini_filename in ini_files:
290            line += ' ' + ini_data[ini_filename][feature]
291
292        print_table_row(outfile, feature, line)
293
294    print_table_divider(outfile, num_cols)
295
296
297def print_table_row(outfile, feature, line):
298    """ Print a single row of the table with fixed formatting. """
299    line = line.rstrip()
300    print('   {:<20}{}'.format(feature, line), file=outfile)
301
302
303def print_table_divider(outfile, num_cols):
304    """ Print the table divider line. """
305    line = ' '
306    column_dividers = ['='] * num_cols
307    line += ' '.join(column_dividers)
308
309    feature = '=' * 20
310
311    print_table_row(outfile, feature, line)
312
313
314def setup(app):
315    generate_nic_overview_table('doc/guides/nics/overview_table.txt')
316
317    if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
318        print('Upgrade sphinx to version >= 1.3.1 for '
319              'improved Figure/Table number handling.')
320        # Add a role to handle :numref: references.
321        app.add_role('numref', numref_role)
322        # Process the numref references once the doctree has been created.
323        app.connect('doctree-resolved', process_numref)
324