From: g0dil Date: Mon, 10 Sep 2007 17:53:36 +0000 (+0000) Subject: Add doclib/fix-links.py to temporarily fix/remove bad doxygen links X-Git-Url: http://g0dil.de/git?p=senf.git;a=commitdiff_plain;h=e84dd6c52a07fc9e283cbd72c7616f3523920387 Add doclib/fix-links.py to temporarily fix/remove bad doxygen links Add 'fixlinks' target and add 'fixlinks' to the auto-build PPI: exchange registerEvent arguments PPI: Add connector 'operator()' aliases PPI: More detailed 'route' and 'registerEvent' documentation git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@434 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Examples/RateStuffer/ratestuffer.cc b/Examples/RateStuffer/ratestuffer.cc index 9ae6bc9..8d3456e 100644 --- a/Examples/RateStuffer/ratestuffer.cc +++ b/Examples/RateStuffer/ratestuffer.cc @@ -63,7 +63,7 @@ RateFilter::RateFilter(senf::ClockService::clock_type interval) { route(input,timer); route(timer,output); - registerEvent(&RateFilter::timeout, timer); + registerEvent(timer, &RateFilter::timeout); } void RateFilter::timeout() diff --git a/PPI/ActiveFeeder.cci b/PPI/ActiveFeeder.cci index 2125db5..4f9b728 100644 --- a/PPI/ActiveFeeder.cci +++ b/PPI/ActiveFeeder.cci @@ -35,7 +35,7 @@ prefix_ senf::ppi::module::ActiveFeeder::ActiveFeeder() { route(input,idle_); route(idle_,output); - registerEvent(& ActiveFeeder::request, idle_); + registerEvent(idle_, & ActiveFeeder::request); } ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/PPI/Connectors.cci b/PPI/Connectors.cci index 5dcb08e..3c3ad79 100644 --- a/PPI/Connectors.cci +++ b/PPI/Connectors.cci @@ -193,6 +193,11 @@ prefix_ senf::ppi::connector::ActiveConnector::ActiveConnector() /////////////////////////////////////////////////////////////////////////// // senf::ppi::connector::InputConnector +prefix_ senf::Packet senf::ppi::connector::InputConnector::read() +{ + return operator()(); +} + prefix_ senf::ppi::connector::OutputConnector & senf::ppi::connector::InputConnector::peer() const { @@ -256,6 +261,11 @@ prefix_ void senf::ppi::connector::OutputConnector::operator()(Packet p) peer().enqueue(p); } +prefix_ void senf::ppi::connector::OutputConnector::write(Packet p) +{ + operator()(p); +} + prefix_ senf::ppi::connector::InputConnector & senf::ppi::connector::OutputConnector::peer() const { diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh index f2e94aa..e42bab9 100644 --- a/PPI/Connectors.hh +++ b/PPI/Connectors.hh @@ -255,6 +255,7 @@ namespace connector { typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements + Packet operator()(); ///< Get a packet /**< This member is the primary method to access received data. On passive connectors, this operator will just @@ -265,6 +266,8 @@ namespace connector { logic error in the module implementation and an exception is raised. */ + Packet read(); ///< Alias for \ref operator()() + OutputConnector & peer() const; queue_iterator begin() const; ///< Access queue begin (head) @@ -299,7 +302,9 @@ namespace connector { : public virtual Connector { public: - void operator()(Packet p); ///< Send out a packet + void operator()(Packet p); ///< Send out a packet + + void write(Packet p); ///< Alias for \ref operator()() InputConnector & peer() const; diff --git a/PPI/IntervalTimer.test.cc b/PPI/IntervalTimer.test.cc index b3984e1..9b49d27 100644 --- a/PPI/IntervalTimer.test.cc +++ b/PPI/IntervalTimer.test.cc @@ -60,7 +60,7 @@ namespace { : timer ( senf::ClockService::milliseconds(d_) ), n ( n_ ) { - registerEvent( &TimerTest::tick, timer ); + registerEvent( timer, &TimerTest::tick ); } }; diff --git a/PPI/Mainpage.dox b/PPI/Mainpage.dox index 2219cde..5ed72b9 100644 --- a/PPI/Mainpage.dox +++ b/PPI/Mainpage.dox @@ -54,10 +54,8 @@ The PPI interface is designed to be as simple as possible. It provides sane defaults for all configurable parameters to simplify getting started. It also automates all resource - management. Especially to simplify resource management, the PPI will take many configuration - objects by value. Even though this is not as efficient, it frees the user from most resource - management chores. This decision does not affect the runtime performance since it only affects - the configuration step. + management. The throttling infrastructure handles blocking conditions (like input exhaustion) + automatically \section packets Packets diff --git a/PPI/Module.ct b/PPI/Module.ct index b88a98c..e1c8fa2 100644 --- a/PPI/Module.ct +++ b/PPI/Module.ct @@ -31,6 +31,8 @@ /////////////////////////////////////////////////////////////////////////// // senf::ppi::module::Module +#ifndef DOXYGEN + template prefix_ senf::ppi::Route & senf::ppi::module::Module::route(Source & source, Target & target) @@ -41,8 +43,20 @@ senf::ppi::module::Module::route(Source & source, Target & target) new Route(*this, source, target)))); } -template -prefix_ void senf::ppi::module::Module::registerEvent(Target target, Descriptor & descriptor) +#else +prefix_ senf::ppi::Route & +senf::ppi::module::Module::route(connector::InputConnector & input, + connector::OutputConnector & output) +{} +prefix_ senf::ppi::Route & +senf::ppi::module::Module::route(connector::InputConnector & input, EventDescriptor & output) +{} +#endif + +#ifndef DOXYGEN + +template +prefix_ void senf::ppi::module::Module::registerEvent(Descriptor & descriptor, Target target) { eventManager().registerEvent( *this, @@ -51,6 +65,13 @@ prefix_ void senf::ppi::module::Module::registerEvent(Target target, Descriptor descriptor.enabled(true); } +#else +template +prefix_ void senf::ppi::module::Module::registerEvent(Target target, + EventDescriptor & descriptor) +{} +#endif + /////////////////////////////////////////////////////////////////////////// // senf::ppi::module::detail namespace members diff --git a/PPI/Module.hh b/PPI/Module.hh index 31ef445..bb0de91 100644 --- a/PPI/Module.hh +++ b/PPI/Module.hh @@ -187,37 +187,60 @@ namespace module { ///< Define flow information /**< Using the route() and noroute() members, the information flow within the module is defined. Routing - may be specified either between inputs, outputs and - events. The routing information is used to perform - automatic throttling. The throttling behavior may - however be controlled manually. + may be defined between inputs, outputs and events. The + routing information is used to perform automatic + throttling. The throttling behavior may however be + controlled manually. Even if no automatic throttling is desired it is - vital to define the flow information for all inputs and - outputs. Without flow information important + essential to define the flow information for all inputs + and outputs. Without flow information important internal state of the module cannot be initialized. This includes, explicitly defining terminal inputs and outputs using noroute. Event - routing however is optional. + routing is optional however. The return value may be used to alter routing parameters like throttling parameters. - + \param[in] source Data source, object which controls incoming data (connector or event) \param[in] target Data target, object which controls outgoing data (connector or event) - \returns Route instance describing this route */ + \returns Route instance describing this route + \note The real implementation is not provided by three + overloads but by a single template member */ Route & route(connector::InputConnector & input, EventDescriptor & output); ///< Define flow information - /**< \see \ref route() */ + /**< Route from a connector to an event. Routing from a + connector to an event defines the event as the + conceptual 'receiver' of the data. This means, the + event is controlling the processing of received data + packets (Example: Routing from an input to an IOEvent + defines, that input data will be processed whenever the + event is signaled.). + + This event routing allows to automatically + enable/disable the event on throttling notifications. + + \see \ref route() */ Route & route(EventDescriptor & input, connector::OutputConnector & output); ///< Define flow information - /**< \see \ref route() */ + /**< Route from an event to a connector. Routing from an + event to a connector defeines the event as the + conceptual 'source' of the data. THis means, the event + controls how packets are sent (Example: Routing from an + IOEVent to an output defines, that output data will be + generated whenever the event is signaled). + + This event routing allows to automatically + enable/disable the event on throttling notifications. + + \see \ref route() */ #endif void noroute(connector::Connector & connector); ///< Define terminal connectors @@ -231,8 +254,12 @@ namespace module { \param[in] connector Terminal connector to declare */ - template - void registerEvent(Target target, Descriptor & descriptor); +#ifndef DOXYGEN + template + void registerEvent(Descriptor & descriptor, Target target); +#else + template + void registerEvent(Target target, EventDescriptor & descriptor); ///< Register an external event /**< The \a target argument may be either an arbitrary callable object or it may be a member function pointer @@ -242,14 +269,14 @@ namespace module { allows to access detailed information on the event delivered. - The \a descriptor describes the event to signal. This - - may be a timer event or some type of I/O event on a - file descriptor or socket. + The \a descriptor describes the event to signal like a + timer event or some type of I/O event on a file + descriptor or socket. \param[in] target The handler to call whenever the event is signaled \param[in] descriptor The type of event to register */ +#endif ClockService::clock_type time() const; ///< Time-stamp of the currently processing event /**< If available, this returns the scheduled time of the diff --git a/PPI/Module.test.cc b/PPI/Module.test.cc index a844abb..47795da 100644 --- a/PPI/Module.test.cc +++ b/PPI/Module.test.cc @@ -53,7 +53,7 @@ namespace { TestModule() { noroute(output); - registerEvent(&TestModule::onEvent, event); + registerEvent(event, &TestModule::onEvent); } void onEvent() { diff --git a/PPI/Route.hh b/PPI/Route.hh index 307d341..beb11e2 100644 --- a/PPI/Route.hh +++ b/PPI/Route.hh @@ -44,6 +44,17 @@ namespace ppi { public: virtual ~RouteBase(); +#ifdef DOXYGEN + Source & source() const; ///< Routing source + /**< \note The real implementation is in the \c + BaseRouteImplementation template in \c Route.ih. This + class is internal and not documented. */ + Target & target() const; ///< Routing target + /**< \note The real implementation is in the \c + BaseRouteImplementation template in \c Route.ih. This + class is internal and not documented. */ +#endif + protected: RouteBase(module::Module & module); @@ -119,9 +130,15 @@ namespace ppi { Route instances are created by Module::route statements. The Route class provides an interface to manipulate the flow processing. - The concrete interface provided depends on the type of route. If the route is a forwarding - route, it will be based on ForwardingRoute otherwise it will be based directly on - RouteBase. + Depending on the type of route, one of the following classes will be a baseclass: + +
ForwardingRoute
If the route is a \e forwarding route. This is a route + which forwards throttling notifications. This is the case, if one of the route endpoints is + a notify source (a connector::ActiveConnector) and the other is a + notify target (a connector::PassiveConnector or an EventDescriptor). + +
RouteBase
If the route is not a forwarding route, it is based directly on the + generic route base class
*/ template class Route diff --git a/PPI/Route.test.cc b/PPI/Route.test.cc index 9184960..08e5125 100644 --- a/PPI/Route.test.cc +++ b/PPI/Route.test.cc @@ -70,7 +70,7 @@ namespace { passiveIn.onRequest(&RouteTester::inputRequest); passiveOut.onRequest(&RouteTester::outputRequest); - registerEvent(&RouteTester::onEvent, event); + registerEvent(event, &RouteTester::onEvent); activeIn.onThrottle(&RouteTester::throttleRequest); activeIn.onUnthrottle(&RouteTester::unthrottleRequest); diff --git a/PPI/SocketReader.ct b/PPI/SocketReader.ct index 63faed0..f4a0152 100644 --- a/PPI/SocketReader.ct +++ b/PPI/SocketReader.ct @@ -49,7 +49,7 @@ prefix_ senf::ppi::module::ActiveSocketReader:: ActiveSocketReader(Handle handle) : handle_(handle), event_(handle_, IOEvent::Read), reader_() { - registerEvent( &ActiveSocketReader::read, event_ ); + registerEvent( event_, &ActiveSocketReader::read ); route(event_, output); } diff --git a/PPI/SocketWriter.ct b/PPI/SocketWriter.ct index 9c01233..29c7e30 100644 --- a/PPI/SocketWriter.ct +++ b/PPI/SocketWriter.ct @@ -37,7 +37,7 @@ template prefix_ senf::ppi::module::ActiveSocketWriter::ActiveSocketWriter(Handle handle) : handle_(handle), event_(handle_, IOEvent::Write), writer_() { - registerEvent( &ActiveSocketWriter::write, event_ ); + registerEvent( event_, &ActiveSocketWriter::write ); route(input, event_); } diff --git a/SConstruct b/SConstruct index 449ab7c..bf5b3eb 100644 --- a/SConstruct +++ b/SConstruct @@ -127,32 +127,38 @@ libsenf = env.Library( env.Default(libsenf) env.Alias('install_all', env.Install('$LIBINSTALLDIR', libsenf)) -env.AlwaysBuild( - env.Alias('deb', [], [ checkLocalConf, - updateRevision, - "$BUILDPACKAGE_COMMAND" ])) - -env.AlwaysBuild( - env.Alias('debsrc', [], [ updateRevision, - "$BUILDPACKAGE_COMMAND -S" ])) - -env.AlwaysBuild( - env.Alias('debbin', [], [ checkLocalConf, - updateRevision, - "$BUILDPACKAGE_COMMAND -nc" ])) - env.Clean('all', [ os.path.join(path,f) for path, subdirs, files in os.walk('.') for pattern in env['CLEAN_PATTERNS'] for f in fnmatch.filter(files,pattern) ]) -env.AlwaysBuild(env.Alias('linklint', [ 'all_docs' ], [ +env.AlwaysBuild(env.Alias('deb', [], [ + checkLocalConf, + updateRevision, + "$BUILDPACKAGE_COMMAND" ])) + +env.AlwaysBuild(env.Alias('debsrc', [], [ + updateRevision, + "$BUILDPACKAGE_COMMAND -S" ])) + +env.AlwaysBuild(env.Alias('debbin', [], [ + checkLocalConf, + updateRevision, + "$BUILDPACKAGE_COMMAND -nc" ])) + +env.AlwaysBuild(env.Alias('linklint', [], [ 'rm -rf linklint', 'linklint -doc linklint -net -limit 99999999 `find -type d -name html -printf "/%P/@ "`', - '[ -r linklint/errorX.html ] && python linklint_addnames.py linklint/errorX.html.new', - '[ -r linklint/errorX.html.new ] && mv linklint/errorX.html.new linklint/errorX.html', - '[ -r linklint/errorAX.html ] && python linklint_addnames.py linklint/errorAX.html.new', - '[ -r linklint/errorAX.html.new ] && mv linklint/errorAX.html.new linklint/errorAX.html', + '[ ! -r linklint/errorX.html ] || python linklint_addnames.py linklint/errorX.html.new', + '[ ! -r linklint/errorX.html.new ] || mv linklint/errorX.html.new linklint/errorX.html', + '[ ! -r linklint/errorAX.html ] || python linklint_addnames.py linklint/errorAX.html.new', + '[ ! -r linklint/errorAX.html.new ] || mv linklint/errorAX.html.new linklint/errorAX.html', '@echo -e "\\nLokal link check results: linklint/index.html"', '@echo -e "Remote link check results: linklint/urlindex.html\\n"' ])) + +env.AlwaysBuild(env.Alias('fixlinks', [ 'linklint' ], [ + '[ ! -r linklint/errorX.txt -o ! -r linklint/errorAX.txt ] || python doclib/fix-links.py -s .svn -s linklint -s debian linklint/errorX.txt linklint/errorAX.txt', +])) + +env.Clean('all', env.Dir('linklint')) diff --git a/admin/build.sh b/admin/build.sh index 98a5d4d..213e0aa 100755 --- a/admin/build.sh +++ b/admin/build.sh @@ -25,7 +25,7 @@ fi rm -f ../svn-update.log echo '$ scons -k all' -scons -k all +scons -k all && scons fixlinks echo -n '# Build completed at '; date --utc exec >../upload.log 2>&1 diff --git a/doclib/fix-links.py b/doclib/fix-links.py new file mode 100644 index 0000000..d0df7f6 --- /dev/null +++ b/doclib/fix-links.py @@ -0,0 +1,231 @@ +#!/usr/bin/python + +import sys,os.path,fnmatch, HTMLParser, getopt + +class HTMLFilter(HTMLParser.HTMLParser): + + def __init__(self, out=None): + HTMLParser.HTMLParser.__init__(self) + self._out = out + self._collect = False + self._data = "" + + def startCollect(self): + self._collect = True + self._data = "" + + def endCollect(self): + self._collect = False + return self._data + + def collecting(self): + return self._collect + + def handle_starttag(self,tag,attrs): + m = getattr(self,'_s_'+tag.upper(),None) + if m: + m(attrs) + else: + self.emit_starttag(tag,attrs) + + def handle_endtag(self,tag): + m = getattr(self,'_e_'+tag.upper(),None) + if m: + m() + else: + self.emit_endtag(tag) + + def handle_data(self,data): + if self._collect: + self._data += data + if self._out: + self._out.write(data) + + def handle_charref(self,name): + self.handle_data(name) + + def handle_entityref(self,name): + self.handle_data(name) + + def emit_starttag(self,tag,attrs): + self.handle_data('<%s%s>' % (tag, "".join([' %s="%s"' % attr for attr in attrs]))) + + def emit_endtag(self,tag): + self.handle_data('' % tag) + + +class AnchorIndex: + + def __init__(self, skipdirs = ('.svn',)): + self._anchors = {} + self._skipdirs = skipdirs + + def build(self): + sys.stderr.write("Building anchor index ") + nf = 0 + for dirname, subdirs, files in os.walk('.'): + for d in self._skipdirs: + if d in subdirs: + subdirs.remove(d) + for f in fnmatch.filter(files,'*.html'): + nf += 1 + path = os.path.normpath(os.path.join(dirname, f)) + self._addAnchor(f, path) + self._extractAnchors(path) + sys.stderr.write(" Done.\n") + dups = 0 + for k in self._anchors.keys(): + if not self._anchors[k]: + dups += 1 + del self._anchors[k] + sys.stderr.write("%d unique anchors in %d files (%d duplicates)\n" + % (len(self._anchors), nf, dups)) + + def _addAnchor(self, anchor, path): + if self._anchors.has_key(anchor): + self._anchors[anchor] = None + else: + self._anchors[anchor] = path + if len(self._anchors) % 100 == 0: + sys.stderr.write('.') + + def __getitem__(self, key): + return self._anchors.get(key) + + class AnchorExtractor(HTMLFilter): + + def __init__(self): + HTMLFilter.__init__(self) + self._anchors = {} + + def _s_A(self,attrs): + attrs = dict(attrs) + if attrs.has_key('name'): + self._anchors[attrs['name']] = None + + def anchors(self): + return self._anchors.keys() + + def _extractAnchors(self, f): + extractor = AnchorIndex.AnchorExtractor() + extractor.feed(file(f).read()) + extractor.close() + for anchor in extractor.anchors(): + self._addAnchor(anchor, f) + + +class LinkFixer: + + def __init__(self, skipdirs=('.svn',)): + self._index = AnchorIndex(skipdirs) + + def init(self): + self._index.build() + self._files = 0 + self._found = 0 + self._fixed = 0 + + class LinkFilter(HTMLFilter): + + def __init__(self, index, key, topdir, out): + HTMLFilter.__init__(self, out) + self._index = index + self._key = key + self._topdir = topdir + self._skip_a = False + self._found = 0 + self._fixed = 0 + + def _s_A(self, attrs): + self._skip_a = False + if self._key in dict(attrs).get('href',''): + self._found += 1 + ix = [ i for i, attr in enumerate(attrs) if attr[0] == 'href' ][0] + target = attrs[ix][1] + if '#' in target: + anchor = target.split('#')[1] + target = self._index[anchor] + if target: + target = '%s#%s' % (target, anchor) + else: + target = self._index[os.path.split(target)[1]] + if target: + self._fixed += 1 + attrs[ix] = ('href', os.path.join(self._topdir,target)) + else: + self._skip_a = True + return + self.emit_starttag('a',attrs) + + def _e_A(self): + if self._skip_a: + self._skip_a = False + else: + self.emit_endtag('a') + + def stats(self): + return (self._found, self._fixed) + + def fix(self, path, target): + self._files += 1 + data = file(path).read() + filt = LinkFixer.LinkFilter(self._index, + target, + "../" * (len(os.path.split(path)[0].split("/"))), + file(path,"w")) + filt.feed(data) + filt.close() + self._found += filt.stats()[0] + self._fixed += filt.stats()[1] + + def stats(self): + return (self._files, self._found, self._fixed) + + +(opts, args) = getopt.getopt(sys.argv[1:], "s:") +if len(args) != 2: + sys.stderr.write("""Usage: + fix-links.py [-s skip-dir]... + +Process the 'errorX.txt' and 'errorAX.txt' files as generated by +'linklint': Check all invalid links and try to find the correct +target. If a target is found, the link is changed accordingly, +otherwise the link is removed. + +To find anchors, fix-links.py generates a complete index of all +anchors defined in any HTML file in the current directory or some +subdirectory. The directories named 'skiped-dir' (at any level) will +not be scanned for '*.html' files. +""") + sys.exit(1) + +skipdirs = [ val for opt, val in opts if opt == '-s' ] + +fixer = LinkFixer(skipdirs) +fixer.init() + +target = None +for l in file(args[0]): + l = l.rstrip() + if l.startswith('/'): + target = '#' + os.path.split(l)[1] + elif l.startswith(' /') and not l.endswith('/'): + sys.stderr.write("%s\n" % l) + fixer.fix(l[5:], target) + +for l in file(args[1]): + l = l.rstrip() + if l.startswith('/'): + target = l.split('#')[1] + elif l.startswith(' /') and not l.endswith('/'): + sys.stderr.write("%s\n" % l) + fixer.fix(l[5:], target) + +files, found, fixed = fixer.stats() + +sys.stderr.write(""" +Files processed : %5d +Links processed : %5d +Links fixed : %5d +Links removed : %5d +""" % (files, found, fixed, found-fixed)) diff --git a/senfscons/SENFSCons.py b/senfscons/SENFSCons.py index 4245fa9..74e035d 100644 --- a/senfscons/SENFSCons.py +++ b/senfscons/SENFSCons.py @@ -118,7 +118,7 @@ def Finalizer(f): # libraries are provided by the distribution, you probably don't need # to specify any parameters. If your configuration is more complex, # refer to the Boost.Build +# href="http://www.boost.org/tools/build/v2/index.html">Boost.Build # documentation for a definition of the terms used above (toolset, # variant, runtime ...). #