/* * Copyright (c) 2012 Mark McCurry * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef RTOSC_PORTS #define RTOSC_PORTS #include #include #include #include #include #include #include #include #include namespace rtosc { //First define all types typedef const char *msg_t; struct Port; struct Ports; struct RtData { RtData(void); char *loc; size_t loc_size; void *obj; int matches; const Port *port; const char *message; virtual void reply(const char *path, const char *args, ...); virtual void reply(const char *msg); virtual void chain(const char *path, const char *args, ...){}; virtual void chain(const char *msg){}; virtual void broadcast(const char *path, const char *args, ...); virtual void broadcast(const char *msg); virtual void forward(const char *rational=NULL); }; /** * Port in rtosc dispatching hierarchy */ struct Port { const char *name; //< Pattern for messages to match const char *metadata;//< Statically accessable data about port const Ports *ports; //< Pointer to further ports std::function cb;//< Callback for matching functions class MetaIterator { public: MetaIterator(const char *str); //A bit odd to return yourself, but it seems to work for this //context const MetaIterator& operator*(void) const {return *this;} const MetaIterator* operator->(void) const {return this;} bool operator==(MetaIterator a) {return title == a.title;} bool operator!=(MetaIterator a) {return title != a.title;} MetaIterator& operator++(void); const char *title; const char *value; }; class MetaContainer { public: MetaContainer(const char *str_); MetaIterator begin(void) const; MetaIterator end(void) const; MetaIterator find(const char *str) const; size_t length(void) const; const char *operator[](const char *str) const; const char *str_ptr; }; MetaContainer meta(void) const { if(metadata && *metadata == ':') return MetaContainer(metadata+1); else return MetaContainer(metadata); } }; /** * Ports - a dispatchable collection of Port entries * * This structure makes it somewhat easier to perform actions on collections of * port entries and it is responsible for the dispatching of OSC messages to * their respective ports. * That said, it is a very simple structure, which uses a stl container to store * all data in a simple dispatch table. * All methods post-initialization are RT safe (assuming callbacks are RT safe) */ struct Ports { std::vector ports; std::function default_handler; typedef std::vector::const_iterator itr_t; /**Forwards to builtin container*/ itr_t begin() const {return ports.begin();} /**Forwards to builtin container*/ itr_t end() const {return ports.end();} /**Forwards to builtin container*/ size_t size() const {return ports.size();} /**Forwards to builtin container*/ const Port &operator[](unsigned i) const {return ports[i];} Ports(std::initializer_list l); ~Ports(void); Ports(const Ports&) = delete; /** * Dispatches message to all matching ports. * This uses simple pattern matching available in rtosc::match. * * @param m a valid OSC message * @param d The RtData object shall contain a path buffer (or null), the length of * the buffer, a pointer to data. */ void dispatch(const char *m, RtData &d, bool base_dispatch=false) const; /** * Retrieve local port by name * TODO implement full matching */ const Port *operator[](const char *name) const; /** * Find the best match for a given path * * @parameter path partial OSC path * @returns first path prefixed by the argument * * Example usage: * @code * Ports p = {{"foo",0,0,dummy_method}, * {"flam",0,0,dummy_method}, * {"bar",0,0,dummy_method}}; * p.apropos("/b")->name;//bar * p.apropos("/f")->name;//foo * p.apropos("/fl")->name;//flam * p.apropos("/gg");//NULL * @endcode */ const Port *apropos(const char *path) const; /** * Collapse path with parent path identifiers "/.." * * e.g. /foo/bar/../baz => /foo/baz */ static char *collapsePath(char *p); protected: void refreshMagic(void); private: //Performance hacks class Port_Matcher *impl; unsigned elms; }; struct ClonePort { const char *name; std::function cb; }; struct ClonePorts:public Ports { ClonePorts(const Ports &p, std::initializer_list c); }; struct MergePorts:public Ports { MergePorts(std::initializer_list c); }; /********************* * Port walking code * *********************/ //typedef std::function port_walker_t; typedef void(*port_walker_t)(const Port*,const char*,void*); void walk_ports(const Ports *base, char *name_buffer, size_t buffer_size, void *data, port_walker_t walker); /********************* * Port Dumping code * *********************/ struct OscDocFormatter { const Ports *p; std::string prog_name; std::string uri; std::string doc_origin; std::string author_first; std::string author_last; //TODO extend this some more }; std::ostream &operator<<(std::ostream &o, OscDocFormatter &formatter); }; #endif