doc: fix PDF with greek letter
[dpdk.git] / doc / guides / conf.py
1 # SPDX-License-Identifier: BSD-3-Clause
2 # Copyright(c) 2010-2015 Intel Corporation
3
4 from __future__ import print_function
5 import subprocess
6 from docutils import nodes
7 from distutils.version import LooseVersion
8 from sphinx import __version__ as sphinx_version
9 from sphinx.highlighting import PygmentsBridge
10 from pygments.formatters.latex import LatexFormatter
11 from os import listdir
12 from os import environ
13 from os.path import basename
14 from os.path import dirname
15 from os.path import join as path_join
16
17 try:
18     # Python 2.
19     import ConfigParser as configparser
20 except:
21     # Python 3.
22     import configparser
23
24 try:
25     import sphinx_rtd_theme
26
27     html_theme = "sphinx_rtd_theme"
28     html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
29 except:
30     print('Install the sphinx ReadTheDocs theme for improved html documentation '
31           'layout: pip install sphinx_rtd_theme')
32     pass
33
34 project = 'Data Plane Development Kit'
35 html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
36 latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
37 html_add_permalinks = ""
38 html_show_copyright = False
39 highlight_language = 'none'
40
41 # If MAKEFLAGS is exported by the user, garbage text might end up in version
42 version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion'],
43                                   env=dict(environ, MAKEFLAGS=""))
44 version = version.decode('utf-8').rstrip()
45 release = version
46
47 master_doc = 'index'
48
49 # Maximum feature description string length
50 feature_str_len = 25
51
52 # Figures, tables and code-blocks automatically numbered if they have caption
53 numfig = True
54
55 latex_documents = [
56     ('index',
57      'doc.tex',
58      '',
59      '',
60      'manual')
61 ]
62
63 # Latex directives to be included directly in the latex/pdf docs.
64 custom_latex_preamble = r"""
65 \usepackage[utf8]{inputenc}
66 \usepackage[T1]{fontenc}
67 \usepackage{textalpha}
68 \usepackage{helvet}
69 \renewcommand{\familydefault}{\sfdefault}
70 \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
71 \usepackage{etoolbox}
72 \robustify\(
73 \robustify\)
74 """
75
76 # Configuration for the latex/pdf docs.
77 latex_elements = {
78     'papersize': 'a4paper',
79     'pointsize': '11pt',
80     # remove blank pages
81     'classoptions': ',openany,oneside',
82     'babel': '\\usepackage[english]{babel}',
83     # customize Latex formatting
84     'preamble': custom_latex_preamble
85 }
86
87
88 # Override the default Latex formatter in order to modify the
89 # code/verbatim blocks.
90 class CustomLatexFormatter(LatexFormatter):
91     def __init__(self, **options):
92         super(CustomLatexFormatter, self).__init__(**options)
93         # Use the second smallest font size for code/verbatim blocks.
94         self.verboptions = r'formatcom=\footnotesize'
95
96 # Replace the default latex formatter.
97 PygmentsBridge.latex_formatter = CustomLatexFormatter
98
99 # Configuration for man pages
100 man_pages = [("testpmd_app_ug/run_app", "testpmd",
101               "tests for dpdk pmds", "", 1),
102              ("tools/pdump", "dpdk-pdump",
103               "enable packet capture on dpdk ports", "", 1),
104              ("tools/proc_info", "dpdk-procinfo",
105               "access dpdk port stats and memory info", "", 1),
106              ("tools/pmdinfo", "dpdk-pmdinfo",
107               "dump a PMDs hardware support info", "", 1),
108              ("tools/devbind", "dpdk-devbind",
109               "check device status and bind/unbind them from drivers", "", 8)]
110
111
112 # ####### :numref: fallback ########
113 # The following hook functions add some simple handling for the :numref:
114 # directive for Sphinx versions prior to 1.3.1. The functions replace the
115 # :numref: reference with a link to the target (for all Sphinx doc types).
116 # It doesn't try to label figures/tables.
117 def numref_role(reftype, rawtext, text, lineno, inliner):
118     """
119     Add a Sphinx role to handle numref references. Note, we can't convert
120     the link here because the doctree isn't build and the target information
121     isn't available.
122     """
123     # Add an identifier to distinguish numref from other references.
124     newnode = nodes.reference('',
125                               '',
126                               refuri='_local_numref_#%s' % text,
127                               internal=True)
128     return [newnode], []
129
130
131 def process_numref(app, doctree, from_docname):
132     """
133     Process the numref nodes once the doctree has been built and prior to
134     writing the files. The processing involves replacing the numref with a
135     link plus text to indicate if it is a Figure or Table link.
136     """
137
138     # Iterate over the reference nodes in the doctree.
139     for node in doctree.traverse(nodes.reference):
140         target = node.get('refuri', '')
141
142         # Look for numref nodes.
143         if target.startswith('_local_numref_#'):
144             target = target.replace('_local_numref_#', '')
145
146             # Get the target label and link information from the Sphinx env.
147             data = app.builder.env.domains['std'].data
148             docname, label, _ = data['labels'].get(target, ('', '', ''))
149             relative_url = app.builder.get_relative_uri(from_docname, docname)
150
151             # Add a text label to the link.
152             if target.startswith('figure'):
153                 caption = 'Figure'
154             elif target.startswith('table'):
155                 caption = 'Table'
156             else:
157                 caption = 'Link'
158
159             # New reference node with the updated link information.
160             newnode = nodes.reference('',
161                                       caption,
162                                       refuri='%s#%s' % (relative_url, label),
163                                       internal=True)
164             node.replace_self(newnode)
165
166
167 def generate_overview_table(output_filename, table_id, section, table_name, title):
168     """
169     Function to generate the Overview Table from the ini files that define
170     the features for each driver.
171
172     The default features for the table and their order is defined by the
173     'default.ini' file.
174
175     """
176     # Default warning string.
177     warning = 'Warning generate_overview_table()'
178
179     # Get the default features and order from the 'default.ini' file.
180     ini_path = path_join(dirname(output_filename), 'features')
181     config = configparser.ConfigParser()
182     config.optionxform = str
183     config.read(path_join(ini_path, 'default.ini'))
184     default_features = config.items(section)
185
186     # Create a dict of the valid features to validate the other ini files.
187     valid_features = {}
188     max_feature_length = 0
189     for feature in default_features:
190         key = feature[0]
191         valid_features[key] = ' '
192         max_feature_length = max(max_feature_length, len(key))
193
194     # Get a list of driver ini files, excluding 'default.ini'.
195     ini_files = [basename(file) for file in listdir(ini_path)
196                  if file.endswith('.ini') and file != 'default.ini']
197     ini_files.sort()
198
199     # Build up a list of the table header names from the ini filenames.
200     pmd_names = []
201     for ini_filename in ini_files:
202         name = ini_filename[:-4]
203         name = name.replace('_vf', 'vf')
204         pmd_names.append(name)
205
206     # Pad the table header names.
207     max_header_len = len(max(pmd_names, key=len))
208     header_names = []
209     for name in pmd_names:
210         if '_vec' in name:
211             pmd, vec = name.split('_')
212             name = '{0:{fill}{align}{width}}vec'.format(pmd,
213                     fill='.', align='<', width=max_header_len-3)
214         else:
215             name = '{0:{fill}{align}{width}}'.format(name,
216                     fill=' ', align='<', width=max_header_len)
217         header_names.append(name)
218
219     # Create a dict of the defined features for each driver from the ini files.
220     ini_data = {}
221     for ini_filename in ini_files:
222         config = configparser.ConfigParser()
223         config.optionxform = str
224         config.read(path_join(ini_path, ini_filename))
225
226         # Initialize the dict with the default.ini value.
227         ini_data[ini_filename] = valid_features.copy()
228
229         # Check for a valid ini section.
230         if not config.has_section(section):
231             print("{}: File '{}' has no [{}] secton".format(warning,
232                                                             ini_filename,
233                                                             section))
234             continue
235
236         # Check for valid features names.
237         for name, value in config.items(section):
238             if name not in valid_features:
239                 print("{}: Unknown feature '{}' in '{}'".format(warning,
240                                                                 name,
241                                                                 ini_filename))
242                 continue
243
244             if value is not '':
245                 # Get the first letter only.
246                 ini_data[ini_filename][name] = value[0]
247
248     # Print out the RST Driver Overview table from the ini file data.
249     outfile = open(output_filename, 'w')
250     num_cols = len(header_names)
251
252     print_table_css(outfile, table_id)
253     print('.. table:: ' + table_name + '\n', file=outfile)
254     print_table_header(outfile, num_cols, header_names, title)
255     print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
256
257
258 def print_table_header(outfile, num_cols, header_names, title):
259     """ Print the RST table header. The header names are vertical. """
260     print_table_divider(outfile, num_cols)
261
262     line = ''
263     for name in header_names:
264         line += ' ' + name[0]
265
266     print_table_row(outfile, title, line)
267
268     for i in range(1, len(header_names[0])):
269         line = ''
270         for name in header_names:
271             line += ' ' + name[i]
272
273         print_table_row(outfile, '', line)
274
275     print_table_divider(outfile, num_cols)
276
277
278 def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
279     """ Print out the body of the table. Each row is a NIC feature. """
280
281     for feature, _ in default_features:
282         line = ''
283
284         for ini_filename in ini_files:
285             line += ' ' + ini_data[ini_filename][feature]
286
287         print_table_row(outfile, feature, line)
288
289     print_table_divider(outfile, num_cols)
290
291
292 def print_table_row(outfile, feature, line):
293     """ Print a single row of the table with fixed formatting. """
294     line = line.rstrip()
295     print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
296
297
298 def print_table_divider(outfile, num_cols):
299     """ Print the table divider line. """
300     line = ' '
301     column_dividers = ['='] * num_cols
302     line += ' '.join(column_dividers)
303
304     feature = '=' * feature_str_len
305
306     print_table_row(outfile, feature, line)
307
308
309 def print_table_css(outfile, table_id):
310     template = """
311 .. raw:: html
312
313    <style>
314       .wy-nav-content {
315          opacity: .99;
316       }
317       table#idx {
318          cursor: default;
319          overflow: hidden;
320       }
321       table#idx th, table#idx td {
322          text-align: center;
323       }
324       table#idx th {
325          font-size: 72%;
326          white-space: pre-wrap;
327          vertical-align: top;
328          padding: 0.5em 0;
329          min-width: 0.9em;
330          width: 2em;
331       }
332       table#idx col:first-child {
333          width: 0;
334       }
335       table#idx th:first-child {
336          vertical-align: bottom;
337       }
338       table#idx td {
339          font-size: 70%;
340          padding: 1px;
341       }
342       table#idx td:first-child {
343          padding-left: 1em;
344          text-align: left;
345       }
346       table#idx tr:nth-child(2n-1) td {
347          background-color: rgba(210, 210, 210, 0.2);
348       }
349       table#idx th:not(:first-child):hover,
350       table#idx td:not(:first-child):hover {
351          position: relative;
352       }
353       table#idx th:not(:first-child):hover::after,
354       table#idx td:not(:first-child):hover::after {
355          content: '';
356          height: 6000px;
357          top: -3000px;
358          width: 100%;
359          left: 0;
360          position: absolute;
361          z-index: -1;
362          background-color: #ffb;
363       }
364       table#idx tr:hover td {
365          background-color: #ffb;
366       }
367    </style>
368 """
369     print(template.replace("idx", "id%d" % (table_id)), file=outfile)
370
371
372 def setup(app):
373     table_file = dirname(__file__) + '/nics/overview_table.txt'
374     generate_overview_table(table_file, 1,
375                             'Features',
376                             'Features availability in networking drivers',
377                             'Feature')
378     table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
379     generate_overview_table(table_file, 1,
380                             'Features',
381                             'Features availability in crypto drivers',
382                             'Feature')
383     table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
384     generate_overview_table(table_file, 2,
385                             'Cipher',
386                             'Cipher algorithms in crypto drivers',
387                             'Cipher algorithm')
388     table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
389     generate_overview_table(table_file, 3,
390                             'Auth',
391                             'Authentication algorithms in crypto drivers',
392                             'Authentication algorithm')
393     table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
394     generate_overview_table(table_file, 4,
395                             'AEAD',
396                             'AEAD algorithms in crypto drivers',
397                             'AEAD algorithm')
398     table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
399     generate_overview_table(table_file, 5,
400                             'Asymmetric',
401                             'Asymmetric algorithms in crypto drivers',
402                             'Asymmetric algorithm')
403     table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
404     generate_overview_table(table_file, 1,
405                             'Features',
406                             'Features availability in compression drivers',
407                             'Feature')
408
409     if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
410         print('Upgrade sphinx to version >= 1.3.1 for '
411               'improved Figure/Table number handling.')
412         # Add a role to handle :numref: references.
413         app.add_role('numref', numref_role)
414         # Process the numref references once the doctree has been created.
415         app.connect('doctree-resolved', process_numref)
416
417     app.add_stylesheet('css/custom.css')