+ 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_ */