VPP-57 Add Doxygen to VPP
- Configures Doxygen. - Adds a source filter to do magic on our use of the preprocessor to do constructor stuff to make Doxygen grok it better. - Adds a convenience helper to the root Makefile. - Adds a README.md to the root directory (and which Doxygem uses as its "mainpage". - Add several other documentative files. - Currently using SVG for call graphs, though this may have a load-time performance impact in browsers. Change-Id: I25fc6fb5bf634319dcb36a7f0e32031921c125ac Signed-off-by: Chris Luke <chrisy@flirble.org>
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -57,3 +57,6 @@ test-driver
|
||||
# cscope and ctags
|
||||
/cscope.*
|
||||
/tags
|
||||
|
||||
# Generated documentation
|
||||
/build-root/docs
|
||||
|
25
Makefile
25
Makefile
@ -39,7 +39,9 @@ endif
|
||||
RPM_DEPENDS_GROUPS = 'Development Tools'
|
||||
RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils
|
||||
RPM_DEPENDS += openssl-devel https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm apr-devel
|
||||
#RPM_DEPENDS += doxygen # TODO
|
||||
EPEL_DEPENDS = libconfuse-devel ganglia-devel
|
||||
#EPEL_DEPENDS += graphviz # TODO
|
||||
|
||||
ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),)
|
||||
STARTUP_CONF ?= $(STARTUP_DIR)/startup.conf
|
||||
@ -209,3 +211,26 @@ ctags: ctags.files
|
||||
cscope: cscope.files
|
||||
@cscope -b -q -v
|
||||
|
||||
|
||||
DOXY_INPUT = \
|
||||
README.md \
|
||||
vppinfra \
|
||||
svm \
|
||||
vlib \
|
||||
vlib-api \
|
||||
vnet \
|
||||
vpp \
|
||||
vpp-api
|
||||
|
||||
.PHONY: doxygen
|
||||
doxygen:
|
||||
@mkdir -p "$(BR)/docs"
|
||||
ROOT="$(WS_ROOT)" \
|
||||
BUILD_ROOT="$(BR)" \
|
||||
INPUT="$(addprefix $(WS_ROOT)/,$(DOXY_INPUT))" \
|
||||
HTML=YES \
|
||||
VERSION="`git describe --tags --dirty`" \
|
||||
doxygen doxygen/doxygen.cfg
|
||||
|
||||
wipe-doxygen:
|
||||
rm -rf "$(BR)/docs"
|
||||
|
94
README.md
Normal file
94
README.md
Normal file
@ -0,0 +1,94 @@
|
||||
Vector Packet Processing
|
||||
========================
|
||||
|
||||
## Introduction.
|
||||
|
||||
The VPP platform is an extensible framework that provides out-of-the-box
|
||||
production quality switch/router functionality. It is the open source version
|
||||
of Cisco's Vector Packet Processing (VPP) technology: a high performance,
|
||||
packet-processing stack that can run on commodity CPUs.
|
||||
|
||||
The benefits of this implementation of VPP are its high performance, proven
|
||||
technology, its modularity and flexibility, and rich feature set.
|
||||
|
||||
For more information on VPP and its features please visit the
|
||||
[FD.io website](http://fd.io/) and
|
||||
[What is VPP?](https://wiki.fd.io/view/VPP/What_is_VPP%3F) pages.
|
||||
|
||||
|
||||
## Directory layout.
|
||||
|
||||
Directory name | Description
|
||||
---------------------- | -------------------------------------------
|
||||
build-data | Build metadata
|
||||
build-root | Build output directory
|
||||
doxygen | Documentation generator configuration
|
||||
dpdk | DPDK patches and build infrastructure
|
||||
g2 | Event log visualization tool
|
||||
gmod | perf related?
|
||||
perftool | Performance tool
|
||||
sample-plugin | A sample plugin
|
||||
@ref svm | Shared virtual memory allocation library
|
||||
test | Unit tests
|
||||
@ref vlib | VPP application library source
|
||||
@ref vlib-api | VPP API library source
|
||||
@ref vnet | VPP networking source
|
||||
@ref vpp | VPP application source
|
||||
@ref vpp-api | VPP application API source
|
||||
vppapigen | VPP API generator source
|
||||
vpp-api-test | VPP API test program source
|
||||
@ref vppinfra | VPP core library source
|
||||
|
||||
(If the page you are viewing is not generated by Doxygen then
|
||||
ignore any @@ref labels in the above table.)
|
||||
|
||||
|
||||
## Getting started.
|
||||
|
||||
In general anyone interested in building, developing or running VPP should
|
||||
consult the [VPP wiki](https://wiki.fd.io/view/VPP) for more complete
|
||||
documentation.
|
||||
|
||||
In particular, readers are recommended to take a look at [Pulling, Building,
|
||||
Running, Hacking, Pushing](https://wiki.fd.io/view/VPP/Pulling,_Building,_Run
|
||||
ning,_Hacking_and_Pushing_VPP_Code) which provides extensive step-by-step
|
||||
coverage of the topic.
|
||||
|
||||
For the impatient, some salient information is distilled below.
|
||||
|
||||
|
||||
### Quick-start: On an existing Linux host.
|
||||
|
||||
To install system dependencies, build VPP and then install it, simply run the
|
||||
build script. This should be performed a non-privileged user with `sudo`
|
||||
access from the project base directory:
|
||||
|
||||
./build-root/vagrant/build.sh
|
||||
|
||||
If you want a more fine-grained approach because you intend to do some
|
||||
development work, the `Makefile` in the root directory of the source tree
|
||||
provides several convenience shortcuts as `make` targets that may be of
|
||||
interest. To see the available targets run:
|
||||
|
||||
make
|
||||
|
||||
|
||||
### Quick-start: Vagrant.
|
||||
|
||||
The directory `build-root/vagrant` contains a `VagrantFile` and supporting
|
||||
scripts to bootstrap a working VPP inside a Vagrant-managed Virtual Machine.
|
||||
This VM can then be used to test concepts with VPP or as a development
|
||||
platform to extend VPP. Some obvious caveats apply when using a VM for VPP
|
||||
since its performance will never match that of bare metal; if your work is
|
||||
timing or performance sensitive, consider using bare metal in addition or
|
||||
instead of the VM.
|
||||
|
||||
For this to work you will need a working installation of Vagrant. Instructions
|
||||
for this can be found [on the Setting up Vagrant wiki page]
|
||||
(https://wiki.fd.io/view/DEV/Setting_Up_Vagrant).
|
||||
|
||||
|
||||
## More information.
|
||||
|
||||
Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more
|
||||
advanced building strategies and development notes.
|
47
doxygen/assets/doxy-vpp.css
Normal file
47
doxygen/assets/doxy-vpp.css
Normal file
@ -0,0 +1,47 @@
|
||||
/* VPP CSS overrides */
|
||||
|
||||
body, table, div, p, dl {
|
||||
font: initial;
|
||||
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
code, tt {
|
||||
font: initial;
|
||||
font-family: Consolas, Courier, monospace;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
|
||||
.title {
|
||||
font: initial;
|
||||
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
|
||||
font-size: 150%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.mdescLeft, .mdescRight,
|
||||
.memItemLeft, .memItemRight,
|
||||
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
|
||||
font-family: Consolas, Courier, monospace;
|
||||
}
|
||||
|
||||
.memname {
|
||||
font-family: Consolas, Courier, monospace;
|
||||
font-weight: bold;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
.paramname {
|
||||
font-family: Consolas, Courier, monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.el {
|
||||
font-family: Consolas, Courier, monospace;
|
||||
}
|
BIN
doxygen/assets/logo_fdio.png
Normal file
BIN
doxygen/assets/logo_fdio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
6
doxygen/dir.dox.sample
Normal file
6
doxygen/dir.dox.sample
Normal file
@ -0,0 +1,6 @@
|
||||
/* Doxygen directory documentation */
|
||||
/**
|
||||
@dir
|
||||
@brief Someone please fix this description
|
||||
@todo This directory needs a description.
|
||||
*/
|
2433
doxygen/doxygen.cfg
Normal file
2433
doxygen/doxygen.cfg
Normal file
File diff suppressed because it is too large
Load Diff
37
doxygen/filter_c.py
Executable file
37
doxygen/filter_c.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, re
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Usage: %s <filename>\n" % (sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
patterns = [
|
||||
# Search for VLIB_CLI_COMMAND, extract its parameter and add a docblock for it
|
||||
( re.compile("(?P<m>VLIB_CLI_COMMAND)\s*[(](?P<name>[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (\g<name>) */ vlib_cli_command_t \g<name>"),
|
||||
|
||||
# Search for VLIB_REGISTER_NODE, extract its parameter and add a docblock for it
|
||||
( re.compile("(?P<m>VLIB_REGISTER_NODE)\s*[(](?P<name>[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (\g<name>) */ vlib_node_registration_t \g<name>"),
|
||||
|
||||
# Search for VLIB_INIT_FUNCTION, extract its parameter and add a docblock for it
|
||||
( re.compile("(?P<m>VLIB_INIT_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+)[)]"), r"/** @brief (@em constructor) \g<m> (@ref \g<name>) */ vlib_init_function_t * _vlib_init_function_\g<name>"),
|
||||
( re.compile("(?P<m>VLIB_DECLARE_INIT_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+)[)]"), r"/** @brief (@em constructor) \g<m> (@ref \g<name>) */ vlib_init_function_t * _vlib_init_function_\g<name>"),
|
||||
|
||||
# Search for VLIB_LOOP_ENTER_FUNCTION, extract the 1st parameter (ignore any others) and add a docblock for it
|
||||
( re.compile("(?P<m>VLIB_MAIN_LOOP_ENTER_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (@ref \g<name>) */ _vlib_main_loop_enter_\g<name>"),
|
||||
( re.compile("(?P<m>VLIB_MAIN_LOOP_EXIT_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+)(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (@ref \g<name>) */ _vlib_main_loop_exit_\g<name>"),
|
||||
|
||||
# Search for VLIB_CONFIG_FUNCTION, extract the 1st parameter (ignore any others) and add a docblock for it
|
||||
( re.compile("(?P<m>VLIB_CONFIG_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+),\s*(?P<n>\"[^\"]+\")(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (\g<name>, \g<n>) */ vlib_config_function_runtime_t _vlib_config_function_\g<name>"),
|
||||
( re.compile("(?P<m>VLIB_EARLY_CONFIG_FUNCTION)\s*[(](?P<name>[a-zA-Z0-9_]+),\s*(?P<n>\"[^\"]+\")(,[^)]*)?[)]"), r"/** @brief (@em constructor) \g<m> (\g<name>, \g<n>) */ vlib_config_function_runtime_t _vlib_config_function_\g<name>"),
|
||||
|
||||
# Search for "format_thing" and "unformat_thing" when used as a function pointer and add parens
|
||||
( re.compile("(?P<pre>(^|,)\s*)(?P<name>(un)?format_[a-zA-Z0-9_]+)(?P<post>\s*(,|$))") , r"\g<pre>\g<name>()\g<post>" ),
|
||||
]
|
||||
|
||||
with open(sys.argv[1]) as fd:
|
||||
for line in fd:
|
||||
str = line
|
||||
for p in patterns:
|
||||
str = p[0].sub(p[1], str)
|
||||
sys.stdout.write(str)
|
194
doxygen/layout.xml
Normal file
194
doxygen/layout.xml
Normal file
@ -0,0 +1,194 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.11 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="" intro=""/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="Source">
|
||||
<tab type="filelist" visible="yes" title="Files" intro=""/>
|
||||
<tab type="globals" visible="yes" title="Symbols" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
5
svm/dir.dox
Normal file
5
svm/dir.dox
Normal file
@ -0,0 +1,5 @@
|
||||
/* Doxygen directory documentation */
|
||||
/**
|
||||
@dir
|
||||
@brief Shared virtual memory allocation library.
|
||||
*/
|
5
vlib/dir.dox
Normal file
5
vlib/dir.dox
Normal file
@ -0,0 +1,5 @@
|
||||
/* Doxygen directory documentation */
|
||||
/**
|
||||
@dir
|
||||
@brief VLIB application library.
|
||||
*/
|
6
vlib/example/dir.dox
Normal file
6
vlib/example/dir.dox
Normal file
@ -0,0 +1,6 @@
|
||||
/* Doxygen directory documentation */
|
||||
/**
|
||||
@dir
|
||||
@brief Someone please fix this description
|
||||
@todo This directory needs a description.
|
||||
*/
|
5
vlib/vlib/dir.dox
Normal file
5
vlib/vlib/dir.dox
Normal file
@ -0,0 +1,5 @@
|
||||
/* Doxygen directory documentation */
|
||||
/**
|
||||
@dir
|
||||
@brief VLIB application library source.
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
@ -23,14 +23,6 @@
|
||||
#include <vnet/devices/dpdk/dpdk.h>
|
||||
#endif
|
||||
|
||||
/** \mainpage Virtual Packet Edge Documentation
|
||||
* \section intro_sec Introduction
|
||||
*
|
||||
* VPE is a specific vector packet processing application,
|
||||
* designed to steer packets to/from tenant virtual machines.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
vpe_main_init (vlib_main_t * vm)
|
||||
{
|
||||
|
3
vppinfra/dir.dox
Normal file
3
vppinfra/dir.dox
Normal file
@ -0,0 +1,3 @@
|
||||
/** @dir
|
||||
* @brief VPP infrastructure library and tools.
|
||||
*/
|
3
vppinfra/tools/dir.dox
Normal file
3
vppinfra/tools/dir.dox
Normal file
@ -0,0 +1,3 @@
|
||||
/** @dir
|
||||
* @brief VPP instrastructure tools.
|
||||
*/
|
3
vppinfra/vppinfra/dir.dox
Normal file
3
vppinfra/vppinfra/dir.dox
Normal file
@ -0,0 +1,3 @@
|
||||
/** @dir
|
||||
* @brief VPP infrastructure library source.
|
||||
*/
|
@ -916,7 +916,7 @@ do { \
|
||||
} while (0)
|
||||
|
||||
|
||||
/** \brief .
|
||||
/** \brief Test whether a vector is a NULL terminated c-string.
|
||||
|
||||
@param V (possibly NULL) pointer to a vector.
|
||||
@return BOOLEAN indicating if the vector c-string is null terminated.
|
||||
@ -924,7 +924,7 @@ do { \
|
||||
#define vec_c_string_is_terminated(V) \
|
||||
(((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
|
||||
|
||||
/** \brief (If necessary) Null terminate a vector containing a c-string.
|
||||
/** \brief (If necessary) NULL terminate a vector containing a c-string.
|
||||
|
||||
@param V (possibly NULL) pointer to a vector.
|
||||
@return V (value-result macro parameter)
|
||||
|
Reference in New Issue
Block a user