diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..fb31768 --- /dev/null +++ b/.cproject @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + + all + true + true + true + + + make + + clean + true + true + false + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..850e1d4 --- /dev/null +++ b/.project @@ -0,0 +1,80 @@ + + + pvAccessCPP + + + pvDataCPP + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/pvAccessApp/Makefile b/pvAccessApp/Makefile index b35d36c..5990db0 100644 --- a/pvAccessApp/Makefile +++ b/pvAccessApp/Makefile @@ -1,5 +1,7 @@ TOP = .. include $(TOP)/configure/CONFIG +DIRS += ca +DIRS += utils testUtils DIRS += client testClient #server #DIRS += localImpl remoteClientImpl remoteServerImpl #DIRS += localImplTest remoteImplTest diff --git a/pvAccessApp/ca/Makefile b/pvAccessApp/ca/Makefile new file mode 100644 index 0000000..7710415 --- /dev/null +++ b/pvAccessApp/ca/Makefile @@ -0,0 +1,17 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG + +INC += caConstants.h +INC += version.h + +LIBSRCS += version.cpp + +LIBRARY = pvAccess + +#pvMisc_LIBS += Com + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/pvAccessApp/ca/caConstants.h b/pvAccessApp/ca/caConstants.h new file mode 100644 index 0000000..947f28b --- /dev/null +++ b/pvAccessApp/ca/caConstants.h @@ -0,0 +1,79 @@ +/* + * constants.hpp + * + * Created on: Oct 8, 2010 + * Author: Miha Vitorovic + */ + +#ifndef CONSTANTS_H_ +#define CONSTANTS_H_ + +#include + +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + /** CA protocol magic number */ + const int8 CA_MAGIC = 0xCA; + + /** CA protocol major revision (implemented by this library). */ + const int8 CA_MAJOR_PROTOCOL_REVISION = 5; + + /** CA protocol minor revision (implemented by this library). */ + const int8 CA_MINOR_PROTOCOL_REVISION = 0; + + /** Unknown CA protocol minor revision. */ + const int8 CA_UNKNOWN_MINOR_PROTOCOL_REVISION = 0; + + /** CA magic/major version signature (e.g. 0xCA50). */ + const int16 CA_MAGIC_AND_MAJOR_VERSION = CA_MAGIC<<8 + |CA_MAJOR_PROTOCOL_REVISION<<4; + + /** CA magic/version signature (e.g. 0xCA51). */ + const int16 CA_MAGIC_AND_VERSION = CA_MAGIC<<8 + |CA_MAJOR_PROTOCOL_REVISION<<4|CA_MINOR_PROTOCOL_REVISION; + + /** CA protocol port base. */ + const int32 CA_PORT_BASE = 5056; + + /** Default CA server port. */ + const int32 CA_SERVER_PORT = CA_PORT_BASE+2*CA_MAJOR_PROTOCOL_REVISION; + + /** Default CA beacon port. */ + const int32 CA_BROADCAST_PORT = CA_SERVER_PORT+1; + + /** CA protocol message header size. */ + const int16 CA_MESSAGE_HEADER_SIZE = 8; + + /** + * UDP maximum send message size. + * MAX_UDP: 1500 (max of ethernet and 802.{2,3} MTU) - 20/40(IPv4/IPv6) + * - 8(UDP) - some reserve (the MTU of Ethernet is currently independent + * of its speed variant) + */ + const int32 MAX_UDP_SEND = 1440; + + /** UDP maximum receive message size. */ + const int32 MAX_UDP_RECV = 0xFFFF+16; + + /** TCP maximum receive message size. */ + const int32 MAX_TCP_RECV = 1024*16; + + /** Maximum number of search requests in one search message. */ + const int32 MAX_SEARCH_BATCH_COUNT = 0xFFFF; + + /** Default priority (corresponds to POSIX SCHED_OTHER) */ + const int16 CA_DEFAULT_PRIORITY = 0; + + /** Unreasonable channel name length. */ + const int32 UNREASONABLE_CHANNEL_NAME_LENGTH = 500; + + /** Invalid data type. */ + const int16 INVALID_DATA_TYPE = (short)0xFFFF; + + } +} + +#endif /* CONSTANTS_H_ */ diff --git a/pvAccessApp/ca/version.cpp b/pvAccessApp/ca/version.cpp new file mode 100644 index 0000000..1b8523f --- /dev/null +++ b/pvAccessApp/ca/version.cpp @@ -0,0 +1,52 @@ +/* + * version.cpp + * + * Created on: Oct 8, 2010 + * Author: Miha Vitorovic + */ + +#include "version.h" + +namespace epics { + namespace pvAccess { + + using epics::pvData::String; + + const String Version::getLongVersionString() const { + String ret; + ret += getProductName(); + ret += " ["; + ret += getImplementationLanguage(); + ret += "] v"; + ret += getMajorVersion(); + ret += "."; + ret += getMinorVersion(); + ret += "."; + if(getDevelopmentVersion()>0) { + ret += "D"; + ret += getDevelopmentVersion(); + } else + ret += getMaintenanceVersion(); + + return ret; + } + + const String Version::getVersionString() const { + String ret; + ret += getProductName(); + ret += " v"; + ret += getMajorVersion(); + ret += "."; + ret += getMinorVersion(); + ret += "."; + if(getDevelopmentVersion()>0) { + ret += "D"; + ret += getDevelopmentVersion(); + } else + ret += getMaintenanceVersion(); + + return ret; + } + + } +} diff --git a/pvAccessApp/ca/version.h b/pvAccessApp/ca/version.h new file mode 100644 index 0000000..dac004d --- /dev/null +++ b/pvAccessApp/ca/version.h @@ -0,0 +1,135 @@ +/* + * version.h + * + * Created on: Oct 8, 2010 + * Author: Miha Vitorovic + */ + +#ifndef VERSION_H_ +#define VERSION_H_ + +#include +#include + +namespace epics { + namespace pvAccess { + + using epics::pvData::String; + + class Version : public epics::pvData::NoDefaultMethods { + public: + /** + * Default constructor. + * @param productName product name. + * @param implementationLangugage implementation language. + * @param majorVersion major version. + * @param minorVersion minor version. + * @param maintenanceVersion maintenance version. + * @param developmentVersion development version. + */ + Version(String productName, String implementationLangugage, + int majorVersion, int minorVersion, int maintenanceVersion, + int developmentVersion) : + _productName(productName), _implementationLanguage( + implementationLangugage), _majorVersion(majorVersion), + _minorVersion(minorVersion), _maintenanceVersion( + maintenanceVersion), _developmentVersion( + developmentVersion) { + } + + /** The name of the product */ + const inline String getProductName() const { + return _productName; + } + + /** Implementation Language: C++ + */ + inline const String getImplementationLanguage() const { + return _implementationLanguage; + } + + /** + * Major version number. This changes only when there is a + * significant, externally apparent enhancement from the previous release. + * 'n' represents the n'th version. + * + * Clients should carefully consider the implications of new versions as + * external interfaces and behaviour may have changed. + */ + inline int getMajorVersion() const { + return _majorVersion; + } + + /** + * Minor vesion number. This changes when: + *
    + *
  • a new set of functionality is to be added
  • + *
  • API or behaviour change
  • + *
  • its designated as a reference release
  • + *
+ */ + inline int getMinorVersion() const { + return _minorVersion; + } + + /** + * Maintenance version number. Optional identifier used to designate + * maintenance drop applied to a specific release and contains fixes for + * defects reported. It maintains compatibility with the release and + * contains no API changes. When missing, it designates the final and + * complete development drop for a release. + */ + inline int getMaintenanceVersion() const { + return _maintenanceVersion; + } + + /** + * Development drop number. Optional identifier designates development drop + * of a specific release. D01 is the first development drop of a new + * release. + * + * Development drops are works in progress towards a compeleted, final + * release. A specific development drop may not completely implement all + * aspects of a new feature, which may take several development drops to + * complete. At the point of the final drop for the release, the D suffix + * will be omitted. + * + * Each 'D' drops can contain functional enhancements as well as defect + * fixes. 'D' drops may not be as stable as the final releases. + */ + inline int getDevelopmentVersion() const { + return _developmentVersion; + } + + /** + * Get the long version string. Version String formatted like
+ * "ProductName \[ImplementationLanguage\] 'v'v.r[.dd|Dnn]" + *
e.g.
"CAJ [Java] v1.0.1" + *
+ * + * @return String denoting current version + */ + const String getLongVersionString() const; + + /** + * Get the basic version string. Version String formatted like
+ * "ProductName 'v'v.r[.dd|Dnn]" + *
e.g.
"CAJ v1.0.1" + *
+ * + * @return String denoting current version + */ + const String getVersionString() const; + + private: + String _productName; + String _implementationLanguage; + int _majorVersion; + int _minorVersion; + int _maintenanceVersion; + int _developmentVersion; + }; + } +} + +#endif /* VERSION_H_ */ diff --git a/pvAccessApp/testUtils/Makefile b/pvAccessApp/testUtils/Makefile new file mode 100644 index 0000000..58d8f96 --- /dev/null +++ b/pvAccessApp/testUtils/Makefile @@ -0,0 +1,20 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG + +PROD_HOST += hexDumpTest +hexDumpTest_SRCS += hexDumpTest.cpp +hexDumpTest_LIBS += pvAccUtils + +PROD_HOST += wildcharMatcherTest +wildcharMatcherTest_SRCS += wildcharMatcherTest.cpp +wildcharMatcherTest_LIBS += pvAccUtils Com + +PROD_HOST += arrayFIFOTest +arrayFIFOTest_SRCS += arrayFIFOTest.cpp +arrayFIFOTest_LIBS += pvAccUtils Com + + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE diff --git a/pvAccessApp/testUtils/arrayFIFOTest.cpp b/pvAccessApp/testUtils/arrayFIFOTest.cpp new file mode 100644 index 0000000..c64bf64 --- /dev/null +++ b/pvAccessApp/testUtils/arrayFIFOTest.cpp @@ -0,0 +1,47 @@ +/* + * arrayFIFOTest.cpp + * + * Created on: Nov 9, 2010 + * Author: Miha Vitorovic + */ + +#include +#include + +#include "arrayFIFO.h" + +using namespace epics::pvAccess; +using std::cout; +using std::endl; + +int main(int argc, char *argv[]) { + ArrayFIFO fifo; + + assert(fifo.size()==0); + assert(fifo.isEmpty()); + + cout<<"Testing clear..."< + +#include "hexDump.h" + +using namespace epics::pvAccess; +using std::cout; +using std::endl; + +int main(int argc, char *argv[]) { + char TO_DUMP[] = "pvAccess dump test\0\1\2\3\4\5\6\254\255\256"; + + hexDump("test", (int8*)TO_DUMP, 18+9); + + hexDump("only text", (int8*)TO_DUMP, 18); + + hexDump("22 byte test", (int8*)TO_DUMP, 22); + + cout< +#include + +#include "wildcharMatcher.h" + +using namespace epics::pvAccess; +using std::cout; + +int main(int argc, char *argv[]) { + String testString = "Test string for matcher"; + + cout<<"testSet(\"[abc]\",1,'a').\n"; + assert(testSet("[abc]", 1, 'a')); + cout<<"testSet(\"[abc]\",1,'b').\n"; + assert(testSet("[abc]", 1, 'b')); + cout<<"testSet(\"[abc]\",1,'c').\n"; + assert(testSet("[abc]", 1, 'c')); + cout<<"testSet(\"[abc]\",1,'d').\n"; + assert(!testSet("[abc]", 1, 'd')); + cout<<"testSet(\"[!abc]\",1,'d').\n"; + assert(testSet("[!abc]", 1, 'd')); + cout<<"testSet(\"[a-c]\",1,'d').\n"; + assert(!testSet("[a-c]", 1, 'd')); + cout<<"testSet(\"[!a-c]\",1,'d').\n"; + assert(testSet("[!a-c]", 1, 'd')); + cout<<"testSet(\"[ac-f]\",1,'d').\n"; + assert(testSet("[ac-f]", 1, 'd')); + cout<<"testSet(\"[!ac-f]\",1,'d').\n"; + assert(!testSet("[!ac-f]", 1, 'd')); + + + cout<<"\n"; + + cout<<"Test string is: \""< +#include + +using epics::pvData::Mutex; +using epics::pvData::Lock; +using epics::pvData::BaseException; + +namespace epics { + namespace pvAccess { + + template + class ArrayFIFO { + public: + /** + * Constructs an empty array deque with an initial capacity + * sufficient to hold 16 elements. Array FIFO is designed to hold + * objects allocated on the heap. + */ + ArrayFIFO(); + + /** + * Constructs an empty array deque with an initial capacity + * sufficient to hold the specified number of elements. Array FIFO + * is designed to hold objects allocated on the heap. + * + * @param[in] numElements lower bound on initial capacity of the deque + */ + ArrayFIFO(size_t numElements); + ~ArrayFIFO(); + + /** + * Inserts the specified element at the front of this deque. + * + * @param[in] e the element to add. + */ + void addFirst(const T e); + + /** + * Inserts the specified element at the end of this deque. + * @param[in] e the element to add + */ + void addLast(const T e); + + T pollFirst(); + T pollLast(); + T peekFirst(); + T peekLast(); + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque. + * + * @param[in] e the element to push + */ + void push(const T e); + + /** + * Pops an element from the stack represented by this deque. In other + * words, removes and returns the first element of this deque. + * + * @return the element at the front of this deque (which is the top + * of the stack represented by this deque), null if no element available. + */ + T pop(); + + /** + * Looks at the object at the top of this stack without removing it + * from the stack. + * @return the object at the top of this stack (the last item + * of the Vector object). + */ + T peek(); + + /** + * Returns the number of elements in this deque. + * @return the number of elements in this deque + */ + size_t size(); + + /** + * Returns true if this deque contains no elements. + * + * @return true if this deque contains no elements + */ + bool isEmpty(); + + /** + * Removes all of the elements from this deque. + * The deque will be empty after this call returns. + * + * @param freeElements tells the methods to automatically free + * the memory of all the elments in the FIFO. Default is {@code true} + */ + void clear(); + + /** + * Removes the first occurrence of the specified element in this + * deque (when traversing the deque from head to tail). + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element e such that + * o.equals(e) (if such an element exists). + * Returns true if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return true if the deque contained the specified element + */ + bool remove(const T e); + + private: + T* _elements; // array of pointers + size_t _head, _tail, _size; + Mutex _mutex; + static int MIN_INITIAL_CAPACITY; + + /** + * Allocate empty array to hold the given number of elements. + * @param[in] numElements the number of elements to hold + */ + void allocateElements(const size_t numElements); + + /** + * Double the capacity of this deque. Call only when full, i.e., + * when head and tail have wrapped around to become equal. + */ + void doubleCapacity(); + + void arraycopy(T* src, size_t srcPos, T* dest, size_t destPos, size_t length); + + /** + * Removes the element at the specified position in the elements array, + * adjusting head and tail as necessary. This can result in motion of + * elements backwards or forwards in the array. + * + *

This method is called delete rather than remove to emphasize + * that its semantics differ from those of {@link List#remove(int)}. + * + * @return true if elements moved backwards + */ + bool del(const size_t i); + + }; + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * g++ requires template definition inside a header file. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + template + int ArrayFIFO::MIN_INITIAL_CAPACITY = 8; + + template + void ArrayFIFO::arraycopy(T* src, size_t srcPos, T* dest, + size_t destPos, size_t length) { + for(size_t i = 0; i + void ArrayFIFO::allocateElements(size_t numElements) { + _size = MIN_INITIAL_CAPACITY; + // Find the best power of two to hold elements. + // Tests "<=" because arrays aren't kept full. + if(numElements>=_size) { + _size = numElements; + _size |= (_size>>1); + _size |= (_size>>2); + _size |= (_size>>4); + _size |= (_size>>8); + _size |= (_size>>16); + _size++; + } + _elements = new T[_size]; + } + + template + void ArrayFIFO::doubleCapacity() { + size_t p = _head; + size_t n = _size; + size_t r = n-p; // number of elements to the right of p + size_t newCapacity = n<<1; + T* a = new T[newCapacity]; + arraycopy(_elements, p, a, 0, r); + arraycopy(_elements, 0, a, r, p); + delete _elements; + _elements = a; + _size = newCapacity; + _head = 0; + _tail = n; + + } + + template + ArrayFIFO::ArrayFIFO() : + _head(0), _tail(0), _size(16), _mutex() { + _elements = new T[16]; + } + + template + ArrayFIFO::ArrayFIFO(size_t numElements) : + _head(0), _tail(0), _mutex() { + allocateElements(numElements); + } + + template + ArrayFIFO::~ArrayFIFO() { + delete _elements; + } + + template + void ArrayFIFO::addFirst(const T e) { + Lock lock(&_mutex); + + _elements[_head = (_head-1)&(_size-1)] = e; + if(_head==_tail) doubleCapacity(); + } + + template + void ArrayFIFO::addLast(const T e) { + Lock lock(&_mutex); + + _elements[_tail] = e; + if((_tail = (_tail+1)&(_size-1))==_head) doubleCapacity(); + } + + template + T ArrayFIFO::pollFirst() { + Lock lock(&_mutex); + + if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + + size_t h = _head; + T result = _elements[h]; // Element is null if deque empty + _elements[h] = NULL; // Must null out slot + _head = (h+1)&(_size-1); + return result; + } + + template + T ArrayFIFO::pollLast() { + Lock lock(&_mutex); + + if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + + int t = (_tail-1)&(_size-1); + T result = _elements[t]; + _tail = t; + return result; + } + + template + T ArrayFIFO::peekFirst() { + Lock lock(&_mutex); + + if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + + return _elements[_head]; + } + + template + T ArrayFIFO::peekLast() { + Lock lock(&_mutex); + + if(isEmpty()) THROW_BASE_EXCEPTION("ArrayFIFO empty"); + + return _elements[(_tail-1)&(_size-1)]; + } + + template + void ArrayFIFO::push(const T e) { + addLast(e); + } + + template + T ArrayFIFO::pop() { + return pollLast(); + } + + template + T ArrayFIFO::peek() { + return peekFirst(); + } + + template + size_t ArrayFIFO::size() { + Lock lock(&_mutex); + + return (_tail-_head)&(_size-1); + } + + template + bool ArrayFIFO::isEmpty() { + Lock lock(&_mutex); + + return _head==_tail; + } + + template + void ArrayFIFO::clear() { + Lock lock(&_mutex); + + _head = _tail = 0; + } + + template + bool ArrayFIFO::del(const size_t i) { + int mask = _size-1; + int h = _head; + int t = _tail; + int front = (i-h)&mask; + int back = (t-i)&mask; + + // Invariant: head <= i < tail mod circularity + if(front>=((t-h)&mask)) THROW_BASE_EXCEPTION( + "Illegal State Exception"); // concurrency problem!!! + + // Optimize for least element motion + if(front + bool ArrayFIFO::remove(const T e) { + Lock lock(&_mutex); + + if(isEmpty()) return false; // nothing to do + + int mask = _size-1; + int i = _head; + while(i!=_tail) { + if(e == _elements[i]) { + del(i); + return true; + } + i = (i+1)&mask; + } + return false; + } + + + } +} + +#endif /* ARRAYFIFO_H_ */ diff --git a/pvAccessApp/utils/hexDump.cpp b/pvAccessApp/utils/hexDump.cpp new file mode 100644 index 0000000..0de66b1 --- /dev/null +++ b/pvAccessApp/utils/hexDump.cpp @@ -0,0 +1,113 @@ +/* + * hexDump.cpp + * + * Created on: Nov 3, 2010 + * Author: Miha Vitorovic + */ + +#include +#include +#include "hexDump.h" + +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + String toHex(int8); + char toAscii(int8); + + void hexDump(const String name, const int8 *bs, int len) { + hexDump(name, bs, 0, len); + } + + void hexDump(const String name, const int8 *bs, int start, int len) { + hexDump("", name, bs, start, len); + } + + void hexDump(const String prologue, const String name, const int8 *bs, + int start, int len) { + + std::stringstream header; + + header<>4)&0x0F; + sb += lookup[upper]; + + int lower = b&0x0F; + sb += lookup[lower]; + + sb += ' '; + + return sb; + } + + /** + * Get ASCII representation of byte, dot if non-readable. + * @param b + * @return ASCII representation of byte, dot if non-readable. + */ + char toAscii(int8 b) { + if(b>(int8)31&&b<(int8)127) + return (char)b; + else + return '.'; + } + + } +} diff --git a/pvAccessApp/utils/hexDump.h b/pvAccessApp/utils/hexDump.h new file mode 100644 index 0000000..8de3aba --- /dev/null +++ b/pvAccessApp/utils/hexDump.h @@ -0,0 +1,49 @@ +/* + * hexDump.h + * + * Created on: Nov 3, 2010 + * Author: user + */ + +#ifndef HEXDUMP_H_ +#define HEXDUMP_H_ + +#include + +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + /** + * Output a buffer in hex format. + * @param name name (description) of the message. + * @param bs buffer to dump + * @param len first bytes (length) to dump. + */ + void hexDump(const String name, const int8 *bs, int len); + + /** + * Output a buffer in hex format. + * @param[in] name name (description) of the message. + * @param[in] bs buffer to dump + * @param[in] start dump message using given offset. + * @param[in] len first bytes (length) to dump. + */ + void hexDump(const String name, const int8 *bs, int start, int len); + + /** + * Output a buffer in hex format. + * @param[in] prologue string to prefixed to debug output, can be null + * @param[in] name name (description) of the message. + * @param[in] bs buffer to dump + * @param[in] start dump message using given offset. + * @param[in] len first bytes (length) to dump. + */ + void hexDump(const String prologue, const String name, const int8 *bs, + int start, int len); + + } +} + +#endif /* HEXDUMP_H_ */ diff --git a/pvAccessApp/utils/wildcharMatcher.cpp b/pvAccessApp/utils/wildcharMatcher.cpp new file mode 100644 index 0000000..3451ef0 --- /dev/null +++ b/pvAccessApp/utils/wildcharMatcher.cpp @@ -0,0 +1,268 @@ +/* + * wildcharMatcher.cpp + * + * Created on: Nov 4, 2010 + * Author: Miha Vitorovic + */ + +#include + +#include "wildcharMatcher.h" + +using std::cout; + +namespace epics { + namespace pvAccess { + + /** Wildchar matcher debug */ + const bool WCM_DEBUG = false; + + /** Value of initial state */ + const int WCM_INITIAL = 0; + + /** Value of final state */ + const int WCM_FINAL = 2; + + /** Value of error state */ + const int WCM_ERROR = 99; + + /** Any character (except control, unless escaped) */ + const int WCM_TOKEN_CHAR = 0; + + /** Token for end of set: ] */ + const int WCM_TOKEN_END = 1; + + /** Token for negation: */ + const int WCM_TOKEN_NOT = 2; + + /** Token for range specification: - */ + const int WCM_TOKEN_MINUS = 3; + + /** + * Transition table holds the nextState used in set parsing. Rows define + * states, columns define tokens. transitions[1][3] = 5 means: if in state + * 1 next token is 3, goto state 5 + */ + const int TRANSITIONS[][4] = { { 1, WCM_FINAL, 3, 4 }, { 1, WCM_FINAL, + WCM_ERROR, 5 }, { WCM_ERROR, WCM_ERROR, WCM_ERROR, WCM_ERROR }, + { 1, WCM_FINAL, WCM_ERROR, 4 }, { 6, WCM_ERROR, WCM_ERROR, + WCM_ERROR }, { 6, WCM_FINAL, WCM_ERROR, WCM_ERROR }, { + 1, WCM_FINAL, WCM_ERROR, WCM_ERROR } }; + + int getToken(const char ch) { + switch(ch) { + case ']': + return WCM_TOKEN_END; + case '!': + return WCM_TOKEN_NOT; + case '-': + return WCM_TOKEN_MINUS; + default: + return WCM_TOKEN_CHAR; + } + } + + bool testSet(const String pattern, int offset, const char ch) { + int n = pattern.length(); + + int state = WCM_INITIAL; + int nextToken = ' '; + char nextChar = ' '; + char ch1 = ' '; + + bool found = false; + + bool negate = false; + + while(!found) { + // Check for offset in case of final state, which is over the limit, + // if ] is at the end of the string. + if(offset=ch1)&&(ch + <=nextChar)); // condition ...a-z... + if(nextToken==WCM_TOKEN_END) found = (ch>=ch1); // condition ...a-] + break; + } + + if(WCM_DEBUG) { + cout<<"( "< "<-1)&&(is>-1)&&(ip-1)&&(is>-1)&&(ip + +using epics::pvData::String; + +namespace epics { + namespace pvAccess { + + /** + * DFA for parsing set strings. DFA was obtained from JFlex using the rule + * : macro: CHAR = [^-\]\!] (everything except ], ! and - rule : + * [!]?(-{CHAR})?(({CHAR}-{CHAR})|({CHAR}))({CHAR}-)?\] Result of + * optimized NDFA is Character classes: class 0: [0-' + * ']['"'-',']['.'-'\']['^'-65535] class 1: [']'] class 2: ['!'] class + * 3: ['-'] Transition graph (for class goto state) State 0: 0 -> 1, 1 -> + * 2, 2 -> 3, 3 -> 4 State 1: 0 -> 1, 1 -> 2, 3 -> 5 State [FINAL] State + * 3: 0 -> 1, 1 -> 2, 3 -> 4 State 4: 0 -> 6 State 5: 0 -> 6, 1 -> 2 State + * 6: 0 -> 1, 1 -> 2 + * + * @param pattern DOCUMENT ME! + * @param offset DOCUMENT ME! + * @param ch DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + bool testSet(const String pattern, int offset, const char ch); + + /** + * Recursive method for parsing the string. To avoid copying the strings, + * the method accepts offset indices into both parameters. + * + * @param pattern Pattern used in parsing + * @param ofp Offset into pattern string (ofp > 0) + * @param str String to test + * @param ofs Offset into test string (ofs > 0); + * + * @return boolean Do the strings match + */ + bool parse(const String pattern, const int ofp, const String str, + const int ofs); + + /** + * DOCUMENT ME! + * + * @param pattern DOCUMENT ME! + * @param str DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + bool match(const String pattern, const String str); + + } +} + +#endif /* WILDCHARMATCHER_H_ */