Is there an equivalent for Glob in D Phobos? - d

In python I can use glob to search path patterns. This for instance:
import glob
for entry in glob.glob("/usr/*/python*"):
print(entry)
Would print this:
/usr/share/python3
/usr/share/python3-plainbox
/usr/share/python
/usr/share/python-apt
/usr/include/python3.5m
/usr/bin/python3
/usr/bin/python3m
/usr/bin/python2.7
/usr/bin/python
/usr/bin/python3.5
/usr/bin/python3.5m
/usr/bin/python2
/usr/lib/python3
/usr/lib/python2.7
/usr/lib/python3.5
How would I glob or make a glob equivalent in in D?
------Updated on Sep 12 2017------
I wrote a small D module to do Glob in D: https://github.com/workhorsy/d-glob

If you only work on a Posix system, you can directly call glob.h. Here's a simple example that shows how easy it is to interface with the Posix API:
void main()
{
import std.stdio;
import glob : glob;
foreach(entry; glob("/usr/*/python*"))
writeln(entry);
}
You can compile this e.g. with rdmd main.d (rdmd does simple dependency management) or dmd main.d glob.d and it yields a similar output as yours on my machine.
glob.d was generated by dstep and is enhanced with a convenience D-style wrapper (first function). Please note that this isn't perfect and a better way would be to expose a range API instead of allocating the entire array.
/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
string[] glob(string pattern)
{
import std.string;
string[] results;
glob_t glob_result;
glob(pattern.toStringz, 0, null, &glob_result);
for (uint i = 0; i < glob_result.gl_pathc; i++)
{
results ~= glob_result.gl_pathv[i].fromStringz().idup;
}
globfree(&glob_result);
return results;
}
import core.stdc.config;
extern (C):
enum _GLOB_H = 1;
/* We need `size_t' for the following definitions. */
alias c_ulong __size_t;
alias c_ulong size_t;
/* The GNU CC stddef.h version defines __size_t as empty. We need a real
definition. */
/* Bits set in the FLAGS argument to `glob'. */
enum GLOB_ERR = 1 << 0; /* Return on read errors. */
enum GLOB_MARK = 1 << 1; /* Append a slash to each name. */
enum GLOB_NOSORT = 1 << 2; /* Don't sort the names. */
enum GLOB_DOOFFS = 1 << 3; /* Insert PGLOB->gl_offs NULLs. */
enum GLOB_NOCHECK = 1 << 4; /* If nothing matches, return the pattern. */
enum GLOB_APPEND = 1 << 5; /* Append to results of a previous call. */
enum GLOB_NOESCAPE = 1 << 6; /* Backslashes don't quote metacharacters. */
enum GLOB_PERIOD = 1 << 7; /* Leading `.' can be matched by metachars. */
enum GLOB_MAGCHAR = 1 << 8; /* Set in gl_flags if any metachars seen. */
enum GLOB_ALTDIRFUNC = 1 << 9; /* Use gl_opendir et al functions. */
enum GLOB_BRACE = 1 << 10; /* Expand "{a,b}" to "a" "b". */
enum GLOB_NOMAGIC = 1 << 11; /* If no magic chars, return the pattern. */
enum GLOB_TILDE = 1 << 12; /* Expand ~user and ~ to home directories. */
enum GLOB_ONLYDIR = 1 << 13; /* Match only directories. */
enum GLOB_TILDE_CHECK = 1 << 14; /* Like GLOB_TILDE but return an error
if the user name is not available. */
enum __GLOB_FLAGS = GLOB_ERR | GLOB_MARK | GLOB_NOSORT | GLOB_DOOFFS | GLOB_NOESCAPE | GLOB_NOCHECK | GLOB_APPEND | GLOB_PERIOD | GLOB_ALTDIRFUNC | GLOB_BRACE | GLOB_NOMAGIC | GLOB_TILDE | GLOB_ONLYDIR | GLOB_TILDE_CHECK;
/* Error returns from `glob'. */
enum GLOB_NOSPACE = 1; /* Ran out of memory. */
enum GLOB_ABORTED = 2; /* Read error. */
enum GLOB_NOMATCH = 3; /* No matches found. */
enum GLOB_NOSYS = 4; /* Not implemented. */
/* Previous versions of this file defined GLOB_ABEND instead of
GLOB_ABORTED. Provide a compatibility definition here. */
/* Structure describing a globbing run. */
struct glob_t
{
__size_t gl_pathc; /* Count of paths matched by the pattern. */
char** gl_pathv; /* List of matched pathnames. */
__size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
void function (void*) gl_closedir;
void* function (void*) gl_readdir;
void* function (const(char)*) gl_opendir;
int function (const(char)*, void*) gl_lstat;
int function (const(char)*, void*) gl_stat;
}
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
/* Do glob searching for PATTERN, placing results in PGLOB.
The bits defined above may be set in FLAGS.
If a directory cannot be opened or read and ERRFUNC is not nil,
it is called with the pathname that caused the error, and the
`errno' value from the failing call; if it returns non-zero
`glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
Otherwise, `glob' returns zero. */
int glob (
const(char)* __pattern,
int __flags,
int function (const(char)*, int) __errfunc,
glob_t* __pglob);
/* Free storage allocated in PGLOB by a previous `glob' call. */
void globfree (glob_t* __pglob);

None of the answers above worked 100% the same as Glob on Windows and Linux. So I made a small D module that does Glob the right way. Hopefully people find it useful:
https://github.com/workhorsy/d-glob
import std.stdio : stdout;
import glob : glob;
foreach (entry ; glob("/usr/*/python*")) {
stdout.writefln("%s", entry);
}

Maybe you are looking for std.file.dirEntries().
Here's example from the documentation:
// Iterate over all D source files in current directory and all its
// subdirectories
auto dFiles = dirEntries("","*.{d,di}",SpanMode.depth);
foreach(d; dFiles)
writeln(d.name);

Basically you don't need to do all this complicated stuff with headers, C and so on, and so forth. This should do the thing:
auto dirIter = dirEntries("/usr", "*/python*", SpanMode.shallow);
foreach(dirFile; dirIter) {
// Process the result as needed

Related

Error compiling the first example code of FreeLing (C++)

I've installed 'freeling-4.2-focal-amd64.deb' on 'Linux Mint 20.3 Cinnamon' and also all the dependencies mentioned here:
https://freeling-user-manual.readthedocs.io/en/v4.2/installation/requirements-linux/#install-dependencies
I tried to compile the first example code from here:
Explanation: https://freeling-tutorial.readthedocs.io/en/latest/example01/
Code: https://freeling-tutorial.readthedocs.io/en/latest/code/example01.cc/
The following Error message appeared while compiling:
FAILED: CMakeFiles/test_freeling.dir/main.cpp.o
/usr/bin/c++ -g -std=gnu++14 -MD -MT CMakeFiles/test_freeling.dir/main.cpp.o -MF CMakeFiles/test_freeling.dir/main.cpp.o.d -o CMakeFiles/test_freeling.dir/main.cpp.o -c /home/ben/Schreibtisch/Bachelor_Projekt/test_freeling/main.cpp
In file included from /usr/include/freeling/morfo/idioma.h:45,
from /usr/include/freeling/morfo/lang_ident.h:44,
from /usr/include/freeling.h:35,
from /home/ben/desktop/Projekt/test_freeling/main.cpp:2:
/usr/include/freeling/morfo/smoothingLD.h: In constructor ‘freeling::smoothingLD<G, E>::smoothingLD(const wstring&, const std::map<std::__cxx11::basic_string<wchar_t>, E>&)’:
/usr/include/freeling/morfo/smoothingLD.h:129:73: error: there are no arguments to ‘log’ that depend on a template parameter, so a declaration of ‘log’ must be available [-fpermissive]
129 | if (name==L"LinearDiscountAlpha") { double a; sin>>a; alpha = log(a); notalpha=log(1-a); }
| ^~~
/usr/include/freeling/morfo/smoothingLD.h:129:73: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
/usr/include/freeling/morfo/smoothingLD.h:129:90: error: there are no arguments to ‘log’ that depend on a template parameter, so a declaration of ‘log’ must be available [-fpermissive]
129 | if (name==L"LinearDiscountAlpha") { double a; sin>>a; alpha = log(a); notalpha=log(1-a); }
| ^~~
/usr/include/freeling/morfo/smoothingLD.h:179:18: error: there are no arguments to ‘log’ that depend on a template parameter, so a declaration of ‘log’ must be available [-fpermissive]
179 | pUnseen = -log(vsize-ntypes); // log version of 1/(vsize-ntypes)
| ^~~
/usr/include/freeling/morfo/smoothingLD.h:180:14: error: there are no arguments to ‘log’ that depend on a template parameter, so a declaration of ‘log’ must be available [-fpermissive]
180 | nobs = log(nobs);
| ^~~
Here is the corresponding source code:
////////////////////////////////////////////////////////////////
//
// FreeLing - Open Source Language Analyzers
//
// Copyright (C) 2014 TALP Research Center
// Universitat Politecnica de Catalunya
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// contact: Lluis Padro (padro#lsi.upc.es)
// TALP Research Center
// despatx C6.212 - Campus Nord UPC
// 08034 Barcelona. SPAIN
//
////////////////////////////////////////////////////////////////
#ifndef _SMOOTHING_LD
#define _SMOOTHING_LD
#include "freeling/morfo/traces.h"
#include "freeling/morfo/util.h"
#include "freeling/morfo/configfile.h"
#undef MOD_TRACENAME
#define MOD_TRACENAME L"SMOOTHING"
#undef MOD_TRACEMODULE
#define MOD_TRACEMODULE LANGIDENT_TRACE
namespace freeling {
///////////////////////////////////////////////////////////////
/// Class smoothingLD computes linear-discount smoothed conditional
/// probabilities P(z|w1...wn) for n-gram transitions.
///
/// template parameters:
/// - E is the type of the ngram elements (e.g. char, int, string, etc.)
/// - G is the type containing the ngram (e.g. string, list<int>, vector<string>, etc.)
/// Elements of G must be of type E.
/// G must have operations push_back(E), erase(G::iterator), and begin()
///////////////////////////////////////////////////////////////
template <class G,class E>
class smoothingLD {
private:
/// log alpha and 1-alpha parameter for linear discount
double alpha;
double notalpha;
/// map to store ngram counts (for any size of ngram)
std::map<G,double> counts;
// probability of unseen unigrams
double pUnseen;
// total number of observations
double nobs;
/// order of the n-gram model. Order=3 => trigram model P(z|xy)
size_t order;
/// translation table for escaped symbols in input (e.g. \s, \n, \t...)
std::map<std::wstring,E> escapes;
//////////////////////////////////////////
// Get observed counts for given ngram
double count(const G &ngram) const {
typename std::map<G, double>::const_iterator p = counts.find(ngram);
if (p!=counts.end()) return p->second;
else return -1;
}
public:
//////////////////////////////////////////
/// Constructor, load data from config file
smoothingLD(const std::wstring &cfgFile,
const std::map<std::wstring,E> &esc=std::map<std::wstring,E>()) : escapes(esc) {
double ntypes=0;
double vsize=0;
nobs=0;
order=0;
enum sections {ORDER,NGRAMS,SMOOTHING};
config_file cfg(true);
cfg.add_section(L"Order",ORDER,true);
cfg.add_section(L"NGrams",NGRAMS,true);
cfg.add_section(L"Smoothing",SMOOTHING,true);
if (not cfg.open(cfgFile))
ERROR_CRASH(L"Error opening file "+cfgFile);
std::wstring line;
while (cfg.get_content_line(line)) {
std::wistringstream sin;
sin.str(line);
// process each content line according to the section where it is found
switch (cfg.get_section()) {
case ORDER: {// read order of ngram model
std::wistringstream sin;
sin.str(line);
size_t x; sin>>x;
if (order!=0 and order!=x)
ERROR_CRASH(L"ERROR - Specified model order does not match ngram size");
order = x;
break;
}
case SMOOTHING: { // reading general parameters
std::wstring name;
sin>>name;
if (name==L"LinearDiscountAlpha") { double a; sin>>a; alpha = log(a); notalpha=log(1-a); }
else if (name==L"VocabularySize") sin>>vsize;
else ERROR_CRASH(L"Unexpected smoothing option '"+name+L"'");
break;
}
case NGRAMS: { // reading ngram counts
// read counts for this ngram to table
double c; sin >> c;
// read ngram components into a G object.
G ngram;
std::wstring w;
while (sin >> w) {
typename std::map<std::wstring,E>::const_iterator p=escapes.find(w);
if (p!=escapes.end())
ngram.push_back(p->second);
else
ngram.push_back(util::wstring_to<E>(w));
}
if (order==0) order = ngram.size();
else if (order != ngram.size())
ERROR_CRASH(L"ERROR - Mixed order ngrams in input file, or specified model order does not match ngram size");
// add ngram (and n-i gram) counts to the model
while (ngram.size()>1) {
// insert ngram count, or increase if it already existed
std::pair<typename std::map<G,double>::iterator,bool> x = counts.insert(make_pair(ngram,c));
if (not x.second) x.first->second += c;
// shorten n gram and loop to insert n-1 gram
ngram.erase(std::prev(ngram.end()));
}
// unigram is left. Add it
std::pair<typename std::map<G,double>::iterator,bool> x = counts.insert(make_pair(ngram,c));
if (x.second) ntypes++; // new unigram inserted, increase type count
else x.first->second += c; // existing unigram, increase count
// update total observation counts
nobs += c;
break;
}
default: break;
}
}
cfg.close();
// precompute logs needed for logprob
if (vsize<=ntypes)
ERROR_CRASH(L"VocabularySize can not be smaller than number of different observed unigrams.");
pUnseen = -log(vsize-ntypes); // log version of 1/(vsize-ntypes)
nobs = log(nobs);
for (typename std::map<G,double>::iterator c=counts.begin(); c!=counts.end(); c++)
c->second = log(c->second);
}
//////////////////////////////////////////
/// destructor
~smoothingLD() {}
//////////////////////////////////////////
/// Compute smoothed conditional log prob of seeing
/// symbol z following given ngram P(z|ngram)
double Prob(const G &ngram, const E &z) const {
// seq = n+1 gram ( ngram + z )
G seq = ngram;
seq.push_back(z);
// log count of complete ngram
double c = count(seq);
if (ngram.size()==0) {
// no conditioning history, use unigrams (seq = [z])
if (c>=0) return notalpha + c - nobs; // log version of (1-alpha)*count(c)/nobs
else return alpha + pUnseen; // log version of alpha * punseen
}
else {
// conditioning history, use LD smoothing
if (c>=0) return notalpha + c - count(ngram); // log version of (1-alpha)*count(c)/count(ngram)
else {
// shorten history and recurse
G sht = ngram; sht.erase(sht.begin());
return alpha + Prob(sht,z); // log version of alpha * Prob(sht,z)
}
}
}
};
} // namespace
#undef MOD_TRACENAME
#undef MOD_TRACECODE
#endif
Why isn't log recognized in this file of the lib and what can I do about it?
It seems the library has not included the proper header file (<cmath>) and that it's using std::log as-if it is guaranteed to be available as log.
I suggest that you try to get the providers of FreeLing to update the library and while waiting for them to fix the issues, you can try to do this:
#include <cmath>
using std::log;
before including any of the FreeLing headers in your own code.

libusb equivalent of PyUSB usb.util.find_descriptor

PyUSB has a little utility function called usb.util.find_descriptor which, as the name implies, allows me to search for a description with specific criteria, for example:
ep = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
I need the same functionality in a C++ application built with libusb. However I don't see anything similar in the libusb API specification. What would be the easiest way to implement the same functionality on top of libusb?
I'm on Linux, if that makes a difference. I'd however would rather not add any additional dependency, unless strictly required.
Update:
This is what I have so far:
libusb_config_descriptor* config;
int ret = libusb_get_config_descriptor(m_dev, 0 /* config_index */, &config);
if (ret != LIBUSB_SUCCESS) {
raise_exception(std::runtime_error, "libusb_get_config_descriptor() failed: " << usb_strerror(ret));
}
// Do not assume endpoint_in is 1
const libusb_interface *interface = config->interface;
const libusb_interface_descriptor configuration = interface->altsetting[0];
for(int i = 0; i < configuration.bNumEndpoints; ++i) {
const libusb_endpoint_descriptor endpoint = configuration.endpoint[i];
if ((endpoint.bEndpointAddress & LIBUSB_ENDPOINT_IN) == LIBUSB_ENDPOINT_IN) {
endpoint_in = endpoint.bEndpointAddress >> 8; // 3 first bytes
log_debug("endpoint_in: " << endpoint_in);
}
}
Iteration works this way, albeit it looks quite ugly and it's mostly non-reusable. Also, extracting the endpoint number with:
endpoint_in = endpoint.bEndpointAddress >> 8; // 3 first bytes
does not seem to work.

GCC Plugin: Is it possible to move a sequence of a basic block of one function to a basic block of another function?

I'm trying to create a plugin for gcc that allows you to instrument the prologue and the epilogue of a function.
The instrumentation code is inserted in two functions "instrument_entry" and "instrument_exit". These two functions are written in a file called instrumentation.h, which is included in the source code of the software I want to instrument.
in a nutshell, it's very similar to the
-finstrument-function of gcc
Unlike the option provided by gcc, through the plugin, I would like to take the code present in the function "instrument_entry" (I checked and this function contains only one basic block) and insert it in all other prologues of the functions present in the software.
I thought to take the sequence present in the basic block of the function "instrument_entry" and insert it in the first basic block of the function to be instrumented.
This is the code:
static basic_block bb_entry_instr;
static unsigned int instrument_functions(function *fun){
std::string func_name = function_name(fun);
if(func_name == "instrument_entry"){
basic_block bb;
bb = ENTRY_BLOCK_PTR_FOR_FN(fun);
bb = bb->next_bb;
bb_entry_instr = bb;
std::cout << "Instrumentation code found! " << std::endl;
}
if(func_name != "instrument_entry" && func_name != "instrument_exit"){
basic_block bb;
bb = ENTRY_BLOCK_PTR_FOR_FN(fun);
bb = bb->next_bb;
gimple_stmt_iterator gsi = gsi_start_bb(bb);
gsi_insert_seq_before(&gsi, bb_seq(bb_entry_instr), GSI_NEW_STMT);
}
} // end of instrument_functions()
bb_entry_instr is the basic block of the "instrument_entry" function
The pass I created for gcc is called after the "cfg" pass:
namespace {
const pass_data instrumentation_pass_data = {
GIMPLE_PASS,
"instr_pass2", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_gimple_any, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0 /* todo_flags_finish */
};
struct instrumentation_pass : gimple_opt_pass {
instrumentation_pass(gcc::context *ctx) : gimple_opt_pass(instrumentation_pass_data, ctx){}
unsigned int execute(function *fun) {
return instrument_functions(fun);
}
};
}
int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version){
... // plugin_default_version_check
struct register_pass_info instr_pass_info;
instr_pass_info.pass = new instrumentation_pass(g);
instr_pass_info.reference_pass_name = "cfg";
instr_pass_info.ref_pass_instance_number = 1;
instr_pass_info.pos_op = PASS_POS_INSERT_AFTER;
}
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &instr_pass_info);
When I try to compile a test program with the plugin, I get this error:
during RTL pass: expand
test_01.c: In function ‘instrument_entry’:
test_01.c:13:9: internal compiler error: in get_rtx_for_ssa_name, at tree-outof-ssa.h:62
13 | fgets(name, 0xff, stdin);
| ^~~~~~~~~~~~~~~~~~~~~~~~
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions.
make: *** [Makefile:14: test] Error 1
Can somebody help me?

Reset __COUNTER__ macro to zero

is it possible to reset the __COUNTER__ macro at the start of a header file to make its evaluation within the header file consistent over several compile units?
How about an enum?
enum { COUNTER_BASE = __COUNTER__ };
#define LOCAL_COUNTER (__COUNTER__ - COUNTER_BASE)
You can set BASE to __COUNTER__ at the top of your header file, and then use __COUNTER__ - BASE later on.
However, do this after you've included all necessary headers, because else thee result would depend on the use of __COUNTER__ within the header guards of those nested include files.
No, there is no way to reset that value.
Take a look at the GCC source that increments the counter:
case BT_COUNTER:
if (CPP_OPTION (pfile, directives_only) && pfile->state.in_directive)
cpp_error (pfile, CPP_DL_ERROR,
"__COUNTER__ expanded inside directive with -fdirectives-only");
number = pfile->counter++;
break;
And if you look arount this library, nowhere is the counter modified again. It is default initialized to 0 and then incremented at every use.
Note that the pfile, where the counter variable resides, represents the the preprocessor input, that in this case is the current compilation unit, not the actual file.
thanks to #Michael, and by using enum you can have complete usage of __COUNTER__ as below:
"source: ESF compiler extension"
//! >>>>>>>>>>>>>>>> Counter >>>>>>>>>>>>>>>>
#pragma region Counter
/* Counter
* Ex:
* <code>
CountOn(InitSteps);
int foo(void)
{
CountIt();
...
CountIt();
...
CountIt();
...
}
Counted(InitSteps);
* </code>
* */
#define CountOn(name) enum { name ## _BASE = __COUNTER__ }; const U8 name
#define CountIt(name) (U8)(__COUNTER__ - (name ## _BASE))
#define Counted(name) const U8 name = (U8)(__COUNTER__ - (name ## _BASE) -1);
/* alias of Counter
* Ex:
* <code>
TakeSteps(InitSteps);
int foo(void)
{
AddStep();
...
AddStep();
...
AddStep();
...
}
TotalSteps(InitSteps);
* </code>
* */
#define TakeSteps(name) CountOn(name)
/* this is invalid to read, want to get value ? use 'CountIt(name)' OR 'NextStep(name)' */
#define AddStep() do { __COUNTER__; } while (0);
#define TotalSteps(name) Counted(name)
/* better use of Counter (on format print 'step, total')
* 'step' starts at 1
* Ex:
* <code>
TakeSteps(InitSteps);
int foo(void)
{
printf(StepsPRT " Initializing system clock...", NextStep(InitSteps));
...
printf(StepsPRT " Loading configurations...", NextStep(InitSteps));
...
printf(StepsPRT " Applying...", NextStep(InitSteps));
...
}
TotalSteps(InitSteps);
* </code>
* */
#define NextStep(name) CountIt(name), name
#define StepsPRT "%d of %d"
#define NextStepP StepsPRT
#pragma endregion Counter
//! <<<<<<<<<<<<<<<< .Counter <<<<<<<<<<<<<<<<

Can I include cppcheck suppression within a function header?

I have added an inline comment to suppress a cppcheck unusedFunction warning for a function, but I would like to include this within the function header so that Doxygen can document all of the unused functions (I am implementing an API, so I have many functions that will not be used in my source). I would prefer not to suppress all unusedFunction errors, but rather on a per-function basis.
I would like to do something like this:
/**
* API function description
*
* #param p1 function pointer to the ...
* #return 0 if successful, -1 otherwise.
* // cppcheck-suppress unusedFunction
*/
int CreateTask(Task_FuncPtr p1)
{
return doSomething();
}
But when I do this, cppcheck does not "see" the inline suppression. If I move it outside the header, but just before the function declaration then the suppression works. The cppcheck documentation seems to imply that the suppression needs to be directly before the line generating then error.
Has any had success with this?
Taking a look at cppcheck sources (file preprocessor.cpp function RemoveComments()), it seems that you cannot do it.
The code to identify comments is:
if (str.compare(i, 2, "//") == 0) { /* ... */ }
and
else if (str.compare(i, 2, "/*") == 0) { /* ... */ }
When a comment is found, the code that manages warning suppression is:
if (_settings && _settings->_inlineSuppressions) {
std::istringstream iss(comment);
std::string word;
iss >> word;
if (word == "cppcheck-suppress") {
iss >> word;
if (iss)
suppressionIDs.push_back(word);
}
}
So cppcheck will skip spaces and check the first token immediately after // or /*.
Unfortunately Doxygen's special comment blocks start with /**, ///, /*! or //! and the third character prevents the "correct match".
Changing:
if (word == "cppcheck-suppress") { /* ... */ }
into:
if (contains(word, "cppcheck-suppress")) { /* ... */ }
// or if (ends_with(word, "cppcheck-suppress"))
should allow what you want:
/**
* API function description
*
* #param p1 function pointer to the ...
* #return 0 if successful, -1 otherwise.
*/
/** cppcheck-suppress unusedFunction */
or
/// API function description
///
/// #param p1 function pointer to the ...
/// #return 0 if successful, -1 otherwise.
///
/// cppcheck-suppress unusedFunction
You can probably open a ticket on http://trac.cppcheck.net/