1. smbase
Start data section to licences/sm_licence.txt[1
/1
]
1: All of the modules in the sm system are
2: hereby placed in the public domain.
3:
Start cpp section to elk/sm_malloc_stub.cpp[1
/1
]
1: #line 9 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7: void checkHeap() {}
8:
9: void checkHeapNode(void *node) {}
10:
11: void malloc_stats() {}
12:
13: unsigned numMallocCalls() { return 0; }
14: unsigned numFreeCalls() { return 0; }
15:
16: void walkMallocHeap(HeapWalkFn func) {}
17:
18:
Start C section to elk/sm_array.h[1
/1
]
1: #line 28 "./lpsrc/sm.pak"
2: // array.h see license.txt for copyright and terms of use
3: // some array classes
4:
5: #ifndef ARRAY_H
6: #define ARRAY_H
7:
8: #include "sm_xassert.h"
9:
10:
11: // -------------------- Array ----------------------
12: // This is the same as C++'s built-in array, but automatically deallocates.
13: // If you want bounds checking too, use GrowArray, below.
14: template <class T>
15: class Array {
16: private: // data
17: T *arr;
18:
19: private: // not allowed
20: Array(Array&);
21: void operator=(Array&);
22:
23: public:
24: Array(int len) : arr(new T[len]) {}
25: ~Array() { delete[] arr; }
26:
27: T const &operator[] (int i) const { return arr[i]; }
28: T &operator[] (int i) { return arr[i]; }
29:
30: operator T const* () const { return arr; }
31: operator T const* () { return arr; }
32: operator T * () { return arr; }
33:
34: T const* operator+ (int i) const { return arr+i; }
35: T * operator+ (int i) { return arr+i; }
36:
37: // convenience
38: void setAll(T val, int len) {
39: for (int i=0; i<len; i++) {
40: arr[i] = val;
41: }
42: }
43: };
44:
45:
46: // ------------------ GrowArray --------------------
47: // This class implements an array of T's; it automatically expands
48: // when 'ensureAtLeast' or 'ensureIndexDoubler' is used; it does not
49: // automatically contract. All accesses are bounds-checked.
50: //
51: // class T must have:
52: // T::T(); // default ctor for making arrays
53: // operator=(T&); // assignment for copying to new storage
54: // T::~T(); // dtor for when old array is cleared
55: template <class T>
56: class GrowArray {
57: private: // data
58: T *arr; // underlying array; NULL if sz==0
59: int sz; // # allocated entries in 'arr'
60:
61: private: // funcs
62: void bc(int i) const // bounds-check an index
63: { xassert((unsigned)i < (unsigned)sz); }
64: void eidLoop(int index);
65:
66: public: // funcs
67: GrowArray(int initSz);
68: ~GrowArray();
69:
70: // allocated space
71: int size() const { return sz; }
72:
73: // element access
74: T const& operator[] (int i) const { bc(i); return arr[i]; }
75: T & operator[] (int i) { bc(i); return arr[i]; }
76:
77: // set size, reallocating if old size is different; if the
78: // array gets bigger, existing elements are preserved; if the
79: // array gets smaller, elements are truncated
80: void setSize(int newSz);
81:
82: // make sure there are at least 'minSz' elements in the array;
83: void ensureAtLeast(int minSz)
84: { if (minSz > sz) { setSize(minSz); } }
85:
86: // grab a read-only pointer to the raw array
87: T const *getArray() const { return arr; }
88:
89: // grab a writable pointer; use with care
90: T *getDangerousWritableArray() { return arr; }
91: T *getArrayNC() { return arr; } // ok, not all that dangerous..
92:
93: // make sure the given index is valid; if this requires growing,
94: // do so by doubling the size of the array (repeatedly, if
95: // necessary)
96: void ensureIndexDoubler(int index)
97: { if (sz-1 < index) { eidLoop(index); } }
98:
99: // set an element, using the doubler if necessary
100: void setIndexDoubler(int index, T const &value)
101: { ensureIndexDoubler(index); arr[index] = value; }
102:
103: // swap my data with the data in another GrowArray object
104: void swapWith(GrowArray<T> &obj) {
105: T *tmp1 = obj.arr; obj.arr = this->arr; this->arr = tmp1;
106: int tmp2 = obj.sz; obj.sz = this->sz; this->sz = tmp2;
107: }
108:
109: // convenience
110: void setAll(T val) {
111: for (int i=0; i<sz; i++) {
112: arr[i] = val;
113: }
114: }
115: };
116:
117:
118: template <class T>
119: GrowArray<T>::GrowArray(int initSz)
120: {
121: sz = initSz;
122: if (sz > 0) {
123: arr = new T[sz];
124: }
125: else {
126: arr = NULL;
127: }
128: }
129:
130:
131: template <class T>
132: GrowArray<T>::~GrowArray()
133: {
134: if (arr) {
135: delete[] arr;
136: }
137: }
138:
139:
140: template <class T>
141: void GrowArray<T>::setSize(int newSz)
142: {
143: if (newSz != sz) {
144: // keep track of old
145: int oldSz = sz;
146: T *oldArr = arr;
147:
148: // make new
149: sz = newSz;
150: if (sz > 0) {
151: arr = new T[sz];
152: }
153: else {
154: arr = NULL;
155: }
156:
157: // copy elements in common
158: for (int i=0; i<sz && i<oldSz; i++) {
159: arr[i] = oldArr[i];
160: }
161:
162: // get rid of old
163: if (oldArr) {
164: delete[] oldArr;
165: }
166: }
167: }
168:
169:
170: // this used to be ensureIndexDoubler's implementation, but
171: // I wanted the very first check to be inlined
172: template <class T>
173: void GrowArray<T>::eidLoop(int index)
174: {
175: if (sz-1 >= index) {
176: return;
177: }
178:
179: int newSz = sz;
180: while (newSz-1 < index) {
181: #ifndef NDEBUG_NO_ASSERTIONS // silence warning..
182: int prevSz = newSz;
183: #endif
184: if (newSz == 0) {
185: newSz = 1;
186: }
187: newSz = newSz*2;
188: xassert(newSz > prevSz); // otherwise overflow -> infinite loop
189: }
190:
191: setSize(newSz);
192: }
193:
194:
195: // ---------------------- ArrayStack ---------------------
196: // This is an array where some of the array is unused. Specifically,
197: // it maintains a 'length', and elements 0 up to length-1 are
198: // considered used, whereas length up to size-1 are unused. The
199: // expected use is as a stack, where "push" adds a new (used) element.
200: template <class T>
201: class ArrayStack : public GrowArray<T> {
202: private:
203: int len; // # of elts in the stack
204:
205: public:
206: ArrayStack(int initArraySize = 10)
207: : GrowArray<T>(initArraySize),
208: len(0)
209: {}
210: ~ArrayStack();
211:
212: // element access; these declarations are necessary because
213: // the uses of 'operator[]' below are not "dependent", hence
214: // they can't use declarations inherited from GrowArray<T>
215: T const& operator[] (int i) const { return GrowArray<T>::operator[](i); }
216: T & operator[] (int i) { return GrowArray<T>::operator[](i); }
217:
218: void push(T const &val)
219: { setIndexDoubler(len++, val); }
220: T pop()
221: { return operator[](--len); }
222: T const &top() const
223: { return operator[](len-1); }
224: T &top()
225: { return operator[](len-1); }
226:
227: // alternate interface, where init/deinit is done explicitly
228: // on returned references
229: T &pushAlt() // returns newly accessible item
230: { GrowArray<T>::ensureIndexDoubler(len++); return top(); }
231: T &popAlt() // returns item popped
232: { return operator[](--len); }
233:
234: // items stored
235: int length() const
236: { return len; }
237:
238: bool isEmpty() const
239: { return len==0; }
240: bool isNotEmpty() const
241: { return !isEmpty(); }
242:
243: void popMany(int ct)
244: { len -= ct; xassert(len >= 0); }
245: void empty()
246: { len = 0; }
247:
248: // useful when someone has used 'getDangerousWritableArray' to
249: // fill the array's internal storage
250: void setLength(int L) { len = L; }
251:
252: // consolidate allocated space to match length
253: void consolidate() { setSize(length()); }
254:
255: // swap
256: void swapWith(ArrayStack<T> &obj) {
257: GrowArray<T>::swapWith(obj);
258: int tmp = obj.len; obj.len = this->len; this->len = tmp;
259: }
260: };
261:
262: template <class T>
263: ArrayStack<T>::~ArrayStack()
264: {}
265:
266:
267: // iterator over contents of an ArrayStack, to make it easier to
268: // switch between it and SObjList as a representation
269: template <class T>
270: class ArrayStackIterNC {
271: NO_OBJECT_COPIES(ArrayStackIterNC); // for now
272:
273: private: // data
274: ArrayStack<T> /*const*/ &arr; // array being accessed
275: int index; // current element
276:
277: public: // funcs
278: ArrayStackIterNC(ArrayStack<T> /*const*/ &a) : arr(a), index(0) {}
279:
280: // iterator actions
281: bool isDone() const { return index >= arr.length(); }
282: void adv() { xassert(!isDone()); index++; }
283: T /*const*/ *data() const { return &(arr[index]); }
284: };
285:
286:
287: // I want const polymorphism!
288:
289:
290: // pop (and discard) a value off a stack at end of scope
291: template <class T>
292: class ArrayStackPopper {
293: private:
294: ArrayStack<T> &stk;
295:
296: public:
297: ArrayStackPopper(ArrayStack<T> &s) : stk(s) {}
298: ArrayStackPopper(ArrayStack<T> &s, T const &pushVal)
299: : stk(s) { stk.push(pushVal); }
300: ~ArrayStackPopper()
301: { stk.pop(); }
302: };
303:
304:
305: // ------------------- ObjArrayStack -----------------
306: // an ArrayStack of owner pointers
307: template <class T>
308: class ObjArrayStack {
309: private: // data
310: ArrayStack<T*> arr;
311:
312: public: // funcs
313: ObjArrayStack(int initArraySize = 10)
314: : arr(initArraySize)
315: {}
316: ~ObjArrayStack() { deleteAll(); }
317:
318: void push(T *ptr) { arr.push(ptr); }
319: T *pop() { return arr.pop(); }
320:
321: T const *topC() const { return arr.top(); }
322: T *top() { return arr.top(); }
323:
324: T const * operator[](int index) const { return arr[index]; }
325: T * operator[](int index) { return arr[index]; }
326:
327: int length() const { return arr.length(); }
328: bool isEmpty() const { return arr.isEmpty(); }
329: bool isNotEmpty() const { return !isEmpty(); }
330:
331: void deleteTopSeveral(int ct);
332: void deleteAll() { deleteTopSeveral(length()); }
333:
334: // will not delete any items
335: void consolidate() { arr.consolidate(); }
336:
337: void swapWith(ObjArrayStack<T> &obj) { arr.swapWith(obj.arr); }
338: };
339:
340:
341: template <class T>
342: void ObjArrayStack<T>::deleteTopSeveral(int ct)
343: {
344: while (ct--) {
345: delete pop();
346: }
347: }
348:
349:
350: // ------------------------- ArrayStackEmbed --------------------------
351: // This is like ArrayStack, but the first 'n' elements are stored
352: // embedded in this object, instead of allocated on the heap; in some
353: // circumstances, this lets us avoid allocating memory in common cases.
354: //
355: // For example, suppose you have an algorithm that is usually given a
356: // small number of elements, say 1 or 2, but occasionally needs to
357: // work with more. If you put the array of elements in the heap, then
358: // even in the common case a heap allocation is required, which is
359: // bad. But by using ArrayStackEmbed<T,2>, you can be sure that if
360: // the number of elements is <= 2 there will be no heap allocation,
361: // even though you still get a uniform (array-like) interface to all
362: // the elements.
363: template <class T, int n>
364: class ArrayStackEmbed {
365: private: // data
366: // embedded storage
367: T embed[n];
368:
369: // heap-allocated storage
370: GrowArray<T> heap;
371:
372: // total number of elements in the stack; if this
373: // exceeds 'n', then heap.arr is non-NULL
374: int len;
375:
376: private: // funcs
377: void bc(int i) const // bounds-check an index
378: { xassert((unsigned)i < (unsigned)len); }
379:
380: public: // funcs
381: ArrayStackEmbed()
382: : /*embed is default-init'd*/
383: heap(0), // initially a NULL ptr
384: len(0)
385: {}
386: ~ArrayStackEmbed()
387: {} // heap auto-deallocs its internal data
388:
389: void push(T const &val)
390: {
391: if (len < n) {
392: embed[len++] = val;
393: }
394: else {
395: heap.setIndexDoubler(len++ - n, val);
396: }
397: }
398:
399: T pop()
400: {
401: xassert(len > 0);
402: if (len <= n) {
403: return embed[--len];
404: }
405: else {
406: return heap[--len - n];
407: }
408: }
409:
410: int length() const
411: { return len; }
412: bool isEmpty() const
413: { return len==0; }
414: bool isNotEmpty() const
415: { return !isEmpty(); }
416:
417: // direct element access
418: T const &getElt(int i) const
419: {
420: bc(i);
421: if (i < n) {
422: return embed[i];
423: }
424: else {
425: return heap[i - n];
426: }
427: }
428:
429: T const& operator[] (int i) const
430: { return getElt(i); }
431: T & operator[] (int i)
432: { return const_cast<T&>(getElt(i)); }
433:
434: T const &top() const
435: { return getElt(len-1); }
436: };
437:
438:
439: #endif // ARRAY_H
Start C section to elk/sm_arraymap.h[1
/1
]
1: #line 468 "./lpsrc/sm.pak"
2: // arraymap.h see license.txt for copyright and terms of use
3: // template class to maintain an array-based map from
4: // integers to object pointers; the map owns all of
5: // the objects referred-to
6:
7: // as far as I know, nothing currently uses this file, but
8: // I believe it *has* been tested (whatever once used it now
9: // uses something else)
10:
11: #ifndef ARRAYMAP_H
12: #define ARRAYMAP_H
13:
14: #include "sm_xassert.h"
15:
16: // map: int -> T
17: template <class T>
18: class ArrayMap {
19: private: // data
20: T **map; // array[0,nextId-1] of owner ptr
21: int nextId; // next id to assign
22: int mapSize; // allocated size of 'map'
23:
24: private: // funcs
25: void make();
26: void del();
27: void validate(int index) const;
28:
29: public: // data
30: ArrayMap() { make(); }
31: ~ArrayMap() { del(); }
32:
33: // # of elements defined
34: int count() const { return nextId; }
35:
36: // insert a new element and yield its assigned id
37: int insert(T * /*owner*/ t);
38:
39: // retrieve by id
40: T const *lookupC(int id) const;
41: T *lookup(int id) { return const_cast<T*>(lookupC(id)); }
42: T *&lookupRef(int id) { validate(id); return map[id]; }
43:
44: // throw everything away
45: void empty() { del(); make(); }
46: };
47:
48: template <class T>
49: void ArrayMap<T>::make()
50: {
51: mapSize = 100;
52: nextId = 0;
53: map = new T* [mapSize];
54: }
55:
56: template <class T>
57: void ArrayMap<T>::del()
58: {
59: for (int i=0; i<nextId; i++) {
60: delete map[i];
61: }
62: delete[] map;
63: }
64:
65: template <class T>
66: int ArrayMap<T>::insert(T *t)
67: {
68: if (nextId == mapSize) {
69: // make it bigger
70: int newMapSize = mapSize * 2;
71: T **newMap = new T* [newMapSize];
72:
73: // copy the old contents to the new map
74: for (int i=0; i<mapSize; i++) {
75: newMap[i] = map[i];
76: }
77: mapSize = newMapSize;
78:
79: // blow away the old map
80: delete[] map;
81:
82: // grab the new map
83: map = newMap;
84: }
85:
86: int ret = nextId++;
87: map[ret] = t;
88: return ret;
89: }
90:
91: template <class T>
92: void ArrayMap<T>::validate(int id) const
93: {
94: xassert(0 <= id && id < nextId);
95: }
96:
97: template <class T>
98: T const *ArrayMap<T>::lookupC(int id) const
99: {
100: validate(id);
101: return map[id];
102: }
103:
104:
105: #define FOREACH_ARRAYMAP(type, array, var) \
106: type const *var = NULL; \
107: for (int var##id=0; \
108: var##id<(array).count() && \
109: (var=(array).lookupC(var##id), true); \
110: var##id++)
111:
112:
113: #define FOREACH_ARRAYMAP_INDEX(array, var) \
114: for (int var=0; \
115: var<(array).count(); \
116: var++)
117:
118:
119: #define MUTATE_EACH_ARRAYMAP(type, array, var) \
120: type *var = NULL; \
121: for (int var##id=0; \
122: var##id<(array).count() && \
123: (var=(array).lookup(var##id), true); \
124: var##id++)
125:
126:
127: #endif // ARRAYMAP_H
Start C section to elk/sm_arrayqueue.h[1
/1
]
1: #line 596 "./lpsrc/sm.pak"
2: // arrayqueue.h
3: // queue, implemented with an array
4:
5: #ifndef ARRAYQUEUE_H
6: #define ARRAYQUEUE_H
7:
8: #include "sm_xassert.h"
9:
10: // needed operations on T:
11: // T() // default ctor
12: // operator=(T&) // assignment
13: // bool operator==(T&) // comparison
14:
15: template <class T>
16: class ArrayQueue {
17: private: // data
18: T *arr; // working storage
19: int arrSize; // allocated length of 'arr'
20: int head; // index of first element to dequeue
21: int tail; // index+1 of last element to dequeue
22:
23: // NOTE: If head == tail then the queue is empty. If head > tail,
24: // then the queue elements circularly wrap around the end of 'arr'.
25: // At all times, 0 <= head,tail < arrSize.
26:
27: public: // funcs
28: ArrayQueue(int initSize = 10);
29: ~ArrayQueue();
30:
31: // test # of elements in queue
32: int length() const
33: { return head<=tail? tail-head : arrSize-(head-tail); }
34: bool isEmpty() const { return head==tail; }
35: bool isNotEmpty() const { return !isEmpty(); }
36:
37: // add/remove elements in FIFO order
38: void enqueue(T const &t);
39: T dequeue();
40:
41: // remove all elements
42: void empty() { head = tail = 0; }
43:
44: // access elements of the queue in dequeue order; that is,
45: // element 0 is the next element to be dequeued, and element
46: // length()-1 is the element most recently enqueued
47: //
48: // as this interface is O(1), it is the intended method
49: // of iterating over the elements in the queue
50: T const &eltC(int index) const;
51: T &elt(int index) { return const_cast<T&>(eltC(index)); }
52: T &operator[] (int index) { return elt(index); }
53: T const &operator[] (int index) const { return eltC(index); }
54:
55: // reverse the sequence of stored elements
56: void reverse();
57:
58: // true if a specific element is among the queue elements
59: bool contains(T const &t) const;
60: };
61:
62:
63: template <class T>
64: ArrayQueue<T>::ArrayQueue(int initSize)
65: {
66: // initial size must be positive, since array growth is
67: // simply by doubling the size
68: xassert(initSize > 0);
69:
70: arr = new T[initSize];
71: arrSize = initSize;
72: head = tail = 0;
73: }
74:
75:
76: template <class T>
77: ArrayQueue<T>::~ArrayQueue()
78: {
79: delete[] arr;
80: }
81:
82:
83: template <class T>
84: void ArrayQueue<T>::enqueue(T const &t)
85: {
86: if (length() == arrSize-1) {
87: // must expand the queue
88:
89: // make new array
90: int newArrSize = arrSize * 2;
91: T *newArr = new T[newArrSize];
92:
93: // copy elements sequentially
94: int oldLength = length();
95: for (int i=0; i<oldLength; i++) {
96: newArr[i] = eltC(i);
97: }
98:
99: // discard old array
100: delete[] arr;
101:
102: // put new one in its place
103: arr = newArr;
104: arrSize = newArrSize;
105: head = 0;
106: tail = oldLength;
107: }
108:
109: // store the new element where 'tail' points
110: arr[tail] = t;
111:
112: // advance 'tail'
113: if (++tail == arrSize) {
114: tail = 0;
115: }
116: }
117:
118:
119: template <class T>
120: T ArrayQueue<T>::dequeue()
121: {
122: if (isEmpty()) {
123: xfailure("attempt to dequeue an empty queue");
124: }
125:
126: // advance 'head' while yielding the element it currently points at;
127: // avoid making an intermediate copy (for performance)
128: if (head == arrSize-1) {
129: head = 0;
130: return arr[arrSize-1];
131: }
132: else {
133: return arr[head++];
134: }
135: }
136:
137:
138: template <class T>
139: T const &ArrayQueue<T>::eltC(int index) const
140: {
141: xassert(0 <= index && index < length());
142:
143: if (head+index < arrSize) {
144: return arr[head+index];
145: }
146: else {
147: return arr[head+index - arrSize];
148: }
149: }
150:
151:
152: template <class T>
153: void ArrayQueue<T>::reverse()
154: {
155: int i = 0, j = length()-1;
156: while (i < j) {
157: // swap i,j elements
158: T tmp = elt(i);
159: elt(i) = elt(j);
160: elt(j) = tmp;
161:
162: i++;
163: j--;
164: }
165: }
166:
167:
168: template <class T>
169: bool ArrayQueue<T>::contains(T const &t) const
170: {
171: int len=length();
172: for (int i=0; i<len; i++) {
173: if (t == eltC(i)) {
174: return true;
175: }
176: }
177: return false;
178: }
179:
180:
181: #endif // ARRAYQUEUE_H
Start C section to elk/sm_astlist.h[1
/1
]
1: #line 778 "./lpsrc/sm.pak"
2: // astlist.h see license.txt for copyright and terms of use
3: // owner list wrapper around VoidTailList
4: // name 'AST' is because the first application is in ASTs
5:
6: #ifndef ASTLIST_H
7: #define ASTLIST_H
8:
9: #include "sm_vdtllist.h"
10:
11: template <class T> class ASTListIter;
12: template <class T> class ASTListIterNC;
13:
14: // a list which owns the items in it (will deallocate them), and
15: // has constant-time access to the last element
16: template <class T>
17: class ASTList {
18: private:
19: friend class ASTListIter<T>;
20: friend class ASTListIterNC<T>;
21:
22: protected:
23: VoidTailList list; // list itself
24:
25: private:
26: ASTList(ASTList const &obj); // not allowed
27:
28: public:
29: ASTList() : list() {}
30: ~ASTList() { deleteAll(); }
31:
32: // ctor to make singleton list; often quite useful
33: ASTList(T *elt) : list() { prepend(elt); }
34:
35: // stealing ctor; among other things, since &src->list is assumed to
36: // point at 'src', this class can't have virtual functions;
37: // these ctors delete 'src'
38: ASTList(ASTList<T> *src) : list(&src->list) {}
39: void steal(ASTList<T> *src) { deleteAll(); list.steal(&src->list); }
40:
41: // selectors
42: int count() const { return list.count(); }
43: bool isEmpty() const { return list.isEmpty(); }
44: bool isNotEmpty() const { return list.isNotEmpty(); }
45: T *nth(int which) { return (T*)list.nth(which); }
46: T const *nthC(int which) const { return (T const*)list.nth(which); }
47: T *first() { return (T*)list.first(); }
48: T const *firstC() const { return (T const*)list.first(); }
49: T *last() { return (T*)list.last(); }
50: T const *lastC() const { return (T const*)list.last(); }
51:
52: // insertion
53: void prepend(T *newitem) { list.prepend(newitem); }
54: void append(T *newitem) { list.append(newitem); }
55: void insertAt(T *newitem, int index) { list.insertAt(newitem, index); }
56: void concat(ASTList<T> &tail) { list.concat(tail.list); }
57:
58: // removal
59: T *removeFirst() { return (T*)list.removeFirst(); }
60: T *removeLast() { return (T*)list.removeLast(); }
61: T *removeAt(int index) { return (T*)list.removeAt(index); }
62: void removeItem(T *item) { list.removeItem((void*)item); }
63:
64: // this one is awkwardly named to remind the user that it's
65: // contrary to the usual intent of this class
66: void removeAll_dontDelete() { return list.removeAll(); }
67:
68: // deletion
69: void deleteFirst() { delete (T*)list.removeFirst(); }
70: void deleteAll();
71:
72: // list-as-set: selectors
73: int indexOf(T const *item) const { return list.indexOf((void*)item); }
74: int indexOfF(T const *item) const { return list.indexOfF((void*)item); }
75: bool contains(T const *item) const { return list.contains((void*)item); }
76:
77: // list-as-set: mutators
78: bool prependUnique(T *newitem) { return list.prependUnique(newitem); }
79: bool appendUnique(T *newitem) { return list.appendUnique(newitem); }
80:
81: // debugging: two additional invariants
82: void selfCheck() const { list.selfCheck(); }
83: };
84:
85:
86: template <class T>
87: void ASTList<T>::deleteAll()
88: {
89: while (!list.isEmpty()) {
90: deleteFirst();
91: }
92: }
93:
94:
95: template <class T>
96: class ASTListIter {
97: protected:
98: VoidTailListIter iter; // underlying iterator
99:
100: public:
101: ASTListIter(ASTList<T> const &list) : iter(list.list) {}
102: ~ASTListIter() {}
103:
104: void reset(ASTList<T> const &list) { iter.reset(list.list); }
105:
106: // iterator copying; generally safe
107: ASTListIter(ASTListIter const &obj) : iter(obj.iter) {}
108: ASTListIter& operator=(ASTListIter const &obj) { iter = obj.iter; return *this; }
109:
110: // iterator actions
111: bool isDone() const { return iter.isDone(); }
112: void adv() { iter.adv(); }
113: T const *data() const { return (T const*)iter.data(); }
114: };
115:
116: #define FOREACH_ASTLIST(T, list, iter) \
117: for(ASTListIter<T> iter(list); !iter.isDone(); iter.adv())
118:
119:
120: // version of the above, but for non-const-element traversal
121: template <class T>
122: class ASTListIterNC {
123: protected:
124: VoidTailListIter iter; // underlying iterator
125:
126: public:
127: ASTListIterNC(ASTList<T> &list) : iter(list.list) {}
128: ~ASTListIterNC() {}
129:
130: void reset(ASTList<T> &list) { iter.reset(list.list); }
131:
132: // iterator copying; generally safe
133: ASTListIterNC(ASTListIterNC const &obj) : iter(obj.iter) {}
134: ASTListIterNC& operator=(ASTListIterNC const &obj) { iter = obj.iter; return *this; }
135:
136: // iterator actions
137: bool isDone() const { return iter.isDone(); }
138: void adv() { iter.adv(); }
139: T *data() const { return (T*)iter.data(); }
140:
141: // iterator mutation; use with caution
142: void setDataLink(T *newData) { iter.setDataLink((void*)newData); }
143: };
144:
145: #define FOREACH_ASTLIST_NC(T, list, iter) \
146: for(ASTListIterNC<T> iter(list); !iter.isDone(); iter.adv())
147:
148:
149: // this function is somewhat at odds with the nominal purpose
150: // of ASTLists, but I need it in a weird situation so ...
151: template <class T>
152: ASTList<T> *shallowCopy(ASTList<T> *src)
153: {
154: ASTList<T> *ret = new ASTList<T>;
155: FOREACH_ASTLIST_NC(T, *src, iter) {
156: ret->append(iter.data());
157: }
158: return ret;
159: }
160:
161:
162: #endif // ASTLIST_H
Start C section to elk/sm_autofile.h[1
/1
]
1: #line 941 "./lpsrc/sm.pak"
2: // autofile.h see license.txt for copyright and terms of use
3: // little wrapper around FILE*
4:
5: #ifndef SMUTIL_H
6: #define SMUTIL_H
7:
8: #include <stdio.h> // FILE
9:
10:
11: // fopen, but throw an XOpen exception (see exc.h) on failure instead
12: // of returning NULL
13: FILE *xfopen(char const *fname, char const *mode);
14:
15:
16: // automatically close a file in the destructor
17: class AutoFclose {
18: private: // data
19: FILE *fp;
20:
21: private: // disallowed
22: AutoFclose(AutoFclose&);
23: void operator=(AutoFclose&);
24:
25: public:
26: AutoFclose(FILE *f) : fp(f) {}
27: ~AutoFclose() { fclose(fp); }
28:
29: // may as well allow access to my storage
30: FILE *getFP() { return fp; }
31: };
32:
33:
34: // simple wrapper on FILE*
35: class AutoFILE : private AutoFclose {
36: public:
37: // open, throwing an XOpen exception on failure
38: AutoFILE(char const *fname, char const *mode);
39:
40: // close the file
41: ~AutoFILE();
42:
43: // behave like FILE* in between
44: operator FILE* () { return getFP(); }
45: };
46:
47:
48: #endif // SMUTIL_H
Start C section to elk/sm_bflatten.h[1
/1
]
1: #line 990 "./lpsrc/sm.pak"
2: // bflatten.h see license.txt for copyright and terms of use
3: // binary file flatten implementation
4:
5: #ifndef BFLATTEN_H
6: #define BFLATTEN_H
7:
8: #include "sm_flatten.h"
9: #include "sm_ohashtbl.h"
10: #include <stdio.h> // FILE
11:
12: class BFlatten : public Flatten {
13: private: // data
14: FILE *fp; // file being read/written
15: bool readMode; // true=read, false=write
16:
17: struct OwnerMapping {
18: void *ownerPtr; // a pointer
19: int intName; // a unique integer name
20: };
21: OwnerHashTable<OwnerMapping> ownerTable; // owner <-> int mapping
22: int nextUniqueName; // counter for making int names
23:
24: private: // funcs
25: static void const* getOwnerPtrKeyFn(OwnerMapping *data);
26: static void const* getIntNameKeyFn(OwnerMapping *data);
27:
28: public: // funcs
29: BFlatten(char const *fname, bool reading);
30: virtual ~BFlatten();
31:
32: // Flatten funcs
33: virtual bool reading() const { return readMode; }
34: virtual void xferSimple(void *var, unsigned len);
35: virtual void noteOwner(void *ownerPtr);
36: virtual void xferSerf(void *&serfPtr, bool nullable=false);
37: };
38:
39:
40: // for debugging, write and then read something
41: template <class T>
42: T *writeThenRead(T &obj)
43: {
44: char const *fname = "flattest.tmp";
45:
46: // write
47: {
48: BFlatten out(fname, false /*reading*/);
49: obj.xfer(out);
50: }
51:
52: // read
53: BFlatten in(fname, true /*reading*/);
54: T *ret = new T(in);
55: ret->xfer(in);
56:
57: remove(fname);
58:
59: return ret;
60: }
61:
62: #endif // BFLATTEN_H
Start C section to elk/sm_bit2d.h[1
/1
]
1: #line 1053 "./lpsrc/sm.pak"
2: // bit2d.h see license.txt for copyright and terms of use
3: // 2-d array of bits
4:
5: #ifndef __BIT2D_H
6: #define __BIT2D_H
7:
8: #include "sm_typ.h"
9: #include "sm_point.h"
10:
11: class Flatten;
12:
13: class Bit2d {
14: private: // data
15: byte *data; // bits; [0..stride-1] is first row, etc.
16: bool owning; // when false, 'data' is not owned by this object
17: point size; // size.x is # of cols, size.y is # of rows
18: int stride; // bytes between starts of adjacent rows;
19: // computable from size.x but stored for quick access
20:
21: private: // funcs
22: byte *byteptr(point const &p) { return data + p.y * stride + (p.x>>3); }
23: byte const *byteptrc(point const &p) const { return data + p.y * stride + (p.x>>3); }
24:
25: // this is the number of bytes allocated in 'data'
26: int datasize() const { return size.y * stride; }
27:
28: public: // funcs
29: // NOTE: does *not* clear the bitmap! use 'setall' to do that
30: Bit2d(point const &aSize);
31: Bit2d(Bit2d const &obj);
32:
33: Bit2d& operator= (Bit2d const &obj); // sizes must be equal already
34: ~Bit2d();
35:
36: Bit2d(Flatten&);
37: void xfer(Flatten &flat);
38:
39: bool okpt(point const &p) const { return p.gtez() && p < size; }
40: point const &Size() const { return size; }
41:
42: bool operator== (Bit2d const &obj) const; // compare sizes and data
43:
44: // bit access (these were inline earlier, but they expand to a huge amount
45: // of code (more than 100 bytes), so I've un-inlined them)
46: int get(point const &p) const;
47: void set(point const &p); // to 1
48: void reset(point const &p); // to 0
49: void setto(point const &p, int val);
50: void toggle(point const &p);
51:
52: // set the bit, but return what it was previously
53: int testAndSet(point const &p);
54:
55: // set everything
56: void setall(int val);
57:
58: // debugging
59: void print() const;
60:
61: // bit of a hack: I want to be able to save the data as code which,
62: // when compiled, will build a bit2d from static data.. for this
63: // I need access to some private fields and a special ctor
64: Bit2d(byte * /*serf*/ data, point const &size, int stride);
65: byte *private_data() { return data; }
66: int private_datasize() const { return datasize(); }
67: int private_stride() const { return stride; }
68: };
69:
70: #endif // __BIT2D_H
71:
Start C section to elk/sm_bitarray.h[1
/1
]
1: #line 1125 "./lpsrc/sm.pak"
2: // bitarray.h see license.txt for copyright and terms of use
3: // one-dimensional array of bits
4:
5: #ifndef BITARRAY_H
6: #define BITARRAY_H
7:
8: #include "sm_xassert.h"
9:
10: class Flatten; // flatten.h
11:
12: class BitArray {
13: private: // data
14: unsigned char *bits;
15: int numBits; // # of bits in the array
16:
17: private: // disallowed for now
18: BitArray(BitArray&);
19: void operator=(BitArray&);
20:
21: private: // funcs
22: void bc(int i) const { xassert((unsigned)i < (unsigned)numBits); }
23: int allocdBytes() const { return (numBits+7) / 8; }
24:
25: public: // funcs
26: BitArray(int n); // create with given # of bits, initially zeroed
27: ~BitArray();
28:
29: BitArray(Flatten&);
30: void xfer(Flatten &flat);
31:
32: // test a bit, return 0 or 1
33: int test(int i) const
34: { bc(i); return ((bits[i >> 3]) >> (i & 7)) & 1; }
35:
36: // set a bit to a specific value
37: void set(int i)
38: { bc(i); bits[i >> 3] |= (1 << (i & 7)); }
39: void reset(int i)
40: { bc(i); bits[i >> 3] &= ~(1 << (i & 7)); }
41:
42: // set a bit to an arbitrary value
43: void setTo(int i, int val) {
44: if (val) {
45: set(i);
46: }
47: else {
48: reset(i);
49: }
50: }
51:
52: // clear all bits
53: void clearAll();
54: };
55:
56:
57: #endif // BITARRAY_H
Start C section to elk/sm_boxprint.h[1
/1
]
1: #line 1183 "./lpsrc/sm.pak"
2: // boxprint.h
3: // another pretty-printing module, this one based on the box model
4: // described at http://caml.inria.fr/FAQ/format-eng.html
5:
6: #ifndef BOXPRINT_H
7: #define BOXPRINT_H
8:
9: #include "sm_str.h"
10: #include "sm_astlist.h"
11: #include "sm_array.h"
12:
13:
14: // fwd
15: class BoxPrint;
16:
17:
18: // manages the process of rendering a boxprint tree to a sm_string
19: class BPRender {
20: public:
21: // output sm_string
22: sm_stringBuilder sb;
23:
24: // right margin column; defaults to 72
25: int margin;
26:
27: // column for next output; equal to the number of characters
28: // after the last newline in 'sb'
29: int curCol;
30:
31: // text to begin every line with; not counted towards column
32: // counts; defaults to ""
33: sm_string lineStartText;
34:
35: public:
36: BPRender();
37: ~BPRender();
38:
39: // chars in the current line
40: int getCurCol() const { return curCol; }
41:
42: // chars remaining on current line before the margin; might
43: // be negative if the input didn't have enough breaks
44: int remainder() const { return margin - getCurCol(); }
45:
46: // add some text (that doesn't include newlines) to the output
47: void add(char const *text);
48:
49: // add a newline, plus indentation to get to column 'ind'
50: void breakLine(int ind);
51:
52: // take the sm_string out of the rendering engine, replacing it
53: // with the empty sm_string
54: sm_string takeString() {
55: sm_string ret(sb);
56: reset();
57: return ret;
58: }
59:
60: // just clear the buffer to its original state; must do this
61: // manually after changing 'lineStartText'
62: void reset();
63:
64: // take the tree out of a boxprint builder, convert it to a sm_string,
65: // and delete the tree
66: sm_string takeAndRender(BoxPrint &bld);
67: };
68:
69:
70: // interface for elements in a boxprint tree
71: class BPElement {
72: public:
73: // if no breaks are taken, compute the # of columns
74: virtual int oneLineWidth()=0;
75:
76: // render this element as a sm_string with newlines, etc.
77: virtual void render(BPRender &mgr)=0;
78:
79: // true if this element is a BPBreak and is enabled; returns false
80: // by default
81: virtual bool isBreak() const;
82:
83: // print the boxprint tree; for debugging code that produces them;
84: // these methods do not emit leading or trailing whitespace
85: virtual void debugPrint(std::ostream &os, int ind) const =0;
86:
87: // deallocate the element
88: virtual ~BPElement();
89: };
90:
91:
92: // leaf in the tree: text to print
93: class BPText : public BPElement {
94: public:
95: sm_string text;
96:
97: public:
98: BPText(char const *t);
99: ~BPText();
100:
101: // BPElement funcs
102: virtual int oneLineWidth();
103: virtual void render(BPRender &mgr);
104: virtual void debugPrint(std::ostream &os, int ind) const;
105: };
106:
107:
108: // leaf in the tree: a "break", which might end up being a
109: // space or a newline+indentation
110: class BPBreak : public BPElement {
111: public:
112: // When true, this is a conditional break, and whether it is taken
113: // or not depends on the prevailing break strategy of the box in
114: // which it is located. When false, the break is never taken, so
115: // this is effectively just a space.
116: bool enabled;
117:
118: // Nominally, when a break is taken, the indentation used is such
119: // that the next char in the box is directly below the first char
120: // in the box. When this break is passed, however, it can add to
121: // that nominal indent of 0; these adjustments accumulate as the
122: // box is rendered.
123: int indent;
124:
125: public:
126: BPBreak(bool e, int i);
127: ~BPBreak();
128:
129: // BPElement funcs
130: virtual int oneLineWidth();
131: virtual void render(BPRender &mgr);
132: virtual bool isBreak() const;
133: virtual void debugPrint(std::ostream &os, int ind) const;
134: };
135:
136:
137: // kinds of boxes
138: enum BPKind {
139: // enabled breaks are always taken
140: BP_vertical,
141:
142: // enabled breaks are individually taken or not taken depending
143: // on how much room is available; "hov"
144: BP_sequence,
145:
146: // either all enabled breaks are taken, or none are taken; "h/v"
147: BP_correlated,
148:
149: // # of kinds, also used to signal the end of a box in some cases
150: NUM_BPKINDS
151: };
152:
153: // internal node in the tree: a list of subtrees, some of which
154: // may be breaks
155: class BPBox : public BPElement {
156: public:
157: // subtrees
158: ASTList<BPElement> elts;
159:
160: // break strategy for this box
161: BPKind kind;
162:
163: public:
164: BPBox(BPKind k);
165: ~BPBox();
166:
167: // BPElement funcs
168: virtual int oneLineWidth();
169: virtual void render(BPRender &mgr);
170: virtual void debugPrint(std::ostream &os, int ind) const;
171: };
172:
173:
174: // assists in the process of building a box tree by providing
175: // a number of syntactic shortcuts
176: class BoxPrint {
177: public: // types
178: // additional command besides BPKind
179: enum Cmd {
180: sp, // insert disabled break
181: br, // insert enabled break
182: ind, // ibr(levelIndent)
183: und, // ibr(-levelIndent) ("unindent")
184: };
185:
186: // insert enabled break with indentation
187: struct IBreak {
188: int indent;
189: IBreak(int i) : indent(i) {}
190: // use default copy ctor
191: };
192:
193: // operator sequence
194: struct Op {
195: char const *text;
196: Op(char const *t) : text(t) {}
197: // default copy ctor
198: };
199:
200: private: // data
201: // stack of open boxes; always one open vert box at the top
202: ObjArrayStack<BPBox> boxStack;
203:
204: public: // data
205: // convenient names for the box kinds
206: static BPKind const vert; // = BP_vertical
207: static BPKind const seq; // = BP_sequence
208: static BPKind const hv; // = BP_correlated ("h/v")
209: static BPKind const end; // = NUM_BPKINDS
210:
211: // indentation amount for the ind/und commands; defaults to 2
212: int levelIndent;
213:
214: private: // funcs
215: // innermost box being built
216: BPBox *box() { return boxStack.top(); }
217:
218: public: // funcs
219: BoxPrint();
220: ~BoxPrint();
221:
222: // append another element to the current innermost box
223: void append(BPElement *elt);
224:
225: // add BPText nodes to current box
226: BoxPrint& operator<< (int i);
227: BoxPrint& operator<< (char const *s);
228:
229: // open/close boxes
230: BoxPrint& operator<< (BPKind k);
231:
232: // insert breaks
233: BoxPrint& operator<< (Cmd c);
234:
235: // insert break with indentation
236: static IBreak ibr(int i) { return IBreak(i); }
237: BoxPrint& operator<< (IBreak b);
238:
239: // op(text) is equivalent to sp << text << br
240: static Op op(char const *text) { return Op(text); }
241: BoxPrint &operator << (Op o);
242:
243: // take the accumulated box tree out; all opened boxes must have
244: // been closed; the builder is left in a state where it can be used
245: // to build a new tree if desired, or it can be simply destroyed
246: BPBox* /*owner*/ takeTree();
247:
248: // print the current stack of trees
249: void debugPrint(std::ostream &os) const;
250: void debugPrintCout() const; // for gdb
251: };
252:
253:
254: #endif // BOXPRINT_H
Start C section to elk/sm_breaker.h[1
/1
]
1: #line 1438 "./lpsrc/sm.pak"
2: // breaker.h see license.txt for copyright and terms of use
3: // function stub through which critical event code flow is directed
4: // for easy breakpoints
5: // Scott McPeak, 1997,1998 This file is public domain.
6:
7: #ifndef __BREAKER_H
8: #define __BREAKER_H
9:
10: void breaker();
11:
12: // bassert = breaker assert; failure simply calls breaker, which is
13: // a breakpoint in the debugger and is ignored when not in debugger;
14: // useful mainly for places I want to ensure something is true during
15: // initial testing, but after that it's ok if it's false
16: template <class T> // allow possibly null pointers, etc
17: inline void bassert(T cond)
18: {
19: if (!cond) {
20: breaker();
21: }
22: }
23:
24:
25: // this will call breaker on the first pass, but not any subsequent (unless
26: // it's called MAXINT*2 times...)
27: #define BREAK_FIRST_PASS \
28: { \
29: static int passCount=0; \
30: bassert(passCount++); \
31: } /*no semicolon*/
32:
33:
34: // this is obsolete...
35: void _breaker_assert(char * __cond, char * __file, int __line);
36: // this will be called on failed assertions instead of _assert
37: // only if BREAKER_ASSERT is defined (due to a modification to
38: // assert.h directly)
39:
40: #endif // __BREAKER_H
41:
Start C section to elk/sm_ckheap.h[1
/1
]
1: #line 1480 "./lpsrc/sm.pak"
2: // ckheap.h see license.txt for copyright and terms of use
3: // interface to check heap integrity, etc.
4:
5: #ifndef CKHEAP_H
6: #define CKHEAP_H
7:
8: #ifdef __cplusplus
9: extern "C" {
10: #endif
11:
12:
13: // check heap integrity, and fail an assertion if it's bad
14: void checkHeap();
15:
16: // check that a given pointer is a valid allocated object;
17: // fail assertion if not
18: void checkHeapNode(void *node);
19:
20: // prints allocation statistics to stderr
21: void malloc_stats();
22:
23: // count # of malloc/free calls in program
24: unsigned numMallocCalls();
25: unsigned numFreeCalls();
26:
27:
28: // actions the heap walk iterator might request
29: enum HeapWalkOpts {
30: HW_GO = 0, // keep going
31: HW_STOP = 1, // stop iterating
32: HW_FREE = 2, // free the block I just examined
33: };
34:
35: // function for walking the heap
36: // block: pointer to the malloc'd block of memory
37: // size: # of bytes in the block; possibly larger than
38: // what was requested
39: // returns: bitwise OR of HeapWalkOpts options
40: // NOTE: you cannot call malloc or free inside this function
41: // (you can cause 'block' to be freed by returning HW_FREE)
42: typedef enum HeapWalkOpts (*HeapWalkFn)(void *block, int size);
43:
44: // heap walk entry
45: void walkMallocHeap(HeapWalkFn func);
46:
47:
48: #ifdef __cplusplus
49: } // extern "C"
50: #endif
51:
52: #endif // CKHEAP_H
Start C section to elk/sm_crc.h[1
/1
]
1: #line 1533 "./lpsrc/sm.pak"
2: // crc.h see license.txt for copyright and terms of use
3: // simple crc function
4:
5: #ifndef __CRC_H
6: #define __CRC_H
7:
8: unsigned long crc32(unsigned char const *data, int length);
9:
10: #endif // __CRC_H
11:
Start C section to elk/sm_datablok.h[1
/1
]
1: #line 1545 "./lpsrc/sm.pak"
2: // datablok.h see license.txt for copyright and terms of use
3: // arbitrary block of data
4: // Scott McPeak, 1998-2000 This file is public domain.
5:
6: #ifndef __DATABLOK_H
7: #define __DATABLOK_H
8:
9: #include "sm_typ.h"
10:
11: class DataBlock {
12: private: // data
13: byte *data; // data itself (may be NULL)
14: int dataLen; // length of data, starting at data[0]
15: int allocated; // amount of memory allocated at 'data'
16:
17: // invariants: 0 <= dataLen <= allocated
18: // (data==NULL) == (allocated==0)
19:
20: // endpost: 'data' will be kept allocated with one extra byte at the
21: // end, where an endpost byte is written. thus, we have another
22: // invariant:
23: // (data!=NULL) implies data[allocated] == endpost
24: static byte const endpost;
25:
26: private: // funcs
27: void init(int allocatedSize);
28: // base ctor
29:
30: static byte *allocate(int size);
31: // allocate a block of memory, writing endpost
32:
33: void copyCtorShared(DataBlock const &obj);
34: // shared by both copy constructors (actually, only one is the true
35: // copy ctor...)
36:
37: void ctor(byte const *srcData, int dataLen);
38: void ctor(byte const *srcData, int dataLen, int allocatedSize);
39: // shared ctor calls as a workaround for char casting problems
40:
41: void selfCheck() const;
42: // confirm that invariants are true
43:
44: public: // funcs
45: // constructors
46: DataBlock(int allocatedSize = 0);
47: // make an empty datablock holder; when allocatedSize is 0, 'data'
48: // is initially set to NULL
49:
50: EXPLICIT DataBlock(char const *srcString);
51: // make a copy of 'srcString' data, which is null-terminated
52:
53: DataBlock(byte const *srcData, int dataLen) { ctor(srcData, dataLen); }
54: DataBlock(char const *srcData, int dataLen) { ctor((byte const*)srcData, dataLen); }
55: // make a copy of 'srcData', which is 'dataLen' bytes long
56:
57: DataBlock(byte const *srcData, int dataLen, int allocatedSize)
58: { ctor(srcData, dataLen, allocatedSize); }
59: DataBlock(char const *srcData, int dataLen, int allocatedSize)
60: { ctor((byte const*)srcData, dataLen, allocatedSize); }
61: // make a copy of 'srcData', which is 'dataLen' bytes long, in a buffer
62: // that is 'allocatedSize' bytes long
63:
64: DataBlock(DataBlock const &obj);
65: // copy data, allocate same amount as 'obj'
66:
67: DataBlock(DataBlock const &obj, int minToAllocate);
68: // copy obj's contents; allocate either obj.getAllocated() or
69: // minToAllocate, whichever is larger (this turns out to be a
70: // common idiom)
71:
72: ~DataBlock();
73:
74: // selectors
75: byte const *getDataC() const { return data; }
76: int getDataLen() const { return dataLen; }
77: int getAllocated() const { return allocated; }
78:
79: bool dataEqual(DataBlock const &obj) const;
80: // compares data length and data-length bytes of data
81:
82: bool allEqual(DataBlock const &obj) const;
83: // compares data, length, and allocation length
84:
85: bool operator== (DataBlock const &obj) const
86: { return dataEqual(obj); }
87: bool operator!= (DataBlock const &obj) const
88: { return !operator==(obj); }
89: // SM, 1/24/99: with the coding of blokutil, I've finally clarified that
90: // allocation length is a concern of efficiency, not correctness, and so
91: // have changed the meaning of == to just look at data. The old behavior
92: // is available as 'allEqual()'.
93:
94: // mutators
95: byte *getData() { return data; }
96: void setDataLen(int newLen);
97: // asserts that 0 <= newLen <= allocated
98: void setAllocated(int newAllocated); // i.e. realloc
99: void addNull();
100: // add a null ('\0') to the end; there must be sufficient allocated space
101:
102: void changeDataLen(int changeAmount)
103: { setDataLen(getDataLen() + changeAmount); }
104:
105: void ensureAtLeast(int minAllocated);
106: // if 'allocated' is currently less than minAllocated, then
107: // set 'allocated' to minAllocated (preserving existing contents)
108:
109: void growDataLen(int changeAmount);
110: // grows allocated data if necessary, whereas changeDataLen will throw
111: // an exception if there isn't already enough allocated space
112:
113: void setFromString(char const *srcString);
114: void setFromBlock(byte const *srcData, int dataLen);
115: void setFromBlock(char const *srcData, int dataLen)
116: { setFromBlock((byte const*)srcData, dataLen); }
117:
118: DataBlock& operator= (DataBlock const &obj);
119: // causes data AND allocation length equality
120:
121: // convenient file read/write
122: void writeToFile(char const *fname) const;
123: void readFromFile(char const *fname);
124:
125: // for debugging
126: enum { DEFAULT_PRINT_BYTES = 16 };
127: void print(char const *label = NULL,
128: int bytesPerLine = DEFAULT_PRINT_BYTES) const;
129: // write a simple representation to stdout
130: // if label is not NULL, the data is surrounded by '---'-style delimiters
131:
132: void dontPrint(char const *label = NULL,
133: int bytesPerLine = DEFAULT_PRINT_BYTES) const;
134: // does nothing; useful for two reasons:
135: // 1. lets me define macros that expand to 'print' during debug
136: // and dontPrint during non-debug
137: // 2. plays a vital role in a g++ bug workaround (g++ sucks!!)
138:
139: // utility, defined here for no good reason
140: static void printHexLine(byte const *data, int length, int lineLength);
141: // print 'length' bytes of 'data' in hex
142: // blank-pad the output as if 'linelen' bytes were present
143:
144: static void printPrintableLine(byte const *data, int length,
145: char unprintable = '.');
146: // print 'length' bytes of 'data', substituting 'unprintable' for bytes for
147: // which 'isprint' is false
148: };
149:
150: #endif // __DATABLOK_H
151:
Start C section to elk/sm_exc.h[1
/1
]
1: #line 1697 "./lpsrc/sm.pak"
2: // exc.h see license.txt for copyright and terms of use
3: // exception classes for SafeTP project
4: // Scott McPeak, 1996-1998 This file is public domain.
5:
6: #ifndef __EXC_H
7: #define __EXC_H
8:
9: #include "sm_breaker.h"
10: #include "sm_typ.h"
11: #include "sm_xassert.h"
12: #include "sm_str.h"
13: #include <iostream> // std::ostream
14:
15: // forward declarations
16: class ELK_EXTERN sm_stringBuilder;
17:
18:
19: // by using this macro, the debugger gets a shot before the stack is unwound
20: #ifdef THROW
21: #undef THROW
22: #endif
23: #define THROW(obj) \
24: { breaker(); throw (obj); }
25:
26:
27: // this function returns true if we're in the process of unwinding the
28: // stack, and therefore destructors may want to avoid throwing new exceptions;
29: // for now, may return false positives, but won't return false negatives
30: bool unwinding();
31:
32: // inside a catch expression, the unwinding() function needs a tweak; pass
33: // the caught expression, and this returns whether there any *additional*
34: // exceptions currently in flight
35: class xBase;
36: bool unwinding_other(xBase const &x);
37:
38: // using unwinding() in destructors to avoid abort()
39: #define CAUTIOUS_RELAY \
40: catch (xBase &x) { \
41: if (!unwinding_other(x)) { \
42: throw; /* re-throw */ \
43: } \
44: }
45:
46:
47: // -------------------- xBase ------------------
48: // intent is to derive all exception objects from this
49: class xBase {
50: sm_string msg;
51: // the human-readable description of the exception
52:
53: public:
54: static bool logExceptions;
55: // initially true; when true, we write a record of the thrown exception
56: // to clog
57:
58: static int creationCount;
59: // current # of xBases running about; used to support unrolling()
60:
61: public:
62: xBase(char const *m); // create exception object with message 'm'
63: xBase(xBase const &m); // copy ctor
64: virtual ~xBase();
65:
66: char const *why() const
67: { return (char const*)msg; }
68:
69: void insert(std::ostream &os) const;
70: friend std::ostream& operator << (std::ostream &os, xBase const &obj)
71: { obj.insert(os); return os; }
72: // print why
73: };
74:
75: // equivalent to THROW(xBase(msg))
76: void xbase(char const *msg) NORETURN;
77:
78:
79: // -------------------- x_assert -----------------------
80: // thrown by _xassert_fail, declared in xassert.h
81: // throwing this corresponds to detecting a bug in the program
82: class x_assert : public xBase {
83: sm_string condition; // text of the failed condition
84: sm_string filename; // name of the source file
85: int lineno; // line number
86:
87: public:
88: x_assert(char const *cond, char const *fname, int line);
89: x_assert(x_assert const &obj);
90: ~x_assert();
91:
92: char const *cond() const { return (char const *)condition; }
93: char const *fname() const { return (char const *)filename; }
94: int line() const { return lineno; }
95: };
96:
97:
98: // ---------------------- xFormat -------------------
99: // throwing this means a formatting error has been detected
100: // in some input data; the program cannot process it, but it
101: // is not a bug in the program
102: class xFormat : public xBase {
103: sm_string condition; // what is wrong with the input
104:
105: public:
106: xFormat(char const *cond);
107: xFormat(xFormat const &obj);
108: ~xFormat();
109:
110: char const *cond() const { return (char const*)condition; }
111: };
112:
113: // compact way to throw an xFormat
114: void xformat(char const *condition) NORETURN;
115:
116: // convenient combination of condition and human-readable message
117: #define checkFormat(cond, message) \
118: ((cond)? (void)0 : xformat(message))
119:
120: // assert-like interface to xFormat
121: void formatAssert_fail(char const *cond, char const *file, int line) NORETURN;
122:
123: #define formatAssert(cond) \
124: ((cond)? (void)0 : formatAssert_fail(#cond, __FILE__, __LINE__))
125:
126:
127: // -------------------- XOpen ---------------------
128: // thrown when we fail to open a file
129: class XOpen : public xBase {
130: public:
131: sm_string filename;
132:
133: public:
134: XOpen(char const *fname);
135: XOpen(XOpen const &obj);
136: ~XOpen();
137: };
138:
139: void throw_XOpen(char const *fname) NORETURN;
140:
141:
142: #endif // __EXC_H
143:
Start C section to elk/sm_flatten.h[1
/1
]
1: #line 1841 "./lpsrc/sm.pak"
2: // flatten.h see license.txt for copyright and terms of use
3: // interface to automate process of flattening structures made of objects with
4: // arbitrary types, and possibly circular references
5: // this is a trimmed-down version of the one in 'proot'
6:
7: #ifndef FLATTEN_H
8: #define FLATTEN_H
9:
10: #include "sm_trdelete.h"
11:
12: class Flatten {
13: public:
14: Flatten();
15: virtual ~Flatten();
16:
17: TRASHINGDELETE;
18:
19: // query the read/write state
20: virtual bool reading() const = 0;
21: bool writing() const { return !reading(); }
22:
23: // transferring xfer a simple data type of fixed length
24: // 'len', in bytes
25: virtual void xferSimple(void *var, unsigned len)=0;
26:
27: // syntactic sugar
28: //#define xferVar(varname) xferSimple(&varname, sizeof(varname))
29: //#define XFERV(varname) flat.xferVar(varname)
30:
31: // xfer various C built-in data types (will add them as I need them)
32: virtual void xferChar(char &c);
33: virtual void xferInt(int &i);
34: virtual void xferLong(long &l);
35: virtual void xferBool(bool &b);
36:
37: // read or write a null-terminated character buffer, allocated with new;
38: // this works if 'str' is NULL
39: virtual void xferCharString(char *&str);
40:
41: // xfer a buffer allocated with 'new', of a given length
42: virtual void xferHeapBuffer(void *&buf, int len);
43:
44: // read: write the code; write: read & compare to code, fail if != ;
45: // the code is arbitrary, but should be unique across the source tree
46: // (I usually make the code with my Emacs' Ctl-Alt-R, which inserts a random number)
47: virtual void checkpoint(int code);
48:
49: // ------------- utilities ---------
50: // for when we already know whether we're reading or writing; internally,
51: // these assert which state we're in
52: void writeInt(int i);
53: int readInt();
54:
55: // ------------- owner/serf ------------
56: // take note of an owner pointer where we expect to xfer serfs to it
57: virtual void noteOwner(void *ownerPtr) = 0;
58:
59: // xfer a serf pointer that we've previously taken note of
60: virtual void xferSerf(void *&serfPtr, bool nullable=false) = 0;
61: void writeSerf(void *serfPtr);
62: void *readSerf();
63: };
64:
65: #endif // FLATTEN_H
Start C section to elk/sm_gprintf.h[1
/1
]
1: #line 1907 "./lpsrc/sm.pak"
2: /* gprintf.h
3: * generalized printf interface
4: * http://www.efgh.com/software/gprintf.htm
5: * this file is in the public domain */
6:
7: #ifndef GPRINTF_H
8: #define GPRINTF_H
9:
10: #include <stdarg.h> /* va_list */
11:
12: #ifdef __cplusplus
13: extern "C" {
14: #endif
15:
16: /* This is called once for each output character. It returns >=0 for
17: * success or <0 for failure, in which case that code will end up as
18: * the return value from general_printf. 'extra' is user-defined
19: * context, and is passed the same value as the 'extra' arg to
20: * general_printf. 'ch' is of course the character to output. */
21: typedef int (*Gprintf_output_function)(void *extra, int ch);
22:
23: /* Interpret 'format' and 'args' as printf does, but calling
24: * 'output' for each rendered character. Returns the # of characters
25: * output (not including final NUL), or <0 for failure (same code
26: * that 'output' returns if it fails). */
27: int general_vprintf(Gprintf_output_function output,
28: void *extra, const char *format, va_list args);
29:
30: /* same thing but accepting variable # of args directly */
31: int general_printf(Gprintf_output_function output,
32: void *extra, const char *format, ...);
33:
34: #ifdef __cplusplus
35: }
36: #endif
37:
38: #endif /* GPRINTF_H */
Start C section to elk/sm_growbuf.h[1
/1
]
1: #line 1946 "./lpsrc/sm.pak"
2: // growbuf.h see license.txt for copyright and terms of use
3: // buffer that grows as needed by doubling in size
4:
5: #ifndef __GROWBUF_H
6: #define __GROWBUF_H
7:
8: #include "sm_datablok.h"
9:
10: class GrowBuffer : public DataBlock {
11: public:
12: GrowBuffer(int allocSize=0)
13: : DataBlock(allocSize) {}
14: ~GrowBuffer() {}
15:
16: // append to the end, at least doubling allocated
17: // size if growth is needed
18: void append(byte const *str, int len);
19: void append(char const *str, int len)
20: { append((byte const*)str, len); }
21: };
22:
23: #endif // __GROWBUF_H
Start C section to elk/sm_hashline.h[1
/1
]
1: #line 1970 "./lpsrc/sm.pak"
2: // hashline.h
3: // module for maintaining and using #line info in source files
4:
5: // terminology:
6: // pp source: preprocessed source, i.e. whatever had the #line
7: // info sprinkled throughout it
8: // orig source: original source, the files to which the #line
9: // directives refer
10:
11: #ifndef HASHLINE_H
12: #define HASHLINE_H
13:
14: #include "sm_strobjdict.h"
15: #include "sm_array.h"
16:
17: // map from lines in some given pp source file to lines in
18: // orig source files; there should be one HashLineMap object
19: // for each pp source file of interest
20: class HashLineMap {
21: private: // types
22: // records a single #line directive
23: class HashLine {
24: public:
25: int ppLine; // pp source line where it appears
26: int origLine; // orig line it names
27: char const *origFname; // orig fname it names
28:
29: public:
30: HashLine()
31: : ppLine(0), origLine(0), origFname(NULL) {}
32: HashLine(int pl, int ol, char const *of)
33: : ppLine(pl), origLine(ol), origFname(of) {}
34: HashLine(HashLine const &obj)
35: : DMEMB(ppLine), DMEMB(origLine), DMEMB(origFname) {}
36: };
37:
38: private: // data
39: // name of the pp file; this is needed for queries to lines
40: // before any #line is encountered
41: sm_string ppFname;
42:
43: // map for canonical storage of orig filenames; I don't rely on
44: // an external sm_string table because I don't want the extra
45: // dependency
46: StringObjDict<sm_string> filenames;
47:
48: // growable array of HashLine objects
49: ArrayStack<HashLine> directives;
50:
51: // previously-added ppLine; used to verify the entries are
52: // being added in sorted order
53: int prev_ppLine;
54:
55: public: // funcs
56: HashLineMap(char const *ppFname);
57: ~HashLineMap();
58:
59: // call this time each time a #line directive is encountered;
60: // successive calls must have strictly increasing values of 'ppLine'
61: void addHashLine(int ppLine, int origLine, char const *origFname);
62:
63: // call this when all the #line directives have been added; this
64: // consolidates the 'directives' array to reclaim any space created
65: // during the growing process but that is now not needed
66: void doneAdding();
67:
68: // map from pp line to orig line/file; note that queries exactly on
69: // #line lines have undefined results
70: void map(int ppLine, int &origLine, char const *&origFname) const;
71: int mapLine(int ppLine) const; // returns 'origLine'
72: char const *mapFile(int ppLine) const; // returns 'origFname'
73:
74: // for curiosity, find out how many unique filenames are recorded in
75: // the 'filenames' dictionary
76: int numUniqueFilenames() { return filenames.size(); }
77: };
78:
79: #endif // HASHLINE_H
Start C section to elk/sm_hashtbl.h[1
/1
]
1: #line 2050 "./lpsrc/sm.pak"
2: // hashtbl.h see license.txt for copyright and terms of use
3: // hash table mapping arbitrary keys to void*, where
4: // the stored pointers can be used to derive the key,
5: // and cannot be NULL
6:
7: #ifndef HASHTBL_H
8: #define HASHTBL_H
9:
10: #include "sm_typ.h"
11:
12: class HashTable {
13: private: // types
14: friend class HashTableIter;
15:
16: public: // types
17: // given a stored data pointer, retrieve the associated key
18: typedef void const* (*GetKeyFn)(void *data);
19:
20: // given a key, retrieve the associated hash value;
21: // this should be a 32-bit integer ready to be mod'd by the table size
22: typedef unsigned (*HashFn)(void const *key);
23:
24: // compare two keys; this is needed so we can handle collisions
25: // in the hash function; return true if they are equal
26: typedef bool (*EqualKeyFn)(void const *key1, void const *key2);
27:
28: // constants
29: enum {
30: defaultSize = 33
31: };
32:
33: private: // data
34: // maps
35: GetKeyFn getKey;
36: HashFn coreHashFn;
37: EqualKeyFn equalKeys;
38:
39: // array of pointers to data, indexed by the hash value,
40: // with collisions resolved by moving to adjacent entries;
41: // some entries are NULL, meaning that hash value has no mapping
42: void **hashTable;
43:
44: // Why use linear hashing instead of double hashing? To support
45: // deletion. Since every probe sequence that goes through index k
46: // will have a tail of k+1,k+2,... (mod tableSize) I can easily find
47: // and re-insert all the elements whose position might have depended
48: // on the presence of a now-deleted element. Excessive clustering
49: // is (hopefully) avoided through load factor control.
50:
51: // number of slots in the hash table
52: int tableSize;
53:
54: // number of mapped (non-NULL) entries
55: int numEntries;
56:
57: // when false, we never make the table smaller (default: true)
58: bool enableShrink;
59:
60: private: // funcs
61: // disallowed
62: HashTable(HashTable&);
63: void operator=(HashTable&);
64: void operator==(HashTable&);
65:
66: // hash fn for the current table size; always in [0,tableSize-1]
67: unsigned hashFunction(void const *key) const;
68:
69: // given a collision at 'index', return the next index to try
70: int nextIndex(int index) const { return (index+1) % tableSize; }
71:
72: // resize the table, transferring all the entries to their
73: // new positions
74: void resizeTable(int newSize);
75:
76: // return the index of the entry corresponding to 'data' if it
77: // is mapped, or a pointer to the entry that should be filled
78: // with its mapping, if unmapped
79: int getEntry(void const *key) const;
80:
81: // make a new table with the given size
82: void makeTable(int size);
83:
84: // check a single entry for integrity
85: void checkEntry(int entry) const;
86:
87: public: // funcs
88: HashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
89: int initSize = HashTable::defaultSize);
90: ~HashTable();
91:
92: // return # of mapped entries
93: int getNumEntries() const { return numEntries; }
94:
95: // if this hash value has a mapping, return it; otherwise,
96: // return NULL
97: void *get(void const *key) const;
98:
99: // add a mapping from 'key' to 'value'; there must not already
100: // be a mapping for this key
101: void add(void const *key, void *value);
102:
103: // remove the mapping for 'key' -- it must exist
104: // returns the removed item
105: void *remove(void const *key);
106:
107: // remove all mappings
108: void empty(int initSize = HashTable::defaultSize);
109:
110: // set whether shrinkage is allowed; it's useful to be able to
111: // disable this to avoid any allocation in certain situations
112: void setEnableShrink(bool en) { enableShrink = en; }
113:
114: // allow external access to an accessor function
115: void const *callGetKeyFn(void *data) { return getKey(data); }
116:
117: // check the data structure's invariants, and throw an exception
118: // if there is a problem
119: void selfCheck() const;
120:
121: // ------ useful default functions -------
122: // returns its argument
123: static void const* identityKeyFn(void *data);
124:
125: // puts the argument through two cycles of a linear
126: // congruential pseudo-random number generator
127: static unsigned lcprngHashFn(void const *key);
128:
129: // does pointer equality comparison
130: static bool pointerEqualKeyFn(void const *key1, void const *key2);
131: };
132:
133: unsigned lcprngTwoSteps(unsigned v);
134:
135:
136: // iterate over all stored values in a HashTable
137: // NOTE: you can't change the table while an iter exists
138: class HashTableIter {
139: private: // data
140: HashTable &table; // table we're iterating over
141: int index; // current slot to return in adv(); -1 when done
142:
143: private: // funcs
144: void moveToSth();
145:
146: public: // funcs
147: HashTableIter(HashTable &table);
148:
149: bool isDone() const { return index == -1; }
150: void adv();
151: void *data() const; // returns a value stored in the table
152: };
153:
154:
155: #endif // HASHTBL_H
Start C section to elk/sm_macros.h[1
/1
]
1: #line 2206 "./lpsrc/sm.pak"
2: // macros.h see license.txt for copyright and terms of use
3: // grab-bag of useful macros, stashed here to avoid mucking up
4: // other modules with more focus; there's no clear rhyme or
5: // reason for why some stuff is here and some in typ.h
6: // (no configuration stuff here!)
7:
8: #ifndef __MACROS_H
9: #define __MACROS_H
10:
11: #include "sm_typ.h"
12:
13: // complement of ==
14: #define NOTEQUAL_OPERATOR(T) \
15: bool operator != (T const &obj) const \
16: { return !operator==(obj); }
17:
18: // toss this into a class that already has == and < defined, to
19: // round out the set of relational operators (assumes a total
20: // order, i.e. a < b <=> b < a)
21: #define RELATIONAL_OPERATORS(T) \
22: NOTEQUAL_OPERATOR(T) \
23: bool operator <= (T const &obj) const \
24: { return !obj.operator<(*this); } \
25: bool operator > (T const &obj) const \
26: { return obj.operator<(*this); } \
27: bool operator >= (T const &obj) const \
28: { return !operator<(obj); }
29:
30:
31: // member copy in constructor initializer list
32: #define DMEMB(var) var(obj.var)
33:
34: // member copy in operator =
35: #define CMEMB(var) var = obj.var
36:
37: // member comparison in operator ==
38: #define EMEMB(var) var == obj.var
39:
40:
41: // standard insert operator
42: // (note that you can put 'virtual' in front of the macro call if desired)
43: #define INSERT_OSTREAM(T) \
44: void insertOstream(std::ostream &os) const; \
45: friend std::ostream& operator<< (std::ostream &os, T const &obj) \
46: { obj.insertOstream(os); return os; }
47:
48:
49: // usual declarations for a data object (as opposed to control object)
50: #define DATA_OBJ_DECL(T) \
51: T(); \
52: T(T const &obj); \
53: ~T(); \
54: T& operator= (T const &obj); \
55: bool operator== (T const &obj) const; \
56: NOTEQUAL_OPERATOR(T) \
57: INSERTOSTREAM(T)
58:
59:
60: // copy this to the .cc file for implementation of DATA_OBJ_DECL
61: #if 0
62: T::T()
63: {}
64:
65: T::T(T const &obj)
66: : DMEMB(),
67: DMEMB(),
68: DMEMB()
69: {}
70:
71: T::~T()
72: {}
73:
74: T& T::operator= (T const &obj)
75: {
76: if (this != &obj) {
77: CMEMB();
78: }
79: return *this;
80: }
81:
82: bool T::operator== (T const &obj) const
83: {
84: return
85: EMEMB() &&
86: EMEMB();
87: }
88:
89: void T::insertOstream(std::ostream &os) const
90: {}
91: #endif // 0
92:
93:
94: // assert something at compile time (must use this inside a function);
95: // works because compilers won't let us declare negative-length arrays
96: // (the expression below works with egcs-1.1.2, gcc-2.x, gcc-3.x)
97: #define STATIC_ASSERT(cond) \
98: { (void)((int (*)(char failed_static_assertion[(cond)?1:-1]))0); }
99:
100: // assert that a table is an expected size; the idea is to make sure
101: // that static data in some table gets updated when a corresponding
102: // symbolic constant is changed
103: #define ASSERT_TABLESIZE(table, size) \
104: STATIC_ASSERT(TABLESIZE(table) == (size))
105:
106:
107: // for silencing variable-not-used warnings
108: template <class T>
109: inline void pretendUsedFn(T const &) {}
110: #define PRETEND_USED(arg) pretendUsedFn(arg) /* user ; */
111:
112:
113: // appended to function declarations to indicate they do not
114: // return control to their caller; e.g.:
115: // void exit(int code) NORETURN;
116: #ifdef __GNUC__
117: #define NORETURN __attribute__((noreturn))
118: #else
119: // just let the warnings roll if we can't suppress them
120: #define NORETURN
121: #endif
122:
123:
124: // these two are a common idiom in my code for typesafe casts;
125: // they are essentially a roll-your-own RTTI
126: #define CAST_MEMBER_FN(destType) \
127: destType const &as##destType##C() const; \
128: destType &as##destType() { return const_cast<destType&>(as##destType##C()); }
129:
130: #define CAST_MEMBER_IMPL(inClass, destType) \
131: destType const &inClass::as##destType##C() const \
132: { \
133: xassert(is##destType()); \
134: return (destType const&)(*this); \
135: }
136:
137:
138: // same as the above, but returning pointers; I think returning
139: // references was a mistake
140: #define DOWNCAST_FN(destType) \
141: destType const *as##destType##C() const; \
142: destType *as##destType() { return const_cast<destType*>(as##destType##C()); }
143:
144: #define DOWNCAST_IMPL(inClass, destType) \
145: destType const *inClass::as##destType##C() const \
146: { \
147: xassert(is##destType()); \
148: return static_cast<destType const*>(this); \
149: }
150:
151:
152: // keep track of a count and a high water mark
153: #define INC_HIGH_WATER(count, highWater) \
154: count++; \
155: if (count > highWater) { \
156: highWater = count; \
157: }
158:
159:
160: // egcs has the annoying "feature" that it warns
161: // about switches on enums where not all cases are
162: // covered .... what is this, f-ing ML??
163: #define INCL_SWITCH \
164: default: break; /*silence warning*/
165:
166:
167: // for a class that maintains allocated-node stats
168: #define ALLOC_STATS_DECLARE \
169: static int numAllocd; \
170: static int maxAllocd; \
171: static void printAllocStats(bool anyway);
172:
173: // these would go in a .cc file, whereas above goes in .h file
174: #define ALLOC_STATS_DEFINE(classname) \
175: int classname::numAllocd = 0; \
176: int classname::maxAllocd = 0; \
177: STATICDEF void classname::printAllocStats(bool anyway) \
178: { \
179: if (anyway || numAllocd != 0) { \
180: std::cout << #classname << " nodes: " << numAllocd \
181: << ", max nodes: " << maxAllocd \
182: << std::endl; \
183: } \
184: }
185:
186: #define ALLOC_STATS_IN_CTOR \
187: INC_HIGH_WATER(numAllocd, maxAllocd);
188:
189: #define ALLOC_STATS_IN_DTOR \
190: numAllocd--;
191:
192:
193: // ----------- automatic data value restorer -------------
194: // used when a value is to be set to one thing now, but restored
195: // to its original value on return (even when the return is by
196: // an exception being thrown)
197: template <class T>
198: class Restorer {
199: T &variable;
200: T prevValue;
201:
202: public:
203: Restorer(T &var, T newValue)
204: : variable(var),
205: prevValue(var)
206: {
207: variable = newValue;
208: }
209:
210: // this one does not set it to a new value, just remembers the current
211: Restorer(T &var)
212: : variable(var),
213: prevValue(var)
214: {}
215:
216: ~Restorer()
217: {
218: variable = prevValue;
219: }
220: };
221:
222:
223: // declare a bunch of a set-like operators for enum types
224: #define ENUM_BITWISE_AND(Type) \
225: inline Type operator& (Type f1, Type f2) \
226: { return (Type)((int)f1 & (int)f2); } \
227: inline Type& operator&= (Type &f1, Type f2) \
228: { return f1 = f1 & f2; }
229:
230: #define ENUM_BITWISE_OR(Type) \
231: inline Type operator| (Type f1, Type f2) \
232: { return (Type)((int)f1 | (int)f2); } \
233: inline Type& operator|= (Type &f1, Type f2) \
234: { return f1 = f1 | f2; }
235:
236: #define ENUM_BITWISE_XOR(Type) \
237: inline Type operator^ (Type f1, Type f2) \
238: { return (Type)((int)f1 ^ (int)f2); } \
239: inline Type& operator^= (Type &f1, Type f2) \
240: { return f1 = f1 ^ f2; }
241:
242: #define ENUM_BITWISE_NOT(Type, ALL) \
243: inline Type operator~ (Type f) \
244: { return (Type)((~(int)f) & ALL); }
245:
246: #define ENUM_BITWISE_OPS(Type, ALL) \
247: ENUM_BITWISE_AND(Type) \
248: ENUM_BITWISE_OR(Type) \
249: ENUM_BITWISE_XOR(Type) \
250: ENUM_BITWISE_NOT(Type, ALL)
251:
252:
253: // macro to conditionalize something on NDEBUG; I typically use this
254: // to hide the declaration of a variable whose value is only used by
255: // debugging trace statements (and thus provokes warnings about unused
256: // variables if NDEBUG is set)
257: #ifdef NDEBUG
258: #define IFDEBUG(stuff)
259: #else
260: #define IFDEBUG(stuff) stuff
261: #endif
262:
263:
264: // put at the top of a class for which the default copy ctor
265: // and operator= are not desired; then don't define these functions
266: #define NO_OBJECT_COPIES(name) \
267: private: \
268: name(name&); \
269: void operator=(name&) /*user ;*/
270:
271:
272: #endif // __MACROS_H
Start C section to elk/sm_missing.h[1
/1
]
1: #line 2479 "./lpsrc/sm.pak"
2: // missing.h see license.txt for copyright and terms of use
3: // routines that I implemented because they aren't available on all platforms
4: // Scott McPeak, 1998 This file is public domain.
5:
6: #ifndef __MISSING_H
7: #define __MISSING_H
8:
9: // stricmp
10: int missing_stricmp(char const *s1, char const *s2);
11:
12: #endif // __MISSING_H
13:
Start C section to elk/sm_mysig.h[1
/1
]
1: #line 2493 "./lpsrc/sm.pak"
2: // mysig.h see license.txt for copyright and terms of use
3: // some simple Unix signal-handling stuff
4:
5: #ifndef MYSIG_H
6: #define MYSIG_H
7:
8: #include <signal.h> // signal stuff
9: #include <setjmp.h> // jmp_buf
10:
11: #ifdef __cplusplus
12: extern "C" {
13: #endif // __cplusplus
14:
15: // type of a signal handler function; generally, there are
16: // three options for a signal handler:
17: // - return, in which case the default action for the
18: // signal is taken
19: // - longjmp to a state where computation can resume
20: // - abort(2) or exit(2)
21: // it's somewhat dangerous to do other system calls, but people
22: // do it anyway
23: typedef void (*SignalHandler)(int signum);
24:
25:
26: // install the given handler on the given signal
27: void setHandler(int signum, SignalHandler handler);
28:
29:
30: // simple handler that just prints and re-raises
31: void printHandler(int signum);
32:
33:
34: // to use jmpHandler, call setjmp(sane_state) before
35: // installing the handler
36: extern jmp_buf sane_state;
37:
38: // handler to do a longjmp to sane_state
39: void jmpHandler(int signum);
40:
41:
42: // install a segfault handler that will print the address that
43: // caused the fault; this is very useful for debugging
44: void printSegfaultAddrs();
45:
46:
47: #ifdef __cplusplus
48: }
49: #endif // __cplusplus
50:
51: #endif // MYSIG_H
Start C section to elk/sm_nonport.h[1
/1
]
1: #line 2545 "./lpsrc/sm.pak"
2: // nonport.h see license.txt for copyright and terms of use
3: // collection of nonportable routines (the interfaces
4: // are portable, but the implementations are not)
5: // Scott McPeak, Dan Bonachea 1998-1999 This file is public domain.
6:
7: #ifndef __NONPORT_H
8: #define __NONPORT_H
9:
10: #include "sm_typ.h"
11: #include <stdarg.h> // va_list
12:
13:
14: // I'm attempting to improve error handling in this module; this fn will be
15: // called when a syscall fails, *in addition* to whatever error behavior
16: // is documented here (e.g., a fn might call this, and then return false).
17: // The default behavior is to do nothing. In sftpc and sftpd, I plan to
18: // point this at xSysError::xsyserror (see syserr.h).
19: typedef void (*NonportFailFunc)(char const *syscallName, char const *context);
20: // syscallName - name of failing system call
21: // context - current activity (maybe just calling fn's name) or NULL
22: extern NonportFailFunc nonportFail;
23:
24: // this is default handler
25: void defaultNonportFail(char const *syscallName, char const *context);
26:
27:
28:
29: // put terminal into 'raw' or 'cooked' mode
30: void setRawMode(bool raw);
31:
32: // get the next character typed without buffering or echoing; needs the
33: // console to be in 'raw' mode
34: char getConsoleChar();
35:
36:
37: // get a millisecond count, where 0 is an unspecified event
38: long getMilliseconds();
39:
40:
41: // remove all priviledges to a file, except for read/write
42: // access by the file's owner; returns false on error
43: bool limitFileAccess(char const *fname);
44:
45:
46: // get process id; meaning is somewhat system-dependent, but the goal
47: // is to return something that can be used to correlate log output
48: // from (say) sftpd with log output from some other source (syslog,
49: // or NT event viewer, etc.)
50: #if 0
51: int getProcessId();
52: #endif
53:
54: // create a new directory; returns false on error;
55: // precise naming semantics, such as use
56: // of 'current working directory', etc., are specified by the
57: // underlying OS's mkdir (or equivalent) command (it is hoped
58: // this underspecification will not be a problem in practice)
59: bool createDirectory(char const *dirname);
60:
61: // change to a directory; returns false on failure
62: // again, current-directory semantics are unspecified
63: bool changeDirectory(char const *dirname);
64:
65: // retrieve the name of the current working directory
66: // (more best effort crap, I guess)
67: bool getCurrentDirectory(char *dirname, int dirnameLen);
68:
69:
70: // get and process the names of files *and directories* in the current directory
71: typedef bool (*PerFileFunc)(char const *name, void *extra);
72: // name - file/dir being processed (contains no slashes)
73: // extra - 2nd parameter to applyToCwdContents
74: // return - true to continue, false to stop iterating
75: void applyToCwdContents(PerFileFunc func, void *extra=NULL);
76:
77: // same as above, but in an explicitly named directory
78: void applyToDirContents(char const *dirName,
79: PerFileFunc func, void *extra=NULL);
80:
81:
82: // return true if the given sm_string names a directory
83: bool isDirectory(char const *path);
84:
85:
86: // delete a file; returns false on failure
87: bool removeFile(char const *fname);
88:
89:
90: // retrieve the current date
91: void getCurrentDate(int &month, int &day, int &year);
92: // month: 1 = January ... 12 = December
93: // day: 1 = first day of month, ...
94: // year: 1999 is when this being coded
95: // e.g., February 8, 1999 is month=2, day=8, year=1999
96:
97:
98: // sleep for a bit (low resolution)
99: void portableSleep(unsigned seconds);
100:
101:
102: /*
103: // determine usable name of current user, and write it into 'buffer'
104: void getCurrentUsername(char *buffer, int buflen);
105: */
106:
107: // read a sm_string from the console, with no echo
108: void readNonechoString(char *buffer, int buflen, char const *prompt);
109:
110:
111: // return true if a file or directory exists
112: bool fileOrDirectoryExists(char const *name);
113:
114:
115: // ensure that the pathname part of a file name exists;
116: // it creates missing directories as necessary, with only
117: // user rwx permission; if 'isDirectory' is true, the whole
118: // name is also verified as a directory; returns false on
119: // error
120: bool ensurePath(char const *filename, bool isDirectory);
121:
122:
123: // returns true if the system has a cryptographically-
124: // secure random number generator
125: bool hasSystemCryptoRandom();
126:
127: // if the above fn returns true, this will retrieve a
128: // random 32-bit integer; may block until the bits
129: // become available
130: unsigned getSystemCryptoRandom();
131:
132:
133: // determine how many characters, *not* including the final NUL, would
134: // be written by vsprintf; this is allowed to overestimate
135: int vnprintf(char const *format, va_list args);
136:
137: // this is implemented in terms of vnprintf, so not technically
138: // a function with "nonportable implementation", but it belongs
139: // here anyway
140: int nprintf(char const *format, ...);
141:
142:
143: #endif // __NONPORT_H
144:
Start C section to elk/sm_objlist.h[1
/1
]
1: #line 2690 "./lpsrc/sm.pak"
2: // objlist.h
3: // owner list of arbitrary dynamically-allocated objects
4: // NOTE: automatically generated from xobjlist.h -- do not edit directly
5:
6: // Author: Scott McPeak, 2000
7:
8: #ifndef OBJLIST_H
9: #define OBJLIST_H
10:
11: #include "sm_voidlist.h"
12:
13:
14: // forward declarations of template classes, so we can befriend them in ObjList
15: // (not required by Borland C++ 4.5, but GNU wants it...)
16: template <class T> class ObjListIter;
17: template <class T> class ObjListMutator;
18: template <class T> class ObjListIterNC;
19:
20:
21: // the list is considered to own all of the items; it is an error to insert
22: // an item into more than one such list, or to insert an item more than once
23: // into any such list
24: template <class T>
25: class ObjList {
26: private:
27: friend class ObjListIter<T>;
28: friend class ObjListMutator<T>;
29: friend class ObjListIterNC<T>;
30:
31: protected:
32: VoidList list; // list itself
33:
34: private:
35: // this is an owner list; these are not allowed
36: ObjList(ObjList const &obj);
37: ObjList& operator= (ObjList const &src);
38:
39: public:
40: ObjList() : list() {}
41: ~ObjList() { deleteAll(); }
42:
43: // The difference function should return <0 if left should come before
44: // right, 0 if they are equivalent, and >0 if right should come before
45: // left. For example, if we are sorting numbers into ascending order,
46: // then 'diff' would simply be subtraction.
47: typedef int (*Diff)(T const *left, T const *right, void *extra);
48:
49: // selectors
50: int count() const { return list.count(); }
51: bool isEmpty() const { return list.isEmpty(); }
52: bool isNotEmpty() const { return list.isNotEmpty(); }
53: T *nth(int which) { return (T*)list.nth(which); }
54: T const *nthC(int which) const { return (T const*)list.nth(which); }
55: T *first() { return (T*)list.first(); }
56: T const *firstC() const { return (T const*)list.first(); }
57: T *last() { return (T*)list.last(); }
58: T const *lastC() const { return (T const*)list.last(); }
59:
60: // insertion
61: void prepend(T *newitem) { list.prepend((void*)newitem); }
62: void append(T *newitem) { list.append((void*)newitem); }
63: void insertAt(T *newitem, int index) { list.insertAt((void*)newitem, index); }
64: void insertSorted(T *newitem, Diff diff, void *extra=NULL)
65: { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
66:
67: // removal
68: T *removeAt(int index) { return (T*)list.removeAt(index); }
69: T *removeFirst() { return (T*)list.removeFirst(); }
70: void deleteAt(int index) { delete (T*)list.removeAt(index); }
71: void deleteAll();
72:
73: // list-as-set: selectors
74: int indexOf(T const *item) const { return list.indexOf((void*)item); }
75: int indexOfF(void *item) const { return list.indexOfF((void*)item); }
76: bool contains(T const *item) const { return list.contains((void*)item); }
77:
78: // list-as-set: mutators
79: bool prependUnique(T *newitem) { return list.prependUnique((void*)newitem); }
80: bool appendUnique(T *newitem) { return list.appendUnique((void*)newitem); }
81: void removeItem(T const *item) { list.removeItem((void*)item); } // whether the arg should be const is debatable..
82: bool removeIfPresent(T const *item) { return list.removeIfPresent((void*)item); }
83:
84: // complex modifiers
85: void reverse() { list.reverse(); }
86: void insertionSort(Diff diff, void *extra=NULL) { list.insertionSort((VoidDiff)diff, extra); }
87: void mergeSort(Diff diff, void *extra=NULL) { list.mergeSort((VoidDiff)diff, extra); }
88:
89: // and a related test
90: bool isSorted(Diff diff, void *extra=NULL) const { return list.isSorted((VoidDiff)diff, extra); }
91:
92: // multiple lists
93: void concat(ObjList &tail) { list.concat(tail.list); }
94: // (we do *not* have appendAll, since these are supposed to be owner lists)
95:
96: // steal
97: void stealTailAt(int index, ObjList &tail) { list.stealTailAt(index, tail.list); }
98:
99: // equal items in equal positions
100: bool equalAsLists(ObjList const &otherList, Diff diff, void *extra=NULL) const
101: { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
102: int compareAsLists(ObjList const &otherList, Diff diff, void *extra=NULL) const
103: { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
104:
105: // last-as-set: comparisons (NOT efficient)
106: bool equalAsSets(ObjList const &otherList, Diff diff, void *extra=NULL) const
107: { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
108: bool isSubsetOf(ObjList const &otherList, Diff diff, void *extra=NULL) const
109: { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
110: bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
111: { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
112:
113: // treating the pointer values themselves as the basis for comparison
114: bool equalAsPointerLists(ObjList const &otherList) const
115: { return list.equalAsPointerLists(otherList.list); }
116: bool equalAsPointerSets(ObjList const &otherList) const
117: { return list.equalAsPointerSets(otherList.list); }
118:
119: // debugging: two additional invariants
120: void selfCheck() const {
121: list.selfCheck();
122: list.checkHeapDataPtrs();
123: list.checkUniqueDataPtrs();
124: }
125: };
126:
127:
128: template <class T>
129: void ObjList<T>::deleteAll()
130: {
131: while (!list.isEmpty()) {
132: deleteAt(0);
133: }
134: }
135:
136:
137: // for traversing the list and modifying it (nodes and/or structure)
138: // NOTE: no list-modification fns should be called on 'list' while this
139: // iterator exists, and only one such iterator should exist for
140: // any given list
141: template <class T>
142: class ObjListMutator {
143: friend class ObjListIter<T>;
144:
145: protected:
146: VoidListMutator mut; // underlying mutator
147:
148: public:
149: ObjListMutator(ObjList<T> &lst) : mut(lst.list) { reset(); }
150: ~ObjListMutator() {}
151:
152: void reset() { mut.reset(); }
153:
154: // iterator copying; safe *only* until one of the mutators modifies
155: // the list structure (by inserting or removing), at which time all
156: // other iterators might be in limbo
157: ObjListMutator(ObjListMutator const &obj) : mut(obj.mut) {}
158: ObjListMutator& operator=(ObjListMutator const &obj) { mut = obj.mut; return *this; }
159: // requires that 'this' and 'obj' already refer to the same 'list'
160:
161: // iterator actions
162: bool isDone() const { return mut.isDone(); }
163: void adv() { mut.adv(); }
164: T *data() { return (T*)mut.data(); }
165: T *&dataRef() { return (T*&)mut.dataRef(); }
166:
167: // insertion
168: void insertBefore(T *item) { mut.insertBefore((void*)item); }
169: // 'item' becomes the new 'current', and the current 'current' is
170: // pushed forward (so the next adv() will make it current again)
171:
172: void insertAfter(T *item) { mut.insertAfter((void*)item); }
173: // 'item' becomes what we reach with the next adv();
174: // isDone() must be false
175:
176: void append(T *item) { mut.append((void*)item); }
177: // only valid while isDone() is true, it inserts 'item' at the end of
178: // the list, and advances such that isDone() remains true; equivalent
179: // to { xassert(isDone()); insertBefore(item); adv(); }
180:
181: // removal
182: T *remove() { return (T*)mut.remove(); }
183: // 'current' is removed from the list and returned, and whatever was
184: // next becomes the new 'current'
185:
186: void deleteIt() { delete (T*)mut.remove(); }
187: // same as remove(), except item is deleted also
188:
189: // debugging
190: void selfCheck() const { mut.selfCheck(); }
191: };
192:
193: #define MUTATE_EACH_OBJLIST(T, list, iter) \
194: for(ObjListMutator< T > iter(list); !iter.isDone(); iter.adv())
195:
196:
197: // for traversing the list without modifying it (neither nodes nor structure)
198: // NOTE: no list-modification fns should be called on 'list' while this
199: // iterator exists
200: template <class T>
201: class ObjListIter {
202: protected:
203: VoidListIter iter; // underlying iterator
204:
205: public:
206: ObjListIter(ObjList<T> const &list) : iter(list.list) {}
207: ObjListIter(ObjList<T> const &list, int pos) : iter(list.list, pos) {}
208: ~ObjListIter() {}
209:
210: void reset(ObjList<T> const &list) { iter.reset(list.list); }
211:
212: // iterator copying; generally safe
213: ObjListIter(ObjListIter const &obj) : iter(obj.iter) {}
214: ObjListIter& operator=(ObjListIter const &obj) { iter = obj.iter; return *this; }
215:
216: // but copying from a mutator is less safe; see above
217: ObjListIter(ObjListMutator<T> &obj) : iter(obj.mut) {}
218:
219: // iterator actions
220: bool isDone() const { return iter.isDone(); }
221: void adv() { iter.adv(); }
222: T const *data() const { return (T const*)iter.data(); }
223: };
224:
225: #define FOREACH_OBJLIST(T, list, iter) \
226: for(ObjListIter< T > iter(list); !iter.isDone(); iter.adv())
227:
228:
229: // intermediate to the above two, this allows modification of the
230: // objects stored on the list, but not the identity or order of
231: // the objects in the list
232: template <class T>
233: class ObjListIterNC {
234: protected:
235: VoidListIter iter; // underlying iterator
236:
237: public:
238: ObjListIterNC(ObjList<T> &list) : iter(list.list) {}
239: ObjListIterNC(ObjList<T> &list, int pos) : iter(list.list, pos) {}
240: ~ObjListIterNC() {}
241:
242: void reset(ObjList<T> &list) { iter.reset(list.list); }
243:
244: // iterator copying; generally safe
245: ObjListIterNC(ObjListIterNC const &obj) : iter(obj.iter) {}
246: ObjListIterNC& operator=(ObjListIterNC const &obj) { iter = obj.iter; return *this; }
247:
248: // but copying from a mutator is less safe; see above
249: ObjListIterNC(ObjListMutator<T> &obj) : iter(obj.mut) {}
250:
251: // iterator actions
252: bool isDone() const { return iter.isDone(); }
253: void adv() { iter.adv(); }
254: T *data() const { return (T*)iter.data(); }
255: };
256:
257: #define FOREACH_OBJLIST_NC(T, list, iter) \
258: for(ObjListIterNC< T > iter(list); !iter.isDone(); iter.adv())
259:
260:
261: // iterate over the combined elements of two or more lists
262: template <class T>
263: class ObjListMultiIter {
264: private:
265: // all the lists
266: ObjList<T> **lists; // serf array of serf list pointers
267: int numLists; // length of this array
268:
269: // current element
270: int curList; // which list we're working on
271: ObjListIter<T> iter; // current element of that list
272:
273: // invariant:
274: // either curList==numLists, or
275: // iter is not 'done'
276:
277: public:
278: ObjListMultiIter(ObjList<T> **L, int n)
279: : lists(L),
280: numLists(n),
281: curList(0),
282: iter(*(lists[0]))
283: {
284: xassert(n > 0);
285: normalize();
286: }
287:
288: // advance the iterator to the next element of the next non-empty list;
289: // establishes invariant above
290: void normalize();
291:
292: bool isDone() const {
293: return curList == numLists;
294: }
295:
296: T const *data() const {
297: return iter.data();
298: }
299:
300: void adv() {
301: iter.adv();
302: normalize();
303: }
304: };
305:
306: // this was originally inline, but that was causing some strange
307: // problems (compiler bug?)
308: template <class T>
309: void ObjListMultiIter<T>::normalize()
310: {
311: while (iter.isDone() && curList < numLists) {
312: curList++;
313: if (curList < numLists) {
314: iter.reset(*(lists[curList]));
315: }
316: }
317: }
318:
319:
320: #endif // OBJLIST_H
Start C section to elk/sm_objpool.h[1
/1
]
1: #line 3011 "./lpsrc/sm.pak"
2: // objpool.h see license.txt for copyright and terms of use
3: // custom allocator: array of objects meant to be
4: // re-used frequently, with high locality
5:
6: #ifndef OBJPOOL_H
7: #define OBJPOOL_H
8:
9: #include "sm_array.h"
10:
11: // the class T should have:
12: // // a link in the free list; it is ok for T to re-use this
13: // // member while the object is not free in the pool
14: // T *nextInFreeList;
15: //
16: // // object is done being used for now
17: // void deinit();
18: //
19: // // needed so we can make arrays
20: // T::T();
21:
22: template <class T>
23: class ObjectPool {
24: private: // data
25: // when the pool needs to expand, it expands by allocating an
26: // additional 'rackSize' objects; I use a linear (instead of
27: // exponential) expansion strategy because these are supposed
28: // to be used for small sets of rapidly-reused objects, not
29: // things allocated for long-term storage
30: int rackSize;
31:
32: // growable array of pointers to arrays of 'rackSize' T objects
33: ArrayStack<T*> racks;
34:
35: // head of the free list; NULL when empty
36: T *head;
37:
38: private: // funcs
39: void expandPool();
40:
41: public: // funcs
42: ObjectPool(int rackSize);
43: ~ObjectPool();
44:
45: // yields a pointer to an object ready to be used; typically,
46: // T should have some kind of init method to play the role a
47: // constructor ordinarily does; this might cause the pool to
48: // expand (but previously allocated objects do *not* move)
49: inline T *alloc();
50:
51: // return an object to the pool of objects; dealloc internally
52: // calls obj->deinit()
53: inline void dealloc(T *obj);
54:
55: // same as 'dealloc', but without the call to 'deinit'
56: inline void deallocNoDeinit(T *obj);
57:
58: // available for diagnostic purposes
59: int freeObjectsInPool() const;
60:
61: // low-level access for heavily-optimized client code; clients that
62: // use these functions accept the burden of possibly needing to
63: // change if internals of ObjectPool change
64: T *private_getHead() { return head; }
65: void private_setHead(T *h) { head = h; }
66: };
67:
68:
69: template <class T>
70: ObjectPool<T>::ObjectPool(int rs)
71: : rackSize(rs),
72: racks(5),
73: head(NULL)
74: {}
75:
76: template <class T>
77: ObjectPool<T>::~ObjectPool()
78: {
79: // deallocate all the objects in the racks
80: for (int i=0; i < racks.length(); i++) {
81: delete[] racks[i];
82: }
83: }
84:
85:
86: template <class T>
87: inline T *ObjectPool<T>::alloc()
88: {
89: if (!head) {
90: // need to expand the pool
91: expandPool();
92: }
93:
94: T *ret = head; // prepare to return this one
95: head = ret->nextInFreeList; // move to next free node
96:
97: #ifndef NDEBUG
98: ret->nextInFreeList = NULL; // paranoia
99: #endif
100:
101: return ret;
102: }
103:
104:
105: // this is pulled out of 'alloc' so alloc can be inlined
106: // without causing excessive object code bloat
107: template <class T>
108: void ObjectPool<T>::expandPool()
109: {
110: T *rack = new T[rackSize];
111: racks.push(rack);
112:
113: // thread new nodes into a free list
114: for (int i=rackSize-1; i>=0; i--) {
115: rack[i].nextInFreeList = head;
116: head = &(rack[i]);
117: }
118: }
119:
120:
121: // usually I want the convenience of dealloc calling deinit; however,
122: // in the inner loop of a performance-critical section of code, I
123: // want finer control
124: template <class T>
125: inline void ObjectPool<T>::deallocNoDeinit(T *obj)
126: {
127: // I don't check that nextInFreeList == NULL, despite having set it
128: // that way in alloc(), because I want to allow for users to make
129: // nextInFreeList share storage (e.g. with a union) with some other
130: // field that gets used while the node is allocated
131:
132: // prepend the object to the free list; will be next yielded
133: obj->nextInFreeList = head;
134: head = obj;
135: }
136:
137:
138: template <class T>
139: inline void ObjectPool<T>::dealloc(T *obj)
140: {
141: // call obj's pseudo-dtor (the decision to have dealloc do this is
142: // motivated by not wanting to have to remember to call deinit
143: // before dealloc)
144: obj->deinit();
145:
146: deallocNoDeinit(obj);
147: }
148:
149:
150: template <class T>
151: int ObjectPool<T>::freeObjectsInPool() const
152: {
153: T *p = head;
154: int ct = 0;
155:
156: while (p) {
157: ct++;
158: p = p->nextInFreeList;
159: }
160:
161: return ct;
162: }
163:
164:
165: #endif // OBJPOOL_H
Start C section to elk/sm_objstack.h[1
/1
]
1: #line 3177 "./lpsrc/sm.pak"
2: // objstack.h see license.txt for copyright and terms of use
3: // stack of objects, owned by the stack
4:
5: #ifndef OBJSTACK_H
6: #define OBJSTACK_H
7:
8: #include "sm_objlist.h"
9:
10: template <class T>
11: class ObjStack {
12: private: // data
13: // will implement the stack as a list, with prepend and removeAt(0)
14: ObjList<T> list;
15:
16: public: // funcs
17: ObjStack() : list() {}
18: ~ObjStack() {}
19:
20: int count() const { return list.count(); }
21: bool isEmpty() const { return list.isEmpty(); }
22: bool isNotEmpty() const { return list.isNotEmpty(); }
23:
24: T const *topC() const { return list.firstC(); }
25: T * /*serf*/ top() { return list.first(); }
26:
27: T * /*owner*/ pop() { return list.removeAt(0); }
28: void delPop() { list.deleteAt(0); }
29: void push(T *item) { list.prepend(item); }
30: void clear() { list.deleteAll(); }
31:
32: bool contains(T const *item) const { return list.contains((void*)item); }
33: };
34:
35: #endif // OBJSTACK_H
Start C section to elk/sm_ohashtbl.h[1
/1
]
1: #line 3213 "./lpsrc/sm.pak"
2: // ohashtbl.h see license.txt for copyright and terms of use
3: // hash table that owns the values; uses void* keys
4: // see hashtbl.h for more detail on the semantics of the member fns
5:
6: #ifndef OHASHTBL_H
7: #define OHASHTBL_H
8: #include "sm_typ.h"
9: #include "sm_hashtbl.h"
10:
11: template <class T> class OwnerHashTableIter;
12:
13: template <class T>
14: class OwnerHashTable {
15: public: // types
16: friend class OwnerHashTableIter<T>;
17:
18: // see hashtbl.h
19: typedef void const* (*GetKeyFn)(T *data);
20: typedef unsigned (*HashFn)(void const *key);
21: typedef bool (*EqualKeyFn)(void const *key1, void const *key2);
22:
23: private: // data
24: // inner table that does the hash mapping
25: HashTable table;
26:
27: public: // funcs
28: OwnerHashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
29: int initSize = HashTable::defaultSize)
30: : table((HashTable::GetKeyFn)gk, hf, ek, initSize) {}
31: ~OwnerHashTable() { empty(1); }
32:
33: int getNumEntries() const { return table.getNumEntries(); }
34: T *get(void const *key) const { return (T*)table.get(key); }
35: void add(void const *key, T *value) { table.add(key, value); }
36: T *remove(void const *key) { return (T*)table.remove(key); }
37: void empty(int initSize = HashTable::defaultSize);
38: void setEnableShrink(bool en) { table.setEnableShrink(en); }
39: void selfCheck() const { table.selfCheck(); }
40:
41: // this simply drops all the entries without deleting them; it is
42: // useful when the objects have been taken out via iteration
43: void disownAndForgetAll(int initSize = HashTable::defaultSize)
44: { table.empty(initSize); }
45: };
46:
47: template <class T>
48: void OwnerHashTable<T>::empty(int initSize)
49: {
50: HashTableIter iter(table);
51: for (; !iter.isDone(); iter.adv()) {
52: delete (T*)iter.data();
53: }
54: table.empty(initSize);
55: }
56:
57:
58: template <class T>
59: class OwnerHashTableIter {
60: private: // data
61: HashTableIter iter; // internal iterator
62:
63: public: // funcs
64: OwnerHashTableIter(OwnerHashTable<T> &table)
65: : iter(table.table) {}
66:
67: bool isDone() const { return iter.isDone(); }
68: void adv() { iter.adv(); }
69: T *data() { return (T*)iter.data(); }
70: };
71:
72: #endif // OHASHTBL_H
Start C section to elk/sm_okhasharr.h[1
/1
]
1: #line 3286 "./lpsrc/sm.pak"
2: // okhasharr.h see license.txt for copyright and terms of use
3: // combination of an owner hash table and an array/stack
4: //
5: // in its present form, it's ideal for a worklist, but not
6: // for a 'finished' list, due to inability to randomly remove
7:
8: #ifndef OKHASHARR_H
9: #define OKHASHARR_H
10:
11: #include "sm_array.h"
12: #include "sm_okhashtbl.h"
13:
14: // T is value, K is key
15: template <class T, class K>
16: class OwnerKHashArray {
17: private: // data
18: OwnerKHashTable<T,K> hash;
19: ArrayStack<T*> stack;
20:
21: public: // funcs
22: OwnerKHashArray(typename OwnerKHashTable<T,K>::GetKeyFn gk,
23: typename OwnerKHashTable<T,K>::HashFn hf,
24: typename OwnerKHashTable<T,K>::EqualKeyFn ek,
25: int initSize = HashTable::defaultSize)
26: : hash(gk, hf, ek, initSize),
27: stack(initSize)
28: {
29: hash.setEnableShrink(false);
30: }
31: ~OwnerKHashArray();
32:
33: // # elts in the structure
34: int count() const { return stack.length(); }
35: bool isEmpty() const { return stack.isEmpty(); }
36: bool isNotEmpty() const { return !isEmpty(); }
37:
38: // access as a hashtable
39: T *lookup(K const *key) const { return hash.get(key); }
40: K const *callGetKeyFn(T *data) { return hash.callGetKeyFn(data); }
41:
42: // TODO: make a new base-level implementation so I can support
43: // removal of arbitrary objects efficiently
44:
45: // access as a stack
46: void push(K const *key, T *value) {
47: hash.add(key, value);
48: stack.push(value);
49: }
50:
51: T *pop() {
52: T *ret = stack.pop();
53: hash.remove(hash.callGetKeyFn(ret));
54: return ret;
55: }
56: };
57:
58:
59: template <class T, class K>
60: OwnerKHashArray<T,K>::~OwnerKHashArray()
61: {}
62:
63:
64: #endif // OKHASHARR_H
Start C section to elk/sm_okhashtbl.h[1
/1
]
1: #line 3351 "./lpsrc/sm.pak"
2: // okhashtbl.h see license.txt for copyright and terms of use
3: // version of ohasharr.h with type-safe keys ("k" for keys)
4:
5: #ifndef OKHASHTBL_H
6: #define OKHASHTBL_H
7:
8: #include "sm_typ.h"
9: #include "sm_hashtbl.h"
10:
11: template <class T, class K> class OwnerKHashTableIter;
12:
13: // T is the value type, K is the key type
14: template <class T, class K>
15: class OwnerKHashTable {
16: public: // types
17: friend class OwnerKHashTableIter<T,K>;
18:
19: // see hashtbl.h
20: typedef K const* (*GetKeyFn)(T *data);
21: typedef unsigned (*HashFn)(K const *key);
22: typedef bool (*EqualKeyFn)(K const *key1, K const *key2);
23:
24: private: // data
25: // inner table that does the hash mapping
26: HashTable table;
27:
28: public: // funcs
29: OwnerKHashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
30: int initSize = HashTable::defaultSize)
31: : table((HashTable::GetKeyFn)gk,
32: (HashTable::HashFn)hf,
33: (HashTable::EqualKeyFn)ek,
34: initSize) {}
35: ~OwnerKHashTable() { empty(1); }
36:
37: int getNumEntries() const { return table.getNumEntries(); }
38: T *get(K const *key) const { return (T*)table.get(key); }
39: void add(K const *key, T *value) { table.add(key, value); }
40: T *remove(K const *key) { return (T*)table.remove(key); }
41: void empty(int initSize = HashTable::defaultSize);
42: void setEnableShrink(bool en) { table.setEnableShrink(en); }
43: K const *callGetKeyFn(T *data) { return (K const*)table.callGetKeyFn(data); }
44: void selfCheck() const { table.selfCheck(); }
45:
46: // this simply drops all the entries without deleting them; it is
47: // useful when the objects have been taken out via iteration
48: void disownAndForgetAll(int initSize = HashTable::defaultSize)
49: { table.empty(initSize); }
50: };
51:
52: template <class T, class K>
53: void OwnerKHashTable<T,K>::empty(int initSize)
54: {
55: HashTableIter iter(table);
56: for (; !iter.isDone(); iter.adv()) {
57: delete (T*)iter.data();
58: }
59: table.empty(initSize);
60: }
61:
62:
63: template <class T, class K>
64: class OwnerKHashTableIter {
65: private: // data
66: HashTableIter iter; // internal iterator
67:
68: public: // funcs
69: OwnerKHashTableIter(OwnerKHashTable<T,K> &table)
70: : iter(table.table) {}
71:
72: bool isDone() const { return iter.isDone(); }
73: void adv() { iter.adv(); }
74: T *data() { return (T*)iter.data(); }
75: };
76:
77: #endif // OKHASHTBL_H
Start C section to elk/sm_oobjmap.h[1
/1
]
1: #line 3429 "./lpsrc/sm.pak"
2: // oobjmap.h see license.txt for copyright and terms of use
3: // owner object map, implemented with a hash table
4: // maps pointer-to-key-object to pointer-to-value-object, and owns
5: // all instances of value-object (they are deallocated when the
6: // map itself goes away)
7:
8: // I had envisioned an interface which didn't require the function
9: // that maps values back to keys.. given that OwnerHashTable requires
10: // this, I'll suspend this line of work for now and keep using
11: // OwnerHashTable directly
12: #error This does not work quite right
13:
14: #ifndef OOBJMAP_H
15: #define OOBJMAP_H
16:
17: #include "sm_ohashtbl.h"
18:
19: template <class Key, class Value> class OObjMapIter;
20:
21: template <class Key, class Value>
22: class OObjMap {
23: public: // types
24: friend class OObjMapIter<Key, Value>;
25:
26: private: // data
27: OwnerHashTable<Value> table; // implementation
28:
29: public: // funcs
30: OObjMap() {}
31: ~OObjMap() {} // deallocates Value objects
32:
33: int getNumEntries() const { return table.getNumEntries(); }
34: Value *get(Key const *key) const { return table.get(key); }
35: void add(Key const *key, Value *value) { table.add(key, value); }
36: Value *remove(Key const *key) { return table.remove(key); }
37: void empty() { table.empty(); }
38: void selfCheck() const { table.selfCheck(); }
39: };
40:
41:
42: template <class Key, class Value>
43: class OObjMapIter {
44: private: // data
45: OwnerHashTableIter<Value> iter; // implementation
46:
47: public:
48: OObjMapIter(OObjMap<Key,Value> &map) : iter(map.table) {}
49:
50: bool isDone() const { return iter.isDone(); }
51: void adv() { iter.adv(); }
52: Value *data() { return iter.data(); }
53: };
54:
55:
56: #endif // OOBJMAP_H
Start C section to elk/sm_owner.h[1
/1
]
1: #line 3486 "./lpsrc/sm.pak"
2: // owner.h see license.txt for copyright and terms of use
3: // a stab at an owner ptr abstraction
4:
5: #ifndef OWNER_H
6: #define OWNER_H
7:
8: #include "sm_typ.h"
9:
10: #ifdef DEBUG_OWNER
11: #include <stdio.h> // printf, temporary
12: #define DBG(fn) printf("%s(%p)\n", fn, ptr)
13: #else
14: #define DBG(fn)
15: #endif
16:
17: template <class T>
18: class Owner {
19: private: // data
20: T *ptr; // the real pointer
21:
22: private: // funcs
23: Owner(Owner&); // not allowed
24:
25: public: // funcs
26: Owner(T *p = NULL) : ptr(p) { DBG("ctor"); }
27: ~Owner() { DBG("dtor"); del(); }
28:
29: // take ownership (no transitive = here)
30: void operator= (T *p) { DBG("op=ptr"); del(); ptr=p; }
31: void operator= (Owner<T> &obj) { DBG("op=obj"); del(); ptr=obj.ptr; obj.ptr=NULL; }
32:
33: // release ownership
34: T *xfr() { DBG("xfr"); T *temp = ptr; ptr = NULL; return temp; }
35:
36: // free
37: void del() { DBG("del"); delete ptr; ptr = NULL; } // relies on delete(NULL) being ok
38:
39: // some operators that make Owner behave more or less like
40: // a native C++ pointer.. note that some compilers to really
41: // bad handling the "ambiguity", so the non-const versions
42: // can be disabled at compile time
43: operator T const* () const { DBG("opcT*"); return ptr; }
44: T const & operator* () const { DBG("opc*"); return *ptr; }
45: T const * operator-> () const { DBG("opc->"); return ptr; }
46:
47: // according to http://www.google.com/search?q=cache:zCRFFDMZvVUC:people.we.mediaone.net/stanlipp/converops.htm+conversion+sequence+for+the+argument+is+better&hl=en&ie=ISO-8859-1,
48: // a solution to the gcc "conversion sequence is better" complaint
49: // is to define this version
50: operator T const* () { DBG("opcT*_nc"); return ptr; }
51:
52: #ifndef NO_OWNER_NONCONST
53: operator T* () { DBG("opT*"); return ptr; }
54: T& operator* () { DBG("op*"); return *ptr; }
55: T* operator-> () { DBG("op->"); return ptr; }
56: #endif
57:
58: // escape hatch for when operators flake out on us
59: T *get() { DBG("get"); return ptr; }
60: T const *getC() const { DBG("getC"); return ptr; }
61:
62: // even more dangerous escape; only use where the caller
63: // agrees to restore the owner invariant!
64: T *&getRef() { DBG("getRed"); return ptr; }
65:
66: // swaps are interesting because they don't require checking
67: void swapWith(Owner<T> &obj) {
68: T *tmp = ptr;
69: ptr = obj.ptr;
70: obj.ptr = tmp;
71: }
72: };
73:
74:
75: template <class T>
76: void swap(Owner<T> &obj1, Owner<T> &obj2)
77: {
78: obj1.swapWith(obj2);
79: }
80:
81:
82: // not used with Owner objects, but rather with
83: // simple pointers (Foo*) that are used as owners
84: template <class T>
85: T *xfr(T *&ptr)
86: {
87: T *ret = ptr;
88: ptr = NULL;
89: return ret;
90: }
91:
92:
93: #endif // OWNER_H
Start C section to elk/sm_point.h[1
/1
]
1: #line 3580 "./lpsrc/sm.pak"
2: // point.h see license.txt for copyright and terms of use
3: // 2-dimensional point
4: // derived from Melee's prmtvs2.hpp
5:
6: #ifndef __POINT_H
7: #define __POINT_H
8:
9: #include "sm_typ.h"
10:
11: // point defined over arbitrary underlying types
12: template <class num>
13: class TPoint {
14: public:
15: num x, y;
16:
17: public:
18: TPoint() {}
19: TPoint(num nx, num ny) { set(nx,ny); }
20: TPoint(TPoint<num> const &obj) : x(obj.x), y(obj.y) {}
21:
22: TPoint const& operator = (TPoint<num> const &obj)
23: { x=obj.x; y=obj.y; return *this; }
24:
25: void set(num nx, num ny) { x=nx; y=ny; }
26: void get(num *gx, num *gy) const { *gx=x; *gy=y; }
27: bool zero() const { return x==0 && y==0; }
28: bool gtez() const { return x>=0 && y>=0; }
29:
30: TPoint<num> operator - () const
31: { return TPoint<num>(-x, -y); }
32: TPoint<num> absval() const
33: { return TPoint<num>(x<0? -x : x, y<0? -y : y); }
34: // don't call abs() because that requires stdlib.h
35: // also, don't call the function "abs" because abs() is usually
36: // implemented as a macro
37:
38: TPoint<num> operator + (TPoint<num> const &obj) const
39: { return TPoint<num>(x+obj.x, y+obj.y); }
40: TPoint<num> operator - (TPoint<num> const &obj) const
41: { return TPoint<num>(x-obj.x, y-obj.y); }
42: num dotprod(TPoint<num> const &obj) const
43: { return x*obj.x + y*obj.y; }
44:
45: // for the arithmetic functions of the form point <op> num, <op> num is
46: // applied to x and y independently
47:
48: TPoint<num> operator * (num factor) const
49: { return TPoint<num>(x*factor, y*factor); }
50: TPoint<num> operator / (num factor) const
51: { return TPoint<num>(x/factor, y/factor); }
52:
53: TPoint<num> operator * (TPoint<num> const &factor) const
54: { return TPoint<num>(x*factor.x, y*factor.y); }
55: TPoint<num> operator / (TPoint<num> const &factor) const
56: { return TPoint<num>(x/factor.x, y/factor.y); }
57:
58: TPoint<num> operator += (TPoint<num> const &obj)
59: { x+=obj.x; y+=obj.y; return *this; }
60: TPoint<num> operator -= (TPoint<num> const &obj)
61: { x-=obj.x; y-=obj.y; return *this; }
62: TPoint<num> operator *= (num factor)
63: { x*=factor; y*=factor; return *this; }
64: TPoint<num> operator /= (num factor)
65: { x/=factor; y/=factor; return *this; }
66:
67: bool operator == (TPoint<num> const &obj) const
68: { return x==obj.x && y==obj.y; }
69: bool operator != (TPoint<num> const &obj) const
70: { return ! operator==(obj); }
71:
72: // use with care; note that each relation requires the relation to hold for
73: // *both* x and y for it to be true (this is different than, for example, the
74: // way STL does relations between pairs)
75: bool operator > (TPoint<num> const &obj) const
76: { return x>obj.x && y>obj.y; }
77: bool operator >= (TPoint<num> const &obj) const
78: { return x>=obj.x && y>=obj.y; }
79: bool operator < (TPoint<num> const &obj) const
80: { return x<obj.x && y<obj.y; }
81: bool operator <= (TPoint<num> const &obj) const
82: { return x<=obj.x && y<=obj.y; }
83: };
84:
85:
86: // common incarnations
87: typedef TPoint<int> point;
88: typedef TPoint<double> fpoint;
89:
90:
91: // and we can then define sm_stringBuilder output ops for them
92: class ELK_EXTERN sm_stringBuilder;
93: sm_stringBuilder& operator<< (sm_stringBuilder &sb, point const &pt);
94: sm_stringBuilder& operator<< (sm_stringBuilder &sb, fpoint const &pt);
95:
96:
97: // iterate: 0,0 1,0 2,0 ... x-1,0 and then
98: // 0,1 1,1 2,1 ... x-1,1 and then
99: // . .
100: // . . (each line in succession)
101: // . .
102: // 0,y-1 1,y-1 2,y-1 ... x-1,y-1 done
103: // can 'break' out of the loop at any time
104:
105: #define FOREACH_point(size, var) \
106: if ((size).x > 0) \
107: for(point var(0,0); var.y < (size).y; ++var.x == (size).x && (var.x=0,var.y++))
108:
109:
110: #endif // ___POINT_H
111:
Start C section to elk/sm_pprint.h[1
/1
]
1: #line 3692 "./lpsrc/sm.pak"
2: // pprint.h
3: // pretty-print code while emitting it
4:
5:
6:
7: // NOTE: This module is a little simpler to use, but much less
8: // powerful than the 'boxprint' module. I'm leaving this module
9: // here for now, but will probably delete it at some point.
10:
11:
12:
13: // inspired by:
14: // CIL's 'pretty' module
15: // http://www.cs.berkeley.edu/~necula/cil/index.html
16: // and
17: // Caml pretty-print module (boxes, etc.)
18: // http://caml.inria.fr/FAQ/format-eng.html
19:
20: // special characters:
21: // '\n' - hard linebreak
22: // '\r' - optional linebreak; is 1 space if the break isn't taken
23: // '\b' - begin a break group (return to <here>)
24: // '\a' - alternate begin group (return to <this_line_ind> + altIndent)
25: // '\f' - finish a break group
26:
27: #ifndef PPRINT_H
28: #define PPRINT_H
29:
30: #include <iostream> // std::ostream
31: #include "sm_str.h"
32: #include "sm_array.h"
33:
34:
35: // output interface for PPrint.. I'd like to just start using the
36: // C++ istd::ostreams interfaces, but reading on the net I get the
37: // impression they're still a little too much in flux
38: class PPrintOut {
39: public:
40: virtual void write(char const *text) = 0;
41: virtual ~PPrintOut(){}
42: };
43:
44: class PPrintStringOut : public PPrintOut {
45: sm_stringBuilder &sb;
46: public:
47: PPrintStringOut(sm_stringBuilder &s) : sb(s) {}
48: virtual void write(char const *text);
49: };
50:
51: class PPrintOstreamOut : public PPrintOut {
52: std::ostream &os;
53: public:
54: PPrintOstreamOut(std::ostream &o) : os(o) {}
55: virtual void write(char const *text);
56: };
57:
58:
59: // pretty printer formatting engine
60: class PPrint {
61: private: // types
62: // manages the line-setting algorithm
63: class Setter {
64: private: // data
65: // inter-line information
66: PPrint &pprint;
67:
68: // emitted text in the current line
69: sm_stringBuilder curLine;
70:
71: // indentation used for 'curLine'
72: int curLineInd;
73:
74: // place in the 'line' buffer; all the chars up to this point
75: // have been sent out
76: int lineIndex;
77:
78: // stack of columns at which indent groups opened
79: ArrayStack<int> indentGroups;
80:
81: private: // funcs
82: // add 'amt' spaces to 'curLine'
83: void indent(int amt);
84:
85: // copy characters [lineIndex,lineIndex+p-1] from 'line' into
86: // 'curLine', moving 'lineIndex' along so eventually it equals
87: // 'p'; also maintain 'indentGroups'
88: void emitTo(int p);
89:
90: // send all of 'curLine' to 'pprint.out', and clear 'curLine'
91: void flush();
92:
93: public: // funcs
94: Setter(PPrint &p)
95: : pprint(p),
96: curLine(),
97: curLineInd(0),
98: lineIndex(0),
99: indentGroups()
100: {}
101: ~Setter();
102:
103: void set();
104: };
105: friend class Setter;
106:
107: private: // data
108: // the contents of each line, up to a hard linebreak, is accumulated here
109: ArrayStack<char> line;
110:
111: public: // data
112: // current indentation level for the beginning of a complete line
113: // (one preceded by a hard linebreak)
114: int lineIndent;
115:
116: // desired right margin; we'll try to set text so it doesn't go
117: // beyond that many columns; defaults to 72
118: int margin;
119:
120: // incremental indentation for '\a' groups; defaults to 2
121: int altIndent;
122:
123: // if not NULL, text to emit at the start of every line; intended
124: // for emitting text into a comment or other embedded context;
125: // defaults to NULL; not counted against the margin
126: char const *startText;
127:
128: // where to send output
129: PPrintOut &out;
130:
131: // When true, and we find that the grouping is unbalanced at
132: // the end of setting a line, pring a warning. This defaults
133: // to 'true'. Note that while too many '\b's will only trigger
134: // this warning, too many '\f's can cause an assertion failure
135: // when the indentation stack underflows.
136: static bool warnWhenUnbalanced;
137:
138: private: // funcs
139: // take the current line buffer and break it up into output
140: // lines, sending them to 'out'
141: void set();
142:
143: public: // funcs
144: PPrint(PPrintOut &out);
145: ~PPrint();
146:
147: // basic printing routine; the text can contain the special
148: // characters listed above; whenever a '\n' is seen, the current
149: // line is set and emitted to 'out'
150: void print(char const *text);
151:
152: // convenience
153: PPrint& operator<< (int i);
154: PPrint& operator<< (char const *s);
155:
156: // manage the line-start indentation
157: void ind(int amt) { lineIndent += amt; }
158: };
159:
160:
161: class PPrintToString : public PPrint {
162: public:
163: sm_stringBuilder sb; // output (set) lines accumulate here
164: PPrintStringOut sbOut; // helper
165:
166: public:
167: PPrintToString()
168: : PPrint(sbOut), sb(), sbOut(sb) {}
169: ~PPrintToString();
170: };
171:
172: class PPrintToOstream : public PPrint {
173: PPrintOstreamOut osOut;
174:
175: public:
176: PPrintToOstream(std::ostream &os)
177: : PPrint(osOut), osOut(os) {}
178: };
179:
180:
181: #endif // PPRINT_H
Start C section to elk/sm_ptrmap.h[1
/1
]
1: #line 3874 "./lpsrc/sm.pak"
2: // ptrmap.h
3: // map from KEY* to VALUE* for arbitrary types KEY and VALUE
4: // (neither are owned by the table)
5:
6: // for const purposes, I regard the mapping itself as the only
7: // thing that cannot be modified in a "const" map; in particular,
8: // I allow a non-const VALUE* to be extracted
9:
10: #ifndef PTRMAP_H
11: #define PTRMAP_H
12:
13: #include "sm_vptrmap.h"
14: #include "sm_typ.h"
15:
16:
17: template <class KEY, class VALUE>
18: class PtrMap {
19: private: // data
20: // underlying map implementation, around which this class
21: // is a type-safe wrapper
22: VoidPtrMap map;
23:
24: public: // funcs
25: PtrMap() : map() {}
26: ~PtrMap() {}
27:
28: // query # of mapped entries
29: int getNumEntries() const { return map.getNumEntries(); }
30: bool isEmpty() const { return getNumEntries() == 0; }
31: bool isNotEmpty() const { return !isEmpty(); }
32:
33: // if this key has a mapping, return it; otherwise, return NULL
34: VALUE *get(KEY const *key) const { return (VALUE*)map.get((void const*)key); }
35:
36: // add a mapping from 'key' to 'value'; replaces existing
37: // mapping, if any
38: void add(KEY *key, VALUE *value) { map.add((void*)key, (void*)value); }
39:
40: // remove all mappings
41: void empty() { map.empty(); }
42:
43:
44: public: // iterators
45: class Iter {
46: private: // data
47: // underlying iterator state
48: VoidPtrMap::Iter iter;
49:
50: public: // fucs
51: Iter(PtrMap<KEY,VALUE> const &map) : iter(map.map) {}
52: ~Iter() {}
53:
54: bool isDone() const { return iter.isDone(); }
55: void adv() { return iter.adv(); }
56:
57: // return information about the currently-referenced table entry
58: KEY *key() const { return (KEY*)iter.key(); }
59: VALUE *value() const { return (VALUE*)iter.value(); }
60: };
61: friend class Iter;
62: };
63:
64:
65: // a set based on PtrMap
66: template <class KEY>
67: class PtrSet : private PtrMap<KEY, KEY> {
68: public:
69: PtrSet() {}
70: ~PtrSet() {}
71:
72: // query # of mapped entries
73: int getNumEntries() const { return PtrMap<KEY, KEY>::getNumEntries(); }
74: bool isEmpty() const { return PtrMap<KEY, KEY>::isEmpty(); }
75: bool isNotEmpty() const { return PtrMap<KEY, KEY>::isNotEmpty(); }
76:
77: // if this key has a mapping, return it; otherwise, return NULL
78: bool contains(KEY const *key) const { return PtrMap<KEY, KEY>::get(key)!=NULL; }
79:
80: // add key to the set
81: void add(KEY *key) { PtrMap<KEY, KEY>::add(key, key); }
82:
83: // make the set empty; FIX: this would be better named makeEmpty(),
84: // as it could be confused with the meaning of isEmpty(); however I
85: // reflect the naming of PtrMap, where the same criticism applies.
86: void empty() { PtrMap<KEY, KEY>::empty(); }
87: };
88:
89:
90: #endif // PTRMAP_H
Start C section to elk/sm_flexlexer.h[1
/1
]
1: #line 3965 "./lpsrc/sm.pak"
2: // sm_flexlexer.h
3: // a layer of indirection to try to work with different
4: // installed versions of Flex
5:
6:
7: // Basically, what has happened is the last version of flex created by
8: // Vern Paxson et al. is 2.5.4, and a lot of distributions use that.
9: // More recently some other people started a project hosted at
10: // Sourceforge, and their current (only?) release is flex-2.5.31.
11: // Unfortunately, the authors of 2.5.31 do not appear concerned with
12: // maintaining compatibility for C++ scanners.
13: //
14: // See bug "[ 751550 ] c++ derived scanners will not compile",
15: // http://sourceforge.net/tracker/index.php?func=detail&aid=751550&group_id=72099&atid=533377
16: //
17: // So in an attempt to make Elkhound/Elsa work, this file is where
18: // I'll put my hacks.
19:
20:
21: // workaround for flex-2.5.31 bug
22: #ifdef yyFlexLexer
23: #undef yyFlexLexer
24: #endif
25:
26: // now get the installed FlexLexer.h.. this nominally lives in
27: // /usr/include or /usr/local/include, depending on how Flex is
28: // installed
29: //#include <FlexLexer.h>
30:
31:
32: // for now I keep the rest but I think I may be able to delete
33: // it soon..
34: //#if 0 // terminates at EOF
35: // FELIX uses this text, never the system FlexLexer.h
36: #if 1
37:
38:
39: // copy of /usr/include/FlexLexer.h from flex-2.5.4
40:
41:
42: // To use this file, use the same flex version as listed above.
43:
44:
45: // Why is this file distributed with smbase?
46: //
47: // 1. I want my distribution tarballs to include the *output* of
48: // tools like flex/bison, but flex's output has an #include of
49: // FlexLexer.h. Since I want the distribution to be self-contained,
50: // that means distributing the .h file as well.
51: //
52: // 2. It avoids version mismatch. Some people have flex-2.5.31,
53: // some have 2.5.4. Some of my classes depend on the internals of
54: // the FlexLexer class which have changed between the versions, and
55: // making it compatible with both is difficult.
56:
57:
58: // What is its copyright status?
59: //
60: // I've put most of smbase into the public domain. However, the
61: // Regents retain copyright on this file. I am in effect just
62: // providing a convenient distribution mechanism for smbase users
63: // (users *could* just download it themselves, for free, just like
64: // smbase).
65:
66:
67: // ------------------ original file below -----------------
68: // $Header: /cvsroot/felix/lpsrc/sm.pak,v 1.19 2006/03/15 12:30:20 skaller Exp $
69:
70: // FlexLexer.h -- define interfaces for lexical analyzer classes generated
71: // by flex
72:
73: // Copyright (c) 1993 The Regents of the University of California.
74: // All rights reserved.
75: //
76: // This code is derived from software contributed to Berkeley by
77: // Kent Williams and Tom Epperly.
78: //
79: // Redistribution and use in source and binary forms with or without
80: // modification are permitted provided that: (1) source distributions retain
81: // this entire copyright notice and comment, and (2) distributions including
82: // binaries display the following acknowledgement: ``This product includes
83: // software developed by the University of California, Berkeley and its
84: // contributors'' in the documentation or other materials provided with the
85: // distribution and in all advertising materials mentioning features or use
86: // of this software. Neither the name of the University nor the names of
87: // its contributors may be used to endorse or promote products derived from
88: // this software without specific prior written permission.
89:
90: // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
91: // WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
92: // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
93:
94: // This file defines FlexLexer, an abstract class which specifies the
95: // external interface provided to flex C++ lexer objects, and yyFlexLexer,
96: // which defines a particular lexer class.
97: //
98: // If you want to create multiple lexer classes, you use the -P flag
99: // to rename each yyFlexLexer to some other xxFlexLexer. You then
100: // include <FlexLexer.h> in your other sources once per lexer class:
101: //
102: // #undef yyFlexLexer
103: // #define yyFlexLexer xxFlexLexer
104: // #include <FlexLexer.h>
105: //
106: // #undef yyFlexLexer
107: // #define yyFlexLexer zzFlexLexer
108: // #include <FlexLexer.h>
109: // ...
110:
111: #ifndef __FLEX_LEXER_H
112: // Never included before - need to define base class.
113: #define __FLEX_LEXER_H
114: #include <iostream>
115:
116: // FELIX: always C++ compiles anyhow
117: //extern "C++" {
118:
119: struct yy_buffer_state;
120: typedef int yy_state_type;
121:
122: class FlexLexer {
123: public:
124: virtual ~FlexLexer() { }
125:
126: const char* YYText() { return yytext; }
127: int YYLeng() { return yyleng; }
128:
129: virtual void
130: yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
131: virtual struct yy_buffer_state*
132: yy_create_buffer( std::istream* s, int size ) = 0;
133: virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
134: virtual void yyrestart( std::istream* s ) = 0;
135:
136: virtual int yylex() = 0;
137:
138: // Call yylex with new input/output sources.
139: int yylex( std::istream* new_in, std::ostream* new_out = 0 )
140: {
141: switch_streams( new_in, new_out );
142: return yylex();
143: }
144:
145: // Switch to new input/output streams. A nil stream pointer
146: // indicates "keep the current one".
147: virtual void switch_streams( std::istream* new_in = 0,
148: std::ostream* new_out = 0 ) = 0;
149:
150: int lineno() const { return yylineno; }
151:
152: int debug() const { return yy_flex_debug; }
153: void set_debug( int flag ) { yy_flex_debug = flag; }
154:
155: protected:
156: char* yytext;
157: int yyleng;
158: int yylineno; // only maintained if you use %option yylineno
159: int yy_flex_debug; // only has effect with -d or "%option debug"
160: };
161:
162: //FELIX: always C++
163: //}
164:
165: #endif
166:
167: #if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
168: // Either this is the first time through (yyFlexLexerOnce not defined),
169: // or this is a repeated include to define a different flavor of
170: // yyFlexLexer, as discussed in the flex man page.
171: #define yyFlexLexerOnce
172:
173: class yyFlexLexer : public FlexLexer {
174: public:
175: // arg_yyin and arg_yyout default to the cin and cout, but we
176: // only make that assignment when initializing in yylex().
177: yyFlexLexer( std::istream* arg_yyin = 0, std::ostream* arg_yyout = 0 );
178:
179: virtual ~yyFlexLexer();
180:
181: void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
182: struct yy_buffer_state* yy_create_buffer( std::istream* s, int size );
183: void yy_delete_buffer( struct yy_buffer_state* b );
184: void yyrestart( std::istream* s );
185:
186: virtual int yylex();
187: virtual void switch_streams( std::istream* new_in, std::ostream* new_out );
188:
189: protected:
190: virtual int LexerInput( char* buf, int max_size );
191: virtual void LexerOutput( const char* buf, int size );
192: virtual void LexerError( const char* msg );
193:
194: void yyunput( int c, char* buf_ptr );
195: int yyinput();
196:
197: void yy_load_buffer_state();
198: void yy_init_buffer( struct yy_buffer_state* b, std::istream* s );
199: void yy_flush_buffer( struct yy_buffer_state* b );
200:
201: int yy_start_stack_ptr;
202: int yy_start_stack_depth;
203: int* yy_start_stack;
204:
205: void yy_push_state( int new_state );
206: void yy_pop_state();
207: int yy_top_state();
208:
209: yy_state_type yy_get_previous_state();
210: yy_state_type yy_try_NUL_trans( yy_state_type current_state );
211: int yy_get_next_buffer();
212:
213: std::istream* yyin; // input source for default LexerInput
214: std::ostream* yyout; // output sink for default LexerOutput
215:
216: struct yy_buffer_state* yy_current_buffer;
217:
218: // yy_hold_char holds the character lost when yytext is formed.
219: char yy_hold_char;
220:
221: // Number of characters read into yy_ch_buf.
222: int yy_n_chars;
223:
224: // Points to current character in buffer.
225: char* yy_c_buf_p;
226:
227: int yy_init; // whether we need to initialize
228: int yy_start; // start state number
229:
230: // Flag which is used to allow yywrap()'s to do buffer switches
231: // instead of setting up a fresh yyin. A bit of a hack ...
232: int yy_did_buffer_switch_on_eof;
233:
234: // The following are not always needed, but may be depending
235: // on use of certain flex features (like REJECT or yymore()).
236:
237: yy_state_type yy_last_accepting_state;
238: char* yy_last_accepting_cpos;
239:
240: yy_state_type* yy_state_buf;
241: yy_state_type* yy_state_ptr;
242:
243: char* yy_full_match;
244: int* yy_full_state;
245: int yy_full_lp;
246:
247: int yy_lp;
248: int yy_looking_for_trail_begin;
249:
250: int yy_more_flag;
251: int yy_more_len;
252: int yy_more_offset;
253: int yy_prev_more_offset;
254: };
255:
256: #endif
257:
258: #endif // 0, from top of file
Start C section to elk/sm_regexp.h[1
/1
]
1: #line 4224 "./lpsrc/sm.pak"
2: // smregexp.h
3: // regular expression matching, etc.
4:
5: // the "sm" prefix in the name is to avoid a name conflict with something
6: // in my version of glibc..
7:
8: // The regular expression language is, for now, the "Extended" regexp
9: // language described in the regex(7) man page, itself a description
10: // of POSIX 1003.2, section 2.8 (Regular Expression Notation).
11:
12: // The interface is based on the POSIX regex functions too, but I
13: // don't actually include regex.h here since I want to allow a
14: // different implementation, if that becomes necessary.
15:
16: #ifndef REGEXP_H
17: #define REGEXP_H
18:
19: #include "sm_macros.h"
20:
21:
22: // ----------------- Regexp class -------------------
23: // This class represents a compiled regexp pattern. For maximum
24: // efficiency, repeated uses of the same pattern should use the
25: // same Regexp object each time instead of making a new one.
26: class Regexp {
27: public: // types
28: // compilation flags
29: enum CFlags {
30: C_NONE = 0x00, // no flags
31: ICASE = 0x02, // case insensitive
32: NOSUB = 0x08, // subsm_string matches are not needed
33: //NEWLINE // still not sure what this really means
34: };
35:
36: // execution flags
37: enum EFlags {
38: E_NONE = 0x00, // no flags
39: NOTBOL = 0x01, // treat 'str' as not including beginning of line
40: NOTEOL = 0x02, // ............................ end of line
41: };
42:
43: private: // data
44: void *impl; // implementation data
45: //int numLParens; // # of left-parens in the pattern
46:
47: private: // funcs
48: // not allowed
49: Regexp(Regexp&);
50: void operator=(Regexp&);
51:
52: void err(int code) NORETURN;
53:
54: public: // funcs
55: Regexp(char const *exp, CFlags flags = C_NONE);
56: ~Regexp();
57:
58: bool match(char const *str, EFlags flags = E_NONE);
59: };
60:
61: // allow '|' to be used on the flags
62: ENUM_BITWISE_OR(Regexp::CFlags)
63: ENUM_BITWISE_OR(Regexp::EFlags)
64:
65:
66: // TODO: Add support for subsm_string matches by building a class to
67: // remember the subsm_string offsets (enable 'numLParens' above)
68: // efficiently. Major question: do I always make an internal copy of
69: // the sm_string in which we searched? Leaning towards yes...
70:
71:
72:
73: // --------------- convenience functions ---------------
74: // The functions in this section are built on top of the
75: // Regexp class in the obvious way.
76:
77: // return true if 'str' matches 'exp'
78: bool regexpMatch(char const *str, char const *exp);
79:
80:
81: #endif // REGEXP_H
Start C section to elk/sm_sobjlist.h[1
/1
]
1: #line 4306 "./lpsrc/sm.pak"
2: // sobjlist.h
3: // serf list of arbitrary objects
4: // NOTE: automatically generated from xobjlist.h -- do not edit directly
5:
6: // Author: Scott McPeak, 2000
7:
8: #ifndef SOBJLIST_H
9: #define SOBJLIST_H
10:
11: #include "sm_voidlist.h"
12:
13:
14: // forward declarations of template classes, so we can befriend them in SObjList
15: // (not required by Borland C++ 4.5, but GNU wants it...)
16: template <class T> class SObjListIter;
17: template <class T> class SObjListMutator;
18: template <class T> class SObjListIterNC;
19:
20:
21: // the list is considered to not own any of the items; it's ok to
22: // insert items multiple times or into multiple lists
23: template <class T>
24: class SObjList {
25: private:
26: friend class SObjListIter<T>;
27: friend class SObjListMutator<T>;
28: friend class SObjListIterNC<T>;
29:
30: protected:
31: VoidList list; // list itself
32:
33: public:
34: // make shallow copies
35: SObjList(SObjList const &obj) : list(obj.list) {}
36: SObjList& operator= (SObjList const &src) { list = src.list; return *this; }
37:
38: public:
39: SObjList() : list() {}
40: ~SObjList() {} /* all items removed */
41:
42: // The difference function should return <0 if left should come before
43: // right, 0 if they are equivalent, and >0 if right should come before
44: // left. For example, if we are sorting numbers into ascending order,
45: // then 'diff' would simply be subtraction.
46: typedef int (*Diff)(T const *left, T const *right, void *extra);
47:
48: // selectors
49: int count() const { return list.count(); }
50: bool isEmpty() const { return list.isEmpty(); }
51: bool isNotEmpty() const { return list.isNotEmpty(); }
52: T *nth(int which) { return (T*)list.nth(which); }
53: T const *nthC(int which) const { return (T const*)list.nth(which); }
54: T *first() { return (T*)list.first(); }
55: T const *firstC() const { return (T const*)list.first(); }
56: T *last() { return (T*)list.last(); }
57: T const *lastC() const { return (T const*)list.last(); }
58:
59: // insertion
60: void prepend(T *newitem) { list.prepend((void*)newitem); }
61: void append(T *newitem) { list.append((void*)newitem); }
62: void insertAt(T *newitem, int index) { list.insertAt((void*)newitem, index); }
63: void insertSorted(T *newitem, Diff diff, void *extra=NULL)
64: { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
65:
66: // removal
67: T *removeAt(int index) { return (T*)list.removeAt(index); }
68: T *removeFirst() { return (T*)list.removeFirst(); }
69: void removeAll() { list.removeAll(); }
70:
71: // list-as-set: selectors
72: int indexOf(T const *item) const { return list.indexOf((void*)item); }
73: int indexOfF(void *item) const { return list.indexOfF((void*)item); }
74: bool contains(T const *item) const { return list.contains((void*)item); }
75:
76: // list-as-set: mutators
77: bool prependUnique(T *newitem) { return list.prependUnique((void*)newitem); }
78: bool appendUnique(T *newitem) { return list.appendUnique((void*)newitem); }
79: void removeItem(T const *item) { list.removeItem((void*)item); } // whether the arg should be const is debatable..
80: bool removeIfPresent(T const *item) { return list.removeIfPresent((void*)item); }
81:
82: // complex modifiers
83: void reverse() { list.reverse(); }
84: void insertionSort(Diff diff, void *extra=NULL) { list.insertionSort((VoidDiff)diff, extra); }
85: void mergeSort(Diff diff, void *extra=NULL) { list.mergeSort((VoidDiff)diff, extra); }
86:
87: // and a related test
88: bool isSorted(Diff diff, void *extra=NULL) const { return list.isSorted((VoidDiff)diff, extra); }
89:
90: // multiple lists
91: void concat(SObjList &tail) { list.concat(tail.list); }
92: void appendAll(SObjList const &tail) { list.appendAll(tail.list); }
93:
94: // steal
95: void stealTailAt(int index, SObjList &tail) { list.stealTailAt(index, tail.list); }
96:
97: // equal items in equal positions
98: bool equalAsLists(SObjList const &otherList, Diff diff, void *extra=NULL) const
99: { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
100: int compareAsLists(SObjList const &otherList, Diff diff, void *extra=NULL) const
101: { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
102:
103: // last-as-set: comparisons (NOT efficient)
104: bool equalAsSets(SObjList const &otherList, Diff diff, void *extra=NULL) const
105: { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
106: bool isSubsetOf(SObjList const &otherList, Diff diff, void *extra=NULL) const
107: { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
108: bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
109: { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
110:
111: // treating the pointer values themselves as the basis for comparison
112: bool equalAsPointerLists(SObjList const &otherList) const
113: { return list.equalAsPointerLists(otherList.list); }
114: bool equalAsPointerSets(SObjList const &otherList) const
115: { return list.equalAsPointerSets(otherList.list); }
116:
117: // debugging: no invariants beyond VoidList
118: void selfCheck() const { list.selfCheck(); }
119:
120: // but export the additional checks for cases where they apply anyway
121: void checkHeapDataPtrs() const { list.checkHeapDataPtrs(); }
122: void checkUniqueDataPtrs() const { list.checkUniqueDataPtrs(); }
123: };
124:
125:
126: // for traversing the list and modifying it (nodes and/or structure)
127: // NOTE: no list-modification fns should be called on 'list' while this
128: // iterator exists, and only one such iterator should exist for
129: // any given list
130: template <class T>
131: class SObjListMutator {
132: friend class SObjListIter<T>;
133:
134: protected:
135: VoidListMutator mut; // underlying mutator
136:
137: public:
138: SObjListMutator(SObjList<T> &lst) : mut(lst.list) { reset(); }
139: ~SObjListMutator() {}
140:
141: void reset() { mut.reset(); }
142:
143: // iterator copying; safe *only* until one of the mutators modifies
144: // the list structure (by inserting or removing), at which time all
145: // other iterators might be in limbo
146: SObjListMutator(SObjListMutator const &obj) : mut(obj.mut) {}
147: SObjListMutator& operator=(SObjListMutator const &obj) { mut = obj.mut; return *this; }
148: // requires that 'this' and 'obj' already refer to the same 'list'
149:
150: // iterator actions
151: bool isDone() const { return mut.isDone(); }
152: void adv() { mut.adv(); }
153: T *data() { return (T*)mut.data(); }
154: T *&dataRef() { return (T*&)mut.dataRef(); }
155:
156: // insertion
157: void insertBefore(T *item) { mut.insertBefore((void*)item); }
158: // 'item' becomes the new 'current', and the current 'current' is
159: // pushed forward (so the next adv() will make it current again)
160:
161: void insertAfter(T *item) { mut.insertAfter((void*)item); }
162: // 'item' becomes what we reach with the next adv();
163: // isDone() must be false
164:
165: void append(T *item) { mut.append((void*)item); }
166: // only valid while isDone() is true, it inserts 'item' at the end of
167: // the list, and advances such that isDone() remains true; equivalent
168: // to { xassert(isDone()); insertBefore(item); adv(); }
169:
170: // removal
171: T *remove() { return (T*)mut.remove(); }
172: // 'current' is removed from the list and returned, and whatever was
173: // next becomes the new 'current'
174:
175: // debugging
176: void selfCheck() const { mut.selfCheck(); }
177: };
178:
179: #define SMUTATE_EACH_OBJLIST(T, list, iter) \
180: for(SObjListMutator< T > iter(list); !iter.isDone(); iter.adv())
181:
182:
183: // for traversing the list without modifying it (neither nodes nor structure)
184: // NOTE: no list-modification fns should be called on 'list' while this
185: // iterator exists
186: template <class T>
187: class SObjListIter {
188: protected:
189: VoidListIter iter; // underlying iterator
190:
191: public:
192: SObjListIter(SObjList<T> const &list) : iter(list.list) {}
193: SObjListIter(SObjList<T> const &list, int pos) : iter(list.list, pos) {}
194: ~SObjListIter() {}
195:
196: void reset(SObjList<T> const &list) { iter.reset(list.list); }
197:
198: // iterator copying; generally safe
199: SObjListIter(SObjListIter const &obj) : iter(obj.iter) {}
200: SObjListIter& operator=(SObjListIter const &obj) { iter = obj.iter; return *this; }
201:
202: // but copying from a mutator is less safe; see above
203: SObjListIter(SObjListMutator<T> &obj) : iter(obj.mut) {}
204:
205: // iterator actions
206: bool isDone() const { return iter.isDone(); }
207: void adv() { iter.adv(); }
208: T const *data() const { return (T const*)iter.data(); }
209: };
210:
211: #define SFOREACH_OBJLIST(T, list, iter) \
212: for(SObjListIter< T > iter(list); !iter.isDone(); iter.adv())
213:
214:
215: // intermediate to the above two, this allows modification of the
216: // objects stored on the list, but not the identity or order of
217: // the objects in the list
218: template <class T>
219: class SObjListIterNC {
220: protected:
221: VoidListIter iter; // underlying iterator
222:
223: public:
224: SObjListIterNC(SObjList<T> &list) : iter(list.list) {}
225: SObjListIterNC(SObjList<T> &list, int pos) : iter(list.list, pos) {}
226: ~SObjListIterNC() {}
227:
228: void reset(SObjList<T> &list) { iter.reset(list.list); }
229:
230: // iterator copying; generally safe
231: SObjListIterNC(SObjListIterNC const &obj) : iter(obj.iter) {}
232: SObjListIterNC& operator=(SObjListIterNC const &obj) { iter = obj.iter; return *this; }
233:
234: // but copying from a mutator is less safe; see above
235: SObjListIterNC(SObjListMutator<T> &obj) : iter(obj.mut) {}
236:
237: // iterator actions
238: bool isDone() const { return iter.isDone(); }
239: void adv() { iter.adv(); }
240: T *data() const { return (T*)iter.data(); }
241: };
242:
243: #define SFOREACH_OBJLIST_NC(T, list, iter) \
244: for(SObjListIterNC< T > iter(list); !iter.isDone(); iter.adv())
245:
246:
247: // iterate over the combined elements of two or more lists
248: template <class T>
249: class SObjListMultiIter {
250: private:
251: // all the lists
252: SObjList<T> **lists; // serf array of serf list pointers
253: int numLists; // length of this array
254:
255: // current element
256: int curList; // which list we're working on
257: SObjListIter<T> iter; // current element of that list
258:
259: // invariant:
260: // either curList==numLists, or
261: // iter is not 'done'
262:
263: public:
264: SObjListMultiIter(SObjList<T> **L, int n)
265: : lists(L),
266: numLists(n),
267: curList(0),
268: iter(*(lists[0]))
269: {
270: xassert(n > 0);
271: normalize();
272: }
273:
274: // advance the iterator to the next element of the next non-empty list;
275: // establishes invariant above
276: void normalize();
277:
278: bool isDone() const {
279: return curList == numLists;
280: }
281:
282: T const *data() const {
283: return iter.data();
284: }
285:
286: void adv() {
287: iter.adv();
288: normalize();
289: }
290: };
291:
292: // this was originally inline, but that was causing some strange
293: // problems (compiler bug?)
294: template <class T>
295: void SObjListMultiIter<T>::normalize()
296: {
297: while (iter.isDone() && curList < numLists) {
298: curList++;
299: if (curList < numLists) {
300: iter.reset(*(lists[curList]));
301: }
302: }
303: }
304:
305:
306: #endif // SOBJLIST_H
Start C section to elk/sm_sobjset.h[1
/1
]
1: #line 4613 "./lpsrc/sm.pak"
2: // sobjset.h see license.txt for copyright and terms of use
3: // non-owning set of objects (identified by address),
4: // implemented with a hashtable
5:
6: #ifndef SOBJSET_H
7: #define SOBJSET_H
8:
9: #include "sm_hashtbl.h"
10:
11: template <class T> class SObjSetIter;
12:
13:
14: // experiment: to try to support const-polymorphism,
15: // I expect T to either be Foo* or Foo const *
16:
17: template <class T>
18: class SObjSet : private HashTable {
19: friend class SObjSetIter<T>;
20:
21: public:
22: SObjSet()
23: : HashTable(identityKeyFn, lcprngHashFn, pointerEqualKeyFn) {}
24:
25: // # of distinct elements in the set
26: int size() const { return HashTable::getNumEntries(); }
27:
28: // true if 'elt' is in the set
29: bool contains(T elt) const { return !!HashTable::get((void const*)elt); }
30:
31: // add 'elt' to the set; if it is already in, this has no effect
32: void add(T elt) { if (!contains(elt)) { HashTable::add((void const*)elt, (void*)elt); } }
33:
34: // remove 'elt' from the set; if it's not there, this has no effect
35: void remove(T elt) { if (contains(elt)) { HashTable::remove((void const*)elt); } }
36:
37: // remove all elements
38: void empty() { HashTable::empty(); }
39:
40: // debug check which throws an exception if there's a problem
41: void selfCheck() { HashTable::selfCheck(); }
42: };
43:
44:
45: template <class T>
46: class SObjSetIter : private HashTableIter {
47: public:
48: SObjSetIter(SObjSet<T> &table)
49: : HashTableIter(table) {} // I'm a friend, I can see it's a HashTable inside
50:
51: bool isDone() const { return HashTableIter::isDone(); }
52: void adv() { return HashTableIter::adv(); }
53: T data() const { return (T)HashTableIter::data(); }
54: };
55:
56:
57: #endif // SOBJSET_H
Start C section to elk/sm_sobjstack.h[1
/1
]
1: #line 4671 "./lpsrc/sm.pak"
2: // sobjstack.h see license.txt for copyright and terms of use
3: // stack of objects, *not* owned by the stack
4:
5: #ifndef SOBJSTACK_H
6: #define SOBJSTACK_H
7:
8: #include "sm_sobjlist.h"
9:
10: template <class T>
11: class SObjStack {
12: public: // data
13: // will implement the stack as a list, with prepend and removeAt(0)
14: SObjList<T> list;
15:
16: public: // funcs
17: SObjStack() : list() {}
18: ~SObjStack() {}
19:
20: int count() const { return list.count(); }
21: bool isEmpty() const { return list.isEmpty(); }
22: bool isNotEmpty() const { return list.isNotEmpty(); }
23:
24: T const *topC() const { return list.firstC(); }
25: T *top() { return list.first(); }
26:
27: T *pop() { return list.removeAt(0); }
28: void push(T *item) { list.prepend(item); }
29:
30: bool contains(T const *item) const { return list.contains((void*)item); }
31: };
32:
33:
34: // utility class for maintaining a first-class sub-stack of the AST
35: // stack isomorphic to the stackframe stack; Note that the fact that
36: // nothing happens if 'obj' is NULL is a feature: sometimes you can't
37: // map the need to call this class completely onto the control flow,
38: // and so some dataflow is involved; since the dtor for this class is
39: // used as a kind of finally statement, we can't nest its construction
40: // in an 'if' statement! Instead pass in NULL if you want a no-op
41: // effect.
42: template<class T>
43: class StackMaintainer {
44: SObjStack<T> &s;
45: T *obj;
46:
47: StackMaintainer(StackMaintainer&); // forbid copying
48:
49: public:
50: explicit StackMaintainer(SObjStack<T> &s0, T *obj0)
51: : s(s0)
52: , obj(obj0)
53: {
54: if (obj) {
55: s.push(obj);
56: }
57: }
58:
59: ~StackMaintainer() {
60: if (obj) {
61: T *obj0 = s.pop();
62: xassert(obj0 == obj);
63: }
64: }
65: };
66:
67:
68: #endif // SOBJSTACK_H
Start C section to elk/sm_srcloc.h[1
/1
]
1: #line 4740 "./lpsrc/sm.pak"
2: // srcloc.h see license.txt for copyright and terms of use
3: // source location information, efficiently represented as one word
4:
5: // The fundamental assumption in this module is that source location
6: // information is frequently created, stored and passed around, but
7: // infrequently decoded into human-readable form. Therefore the
8: // module uses a single word to store the information, and appeals
9: // to several index structures when decoding is necessary.
10: //
11: // Since decoding, when it happens, also usually has high locality,
12: // the data structures include caches to make accesses to nearby
13: // locations fast.
14: //
15: // No attempt is made to fold creation of SourceLocs into other
16: // file-processing activities, such as traditional lexical analysis.
17: // The complexity of doing that would be substantial, with little gain
18: // in efficiency, due to the large buffer caches in modern OSes. The
19: // main drawback is the inability to work with non-seekable inputs
20: // (like pipes) because we consume the whole input when its line
21: // counts are computed.
22:
23: #ifndef SRCLOC_H
24: #define SRCLOC_H
25:
26: #include "sm_str.h"
27: #include "sm_objlist.h"
28: #include "flx_elk_config.hpp"
29:
30: class HashLineMap; // hashline.h
31:
32:
33: // This is a source location. It's interpreted as an integer
34: // specifying the byte offset within a hypothetical file created by
35: // concatenating all the sources together. Its type is 'enum' so I
36: // can overload functions to accept SourceLoc without confusion.
37: // I assume the compiler will use a machine word for this (and check
38: // that assumption in the .cc file).
39: //
40: // I would love to be able to annotate this so that the C++ compiler
41: // would not allow variables of this type to be created
42: // uninitialized.. that's the one drawback of calling this an 'enum'
43: // instead of a 'class': I don't get to write a constructor.
44: enum SourceLoc {
45: // entity is defined within the translator's initialization code
46: SL_INIT=-1,
47:
48: // location is unknown for some reason
49: SL_UNKNOWN=0
50: };
51:
52:
53: // This class manages all the data associated with creating and
54: // interpreting SourceLocs. It's expected to be a singleton in the
55: // program, though within this module that assumption is confined to
56: // the 'toString' function at the end.
57: class ELK_EXTERN SourceLocManager {
58: private: // types
59: // a triple which identifies a line boundary in a file (it's
60: // implicit which file it is) with respect to all of the relevant
61: // spaces
62: class Marker {
63: public:
64: // character offset, starting with 0
65: int charOffset;
66:
67: // line offset, starting with 1
68: int lineOffset;
69:
70: // offset into the 'lineLengths' array; this is not simply
71: // lineOffset-1 because of the possible presence of lines with
72: // length longer than 254 chars
73: int arrayOffset;
74:
75: public:
76: Marker() {} // for creation in arrays
77: Marker(int c, int L, int a)
78: : charOffset(c), lineOffset(L), arrayOffset(a) {}
79: Marker(Marker const &obj)
80: : DMEMB(charOffset), DMEMB(lineOffset), DMEMB(arrayOffset) {}
81: };
82:
83: public: // types
84: // describes a file we know about
85: class File {
86: public: // data
87: // file name; we consider two files to be the same if and only
88: // if their names are equal, i.e. there is no checking done to
89: // see if their names happen to be aliases in the filesystem
90: sm_string name;
91:
92: // start offset in the SourceLoc space
93: SourceLoc startLoc;
94:
95: // number of chars in the file
96: int numChars;
97:
98: // number of lines in the file
99: int numLines;
100:
101: // average number of chars per line; this is used for estimating
102: // whether the index should be consulted for some lookups (and
103: // it's stored instead of computed to save a division)
104: int avgCharsPerLine;
105:
106: // known #line directives for this file; NULL if none are known
107: HashLineMap *hashLines; // (nullable owner)
108:
109: private: // data
110: // an array of line lengths; to handle lines longer than 255
111: // chars, we use runs of '\xFF' chars to (in unary) encode
112: // multiples of 254 (one less than 255) chars, plus the final
113: // short count to give the total length
114: unsigned char *lineLengths; // (owner)
115:
116: // # of elements in 'lineLengths'
117: int lineLengthsSize;
118:
119: // this marker and offset can name an arbitrary point
120: // in the array, including those that are not at the
121: // start of a line; we move this around when searching
122: // within the array
123: Marker marker;
124: int markerCol; // 1-based column; it's usually 1
125:
126: // an index built on top of 'lineLengths' for faster random access
127: Marker *index; // (owner)
128:
129: // # of elements in 'index'
130: int indexSize;
131:
132: private: // funcs
133: File(File&); // disallowed
134: void resetMarker();
135: void advanceMarker();
136:
137: public: // funcs
138: // this builds both the array and the index
139: File(char const *name, SourceLoc startLoc);
140: ~File();
141:
142: // line number to character offset
143: int lineToChar(int lineNum);
144:
145: // line/col to offset, with truncation if col exceeds line length
146: int lineColToChar(int lineNum, int col);
147:
148: // char offset to line/col
149: void charToLineCol(int offset, int &line, int &col);
150:
151: // true if this file contains the specified location
152: bool hasLoc(SourceLoc sl) const
153: { return toInt(startLoc) <= sl &&
154: sl <= toInt(startLoc) + numChars; }
155:
156: // call this time each time a #line directive is encountered;
157: // same semantics as HashLineMap::addHashLine
158: void addHashLine(int ppLine, int origLine, char const *origFname);
159: void doneAdding();
160: };
161:
162: // this is used for SourceLocs where the file isn't reliably
163: // available, yet we'd like to be able to store some location
164: // information anyway; the queries below just return the static
165: // information stored, and incremental update is impossible
166: class StaticLoc {
167: public:
168: sm_string name; // file name
169: int offset; // char offset
170: int line, col; // line,col
171:
172: public:
173: StaticLoc(char const *n, int o, int L, int c)
174: : name(n), offset(o), line(L), col(c) {}
175: StaticLoc(StaticLoc const &obj)
176: : DMEMB(name), DMEMB(offset), DMEMB(line), DMEMB(col) {}
177: ~StaticLoc();
178: };
179:
180: private: // data
181: // list of files; it would be possible to use a data structure
182: // that is faster to search, but the cache ought to exploit
183: // query locality to the extent that it doesn't matter
184: ObjList<File> files;
185:
186: // most-recently accessed File; this is a cache
187: File *recent; // (serf)
188:
189: // list of StaticLocs; any SourceLoc less than 0 is interpreted
190: // as an index into this list
191: ObjList<StaticLoc> statics;
192:
193: // next source location to assign
194: SourceLoc nextLoc;
195:
196: // next static (negative) location
197: SourceLoc nextStaticLoc;
198:
199: public: // data
200: // number of static locations at which we print a warning message;
201: // defaults to 100
202: int maxStaticLocs;
203:
204: // when true, we automatically consult the #line maps when decoding;
205: // defaults to true; NOTE: when this is true, encode and decode are
206: // not necessarily inverses of each other
207: bool useHashLines;
208:
209: // count the # of times we had to truncate a char offset because
210: // the #line map pointed at a line shorter than the column number
211: // we expected to use; this is initially 0; calling code can use
212: // this to tell if the offset information across a given call or
213: // sequence of calls is perfect or truncated
214: static int shortLineCount;
215:
216: private: // funcs
217: // let File know about these functions
218: friend class SourceLocManager::File;
219:
220: static SourceLoc toLoc(int L) {
221: SourceLoc ret = (SourceLoc)L;
222:
223: // in debug mode, we verify that SourceLoc is wide enough
224: // to encode this integer
225: xassertdb(toInt(ret) == L);
226:
227: return ret;
228: }
229: static int toInt(SourceLoc loc) { return (int)loc; }
230:
231: File *findFile(char const *name);
232: File *getFile(char const *name);
233:
234: public: // dsw: I need this so I have an object to annotate with a VoidVoidDict
235: File *findFileWithLoc(SourceLoc loc);
236: private:
237: StaticLoc const *getStatic(SourceLoc loc);
238:
239: public: // funcs
240: SourceLocManager();
241: ~SourceLocManager();
242:
243: // origins:
244: // character offsets start at 0
245: // lines start at 1
246: // columns start at 1
247:
248: // encode from scratch
249: SourceLoc encodeOffset(char const *filename, int charOffset);
250: SourceLoc encodeBegin(char const *filename)
251: { return encodeOffset(filename, 0 /*offset*/); }
252: SourceLoc encodeLineCol(char const *filename, int line, int col);
253:
254: // some care is required with 'encodeStatic', since each call makes
255: // a new location with a new entry in the static array to back it
256: // up, so the caller should ensure a given static location is not
257: // encoded more than once, if possible
258: SourceLoc encodeStatic(StaticLoc const &obj);
259: SourceLoc encodeStatic(char const *fname, int offset, int line, int col)
260: { return encodeStatic(StaticLoc(fname, offset, line, col)); }
261: static bool isStatic(SourceLoc loc) { return toInt(loc) <= 0; }
262:
263: // encode incremental; these are the methods we expect are called
264: // the most frequently; this interface is supposed to allow an
265: // implementation which uses explicit line/col, even though that
266: // is not what is used here
267: static SourceLoc advCol(SourceLoc base, int colOffset)
268: { xassert(!isStatic(base)); return toLoc(toInt(base) + colOffset); }
269: static SourceLoc advLine(SourceLoc base) // from end of line to beginning of next
270: { xassert(!isStatic(base)); return toLoc(toInt(base) + 1); }
271: static SourceLoc advText(SourceLoc base, char const * /*text*/, int textLen)
272: { xassert(!isStatic(base)); return toLoc(toInt(base) + textLen); }
273:
274: // decode
275: void decodeOffset(SourceLoc loc, char const *&filename, int &charOffset);
276: void decodeLineCol(SourceLoc loc, char const *&filename, int &line, int &col);
277:
278: // more specialized decode
279: char const *getFile(SourceLoc loc);
280: int getOffset(SourceLoc loc);
281: int getLine(SourceLoc loc);
282: int getCol(SourceLoc loc);
283:
284: // get access to the File itself, for adding #line directives
285: File *getInternalFile(char const *fname)
286: { return getFile(fname); }
287:
288: // render as sm_string in "file:line:col" format
289: sm_string getString(SourceLoc loc);
290:
291: // "line:col" format
292: sm_string getLCString(SourceLoc loc);
293: };
294:
295:
296: // singleton pointer, set automatically by the constructor
297: extern SourceLocManager *sourceLocManager;
298:
299: // dsw: So that gdb can find it please DO NOT inline this; also the
300: // unique public name is intensional: I don't want gdb doing
301: // overloading and sometimes getting it wrong, which it does
302: ELK_EXTERN sm_string locToStr(SourceLoc sl);
303:
304: inline sm_string toString(SourceLoc sl)
305: { return locToStr(sl); }
306:
307: inline sm_stringBuilder& operator<< (sm_stringBuilder &sb, SourceLoc sl)
308: { return sb << toString(sl); }
309:
310: inline sm_string toLCString(SourceLoc sl)
311: { return sourceLocManager->getLCString(sl); }
312:
313:
314: // macro for obtaining a source location that points at the
315: // point in the source code where this macro is invoked
316: #define HERE_SOURCELOC \
317: (sourceLocManager->encodeStatic(__FILE__, 0, __LINE__, 1))
318:
319:
320: // it's silly to demand mention of 'SourceLocManager' just to update
321: // the locations, esp. since SourceLoc is its own type and therefore
322: // overloading will avoid any possible collisions
323: inline SourceLoc advCol(SourceLoc base, int colOffset)
324: { return SourceLocManager::advCol(base, colOffset); }
325: inline SourceLoc advLine(SourceLoc base)
326: { return SourceLocManager::advLine(base); }
327: inline SourceLoc advText(SourceLoc base, char const *text, int textLen)
328: { return SourceLocManager::advText(base, text, textLen); }
329:
330:
331: #endif // SRCLOC_H
Start C section to elk/sm_strdict.h[1
/1
]
1: #line 5072 "./lpsrc/sm.pak"
2: // strdict.h see license.txt for copyright and terms of use
3: // sm_string dictionary
4: // (c) Scott McPeak, 2000
5:
6: // entire module is case sensitive
7:
8: #ifndef __STRDICT_H
9: #define __STRDICT_H
10:
11: #include <iostream> // std::ostream
12: #include "sm_str.h"
13: #include "sm_macros.h"
14: #include "sm_xassert.h"
15: #include "sm_typ.h"
16:
17: class StringDict {
18: private: // types
19: class Node {
20: public:
21: Node *next;
22: sm_string key, value;
23:
24: public:
25: Node(char const *k, char const *v, Node *n = NULL)
26: : next(n), key(k), value(v) {}
27: ~Node() {}
28: };
29:
30: public: // types
31: // Note: some care must be taken when dealing with Iters, because
32: // they can be invalidated when held across modifications to
33: // structure of the underlying dictionary
34: class Iter {
35: private:
36: Node *current;
37:
38: public:
39: Iter(Node *n) : current(n) {}
40: Iter(StringDict &dict) { operator=(dict.getIter()); }
41: Iter(Iter const &obj) : DMEMB(current) {}
42: Iter& operator= (Iter const &obj) { CMEMB(current); return *this; }
43:
44: bool isDone() const { return current == NULL; }
45: Iter& next() { xassert(current); current = current->next; return *this; }
46: // 'next' returns a value primarily to allow use in for-loop comma exprs
47:
48: sm_string& key() const { return current->key; }
49: sm_string& value() const { return current->value; }
50: };
51: friend class Iter;
52:
53: // iterator that can't modify the dictionary entries
54: class IterC : protected Iter {
55: public:
56: IterC(Node const *n) : Iter(const_cast<Node*>(n)) {}
57: IterC(StringDict const &dict) : Iter(const_cast<StringDict&>(dict)) {}
58: IterC(IterC const &obj) : Iter(obj) {}
59: IterC& operator= (IterC const &obj) { Iter::operator=(obj); return *this; }
60:
61: // some operations can be made available unchanged
62: Iter::isDone;
63: Iter::next;
64:
65: // others must be const-ified
66: sm_string const &key() const { return Iter::key(); }
67: sm_string const &value() const { return Iter::value(); }
68: };
69:
70: private: // data
71: Node *top; // first list node (possibly NULL)
72:
73: protected: // funcs
74: void selfCheck() const; // throw exception if invariants violated
75:
76: void verifySorted() const; // throw exception if list isn't sorted
77:
78: void /*mutable*/ sort(); // arrange nodes in alphabetically sorted order
79: // (mutable because this isn't supposed to be visible from the outside)
80:
81: // invariants:
82: // list is well-formed structurally
83:
84: public:
85: StringDict(); // initializes to empty dictionary
86: StringDict(StringDict const &obj);
87: ~StringDict();
88:
89: StringDict& operator= (StringDict const &obj);
90:
91: bool operator== (StringDict const &obj) const;
92: NOTEQUAL_OPERATOR(StringDict)
93:
94: // ------- selectors ---------
95: int size() const;
96: // retrieve # of mappings
97:
98: bool isEmpty() const;
99: // returns true if size() is 0
100:
101: bool isNotEmpty() const
102: { return !isEmpty(); }
103:
104: bool query(char const *key, sm_string &value) const;
105: // if 'key' is mapped to a value, put it into 'value' and return true;
106: // otherwise, return false
107:
108: sm_string queryf(char const *key) const;
109: // return the value corresponding to 'key', or throw an exception of it's
110: // not mapped
111:
112: bool isMapped(char const *key) const;
113: // return true if 'key' is mapped to a value
114:
115: // -------- mutators -----------
116: void add(char const *key, char const *value);
117: // add a mapping from 'key' to 'value'; 'key' must initially be unmapped
118:
119: void modify(char const *key, char const *newValue);
120: // change the existing value for 'key', which must exist, to 'newValue'
121:
122: void remove(char const *key);
123: // remove the mapping from 'key', which must exist
124:
125: void empty();
126: // remove all mappings
127:
128: // --------- iters -------------
129: Iter getIter();
130: // retrieve an iterator (the iterator remains valid only as long as
131: // the structure of the dictionary does not get modified);
132: // values will be iterated in *alphabetical* order
133:
134: IterC getIterC() const;
135: // retrieve a const iterator
136:
137: Iter find(char const *key);
138: // return an iterator pointing to 'key', or an iterator
139: // that isDone() if 'key' isn't mapped
140:
141: // ------------ misc --------------
142: INSERT_OSTREAM(StringDict)
143: sm_string toString() const;
144: };
145:
146: #endif // __STRDICT_H
Start C section to elk/sm_str.h[1
/1
]
1: #line 5219 "./lpsrc/sm.pak"
2: // str.h see license.txt for copyright and terms of use
3: // a sm_string class
4: // the representation uses just one char*, so that a smart compiler
5: // can pass the entire object as a single word
6: // Scott McPeak, 1995-2000 This file is public domain.
7:
8: #ifndef STR_H
9: #define STR_H
10:
11: // this should eventually be put someplace more general...
12: #ifndef va_copy
13: #ifdef __va_copy
14: #define va_copy(a,b) __va_copy(a,b)
15: #else
16: #define va_copy(a,b) (a)=(b)
17: #endif
18: #endif
19: // MOVE THE ABOVE TO PLACE MORE GENERAL
20:
21: #include "flx_elk_config.hpp"
22: #include "sm_typ.h"
23: #include <iostream> // std::istream, std::ostream
24: #include <stdarg.h> // va_list
25:
26: class Flatten; // flatten.h
27: class ELK_EXTERN sm_string;
28:
29: class ELK_EXTERN sm_string {
30: protected: // data
31: // 10/12/00: switching to never letting s be NULL
32: char *s; // sm_string contents; never NULL
33: static char * const empty; // a global ""; should never be modified
34:
35: protected: // funcs
36: void dup(char const *source); // copies, doesn't dealloc first
37: void kill(); // dealloc if str != 0
38:
39: public: // funcs
40: sm_string(sm_string const &src) { dup(src.s); }
41: sm_string(char const *src) { dup(src); }
42: sm_string(char const *src, int length); // grab a subsm_string
43: sm_string(int length) { s=empty; setlength(length); }
44: sm_string() { s=empty; }
45:
46: ~sm_string() { kill(); }
47:
48: sm_string(Flatten&);
49: void xfer(Flatten &flat);
50:
51: // simple queries
52: int length() const; // returns number of non-null chars in the sm_string; length of "" is 0
53: bool isempty() const { return s[0]==0; }
54: bool contains(char c) const;
55:
56: // array-like access
57: char& operator[] (int i) { return s[i]; }
58: char operator[] (int i) const { return s[i]; }
59:
60: // subsm_string
61: sm_string subsm_string(int startIndex, int length) const;
62:
63: // conversions
64: //operator char* () { return s; } // ambiguities...
65: operator char const* () const { return s; }
66: char *pchar() { return s; }
67: char const *pcharc() const { return s; }
68:
69: // assignment
70: sm_string& operator=(sm_string const &src)
71: { if (&src != this) { kill(); dup(src.s); } return *this; }
72: sm_string& operator=(char const *src)
73: { if (src != s) { kill(); dup(src); } return *this; }
74:
75: // allocate 'newlen' + 1 bytes (for null); initial contents is ""
76: sm_string& setlength(int newlen);
77:
78: // comparison; return value has same meaning as strcmp's return value:
79: // <0 if *this < src
80: // 0 if *this == src
81: // >0 if *this > src
82: int compareTo(sm_string const &src) const;
83: int compareTo(char const *src) const;
84: bool equals(char const *src) const { return compareTo(src) == 0; }
85:
86: #define MAKEOP(op) \
87: bool operator op (sm_string const &src) const { return compareTo(src) op 0; } \
88: /*bool operator op (const char *src) const { return compareTo(src) op 0; }*/ \
89: /* killed stuff with char* because compilers are too flaky; use compareTo */
90: MAKEOP(==) MAKEOP(!=)
91: MAKEOP(>=) MAKEOP(>)
92: MAKEOP(<=) MAKEOP(<)
93: #undef MAKEOP
94:
95: // concatenation (properly handles sm_string growth)
96: // uses '&' instead of '+' to avoid char* coercion problems
97: sm_string operator& (sm_string const &tail) const;
98: sm_string& operator&= (sm_string const &tail);
99:
100: // input/output
101: friend std::istream& operator>> (std::istream &is, sm_string &obj)
102: { obj.readline(is); return is; }
103: friend std::ostream& operator<< (std::ostream &os, sm_string const &obj)
104: { obj.write(os); return os; }
105:
106: // note: the read* functions are currently implemented in a fairly
107: // inefficient manner (one char at a time)
108:
109: void readdelim(std::istream &is, char const *delim);
110: // read from is until any character in delim is encountered; consumes that
111: // character, but does not put it into the sm_string; if delim is null or
112: // empty, reads until EOF
113:
114: void readall(std::istream &is) { readdelim(is, NULL); }
115: // read all remaining chars of is into this
116:
117: void readline(std::istream &is) { readdelim(is, "\n"); }
118: // read a line from input stream; consumes the \n, but doesn't put it into
119: // the sm_string
120:
121: void write(std::ostream &os) const;
122: // writes all stored characters (but not '\0')
123:
124: // debugging
125: void selfCheck() const;
126: // fail an assertion if there is a problem
127: };
128:
129:
130: // replace() and trimWhiteSpace() have been moved to strutil.h
131:
132:
133: // this class is specifically for appending lots of things
134: class ELK_EXTERN sm_stringBuilder : public sm_string {
135: protected:
136: enum { EXTRA_SPACE = 30 }; // extra space allocated in some situations
137: char *end; // current end of the sm_string (points to the NUL character)
138: int size; // amount of space (in bytes) allocated starting at 's'
139:
140: protected:
141: void init(int initSize);
142: void dup(char const *src);
143:
144: public:
145: sm_stringBuilder(int length=0); // creates an empty sm_string
146: sm_stringBuilder(char const *str);
147: sm_stringBuilder(char const *str, int length);
148: sm_stringBuilder(sm_string const &str) { dup((char const*)str); }
149: sm_stringBuilder(sm_stringBuilder const &obj) { dup((char const*)obj); }
150: ~sm_stringBuilder() {}
151:
152: sm_stringBuilder& operator= (char const *src);
153: sm_stringBuilder& operator= (sm_string const &s) { return operator= ((char const*)s); }
154: sm_stringBuilder& operator= (sm_stringBuilder const &s) { return operator= ((char const*)s); }
155:
156: int length() const { return end-s; }
157: bool isempty() const { return length()==0; }
158:
159: sm_stringBuilder& setlength(int newlen); // change length, forget current data
160:
161: // make sure we can store 'someLength' non-null chars; grow if necessary
162: void ensure(int someLength) { if (someLength >= size) { grow(someLength); } }
163:
164: // grow the sm_string's length (retaining data); make sure it can hold at least
165: // 'newMinLength' non-null chars
166: void grow(int newMinLength);
167:
168: // this can be useful if you modify the sm_string contents directly..
169: // it's not really the intent of this class, though
170: void adjustend(char* newend);
171:
172: // make the sm_string be the empty sm_string, but don't change the
173: // allocated space
174: void clear() { adjustend(s); }
175:
176: // concatenation, which is the purpose of this class
177: sm_stringBuilder& operator&= (char const *tail);
178:
179: // useful for appending subsm_strings or sm_strings with NUL in them
180: void append(char const *tail, int length);
181:
182: // append a given number of spaces; meant for contexts where we're
183: // building a multi-line sm_string; returns '*this'
184: sm_stringBuilder& indent(int amt);
185:
186: // sort of a mixture of Java compositing and C++ i/o strstream
187: // (need the coercion versions (like int) because otherwise gcc
188: // spews mountains of f-ing useless warnings)
189: sm_stringBuilder& operator << (char const *text) { return operator&=(text); }
190: sm_stringBuilder& operator << (char c);
191: sm_stringBuilder& operator << (unsigned char c) { return operator<<((char)c); }
192: sm_stringBuilder& operator << (long i);
193: sm_stringBuilder& operator << (unsigned long i);
194: sm_stringBuilder& operator << (int i) { return operator<<((long)i); }
195: sm_stringBuilder& operator << (unsigned i) { return operator<<((unsigned long)i); }
196: sm_stringBuilder& operator << (short i) { return operator<<((long)i); }
197: sm_stringBuilder& operator << (unsigned short i) { return operator<<((long)i); }
198: sm_stringBuilder& operator << (float d);
199: sm_stringBuilder& operator << (double d);
200: sm_stringBuilder& operator << (void *ptr); // inserts address in hex
201: #ifdef HAVE_LONGLONG
202: sm_stringBuilder& operator << (long long i);
203: sm_stringBuilder& operator << (unsigned long long i);
204: #endif
205: #ifdef HAVE_LONGDOUBLE
206: sm_stringBuilder& operator << (long double d);
207: #endif
208: #ifndef LACKS_BOOL
209: sm_stringBuilder& operator << (bool b) { return operator<<((long)b); }
210: #endif // LACKS_BOOL
211:
212: // useful in places where long << expressions make it hard to
213: // know when arguments will be evaluated, but order does matter
214: typedef sm_stringBuilder& (*Manipulator)(sm_stringBuilder &sb);
215: sm_stringBuilder& operator<< (Manipulator manip);
216:
217: // stream readers
218: friend std::istream& operator>> (std::istream &is, sm_stringBuilder &sb)
219: { sb.readline(is); return is; }
220: void readall(std::istream &is) { readdelim(is, NULL); }
221: void readline(std::istream &is) { readdelim(is, "\n"); }
222:
223: void readdelim(std::istream &is, char const *delim);
224:
225: // an experiment: hex formatting (something I've sometimes done by resorting
226: // to sprintf in the past)
227: class Hex {
228: public:
229: unsigned long value;
230:
231: Hex(unsigned long v) : value(v) {}
232: Hex(Hex const &obj) : value(obj.value) {}
233: };
234: sm_stringBuilder& operator<< (Hex const &h);
235: #define SBHex sm_stringBuilder::Hex
236: };
237:
238:
239: // the real strength of this entire module: construct sm_strings in-place
240: // using the same syntax as C++ istd::ostreams. e.g.:
241: // puts(sm_stringb("x=" << x << ", y=" << y));
242: #define sm_stringb(expr) (sm_stringBuilder() << expr)
243:
244: // experimenting with dropping the () in favor of <<
245: // (the "c" can be interpreted as "constructor", or maybe just
246: // the successor to "b" above)
247: #define sm_stringc sm_stringBuilder()
248:
249:
250: // experimenting with using toString as a general method for datatypes
251: sm_string toString(int i);
252: sm_string toString(unsigned i);
253: sm_string toString(char c);
254: sm_string toString(long i);
255: sm_string toString(char const *str);
256: sm_string toString(float f);
257:
258:
259: // printf-like construction of a sm_string; often very convenient, since
260: // you can use any of the formatting characters (like %X) that your
261: // libc's sprintf knows about
262: sm_string sm_stringf(char const *format, ...);
263: sm_string vsm_stringf(char const *format, va_list args);
264:
265:
266: #endif // STR_H
Start C section to elk/sm_strhash.h[1
/1
]
1: #line 5486 "./lpsrc/sm.pak"
2: // strhash.h see license.txt for copyright and terms of use
3: // hash table mapping sm_strings to arbitrary pointers, where
4: // the stored pointers can be used to derive the key, and
5: // cannot be NULL
6:
7: #ifndef STRHASH_H
8: #define STRHASH_H
9:
10: #include "sm_hashtbl.h"
11:
12: class StringHash : private HashTable {
13: public: // types
14: // given a stored data pointer, retrieve the associated key
15: typedef char const* (*GetKeyFn)(void *data);
16:
17: private: // funcs
18: // disallowed
19: StringHash(StringHash&);
20: void operator=(StringHash&);
21: void operator==(StringHash&);
22:
23: public: // funcs
24: StringHash(GetKeyFn getKey);
25: ~StringHash();
26:
27: // utilities
28: static unsigned coreHash(char const *key);
29: static bool keyCompare(char const *key1, char const *key2);
30:
31: // return # of mapped entries
32: int getNumEntries() const
33: { return HashTable::getNumEntries(); }
34:
35: // if this key has a mapping, return it; otherwise,
36: // return NULL
37: void *get(char const *key) const
38: { return HashTable::get(key); }
39:
40: // add a mapping from 'key' to 'value'; there must not already
41: // be a mapping for this key
42: void add(char const *key, void *value)
43: { HashTable::add(key, value); }
44:
45: // remove the mapping for 'key' -- it must exist
46: void remove(char const *key)
47: { HashTable::remove(key); }
48:
49: // drop all entries
50: void empty()
51: { HashTable::empty(); }
52:
53: // check the data structure's invariants, and throw an exception
54: // if there is a problem
55: void selfCheck() const
56: { HashTable::selfCheck(); }
57: };
58:
59:
60: // type-safe template wrapper
61: template <class T>
62: class TStringHash : public StringHash {
63: public: // types
64: typedef char const* (*GetKeyFn)(T *data);
65:
66: public:
67: TStringHash(GetKeyFn fn) : StringHash((StringHash::GetKeyFn)fn) {}
68: ~TStringHash() {}
69:
70: int getNumEntries() const { return StringHash::getNumEntries(); }
71: T *get(char const *key) const { return (T*)StringHash::get(key); }
72: void add(char const *key, T *value) { StringHash::add(key, (void*)value); }
73: void remove(char const *key) { StringHash::remove(key); }
74: void empty() { StringHash::empty(); }
75: };
76:
77:
78: #endif // STRHASH_H
Start C section to elk/sm_stringset.h[1
/1
]
1: #line 5565 "./lpsrc/sm.pak"
2: // sm_stringset.h see license.txt for copyright and terms of use
3: // set of character sm_strings
4:
5: #ifndef STRINGSET_H
6: #define STRINGSET_H
7:
8: #include "sm_strsobjdict.h"
9:
10: class StringSet {
11: private: // data
12: // represent using a dictionary of pointers to nothing
13: StringSObjDict<int> elts;
14:
15: public: // funcs
16: StringSet() : elts() {}
17: ~StringSet();
18:
19: // # elts in the set
20: int size() const { return elts.size(); }
21:
22: bool isEmpty() const { return elts.isEmpty(); }
23: bool isNotEmpty() const { return elts.isNotEmpty(); }
24:
25: // true if elt is in the set
26: bool contains(char const *elt) const { return elts.isMapped(elt); }
27:
28: // add elt to the set; ok if it's already there
29: void add(char const *elt);
30:
31: // remove elt from the set; ok if it's not there now
32: void remove(char const *elt);
33:
34: // empty the set
35: void empty() { elts.empty(); }
36: };
37:
38: #endif // STRINGSET_H
Start C section to elk/sm_strobjdict.h[1
/1
]
1: #line 5604 "./lpsrc/sm.pak"
2: // strobjdict.h see license.txt for copyright and terms of use
3: // dictionary of objects, indexed by sm_string (case-sensitive)
4: // (c) Scott McPeak, 2000
5:
6: #ifndef __STROBJDICT_H
7: #define __STROBJDICT_H
8:
9: #include "sm_svdict.h"
10:
11:
12: // the dictionary object is considered to own all of the things
13: // contained, so constness means constness of the contained objects
14: // as well as the mapping from sm_strings to them
15:
16: template <class T>
17: class StringObjDict {
18: public: // types
19: // 'foreach' iterator functions
20: typedef bool (*ForeachCFn)(sm_string const &key, T const *value, void *extra);
21: typedef bool (*ForeachFn)(sm_string const &key, T * /*serf*/ value, void *extra);
22:
23: // external iterator
24: class Iter {
25: private:
26: StringVoidDict::IterC iter;
27:
28: public:
29: Iter(StringObjDict const &dict) : iter(dict.dict) {}
30: Iter(Iter const &obj) : DMEMB(iter) {}
31: Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
32:
33: bool isDone() const { return iter.isDone(); }
34: Iter& next() { iter.next(); return *this; }
35:
36: sm_string const &key() const { return iter.key(); }
37: T const *&value() const { return (T const *&)iter.value(); }
38: };
39: friend class Iter;
40:
41: private: // data
42: // underlying dictionary functionality
43: StringVoidDict dict;
44:
45: private: // funcs
46: // disallowed
47: StringObjDict(StringObjDict const &obj);
48: StringObjDict& operator= (StringObjDict const &obj);
49: bool operator== (StringObjDict const &obj) const;
50:
51: public: // funcs
52: StringObjDict() : dict() {}
53: ~StringObjDict() { empty(); }
54:
55: // due to similarity with StringVoidDict, see svdict.h for
56: // details on these functions' interfaces
57:
58: // ------- selectors ---------
59: int size() const { return dict.size(); }
60:
61: bool isEmpty() const { return dict.isEmpty(); }
62: bool isNotEmpty() const { return !isEmpty(); }
63:
64: bool queryC(char const *key, T const *&value) const { return dict.query(key, (void*&)value); }
65: bool query(char const *key, T *&value) { return queryC(key, (T const*&)value); }
66:
67: T const *queryfC(char const *key) const { return (T const *)dict.queryf(key); }
68: T * /*serf*/ queryf(char const *key) { return (T*)dict.queryf(key); }
69: T * /*serf*/ queryif(char const *key) { return (T*)dict.queryif(key); }
70:
71: bool isMapped(char const *key) const { return dict.isMapped(key); }
72:
73: // -------- mutators -----------
74: void add(char const *key, T *value) { dict.add(key, value); }
75:
76: T * /*owner*/ remove(char const *key) { return (T*)dict.remove(key); }
77: void deleteAt(char const *key) { deleteObject(remove(key)); }
78:
79: void empty() { dict.emptyAndDel((StringVoidDict::DelFn)deleteObject); }
80:
81: // --------- iters -------------
82: void foreachC(ForeachCFn func, void *extra=NULL) const
83: { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
84: void foreach(ForeachFn func, void *extra=NULL)
85: { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
86:
87: // ------------ misc --------------
88: static void deleteObject(T *obj);
89: };
90:
91:
92: template <class T>
93: STATICDEF void StringObjDict<T>::deleteObject(T *obj)
94: {
95: delete obj;
96: }
97:
98: #endif // __STROBJDICT_H
Start C section to elk/sm_strsobjdict.h[1
/1
]
1: #line 5703 "./lpsrc/sm.pak"
2: // strsobjdict.h see license.txt for copyright and terms of use
3: // dictionary of *serf* pointers to objects, indexed by sm_string (case-sensitive)
4: // (c) Scott McPeak, 2000
5:
6: // created by copying strobjdict and modifying.. nonideal..
7:
8: #ifndef __STRSOBJDICT_H
9: #define __STRSOBJDICT_H
10:
11: #include "sm_svdict.h"
12:
13:
14: // since the dictionary does not own the pointed-to objects,
15: // it has the same constness model as StringVoidDict, namely
16: // that const means the *mapping* is constant but not the
17: // pointed-to objects
18:
19: template <class T>
20: class StringSObjDict {
21: public: // types
22: // 'foreach' iterator functions
23: typedef bool (*ForeachFn)(sm_string const &key, T *value, void *extra);
24:
25: // external iterator
26: class Iter {
27: private:
28: StringVoidDict::Iter iter;
29:
30: public:
31: Iter(StringSObjDict &dict) : iter(dict.dict) {}
32: Iter(Iter const &obj) : DMEMB(iter) {}
33: Iter& operator= (Iter const &obj) { CMEMB(iter); return *this; }
34:
35: bool isDone() const { return iter.isDone(); }
36: Iter& next() { iter.next(); return *this; }
37:
38: sm_string const &key() const { return iter.key(); }
39: T *&value() const { return (T *&)iter.value(); }
40:
41: //int private_getCurrent() const { return iter.private_getCurrent(); }
42: void *private_getCurrent() const { return iter.private_getCurrent(); }
43: };
44: friend class Iter;
45:
46: class IterC {
47: private:
48: StringVoidDict::IterC iter;
49:
50: public:
51: IterC(StringSObjDict const &dict) : iter(dict.dict) {}
52: IterC(IterC const &obj) : DMEMB(iter) {}
53: IterC& operator= (IterC const &obj) { CMEMB(iter); return *this; }
54:
55: bool isDone() const { return iter.isDone(); }
56: IterC& next() { iter.next(); return *this; }
57:
58: sm_string const &key() const { return iter.key(); }
59: T *value() const { return (T *)iter.value(); }
60:
61: //int private_getCurrent() const { return iter.private_getCurrent(); }
62: void *private_getCurrent() const { return iter.private_getCurrent(); }
63: };
64: friend class IterC;
65:
66: private: // data
67: // underlying dictionary functionality
68: StringVoidDict dict;
69:
70: public: // funcs
71: StringSObjDict() : dict() {}
72: StringSObjDict(StringSObjDict const &obj) : dict(obj.dict) {}
73: ~StringSObjDict() {}
74:
75: // comparison and assignment use *pointer* comparison/assignment
76:
77: StringSObjDict& operator= (StringSObjDict const &obj) { dict = obj.dict; return *this; }
78:
79: bool operator== (StringSObjDict const &obj) const { return dict == obj.dict; }
80: NOTEQUAL_OPERATOR(StringSObjDict)
81:
82: // due to similarity with StringVoidDict, see svdict.h for
83: // details on these functions' interfaces
84:
85: // ------- selectors ---------
86: int size() const { return dict.size(); }
87:
88: bool isEmpty() const { return dict.isEmpty(); }
89: bool isNotEmpty() const { return !isEmpty(); }
90:
91: bool query(char const *key, T *&value) const { return dict.query(key, (void*&)value); }
92: T *queryf(char const *key) const { return (T*)dict.queryf(key); }
93: T *queryif(char const *key) const { return (T*)dict.queryif(key); }
94:
95: bool isMapped(char const *key) const { return dict.isMapped(key); }
96:
97: // -------- mutators -----------
98: void add(char const *key, T *value) { dict.add(key, (void*)value); }
99:
100: T *modify(char const *key, T *newValue) { return (T*)dict.modify(key, (void*)newValue); }
101:
102: T *remove(char const *key) { return (T*)dict.remove(key); }
103:
104: void empty() { dict.empty(); }
105:
106: // --------- iters -------------
107: void foreach(ForeachFn func, void *extra=NULL) const
108: { dict.foreach((StringVoidDict::ForeachFn)func, extra); }
109:
110: // debugging
111: //int private_getTopAddr() const { return dict.private_getTopAddr(); }
112: void *private_getTopAddr() const { return dict.private_getTopAddr(); }
113: };
114:
115:
116: #endif // __STRSOBJDICT_H
Start C section to elk/sm_strtokp.h[1
/1
]
1: #line 5820 "./lpsrc/sm.pak"
2: // strtokp.h see license.txt for copyright and terms of use
3: // using std::strtok to parse an entire sm_string at once
4: // Scott McPeak, 1997 This file is public domain.
5:
6: #ifndef __STRTOKP_H
7: #define __STRTOKP_H
8:
9: #include "sm_str.h"
10: #include <cstring> // std::strlen
11:
12: class StrtokParse {
13: sm_string buf; // locally allocated storage
14: int _tokc; // # of tokens found
15: char **_tokv; // array of tokens themselves
16:
17: private:
18: void validate(int which) const;
19: // throw an exception if which is invalid token
20:
21: public:
22: StrtokParse(char const *str, char const *delim);
23: // parse 'str' into tokens delimited by chars from 'delim'
24:
25: ~StrtokParse();
26: // clean up'
27:
28: int tokc() const { return _tokc; }
29: operator int () const { return tokc(); }
30: // simple count of available tokens
31:
32: char const *tokv(int which) const; // may throw xArrayBounds
33: char const* operator[] (int which) const { return tokv(which); }
34: // access to tokens; must make local copies to modify
35:
36: sm_string reassemble(int firstTok, int lastTok, char const *originalString) const;
37: // return the subsm_string of the original sm_string spanned by the
38: // given range of tokens; if firstTok==lastTok, only that token is
39: // returned (without any separators); must be that firstTok <=
40: // lastTok
41:
42: sm_string join(int firstTok, int lastTok, char const *separator) const;
43: // return a sm_string created by concatenating the given range of tokens
44: // together with 'separator' in between them
45:
46: int offset(int which) const;
47: // return a value that, when added to the original 'str' parameter,
48: // yields a pointer to where tokv(which) is, as a subsm_string, in that sm_string
49:
50: int offsetAfter(int which) const
51: { return offset(which) + std::strlen(tokv(which)); }
52: // offset for character just beyond last one in tokv (should be either
53: // a delimiter character, or 0)
54:
55: char **spawn_tokv_array() { return _tokv; }
56: // this is defined because it makes it convenient to generate
57: // spawn arguments, and should be limited to use for that purpose
58: // (because it exposes internal representation which is in
59: // principle subject to change)
60: };
61:
62: #endif // __STRTOKP_H
63:
Start C section to elk/sm_strutil.h[1
/1
]
1: #line 5884 "./lpsrc/sm.pak"
2: // strutil.h see license.txt for copyright and terms of use
3: // various sm_string utilities built upon the 'str' module
4: // Scott McPeak, July 2000
5:
6: #ifndef STRUTIL_H
7: #define STRUTIL_H
8:
9: #include "sm_str.h"
10: #include <stdio.h> // FILE
11:
12: // direct sm_string replacement, replacing instances of oldstr with newstr
13: // (newstr may be "")
14: sm_string replace(char const *src, char const *oldstr, char const *newstr);
15:
16: // works like unix "tr": the source sm_string is translated character-by-character,
17: // with occurrences of 'srcchars' replaced by corresponding characters from
18: // 'destchars'; further, either set may use the "X-Y" notation to denote a
19: // range of characters from X to Y
20: sm_string translate(char const *src, char const *srcchars, char const *destchars);
21:
22: // a simple example of using translate; it was originally inline, but a bug
23: // in egcs made me move it out of line
24: sm_string sm_stringToupper(char const *src);
25: // { return translate(src, "a-z", "A-Z"); }
26:
27:
28: // remove any whitespace at the beginning or end of the sm_string
29: sm_string trimWhitespace(char const *str);
30:
31:
32: // encode a block of bytes as a sm_string with C backslash escape
33: // sequences (but without the opening or closing quotes)
34: sm_string encodeWithEscapes(char const *src, int len);
35:
36: // safe when the text has no NUL characters
37: sm_string encodeWithEscapes(char const *src);
38:
39: // adds the quotes too
40: sm_string quoted(char const *src);
41:
42:
43: // decode an escaped sm_string; throw xFormat if there is a problem
44: // with the escape syntax; if 'delim' is specified, it will also
45: // make sure there are no unescaped instances of that
46: void decodeEscapes(sm_string &dest, int &destLen, char const *src,
47: char delim = 0, bool allowNewlines=false);
48:
49: // given a sm_string with quotes and escapes, yield just the sm_string;
50: // works if there are no escaped NULs
51: sm_string parseQuotedString(char const *text);
52:
53:
54: // this probably belongs in a dedicated module for time/date stuff..
55: // returns asctime(localtime(time))
56: sm_string localTimeString();
57:
58:
59: // given a directory name like "a/b/c", return "c"
60: // renamed from 'basename' because of conflict with something in sm_string.h
61: sm_string sm_basename(char const *src);
62:
63: // given a directory name like "a/b/c", return "a/b"; if 'src' contains
64: // no slashes at all, return "."
65: sm_string dirname(char const *src);
66:
67:
68: // return 'prefix', pluralized if n!=1; for example
69: // plural(1, "egg") yields "egg", but
70: // plural(2, "egg") yields "eggs";
71: // it knows about a few irregular pluralizations (see the source),
72: // and the expectation is I'll add more irregularities as I need them
73: sm_string plural(int n, char const *prefix);
74:
75: // same as 'plural', but with the sm_stringized version of the number:
76: // pluraln(1, "egg") yields "1 egg", and
77: // pluraln(2, "eggs") yields "2 eggs"
78: sm_string pluraln(int n, char const *prefix);
79:
80:
81: // Sometimes it's useful to store a sm_string value in a static buffer;
82: // most often this is so 'gdb' can see the result. This function just
83: // copies its input into a static buffer (of unspecified length, but
84: // it checks bounds internally), and returns a pointer to that buffer.
85: char *copyToStaticBuffer(char const *src);
86:
87:
88: // true if the first part of 'str' matches 'prefix'
89: bool prefixEquals(char const *str, char const *prefix);
90:
91: // and similar for last part
92: bool suffixEquals(char const *str, char const *suffix);
93:
94:
95: // read/write sm_strings <-> files
96: void writeStringToFile(char const *str, char const *fname);
97: sm_string readStringFromFile(char const *fname);
98:
99:
100: // read the next line from a FILE* (e.g. an AutoFILE); the
101: // newline is returned if it is present (you can use 'chomp'
102: // to remove it); returns false (and "") on EOF
103: bool readLine(sm_string &dest, FILE *fp);
104:
105:
106: // like perl 'chomp': remove a final newline if there is one
107: sm_string chomp(char const *src);
108:
109:
110: #endif // STRUTIL_H
Start C section to elk/sm_svdict.h[1
/1
]
1: #line 5995 "./lpsrc/sm.pak"
2: // svdict.h see license.txt for copyright and terms of use
3: // dictionary of void*, indexed by sm_string (case-sensitive)
4: // (c) Scott McPeak, 2000
5:
6: // created by modifying strdict; at some point strdict should
7: // be rewritten to use this module
8:
9: #ifndef __SVDICT_H
10: #define __SVDICT_H
11:
12: #include <iostream> // std::ostream
13: #include "sm_str.h"
14: #include "sm_macros.h"
15: #include "sm_xassert.h"
16: #include "sm_typ.h"
17: #include "sm_strhash.h"
18:
19:
20: // constness: for this class, 'const' means the *mapping* from sm_string
21: // to void* won't change; but I don't prevent the thing pointed-at
22: // by the void* from changing (would like multiple levels of constness..)
23:
24: class StringVoidDict {
25: private: // types
26: // 3/16/03: I believe the reason I stored the information both in a
27: // hash table and in a linked list is to be able to support efficient
28: // alphabetical iteration
29: class Node {
30: public:
31: Node *next;
32: sm_string key;
33: void *value;
34:
35: public:
36: Node(char const *k, void *v, Node *n = NULL)
37: : next(n), key(k), value(v) {}
38: ~Node() {}
39:
40: static char const *getKey(Node const *n);
41: };
42:
43: public: // types
44: // function for general foreach; return false to continue,
45: // true to stop iterating
46: typedef bool (*ForeachFn)(sm_string const &key, void *value, void *extra);
47:
48: // function type to delete void*s while emptying
49: typedef void (*DelFn)(void *value);
50:
51: // Note: some care must be taken when dealing with Iters, because
52: // they can be invalidated when held across modifications to
53: // structure of the underlying dictionary
54: class Iter {
55: private:
56: Node *current;
57:
58: public:
59: Iter(Node *n) : current(n) {}
60: Iter(StringVoidDict &dict) { operator=(dict.getIter()); }
61: Iter(Iter const &obj) : DMEMB(current) {}
62: Iter& operator= (Iter const &obj) { CMEMB(current); return *this; }
63:
64: bool isDone() const { return current == NULL; }
65: Iter& next() { xassert(current); current = current->next; return *this; }
66: // 'next' returns a value primarily to allow use in for-loop comma exprs
67:
68: sm_string &key() const { return current->key; }
69: void *&value() const { return current->value; }
70:
71: //int private_getCurrent() const { return (int)current; }
72: void *private_getCurrent() const { return current; }
73: };
74: friend class Iter;
75:
76: // iterator that can't modify the dictionary entries
77: class IterC : protected Iter {
78: public:
79: IterC(Node const *n) : Iter(const_cast<Node*>(n)) {}
80: IterC(StringVoidDict const &dict) : Iter(const_cast<StringVoidDict&>(dict)) {}
81: IterC(IterC const &obj) : Iter(obj) {}
82: IterC& operator= (IterC const &obj) { Iter::operator=(obj); return *this; }
83:
84: // some operations can be made available unchanged
85: Iter::isDone;
86: Iter::next;
87: Iter::private_getCurrent;
88:
89: // others must be const-ified
90: sm_string const &key() const { return Iter::key(); }
91: void const *&value() const { return (void const *&)Iter::value(); }
92: };
93:
94: private: // data
95: // first list node (possibly NULL)
96: Node *top;
97:
98: // hash table to improve lookup performance
99: StringHash hash;
100:
101: // invariants:
102: // list is well-formed structurally
103: // every node is in the hash table, and vice versa
104:
105: protected: // funcs
106: void selfCheck() const; // throw exception if invariants violated
107:
108: void verifySorted() const; // throw exception if list isn't sorted
109:
110: void /*mutable*/ sort(); // arrange nodes in alphabetically sorted order
111: // (mutable because this isn't supposed to be visible from the outside)
112:
113: public:
114: StringVoidDict(); // initializes to empty dictionary
115: StringVoidDict(StringVoidDict const &obj);
116: ~StringVoidDict();
117:
118: StringVoidDict& operator= (StringVoidDict const &obj);
119:
120: // comparison is done by pointer equality of void*
121: bool operator== (StringVoidDict const &obj) const;
122: NOTEQUAL_OPERATOR(StringVoidDict)
123:
124: // ------- selectors ---------
125: int size() const;
126: // retrieve # of mappings
127:
128: bool isEmpty() const;
129: // returns true if size() is 0
130:
131: bool isNotEmpty() const
132: { return !isEmpty(); }
133:
134: bool query(char const *key, void *&value) const;
135: // if 'key' is mapped to a value, put it into 'value' and return true;
136: // otherwise, return false
137:
138: void *queryf(char const *key) const;
139: // return the value corresponding to 'key', or throw an exception of it's
140: // not mapped
141:
142: void *queryif(char const *key) const;
143: // return the value corresponding to 'key', or return NULL
144:
145: bool isMapped(char const *key) const;
146: // return true if 'key' is mapped to a value
147:
148: // -------- mutators -----------
149: void add(char const *key, void *value);
150: // add a mapping from 'key' to 'value'; 'key' must initially be unmapped
151:
152: void *modify(char const *key, void *newValue);
153: // change the existing value for 'key', which must exist, to 'newValue';
154: // the old value is returned
155:
156: void *remove(char const *key);
157: // remove the mapping from 'key', which must exist; it is returned
158:
159: void emptyAndDel(DelFn func);
160: // apply the deletion func to all values, during empty()
161:
162: void empty();
163: // remove all mappings
164:
165: // --------- iters -------------
166: Iter getIter();
167: // retrieve an iterator (the iterator remains valid only as long as
168: // the structure of the dictionary does not get modified);
169: // values will be iterated in *alphabetical* order
170:
171: IterC getIterC() const;
172: // retrieve a const iterator
173:
174: Iter find(char const *key);
175: // return an iterator pointing to 'key', or an iterator
176: // that isDone() if 'key' isn't mapped
177:
178: void foreach(ForeachFn func, void *extra=NULL) const;
179: // apply 'func' to every mapping, in alphabetical order
180:
181: // ------------ misc --------------
182: INSERT_OSTREAM(StringVoidDict)
183: sm_string toString() const;
184:
185: // debugging...
186: //int private_getTopAddr() const { return (int)top; }
187: void *private_getTopAddr() const { return top; }
188: };
189:
190: #endif // __SVDICT_H
Start C section to elk/sm_syserr.h[1
/1
]
1: #line 6186 "./lpsrc/sm.pak"
2: // syserr.h see license.txt for copyright and terms of use
3: // error-reporting exception for system calls that fail
4: // Scott McPeak, 1999 This file is public domain.
5:
6: // The intent here is to provide a way for portable *handling* of errors
7: // that are generated by nonportable code.
8:
9: #ifndef __SYSERR_H
10: #define __SYSERR_H
11:
12: #include "sm_exc.h"
13:
14: class xSysError : public xBase {
15: private: // data
16: // error sm_strings for Reasons
17: static char const * const reasonStrings[];
18:
19: public: // data
20: // portable failure reasons (modelled loosely on errno.h)
21: // it is anticipated that, as certain errors become important on certain
22: // platforms, that this list will be extended as necessary
23: enum Reason {
24: R_NO_ERROR, // no error occurred
25: R_FILE_NOT_FOUND,
26: R_PATH_NOT_FOUND,
27: R_ACCESS_DENIED,
28: R_OUT_OF_MEMORY,
29: R_SEGFAULT, // invalid address / pointer
30: R_FORMAT, // bad data format
31: R_INVALID_ARGUMENT,
32: R_READ_ONLY,
33: R_ALREADY_EXISTS,
34: R_AGAIN, // resource temporarily unavailable
35: R_BUSY, // resource busy
36: R_INVALID_FILENAME, // too long, bad chars, etc.
37: R_UNKNOWN, // OS-specific, can't find out, just don't know, etc.
38: NUM_REASONS // (must be last item in list)
39: } reason;
40:
41: // reason sm_string that corresponds to 'reason'
42: char const * const reasonString;
43:
44: // nonportable error code (errno on Unix, GetLastError() on Windows)
45: // (value is 0 when we don't have this information)
46: int sysErrorCode;
47:
48: // reason sm_string given by the OS, if any (might be NULL)
49: sm_string sysReasonString;
50:
51: // name of syscall or API function name
52: sm_string syscallName;
53:
54: // error context; what was being done (e.g., "opening an.important.file")
55: sm_string context;
56:
57: public: // funcs
58: xSysError(Reason r, int sysCode, char const *sysReason,
59: char const *syscall, char const *ctx);
60: xSysError(xSysError const &obj);
61: ~xSysError();
62:
63: // mapping functions used internally
64: static int getSystemErrorCode();
65: // retrieve the error code used by local convention
66: // [nonportable implementation]
67:
68: static Reason portablize(int sysErrorCode, sm_string &sysReason);
69: // return a portable equivalent of a system error code;
70: // returns R_UNKNOWN if the code is esoteric or invalid;
71: // sets 'sysmsg' to the system's message sm_string, if possible
72: // [nonportable implementation]
73:
74: static char const *getReasonString(Reason r);
75: // translate a Reason into a sm_string (if r is invalid, a sm_string
76: // saying to will be returned)
77:
78: static sm_string constructWhyString(Reason r, char const *sysReason,
79: char const *syscall, char const *ctx);
80: // construct the sm_string we throw as the 'why' of xBase; if ctx is NULL,
81: // the sm_string doesn't include it
82:
83: static void xsyserror(char const *syscallName, char const *context);
84: // does the throw
85: };
86:
87:
88: // function that does the throw
89: inline void xsyserror(char const *syscallName, char const *context = NULL)
90: {
91: xSysError::xsyserror(syscallName, context);
92: }
93:
94:
95: // get a representative sm_string, for logging etc.
96: sm_string sysErrorCodeString(int systemErrorCode, char const *syscallName,
97: char const *context=NULL);
98:
99: inline sm_string sysErrorString(char const *syscallName, char const *context=NULL)
100: {
101: return sysErrorCodeString(xSysError::getSystemErrorCode(),
102: syscallName, context);
103: }
104:
105:
106: #endif // __SYSERR_H
107:
Start C section to elk/sm_taillist.h[1
/1
]
1: #line 6294 "./lpsrc/sm.pak"
2: // taillist.h; see license.txt for copyright and terms of use
3: // list wrapper around VoidTailList in the spirit of ASTList, but doesn't own
4:
5: // taken almost verbatim from asttlist.h in smbase
6:
7: #ifndef TAILLIST_H
8: #define TAILLIST_H
9:
10: #include "sm_vdtllist.h"
11:
12: template <class T> class TailListIter;
13: template <class T> class TailListIterNC;
14:
15: // a list which does not own the items in it (will NOT deallocate
16: // them), and has constant-time access to the last element
17: template <class T>
18: class TailList {
19: private:
20: friend class TailListIter<T>;
21: friend class TailListIterNC<T>;
22:
23: protected:
24: VoidTailList list; // list itself
25:
26: private:
27: TailList(TailList const &obj); // not allowed
28:
29: public:
30: TailList() : list() {}
31: ~TailList() { }
32:
33: // ctor to make singleton list; often quite useful
34: TailList(T *elt) : list() { prepend(elt); }
35:
36: // stealing ctor; among other things, since &src->list is assumed to
37: // point at 'src', this class can't have virtual functions;
38: // these ctors delete 'src'
39: TailList(TailList<T> *src) : list(&src->list) {}
40: void steal(TailList<T> *src) { list.steal(&src->list); }
41:
42: // selectors
43: int count() const { return list.count(); }
44: bool isEmpty() const { return list.isEmpty(); }
45: bool isNotEmpty() const { return list.isNotEmpty(); }
46: T *nth(int which) { return (T*)list.nth(which); }
47: T const *nthC(int which) const { return (T const*)list.nth(which); }
48: T *first() { return (T*)list.first(); }
49: T const *firstC() const { return (T const*)list.first(); }
50: T *last() { return (T*)list.last(); }
51: T const *lastC() const { return (T const*)list.last(); }
52:
53: // insertion
54: void prepend(T *newitem) { list.prepend(newitem); }
55: void append(T *newitem) { list.append(newitem); }
56: void insertAt(T *newitem, int index) { list.insertAt(newitem, index); }
57: void concat(TailList<T> &tail) { list.concat(tail.list); }
58:
59: // removal
60: T *removeFirst() { return (T*)list.removeFirst(); }
61: T *removeLast() { return (T*)list.removeLast(); }
62: T *removeAt(int index) { return (T*)list.removeAt(index); }
63: void removeItem(T *item) { list.removeItem((void*)item); }
64:
65: // list-as-set: selectors
66: int indexOf(T const *item) const { return list.indexOf((void*)item); }
67: int indexOfF(T const *item) const { return list.indexOfF((void*)item); }
68: bool contains(T const *item) const { return list.contains((void*)item); }
69:
70: // list-as-set: mutators
71: bool prependUnique(T *newitem) { return list.prependUnique(newitem); }
72: bool appendUnique(T *newitem) { return list.appendUnique(newitem); }
73:
74: // debugging: two additional invariants
75: void selfCheck() const { list.selfCheck(); }
76: };
77:
78:
79: template <class T>
80: class TailListIter {
81: protected:
82: VoidTailListIter iter; // underlying iterator
83:
84: public:
85: TailListIter(TailList<T> const &list) : iter(list.list) {}
86: ~TailListIter() {}
87:
88: void reset(TailList<T> const &list) { iter.reset(list.list); }
89:
90: // iterator copying; generally safe
91: TailListIter(TailListIter const &obj) : iter(obj.iter) {}
92: TailListIter& operator=(TailListIter const &obj) { iter = obj.iter; return *this; }
93:
94: // iterator actions
95: bool isDone() const { return iter.isDone(); }
96: void adv() { iter.adv(); }
97: T const *data() const { return (T const*)iter.data(); }
98: };
99:
100: #define FOREACH_TAILLIST(T, list, iter) \
101: for(TailListIter<T> iter(list); !iter.isDone(); iter.adv())
102:
103:
104: // version of the above, but for non-const-element traversal
105: template <class T>
106: class TailListIterNC {
107: protected:
108: VoidTailListIter iter; // underlying iterator
109:
110: public:
111: TailListIterNC(TailList<T> &list) : iter(list.list) {}
112: ~TailListIterNC() {}
113:
114: void reset(TailList<T> &list) { iter.reset(list.list); }
115:
116: // iterator copying; generally safe
117: TailListIterNC(TailListIterNC const &obj) : iter(obj.iter) {}
118: TailListIterNC& operator=(TailListIterNC const &obj) { iter = obj.iter; return *this; }
119:
120: // iterator actions
121: bool isDone() const { return iter.isDone(); }
122: void adv() { iter.adv(); }
123: T *data() const { return (T*)iter.data(); }
124:
125: // iterator mutation; use with caution
126: void setDataLink(T *newData) { iter.setDataLink((void*)newData); }
127: };
128:
129: #define FOREACH_TAILLIST_NC(T, list, iter) \
130: for(TailListIterNC<T> iter(list); !iter.isDone(); iter.adv())
131:
132: #endif // TailLIST_H
Start C section to elk/sm_test.h[1
/1
]
1: #line 6427 "./lpsrc/sm.pak"
2: // test.h see license.txt for copyright and terms of use
3: // utilities for test code
4: // Scott McPeak, 1999 This file is public domain.
5:
6: #ifndef __TEST_H
7: #define __TEST_H
8:
9: #include <iostream> // cout
10: #include <stdio.h> // printf
11: #include "sm_exc.h"
12: #include "sm_nonport.h"
13:
14:
15: // reports uncaught exceptions
16: //
17: // 12/30/02: I used to print "uncaught exception: " before
18: // printing the exception, but this is meaningless to the
19: // user and the message usually has enough info anyway
20: #define USUAL_MAIN \
21: void entry(); \
22: int main() \
23: { \
24: try { \
25: entry(); \
26: return 0; \
27: } \
28: catch (xBase &x) { \
29: std::cout << x << std::endl; \
30: return 4; \
31: } \
32: }
33:
34: // same as above, but with command-line args
35: #define ARGS_MAIN \
36: void entry(int argc, char *argv[]); \
37: int main(int argc, char *argv[]) \
38: { \
39: try { \
40: entry(argc, argv); \
41: return 0; \
42: } \
43: catch (xBase &x) { \
44: std::cout << x << std::endl; \
45: return 4; \
46: } \
47: }
48:
49:
50: // convenient for printing the value of a variable or expression
51: #define PVAL(val) std::cout << #val << " = " << (val) << std::endl
52:
53:
54: // easy way to time a section of code
55: class TimedSection {
56: char const *name;
57: long start;
58:
59: public:
60: TimedSection(char const *n) : name(n) {
61: start = getMilliseconds();
62: }
63: ~TimedSection() {
64: std::cout << name << ": " << (getMilliseconds() - start) << " msecs\n";
65: }
66: };
67:
68:
69: #endif // __TEST_H
70:
Start C section to elk/sm_thashtbl.h[1
/1
]
1: #line 6498 "./lpsrc/sm.pak"
2: // thashtbl.h see license.txt for copyright and terms of use
3: // type-safe version of HashTable
4:
5: #ifndef THASHTBL_H
6: #define THASHTBL_H
7:
8: #include "sm_hashtbl.h"
9:
10: template <class KEY, class DATA> class THashTableIter;
11:
12: template <class KEY, class DATA>
13: class THashTable {
14: private: // types
15: friend class THashTableIter<KEY, DATA>;
16:
17: public: // types
18: // given a stored data pointer, retrieve the associated key
19: typedef KEY const* (*GetKeyFn)(DATA *data);
20:
21: // given a key, retrieve the associated hash value;
22: // this should be a 32-bit integer ready to be mod'd by the table size
23: typedef unsigned (*HashFn)(KEY const *key);
24:
25: // compare two keys; this is needed so we can handle collisions
26: // in the hash function; return true if they are equal
27: typedef bool (*EqualKeyFn)(KEY const *key1, KEY const *key2);
28:
29: private: // data
30: // underlying table
31: HashTable table;
32:
33: private: // funcs
34: // disallowed
35: THashTable(THashTable&);
36: void operator=(THashTable&);
37: void operator==(THashTable&);
38:
39: public: // funcs
40: THashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek,
41: int initSize = HashTable::defaultSize)
42: : table((HashTable::GetKeyFn)gk,
43: (HashTable::HashFn)hf,
44: (HashTable::EqualKeyFn)ek,
45: initSize)
46: {}
47: ~THashTable() {}
48:
49: // return # of mapped entries
50: int getNumEntries() const { return table.getNumEntries(); }
51:
52: // if this hash value has a mapping, return it; otherwise,
53: // return NULL
54: DATA *get(KEY const *key) const { return (DATA*)table.get(key); }
55:
56: // add a mapping from 'key' to 'value'; there must not already
57: // be a mapping for this key
58: void add(KEY const *key, DATA *value) { table.add(key, value); }
59:
60: // remove the mapping for 'key' -- it must exist;
61: // returns the removed item
62: DATA *remove(KEY const *key) { return (DATA*)table.remove(key); }
63:
64: // remove all mappings
65: void empty(int initSize = HashTable::defaultSize) { table.empty(initSize); }
66:
67: // set whether shrinkage is allowed; it's useful to be able to
68: // disable this to avoid any allocation in certain situations
69: void setEnableShrink(bool en) { table.setEnableShrink(en); }
70:
71: // allow external access to an accessor function
72: KEY const *callGetKeyFn(DATA *data) { return (KEY const*)table.getKey(data); }
73:
74: // check the data structure's invariants, and throw an exception
75: // if there is a problem
76: void selfCheck() const { table.selfCheck(); }
77: };
78:
79:
80: // iterate over all stored values in a THashTable
81: // NOTE: you can't change the table while an iter exists
82: template <class KEY, class DATA>
83: class THashTableIter {
84: private: // data
85: HashTableIter iter; // underlying iter
86:
87: public: // funcs
88: THashTableIter(THashTable<KEY,DATA> &table) : iter(table.table) {}
89:
90: bool isDone() const { return iter.isDone(); }
91: void adv() { return iter.adv(); }
92: DATA *data() const { return (DATA*)iter.data(); }
93: };
94:
95:
96: #endif // THASHTBL_H
Start C section to elk/sm_trace.h[1
/1
]
1: #line 6595 "./lpsrc/sm.pak"
2: // trace.h see license.txt for copyright and terms of use
3: // module for diagnostic tracing
4: // see trace.html
5:
6: #ifndef TRACE_H
7: #define TRACE_H
8:
9: #include <iostream> // std::ostream
10:
11:
12: // add a subsystem to the list of those being traced
13: void traceAddSys(char const *sysName);
14:
15: // remove a subsystem; must have been there
16: void traceRemoveSys(char const *sysName);
17:
18: // see if a subsystem is among those to trace
19: bool tracingSys(char const *sysName);
20:
21: // clear all tracing flags
22: void traceRemoveAll();
23:
24:
25: // trace; if the named system is active, this yields cout (after
26: // sending a little output to identify the system); if not, it
27: // yields an std::ostream attached to /dev/null; when using this
28: // method, it is up to you to put the newline
29: std::ostream &trace(char const *sysName);
30:
31: // give an entire sm_string to trace; do *not* put a newline in it
32: // (the tracer will do that)
33: void trstr(char const *sysName, char const *traceString);
34:
35: // trace macro which disables itself when NDEBUG is true,
36: // and automatically supplies 'std::endl' when it's not true
37: //
38: // dsw: debugging *weakly* implies tracing: if we are debugging, do
39: // tracing unless otherwise specified
40: #ifndef NDEBUG
41: #ifndef DO_TRACE
42: #define DO_TRACE 1
43: #endif
44: #endif
45: // dsw: tracing *bidirectionally* configurable from the command line:
46: // it may be turned on *or* off: any definition other than '0' counts
47: // as true, such as -DDO_TRACE=1 or just -DDO_TRACE
48: #ifndef DO_TRACE
49: #define DO_TRACE 0
50: #endif
51: #if DO_TRACE != 0
52: #define TRACE(tag, exp) trace(tag) << exp << std::endl /* user ; */
53: #else
54: #define TRACE(tag, exp) ((void)0)
55: #endif
56:
57:
58: // special for "progress" tracing; prints time too;
59: // 'level' is level of detail -- 1 is highest level, 2 is
60: // more refined (and therefore usually not printed), etc.
61: std::ostream &traceProgress(int level=1);
62:
63:
64: // add one or more subsystems, separated by commas
65: void traceAddMultiSys(char const *systemNames);
66:
67: // if the first argument is a tracing directive, handle it, modify
68: // argc and argv modified to effectively remove it, and return true
69: // (argv[0] is assumed to be ignored by everything); this calls
70: // 'traceAddFromEnvVar' too
71: bool traceProcessArg(int &argc, char **&argv);
72:
73: // so here's a simple loop that will consume any leading
74: // trace arguments
75: #define TRACE_ARGS() while (traceProcessArg(argc, argv)) {}
76:
77:
78: // add tracing flags from the environment variable "TRACE",
79: // unless 'ignoreTraceEnvVar' is true; this sets it to true,
80: // so it's idempotent
81: void traceAddFromEnvVar();
82: extern bool ignoreTraceEnvVar; // initially false
83:
84:
85: #endif // TRACE_H
Start C section to elk/sm_trdelete.h[1
/1
]
1: #line 6681 "./lpsrc/sm.pak"
2: // trdelete.h see license.txt for copyright and terms of use
3: // objects which trash their contents upon deletion
4: // I would love to have implemented this as a base class and simply derive
5: // things from it, but a poor implementation choice by Borland makes this
6: // too costly in terms of performance
7:
8: #ifdef _MSC_VER
9: // this module doesn't work under msvc, I don't care to figure out why
10: #define TRDELETE_H // make it omit this file
11: #define TRASHINGDELETE // and all references to it a no-op
12: #endif
13:
14: #ifndef TRDELETE_H
15: #define TRDELETE_H
16:
17: #include <stddef.h> // size_t
18:
19: void trashingDelete(void *blk, size_t size);
20: void trashingDeleteArr(void *blk, size_t size);
21:
22: // to use, include the TRASHINGDELETE macro in the public section of a class
23:
24: #define TRASHINGDELETE \
25: void operator delete(void *blk, size_t size) { trashingDelete(blk, size); } \
26: void operator delete[](void *blk, size_t size) { trashingDeleteArr(blk, size); }
27:
28: #endif // TRDELETE_H
Start C section to elk/sm_typ.h[1
/1
]
1: #line 6710 "./lpsrc/sm.pak"
2: // typ.h see license.txt for copyright and terms of use
3: // various types and definitions, some for portability, others for convenience
4: // Scott McPeak, 1996-2000 This file is public domain.
5:
6: #ifndef __TYP_H
7: #define __TYP_H
8:
9: // js: this crud is required to provide an integer type
10: // to which a void* can be cast so the result can be
11: // input to a hashing function
12:
13: #include "../rtl/flx_elk_config.hpp"
14: typedef FLX_RAWADDRESS SM_RAWADDRESS;
15:
16: // byte
17: typedef unsigned char byte;
18: typedef signed char signed_byte;
19:
20:
21: // int32 used to be here, but defined nonportably, and I don't use
22: // it anyway, so I ripped it out
23:
24:
25: // NULL
26: #ifndef NULL
27: # define NULL 0
28: #endif // NULL
29:
30:
31: // bool
32: #ifdef LACKS_BOOL
33: typedef int bool;
34: bool const false=0;
35: bool const true=1;
36: #endif // LACKS_BOOL
37:
38:
39: // min, max
40: #undef min
41: #undef max
42:
43: template <class T>
44: inline T min(T const &a, T const &b)
45: {
46: return a<b? a:b;
47: }
48:
49: template <class T>
50: inline T max(T const &a, T const &b)
51: {
52: return a>b? a:b;
53: }
54:
55:
56: #if 0 // old
57: #ifndef __MINMAX_DEFINED
58: # ifndef min
59: # define min(a,b) ((a)<(b)?(a):(b))
60: # endif
61: # ifndef max
62: # define max(a,b) ((a)>(b)?(a):(b))
63: # endif
64: # define __MINMAX_DEFINED
65: #endif // __MINMAX_DEFINED
66: #endif // 0
67:
68:
69: // tag for definitions of static member functions; there is no
70: // compiler in existence for which this is useful, but I like
71: // to see *something* next to implementations of static members
72: // saying that they are static, and this seems slightly more
73: // formal than just a comment
74: #define STATICDEF /*static*/
75:
76:
77: // often-useful number-of-entries function
78: #define TABLESIZE(tbl) ((int)(sizeof(tbl)/sizeof((tbl)[0])))
79:
80:
81: // concise way to loop on an integer range
82: #define loopi(end) for(int i=0; i<(int)(end); i++)
83: #define loopj(end) for(int j=0; j<(int)(end); j++)
84: #define loopk(end) for(int k=0; k<(int)(end); k++)
85:
86:
87: // for using selfCheck methods
88: // to explicitly check invariants in debug mode
89: //
90: // dsw: debugging *weakly* implies selfchecking: if we are debugging,
91: // do selfcheck unless otherwise specified
92: #ifndef NDEBUG
93: #ifndef DO_SELFCHECK
94: #define DO_SELFCHECK 1
95: #endif
96: #endif
97: // dsw: selfcheck *bidirectionally* configurable from the command line: it
98: // may be turned on *or* off: any definition other than '0' counts as
99: // true, such as -DDO_SELFCHECK=1 or just -DDO_SELFCHECK
100: #ifndef DO_SELFCHECK
101: #define DO_SELFCHECK 0
102: #endif
103: #if DO_SELFCHECK != 0
104: #define SELFCHECK() selfCheck()
105: #else
106: #define SELFCHECK() ((void)0)
107: #endif
108:
109:
110: // division with rounding towards +inf
111: // (when operands are positive)
112: template <class T>
113: inline T div_up(T const &x, T const &y)
114: { return (x + y - 1) / y; }
115:
116:
117: // mutable
118: #ifdef __BORLANDC__
119: # define MUTABLE
120: # define EXPLICIT
121: #else
122: # define MUTABLE mutable
123: # define EXPLICIT explicit
124: #endif
125:
126:
127: #define SWAP(a,b) \
128: temp = a; \
129: a = b; \
130: b = temp /*user supplies semicolon*/
131:
132:
133: // verify something is true at compile time (will produce
134: // a compile error if it isn't)
135: // update: use STATIC_ASSERT defined in macros.h instead
136: //#define staticAssert(cond) extern int dummyArray[cond? 1 : 0]
137:
138:
139: #endif // __TYP_H
140:
Start C section to elk/sm_vdtllist.h[1
/1
]
1: #line 6851 "./lpsrc/sm.pak"
2: // vdtllist.h see license.txt for copyright and terms of use
3: // list of void*, with a pointer maintained to the last (tail)
4: // element, for constant-time append
5:
6: #ifndef VDTLLIST_H
7: #define VDTLLIST_H
8:
9: #include "sm_voidlist.h"
10:
11: // inherit privately so I can choose what to expose
12: class VoidTailList : private VoidList {
13: private:
14: // by making this a friend, it should see VoidList as a
15: // base class, and thus simply work
16: // but it doesn't..
17: //friend VoidListIter;
18:
19: friend class VoidTailListIter;
20:
21: // no mutator for now
22:
23: protected:
24: VoidNode *tail; // (serf) last element of list, or NULL if list is empty
25: VoidNode *getTop() const { return VoidList::getTop(); }
26:
27: private:
28: VoidTailList(VoidTailList const &obj); // not allowed
29:
30: void adjustTail();
31:
32: public:
33: VoidTailList() { tail = NULL; }
34: ~VoidTailList() {}
35:
36: // special ctor which steals the list and then deallocates the header
37: VoidTailList(VoidTailList *src) { tail = NULL; steal(src); }
38: void steal(VoidTailList *src); // deletes 'src'
39:
40: // this syntax just makes the implementation inherited from
41: // 'VoidList' public, whereas it would default to private,
42: // since it was inherited privately
43: VoidList::count;
44:
45: // see voidlist.h for documentation of each of these functions
46: VoidList::isEmpty;
47: VoidList::isNotEmpty;
48: VoidList::nth;
49: VoidList::first;
50: void *last() const { xassert(tail); return tail->data; }
51:
52: // insertion
53: void prepend(void *newitem);
54: void append(void *newitem);
55: void insertAt(void *newitem, int index);
56: void concat(VoidTailList &tail);
57:
58: // removal
59: void *removeFirst(); // remove first, return data; must exist
60: void *removeLast();
61: void *removeAt(int index);
62: void removeAll();
63: VoidList::removeItem;
64:
65: // list-as-set: selectors
66: VoidList::indexOf;
67: VoidList::indexOfF;
68: VoidList::contains;
69:
70: // list-as-set: mutators
71: bool prependUnique(void *newitem);
72: bool appendUnique(void *newitem);
73: //void removeItem(void *item);
74: //bool removeIfPresent(void *item);
75:
76: // debugging
77: void selfCheck() const;
78: VoidList::debugPrint;
79: };
80:
81:
82: // copied from voidlist.h because g++ won't do what I want..
83: class VoidTailListIter {
84: protected:
85: VoidNode *p; // (serf) current item
86:
87: public:
88: VoidTailListIter(VoidTailList const &list) { reset(list); }
89: ~VoidTailListIter() {}
90:
91: void reset(VoidTailList const &list) { p = list.getTop(); }
92:
93: // iterator copying; generally safe
94: VoidTailListIter(VoidTailListIter const &obj) { p = obj.p; }
95: VoidTailListIter& operator=(VoidTailListIter const &obj) { p = obj.p; return *this; }
96:
97: // but copying from a mutator is less safe; see above
98: //VoidTailListIter(VoidListMutator &obj) { p = obj.current; }
99:
100: // iterator actions
101: bool isDone() const { return p == NULL; }
102: void adv() { p = p->next; }
103: void *data() const { return p->data; }
104:
105: // iterator mutation; use with caution
106: void setDataLink(void *newData) { p->data = newData; }
107: };
108:
109:
110:
111: #endif // VDTLLIST_H
Start C section to elk/sm_voidlist.h[1
/1
]
1: #line 6963 "./lpsrc/sm.pak"
2: // voidlist.h see license.txt for copyright and terms of use
3: // list of void*
4:
5: // Author: Scott McPeak, 2000
6:
7: #ifndef __VOIDLIST_H
8: #define __VOIDLIST_H
9:
10: #include "sm_xassert.h"
11: #include "sm_typ.h"
12: #include "sm_trdelete.h"
13:
14: // -------------------------- non-typesafe core -----------------------------
15: // non-typesafe list node
16: class VoidNode {
17: public:
18: TRASHINGDELETE
19:
20: VoidNode *next; // (owner) next item in list, or NULL if last item
21: void *data; // whatever it is the list is holding
22:
23: VoidNode(void *aData=NULL, VoidNode *aNext=NULL) { data=aData; next=aNext; }
24: };
25:
26:
27: // forward decls for 'friend' decls
28: class VoidListIter;
29: class VoidListMutator;
30:
31:
32: // The difference function should return <0 if left should come before
33: // right, 0 if they are equivalent, and >0 if right should come before
34: // left. For example, if we are sorting numbers into ascending order,
35: // then 'diff' could simply be subtraction.
36: typedef int (*VoidDiff)(void *left, void *right, void *extra);
37:
38:
39: // list of void*; at this level, the void* are completely opaque;
40: // the list won't attempt to delete(), compare them, or anything else
41: // (well, some comparison has creeped in now... but only via VoidDiff)
42: class VoidList {
43: private:
44: friend class VoidListIter;
45: friend class VoidListMutator;
46:
47: protected:
48: VoidNode *top; // (owner) first node, or NULL if list is empty
49: VoidNode *getTop() const { return top; } // for iterator, below
50:
51: public:
52: VoidList() { top=NULL; }
53: VoidList(VoidList const &obj); // makes a (shallow) copy of the contents
54: ~VoidList() { removeAll(); }
55:
56: // selectors
57: int count() const; // # of items in list
58: bool isEmpty() const { return top == NULL; }
59: bool isNotEmpty() const { return top != NULL; }
60: void *nth(int which) const; // get particular item, 0 is first (item must exist)
61: void *first() const { return nth(0); }
62: void *last() const { return nth(count()-1); }
63:
64: // insertion
65: void prepend(void *newitem); // insert at front
66: void append(void *newitem); // insert at rear
67: void insertAt(void *newitem, int index);
68: // new item is inserted such that its index becomdes 'index'
69: void insertSorted(void *newitem, VoidDiff diff, void *extra=NULL);
70: // insert into an already-sorted list so that the list is sorted afterwards
71:
72: // removal
73: void *removeAt(int index); // remove from list (must exist), and return removed item
74: void *removeFirst() { return removeAt(0); }
75: void removeAll();
76:
77: // list-as-set: selectors
78: int indexOf(void *item) const; // returns index of *first* occurrance, or -1 if not present
79: int indexOfF(void *item) const; // same as indexOf, but throws exception if not present
80: bool contains(void *item) const // true if the item appears in the list
81: { return indexOf(item) >= 0; }
82:
83: // list-as-set: mutators
84: bool prependUnique(void *newitem); // prepend only if not already there
85: bool appendUnique(void *newitem); // append " "
86: void removeItem(void *item); // remove first occurrance -- must exist
87: bool removeIfPresent(void *item); // remove first occurrance; return true if changed
88:
89: // complex modifiers
90: void reverse();
91: void insertionSort(VoidDiff diff, void *extra=NULL);
92: void mergeSort(VoidDiff diff, void *extra=NULL);
93:
94: // and a related test
95: bool isSorted(VoidDiff diff, void *extra=NULL) const;
96:
97: // multiple lists
98: void concat(VoidList &tail); // tail is emptied, nodes appended to this
99: void appendAll(VoidList const &tail); // tail is untouched.. but its contents are now exposed to non-constness... ug... oh well
100: VoidList& operator= (VoidList const &src); // afterwards, 'this' and 'src' have same contents
101:
102: // steal (become the container for) the tail of a source list at any
103: // point; if 'index' is 0, the entire 'source' is stolen (i.e.
104: // index=0 is equivalent to 'concat', above); stolen items appended
105: // to 'this'
106: void stealTailAt(int index, VoidList &source);
107:
108: // equal items in equal positions
109: bool equalAsLists(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
110:
111: // if equal, returns 0; otherwise, return order (-1/+1) according to
112: // the first differing pair of elements; a shorter (but otherwise
113: // idential list) will compare as being less
114: int compareAsLists(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
115:
116: // last-as-set: comparisons (NOT efficient)
117: bool equalAsSets(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
118: // A subset of B, and vice-versa
119: bool isSubsetOf(VoidList const &otherList, VoidDiff diff, void *extra=NULL) const;
120: // uses slow elementwise containment
121: bool containsByDiff(void *item, VoidDiff diff, void *extra=NULL) const;
122:
123: // treating the pointer values themselves as the basis for comparison
124: static int pointerAddressDiff(void *left, void *right, void*);
125: bool equalAsPointerLists(VoidList const &otherList) const
126: { return equalAsLists(otherList, pointerAddressDiff); }
127: bool equalAsPointerSets(VoidList const &otherList) const
128: { return equalAsSets(otherList, pointerAddressDiff); }
129:
130: // debugging
131: void selfCheck() const; // test this list; fail assertion if malformed
132: void debugPrint() const; // print list contents to stdout
133: void checkHeapDataPtrs() const; // fail assertion if any 'data' ptr isn't valid heap ptr
134: void checkUniqueDataPtrs() const; // fail assertion if any 'data' ptr matches any other in this list
135: };
136:
137:
138: // for traversing the list and modifying it
139: // NOTE: no list-modification fns should be called on 'list' while this
140: // iterator exists, and only one such iterator should exist for
141: // any given list
142: class VoidListMutator {
143: friend class VoidListIter;
144:
145: protected:
146: VoidList &list; // underlying list
147: VoidNode *prev; // (serf) previous node; NULL if at list's head
148: VoidNode *current; // (serf) node we're considered to be pointing at
149:
150: public:
151: VoidListMutator(VoidList &lst) : list(lst) { reset(); }
152: ~VoidListMutator() {}
153:
154: void reset() { prev = NULL; current = list.top; }
155:
156: // iterator copying; safe *only* until one of the mutators modifies
157: // the list structure (by inserting or removing), at which time all
158: // other iterators might be in limbo
159: VoidListMutator(VoidListMutator const &obj)
160: : list(obj.list), prev(obj.prev), current(obj.current) {}
161: VoidListMutator& operator=(VoidListMutator const &obj);
162: // requires that 'this' and 'obj' already refer to the same 'list'
163:
164: // iterator actions
165: bool isDone() const { return current == NULL; }
166: void adv() { prev = current; current = current->next; }
167: void *data() { return current->data; }
168: void *&dataRef() { return current->data; }
169:
170: // insertion
171: void insertBefore(void *item);
172: // 'item' becomes the new 'current', and the current 'current' is
173: // pushed forward (so the next adv() will make it current again)
174:
175: void insertAfter(void *item);
176: // 'item' becomes what we reach with the next adv();
177: // isDone() must be false
178:
179: void append(void *item);
180: // only valid while isDone() is true, it inserts 'item' at the end of
181: // the list, and advances such that isDone() remains true; equivalent
182: // to { xassert(isDone()); insertBefore(item); adv(); }
183:
184: // removal
185: void *remove();
186: // 'current' is removed from the list and returned, and whatever was
187: // next becomes the new 'current'
188:
189: // debugging
190: void selfCheck() const
191: { xassert((prev->next == current && current != list.top) ||
192: (prev==NULL && current==list.top)); }
193: };
194:
195:
196: // for traversing the list without modifying it
197: // NOTE: no list-modification fns should be called on 'list' while this
198: // iterator exists
199: class VoidListIter {
200: protected:
201: VoidNode *p; // (serf) current item
202:
203: public:
204: VoidListIter(VoidList const &list) { reset(list); }
205: VoidListIter(VoidList const &list, int pos); // advance 'pos' times
206: ~VoidListIter() {}
207:
208: void reset(VoidList const &list) { p = list.getTop(); }
209:
210: // iterator copying; generally safe
211: VoidListIter(VoidListIter const &obj) { p = obj.p; }
212: VoidListIter& operator=(VoidListIter const &obj) { p = obj.p; return *this; }
213:
214: // but copying from a mutator is less safe; see above
215: VoidListIter(VoidListMutator &obj) { p = obj.current; }
216:
217: // iterator actions
218: bool isDone() const { return p == NULL; }
219: void adv() { p = p->next; }
220: void *data() const { return p->data; }
221: };
222:
223:
224: #endif // __VOIDLIST_H
Start C section to elk/sm_vptrmap.h[1
/1
]
1: #line 7188 "./lpsrc/sm.pak"
2: // vptrmap.h
3: // map from void* to void*
4: // interface based partly on hashtbl.h
5:
6: // Design considerations:
7: //
8: // Keys are pointers to objects. They are likely to have the same
9: // high bits (page) and low bits (alignment), and thus be
10: // distinguished primarily by the bits in the middle. No key is NULL.
11: //
12: // Deletion of a single mapping is not supported. To delete some
13: // mappings you have to rebuild the table.
14: //
15: // No adversary is present; hash function is fixed in advance.
16:
17:
18: #ifndef VPTRMAP_H
19: #define VPTRMAP_H
20:
21:
22: class VoidPtrMap {
23: private: // types
24: // single entry in the hash table
25: struct Entry {
26: void *key; // NULL only for unused entries
27: void *value; // NULL if key is NULL
28: };
29:
30: private: // data
31: // hash table itself; collision is resolved with double hashing,
32: // which is why efficient deletion is impossible
33: Entry *hashTable;
34:
35: // number of (allocated) slots in the hash table; this is always a
36: // power of 2
37: int tableSize;
38:
39: // tableSize always equals 1 << tableSizeBits
40: int tableSizeBits;
41:
42: // number of mappings (i.e. key!=NULL); always numEntries < tableSize
43: int numEntries;
44:
45: // number of outstanding iterators; used to check that we don't
46: // modify the table while one is active (experimental)
47: mutable int iterators;
48:
49: public: // data
50: // total # of lookups
51: static int lookups;
52:
53: // total # of entries examined during lookups; perfect hashing
54: // would yield lookups==probes
55: static int probes;
56:
57: private: // funcs
58: // 'bits' becomes tableSizeBits; also set hashTable and tableSize
59: void alloc(int bits);
60:
61: // multiplicative hash function
62: inline unsigned hashFunc(unsigned multiplier, unsigned key) const;
63:
64: // return the first entry in key's probe sequence that has either
65: // a NULL key or a key equal to 'key'
66: Entry &findEntry(void const *key) const;
67:
68: // make the table twice as big, and move all the entries into
69: // that new table
70: void expand();
71:
72: // disallowed
73: VoidPtrMap(VoidPtrMap &obj);
74: void operator=(VoidPtrMap &obj);
75: void operator==(VoidPtrMap &obj);
76:
77: public: // funcs
78: VoidPtrMap(); // empty map
79: ~VoidPtrMap();
80:
81: // return # of mapped entries
82: int getNumEntries() const { return numEntries; }
83:
84: // if this key has a mapping, return it; otherwise, return NULL
85: void *get(void const *key) const { return findEntry(key).value; }
86:
87: // add a mapping from 'key' to 'value'; replaces existing
88: // mapping, if any
89: void add(void *key, void *value);
90:
91: // remove all mappings
92: void empty();
93:
94:
95: public: // iterators
96: // iterate over all stored values in a VoidPtrMap
97: // NOTE: you can't change the table while an iter exists
98: class Iter {
99: private: // data
100: VoidPtrMap const ↦ // table we're iterating over
101: int index; // current slot to return in adv(); -1 when done
102:
103: public: // funcs
104: Iter(VoidPtrMap const &map);
105: ~Iter();
106:
107: bool isDone() const { return index < 0; }
108: void adv(); // must not be isDone()
109:
110: // return information about the currently-referenced table entry
111: void *key() const // key (never NULL)
112: { return map.hashTable[index].key; }
113: void *value() const // associated value
114: { return map.hashTable[index].value; }
115: };
116: friend class Iter;
117: };
118:
119:
120: #endif // VPTRMAP_H
Start C section to elk/sm_warn.h[1
/1
]
1: #line 7309 "./lpsrc/sm.pak"
2: // warn.h see license.txt for copyright and terms of use
3: // module to facilitate providing operational warnings to the user
4: // Scott McPeak, 1999 This file is public domain.
5:
6: #ifndef __WARN_H
7: #define __WARN_H
8:
9: // note: In retrospect, this module was either a bad idea, or I didn't
10: // implement it well. Either way, don't use it for anything new.
11:
12: // non-disjoint warning classification scheme
13: // (add more classes as necessary)
14: enum WarnLevel {
15: WARN_PERFORMANCE = 0x01,
16: // may cause suboptimal performance
17:
18: WARN_SECURITY = 0x02,
19: // possible compromise of private data, unauthrorized
20: // access, authentication warning, etc.
21:
22: WARN_COMPATIBILITY = 0x04,
23: // interoperability with other software (including
24: // different versions of this software) may be
25: // adversely affected
26:
27: WARN_DEBUG = 0x08,
28: // of use during debugging only; setting this flag means
29: // the warning handler should alert an attached debugger
30:
31: WARN_INFORMATION = 0x10,
32: // I'm not sure when/why this would be used...
33: // Note: This is *not* to be used as a diagnostic 'printf'.
34:
35: WARN_ALL = 0x1F,
36: // logical-or of all flags
37:
38: WARN_NONE = 0x0,
39: // no warnings
40: };
41:
42:
43: // user interface
44: // --------------
45: // call this to report a warning
46: // level - logical-or of applicable conditions
47: // message - user-intelligible message (should *not* contain a newline)
48: void warning(WarnLevel level, char const *message);
49:
50:
51: // handler interface
52: // -----------------
53: // the warning() function calls warningHandler(), so new
54: // handlers are installed by changing that value
55: typedef void (*WarningHandler)(WarnLevel level, char const *message);
56: extern WarningHandler warningHandler;
57:
58:
59: // default handler
60: // ---------------
61: // the default warning handler masks the input level with two
62: // global variables:
63: // logWarnLevel - messages are written to a log file, "warning.log"
64: // displayWarnLevel - messages are written to stderr via stdio 'stderr'
65: extern WarnLevel logWarnLevel; // default: WARN_ALL, minus WARN_DEBUG ifdef NDEBUG
66: extern WarnLevel displayWarnLevel; // default: ifdef NDEBUG, WARN_NONE, else WARN_ALL
67:
68: // handler functions (handler dispatches to logger and printer)
69: void defaultWarningHandler(WarnLevel level, char const *message);
70: void defaultWarningLogger(WarnLevel level, char const *message);
71: void defaultWarningPrinter(WarnLevel level, char const *message);
72:
73:
74: #endif // __WARN_H
75:
Start C section to elk/sm_xassert.h[1
/1
]
1: #line 7385 "./lpsrc/sm.pak"
2: // xassert.h see license.txt for copyright and terms of use
3: // replacement for assert that throws an exception on failure
4: // (x_assert_fail is defined in exc.cpp)
5: // Scott McPeak, 1997-1998 This file is public domain.
6:
7: #ifndef XASSERT_H
8: #define XASSERT_H
9:
10: #include "sm_macros.h"
11:
12: // linkdepend: exc.cpp
13:
14: void x_assert_fail(char const *cond, char const *file, int line) NORETURN;
15:
16: // Ordinary 'xassert' *can* be turned off, but the nominal intent
17: // is that it be left on, under the "ship what you test" theory.
18: // I advocate using NDEBUG_NO_ASSERTIONS only as a way to gauge the
19: // performance impact of the existing assertions.
20: #if !defined(NDEBUG_NO_ASSERTIONS)
21: #define xassert(cond) \
22: ((cond)? (void)0 : x_assert_fail(#cond, __FILE__, __LINE__))
23: #else
24: #define xassert(cond) ((void)0)
25: #endif
26:
27: // Here's a version which will turn off with ordinary NDEBUG. It
28: // is for more expensive checks that need not ship.
29: #if !defined(NDEBUG)
30: #define xassertdb(cond) xassert(cond)
31: #else
32: #define xassertdb(cond) ((void)0)
33: #endif
34:
35: // call when state is known to be bad; will *not* return
36: #define xfailure(why) x_assert_fail(why, __FILE__, __LINE__)
37:
38:
39: // Quick note: one prominent book on writing code recommends that
40: // assertions *not* include the failure condition, since the file
41: // and line number are sufficient, and the condition sm_string uses
42: // memory. The problem is that sometimes a compiled binary is
43: // out of date w/respect to the code, and line numbers move, so
44: // the condition sm_string provides a good way to find the right
45: // assertion.
46:
47:
48: /*
49: Why throw an exception after an assertion?
50:
51: The standard assert() calls abort() after printing its message.
52: This is like throwing an exception all the way to the calling
53: process. This is fine if programs are small.
54:
55: But when a program is large enough, it may contain subsystems at
56: several layers, such that a higher level module is capable of
57: recovering from the failure of a lower level module. Using abort(),
58: one would have to resort to catching signals, which is messy.
59:
60: An exception is much nicer to catch, and has the added benefit that
61: intermediate layers can catch and rethrow, appending little bits of
62: context, if they want to make the message more informative.
63:
64: In most of my programs, the 'x_assert' exception is only caught in
65: main() (implicitly, by catching 'xBase'), and hence 'xassert' acts
66: very much like 'assert'. But by using 'xassert' consistenty, any
67: time I *do* have a large program with recovery, all the lower-level
68: modules are all ready to cooperate.
69:
70: Speaking of recovery: Be aware that when a module fails an
71: assertion, its internal state is most likely inconsistent. Recovery
72: actions need to be fairly conservative about what code gets
73: re-entered and state re-used after a failure. This is no different
74: than with 'assert', as a program could have inconsistent state *on
75: disk* that gets reactivated upon being restarted, but persistent
76: (across process boundaries) inconsistent state is simply less
77: common.
78:
79: */
80:
81: #endif // XASSERT_H
82:
Start C section to elk/sm_xobjlist.h[1
/1
]
1: #line 7468 "./lpsrc/sm.pak"
2: m4_dnl // xobjlist.h see license.txt for copyright and terms of use
3: m4_dnl // template file to be processed with m4 to generate one
4: m4_dnl // of the wrappers around VoidList
5: m4_dnl
6: m4_changequote([, ])m4_dnl // for this section
7: m4_changecom[]m4_dnl // no m4 "comments"
8: m4_ifelse(m4_output, sobjlist.h, [m4_dnl
9: // sobjlist.h
10: // serf list of arbitrary objects
11: m4_define(makeName, S[$1])m4_dnl
12: m4_define(outputCond, [$1])m4_dnl // select 1st arg
13: m4_define(SPC, [])m4_dnl
14: ], [m4_dnl
15: // objlist.h
16: // owner list of arbitrary dynamically-allocated objects
17: m4_define(makeName, [$1])m4_dnl
18: m4_define(outputCond, [$2])m4_dnl // select 2nd arg
19: m4_define(SPC, [ ])m4_dnl // for balancing lined-up comments
20: ])m4_dnl
21: m4_define(includeLatch, makeName(OBJLIST_H))m4_dnl
22: m4_define(className, makeName(ObjList))m4_dnl
23: m4_define(iterName, makeName(ObjListIter))m4_dnl
24: m4_define(mutatorName, makeName(ObjListMutator))m4_dnl
25: m4_define(iterNameNC, makeName(ObjListIterNC))m4_dnl
26: m4_define(multiIterName, makeName(ObjListMultiIter))m4_dnl
27: m4_changequote(, )m4_dnl // so quotes are not quoted..
28: m4_changequote([[[, ]]])m4_dnl // reduce likelihood of confusion
29: // NOTE: automatically generated from xobjlist.h -- do not edit directly
30:
31: // Author: Scott McPeak, 2000
32:
33: #ifndef includeLatch
34: #define includeLatch
35:
36: #include "sm_voidlist.h"
37:
38:
39: // forward declarations of template classes, so we can befriend them in className
40: // (not required by Borland C++ 4.5, but GNU wants it...)
41: template <class T> class iterName;
42: template <class T> class mutatorName;
43: template <class T> class iterNameNC;
44:
45:
46: outputCond([[[m4_dnl // sobjlist
47: // the list is considered to not own any of the items; it's ok to
48: // insert items multiple times or into multiple lists
49: ]]], [[[m4_dnl // objlist
50: // the list is considered to own all of the items; it is an error to insert
51: // an item into more than one such list, or to insert an item more than once
52: // into any such list
53: ]]])m4_dnl
54: template <class T>
55: class className {
56: private:
57: friend class iterName<T>;
58: friend class mutatorName<T>;
59: friend class iterNameNC<T>;
60:
61: protected:
62: VoidList list; // list itself
63:
64: outputCond([[[m4_dnl // sobjlist
65: public:
66: // make shallow copies
67: className[[[]]](className const &obj) : list(obj.list) {}
68: className& operator= (className const &src) { list = src.list; return *this; }
69: ]]], [[[m4_dnl // objlist
70: private:
71: // this is an owner list; these are not allowed
72: className[[[]]](className const &obj);
73: className& operator= (className const &src);
74: ]]])m4_dnl
75:
76: public:
77: className[[[]]]() : list() {}
78: ~className[[[]]]() m4_dnl
79: outputCond({} /* all items removed */, { deleteAll(); })
80:
81: // The difference function should return <0 if left should come before
82: // right, 0 if they are equivalent, and >0 if right should come before
83: // left. For example, if we are sorting numbers into ascending order,
84: // then 'diff' would simply be subtraction.
85: typedef int (*Diff)(T const *left, T const *right, void *extra);
86:
87: // selectors
88: int count() const { return list.count(); }
89: bool isEmpty() const { return list.isEmpty(); }
90: bool isNotEmpty() const { return list.isNotEmpty(); }
91: T *nth(int which) { return (T*)list.nth(which); }
92: T const *nthC(int which) const { return (T const*)list.nth(which); }
93: T *first() { return (T*)list.first(); }
94: T const *firstC() const { return (T const*)list.first(); }
95: T *last() { return (T*)list.last(); }
96: T const *lastC() const { return (T const*)list.last(); }
97:
98: // insertion
99: void prepend(T *newitem) { list.prepend((void*)newitem); }
100: void append(T *newitem) { list.append((void*)newitem); }
101: void insertAt(T *newitem, int index) { list.insertAt((void*)newitem, index); }
102: void insertSorted(T *newitem, Diff diff, void *extra=NULL)
103: { list.insertSorted((void*)newitem, (VoidDiff)diff, extra); }
104:
105: // removal
106: T *removeAt(int index) { return (T*)list.removeAt(index); }
107: T *removeFirst() { return (T*)list.removeFirst(); }
108: outputCond([[[m4_dnl // sobjlist
109: void removeAll() { list.removeAll(); }
110: ]]], [[[m4_dnl // objlist
111: void deleteAt(int index) { delete (T*)list.removeAt(index); }
112: void deleteAll();
113: ]]])m4_dnl
114:
115: // list-as-set: selectors
116: int indexOf(T const *item) const { return list.indexOf((void*)item); }
117: int indexOfF(void *item) const { return list.indexOfF((void*)item); }
118: bool contains(T const *item) const { return list.contains((void*)item); }
119:
120: // list-as-set: mutators
121: bool prependUnique(T *newitem) { return list.prependUnique((void*)newitem); }
122: bool appendUnique(T *newitem) { return list.appendUnique((void*)newitem); }
123: void removeItem(T const *item) { list.removeItem((void*)item); } // whether the arg should be const is debatable..
124: bool removeIfPresent(T const *item) { return list.removeIfPresent((void*)item); }
125:
126: // complex modifiers
127: void reverse() { list.reverse(); }
128: void insertionSort(Diff diff, void *extra=NULL) { list.insertionSort((VoidDiff)diff, extra); }
129: void mergeSort(Diff diff, void *extra=NULL) { list.mergeSort((VoidDiff)diff, extra); }
130:
131: // and a related test
132: bool isSorted(Diff diff, void *extra=NULL) const { return list.isSorted((VoidDiff)diff, extra); }
133:
134: // multiple lists
135: void concat(className &tail) { list.concat(tail.list); }
136: outputCond([[[m4_dnl // sobjlist
137: void appendAll(className const &tail) { list.appendAll(tail.list); }
138: ]]], [[[m4_dnl // objlist
139: // (we do *not* have appendAll, since these are supposed to be owner lists)
140: ]]])m4_dnl
141:
142: // steal
143: void stealTailAt(int index, className &tail) { list.stealTailAt(index, tail.list); }
144:
145: // equal items in equal positions
146: bool equalAsLists(className const &otherList, Diff diff, void *extra=NULL) const
147: { return list.equalAsLists(otherList.list, (VoidDiff)diff, extra); }
148: int compareAsLists(className const &otherList, Diff diff, void *extra=NULL) const
149: { return list.compareAsLists(otherList.list, (VoidDiff)diff, extra); }
150:
151: // last-as-set: comparisons (NOT efficient)
152: bool equalAsSets(className const &otherList, Diff diff, void *extra=NULL) const
153: { return list.equalAsSets(otherList.list, (VoidDiff)diff, extra); }
154: bool isSubsetOf(className const &otherList, Diff diff, void *extra=NULL) const
155: { return list.isSubsetOf(otherList.list, (VoidDiff)diff, extra); }
156: bool containsByDiff(T const *item, Diff diff, void *extra=NULL) const
157: { return list.containsByDiff((void*)item, (VoidDiff)diff, extra); }
158:
159: // treating the pointer values themselves as the basis for comparison
160: bool equalAsPointerLists(className const &otherList) const
161: { return list.equalAsPointerLists(otherList.list); }
162: bool equalAsPointerSets(className const &otherList) const
163: { return list.equalAsPointerSets(otherList.list); }
164:
165: outputCond([[[m4_dnl // sobjlist
166: // debugging: no invariants beyond VoidList
167: void selfCheck() const { list.selfCheck(); }
168:
169: // but export the additional checks for cases where they apply anyway
170: void checkHeapDataPtrs() const { list.checkHeapDataPtrs(); }
171: void checkUniqueDataPtrs() const { list.checkUniqueDataPtrs(); }
172: ]]], [[[m4_dnl // objlist
173: // debugging: two additional invariants
174: void selfCheck() const {
175: list.selfCheck();
176: list.checkHeapDataPtrs();
177: list.checkUniqueDataPtrs();
178: }
179: ]]])m4_dnl
180: };
181:
182:
183: outputCond(, [[[m4_dnl // objlist
184: template <class T>
185: void ObjList<T>::deleteAll()
186: {
187: while (!list.isEmpty()) {
188: deleteAt(0);
189: }
190: }
191:
192:
193: ]]])m4_dnl
194: // for traversing the list and modifying it (nodes and/or structure)
195: // NOTE: no list-modification fns should be called on 'list' while this
196: // iterator exists, and only one such iterator should exist for
197: // any given list
198: template <class T>
199: class mutatorName {
200: friend class iterName<T>;
201:
202: protected:
203: VoidListMutator mut; // underlying mutator
204:
205: public:
206: mutatorName[[[]]](className<T> &lst) : mut(lst.list) { reset(); }
207: ~mutatorName[[[]]]() {}
208:
209: void reset() { mut.reset(); }
210:
211: // iterator copying; safe *only* until one of the mutators modifies
212: // the list structure (by inserting or removing), at which time all
213: // other iterators might be in limbo
214: mutatorName[[[]]](mutatorName const &obj) : mut(obj.mut) {}
215: mutatorName& operator=(mutatorName const &obj) { mut = obj.mut; return *this; }
216: // requires that 'this' and 'obj' already refer to the same 'list'
217:
218: // iterator actions
219: bool isDone() const { return mut.isDone(); }
220: void adv() { mut.adv(); }
221: T *data() { return (T*)mut.data(); }
222: T *&dataRef() { return (T*&)mut.dataRef(); }
223:
224: // insertion
225: void insertBefore(T *item) { mut.insertBefore((void*)item); }
226: // 'item' becomes the new 'current', and the current 'current' is
227: // pushed forward (so the next adv() will make it current again)
228:
229: void insertAfter(T *item) { mut.insertAfter((void*)item); }
230: // 'item' becomes what we reach with the next adv();
231: // isDone() must be false
232:
233: void append(T *item) { mut.append((void*)item); }
234: // only valid while isDone() is true, it inserts 'item' at the end of
235: // the list, and advances such that isDone() remains true; equivalent
236: // to { xassert(isDone()); insertBefore(item); adv(); }
237:
238: // removal
239: T *remove() { return (T*)mut.remove(); }
240: // 'current' is removed from the list and returned, and whatever was
241: // next becomes the new 'current'
242:
243: outputCond(, [[[m4_dnl // sobjlist
244: void deleteIt() { delete (T*)mut.remove(); }
245: // same as remove(), except item is deleted also
246:
247: ]]])m4_dnl
248: // debugging
249: void selfCheck() const { mut.selfCheck(); }
250: };
251:
252: #define makeName(MUTATE_EACH_OBJLIST)(T, list, iter) \
253: for(mutatorName< T > iter(list); !iter.isDone(); iter.adv())
254:
255:
256: // for traversing the list without modifying it (neither nodes nor structure)
257: // NOTE: no list-modification fns should be called on 'list' while this
258: // iterator exists
259: template <class T>
260: class iterName {
261: protected:
262: VoidListIter iter; // underlying iterator
263:
264: public:
265: iterName[[[]]](className<T> const &list) : iter(list.list) {}
266: iterName[[[]]](className<T> const &list, int pos) : iter(list.list, pos) {}
267: ~iterName[[[]]]() {}
268:
269: void reset(className<T> const &list) { iter.reset(list.list); }
270:
271: // iterator copying; generally safe
272: iterName[[[]]](iterName const &obj) : iter(obj.iter) {}
273: iterName& operator=(iterName const &obj) { iter = obj.iter; return *this; }
274:
275: // but copying from a mutator is less safe; see above
276: iterName[[[]]](mutatorName<T> &obj) : iter(obj.mut) {}
277:
278: // iterator actions
279: bool isDone() const { return iter.isDone(); }
280: void adv() { iter.adv(); }
281: T const *data() const { return (T const*)iter.data(); }
282: };
283:
284: #define makeName(FOREACH_OBJLIST)(T, list, iter) \
285: for(iterName< T > iter(list); !iter.isDone(); iter.adv())
286:
287:
288: // intermediate to the above two, this allows modification of the
289: // objects stored on the list, but not the identity or order of
290: // the objects in the list
291: template <class T>
292: class iterNameNC {
293: protected:
294: VoidListIter iter; // underlying iterator
295:
296: public:
297: iterNameNC[[[]]](className<T> &list) : iter(list.list) {}
298: iterNameNC[[[]]](className<T> &list, int pos) : iter(list.list, pos) {}
299: ~iterNameNC[[[]]]() {}
300:
301: void reset(className<T> &list) { iter.reset(list.list); }
302:
303: // iterator copying; generally safe
304: iterNameNC[[[]]](iterNameNC const &obj) : iter(obj.iter) {}
305: iterNameNC& operator=(iterNameNC const &obj) { iter = obj.iter; return *this; }
306:
307: // but copying from a mutator is less safe; see above
308: iterNameNC[[[]]](mutatorName<T> &obj) : iter(obj.mut) {}
309:
310: // iterator actions
311: bool isDone() const { return iter.isDone(); }
312: void adv() { iter.adv(); }
313: T *data() const { return (T*)iter.data(); }
314: };
315:
316: #define makeName(FOREACH_OBJLIST_NC)(T, list, iter) \
317: for(iterNameNC< T > iter(list); !iter.isDone(); iter.adv())
318:
319:
320: // iterate over the combined elements of two or more lists
321: template <class T>
322: class multiIterName {
323: private:
324: // all the lists
325: className<T> **lists; SPC// serf array of serf list pointers
326: int numLists; // length of this array
327:
328: // current element
329: int curList; // which list we're working on
330: iterName<T> iter; SPC// current element of that list
331:
332: // invariant:
333: // either curList==numLists, or
334: // iter is not 'done'
335:
336: public:
337: multiIterName[[[]]](className<T> **L, int n)
338: : lists(L),
339: numLists(n),
340: curList(0),
341: iter(*(lists[0]))
342: {
343: xassert(n > 0);
344: normalize();
345: }
346:
347: // advance the iterator to the next element of the next non-empty list;
348: // establishes invariant above
349: void normalize();
350:
351: bool isDone() const {
352: return curList == numLists;
353: }
354:
355: T const *data() const {
356: return iter.data();
357: }
358:
359: void adv() {
360: iter.adv();
361: normalize();
362: }
363: };
364:
365: // this was originally inline, but that was causing some strange
366: // problems (compiler bug?)
367: template <class T>
368: void multiIterName<T>::normalize()
369: {
370: while (iter.isDone() && curList < numLists) {
371: curList++;
372: if (curList < numLists) {
373: iter.reset(*(lists[curList]));
374: }
375: }
376: }
377:
378:
379: #endif // includeLatch
Start cpp section to elk/sm_autofile.cpp[1
/1
]
1: #line 7848 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9: FILE *xfopen(char const *fname, char const *mode)
10: {
11: FILE *ret = fopen(fname, mode);
12: if (!ret) {
13: throw_XOpen(fname);
14: }
15:
16: return ret;
17: }
18:
19:
20: AutoFILE::AutoFILE(char const *fname, char const *mode)
21: : AutoFclose(xfopen(fname, mode))
22: {}
23:
24: AutoFILE::~AutoFILE()
25: {
26:
27: }
28:
29:
30:
Start cpp section to elk/sm_bflatten.cpp[1
/1
]
1: #line 7879 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10: BFlatten::BFlatten(char const *fname, bool r)
11: : readMode(r),
12: ownerTable(!r? &BFlatten::getOwnerPtrKeyFn : &BFlatten::getIntNameKeyFn,
13: HashTable::lcprngHashFn,
14: HashTable::pointerEqualKeyFn),
15: nextUniqueName(1)
16: {
17: fp = fopen(fname, readMode? "rb" : "wb");
18: if (!fp) {
19: throw_XOpen(fname);
20: }
21: }
22:
23: BFlatten::~BFlatten()
24: {
25: fclose(fp);
26: }
27:
28:
29: STATICDEF void const* BFlatten::getOwnerPtrKeyFn(OwnerMapping *data)
30: {
31: return data->ownerPtr;
32: }
33:
34: STATICDEF void const* BFlatten::getIntNameKeyFn(OwnerMapping *data)
35: {
36: return (void const*)(data->intName);
37: }
38:
39:
40: void BFlatten::xferSimple(void *var, unsigned len)
41: {
42: if (writing()) {
43: if (fwrite(var, 1, len, fp) < len) {
44: xsyserror("fwrite");
45: }
46: }
47: else {
48: if (fread(var, 1, len, fp) < len) {
49: xsyserror("fread");
50: }
51: }
52: }
53:
54:
55: void BFlatten::noteOwner(void *ownerPtr)
56: {
57:
58: OwnerMapping *map = new OwnerMapping;
59: map->ownerPtr = ownerPtr;
60: map->intName = nextUniqueName++;
61:
62:
63: if (writing()) {
64:
65: ownerTable.add(ownerPtr, map);
66: }
67: else {
68:
69: ownerTable.add((void const*)(map->intName), map);
70: }
71: }
72:
73:
74: void BFlatten::xferSerf(void *&serfPtr, bool nullable)
75: {
76: if (writing()) {
77: xassert(nullable || serfPtr!=NULL);
78:
79: if (serfPtr == NULL) {
80:
81: writeInt(0);
82: }
83: else {
84:
85: OwnerMapping *map = ownerTable.get(serfPtr);
86:
87:
88: xassert(map != NULL);
89:
90:
91: writeInt(map->intName);
92: }
93: }
94: else /*reading*/ {
95:
96: int name = readInt();
97:
98: if (name == 0) {
99: xassert(nullable);
100: serfPtr = NULL;
101: }
102: else {
103:
104: OwnerMapping *map = ownerTable.get((void const*)name);
105: formatAssert(map != NULL);
106:
107:
108: serfPtr = map->ownerPtr;
109: }
110: }
111: }
112:
113:
114:
115:
116:
117:
118:
119: void entry()
120: {
121:
122: int x = 9, y = 22;
123: sm_string s("foo bar");
124: int *px = &x, *py = &y;
125:
126:
127: {
128: BFlatten flat("bflat.tmp", false /*reading*/);
129: flat.xferInt(x);
130: flat.noteOwner(&x);
131: s.xfer(flat);
132: flat.xferSerf((void*&)px);
133: flat.xferInt(y);
134: flat.noteOwner(&y);
135: flat.xferSerf((void*&)py);
136: }
137:
138:
139: int x2, y2;
140: sm_string s2;
141: int *px2, *py2;
142:
143:
144: {
145: BFlatten flat("bflat.tmp", true /*reading*/);
146: flat.xferInt(x2);
147: flat.noteOwner(&x2);
148: s2.xfer(flat);
149: flat.xferSerf((void*&)px2);
150: flat.xferInt(y2);
151: flat.noteOwner(&y2);
152: flat.xferSerf((void*&)py2);
153: }
154:
155:
156: xassert(x == x2);
157: xassert(y == y2);
158: xassert(s.equals(s2));
159: xassert(px2 == &x2);
160: xassert(py2 == &y2);
161:
162:
163: remove("bflat.tmp");
164:
165: printf("bflatten works\n");
166: }
167:
168:
169: USUAL_MAIN
170:
171:
172:
Start cpp section to elk/sm_bit2d.cpp[1
/1
]
1: #line 8052 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: Bit2d::Bit2d(point const &aSize)
14: : owning(true),
15: size(aSize)
16: {
17: xassert(size.x > 0 && size.y > 0);
18: stride = (size.x+7)/8;
19: data = new byte[datasize()];
20: }
21:
22:
23: Bit2d::~Bit2d()
24: {
25: if (owning) {
26: delete data;
27: }
28: }
29:
30:
31: Bit2d::Bit2d(Bit2d const &obj)
32: {
33: size = obj.size;
34: stride = obj.stride;
35: data = new byte[datasize()];
36: owning = true;
37: std::memcpy(data, obj.data, datasize());
38: }
39:
40:
41: Bit2d& Bit2d::operator= (Bit2d const &obj)
42: {
43: if (this != &obj) {
44: xassert(size == obj.size);
45: std::memcpy(data, obj.data, datasize());
46: }
47: return *this;
48: }
49:
50:
51: bool Bit2d::operator== (Bit2d const &obj) const
52: {
53: return (size == obj.size) &&
54: (0==std::memcmp(data, obj.data, datasize()));
55: }
56:
57:
58: Bit2d::Bit2d(Flatten &)
59: : data(NULL),
60: owning(true)
61: {}
62:
63: void Bit2d::xfer(Flatten &flat)
64: {
65: flat.xferInt(size.x);
66: flat.xferInt(size.y);
67: flat.xferInt(stride);
68:
69: flat.xferHeapBuffer((void*&)data, datasize());
70: }
71:
72:
73: void Bit2d::setall(int val)
74: {
75: std::memset(data, val? 0xFF : 0, datasize());
76: }
77:
78:
79: int Bit2d::get(point const &p) const
80: {
81: xassert(okpt(p));
82: return ( *(byteptrc(p)) >> (p.x&7) ) & 1;
83: }
84:
85: void Bit2d::set(point const &p)
86: {
87: xassert(okpt(p));
88: *(byteptr(p)) |= (byte) ( 1 << (p.x&7) ) ;
89: }
90:
91: void Bit2d::reset(point const &p)
92: {
93: xassert(okpt(p));
94: *(byteptr(p)) &= (byte)(~( 1 << (p.x&7) ));
95: }
96:
97: void Bit2d::setto(point const &p, int val)
98: {
99: if (val) { set(p); }
100: else { reset(p); }
101: }
102:
103: int Bit2d::testAndSet(point const &p)
104: {
105: byte *b = byteptr(p);
106: int ret = (*b >> (p.x&7)) & 1;
107: *b |= (byte)( 1 << (p.x&7) );
108: return ret;
109: }
110:
111: void Bit2d::toggle(point const &p)
112: {
113: xassert(okpt(p));
114: *(byteptr(p)) ^= (byte) ( 1 << (p.x&7) );
115: }
116:
117:
118:
119:
120: static int digits(int value)
121: {
122: xassert(value > 0);
123: int ct=0;
124: while (value > 0) {
125: ct++;
126: value /= 10;
127: }
128: return ct;
129: }
130:
131:
132: /*
133: * Goal is to draw something like this:
134: *
135: * 1 2 3
136: * 1 [ 0 0 0 ]
137: * 2 [ 0 1 1 ]
138: * 3 [ 0 1 0 ]
139: *
140: */
141: void Bit2d::print() const
142: {
143:
144: int rowLabelWidth = digits(size.y-1);
145: int colLabelWidth = digits(size.x-1);
146:
147:
148: printf("%*s ", rowLabelWidth, "");
149: loopi(size.x) {
150: printf("%*d ", colLabelWidth, i);
151: }
152: printf("\n");
153:
154: for (int row=0; row<size.y; row++) {
155: printf("%*d [ ", rowLabelWidth, row);
156: loopi(size.x) {
157: printf("%*s ", colLabelWidth,
158: get(point(i, row))? "1" : ".");
159: }
160: printf("]\n");
161: }
162: }
163:
164:
165:
166: Bit2d::Bit2d(byte * /*serf*/ d, point const &sz, int str)
167: : data(d),
168: owning(false),
169: size(sz),
170: stride(str)
171: {}
172:
173:
174:
175:
176:
177:
178:
179:
180: int main()
181: {
182: Bit2d bits(point(17,3));
183: xassert(bits.okpt(point(16,2)) &&
184: !bits.okpt(point(17,3)) &&
185: !bits.okpt(point(2,16)));
186:
187: bits.setall(0);
188: xassert(!bits.testAndSet(point(9,1)));
189: xassert(bits.testAndSet(point(9,1)));
190:
191: xassert(!bits.testAndSet(point(2,0)));
192: xassert(bits.testAndSet(point(2,0)));
193:
194: xassert(!bits.testAndSet(point(16,2)));
195: xassert(bits.testAndSet(point(16,2)));
196:
197: bits.toggle(point(3,2));
198: xassert(bits.get(point(3,2)));
199:
200: bits.print();
201:
202:
203: Bit2d *another = writeThenRead(bits);
204: xassert(*another == bits);
205: delete another;
206:
207: printf("bit2d works\n");
208:
209: return 0;
210: }
211:
212:
213:
Start cpp section to elk/sm_bitarray.cpp[1
/1
]
1: #line 8266 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11: BitArray::BitArray(int n)
12: : numBits(n)
13: {
14: bits = new unsigned char[allocdBytes()];
15: clearAll();
16: }
17:
18:
19: BitArray::~BitArray()
20: {
21: delete[] bits;
22: }
23:
24:
25: BitArray::BitArray(Flatten&)
26: : bits(NULL)
27: {}
28:
29: void BitArray::xfer(Flatten &flat)
30: {
31: flat.xferInt(numBits);
32:
33: if (flat.reading()) {
34: bits = new unsigned char[allocdBytes()];
35: }
36: flat.xferSimple(bits, allocdBytes());
37: }
38:
39:
40: void BitArray::clearAll()
41: {
42: std::memset(bits, 0, allocdBytes());
43: }
44:
Start cpp section to elk/sm_boxprint.cpp[1
/1
]
1: #line 8311 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12: BPRender::BPRender()
13: : sb(),
14: margin(72),
15: curCol(0),
16: lineStartText("")
17: {}
18:
19: BPRender::~BPRender()
20: {}
21:
22:
23: void BPRender::reset()
24: {
25: sb.clear();
26: sb << lineStartText;
27: }
28:
29:
30: void BPRender::add(char const *text)
31: {
32: int len = std::strlen(text);
33: sb << text;
34: curCol += len;
35: }
36:
37: void BPRender::breakLine(int ind)
38: {
39: sb << "\n" << lineStartText;
40:
41: for (int i=0; i < ind; i++) {
42: sb << ' ';
43: }
44:
45: curCol = ind;
46: }
47:
48:
49: sm_string BPRender::takeAndRender(BoxPrint &bld)
50: {
51: BPBox* /*owner*/ tree = bld.takeTree();
52: tree->render(*this);
53: sm_string ret(sb);
54: sb.clear();
55: delete tree;
56: return ret;
57: }
58:
59:
60:
61: bool BPElement::isBreak() const
62: {
63: return false;
64: }
65:
66: BPElement::~BPElement()
67: {}
68:
69:
70:
71: BPText::BPText(char const *t)
72: : text(t)
73: {}
74:
75: BPText::~BPText()
76: {}
77:
78:
79: int BPText::oneLineWidth()
80: {
81: return text.length();
82: }
83:
84: void BPText::render(BPRender &mgr)
85: {
86: mgr.add(text);
87: }
88:
89:
90: void BPText::debugPrint(std::ostream &os, int /*ind*/) const
91: {
92: os << "text(" << quoted(text) << ")";
93: }
94:
95:
96:
97: BPBreak::BPBreak(bool e, int i)
98: : enabled(e),
99: indent(i)
100: {}
101:
102: BPBreak::~BPBreak()
103: {}
104:
105: int BPBreak::oneLineWidth()
106: {
107: return 1;
108: }
109:
110: void BPBreak::render(BPRender &mgr)
111: {
112:
113: mgr.add(" ");
114: }
115:
116: bool BPBreak::isBreak() const
117: {
118: return enabled;
119: }
120:
121: void BPBreak::debugPrint(std::ostream &os, int /*ind*/) const
122: {
123: os << "break(en=" << (int)enabled << ", ind=" << indent << ")";
124: }
125:
126:
127:
128: BPBox::BPBox(BPKind k)
129: : elts(),
130: kind(k)
131: {
132: xassert((unsigned)k < NUM_BPKINDS);
133: }
134:
135: BPBox::~BPBox()
136: {}
137:
138:
139: int BPBox::oneLineWidth()
140: {
141: int sum = 0;
142: FOREACH_ASTLIST_NC(BPElement, elts, iter) {
143: sum += iter.data()->oneLineWidth();
144: }
145: return sum;
146: }
147:
148:
149:
150: void BPBox::render(BPRender &mgr)
151: {
152: int startCol = mgr.getCurCol();
153:
154: if (kind == BP_vertical ||
155: (kind == BP_correlated && oneLineWidth() > mgr.remainder())) {
156:
157: FOREACH_ASTLIST_NC(BPElement, elts, iter) {
158: BPElement *elt = iter.data();
159: if (elt->isBreak()) {
160: startCol += static_cast<BPBreak*>(elt)->indent;
161: mgr.breakLine(startCol);
162: }
163: else {
164: elt->render(mgr);
165: }
166: }
167: return;
168: }
169:
170: if (kind == BP_correlated) {
171:
172: FOREACH_ASTLIST_NC(BPElement, elts, iter) {
173: BPElement *elt = iter.data();
174: elt->render(mgr);
175: }
176: return;
177: }
178:
179: xassert(kind == BP_sequence);
180:
181:
182: ASTListIterNC<BPElement> cursor(elts);
183:
184:
185:
186: BPBreak *pendingBreak = NULL;
187:
188: while (!cursor.isDone()) {
189:
190: int segmentWidth = pendingBreak? 1 : 0;
191: ASTListIterNC<BPElement> lookahead(cursor);
192: while (!lookahead.isDone() && !lookahead.data()->isBreak()) {
193: segmentWidth += lookahead.data()->oneLineWidth();
194: lookahead.adv();
195: }
196:
197: if (pendingBreak && segmentWidth > mgr.remainder()) {
198:
199: startCol += pendingBreak->indent;
200: mgr.breakLine(startCol);
201: pendingBreak = NULL;
202: }
203:
204:
205: else if (pendingBreak) {
206: pendingBreak->render(mgr);
207: pendingBreak = NULL;
208: }
209:
210: xassert(pendingBreak == NULL);
211:
212:
213: while (!cursor.isDone() && !cursor.data()->isBreak()) {
214: cursor.data()->render(mgr);
215: cursor.adv();
216: }
217:
218: if (!cursor.isDone()) {
219:
220: pendingBreak = static_cast<BPBreak*>(cursor.data());
221: cursor.adv();
222: }
223: }
224:
225: if (pendingBreak) {
226:
227: pendingBreak->render(mgr);
228: }
229: }
230:
231:
232: void BPBox::debugPrint(std::ostream &os, int ind) const
233: {
234: static char const * const map[] = {
235: "vert",
236: "seq",
237: "corr"
238: };
239:
240: os << "box(kind=" << map[kind] << ") {\n";
241: ind += 2;
242:
243: FOREACH_ASTLIST(BPElement, elts, iter) {
244: for (int i=0; i<ind; i++) {
245: os << " ";
246: }
247:
248: iter.data()->debugPrint(os, ind);
249: os << "\n";
250: }
251:
252: ind -= 2;
253: for (int i=0; i<ind; i++) {
254: os << " ";
255: }
256: os << "}";
257: }
258:
259:
260:
261: BPKind const BoxPrint::vert = BP_vertical;
262: BPKind const BoxPrint::seq = BP_sequence;
263: BPKind const BoxPrint::hv = BP_correlated;
264: BPKind const BoxPrint::end = NUM_BPKINDS;
265:
266:
267: BoxPrint::BoxPrint()
268: : boxStack(),
269: levelIndent(2)
270: {
271:
272: boxStack.push(new BPBox(BP_vertical));
273: }
274:
275: BoxPrint::~BoxPrint()
276: {}
277:
278:
279: void BoxPrint::append(BPElement *elt)
280: {
281: box()->elts.append(elt);
282: }
283:
284:
285: BoxPrint& BoxPrint::operator<< (int i)
286: {
287: return operator<< (sm_stringc << i);
288: }
289:
290: BoxPrint& BoxPrint::operator<< (char const *s)
291: {
292: append(new BPText(s));
293: return *this;
294: }
295:
296:
297: BoxPrint& BoxPrint::operator<< (BPKind k)
298: {
299: if (k == NUM_BPKINDS) {
300:
301: append(boxStack.pop());
302: }
303: else {
304:
305: boxStack.push(new BPBox(k));
306: }
307: return *this;
308: }
309:
310:
311: BoxPrint& BoxPrint::operator<< (Cmd c)
312: {
313: if (c == br || c == sp) {
314: append(new BPBreak(c==br /*enabled*/, 0 /*indent*/));
315: }
316: else {
317: append(new BPBreak(true /*enabled*/, c==ind? levelIndent : -levelIndent));
318: }
319: return *this;
320: }
321:
322:
323: BoxPrint& BoxPrint::operator<< (IBreak b)
324: {
325: append(new BPBreak(true /*enabled*/, b.indent /*indent*/));
326: return *this;
327: }
328:
329:
330: BoxPrint& BoxPrint::operator<< (Op o)
331: {
332: return *this << sp << o.text << br;
333: }
334:
335:
336: BPBox* /*owner*/ BoxPrint::takeTree()
337: {
338:
339: xassert(boxStack.length() == 1);
340:
341: BPBox *ret = boxStack.pop();
342:
343:
344:
345: boxStack.push(new BPBox(BP_vertical));
346:
347: return ret;
348: }
349:
350:
351: void BoxPrint::debugPrint(std::ostream &os) const
352: {
353: for (int i=0; i < boxStack.length(); i++) {
354: os << "----- frame -----\n";
355: boxStack[i]->debugPrint(os, 0 /*ind*/);
356: os << "\n";
357: }
358: }
359:
360: void BoxPrint::debugPrintCout() const
361: {
362: debugPrint(std::cout);
363: }
364:
365:
366:
367:
368:
369:
370:
371:
372: void doit(int argc, char *argv[])
373: {
374: BoxPrint bp;
375:
376: bp << "int foo()" << bp.br
377: << "{" << bp.ind;
378:
379: bp << "printf(" << bp.seq
380: << "\"hello there %d!\\n\"," << bp.br
381: << "123456789"
382: << bp.end << ");" << bp.br;
383:
384: bp << "bar(" << bp.seq
385: << "1" << bp.op("+")
386: << "2" << bp.op("+")
387: << "3" << bp.op("+")
388: << "4" << bp.op("+")
389: << "5" << bp.op("+")
390: << "6" << bp.op("+")
391: << "7" << bp.op("+")
392: << "8" << bp.op("+")
393: << "9" << bp.op("+")
394: << "10"
395: << bp.end << ");" << bp.br;
396:
397: bp << "baz(" << bp.seq
398: << "\"a really long line that has no optional breaks at all\""
399: << bp.end << ");" << bp.br;
400:
401: bp << "zoo(" << bp.seq
402: << "\"one break is here, but it is very\"," << bp.br
403: << "\"far from the start\""
404: << bp.end << ");" << bp.br;
405:
406: bp << "assert(" << bp.seq
407: << bp.seq << "x" << bp.op("=") << "y" << bp.end << bp.op("&&")
408: << bp.seq << "z" << bp.op("=") << "w" << bp.end << bp.op("&&")
409: << "(" << bp.seq
410: << bp.seq << "moron" << bp.op("!=") << "fool" << bp.end << bp.op("||")
411: << "taxes->theRich"
412: << bp.end << ")"
413: << bp.end << ")" << bp.br;
414:
415: bp << bp.hv
416: << "forall(" << bp.seq
417: << "x," << bp.br << "y," << bp.br << "z"
418: << bp.end << "). if {" << bp.ind
419: << bp.seq << "x" << bp.op("==") << "yooey_more" << bp.end << ";" << bp.br
420: << bp.seq << "yowza" << bp.op("!=") << "fooey" << bp.end << ";"
421: << bp.und << "} /*==>*/ {" << bp.ind
422: << bp.seq << "z(x,y,z)" << bp.op("==") << "3" << bp.end << ";" << bp.br
423: << "ay_caramba" << ";"
424: << bp.und << "};"
425: << bp.end;
426:
427: bp << bp.und << "}" << bp.br;
428:
429: BPBox *tree = bp.takeTree();
430:
431: BPRender ren;
432: ren.margin = 30;
433: if (argc >= 2) {
434: ren.margin = atoi(argv[1]);
435: }
436: std::cout << "margin: " << ren.margin << "\n";
437:
438: tree->render(ren);
439: delete tree;
440:
441: std::cout << " 1 1 2 2 3 3 4 4 5 5 6 6 7\n";
442: std::cout << "1---5----0----5----0----5----0----5----0----5----0----5----0----5----0\n";
443: std::cout << ren.takeString();
444: }
445:
446: int main(int argc, char *argv[])
447: {
448: doit(argc, argv);
449:
450: return 0;
451: }
452:
453:
454:
Start cpp section to elk/sm_flatten.cpp[1
/1
]
1: #line 8766 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12: Flatten::Flatten()
13: {}
14:
15: Flatten::~Flatten()
16: {}
17:
18:
19: void Flatten::xferChar(char &c)
20: {
21: xferSimple(&c, sizeof(c));
22: }
23:
24: void Flatten::xferInt(int &i)
25: {
26: xferSimple(&i, sizeof(i));
27: }
28:
29: void Flatten::xferLong(long &l)
30: {
31: xferSimple(&l, sizeof(l));
32: }
33:
34: void Flatten::xferBool(bool &b)
35: {
36: xferSimple(&b, sizeof(b));
37: }
38:
39:
40: void Flatten::xferHeapBuffer(void *&buf, int len)
41: {
42: if (reading()) {
43: buf = new unsigned char[len];
44: }
45: xferSimple(buf, len);
46: }
47:
48:
49: void Flatten::xferCharString(char *&str)
50: {
51: if (writing()) {
52: if (!str) {
53: writeInt(-1);
54: return;
55: }
56:
57: int len = std::strlen(str);
58: writeInt(len);
59:
60:
61:
62: xferSimple(str, len+1);
63: }
64: else {
65: int len = readInt();
66: if (len == -1) {
67: str = NULL;
68: return;
69: }
70:
71: str = new char[len+1];
72: xferSimple(str, len+1);
73: formatAssert(str[len] == '\0');
74: }
75: }
76:
77:
78: void Flatten::checkpoint(int code)
79: {
80: if (writing()) {
81: writeInt(code);
82: }
83: else {
84: int c = readInt();
85: formatAssert(c == code);
86: }
87: }
88:
89:
90: void Flatten::writeInt(int i)
91: {
92: xassert(writing());
93: xferInt(i);
94: }
95:
96: int Flatten::readInt()
97: {
98: xassert(reading());
99: int i;
100: xferInt(i);
101: return i;
102: }
103:
Start cpp section to elk/sm_gprintf.cpp[1
/1
]
1: #line 8870 "./lpsrc/sm.pak"
2: /* gprintf.c */
3: /* originally from: http:
4: /* this file is in the public domain */
5:
6: /* modified by Scott McPeak, April 2003:
7: * - use va_list instead of 'const int*' for the
8: * pointer-to-argument type (for portability)
9: * - implement conservative estimates for unknown format
10: * chars, particularly 'f' (CONSERVATIVE_ESTIMATE flag)
11: * - add a few test vectors
12: */
13:
14: /* NOTE: There are quite a few differences among the *printf
15: * implementations running around in the various libcs. The
16: * implementation in this module doesn't know about all of those
17: * variations and extensions. So, if you're using this to estimate
18: * the # of chars your libc's printf will use, be sure to compare
19: * libc's printf's actual return value, to make sure something doesn't
20: * slip through the cracks. */
21:
22: /* Code for general_printf() */
23: /* Change extension to .c before compiling */
24:
25:
26:
27:
28: /* when this is true, unknown fields are filled with Xs, in an attempt
29: * to print at least as many characters as libc's sprintf */
30:
31:
32:
33:
34: struct parameters
35: {
36: int number_of_output_chars;
37: short minimum_field_width;
38: char options;
39: #define MINUS_SIGN 1
40: #define RIGHT_JUSTIFY 2
41: #define ZERO_PAD 4
42: #define CAPITAL_HEX 8
43: short edited_sm_string_length;
44: short leading_zeros;
45: int (*output_function)(void *, int);
46: void *output_pointer;
47: };
48:
49: static void output_and_count(struct parameters *p, int c)
50: {
51: if (p->number_of_output_chars >= 0)
52: {
53: int n = (*p->output_function)(p->output_pointer, c);
54: if (n>=0) p->number_of_output_chars++;
55: else p->number_of_output_chars = n;
56: }
57: }
58:
59: static void output_field(struct parameters *p, char const *s)
60: {
61: short justification_length =
62: p->minimum_field_width - p->leading_zeros - p->edited_sm_string_length;
63: if (p->options & MINUS_SIGN)
64: {
65: if (p->options & ZERO_PAD)
66: output_and_count(p, '-');
67: justification_length--;
68: }
69: if (p->options & RIGHT_JUSTIFY)
70: while (--justification_length >= 0)
71: output_and_count(p, p->options & ZERO_PAD ? '0' : ' ');
72: if (p->options & MINUS_SIGN && !(p->options & ZERO_PAD))
73: output_and_count(p, '-');
74: while (--p->leading_zeros >= 0)
75: output_and_count(p, '0');
76: while (--p->edited_sm_string_length >= 0)
77: output_and_count(p, *s++);
78: while (--justification_length >= 0)
79: output_and_count(p, ' ');
80: }
81:
82:
83: int general_vprintf(Gprintf_output_function output_function,
84: void *output_pointer,
85: const char *control_sm_string,
86: va_list argument_pointer)
87: {
88: struct parameters p;
89: char control_char;
90: p.number_of_output_chars = 0;
91: p.output_function = output_function;
92: p.output_pointer = output_pointer;
93: control_char = *control_sm_string++;
94: while (control_char != '\0')
95: {
96: if (control_char == '%')
97: {
98: short precision = -1;
99: short long_argument = 0;
100: short base = 0;
101: control_char = *control_sm_string++;
102: p.minimum_field_width = 0;
103: p.leading_zeros = 0;
104: p.options = RIGHT_JUSTIFY;
105: if (control_char == '-')
106: {
107: p.options = 0;
108: control_char = *control_sm_string++;
109: }
110: if (control_char == '0')
111: {
112: p.options |= ZERO_PAD;
113: control_char = *control_sm_string++;
114: }
115: if (control_char == '*')
116: {
117: p.minimum_field_width = va_arg(argument_pointer, int);
118: control_char = *control_sm_string++;
119: }
120: else
121: {
122: while ('0' <= control_char && control_char <= '9')
123: {
124: p.minimum_field_width =
125: p.minimum_field_width * 10 + control_char - '0';
126: control_char = *control_sm_string++;
127: }
128: }
129: if (control_char == '.')
130: {
131: control_char = *control_sm_string++;
132: if (control_char == '*')
133: {
134: precision = va_arg(argument_pointer, int);
135: control_char = *control_sm_string++;
136: }
137: else
138: {
139: precision = 0;
140: while ('0' <= control_char && control_char <= '9')
141: {
142: precision = precision * 10 + control_char - '0';
143: control_char = *control_sm_string++;
144: }
145: }
146: }
147: if (control_char == 'l')
148: {
149: long_argument = 1;
150: control_char = *control_sm_string++;
151: }
152: if (control_char == 'd')
153: base = 10;
154: else if (control_char == 'x')
155: base = 16;
156: else if (control_char == 'X')
157: {
158: base = 16;
159: p.options |= CAPITAL_HEX;
160: }
161: else if (control_char == 'u')
162: base = 10;
163: else if (control_char == 'o')
164: base = 8;
165: else if (control_char == 'b')
166: base = 2;
167: else if (control_char == 'c')
168: {
169: base = -1;
170: p.options &= ~ZERO_PAD;
171: }
172: else if (control_char == 's')
173: {
174: base = -2;
175: p.options &= ~ZERO_PAD;
176: }
177: if (base == 0) /* invalid conversion type */
178: {
179: if (control_char != '\0')
180: {
181: #if !CONSERVATIVE_ESTIMATE
182: /* sm: this was the original code; it just prints the
183: * format character itself */
184: output_and_count(&p, control_char);
185:
186: #else
187: /* since my goal is actually to compute a conservative
188: * upper bound on the # of chars output by sprintf, I want
189: * to fill unknown fields with Xs */
190: static char const * const XXX =
191: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; /* 50 Xs */
192: assert(precision <= 30); /* otherwise I need more Xs */
193:
194: /* I'm assuming that printing floating-point is the worst case.
195: * I further assume non-fractional parts (integer part,
196: * exponent, decimal, sign) won't exceed 20 chars. Finally,
197: * up to 30 characters of decimal part are supported (this
198: * is checked with the assertion above). */
199: if (precision == -1) {
200: p.edited_sm_string_length = 20 + 6; /* 6 is default precision for 'f' */
201: }
202: else {
203: p.edited_sm_string_length = 20 + precision;
204: }
205: output_field(&p, XXX);
206: #endif
207:
208: control_char = *control_sm_string++;
209: }
210: }
211: else
212: {
213: if (base == -1) /* conversion type c */
214: {
215: /* 'char' is passed as 'int' through '...' */
216: char c = (char)va_arg(argument_pointer, int);
217: p.edited_sm_string_length = 1;
218: output_field(&p, &c);
219: }
220: else if (base == -2) /* conversion type s */
221: {
222: char *sm_string;
223: p.edited_sm_string_length = 0;
224: sm_string = va_arg(argument_pointer, char*);
225: while (sm_string[p.edited_sm_string_length] != 0)
226: p.edited_sm_string_length++;
227: if (precision >= 0 && p.edited_sm_string_length > precision)
228: p.edited_sm_string_length = precision;
229: output_field(&p, sm_string);
230: }
231: else /* conversion type d, b, o or x */
232: {
233: unsigned long x;
234: char buffer[BITS_PER_BYTE * sizeof(unsigned long) + 1];
235: p.edited_sm_string_length = 0;
236: if (long_argument)
237: {
238: x = va_arg(argument_pointer, unsigned long);
239: }
240: else if (control_char == 'd')
241: x = va_arg(argument_pointer, long);
242: else
243: x = va_arg(argument_pointer, unsigned);
244: if (control_char == 'd' && (long) x < 0)
245: {
246: p.options |= MINUS_SIGN;
247: x = - (long) x;
248: }
249: do
250: {
251: int c;
252: c = x % base + '0';
253: if (c > '9')
254: {
255: if (p.options & CAPITAL_HEX)
256: c += 'A'-'9'-1;
257: else
258: c += 'a'-'9'-1;
259: }
260: buffer[sizeof(buffer) - 1 - p.edited_sm_string_length++] = c;
261: }
262: while ((x/=base) != 0);
263: if (precision >= 0 && precision > p.edited_sm_string_length)
264: p.leading_zeros = precision - p.edited_sm_string_length;
265: output_field(&p, buffer + sizeof(buffer) - p.edited_sm_string_length);
266: }
267: control_char = *control_sm_string++;
268: }
269: }
270: else
271: {
272: output_and_count(&p, control_char);
273: control_char = *control_sm_string++;
274: }
275: }
276: return p.number_of_output_chars;
277: }
278:
279:
280: int general_printf(Gprintf_output_function output,
281: void *extra, const char *format, ...)
282: {
283: va_list args;
284: int ret;
285:
286: va_start(args, format);
287: ret = general_vprintf(output, extra, format, args);
288: va_end(args);
289:
290: return ret;
291: }
292:
293:
294: /* ------------------ test code --------------------- */
295:
296:
297:
298:
299:
300:
301:
302: int sm_string_output(void *extra, int ch)
303: {
304: /* the 'extra' argument is a pointer to a pointer to the
305: * next character to write */
306: char **s = (char**)extra;
307:
308: **s = ch; /* write */
309: (*s)++; /* advance */
310:
311: return 0;
312: }
313:
314: int general_vsprintf(char *dest, char const *format, va_list args)
315: {
316: char *s = dest;
317: int ret;
318:
319: ret = general_vprintf(sm_string_output, &s, format, args);
320: *s = 0;
321:
322: return ret;
323: }
324:
325:
326: char output1[1024]; /* for libc */
327: char output2[1024]; /* for this module */
328:
329:
330: void expect_vector_len(int expect_len, char const *expect_output,
331: char const *format, va_list args)
332: {
333: int len;
334: static int vectors = 0;
335:
336: /* keep track of how many vectors we've tried, to make it
337: * a little easier to correlate failures with the inputs
338: * in this file */
339: vectors++;
340:
341: /* run the generalized vsprintf */
342: len = general_vsprintf(output2, format, args);
343:
344: /* compare */
345: if (len!=expect_len ||
346: 0!=strcmp(expect_output, output2)) {
347: printf("outputs differ for vector %d!\n", vectors);
348: printf(" format: %s\n", format);
349: printf(" expect: %s (%d)\n", expect_output, expect_len);
350: printf(" me: %s (%d)\n", output2, len);
351: exit(2);
352: }
353: }
354:
355:
356: void expect_vector(char const *expect_output,
357: char const *format, ...)
358: {
359: va_list args;
360: va_start(args, format);
361: expect_vector_len(std::strlen(expect_output), expect_output, format, args);
362: va_end(args);
363: }
364:
365:
366: void vector(char const *format, ...)
367: {
368: va_list args;
369: int len;
370:
371: /* run the real vsprintf */
372: va_start(args, format);
373: len = vsprintf(output1, format, args);
374: va_end(args);
375:
376: /* test against the generalized vsprintf */
377: va_start(args, format);
378: expect_vector_len(len, output1, format, args);
379: va_end(args);
380: }
381:
382:
383: int main()
384: {
385: printf("testing gprintf...\n");
386:
387: /* test against libc */
388: vector("simple");
389: vector("a %s more", "little");
390: vector("some %4d more %s complicated %c stuff",
391: 33, "yikes", 'f');
392:
393: /* test unknown format chars */
394: expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXX", "%f", 3.4);
395: expect_vector("XXXXXXXXXXXXXXXXXXXXXXX", "%.3f", 3.4);
396: expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.10f", 3.4);
397: expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.30f", 3.4);
398:
399: /* fails assertion, as it should */
400: /* expect_vector("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "%.31f", 3.4); */
401:
402: /* TODO: add more tests */
403:
404: printf("gprintf works\n");
405: return 0;
406: }
407:
408:
Start cpp section to elk/sm_growbuf.cpp[1
/1
]
1: #line 9279 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9: void GrowBuffer::append(byte const *str, int len)
10: {
11:
12: int newLen = getDataLen() + len;
13: if (newLen > getAllocated()) {
14:
15: int newAlloc = max(getAllocated(), 16);
16: while (newLen > newAlloc) {
17: newAlloc *= 2;
18: }
19:
20: setAllocated(newAlloc);
21: }
22:
23:
24: std::memcpy(getData()+getDataLen(), str, len);
25: setDataLen(newLen);
26: }
27:
28:
29:
30:
31:
32:
33: void entry()
34: {
35: byte const str[] = "crazy like a mad cow!";
36: int len = sizeof(str);
37:
38: GrowBuffer buf;
39: loopi(10) {
40: buf.append(str, len);
41: }
42: loopi(10) {
43: if (0!=std::memcmp(str, buf.getData()+len*i, len)) {
44: xfailure("buffer contents are wrong");
45: }
46: }
47: std::cout << "growbuf ok\n";
48: }
49:
50: USUAL_MAIN
51:
52:
Start cpp section to elk/sm_hashline.cpp[1
/1
]
1: #line 9332 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10: HashLineMap::HashLineMap(char const *pf)
11: : ppFname(pf),
12: filenames(),
13: directives(),
14: prev_ppLine(-1)
15: {}
16:
17:
18: HashLineMap::~HashLineMap()
19: {}
20:
21:
22: void HashLineMap::addHashLine(int ppLine, int origLine, char const *origFname)
23: {
24:
25: xassert(ppLine > prev_ppLine);
26: prev_ppLine = ppLine;
27:
28:
29: sm_string *canon = filenames.queryif(origFname);
30: if (!canon) {
31:
32: canon = new sm_string(origFname);
33: filenames.add(origFname, canon);
34: }
35: origFname = canon->pcharc();
36:
37:
38: directives.push(HashLine(ppLine, origLine, origFname));
39: }
40:
41:
42: void HashLineMap::doneAdding()
43: {
44:
45: ArrayStack<HashLine> tmp(directives.length());
46:
47:
48: std::memcpy(tmp.getDangerousWritableArray(), directives.getArray(),
49: directives.length() * sizeof(HashLine));
50: tmp.setLength(directives.length());
51:
52:
53:
54: tmp.swapWith(directives);
55:
56:
57: }
58:
59:
60:
61:
62:
63: void HashLineMap::map(int ppLine, int &origLine, char const *&origFname) const
64: {
65:
66: if (directives.isEmpty() ||
67: ppLine < directives[0].ppLine) {
68:
69: origLine = ppLine;
70: origFname = ppFname.pcharc();
71: return;
72: }
73:
74:
75: int low = 0;
76: int high = directives.length()-1;
77:
78: while (low < high) {
79:
80: int mid = (low+high+1)/2;
81: if (directives[mid].ppLine > ppLine) {
82:
83: high = mid-1;
84: }
85: else {
86:
87: low = mid;
88: }
89: }
90: xassert(low == high);
91: HashLine const &hl = directives[low];
92:
93:
94:
95:
96: origLine = hl.origLine + (ppLine - hl.ppLine - 1);
97:
98: origFname = hl.origFname;
99: }
100:
101:
102: int HashLineMap::mapLine(int ppLine) const
103: {
104: int origLine;
105: char const *origFname;
106: map(ppLine, origLine, origFname);
107: return origLine;
108: }
109:
110: char const *HashLineMap::mapFile(int ppLine) const
111: {
112: int origLine;
113: char const *origFname;
114: map(ppLine, origLine, origFname);
115: return origFname;
116: }
117:
118:
119:
120:
121:
122:
123:
124:
125: void query(HashLineMap &hl, int ppLine,
126: int expectOrigLine, char const *expectOrigFname)
127: {
128: int origLine;
129: char const *origFname;
130: hl.map(ppLine, origLine, origFname);
131:
132: if (origLine != expectOrigLine ||
133: 0!=strcmp(origFname, expectOrigFname)) {
134: printf("map(%d) yielded %s:%d, but I expected %s:%d\n",
135: ppLine, origFname, origLine,
136: expectOrigFname, expectOrigLine);
137: exit(2);
138: }
139: }
140:
141:
142: int main()
143: {
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157: HashLineMap hl("foo.i");
158: hl.addHashLine(2, 1, "foo.cc");
159: hl.addHashLine(5, 1, "foo.h");
160: hl.addHashLine(76, 5, "foo.cc");
161: hl.addHashLine(100, 101, "foo.i");
162: hl.doneAdding();
163:
164:
165: query(hl, 1, 1, "foo.i");
166:
167: query(hl, 3, 1, "foo.cc");
168: query(hl, 4, 2, "foo.cc");
169:
170: query(hl, 6, 1, "foo.h");
171: query(hl, 7, 2, "foo.h");
172:
173: query(hl, 75, 70, "foo.h");
174:
175: query(hl, 77, 5, "foo.cc");
176: query(hl, 78, 6, "foo.cc");
177:
178: query(hl, 99, 27, "foo.cc");
179:
180: query(hl, 101, 101, "foo.i");
181: query(hl, 102, 102, "foo.i");
182:
183:
184: printf("unique filenames: %d\n", hl.numUniqueFilenames());
185: printf("hashline seems to work\n");
186:
187: return 0;
188: }
189:
190:
Start cpp section to elk/sm_hashtbl.cpp[1
/1
]
1: #line 9523 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11: unsigned HashTable::hashFunction(void const *key) const
12: {
13: return coreHashFn(key) % (unsigned)tableSize;
14: }
15:
16:
17: HashTable::HashTable(GetKeyFn gk, HashFn hf, EqualKeyFn ek, int initSize)
18: : getKey(gk),
19: coreHashFn(hf),
20: equalKeys(ek)
21: {
22: makeTable(initSize);
23: }
24:
25: HashTable::~HashTable()
26: {
27: delete[] hashTable;
28: }
29:
30:
31: void HashTable::makeTable(int size)
32: {
33: hashTable = new void*[size];
34: tableSize = size;
35: std::memset(hashTable, 0, sizeof(void*) * tableSize);
36: numEntries = 0;
37: }
38:
39:
40: int HashTable::getEntry(void const *key) const
41: {
42: int index = hashFunction(key);
43: int originalIndex = index;
44: for(;;) {
45: if (hashTable[index] == NULL) {
46:
47: return index;
48: }
49: if (equalKeys(key, getKey(hashTable[index]))) {
50:
51: return index;
52: }
53:
54:
55:
56:
57: index = nextIndex(index);
58:
59:
60: xassert(index != originalIndex);
61: }
62: }
63:
64:
65: void *HashTable::get(void const *key) const
66: {
67: return hashTable[getEntry(key)];
68: }
69:
70:
71: void HashTable::resizeTable(int newSize)
72: {
73:
74: void **oldTable = hashTable;
75: int oldSize = tableSize;
76: int oldEntries = numEntries;
77:
78:
79: makeTable(newSize);
80:
81:
82: for (int i=0; i<oldSize; i++) {
83: if (oldTable[i] != NULL) {
84: add(getKey(oldTable[i]), oldTable[i]);
85: oldEntries--;
86: }
87: }
88: xassert(oldEntries == 0);
89:
90:
91: delete[] oldTable;
92: }
93:
94:
95: void HashTable::add(void const *key, void *value)
96: {
97: if (numEntries+1 > tableSize*2/3) {
98:
99: resizeTable(tableSize * 2 + 1);
100: }
101:
102: int index = getEntry(key);
103: xassert(hashTable[index] == NULL);
104:
105: hashTable[index] = value;
106: numEntries++;
107: }
108:
109:
110: void *HashTable::remove(void const *key)
111: {
112: if (enableShrink &&
113: numEntries-1 < tableSize/5 &&
114: tableSize > defaultSize) {
115:
116: resizeTable(tableSize / 2);
117: }
118:
119: int index = getEntry(key);
120: xassert(hashTable[index] != NULL);
121:
122:
123: void *retval = hashTable[index];
124: hashTable[index] = NULL;
125: numEntries--;
126:
127:
128:
129:
130:
131:
132: int originalIndex = index;
133: for(;;) {
134: index = nextIndex(index);
135: xassert(index != originalIndex);
136:
137: if (hashTable[index] == NULL) {
138:
139: break;
140: }
141:
142:
143: void *data = hashTable[index];
144: hashTable[index] = NULL;
145: numEntries--;
146:
147:
148: add(getKey(data), data);
149: }
150:
151: return retval;
152: }
153:
154:
155: void HashTable::empty(int initSize)
156: {
157: delete[] hashTable;
158: makeTable(initSize);
159: }
160:
161:
162: void HashTable::selfCheck() const
163: {
164: int ct=0;
165: for (int i=0; i<tableSize; i++) {
166: if (hashTable[i] != NULL) {
167: checkEntry(i);
168: ct++;
169: }
170: }
171:
172: xassert(ct == numEntries);
173: }
174:
175: void HashTable::checkEntry(int entry) const
176: {
177: int index = getEntry(getKey(hashTable[entry]));
178: int originalIndex = index;
179: for(;;) {
180: if (index == entry) {
181:
182: return;
183: }
184: if (hashTable[index] == NULL) {
185:
186:
187: xfailure("checkEntry: entry in wrong slot");
188: }
189:
190:
191: index = nextIndex(index);
192: xassert(index != originalIndex);
193: }
194: }
195:
196:
197:
198: HashTableIter::HashTableIter(HashTable &t)
199: : table(t)
200: {
201: index = 0;
202: moveToSth();
203: }
204:
205: void HashTableIter::adv()
206: {
207: xassert(!isDone());
208:
209:
210: index++;
211:
212:
213: moveToSth();
214: }
215:
216: void HashTableIter::moveToSth()
217: {
218: while (index < table.tableSize &&
219: table.hashTable[index] == NULL) {
220: index++;
221: }
222:
223: if (index == table.tableSize) {
224: index = -1;
225: }
226: }
227:
228:
229: void *HashTableIter::data() const
230: {
231: xassert(!isDone());
232: return table.hashTable[index];
233: }
234:
235:
236: STATICDEF void const *HashTable::identityKeyFn(void *data)
237: {
238: return data;
239: }
240:
241: unsigned lcprngTwoSteps(SM_RAWADDRESS v)
242: {
243:
244:
245: v = (v * 1103515245) + 12345;
246:
247:
248: v = (v * 1103515245) + 12345;
249:
250: return v;
251: }
252:
253: STATICDEF unsigned HashTable::lcprngHashFn(void const *key)
254: {
255: return lcprngTwoSteps((SM_RAWADDRESS)key);
256: }
257:
258: STATICDEF bool HashTable::
259: pointerEqualKeyFn(void const *key1, void const *key2)
260: {
261: return key1 == key2;
262: }
263:
Start cpp section to elk/sm_mysig.cpp[1
/1
]
1: #line 9787 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: void setHandler(int signum, SignalHandler handler)
20: {
21: struct sigaction sa;
22: std::memset(&sa, 0, sizeof(sa));
23: sa.sa_handler = handler;
24: sigemptyset(&sa.sa_mask);
25: sa.sa_flags = SA_RESTART;
26:
27:
28: if (0 > sigaction(signum, &sa, NULL)) {
29: perror("sigaction");
30: exit(2);
31: }
32: }
33:
34:
35:
36: void printHandler(int signum)
37: {
38: fprintf(stderr, "printHandler: I caught signal %d\n", signum);
39: psignal(signum, "psignal message");
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51: setHandler(signum, SIG_DFL);
52:
53:
54:
55:
56:
57: fprintf(stderr, "re-raising...\n");
58: raise(signum);
59: }
60:
61:
62: jmp_buf sane_state;
63:
64:
65: void jmpHandler(int signum)
66: {
67:
68: psignal(signum, "jmpHandler: caught signal");
69:
70:
71: setHandler(signum, SIG_DFL);
72:
73:
74:
75: longjmp(sane_state, 1);
76: }
77:
78:
79: void printAddrHandler(int signum, siginfo_t *info, void *)
80: {
81: fprintf(stderr, "faulting address: %p\n", (info->si_addr));
82:
83:
84: setHandler(signum, SIG_DFL);
85: raise(signum);
86: }
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101: void printSegfaultAddrs()
102: {
103:
104:
105:
106:
107:
108:
109: #if 0
110:
111: struct sigaltstack sas;
112: sas.ss_sp = mysigstack;
113: sas.ss_size = MYSZ;
114: sas.ss_flags = SS_ONSTACK;
115:
116: if (0 > sigaltstack(&sas, NULL)) {
117: perror("sigaltstack");
118: exit(2);
119: }
120: #endif
121:
122:
123:
124:
125:
126:
127:
128:
129:
130: struct sigaction sa;
131: std::memset(&sa, 0, sizeof(sa));
132: sa.sa_sigaction = printAddrHandler;
133: sigemptyset(&sa.sa_mask);
134: sa.sa_flags = SA_SIGINFO;
135:
136:
137: if (0 > sigaction(SIGSEGV, &sa, NULL)) {
138: perror("sigaction");
139: exit(2);
140: }
141: }
142:
143:
144:
145:
146:
147: static void infiniteRecursion()
148: {
149: char buf[1024];
150: buf[0] = 4;
151: buf[1] = buf[0];
152: buf[1023] = 6;
153: infiniteRecursion();
154: }
155:
156: int main(int argc, char **argv)
157: {
158: if (argc >= 2) {
159:
160: printSegfaultAddrs();
161:
162: if (0==strcmp(argv[1], "inf")) {
163:
164: printf("going into infinite recursion...\n");
165: infiniteRecursion();
166: }
167:
168: int addr = strtoul(argv[1], NULL /*endp*/, 0 /*radix*/);
169: printf("about to access 0x%08X ...\n", addr);
170: *((int*)addr) = 0;
171: return 0;
172: }
173:
174: if (setjmp(sane_state) == 0) {
175: setHandler(SIGINT, printHandler);
176: setHandler(SIGTERM, printHandler);
177: setHandler(SIGUSR1, jmpHandler);
178: setHandler(SIGSEGV, jmpHandler);
179: setHandler(SIGBUS, jmpHandler);
180:
181:
182:
183: printf("about to deliberately cause a segfault ...\n");
184: *((int*)0) = 0;
185:
186: printf("didn't segfault??\n");
187: return 2;
188: }
189:
190: else {
191: printf("came back from a longjmp!\n");
192: printf("\nmysig works\n");
193: return 0;
194: }
195: }
196:
197:
198:
199:
200:
201: void setHandler(int, SignalHandler) {}
202: void printHandler(int) {}
203: jmp_buf sane_state;
204: void jmpHandler(int) {}
205:
206:
207: int main()
208: {
209: printf("mysig on cygwin: nop\n");
210: return 0;
211: }
212:
213:
214:
Start cpp section to elk/sm_point.cpp[1
/1
]
1: #line 10002 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8: sm_stringBuilder& operator<< (sm_stringBuilder &sb, point const &pt)
9: {
10: return sb << "(" << pt.x << ", " << pt.y << ")";
11: }
12:
13: sm_stringBuilder& operator<< (sm_stringBuilder &sb, fpoint const &pt)
14: {
15: return sb << "(" << pt.x << ", " << pt.y << ")";
16: }
Start cpp section to elk/sm_pprint.cpp[1
/1
]
1: #line 10019 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12: void PPrintStringOut::write(char const *text)
13: {
14: sb << text;
15: }
16:
17: void PPrintOstreamOut::write(char const *text)
18: {
19: os << text;
20: }
21:
22:
23:
24: bool PPrint::warnWhenUnbalanced = true;
25:
26: PPrint::PPrint(PPrintOut &o)
27: : line(),
28: lineIndent(0),
29: margin(72),
30: altIndent(2),
31: startText(NULL),
32: out(o)
33: {}
34:
35: PPrint::~PPrint()
36: {
37: if (line.length() > 0) {
38:
39:
40: breaker();
41:
42:
43: print("\n");
44: }
45: }
46:
47:
48: struct BreakInfo {
49: int p;
50: int pCol;
51: int pInd;
52:
53: BreakInfo(int pp, int pc, int pi)
54: : p(pp), pCol(pc), pInd(pi) {}
55: BreakInfo() {}
56:
57:
58:
59:
60: int sum(/*int margin*/) const {
61:
62:
63: return pCol +
64: (/*margin*/ - pInd);
65: }
66:
67:
68: bool betterThan(BreakInfo const &obj /*, int margin*/) {
69: if (sum(/*margin*/) > obj.sum(/*margin*/))
70: { return true; }
71:
72:
73:
74:
75: if (sum(/*margin*/) == obj.sum(/*margin*/) &&
76: pInd < obj.pInd)
77: { return true; }
78:
79: return false;
80: }
81: };
82:
83:
84: void PPrint::Setter::indent(int amt)
85: {
86: for (int i=0; i<amt; i++) {
87: curLine << ' ';
88: }
89: }
90:
91:
92: void PPrint::Setter::set()
93: {
94:
95: indentGroups.push(pprint.lineIndent);
96:
97:
98: while (lineIndex < pprint.line.length()) {
99:
100: curLineInd = indentGroups.top();
101: indent(curLineInd);
102:
103:
104:
105: ArrayStack<BreakInfo> breaks;
106:
107:
108: int p = lineIndex;
109:
110:
111: int pCol = curLine.length();
112:
113:
114:
115: ArrayStack<int> pInd;
116:
117:
118:
119:
120: {
121: pInd.ensureAtLeast(indentGroups.length());
122: for (int i=0; i < indentGroups.length(); i++) {
123: pInd[i] = indentGroups[i];
124: }
125: pInd.setLength(indentGroups.length());
126: }
127:
128: while (p < pprint.line.length()-1 && pCol < pprint.margin) {
129: switch (pprint.line[p]) {
130: case '\r':
131: breaks.push(BreakInfo(p, pCol, pInd.top()));
132: pCol++;
133: break;
134:
135: case '\b':
136: pInd.push(pCol);
137: break;
138:
139: case '\a':
140: pInd.push(curLineInd + pprint.altIndent);
141: break;
142:
143: case '\f':
144: pInd.pop();
145: break;
146:
147: default:
148:
149: pCol++;
150: break;
151: }
152:
153: p++;
154: }
155:
156: if (pCol < pprint.margin) {
157:
158:
159: emitTo(p+1 /*include newline*/);
160: flush();
161: return;
162: }
163:
164: if (breaks.isEmpty()) {
165:
166:
167: while (p < pprint.line.length()-1) {
168: if (pprint.line[p] == '\r') {
169: emitTo(p /*not including '\r'*/);
170: lineIndex++;
171: curLine << '\n';
172: flush();
173: break;
174: }
175:
176: p++;
177: }
178:
179: if (p == pprint.line.length()-1) {
180:
181: emitTo(p+1 /*include newline*/);
182: flush();
183: return;
184: }
185: }
186:
187: else {
188:
189: int best = 0;
190: for (int i=1; i < breaks.length(); i++) {
191: if (breaks[i].betterThan(breaks[best] /*, pprint.margin*/)) {
192: best = i;
193: }
194: }
195:
196:
197: emitTo(breaks[best].p /*not including '\r'*/);
198: lineIndex++;
199: curLine << '\n';
200: flush();
201: }
202: }
203: }
204:
205: PPrint::Setter::~Setter()
206: {
207: if (indentGroups.length() != 1) {
208:
209: breaker();
210: if (warnWhenUnbalanced) {
211: std::cout << "warning: unbalanced indentation grouping in pprint input\n";
212: }
213: }
214: }
215:
216:
217: void PPrint::Setter::emitTo(int p)
218: {
219: while (lineIndex < p) {
220: char ch = pprint.line[lineIndex];
221: switch (ch) {
222: case '\r':
223:
224: curLine << ' ';
225: break;
226:
227: case '\b':
228: indentGroups.push(curLine.length());
229: break;
230:
231: case '\a':
232: indentGroups.push(curLineInd + pprint.altIndent);
233: break;
234:
235: case '\f':
236: indentGroups.pop();
237: break;
238:
239: default:
240: curLine << ch;
241: break;
242: }
243:
244: lineIndex++;
245: }
246: }
247:
248:
249: void PPrint::Setter::flush()
250: {
251: if (pprint.startText) {
252: pprint.out.write(pprint.startText);
253: }
254: pprint.out.write(curLine);
255: curLine.clear();
256: }
257:
258:
259: void PPrint::set()
260: {
261:
262: xassert(line[line.length()-1] == '\n');
263:
264: Setter s(*this);
265: s.set();
266:
267:
268: line.setLength(0);
269: }
270:
271:
272: void append(ArrayStack<char> &line, char const *src, int len)
273: {
274: line.ensureAtLeast(line.length() + len);
275: std::memcpy(line.getArrayNC()+line.length(),
276: src, len);
277: line.setLength(line.length() + len);
278: }
279:
280: void PPrint::print(char const *text)
281: {
282:
283: char const *p = text;
284: while (*p != 0) {
285: if (*p == '\n') {
286:
287: int copylen = p-text+1;
288: append(line, text, copylen);
289:
290:
291:
292: text += copylen;
293:
294:
295: set();
296: }
297:
298: p++;
299: }
300:
301:
302: append(line, text, p-text);
303: }
304:
305:
306: PPrint& PPrint::operator<< (int i)
307: {
308: char tmp[40];
309: sprintf(tmp, "%d", i);
310: print(tmp);
311: return *this;
312: }
313:
314: PPrint& PPrint::operator<< (char const *s)
315: {
316: print(s);
317: return *this;
318: }
319:
320:
321: PPrintToString::~PPrintToString()
322: {}
323:
324:
325:
326:
327:
328: PPrintToString pp;
329:
330: int main()
331: {
332: pp.margin = 30;
333: pp.startText = "; ";
334:
335: std::cout << " 1 1 2 2 3\n";
336: std::cout << "1---5----0----5----0----5----0\n";
337:
338: pp << "int foo()\n"
339: "{\n"
340: ;
341: pp.ind(+2);
342: pp << "printf(\b\"hello there %d!\\n\",\r123456789\f);\n";
343: pp << "bar(\b1 +\r2 +\r3 +\r4 +\r5 +\r6 +\r7 +\r8 +\r9 +\r10\f);\n";
344: pp << "baz(\b\"a really long line that has no optional breaks at all\"\f);\n";
345: pp << "zoo(\b\"one break is here, but it is very\",\r\"far from the start\"\f);\n";
346: pp << "assert(\bx ==\ry &&\rz ==\rw &&\r"
347: "(\bmoron !=\rfool ||\rtaxes->theRich\f)\f);\n";
348: pp << "\aforall(x, y, z). if {\r"
349: "x == yooey_more;\r"
350: "yowza != fooey;\f\r"
351: "} {\a\r"
352: "z(x,y,z)==3;\r"
353: "ay_caramba;\f\r"
354: "}\n";
355: pp.ind(-2);
356: pp << "}\n";
357:
358: std::cout << pp.sb;
359:
360: return 0;
361: }
362:
363:
364:
Start cpp section to elk/sm_regexp.cpp[1
/1
]
1: #line 10384 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25: static sm_string regexpErrorString(regex_t const *pat, int code)
26: {
27:
28:
29: int size = regerror(code, pat, NULL, 0);
30:
31:
32: sm_string ret(size);
33: regerror(code, pat, ret.pchar(), size);
34:
35: return ret;
36: }
37:
38:
39: static void regexpError(regex_t const *pat, int code) NORETURN;
40: static void regexpError(regex_t const *pat, int code)
41: {
42: xbase(regexpErrorString(pat, code));
43: }
44:
45:
46:
47:
48:
49:
50: Regexp::Regexp(char const *exp, CFlags flags)
51: {
52: PAT = new regex_t;
53:
54: int f = REG_EXTENDED;
55:
56:
57:
58:
59:
60:
61: if (REG_ICASE==ICASE && REG_NOSUB==NOSUB) {
62: f |= (int)flags;
63: }
64: else {
65:
66: if (flags & ICASE) f |= REG_ICASE;
67: if (flags & NOSUB) f |= REG_NOSUB;
68: }
69:
70: int code = regcomp(PAT, exp, f);
71: if (code) {
72:
73: sm_string msg = regexpErrorString(PAT, code);
74: delete PAT;
75: xbase(msg);
76: }
77: }
78:
79: Regexp::~Regexp()
80: {
81: regfree(PAT);
82: delete PAT;
83: }
84:
85:
86: void Regexp::err(int code)
87: {
88: regexpError(PAT, code);
89: }
90:
91:
92: bool Regexp::match(char const *str, EFlags flags)
93: {
94: int f = 0;
95:
96:
97: if (REG_NOTBOL==NOTBOL && REG_NOTEOL==NOTEOL) {
98: f = (int)flags;
99: }
100: else {
101: if (flags & NOTBOL) f |= REG_NOTBOL;
102: if (flags & NOTEOL) f |= REG_NOTEOL;
103: }
104:
105: int code = regexec(PAT, str, 0, NULL, f);
106: if (code == 0) {
107: return true;
108: }
109: else if (code == REG_NOMATCH) {
110: return false;
111: }
112: else {
113: err(code);
114: }
115: }
116:
117:
118:
119:
120:
121:
122: bool regexpMatch(char const *str, char const *exp)
123: {
124: Regexp pat(exp, Regexp::NOSUB);
125: return pat.match(str);
126: }
127:
128:
129:
130:
131:
132:
133:
134:
135:
136: void matchVector(char const *str, char const *exp, bool expect)
137: {
138: bool actual = regexpMatch(str, exp);
139: if (actual != expect) {
140: printf("regexp failure\n");
141: printf(" str: %s\n", str);
142: printf(" exp: %s\n", exp);
143: printf(" expect: %s\n", (expect? "true" : "false"));
144: printf(" actual: %s\n", (actual? "true" : "false"));
145: exit(2);
146: }
147: }
148:
149:
150: int main()
151: {
152: matchVector("abc", "a", true);
153: matchVector("abc", "b", true);
154: matchVector("abc", "c", true);
155: matchVector("abc", "d", false);
156:
157: matchVector("abc", "^a", true);
158: matchVector("abc", "^b", false);
159: matchVector("abc", "b$", false);
160: matchVector("abc", "c$", true);
161: matchVector("abc", "^d", false);
162:
163: printf("regexp works\n");
164: return 0;
165: }
166:
167:
168:
Start cpp section to elk/sm_srcloc.cpp[1
/1
]
1: #line 10553 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: enum { MARKER_PERIOD = 100 };
20:
21:
22:
23: void addLineLength(ArrayStack<unsigned char> &lengths, int len)
24: {
25: while (len >= 255) {
26:
27: lengths.push(255);
28: len -= 254;
29: }
30:
31:
32: lengths.push((unsigned char)len);
33: }
34:
35:
36: SourceLocManager::File::File(char const *n, SourceLoc aStartLoc)
37: : name(n),
38: startLoc(aStartLoc),
39: hashLines(NULL),
40:
41:
42: marker(0, 1, 0),
43: markerCol(1)
44: {
45: AutoFILE fp(name, "r");
46:
47:
48:
49:
50: setbuf(fp, NULL);
51:
52:
53:
54:
55:
56: ArrayStack<unsigned char> lineLengths;
57: ArrayStack<Marker> index;
58:
59:
60: index.push(Marker(0, 1, 0));
61:
62:
63: int indexDelay = MARKER_PERIOD;
64:
65:
66: int charOffset = 0;
67: int lineNum = 1;
68: int lineLen = 0;
69:
70:
71: enum { BUFLEN=8192 };
72: char buf[BUFLEN];
73: for (;;) {
74:
75: int len = fread(buf, 1, BUFLEN, fp);
76: if (len < 0) {
77: xsyserror("fread", name);
78: }
79: if (len==0) {
80: break;
81: }
82:
83:
84:
85:
86: char const *start = buf;
87: char const *p = buf;
88: char const *end = buf+len;
89:
90:
91: while (start < end) {
92:
93: while (p<end && *p!='\n') {
94: p++;
95: }
96: if (p==end) {
97: break;
98: }
99: xassert(*p == '\n');
100:
101:
102: charOffset += p-start;
103: lineLen += p-start;
104: start = p;
105:
106:
107: addLineLength(lineLengths, lineLen);
108: charOffset++;
109: lineNum++;
110: lineLen = 0;
111:
112: p++;
113: start++;
114:
115: if (--indexDelay == 0) {
116:
117: index.push(Marker(charOffset, lineNum, lineLengths.length()));
118: indexDelay = MARKER_PERIOD;
119: }
120: }
121:
122:
123: charOffset += p-start;
124: lineLen += p-start;
125: start = p;
126: xassert(start == end);
127: }
128:
129:
130:
131:
132: addLineLength(lineLengths, lineLen);
133: charOffset += lineLen;
134:
135:
136: this->numChars = charOffset;
137: this->numLines = lineNum-1;
138: if (numLines == 0) {
139:
140: this->avgCharsPerLine = numChars;
141: }
142: else {
143: this->avgCharsPerLine = numChars / numLines;
144: }
145:
146: this->lineLengthsSize = lineLengths.length();
147: this->lineLengths = new unsigned char[lineLengthsSize];
148: std::memcpy(this->lineLengths, lineLengths.getArray(),
149: lineLengthsSize * sizeof(this->lineLengths[0]));
150:
151: this->indexSize = index.length();
152: this->index = new Marker[indexSize];
153: std::memcpy(this->index, index.getArray(),
154: indexSize * sizeof(this->index[0]));
155:
156:
157: }
158:
159:
160: SourceLocManager::File::~File()
161: {
162: if (hashLines) {
163: delete hashLines;
164: }
165: delete[] lineLengths;
166: }
167:
168:
169: void SourceLocManager::File::resetMarker()
170: {
171: marker.charOffset = 0;
172: marker.lineOffset = 1;
173: marker.arrayOffset = 0;
174: markerCol = 1;
175: }
176:
177:
178:
179:
180: inline void SourceLocManager::File::advanceMarker()
181: {
182: int len = (int)lineLengths[marker.arrayOffset];
183: if (len < 255) {
184:
185: marker.charOffset += len+1;
186: marker.lineOffset++;
187: marker.arrayOffset++;
188: markerCol = 1;
189: }
190: else {
191:
192: marker.charOffset += 254;
193: marker.arrayOffset++;
194: markerCol += 254;
195: }
196: }
197:
198:
199: int SourceLocManager::File::lineToChar(int lineNum)
200: {
201: if (lineNum == numLines+1) {
202:
203: return numChars;
204: }
205:
206: xassert(1 <= lineNum && lineNum <= numLines);
207:
208:
209: if (marker.lineOffset <= lineNum &&
210: lineNum < marker.lineOffset + MARKER_PERIOD) {
211:
212: }
213: else {
214:
215:
216: int low = 0;
217: int high = indexSize-1;
218: while (low < high) {
219:
220: int mid = (low+high+1)/2;
221: if (index[mid].lineOffset > lineNum) {
222:
223: high = mid-1;
224: }
225: else {
226:
227: low = mid;
228: }
229: }
230:
231:
232: marker = index[low];
233: markerCol = 1;
234: }
235:
236: xassert(marker.lineOffset <= lineNum);
237:
238:
239:
240: while (marker.lineOffset < lineNum) {
241: advanceMarker();
242: }
243:
244:
245: xassert(marker.arrayOffset < lineLengthsSize);
246:
247:
248: return marker.charOffset - (markerCol-1);
249: }
250:
251:
252: int SourceLocManager::File::lineColToChar(int lineNum, int col)
253: {
254:
255: int offset = lineToChar(lineNum);
256:
257:
258:
259:
260: if (col <= markerCol) {
261:
262:
263:
264: return offset + (col-1);
265: }
266:
267:
268:
269:
270: offset = marker.charOffset;
271: col -= markerCol;
272:
273:
274:
275:
276:
277: int index = marker.arrayOffset;
278: for (;;) {
279: int len = (int)lineLengths[index];
280: if (col <= len) {
281:
282:
283: return offset + col;
284: }
285: if (len < 255) {
286:
287: SourceLocManager::shortLineCount++;
288: return offset + len;
289: }
290:
291:
292: xassertdb(len == 255);
293:
294: col -= 254;
295: offset += 254;
296: xassertdb(col > 0);
297:
298: index++;
299: xassert(index < lineLengthsSize);
300: }
301: }
302:
303:
304: void SourceLocManager::File::charToLineCol(int offset, int &line, int &col)
305: {
306: if (offset == numChars) {
307:
308: line = numLines+1;
309: col = 1;
310: return;
311: }
312:
313: xassert(0 <= offset && offset < numChars);
314:
315:
316: if (marker.charOffset <= offset &&
317: offset < marker.charOffset + MARKER_PERIOD*avgCharsPerLine) {
318:
319: }
320: else {
321:
322: int low = 0;
323: int high = indexSize-1;
324: while (low < high) {
325:
326: int mid = (low+high+1)/2;
327: if (index[mid].charOffset > offset) {
328: high = mid-1;
329: }
330: else {
331: low = mid;
332: }
333: }
334:
335:
336: marker = index[low];
337: markerCol = 1;
338: }
339:
340: xassert(marker.charOffset <= offset);
341:
342:
343:
344: while (marker.charOffset + lineLengths[marker.arrayOffset] < offset) {
345: advanceMarker();
346: }
347:
348:
349: xassert(marker.arrayOffset < lineLengthsSize);
350:
351:
352: line = marker.lineOffset;
353: col = markerCol + (offset - marker.charOffset);
354: }
355:
356:
357: void SourceLocManager::File::addHashLine
358: (int ppLine, int origLine, char const *origFname)
359: {
360: if (!hashLines) {
361: hashLines = new HashLineMap(name);
362: }
363: hashLines->addHashLine(ppLine, origLine, origFname);
364: }
365:
366: void SourceLocManager::File::doneAdding()
367: {
368: if (hashLines) {
369: hashLines->doneAdding();
370: }
371: else {
372:
373:
374: }
375: }
376:
377:
378:
379: SourceLocManager::StaticLoc::~StaticLoc()
380: {}
381:
382:
383:
384: int SourceLocManager::shortLineCount = 0;
385:
386: SourceLocManager *sourceLocManager = NULL;
387:
388:
389: SourceLocManager::SourceLocManager()
390: : files(),
391: recent(NULL),
392: statics(),
393: nextLoc(toLoc(1)),
394: nextStaticLoc(toLoc(0)),
395: maxStaticLocs(100),
396: useHashLines(true)
397: {
398: if (!sourceLocManager) {
399: sourceLocManager = this;
400: }
401:
402:
403: SourceLoc u = encodeStatic(StaticLoc("<noloc>", 0,1,1));
404: xassert(u == SL_UNKNOWN);
405: PRETEND_USED(u);
406:
407:
408: u = encodeStatic(StaticLoc("<init>", 0,1,1));
409: xassert(u == SL_INIT);
410: PRETEND_USED(u);
411: }
412:
413: SourceLocManager::~SourceLocManager()
414: {
415: if (sourceLocManager == this) {
416: sourceLocManager = NULL;
417: }
418: }
419:
420:
421:
422: SourceLocManager::File *SourceLocManager::findFile(char const *name)
423: {
424: if (!this) {
425:
426:
427:
428:
429: xfailure("you have to create a SourceLocManager in your main() function");
430: }
431:
432: if (recent && recent->name.equals(name)) {
433: return recent;
434: }
435:
436: FOREACH_OBJLIST_NC(File, files, iter) {
437: if (iter.data()->name.equals(name)) {
438: return recent = iter.data();
439: }
440: }
441:
442: return NULL;
443: }
444:
445:
446: SourceLocManager::File *SourceLocManager::getFile(char const *name)
447: {
448: File *f = findFile(name);
449: if (!f) {
450:
451: f = new File(name, nextLoc);
452: files.append(f);
453:
454:
455:
456: nextLoc = toLoc(f->startLoc + f->numChars + 1);
457: }
458:
459: return recent = f;
460: }
461:
462:
463: SourceLoc SourceLocManager::encodeOffset(
464: char const *filename, int charOffset)
465: {
466: xassert(charOffset >= 0);
467:
468: File *f = getFile(filename);
469: return toLoc(f->startLoc + charOffset);
470: }
471:
472:
473: SourceLoc SourceLocManager::encodeLineCol(
474: char const *filename, int line, int col)
475: {
476: xassert(line >= 1);
477: xassert(col >= 1);
478:
479: File *f = getFile(filename);
480:
481:
482: #if 1
483: int charOffset = f->lineColToChar(line, col);
484: return toLoc(toInt(f->startLoc) + charOffset);
485: #else
486: int charOffset = f->lineToChar(line);
487: return toLoc(toInt(f->startLoc) + charOffset + (col-1));
488: #endif
489: }
490:
491:
492: SourceLoc SourceLocManager::encodeStatic(StaticLoc const &obj)
493: {
494: if (-toInt(nextStaticLoc) == maxStaticLocs) {
495:
496:
497:
498:
499:
500:
501:
502:
503:
504: fprintf(stderr,
505: "Warning: You've created %d static locations, which is symptomatic\n"
506: "of a bug. See %s, line %d.\n",
507: maxStaticLocs, __FILE__, __LINE__);
508: }
509:
510:
511: statics.append(new StaticLoc(obj));
512:
513:
514: SourceLoc ret = nextStaticLoc;
515: nextStaticLoc = toLoc(toInt(ret) - 1);
516: return ret;
517: }
518:
519:
520: SourceLocManager::File *SourceLocManager::findFileWithLoc(SourceLoc loc)
521: {
522:
523: if (recent && recent->hasLoc(loc)) {
524: return recent;
525: }
526:
527:
528: FOREACH_OBJLIST_NC(File, files, iter) {
529: if (iter.data()->hasLoc(loc)) {
530: return recent = iter.data();
531: }
532: }
533:
534:
535: xfailure("invalid source location");
536: return NULL;
537: }
538:
539:
540: SourceLocManager::StaticLoc const *SourceLocManager::getStatic(SourceLoc loc)
541: {
542: int index = -toInt(loc);
543: return statics.nthC(index);
544: }
545:
546:
547: void SourceLocManager::decodeOffset(
548: SourceLoc loc, char const *&filename, int &charOffset)
549: {
550:
551: if (isStatic(loc)) {
552: StaticLoc const *s = getStatic(loc);
553: filename = s->name.pcharc();
554: charOffset = s->offset;
555: return;
556: }
557:
558: File *f = findFileWithLoc(loc);
559: filename = f->name.pcharc();
560: charOffset = toInt(loc) - toInt(f->startLoc);
561:
562: if (useHashLines && f->hashLines) {
563:
564:
565:
566:
567:
568: int ppLine, ppCol;
569: f->charToLineCol(charOffset, ppLine, ppCol);
570:
571:
572: int origLine;
573: char const *origFname;
574: f->hashLines->map(ppLine, origLine, origFname);
575:
576:
577:
578: File *orig = getFile(origFname);
579:
580:
581:
582: charOffset = orig->lineColToChar(origLine, ppCol);
583:
584:
585: filename = origFname;
586: }
587: }
588:
589:
590: void SourceLocManager::decodeLineCol(
591: SourceLoc loc, char const *&filename, int &line, int &col)
592: {
593: if (!this) {
594:
595: if (loc == SL_UNKNOWN) {
596: filename = "<noloc>";
597: line = 1;
598: col = 1;
599: return;
600: }
601: else {
602: xfailure("you have to create a SourceLocManager in your main() function");
603: }
604: }
605:
606:
607: if (isStatic(loc)) {
608: StaticLoc const *s = getStatic(loc);
609: filename = s->name.pcharc();
610: line = s->line;
611: col = s->col;
612: return;
613: }
614:
615: File *f = findFileWithLoc(loc);
616: filename = f->name.pcharc();
617: int charOffset = toInt(loc) - toInt(f->startLoc);
618:
619: f->charToLineCol(charOffset, line, col);
620:
621: if (useHashLines && f->hashLines) {
622:
623:
624:
625: f->hashLines->map(line, line, filename);
626: }
627: }
628:
629:
630: char const *SourceLocManager::getFile(SourceLoc loc)
631: {
632: char const *name;
633: int ofs;
634: decodeOffset(loc, name, ofs);
635: return name;
636: }
637:
638:
639: int SourceLocManager::getOffset(SourceLoc loc)
640: {
641: char const *name;
642: int ofs;
643: decodeOffset(loc, name, ofs);
644: return ofs;
645: }
646:
647:
648: int SourceLocManager::getLine(SourceLoc loc)
649: {
650: char const *name;
651: int line, col;
652: decodeLineCol(loc, name, line, col);
653: return line;
654: }
655:
656:
657: int SourceLocManager::getCol(SourceLoc loc)
658: {
659: char const *name;
660: int line, col;
661: decodeLineCol(loc, name, line, col);
662: return col;
663: }
664:
665:
666: sm_string SourceLocManager::getString(SourceLoc loc)
667: {
668: char const *name;
669: int line, col;
670: decodeLineCol(loc, name, line, col);
671:
672: return sm_stringc << name << ":" << line << ":" << col;
673: }
674:
675: sm_string SourceLocManager::getLCString(SourceLoc loc)
676: {
677: char const *name;
678: int line, col;
679: decodeLineCol(loc, name, line, col);
680:
681: return sm_stringc << line << ":" << col;
682: }
683:
684:
685: sm_string locToStr(SourceLoc sl)
686: {
687: return sourceLocManager->getString(sl);
688: }
689:
690:
691:
692:
693:
694:
695:
696:
697:
698:
699: SourceLocManager mgr;
700: int longestLen=0;
701:
702:
703:
704: void testRoundTrip(SourceLoc loc)
705: {
706: char const *fname;
707: int line, col;
708: mgr.decodeLineCol(loc, fname, line, col);
709:
710: if (col > longestLen) {
711: longestLen = col;
712: }
713:
714: SourceLoc loc2 = mgr.encodeLineCol(fname, line, col);
715:
716: xassert(loc == loc2);
717: }
718:
719:
720:
721:
722:
723:
724:
725:
726:
727:
728:
729:
730:
731:
732:
733:
734: class BiLoc {
735: public:
736: int line, col;
737: SourceLoc loc;
738: };
739:
740:
741:
742:
743: void testFile(char const *fname)
744: {
745:
746: int len;
747: {
748: AutoFILE fp(fname, "r");
749:
750: fseek(fp, 0, SEEK_END);
751: len = (int)ftell(fp);
752: }
753:
754:
755: SourceLoc start = mgr.encodeOffset(fname, 0);
756: SourceLoc end = mgr.encodeOffset(fname, len-1);
757:
758:
759: xassert(mgr.getLine(start) == 1);
760: xassert(mgr.getCol(start) == 1);
761:
762:
763: testRoundTrip(start);
764: testRoundTrip(end);
765:
766:
767:
768:
769: BiLoc *bi = new BiLoc[len+1];
770: char const *dummy;
771:
772:
773:
774:
775:
776: int i;
777: for (i=0; i<=len; i++) {
778: SourceLoc loc = mgr.encodeOffset(fname, i);
779: testRoundTrip(loc);
780:
781: bi[i].loc = loc;
782: mgr.decodeLineCol(loc, dummy, bi[i].line, bi[i].col);
783: }
784:
785:
786: for (i=len; i>0; i--) {
787: SourceLoc loc = mgr.encodeOffset(fname, i);
788: testRoundTrip(loc);
789: }
790:
791:
792: for (i=0; i<=len; i++) {
793: int j = rand()%(len+1);
794: int dir = rand()%2;
795:
796: if (dir==0) {
797:
798: int line, col;
799: mgr.decodeLineCol(bi[j].loc, dummy, line, col);
800: xassert(line == bi[j].line);
801: xassert(col == bi[j].col);
802: }
803: else {
804:
805: SourceLoc loc = mgr.encodeLineCol(fname, bi[j].line, bi[j].col);
806: xassert(loc == bi[j].loc);
807: }
808: }
809:
810: delete[] bi;
811: }
812:
813:
814:
815: void expect(SourceLoc loc, char const *expFname, int expLine, int expCol)
816: {
817: char const *fname;
818: int line, col;
819: mgr.decodeLineCol(loc, fname, line, col);
820:
821: if (0!=strcmp(fname, expFname) ||
822: line != expLine ||
823: col != expCol) {
824: printf("expected %s:%d:%d, but got %s:%d:%d\n",
825: expFname, expLine, expCol,
826: fname, line, col);
827: exit(2);
828: }
829: }
830:
831:
832:
833:
834:
835: EXPANDER
836:
837:
838:
839: sm_string locString(char const *fname, int line, int col)
840: {
841: return sm_stringc << fname << ":" << line << ":" << col;
842: }
843:
844:
845: void testHashMap()
846: {
847:
848: system("cpp -DTEST_SRCLOC srcloc.cc >srcloc.tmp");
849:
850: SourceLocManager::File *pp = mgr.getInternalFile("srcloc.tmp");
851: SourceLocManager::File *orig = mgr.getInternalFile("srcloc.cc");
852:
853:
854: int expanderLine=0;
855: {
856: AutoFILE fp("srcloc.tmp", "r");
857:
858: enum { SZ=256 };
859: char buf[SZ];
860: int ppLine=0;
861: while (fgets(buf, SZ, fp)) {
862: if (buf[std::strlen(buf)-1] == '\n') {
863: ppLine++;
864: }
865:
866: if (0==std::memcmp(buf, "int blah_de_blah", 16)) {
867: expanderLine = ppLine;
868: }
869:
870: if (buf[0]!='#') continue;
871:
872:
873:
874:
875: StrtokParse tok(buf, " \n");
876: if (tok < 3) continue;
877:
878: int origLine = atoi(tok[1]);
879: char const *tok2 = tok[2];
880: sm_string origFname = sm_string(tok2+1, std::strlen(tok2)-2);
881: pp->addHashLine(ppLine, origLine, origFname);
882: }
883: pp->doneAdding();
884: }
885:
886:
887:
888:
889:
890:
891:
892:
893:
894:
895: int ppLine;
896: for (ppLine = 1; ppLine < 10; ppLine++) {
897: SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
898: std::cout << "ppLine " << ppLine << ": " << toString(loc) << std::endl;
899: }
900:
901:
902: for (ppLine = pp->numLines - 10; ppLine <= pp->numLines; ppLine++) {
903: SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", ppLine, 1);
904: std::cout << "ppLine " << ppLine << ": " << toString(loc) << std::endl;
905: }
906:
907:
908: if (!expanderLine) {
909: std::cout << "didn't find expander line!\n";
910: exit(2);
911: }
912: else {
913: SourceLoc loc = mgr.encodeLineCol("srcloc.tmp", expanderLine, 1);
914: std::cout << "expander column 1: " << toString(loc) << std::endl;
915:
916:
917:
918: loc = advCol(loc, 20);
919:
920: char const *fname;
921: int offset;
922: mgr.decodeOffset(loc, fname, offset);
923: std::cout << "expander column 21: " << fname << ", offset " << offset << std::endl;
924: xassert(0==strcmp(fname, "srcloc.cc"));
925:
926:
927: int line, col;
928: orig->charToLineCol(offset, line, col);
929: std::cout << "expander column 21: " << locString(fname, line, col) << std::endl;
930: if (col != 9) {
931: std::cout << "expected column 9!\n";
932: exit(2);
933: }
934: }
935: }
936:
937:
938: void entry(int argc, char ** /*argv*/)
939: {
940: traceAddSys("progress");
941: traceProgress() << "begin" << std::endl;
942:
943: if (argc >= 2) {
944:
945: mgr.maxStaticLocs = 1;
946: }
947:
948:
949: testFile("srcloc.cc");
950: testFile("srcloc.h");
951:
952:
953:
954: for (int i=0; i<1; i++) {
955: testFile("srcloc.cc");
956: testFile("srcloc.h");
957: }
958:
959: traceProgress() << "end" << std::endl;
960:
961:
962:
963: std::cout << "\n";
964: std::cout << "long line len: " << longestLen << std::endl;
965:
966:
967: std::cout << "invalid: " << toString(SL_UNKNOWN) << std::endl;
968: std::cout << "here: " << toString(HERE_SOURCELOC) << std::endl;
969:
970: std::cout << "\n";
971: testHashMap();
972:
973: std::cout << "srcloc is ok\n";
974: }
975:
976: ARGS_MAIN
977:
978:
979:
Start cpp section to elk/sm_strdict.cpp[1
/1
]
1: #line 11533 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10: for(Node *itervar = top; itervar != NULL; itervar = itervar->next)
11:
12:
13: for(Iter itervar = (dict).getIter(); !itervar.isDone(); itervar.next())
14:
15:
16: for(IterC itervar = (dict).getIterC(); !itervar.isDone(); itervar.next())
17:
18:
19:
20:
21: StringDict::StringDict()
22: : top(NULL)
23: {}
24:
25:
26: StringDict::StringDict(StringDict const &obj)
27: : top(NULL)
28: {
29: *this = obj;
30: }
31:
32:
33: StringDict::~StringDict()
34: {
35: SELFCHECK();
36: empty();
37: }
38:
39:
40: StringDict& StringDict::operator= (StringDict const &obj)
41: {
42: if (this == &obj) {
43: return *this;
44: }
45:
46: empty();
47:
48: Node *end = top;
49: FOREACH_ITERC(obj, src) {
50: Node *newnode = new Node(src.key(), src.value());
51: if (!end) {
52:
53: end = top = newnode;
54: }
55: else {
56:
57: end = end->next = newnode;
58: }
59: }
60:
61: SELFCHECK();
62: return *this;
63: }
64:
65:
66: bool StringDict::operator== (StringDict const &obj) const
67: {
68:
69: MUTABLE_SORT(*this);
70: MUTABLE_SORT(obj);
71:
72: IterC ths(*this), other(obj);
73: while (!ths.isDone() && !other.isDone()) {
74: if (0!=strcmp(ths.key(), other.key()) ||
75: 0!=strcmp(ths.value(), other.value())) {
76: return false;
77: }
78: ths.next();
79: other.next();
80: }
81:
82: if (!ths.isDone() || !other.isDone()) {
83:
84: return false;
85: }
86:
87: return true;
88: }
89:
90:
91: bool StringDict::isEmpty() const
92: {
93: return top == NULL;
94: }
95:
96:
97: int StringDict::size() const
98: {
99: int ret=0;
100: FOREACH_ITERC(*this, entry) {
101: ret++;
102: }
103: return ret;
104: }
105:
106:
107: bool StringDict::query(char const *key, sm_string &value) const
108: {
109: FOREACH_ITERC(*this, entry) {
110: if (0==strcmp(entry.key(), key)) {
111: value = entry.value();
112: return true;
113: }
114: }
115:
116: return false;
117: }
118:
119:
120: sm_string StringDict::queryf(char const *key) const
121: {
122: sm_string ret;
123: bool ok = query(key, ret);
124: xassert(ok);
125: return ret;
126: }
127:
128:
129: bool StringDict::isMapped(char const *key) const
130: {
131: sm_string dummy;
132: return query(key, dummy);
133: }
134:
135:
136: void StringDict::add(char const *key, char const *value)
137: {
138: xassert(!isMapped(key));
139:
140:
141: top = new Node(key, value, top);
142:
143: SELFCHECK();
144: }
145:
146:
147: void StringDict::modify(char const *key, char const *newValue)
148: {
149: Iter entry = find(key);
150: xassert(!entry.isDone());
151:
152: entry.value() = newValue;
153:
154: SELFCHECK();
155: }
156:
157:
158: StringDict::Iter StringDict::find(char const *key)
159: {
160: FOREACH_ITER(*this, entry) {
161: if (0==strcmp(entry.key(), key)) {
162: return entry;
163: }
164: }
165: return Iter(NULL);
166: }
167:
168:
169: void StringDict::remove(char const *key)
170: {
171: xassert(top);
172:
173:
174: if (0==strcmp(top->key, key)) {
175: Node *temp = top;
176: top = top->next;
177: delete temp;
178: }
179:
180:
181: else {
182: Node *p = top;
183: while (p->next && 0!=strcmp(p->next->key, key)) {
184: p = p->next;
185: }
186:
187: if (!p->next) {
188:
189: xfailure("failed to find key");
190: }
191:
192:
193: Node *temp = p->next;
194: p->next = p->next->next;
195: delete temp;
196: }
197:
198: SELFCHECK();
199: }
200:
201:
202: void StringDict::empty()
203: {
204: while (top) {
205: Node *temp = top;
206: top = top->next;
207: delete temp;
208: }
209:
210: SELFCHECK();
211: }
212:
213:
214: StringDict::Iter StringDict::getIter()
215: {
216: sort();
217: return Iter(top);
218: }
219:
220:
221: StringDict::IterC StringDict::getIterC() const
222: {
223:
224: const_cast<StringDict*>(this)->sort();
225: return IterC(top);
226: }
227:
228:
229:
230: /*mutable*/ void StringDict::sort()
231: {
232: if (!top) {
233: return;
234: }
235:
236:
237:
238: Node *walker = top;
239: while (walker->next != NULL) {
240:
241: if (0 <= strcmp(walker->key, walker->next->key)) {
242:
243: walker = walker->next;
244: continue;
245: }
246:
247:
248:
249:
250: Node *mover = walker->next;
251: walker->next = walker->next->next;
252: mover->next = NULL;
253:
254:
255: if (0 < strcmp(mover->key, top->key)) {
256: mover->next = top;
257: top = mover;
258: continue;
259: }
260:
261:
262:
263: Node *searcher = top;
264: while (0 < strcmp(searcher->next->key, mover->key)) {
265: searcher = searcher->next;
266: xassert(searcher != walker);
267:
268: }
269:
270:
271: mover->next = searcher->next;
272: searcher->next = mover;
273: }
274:
275: SELFCHECK();
276:
277: #ifndef NDEBUG
278: verifySorted();
279: #endif
280: }
281:
282:
283: void StringDict::verifySorted() const
284: {
285: if (!top) {
286: return;
287: }
288:
289: Node *p = top;
290: while (p->next) {
291: xassert(0 <= strcmp(p->key, p->next->key));
292: p = p->next;
293: }
294: }
295:
296:
297:
298: void StringDict::selfCheck() const
299: {
300: Node *fast = top, *slow = top;
301: while (fast && fast->next) {
302: fast = fast->next->next;
303: slow = slow->next;
304:
305: xassert(fast != slow);
306:
307: }
308: }
309:
310:
311: void StringDict::insertOstream(std::ostream &os) const
312: {
313: FOREACH_ITERC(*this, entry) {
314: os << entry.key() << " = " << entry.value() << std::endl;
315: }
316: }
317:
318:
319: sm_string StringDict::toString() const
320: {
321: sm_stringBuilder sb;
322: sb << "{";
323: int count=0;
324: FOREACH_ITERC(*this, entry) {
325: if (count++ > 0) {
326: sb << ",";
327: }
328: sb << " " << entry.key() << "=\"" << entry.value() << "\"";
329: }
330: sb << " }";
331: return sb;
332: }
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343: char randChar()
344: {
345: return (char)(myrandom(127-32+1)+32);
346: }
347:
348: sm_string randString(int len)
349: {
350: sm_stringBuilder str;
351: loopj(len) {
352: str << randChar();
353: }
354: return str;
355: }
356:
357: sm_string randStringRandLen(int maxlen)
358: {
359: return randString(myrandom(maxlen)+1);
360: }
361:
362: sm_string randKey(StringDict const &dict)
363: {
364: int size = dict.size();
365: xassert(size > 0);
366:
367: int nth = myrandom(size);
368: StringDict::IterC entry(dict);
369: for (; nth > 0; entry.next(), nth--)
370: {}
371:
372: return entry.key();
373: }
374:
375:
376: void entry()
377: {
378: StringDict dict;
379: int size=0, collisions=0;
380:
381: int iters = 1000;
382: loopi(iters) {
383: switch (myrandom(6)) {
384: case 0: {
385:
386: sm_string key = randStringRandLen(10);
387: sm_string value = randStringRandLen(30);
388:
389: if (!dict.isMapped(key)) {
390: dict.add(key, value);
391: size++;
392: }
393: else {
394: collisions++;
395: }
396: break;
397: }
398:
399: case 1: {
400:
401: if (dict.isEmpty()) {
402: break;
403: }
404:
405: sm_string key = randKey(dict);
406: dict.remove(key);
407: size--;
408: break;
409: }
410:
411: case 2: {
412:
413: sm_string key = randStringRandLen(10);
414: if (dict.isMapped(key)) {
415: collisions++;
416: }
417: break;
418: }
419:
420: case 3: {
421:
422: xassert(size == dict.size());
423: break;
424: }
425:
426: case 4: {
427:
428: StringDict dict2(dict);
429: xassert(dict2 == dict);
430: xassert(dict2.size() == dict.size());
431:
432:
433: if (!dict2.isEmpty()) {
434: sm_string key = randKey(dict2);
435: sm_string value = dict2.queryf(key);
436:
437: if (myrandom(2) == 0) {
438: dict2.remove(key);
439: }
440: else {
441: dict2.modify(key, value & "x");
442: }
443: xassert(dict2 != dict);
444: }
445:
446: break;
447: }
448:
449: case 5: {
450:
451: if (!dict.isEmpty()) {
452: sm_string key = randKey(dict);
453: dict.modify(key, randStringRandLen(30));
454: }
455: break;
456: }
457:
458: default:
459: xfailure("huh?");
460: break;
461: }
462: }
463:
464: std::cout << "final size: " << size
465: << "\ncollisions: " << collisions
466: << "\n";
467:
468: std::cout << "all tests passed\n";
469: }
470:
471: USUAL_MAIN
472:
473:
Start cpp section to elk/sm_strhash.cpp[1
/1
]
1: #line 12007 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41: StringHash::StringHash(GetKeyFn gk)
42: : HashTable((HashTable::GetKeyFn)gk,
43: (HashTable::HashFn)coreHash,
44: (HashTable::EqualKeyFn)keyCompare)
45: {}
46:
47: StringHash::~StringHash()
48: {}
49:
50:
51: STATICDEF unsigned StringHash::coreHash(char const *key)
52: {
53:
54:
55:
56:
57:
58:
59:
60: xassertdb(key);
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88: #if 0
89:
90:
91: unsigned val = 0x42e9d115;
92: while (*key != 0) {
93: val *= (unsigned)(*key);
94: val += 1;
95: key++;
96: }
97: return val;
98: #endif
99:
100:
101: #ifndef STRHASH_ALG
102: #define STRHASH_ALG 1
103: #endif
104:
105:
106: #if STRHASH_ALG == 1
107: #ifdef SAY_STRHASH_ALG
108: #warning hash function 1: Nelson
109: #endif
110:
111: /* An excellent sm_string hashing function.
112: Adapted from glib's g_str_hash().
113: Investigation by Karl Nelson <kenelson@ece.ucdavis.edu>.
114: Do a web search for "g_str_hash X31_HASH" if you want to know more. */
115: /* update: this is the same function as that described in Kernighan and Pike,
116: "The Practice of Programming", section 2.9 */
117: unsigned h = 0;
118: for (; *key != '\0'; key += 1) {
119:
120: h = ( h << 5 ) - h + *key;
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134: }
135: return h;
136:
137:
138: #elif STRHASH_ALG == 2
139: #ifdef SAY_STRHASH_ALG
140: #warning hash function 2: word-rotate/final-mix
141: #endif
142:
143:
144: #warning word-rotate/final-mix hash function only works on 32-bit architectures
145: #warning word-rotate/final-mix hash function still needs to be tested for randomness vs nelson
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156: #define ROTATE(n, b) (n >> b) | (n << (32 - b))
157:
158:
159:
160: static unsigned const primeA = 1500450271U;
161: static unsigned const primeB = 2860486313U;
162:
163: static unsigned const primeC = (1U<<31) - 99U;
164: static unsigned const primeD = (1U<<30) - 35U;
165:
166: static int count = 0;
167: ++count;
168:
169: unsigned h = primeA;
170:
171:
172:
173:
174:
175:
176:
177:
178:
179: if (!key[0]) goto end0;
180: if (!key[1]) goto end1;
181: if (!key[2]) goto end2;
182: if (!key[3]) goto end3;
183:
184: h += *( (unsigned *) key );
185: key += 4;
186: while (1) {
187:
188: if (!key[0]) {h = ROTATE(h, 5); goto end0;}
189: if (!key[1]) {h = ROTATE(h, 5); goto end1;}
190: if (!key[2]) {h = ROTATE(h, 5); goto end2;}
191: if (!key[3]) {h = ROTATE(h, 5); goto end3;}
192: h = ROTATE(h, 5);
193:
194:
195:
196: h += *( (unsigned *) key );
197: key += 4;
198: }
199: xfailure("shouldn't get here");
200:
201:
202:
203: end3:
204: h += *key; h = ROTATE(h, 5); key += 1;
205: end2:
206: h += *key; h = ROTATE(h, 5); key += 1;
207: end1:
208: h += *key;
209: #ifndef NDEBUG
210: key += 1;
211: #endif
212: end0:
213: xassertdb(*key=='\0');
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238: h *= primeB;
239:
240:
241:
242:
243:
244:
245:
246: h = ROTATE(h, 16);
247: h *= primeC;
248:
249:
250:
251:
252:
253: h = ROTATE(h, 16);
254: h *= primeD;
255:
256: return h;
257:
258: #undef ROTATE
259:
260:
261: #else
262: #error You must pick a hash function
263: #endif
264: }
265:
266:
267: STATICDEF bool StringHash::keyCompare(char const *key1, char const *key2)
268: {
269: return 0==strcmp(key1, key2);
270: }
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287: struct StringArray {
288: int tableSize;
289: GrowArray<char*> table;
290: bool appendable;
291:
292: StringArray(int tableSize0)
293: : tableSize(tableSize0)
294: , table(tableSize)
295: , appendable(tableSize == 0)
296: {}
297: void append(char *str) {
298: xassert(appendable);
299: table.ensureIndexDoubler(tableSize);
300: table[tableSize] = str;
301: ++tableSize;
302: }
303: };
304:
305:
306: StringArray *dataArray = NULL;
307:
308:
309: char const *id(void *p)
310: {
311: return (char const*)p;
312: }
313:
314: char *randomString()
315: {
316: char *ret = new char[11];
317: loopi(10) {
318: ret[i] = (rand()%26)+'a';
319: }
320: ret[10]=0;
321: return ret;
322: }
323:
324:
325: void makeRandomData(int numRandStrs) {
326: dataArray = new StringArray(numRandStrs);
327: {loopi(dataArray->tableSize) {
328: dataArray->table[i] = randomString();
329: }}
330: }
331:
332:
333:
334: void readDataFromFile(char *inFileName) {
335: dataArray = new StringArray(0);
336: char *delim = " \t\n\r\v\f";
337: std::filebuf fb;
338: fb.open (inFileName, ios::in);
339: std::istream in(&fb);
340: while(true) {
341: sm_stringBuilder s;
342: s.readdelim(in, delim);
343:
344: if (in.eof()) break;
345:
346:
347: dataArray->append(strdup(s.pcharc()));
348: }
349: }
350:
351: void writeData(std::ostream &out) {
352: std::cout << "write data" << std::endl;
353: for(int i=0; i<dataArray->tableSize; ++i) {
354: out << dataArray->table[i] << std::endl;
355: }
356: }
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367: void correctnessTest() {
368: traceProgress() << "start of strhash correctness testing\n";
369:
370:
371: StringHash hash(id);
372: {loopi(dataArray->tableSize) {
373: hash.add(dataArray->table[i], dataArray->table[i]);
374: hash.selfCheck();
375: }}
376: hash.selfCheck();
377: xassert(hash.getNumEntries() == dataArray->tableSize);
378:
379:
380: {loopi(dataArray->tableSize) {
381: xassert(hash.get(dataArray->table[i]) == dataArray->table[i]);
382: }}
383: hash.selfCheck();
384:
385:
386: {loopi(dataArray->tableSize) {
387: if (i%2 == 0) {
388: hash.remove(dataArray->table[i]);
389: hash.selfCheck();
390: }
391: }}
392: hash.selfCheck();
393: xassert(hash.getNumEntries() == dataArray->tableSize / 2);
394:
395:
396: {loopi(dataArray->tableSize) {
397: if (i%2 == 0) {
398: xassert(hash.get(dataArray->table[i]) == NULL);
399: }
400: else {
401: xassert(hash.get(dataArray->table[i]) == dataArray->table[i]);
402: }
403: }}
404: hash.selfCheck();
405:
406:
407: {loopi(dataArray->tableSize) {
408: if (i%2 == 1) {
409: hash.remove(dataArray->table[i]);
410: hash.selfCheck();
411: }
412: }}
413: hash.selfCheck();
414: xassert(hash.getNumEntries() == 0);
415:
416: traceProgress() << "end of strhash correctness testing\n";
417: }
418:
419: void performanceTest(int numPerfRuns) {
420:
421: traceProgress() << "start of strhash performance testing\n";
422:
423: long startTime = getMilliseconds();
424: loopj(numPerfRuns) {
425: loopi(dataArray->tableSize) {
426: StringHash::coreHash(dataArray->table[i]);
427:
428:
429: }
430: }
431: long stopTime = getMilliseconds();
432: long duration = stopTime - startTime;
433: std::cout << "milliseconds to hash: " << duration << std::endl;
434:
435: traceProgress() << "end of strhash performance testing\n";
436: }
437:
438:
439: int numRandStrs = 0;
440: char *inFileName = NULL;
441: bool dump = false;
442: bool testCor = true;
443: bool testPerf = true;
444: int numPerfRuns = 10000;
445:
446: void usage() {
447: std::cout << "Test the sm_string hashing module strhash.cc\n"
448: << " --help / -h : print this message\n"
449: << " --[no-]testCor : run the correctness tests\n"
450: << " will fail if data has duplicate sm_strings (?!)\n"
451: << " --[no-]testPerf : run the performance tests\n"
452: << " --numPerfRuns N : loop over data N times during performance run\n"
453: << " --file FILE : use the whitespace-delimited sm_string contents of FILE\n"
454: << " --random N : use N internally generated random sm_strings of length 10;\n"
455: << " N should be even\n"
456: << " --dump : dump out the data after generating/reading it\n"
457: << "The default is '--random 300 --testCor --testPerf --numPerfRuns 10000'."
458: << std::endl;
459: }
460:
461: void initFromFlags(int &argc, char**&argv) {
462: --argc; ++argv;
463: for(;
464: *argv;
465: --argc, ++argv) {
466: if (strcmp(*argv, "--help")==0 || strcmp(*argv, "-h")==0) {
467: usage();
468: exit(0);
469: } else if (strcmp(*argv, "--testCor")==0) {
470: testCor = true;
471: } else if (strcmp(*argv, "--no-testCor")==0) {
472: testCor = false;
473: } else if (strcmp(*argv, "--testPerf")==0) {
474: testPerf = true;
475: } else if (strcmp(*argv, "--no-testPerf")==0) {
476: testPerf = false;
477: } else if (strcmp(*argv, "--random")==0) {
478: if (inFileName) {
479: std::cout << "do not use --random and --file together" << std::endl;
480: usage();
481: exit(1);
482: }
483: --argc; ++argv;
484: if (!*argv) {
485: std::cout << "supply an argument to --random" << std::endl;
486: usage();
487: exit(1);
488: }
489: numRandStrs = atoi(*argv);
490: if (!(numRandStrs > 0)) {
491: std::cout << "argument to --random must be > 0" << std::endl;
492: usage();
493: exit(1);
494: }
495: } else if (strcmp(*argv, "--file")==0) {
496: if (numRandStrs) {
497: std::cout << "do not use --random and --file together" << std::endl;
498: usage();
499: exit(1);
500: }
501: --argc; ++argv;
502: if (!*argv) {
503: std::cout << "supply an argument to --file" << std::endl;
504: usage();
505: exit(1);
506: }
507: inFileName = strdup(*argv);
508: xassert(inFileName);
509: } else if (strcmp(*argv, "--numPerfRuns")==0) {
510: --argc; ++argv;
511: if (!*argv) {
512: std::cout << "supply an argument to --numPerfRuns" << std::endl;
513: usage();
514: exit(1);
515: }
516: numPerfRuns = atoi(*argv);
517: if (!(numPerfRuns > 0)) {
518: std::cout << "argument to --numPerfRuns must be > 0" << std::endl;
519: usage();
520: exit(1);
521: }
522: } else if (strcmp(*argv, "--dump")==0) {
523: dump = true;
524: } else {
525: std::cout << "unrecognized flag " << *argv << std::endl;
526: usage();
527: exit(1);
528: }
529: }
530: }
531:
532: int main(int argc, char **argv)
533: {
534: traceAddSys("progress");
535:
536: #if STRHASH_ALG == 1
537: std::cout << "hash function 1: Nelson" << std::endl;
538: #elif STRHASH_ALG == 2
539: std::cout << "hash function 2: word-rotate/final-mix" << std::endl;
540: #else
541: #error You must pick a hash function
542: #endif
543:
544:
545: initFromFlags(argc, argv);
546:
547:
548: if ((!inFileName) && (!numRandStrs)) {
549: numRandStrs = 300;
550: }
551: if (numRandStrs % 2 != 0) {
552: std::cout << "use an even-number argument for --random" << std::endl;
553: usage();
554: exit(1);
555: }
556: if (numRandStrs) {
557: makeRandomData(numRandStrs);
558: } else if (inFileName) {
559: if (testCor) {
560: std::cout << "Warning: The correctness test fails if sm_strings are duplicated "
561: "and you are reading data from a file." << std::endl;
562: }
563: readDataFromFile(inFileName);
564: } else {
565: xfailure("goink?");
566: }
567:
568:
569: if (dump) {
570: writeData(std::cout);
571: }
572:
573:
574: if (testCor) {
575: correctnessTest();
576: }
577: if (testPerf) {
578: performanceTest(numPerfRuns);
579: }
580:
581:
582:
583:
584: std::cout << "strhash tests finished\n";
585: return 0;
586: }
587:
588:
Start cpp section to elk/sm_stringset.cpp[1
/1
]
1: #line 12596 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7: StringSet::~StringSet()
8: {}
9:
10: void StringSet::add(char const *elt)
11: {
12: if (!contains(elt)) {
13: elts.add(elt, NULL);
14: }
15: }
16:
17: void StringSet::remove(char const *elt)
18: {
19: if (contains(elt)) {
20: elts.remove(elt);
21: }
22: }
23:
Start cpp section to elk/sm_strutil.cpp[1
/1
]
1: #line 12620 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17: sm_string replace(char const *src, char const *oldstr, char const *newstr)
18: {
19: sm_stringBuilder ret("");
20:
21: while (*src) {
22: char const *next = strstr(src, oldstr);
23: if (!next) {
24: ret &= sm_string(src);
25: break;
26: }
27:
28:
29: sm_string upto(src, next-src);
30:
31:
32: ret &= upto;
33:
34:
35: ret &= sm_string(newstr);
36:
37:
38: src += (next-src) + std::strlen(oldstr);
39: }
40:
41: return ret;
42: }
43:
44:
45: sm_string expandRanges(char const *chars)
46: {
47: sm_stringBuilder ret;
48:
49: while (*chars) {
50: if (chars[1] == '-' && chars[2] != 0) {
51:
52: if (chars[0] > chars[2]) {
53: xformat("range specification with wrong collation order");
54: }
55:
56: for (char c = chars[0]; c <= chars[2]; c++) {
57: ret << c;
58: }
59: chars += 3;
60: }
61: else {
62:
63: ret << chars[0];
64: chars++;
65: }
66: }
67:
68: return ret;
69: }
70:
71:
72: sm_string translate(char const *src, char const *srcchars, char const *destchars)
73: {
74:
75: sm_string srcSpec = expandRanges(srcchars);
76: sm_string destSpec = expandRanges(destchars);
77:
78:
79: char map[256];
80: int i;
81: for (i=0; i<256; i++) {
82: map[i] = i;
83: }
84:
85:
86: for (i=0; i < srcSpec.length() && i < destSpec.length(); i++) {
87: map[(unsigned char)( srcSpec[i] )] = destSpec[i];
88: }
89:
90:
91: sm_string ret(std::strlen(src));
92: char *dest = ret.pchar();
93: while (*src) {
94: *dest = map[(unsigned char)*src];
95: dest++;
96: src++;
97: }
98: *dest = 0;
99:
100: return ret;
101: }
102:
103:
104:
105: sm_string sm_stringToupper(char const *src)
106: { return translate(src, "a-z", "A-Z"); }
107:
108:
109: sm_string trimWhitespace(char const *str)
110: {
111:
112: while (isspace(*str)) {
113: str++;
114: }
115:
116:
117: char const *end = str + std::strlen(str);
118: while (end > str &&
119: isspace(end[-1])) {
120: end--;
121: }
122:
123:
124: return sm_string(str, end-str);
125: }
126:
127:
128:
129: static struct Escape {
130: char actual;
131: char escape;
132: } const escapes[] = {
133: { '\0', '0' },
134: { '\a', 'a' },
135: { '\b', 'b' },
136: { '\f', 'f' },
137: { '\n', 'n' },
138: { '\r', 'r' },
139: { '\t', 't' },
140: { '\v', 'v' },
141: { '\\', '\\'},
142: { '"', '"' },
143: { '\'', '\''},
144: };
145:
146:
147: sm_string encodeWithEscapes(char const *p, int len)
148: {
149: sm_stringBuilder sb;
150:
151: for (; len>0; len--, p++) {
152:
153: unsigned i;
154: for (i=0; i<TABLESIZE(escapes); i++) {
155: if (escapes[i].actual == *p) {
156: sb << '\\' << escapes[i].escape;
157: break;
158: }
159: }
160: if (i<TABLESIZE(escapes)) {
161: continue;
162: }
163:
164:
165: if (isprint(*p)) {
166: sb << *p;
167: continue;
168: }
169:
170:
171: char tmp[5];
172: sprintf(tmp, "\\x%02X", (unsigned char)(*p));
173: sb << tmp;
174: }
175:
176: return sb;
177: }
178:
179:
180: sm_string encodeWithEscapes(char const *p)
181: {
182: return encodeWithEscapes(p, std::strlen(p));
183: }
184:
185:
186: sm_string quoted(char const *src)
187: {
188: return sm_stringc << "\""
189: << encodeWithEscapes(src, std::strlen(src))
190: << "\"";
191: }
192:
193:
194: void decodeEscapes(sm_string &dest, int &destLen, char const *src,
195: char delim, bool allowNewlines)
196: {
197:
198: sm_stringBuilder sb;
199: destLen = 0;
200:
201: while (*src != '\0') {
202: if (*src == '\n' && !allowNewlines) {
203: xformat("unescaped newline (unterminated sm_string)");
204: }
205: if (*src == delim) {
206: xformat(sm_stringc << "unescaped delimiter (" << delim << ")");
207: }
208:
209: if (*src != '\\') {
210:
211: sb << *src;
212: destLen++;
213: src++;
214: continue;
215: }
216:
217:
218: src++;
219:
220:
221:
222:
223:
224: int i;
225: for (i=1; i<TABLESIZE(escapes); i++) {
226: if (escapes[i].escape == *src) {
227: sb << escapes[i].actual;
228: destLen++;
229: src++;
230: break;
231: }
232: }
233: if (i < TABLESIZE(escapes)) {
234: continue;
235: }
236:
237: if (*src == '\0') {
238: xformat("backslash at end of sm_string");
239: }
240:
241: if (*src == '\n') {
242:
243: src++;
244: while (*src==' ' || *src=='\t') {
245: src++;
246: }
247: continue;
248: }
249:
250: if (*src == 'x' || isdigit(*src)) {
251:
252:
253:
254: bool hex = (*src == 'x');
255: if (hex) {
256: src++;
257:
258:
259: if (isspace(*src)) {
260: xformat("whitespace following hex (\\x) escape");
261: }
262: }
263:
264: char const *endptr;
265: unsigned long val = strtoul(src, (char**)&endptr, hex? 16 : 8);
266: if (src == endptr) {
267:
268:
269: xformat("invalid hex (\\x) escape");
270: }
271:
272: sb << (unsigned char)val;
273: destLen++;
274: src = endptr;
275: continue;
276: }
277:
278:
279:
280:
281:
282:
283:
284:
285:
286: sb << *src;
287: destLen++;
288: src++;
289: }
290:
291:
292: dest.setlength(destLen);
293: if (destLen > 0) {
294: std::memcpy(dest.pchar(), sb.pchar(), destLen);
295: }
296: }
297:
298:
299: sm_string parseQuotedString(char const *text)
300: {
301: if (!( text[0] == '"' &&
302: text[std::strlen(text)-1] == '"' )) {
303: xformat(sm_stringc << "quoted sm_string is missing quotes: " << text);
304: }
305:
306:
307: sm_string noQuotes = sm_string(text+1, std::strlen(text)-2);
308:
309:
310: sm_string ret;
311: int dummyLen;
312: decodeEscapes(ret, dummyLen, noQuotes, '"');
313: return ret;
314: }
315:
316:
317: sm_string localTimeString()
318: {
319: time_t t = time(NULL);
320: char const *p = asctime(localtime(&t));
321: return sm_string(p, std::strlen(p) - 1);
322: }
323:
324:
325: sm_string sm_basename(char const *src)
326: {
327: int n = std::strlen(src);
328: while(n>0 && (src[n-1] == '/' || src[n-1] == '\\' || src[n-1] == ':'))--n;
329: int m = n;
330: while(m>0 && src[m-1] != '/' && src[m-1] != '\\' && src[m-1] != ':')--m;
331: if(n==0 && m==0) return sm_string(src);
332: else return sm_string(src+m,n-m);
333: }
334:
335: sm_string dirname(char const *src)
336: {
337: int n = std::strlen(src);
338: while(n>0 && (src[n-1] == '/' || src[n-1] == '\\' || src[n-1] == ':'))--n;
339: int m = n;
340: while(m>0 && src[m-1] != '/' && src[m-1] != '\\' && src[m-1] != ':')--m;
341: if(n==0 && m==0) return sm_string(".");
342: else return sm_string(src,m);
343: }
344:
345:
346:
347:
348: sm_string plural(int n, char const *prefix)
349: {
350: if (n==1) {
351: return sm_string(prefix);
352: }
353:
354: if (0==strcmp(prefix, "was")) {
355: return sm_string("were");
356: }
357: if (prefix[std::strlen(prefix)-1] == 'y') {
358: return sm_stringc << sm_string(prefix, std::strlen(prefix)-1) << "ies";
359: }
360: else {
361: return sm_stringc << prefix << "s";
362: }
363: }
364:
365: sm_string pluraln(int n, char const *prefix)
366: {
367: return sm_stringc << n << " " << plural(n, prefix);
368: }
369:
370:
371: char *copyToStaticBuffer(char const *s)
372: {
373: enum { SZ=200 };
374: static char buf[SZ+1];
375:
376: int len = std::strlen(s);
377: if (len > SZ) len=SZ;
378: std::memcpy(buf, s, len);
379: buf[len] = 0;
380:
381: return buf;
382: }
383:
384:
385: bool prefixEquals(char const *str, char const *prefix)
386: {
387: int slen = std::strlen(str);
388: int plen = std::strlen(prefix);
389: return slen >= plen &&
390: 0==std::memcmp(str, prefix, plen);
391: }
392:
393: bool suffixEquals(char const *str, char const *suffix)
394: {
395: int slen = std::strlen(str);
396: int ulen = std::strlen(suffix);
397: return slen >= ulen &&
398: 0==std::memcmp(str+slen-ulen, suffix, ulen);
399: }
400:
401:
402: void writeStringToFile(char const *str, char const *fname)
403: {
404: AutoFILE fp(fname, "w");
405:
406: if (fputs(str, fp) < 0) {
407: xbase("fputs: EOF");
408: }
409: }
410:
411:
412: sm_string readStringFromFile(char const *fname)
413: {
414: AutoFILE fp(fname, "r");
415:
416: sm_stringBuilder sb;
417:
418: char buf[4096];
419: for (;;) {
420: int len = fread(buf, 1, 4096, fp);
421: if (len < 0) {
422: xbase("fread failed");
423: }
424: if (len == 0) {
425: break;
426: }
427:
428: sb.append(buf, len);
429: }
430:
431: return sb;
432: }
433:
434:
435: bool readLine(sm_string &dest, FILE *fp)
436: {
437: char buf[80];
438:
439: if (!fgets(buf, 80, fp)) {
440: return false;
441: }
442:
443: if (buf[std::strlen(buf)-1] == '\n') {
444:
445: dest = buf;
446: return true;
447: }
448:
449:
450: sm_stringBuilder sb;
451: while (buf[std::strlen(buf)-1] != '\n') {
452: sb << buf;
453: if (!fgets(buf, 80, fp)) {
454:
455:
456: break;
457: }
458: }
459:
460: dest = sb;
461: return true;
462: }
463:
464:
465: sm_string chomp(char const *src)
466: {
467: if (src && src[std::strlen(src)-1] == '\n') {
468: return sm_string(src, std::strlen(src)-1);
469: }
470: else {
471: return sm_string(src);
472: }
473: }
474:
475:
476:
477:
478:
479:
480:
481:
482: void expRangeVector(char const *in, char const *out)
483: {
484: printf("expRangeVector(%s, %s)\n", in, out);
485: sm_string result = expandRanges(in);
486: xassert(result.equals(out));
487: }
488:
489: void trVector(char const *in, char const *srcSpec, char const *destSpec, char const *out)
490: {
491: printf("trVector(%s, %s, %s, %s)\n", in, srcSpec, destSpec, out);
492: sm_string result = translate(in, srcSpec, destSpec);
493: xassert(result.equals(out));
494: }
495:
496: void decodeVector(char const *in, char const *out, int outLen)
497: {
498: printf("decodeVector: \"%s\"\n", in);
499: sm_string dest;
500: int destLen;
501: decodeEscapes(dest, destLen, in, '\0' /*delim, ignored*/, false /*allowNewlines*/);
502: xassert(destLen == outLen);
503: xassert(0==std::memcmp(out, dest.pcharc(), destLen));
504: }
505:
506: void basenameVector(char const *in, char const *out)
507: {
508: printf("basenameVector(%s, %s)\n", in, out);
509: sm_string result = sm_basename(in);
510: xassert(result.equals(out));
511: }
512:
513: void dirnameVector(char const *in, char const *out)
514: {
515: printf("dirnameVector(%s, %s)\n", in, out);
516: sm_string result = dirname(in);
517: xassert(result.equals(out));
518: }
519:
520: void pluralVector(int n, char const *in, char const *out)
521: {
522: printf("pluralVector(%d, %s, %s)\n", n, in, out);
523: sm_string result = plural(n, in);
524: xassert(result.equals(out));
525: }
526:
527:
528: void entry()
529: {
530: expRangeVector("abcd", "abcd");
531: expRangeVector("a", "a");
532: expRangeVector("a-k", "abcdefghijk");
533: expRangeVector("0-9E-Qz", "0123456789EFGHIJKLMNOPQz");
534:
535: trVector("foo", "a-z", "A-Z", "FOO");
536: trVector("foo BaR", "a-z", "A-Z", "FOO BAR");
537: trVector("foo BaR", "m-z", "M-Z", "fOO BaR");
538:
539: decodeVector("\\r\\n", "\r\n", 2);
540: decodeVector("abc\\0def", "abc\0def", 7);
541: decodeVector("\\033", "\033", 1);
542: decodeVector("\\x33", "\x33", 1);
543: decodeVector("\\?", "?", 1);
544:
545: basenameVector("a/b/c", "c");
546: basenameVector("abc", "abc");
547: basenameVector("/", "");
548: basenameVector("a/b/c/", "c");
549:
550: dirnameVector("a/b/c", "a/b");
551: dirnameVector("a/b/c/", "a/b");
552: dirnameVector("/a", "/");
553: dirnameVector("abc", ".");
554: dirnameVector("/", "/");
555:
556: pluralVector(1, "path", "path");
557: pluralVector(2, "path", "paths");
558: pluralVector(1, "fly", "fly");
559: pluralVector(2, "fly", "flies");
560: pluralVector(2, "was", "were");
561: }
562:
563:
564: USUAL_MAIN
565:
566:
Start cpp section to elk/sm_svdict.cpp[1
/1
]
1: #line 13187 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10: for(Node *itervar = top; itervar != NULL; itervar = itervar->next)
11:
12:
13: for(Iter itervar = (dict).getIter(); !itervar.isDone(); itervar.next())
14:
15:
16: for(IterC itervar = (dict).getIterC(); !itervar.isDone(); itervar.next())
17:
18:
19:
20:
21: STATICDEF char const *StringVoidDict::Node::getKey(StringVoidDict::Node const *n)
22: {
23: return n->key.pcharc();
24: }
25:
26:
27: StringVoidDict::StringVoidDict()
28: : top(NULL),
29: hash((StringHash::GetKeyFn)Node::getKey)
30: {}
31:
32:
33: StringVoidDict::StringVoidDict(StringVoidDict const &obj)
34: : top(NULL),
35: hash((StringHash::GetKeyFn)Node::getKey)
36: {
37: *this = obj;
38: }
39:
40:
41: StringVoidDict::~StringVoidDict()
42: {
43: SELFCHECK();
44: empty();
45: }
46:
47:
48: StringVoidDict& StringVoidDict::operator= (StringVoidDict const &obj)
49: {
50: if (this == &obj) {
51: return *this;
52: }
53:
54: empty();
55:
56: Node *end = top;
57: FOREACH_ITERC(obj, src) {
58:
59:
60: Node *newnode = new Node(src.key(), const_cast<void*>(src.value()));
61: if (!end) {
62:
63: end = top = newnode;
64: }
65: else {
66:
67: end = end->next = newnode;
68: }
69: hash.add(newnode->key, newnode);
70: }
71:
72: SELFCHECK();
73: return *this;
74: }
75:
76:
77: bool StringVoidDict::operator== (StringVoidDict const &obj) const
78: {
79:
80: MUTABLE_SORT(*this);
81: MUTABLE_SORT(obj);
82:
83: IterC ths(*this), other(obj);
84: while (!ths.isDone() && !other.isDone()) {
85: if (0!=std::strcmp(ths.key(), other.key()) ||
86: ths.value() != other.value()) {
87: return false;
88: }
89: ths.next();
90: other.next();
91: }
92:
93: if (!ths.isDone() || !other.isDone()) {
94:
95: return false;
96: }
97:
98: return true;
99: }
100:
101:
102: bool StringVoidDict::isEmpty() const
103: {
104: return top == NULL;
105: }
106:
107:
108: int StringVoidDict::size() const
109: {
110: return hash.getNumEntries();
111: }
112:
113:
114: bool StringVoidDict::query(char const *key, void *&value) const
115: {
116: Node *n = (Node*)hash.get(key);
117: if (!n) {
118: return false;
119: }
120:
121: value = n->value;
122: return true;
123: }
124:
125:
126: void *StringVoidDict::queryf(char const *key) const
127: {
128: void *ret;
129: bool ok = query(key, ret);
130: xassert(ok);
131: return ret;
132: }
133:
134:
135: void *StringVoidDict::queryif(char const *key) const
136: {
137: void *ret;
138: if (query(key, ret)) {
139: return ret;
140: }
141: else {
142: return NULL;
143: }
144: }
145:
146:
147: bool StringVoidDict::isMapped(char const *key) const
148: {
149: void *dummy;
150: return query(key, dummy);
151: }
152:
153:
154: void StringVoidDict::add(char const *key, void *value)
155: {
156: xassert(!isMapped(key));
157:
158:
159: top = new Node(key, value, top);
160: hash.add(key, top);
161:
162: SELFCHECK();
163: }
164:
165:
166: void *StringVoidDict::modify(char const *key, void *newValue)
167: {
168: Iter entry = find(key);
169: xassert(!entry.isDone());
170:
171: void *ret = entry.value();
172: entry.value() = newValue;
173:
174: SELFCHECK();
175: return ret;
176: }
177:
178:
179: StringVoidDict::Iter StringVoidDict::find(char const *key)
180: {
181: Node *n = (Node*)hash.get(key);
182: return Iter(n);
183: }
184:
185:
186: void *StringVoidDict::remove(char const *key)
187: {
188: void *ret;
189: xassert(top);
190:
191:
192: if (0==std::strcmp(top->key, key)) {
193: Node *temp = top;
194: top = top->next;
195: ret = temp->value;
196: hash.remove(temp->key);
197: delete temp;
198: }
199:
200:
201: else {
202: Node *p = top;
203: while (p->next && 0!=std::strcmp(p->next->key, key)) {
204: p = p->next;
205: }
206:
207: if (!p->next) {
208:
209: xfailure("failed to find key");
210: }
211:
212:
213: Node *temp = p->next;
214: p->next = p->next->next;
215: ret = temp->value;
216: hash.remove(temp->key);
217: delete temp;
218: }
219:
220: SELFCHECK();
221: return ret;
222: }
223:
224:
225: void StringVoidDict::empty()
226: {
227: emptyAndDel(NULL);
228: }
229:
230: void StringVoidDict::emptyAndDel(DelFn func)
231: {
232: while (top) {
233: Node *temp = top;
234: top = top->next;
235:
236: if (func != NULL) {
237: func(temp->value);
238: }
239: hash.remove(temp->key);
240: delete temp;
241: }
242:
243: SELFCHECK();
244: }
245:
246:
247: StringVoidDict::Iter StringVoidDict::getIter()
248: {
249: sort();
250: return Iter(top);
251: }
252:
253:
254: StringVoidDict::IterC StringVoidDict::getIterC() const
255: {
256:
257: const_cast<StringVoidDict*>(this)->sort();
258: return IterC(top);
259: }
260:
261:
262: void StringVoidDict::foreach(ForeachFn func, void *extra) const
263: {
264: const_cast<StringVoidDict*>(this)->sort();
265:
266: for (Node *n = top; n != NULL; n = n->next) {
267: if (func(n->key, n->value, extra)) {
268: return;
269: }
270: }
271: }
272:
273:
274:
275: /*mutable*/ void StringVoidDict::sort()
276: {
277: if (!top) {
278: return;
279: }
280:
281:
282:
283: Node *walker = top;
284: while (walker->next != NULL) {
285:
286: if (0 <= std::strcmp(walker->key, walker->next->key)) {
287:
288: walker = walker->next;
289: continue;
290: }
291:
292:
293:
294:
295: Node *mover = walker->next;
296: walker->next = walker->next->next;
297: mover->next = NULL;
298:
299:
300: if (0 < std::strcmp(mover->key, top->key)) {
301: mover->next = top;
302: top = mover;
303: continue;
304: }
305:
306:
307:
308: Node *searcher = top;
309: while (0 < std::strcmp(searcher->next->key, mover->key)) {
310: searcher = searcher->next;
311: xassert(searcher != walker);
312:
313: }
314:
315:
316: mover->next = searcher->next;
317: searcher->next = mover;
318: }
319:
320: SELFCHECK();
321:
322: #ifndef NDEBUG
323: verifySorted();
324: #endif
325: }
326:
327:
328: void StringVoidDict::verifySorted() const
329: {
330: if (!top) {
331: return;
332: }
333:
334: Node *p = top;
335: while (p->next) {
336: xassert(0 <= std::strcmp(p->key, p->next->key));
337: p = p->next;
338: }
339: }
340:
341:
342:
343: void StringVoidDict::selfCheck() const
344: {
345: {
346: Node *fast = top, *slow = top;
347: while (fast && fast->next) {
348: fast = fast->next->next;
349: slow = slow->next;
350:
351: xassert(fast != slow);
352:
353: }
354: }
355:
356:
357: int ct=0;
358: for (Node *n = top; n != NULL; n = n->next, ct++) {
359: xassert(hash.get(n->key) == n);
360: }
361: xassert(hash.getNumEntries() == ct);
362: }
363:
364:
365: void StringVoidDict::insertOstream(std::ostream &os) const
366: {
367: FOREACH_ITERC(*this, entry) {
368: os << entry.key() << " = " << entry.value() << std::endl;
369: }
370: }
371:
372:
373: sm_string StringVoidDict::toString() const
374: {
375: sm_stringBuilder sb;
376: sb << "{";
377: int count=0;
378: FOREACH_ITERC(*this, entry) {
379: if (count++ > 0) {
380: sb << ",";
381: }
382: sb << " " << entry.key() << "=\"" << entry.value() << "\"";
383: }
384: sb << " }";
385: return sb;
386: }
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397: char randChar()
398: {
399: return (char)(myrandom(127-32+1)+32);
400: }
401:
402: sm_string randString(int len)
403: {
404: sm_stringBuilder str;
405: loopj(len) {
406: str << randChar();
407: }
408: return str;
409: }
410:
411: sm_string randStringRandLen(int maxlen)
412: {
413: return randString(myrandom(maxlen)+1);
414: }
415:
416: sm_string randKey(StringVoidDict const &dict)
417: {
418: int size = dict.size();
419: xassert(size > 0);
420:
421: int nth = myrandom(size);
422: StringVoidDict::IterC entry(dict);
423: for (; nth > 0; entry.next(), nth--)
424: {}
425:
426: return entry.key();
427: }
428:
429: void *randVoidPtr()
430: {
431: return (void*)(myrandom(100) * 8);
432: }
433:
434:
435: void entry()
436: {
437: StringVoidDict dict;
438: int size=0, collisions=0;
439:
440: int iters = 1000;
441: loopi(iters) {
442: switch (myrandom(6)) {
443: case 0: {
444:
445: sm_string key = randStringRandLen(10);
446: void *value = randVoidPtr();
447:
448: if (!dict.isMapped(key)) {
449: dict.add(key, value);
450: size++;
451: }
452: else {
453: collisions++;
454: }
455: break;
456: }
457:
458: case 1: {
459:
460: if (dict.isEmpty()) {
461: break;
462: }
463:
464: sm_string key = randKey(dict);
465: dict.remove(key);
466: size--;
467: break;
468: }
469:
470: case 2: {
471:
472: sm_string key = randStringRandLen(10);
473: if (dict.isMapped(key)) {
474: collisions++;
475: }
476: break;
477: }
478:
479: case 3: {
480:
481: xassert(size == dict.size());
482: break;
483: }
484:
485: case 4: {
486:
487: StringVoidDict dict2(dict);
488: xassert(dict2 == dict);
489: xassert(dict2.size() == dict.size());
490:
491:
492: if (!dict2.isEmpty()) {
493: sm_string key = randKey(dict2);
494: void *value = dict2.queryf(key);
495:
496: if (myrandom(2) == 0) {
497: dict2.remove(key);
498: }
499: else {
500: dict2.modify(key, (void*)((int)value + 24));
501: }
502: xassert(dict2 != dict);
503: }
504:
505: break;
506: }
507:
508: case 5: {
509:
510: if (!dict.isEmpty()) {
511: sm_string key = randKey(dict);
512: dict.modify(key, randVoidPtr());
513: }
514: break;
515: }
516:
517: default:
518: xfailure("huh?");
519: break;
520: }
521: }
522:
523: std::cout << "final size: " << size
524: << "\ncollisions: " << collisions
525: << "\n";
526:
527: std::cout << "all tests passed\n";
528: }
529:
530: USUAL_MAIN
531:
532:
Start cpp section to elk/sm_trace.cpp[1
/1
]
1: #line 13720 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16: static bool inited = false;
17:
18:
19: static ObjList<sm_string> tracers;
20:
21:
22: std::ofstream devNullObj("/dev/null");
23: static std::ostream *devNull = &devNullObj;
24:
25:
26:
27: static void init()
28: {
29: if (inited) {
30: return;
31: }
32:
33:
34:
35:
36:
37:
38:
39: inited = true;
40: }
41:
42:
43: void traceAddSys(char const *sysName)
44: {
45: init();
46:
47: tracers.prepend(new sm_string(sysName));
48: }
49:
50:
51: void traceRemoveSys(char const *sysName)
52: {
53: init();
54:
55: MUTATE_EACH_OBJLIST(sm_string, tracers, mut) {
56: if (mut.data()->compareTo(sysName) == 0) {
57: mut.deleteIt();
58: return;
59: }
60: }
61: xfailure("traceRemoveSys: tried to remove system that isn't there");
62: }
63:
64:
65: bool tracingSys(char const *sysName)
66: {
67: init();
68:
69: FOREACH_OBJLIST(sm_string, tracers, iter) {
70: if (iter.data()->compareTo(sysName) == 0) {
71: return true;
72: }
73: }
74: return false;
75: }
76:
77:
78: void traceRemoveAll()
79: {
80: tracers.deleteAll();
81: }
82:
83:
84: std::ostream &trace(char const *sysName)
85: {
86: init();
87:
88: if (tracingSys(sysName)) {
89: std::cout << "%%% " << sysName << ": ";
90: return std::cout;
91: }
92: else {
93: return *devNull;
94: }
95: }
96:
97:
98: void trstr(char const *sysName, char const *traceString)
99: {
100: trace(sysName) << traceString << std::endl;
101: }
102:
103:
104: std::ostream &traceProgress(int level)
105: {
106: if ( (level == 1) ||
107: (level == 2 && tracingSys("progress2")) ) {
108: static long progStart = getMilliseconds();
109:
110: return trace("progress") << (getMilliseconds() - progStart) << "ms: ";
111: }
112: else {
113: return *devNull;
114: }
115: }
116:
117:
118: void traceAddMultiSys(char const *systemNames)
119: {
120: StrtokParse tok(systemNames, ",");
121: loopi(tok) {
122: if (tok[i][0] == '-') {
123:
124:
125:
126: char const *name = tok[i]+1;
127: if (tracingSys(name)) {
128: traceRemoveSys(name);
129: }
130: else {
131: std::cout << "Currently, `" << name << "' is not being traced.\n";
132: }
133: }
134:
135: else {
136:
137: traceAddSys(tok[i]);
138: }
139: }
140: }
141:
142:
143: bool traceProcessArg(int &argc, char **&argv)
144: {
145: traceAddFromEnvVar();
146:
147: if (argc >= 3 && 0==std::strcmp(argv[1], "-tr")) {
148: traceAddMultiSys(argv[2]);
149: argc -= 2;
150: argv += 2;
151: return true;
152: }
153: else {
154: return false;
155: }
156: }
157:
158:
159: bool ignoreTraceEnvVar = false;
160:
161: void traceAddFromEnvVar()
162: {
163: if (ignoreTraceEnvVar) {
164: return;
165: }
166:
167: char const *var = getenv("TRACE");
168: if (var) {
169: traceAddMultiSys(var);
170: }
171:
172: ignoreTraceEnvVar = true;
173: }
174:
175:
176:
Start cpp section to elk/sm_trdelete.cpp[1
/1
]
1: #line 13897 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33: static void trash(void *blk, size_t size)
34: {
35: #ifdef __BORLANDC__
36: long guess = ((long*)blk)[-1];
37: if (abs(guess - (long)size) > 64) {
38:
39: breaker();
40: return;
41: }
42: #endif
43:
44:
45: std::memset(blk, 0xAA, size);
46:
47:
48: }
49:
50:
51: void trashingDelete(void *blk, size_t size)
52: {
53: trash(blk, size);
54:
55:
56:
57:
58: ::delete((char*)blk);
59: }
60:
61:
62: void trashingDeleteArr(void *blk, size_t size)
63: {
64: trash(blk, size);
65:
66:
67:
68: ::delete[]((char*)blk);
69: }
70:
71:
72:
73:
74:
75:
76:
77: class Foo {
78: public:
79: TRASHINGDELETE
80: int junk[10];
81: int x;
82: int moreJunk[10];
83: };
84:
85: class Bar {
86: public:
87: int junk[10];
88: int x;
89: int moreJunk[10];
90: };
91:
92:
93: int main()
94: {
95: printf("malloc: %p\n", malloc(10));
96:
97: Foo *f = new Foo;
98: f->x = 5;
99: delete f;
100: if (f->x == 5) {
101: printf("trashing-delete failed\n");
102: return 2;
103: }
104:
105: Bar *b = new Bar;
106: b->x = 7;
107: delete b;
108: if ((unsigned)b->x == 0xAAAAAAAAu) {
109: printf("non-trashing-delete failed\n");
110: return 2;
111: }
112:
113: printf("trashing delete works\n");
114: return 0;
115: }
116:
117:
Start cpp section to elk/sm_tsobjlist.cpp[1
/1
]
1: #line 14015 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8: int main()
9: {
10: char const *hi = "hi there";
11: char const *what = "what's up?";
12:
13:
14:
15:
16: SObjList<char const> list;
17:
18:
19:
20:
21: list.prepend(hi);
22:
23: list.append(what);
24:
25:
26:
27: int i = list.indexOf(hi);
28: printf("index of 'hi' is %d\n", i);
29:
30: i = list.indexOf(what);
31: printf("index of 'what' is %d\n", i);
32:
33:
34:
35: int const /*const*/ x = 5;
36: printf("x is %d\n", x);
37:
38: return 0;
39: }
40:
41:
Start cpp section to elk/sm_vdtllist.cpp[1
/1
]
1: #line 14057 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7: void VoidTailList::steal(VoidTailList *src)
8: {
9: if (src) {
10: top = src->top;
11: tail = src->tail;
12: src->top = NULL;
13: delete src;
14: }
15: else {
16: top = NULL;
17: tail = NULL;
18: }
19: }
20:
21: void VoidTailList::prepend(void *newitem)
22: {
23: VoidList::prepend(newitem);
24: if (!tail) {
25: tail = top;
26: }
27: }
28:
29: void VoidTailList::append(void *newitem)
30: {
31: if (isEmpty()) {
32: prepend(newitem);
33: }
34: else {
35:
36: tail->next = new VoidNode(newitem, NULL);
37: tail = tail->next;
38: }
39: }
40:
41: void VoidTailList::insertAt(void *newitem, int index)
42: {
43: VoidList::insertAt(newitem, index);
44: adjustTail();
45: }
46:
47: void VoidTailList::concat(VoidTailList &srcList)
48: {
49:
50: VoidNode *catTail = srcList.top? srcList.tail : tail;
51:
52:
53: VoidList::concat(srcList);
54:
55:
56: tail = catTail;
57: srcList.tail = NULL;
58: }
59:
60: void VoidTailList::adjustTail()
61: {
62: if (!tail) {
63: tail = top;
64: }
65: else if (tail->next) {
66: tail = tail->next;
67: }
68: xassert(tail->next == NULL);
69: }
70:
71: void *VoidTailList::removeFirst()
72: {
73: xassert(top);
74: if (top == tail) {
75: tail = NULL;
76: }
77: void *retval = top->data;
78: VoidNode *tmp = top;
79: top = top->next;
80: delete tmp;
81: return retval;
82: }
83:
84: void *VoidTailList::removeLast()
85: {
86: xassert(top);
87: if (top == tail) {
88: return removeFirst();
89: }
90:
91: VoidNode *before = top;
92: while (before->next != tail) {
93: before = before->next;
94: }
95: void *retval = tail->data;
96: delete tail;
97: tail = before;
98: tail->next = NULL;
99: return retval;
100: }
101:
102: void *VoidTailList::removeAt(int index)
103: {
104: xassert(top);
105: if (index == 0) {
106: return removeFirst();
107: }
108:
109: VoidNode *before = top;
110: index--;
111: while (index > 0) {
112: before = before->next;
113: index--;
114: }
115: xassert(index == 0);
116:
117:
118: if (tail == before->next) {
119: tail = before;
120: }
121:
122:
123: VoidNode *toDelete = before->next;
124: void *retval = toDelete->data;
125: before->next = toDelete->next;
126: delete toDelete;
127:
128: return retval;
129: }
130:
131: void VoidTailList::removeAll()
132: {
133: VoidList::removeAll();
134: tail = NULL;
135: }
136:
137: bool VoidTailList::prependUnique(void *newitem)
138: {
139: bool retval = VoidList::prependUnique(newitem);
140: adjustTail();
141: return retval;
142: }
143:
144: bool VoidTailList::appendUnique(void *newitem)
145: {
146: bool retval = VoidList::appendUnique(newitem);
147: adjustTail();
148: return retval;
149: }
150:
151: void VoidTailList::selfCheck() const
152: {
153: VoidList::selfCheck();
154:
155: if (isNotEmpty()) {
156:
157: VoidNode *n = top;
158: while (n->next) {
159: n = n->next;
160: }
161:
162:
163: xassert(tail == n);
164: }
165: else {
166: xassert(tail == NULL);
167: }
168: }
169:
170:
171:
172:
173:
174:
175:
176: int main()
177: {
178: VoidTailList list;
179: int zero, one, two, three;
180:
181:
182:
183:
184: list.selfCheck();
185:
186: list.append(&two); list.selfCheck();
187: list.prepend(&one); list.selfCheck();
188: list.append(&three); list.selfCheck();
189: list.prepend(&zero); list.selfCheck();
190:
191: xassert(list.nth(0) == &zero);
192: xassert(list.nth(1) == &one);
193: xassert(list.nth(2) == &two);
194: xassert(list.nth(3) == &three);
195:
196: list.removeAll();
197: list.selfCheck();
198:
199: printf("vdtllist works\n");
200:
201: return 0;
202: }
203:
204:
Start cpp section to elk/sm_voidlist.cpp[1
/1
]
1: #line 14262 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15: VoidList::VoidList(VoidList const &obj)
16: : top(NULL)
17: {
18: *this = obj;
19: }
20:
21:
22:
23: int VoidList::count() const
24: {
25: int ct=0;
26: for(VoidNode *p = top; p; p = p->next) {
27: ct++;
28: }
29: return ct;
30: }
31:
32:
33:
34: void *VoidList::nth(int which) const
35: {
36: VoidNode *p;
37: xassert(which>=0);
38: for (p = top; which > 0; which--) {
39: xassert(p);
40: p = p->next;
41: }
42: if (p == NULL) {
43: xfailure(sm_stringc << "asked for list element "
44: << (count()+which) << " (0-based) but list only has "
45: << count() << " elements");
46: }
47: return p->data;
48: }
49:
50:
51:
52: void VoidList::selfCheck() const
53: {
54: if (!top) {
55: return;
56: }
57:
58:
59:
60:
61:
62:
63:
64: VoidNode *slow=top, *fast=top->next;
65: while (fast && fast != slow) {
66:
67: checkHeapNode(fast);
68:
69: slow = slow->next;
70: fast = fast->next;
71: if (fast) {
72: checkHeapNode(fast);
73: fast = fast->next;
74: }
75: }
76:
77: if (fast == slow) {
78: xfailure("linked list has a cycle");
79: }
80: else {
81: return;
82: }
83: }
84:
85:
86: void VoidList::checkHeapDataPtrs() const
87: {
88: for (VoidNode *p=top; p!=NULL; p=p->next) {
89: checkHeapNode(p->data);
90: }
91: }
92:
93:
94: void VoidList::checkUniqueDataPtrs() const
95: {
96: for (VoidNode *p=top; p!=NULL; p=p->next) {
97:
98:
99: for (VoidNode *q=top; q!=p; q=q->next) {
100: if (q->data == p->data) {
101: xfailure("linked list with duplicate element");
102: }
103: }
104: }
105: }
106:
107:
108:
109: void VoidList::prepend(void *newitem)
110: {
111: top = new VoidNode(newitem, top);
112: }
113:
114:
115:
116: void VoidList::append(void *newitem)
117: {
118: if (!top) {
119: prepend(newitem);
120: }
121: else {
122: VoidNode *p;
123: for (p = top; p->next; p = p->next)
124: {}
125: p->next = new VoidNode(newitem);
126: }
127: }
128:
129:
130:
131: void VoidList::insertAt(void *newitem, int index)
132: {
133: if (index == 0 || isEmpty()) {
134:
135: xassert(index == 0);
136: prepend(newitem);
137: }
138:
139: else {
140:
141:
142:
143:
144:
145:
146: index--;
147: VoidNode *p;
148: for (p = top; p->next && index; p = p->next) {
149: index--;
150: }
151: xassert(index == 0);
152:
153:
154:
155: VoidNode *n = new VoidNode(newitem);
156: n->next = p->next;
157: p->next = n;
158: }
159: }
160:
161:
162: void VoidList::insertSorted(void *newitem, VoidDiff diff, void *extra)
163: {
164:
165: if (!top ||
166: diff(newitem, top->data, extra) <= 0) {
167: prepend(newitem);
168: return;
169: }
170:
171:
172: VoidNode *cursor = top;
173: while (cursor->next != NULL &&
174: diff(cursor->next->data, newitem, extra) < 0) {
175: cursor = cursor->next;
176: }
177:
178:
179: VoidNode *newNode = new VoidNode(newitem);
180: newNode->next = cursor->next;
181: cursor->next = newNode;
182: }
183:
184:
185:
186:
187: int VoidList::indexOf(void *item) const
188: {
189: int index = 0;
190: for (VoidNode *p = top; p != NULL; p = p->next, index++) {
191: if (p->data == item) {
192: return index;
193: }
194: }
195: return -1;
196: }
197:
198:
199: int VoidList::indexOfF(void *item) const
200: {
201: int ret = indexOf(item);
202: xassert(ret >= 0);
203: return ret;
204: }
205:
206:
207: bool VoidList::prependUnique(void *newitem)
208: {
209: if (!contains(newitem)) {
210: prepend(newitem);
211: return true;
212: }
213: else {
214: return false;
215: }
216: }
217:
218:
219: bool VoidList::appendUnique(void *newitem)
220: {
221: if (!top) {
222: prepend(newitem);
223: return true;
224: }
225:
226:
227:
228: VoidNode *p;
229: for (p = top; p->next; p = p->next) {
230: if (p->data == newitem) {
231: return false;
232: }
233: }
234: if (p->data == newitem) {
235: return false;
236: }
237:
238: p->next = new VoidNode(newitem);
239: return true;
240: }
241:
242:
243: bool VoidList::removeIfPresent(void *item)
244: {
245:
246: int index = indexOf(item);
247: if (index == -1) {
248: return false;
249: }
250: else {
251: removeAt(index);
252: return true;
253: }
254: }
255:
256:
257: void VoidList::removeItem(void *item)
258: {
259: bool wasThere = removeIfPresent(item);
260: xassert(wasThere);
261: }
262:
263:
264:
265:
266: void *VoidList::removeAt(int index)
267: {
268: if (index == 0) {
269: xassert(top != NULL);
270: VoidNode *temp = top;
271: void *retval = temp->data;
272: top = top->next;
273: delete temp;
274: return retval;
275: }
276:
277:
278: index--;
279:
280: VoidNode *p;
281: for (p = top; p->next && index>0;
282: p = p->next, index--)
283: {}
284:
285: if (p->next) {
286:
287: VoidNode *temp = p->next;
288: void *retval = temp->data;
289: p->next = p->next->next;
290: delete temp;
291: return retval;
292: }
293: else {
294:
295: xfailure("Tried to remove an element not on the list");
296: return NULL;
297: }
298: }
299:
300:
301: void VoidList::removeAll()
302: {
303: while (top != NULL) {
304: VoidNode *temp = top;
305: top = top->next;
306: delete temp;
307: }
308: }
309:
310:
311: void VoidList::reverse()
312: {
313:
314: VoidNode *oldlist = top;
315: top = NULL;
316:
317:
318: while (oldlist != NULL) {
319:
320: VoidNode *node = oldlist;
321: oldlist = oldlist->next;
322:
323:
324: node->next = top;
325: top = node;
326: }
327: }
328:
329:
330:
331:
332:
333:
334:
335:
336:
337: void VoidList::insertionSort(VoidDiff diff, void *extra)
338: {
339: VoidNode *primary = top;
340: while (primary && primary->next) {
341: if (diff(primary->data, primary->next->data, extra) > 0) {
342: VoidNode *tomove = primary->next;
343: primary->next = primary->next->next;
344:
345: if (diff(tomove->data, top->data, extra) < 0) {
346: tomove->next = top;
347: top = tomove;
348: }
349:
350: else {
351: VoidNode *searcher = top;
352: while (diff(tomove->data, searcher->next->data, extra) > 0) {
353: searcher = searcher->next;
354: }
355:
356: tomove->next = searcher->next;
357: searcher->next = tomove;
358: }
359: }
360:
361: else {
362: primary = primary->next;
363: }
364: }
365: }
366:
367:
368:
369: void VoidList::mergeSort(VoidDiff diff, void *extra)
370: {
371: if (top == NULL || top->next == NULL) {
372: return;
373: }
374:
375:
376: VoidList leftHalf;
377: VoidList rightHalf;
378:
379:
380: {
381:
382:
383:
384:
385: VoidNode *slow = top;
386: VoidNode *fast = top->next;
387:
388: while (fast && fast->next) {
389: slow = slow->next;
390: fast = fast->next;
391: fast = fast->next;
392: }
393:
394:
395:
396:
397:
398:
399:
400: rightHalf.top = slow->next;
401: leftHalf.top = this->top;
402: slow->next = NULL;
403: }
404:
405:
406: leftHalf.mergeSort(diff, extra);
407: rightHalf.mergeSort(diff, extra);
408:
409:
410: VoidNode *merged = NULL;
411: while (leftHalf.top != NULL &&
412: rightHalf.top != NULL) {
413:
414: VoidNode *selected;
415: if (diff(leftHalf.top->data, rightHalf.top->data, extra) < 0) {
416: selected = leftHalf.top;
417: leftHalf.top = leftHalf.top->next;
418: }
419: else {
420: selected = rightHalf.top;
421: rightHalf.top = rightHalf.top->next;
422: }
423:
424:
425: if (merged == NULL) {
426:
427: merged = this->top = selected;
428: }
429: else {
430:
431: merged = merged->next = selected;
432: }
433: }
434:
435:
436:
437: if (leftHalf.top != NULL) {
438: merged->next = leftHalf.top;
439: leftHalf.top = NULL;
440: }
441: else {
442: merged->next = rightHalf.top;
443: rightHalf.top = NULL;
444: }
445:
446:
447: xassert(leftHalf.top == NULL &&
448: rightHalf.top == NULL);
449:
450:
451: }
452:
453:
454: bool VoidList::isSorted(VoidDiff diff, void *extra) const
455: {
456: if (isEmpty()) {
457: return true;
458: }
459:
460: void *prev = top->data;
461: VoidListIter iter(*this);
462: iter.adv();
463: for (; !iter.isDone(); iter.adv()) {
464: void *current = iter.data();
465:
466: if (diff(prev, current, extra) <= 0) {
467:
468: }
469: else {
470: return false;
471: }
472:
473: prev = current;
474: }
475:
476: return true;
477: }
478:
479:
480:
481: void VoidList::concat(VoidList &tail)
482: {
483: if (!top) {
484: top = tail.top;
485: }
486: else {
487: VoidNode *n = top;
488: for(; n->next; n = n->next)
489: {}
490: n->next = tail.top;
491: }
492:
493: tail.top = NULL;
494: }
495:
496:
497:
498: void VoidList::stealTailAt(int index, VoidList &source)
499: {
500: if (index == 0) {
501: concat(source);
502: return;
503: }
504:
505:
506:
507: VoidNode *beforeTransfer = source.top;
508: index--;
509: while (index--) {
510: beforeTransfer = beforeTransfer->next;
511: }
512:
513:
514: VoidNode *tailStart = beforeTransfer->next;
515: beforeTransfer->next = NULL;
516:
517:
518: if (!top) {
519: top = tailStart;
520: }
521: else {
522:
523: VoidNode *n = top;
524: for(; n->next; n = n->next)
525: {}
526: n->next = tailStart;
527: }
528: }
529:
530:
531: void VoidList::appendAll(VoidList const &tail)
532: {
533:
534: VoidListMutator destIter(*this);
535: while (!destIter.isDone()) {
536: destIter.adv();
537: }
538:
539: VoidListIter srcIter(tail);
540: for (; !srcIter.isDone(); srcIter.adv()) {
541: destIter.append(srcIter.data());
542: }
543: }
544:
545:
546: VoidList& VoidList::operator= (VoidList const &src)
547: {
548: if (this != &src) {
549: removeAll();
550: appendAll(src);
551: }
552: return *this;
553: }
554:
555:
556: bool VoidList::equalAsLists(VoidList const &otherList, VoidDiff diff, void *extra) const
557: {
558: return 0==compareAsLists(otherList, diff, extra);
559: }
560:
561: int VoidList::compareAsLists(VoidList const &otherList, VoidDiff diff, void *extra) const
562: {
563: VoidListIter mine(*this);
564: VoidListIter his(otherList);
565:
566: while (!mine.isDone() && !his.isDone()) {
567: int cmp = diff(mine.data(), his.data(), extra);
568: if (cmp == 0) {
569:
570: }
571: else {
572:
573: return cmp;
574: }
575:
576: mine.adv();
577: his.adv();
578: }
579:
580: if (!mine.isDone() || !his.isDone()) {
581:
582: return mine.isDone()? -1 : +1;
583: }
584:
585: return 0;
586: }
587:
588:
589: bool VoidList::equalAsSets(VoidList const &otherList, VoidDiff diff, void *extra) const
590: {
591: return this->isSubsetOf(otherList, diff, extra) &&
592: otherList.isSubsetOf(*this, diff, extra);
593: }
594:
595:
596: bool VoidList::isSubsetOf(VoidList const &otherList, VoidDiff diff, void *extra) const
597: {
598: for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
599: if (!otherList.containsByDiff(iter.data(), diff, extra)) {
600: return false;
601: }
602: }
603: return true;
604: }
605:
606:
607: bool VoidList::containsByDiff(void *item, VoidDiff diff, void *extra) const
608: {
609: for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
610: if (0==diff(item, iter.data(), extra)) {
611: return true;
612: }
613: }
614: return false;
615: }
616:
617:
618: STATICDEF int VoidList::pointerAddressDiff(void *left, void *right, void*)
619: {
620:
621: return
622: std::less<void*>()(right, left) ? 1 :
623: ((left == right) ? 0 : -1);
624: }
625:
626:
627: void VoidList::debugPrint() const
628: {
629: printf("{ ");
630: for (VoidListIter iter(*this); !iter.isDone(); iter.adv()) {
631: printf("%p ", iter.data());
632: }
633: printf("}");
634: }
635:
636:
637:
638: VoidListMutator&
639: VoidListMutator::operator=(VoidListMutator const &obj)
640: {
641:
642:
643:
644: xassert(&list == &obj.list);
645:
646: prev = obj.prev;
647: current = obj.current;
648:
649: return *this;
650: }
651:
652:
653: void VoidListMutator::insertBefore(void *item)
654: {
655: if (prev == NULL) {
656:
657: list.prepend(item);
658: reset();
659: }
660: else {
661: current = prev->next = new VoidNode(item, current);
662: }
663: }
664:
665:
666: void VoidListMutator::insertAfter(void *item)
667: {
668: xassert(!isDone());
669: current->next = new VoidNode(item, current->next);
670: }
671:
672:
673: void VoidListMutator::append(void *item)
674: {
675: xassert(isDone());
676: insertBefore(item);
677: adv();
678: }
679:
680:
681: void *VoidListMutator::remove()
682: {
683: xassert(!isDone());
684: void *retval = data();
685: if (prev == NULL) {
686:
687: list.top = current->next;
688: delete current;
689: current = list.top;
690: }
691: else {
692: current = current->next;
693: delete prev->next;
694: prev->next = current;
695: }
696: return retval;
697: }
698:
699:
700:
701: VoidListIter::VoidListIter(VoidList const &list, int pos)
702: {
703: reset(list);
704: while (pos--) {
705: adv();
706: }
707: }
708:
709:
710:
711:
712:
713:
714:
715:
716:
717: void verifySorted(VoidList const &list)
718: {
719: int prev = 0;
720: VoidListIter iter(list);
721: for (; !iter.isDone(); iter.adv()) {
722: int current = (int)iter.data();
723: xassert(prev <= current);
724: prev = current;
725: }
726: }
727:
728:
729:
730:
731: void testSorting()
732: {
733: enum { ITERS=100, ITEMS=20 };
734:
735: loopi(ITERS) {
736:
737: VoidList list1;
738: VoidList list3;
739: int numItems;
740: do {
741: list1.removeAll();
742: list3.removeAll();
743: numItems = rand()%ITEMS;
744: loopj(numItems) {
745: void *toInsert = (void*)( (rand()%ITEMS) * 4 );
746: list1.prepend(toInsert);
747: list3.insertSorted(toInsert, VoidList::pointerAddressDiff);
748: }
749: } while (list1.isSorted(VoidList::pointerAddressDiff));
750:
751:
752:
753: verifySorted(list3);
754:
755:
756: VoidList list2;
757: list2 = list1;
758:
759:
760: list1.insertionSort(VoidList::pointerAddressDiff);
761: xassert(list1.equalAsPointerSets(list2));
762: xassert(!list1.equalAsPointerLists(list2));
763: list2.mergeSort(VoidList::pointerAddressDiff);
764:
765:
766:
767: list1.selfCheck();
768: list2.selfCheck();
769:
770:
771: xassert(list1.count() == numItems && list2.count() == numItems);
772:
773:
774: verifySorted(list1);
775: verifySorted(list2);
776:
777:
778: xassert(list1.equalAsPointerLists(list2));
779: xassert(list1.equalAsPointerLists(list3));
780:
781:
782: void *first = list1.first();
783: while (list1.removeIfPresent(first))
784: {}
785: xassert(!list1.equalAsPointerSets(list2));
786: }
787: }
788:
789:
790: void entry()
791: {
792:
793: {
794:
795: void *a=(void*)4, *b=(void*)8, *c=(void*)12, *d=(void*)16;
796:
797: VoidList list;
798:
799:
800: list.append(c); PRINT(list);
801: list.prepend(b); PRINT(list);
802: list.append(d); PRINT(list);
803: list.prepend(a); PRINT(list);
804: list.removeAt(2); PRINT(list);
805:
806: xassert( list.count() == 3 &&
807: !list.isEmpty() &&
808: list.nth(0) == a &&
809: list.nth(1) == b &&
810: list.nth(2) == d &&
811: list.indexOf(a) == 0 &&
812: list.indexOf(b) == 1 &&
813: list.indexOf(c) == -1 &&
814: list.indexOf(d) == 2
815: );
816: list.selfCheck();
817:
818:
819: {
820: VoidListMutator mut(list);
821: mut.adv();
822:
823: mut.insertAfter(c);
824:
825: verifySorted(list);
826: mut.remove();
827:
828: xassert(mut.data() == c);
829:
830:
831: VoidListMutator mut2(mut);
832: mut2.adv();
833: xassert(mut.data() == c && mut2.data() == d);
834:
835:
836: VoidListIter iter(mut);
837: iter.adv();
838: xassert(iter.data() == d);
839: iter.adv();
840: xassert(iter.isDone() && mut.data() == c);
841:
842: PRINT(list);
843: }
844:
845:
846:
847: xassert(list.appendUnique(c) == false &&
848: list.prependUnique(d) == false &&
849: list.prependUnique(b) == true);
850:
851: list.removeItem(a);
852: xassert(list.removeIfPresent(a) == false);
853:
854: verifySorted(list);
855: PRINT(list);
856:
857:
858: list.reverse();
859:
860: xassert(list.indexOf(d) == 0 &&
861: list.indexOf(c) == 1 &&
862: list.indexOf(b) == 2);
863: PRINT(list);
864:
865:
866: VoidList thief;
867: thief.stealTailAt(1, list);
868:
869:
870: xassert(list.count() == 1 &&
871: list.indexOf(d) == 0 &&
872: thief.count() == 2 &&
873: thief.indexOf(c) == 0 &&
874: thief.indexOf(b) == 1);
875: }
876:
877:
878:
879: testSorting();
880:
881: printf("voidlist ok\n");
882: }
883:
884: USUAL_MAIN
885:
886:
887:
Start cpp section to elk/sm_vptrmap.cpp[1
/1
]
1: #line 15150 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: int VoidPtrMap::lookups = 0;
14: int VoidPtrMap::probes = 0;
15:
16:
17: VoidPtrMap::VoidPtrMap()
18: : hashTable(NULL),
19: tableSize(0),
20: tableSizeBits(0),
21: numEntries(0),
22: iterators(0)
23: {
24: alloc(4);
25: empty();
26: }
27:
28: VoidPtrMap::~VoidPtrMap()
29: {
30: delete[] hashTable;
31: }
32:
33:
34: void VoidPtrMap::alloc(int bits)
35: {
36: tableSizeBits = bits;
37: tableSize = 1 << bits;
38: hashTable = new Entry[tableSize];
39: }
40:
41:
42: inline unsigned VoidPtrMap::hashFunc(unsigned multiplier, unsigned key) const
43: {
44:
45:
46:
47: unsigned ret = key * multiplier;
48:
49:
50: ret = ret >> ((sizeof(unsigned)*8) - tableSizeBits);
51: ret = ret & (tableSize-1);
52:
53: return ret;
54: }
55:
56:
57: VoidPtrMap::Entry &VoidPtrMap::findEntry(void const *key) const
58: {
59: xassert(key != NULL);
60: lookups++;
61:
62:
63: enum {
64:
65:
66:
67: CONST1 = 0x9E3779B9U,
68:
69:
70:
71:
72:
73:
74:
75:
76: CONST2 = 0x5DB3D742U
77: };
78:
79:
80:
81: unsigned index = hashFunc(CONST1, (SM_RAWADDRESS)key);
82:
83:
84:
85: {
86: probes++;
87: Entry &e = hashTable[index];
88: if (e.key == NULL ||
89: e.key == key) {
90: return e;
91: }
92: }
93:
94:
95:
96:
97: unsigned stride = hashFunc(CONST2, (SM_RAWADDRESS)key) | 1;
98:
99:
100:
101:
102:
103:
104:
105: for (int i=0; i<tableSize; i++) {
106: index = (index + stride) & (tableSize-1);
107:
108: probes++;
109: Entry &e = hashTable[index];
110: if (e.key == NULL ||
111: e.key == key) {
112: return e;
113: }
114: }
115:
116:
117:
118:
119: xfailure("findEntry traversed all entries");
120: return *((Entry*)NULL);
121: }
122:
123:
124: void VoidPtrMap::add(void *key, void *value)
125: {
126: xassert(iterators == 0);
127:
128:
129: if (numEntries+1 > (tableSize/2 + tableSize/4)) {
130: expand();
131: }
132:
133: Entry &e = findEntry(key);
134: if (e.key == NULL) {
135: e.key = key;
136: numEntries++;
137: }
138: else {
139: xassert(e.key == key);
140: }
141: e.value = value;
142: }
143:
144:
145: void VoidPtrMap::expand()
146: {
147: Entry *oldHashTable = hashTable;
148: int oldTableSize = tableSize;
149:
150: alloc(tableSizeBits + 1);
151: empty();
152:
153:
154: for (int i=0; i < oldTableSize; i++) {
155: Entry &e = oldHashTable[i];
156: if (e.key) {
157: add(e.key, e.value);
158: }
159: }
160:
161: delete[] oldHashTable;
162: }
163:
164:
165: void VoidPtrMap::empty()
166: {
167: xassert(iterators == 0);
168:
169:
170: std::memset(hashTable, 0, sizeof(*hashTable) * tableSize);
171: numEntries = 0;
172: }
173:
174:
175:
176: VoidPtrMap::Iter::Iter(VoidPtrMap const &m)
177: : map(m),
178: index(map.tableSize)
179: {
180: map.iterators++;
181: adv();
182: }
183:
184: VoidPtrMap::Iter::~Iter()
185: {
186: map.iterators--;
187: }
188:
189:
190: void VoidPtrMap::Iter::adv()
191: {
192: xassert(index >= 0);
193: index--;
194: while (index >= 0 &&
195: map.hashTable[index].key == NULL) {
196: index--;
197: }
198: }
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213: class Node {
214: public:
215: int *value;
216: bool found;
217:
218: public:
219: Node() {
220: value = new int(0);
221: found = false;
222: }
223: ~Node() {
224: delete value;
225: }
226: };
227:
228:
229: int doubleCompar(void const *dp1, void const *dp2)
230: {
231: double d1 = *((double*)dp1);
232: double d2 = *((double*)dp2);
233: if (d1 < d2) return -1;
234: if (d1 > d2) return +1;
235: return 0;
236: }
237:
238:
239: void test1()
240: {
241: printf("test1: testing PtrMap\n");
242:
243: enum { ITERS1=10, ITERS2MAX=2000 };
244:
245: double avgprobes[ITERS1];
246:
247: printf(" iter iters entries lookups probes avgprobes\n");
248: printf(" ---- ----- ------- ------- ------ ---------\n");
249:
250: for (int i=0; i < ITERS1; i++) {
251:
252:
253:
254:
255:
256: #define CAST(something) /*nothing*/
257:
258: PtrMap<Node,int> map;
259: ObjArrayStack<Node> stack;
260:
261: int iters2 = rand() % ITERS2MAX;
262: for (int j=0; j < iters2; j++) {
263: int op = rand() % 100;
264:
265: if (op <= 40) {
266: Node *n = new Node;
267: stack.push(n);
268: map.add(n, n->value);
269: }
270:
271: else if (op <= 80) {
272: if (stack.isNotEmpty()) {
273: Node *n = stack[rand() % stack.length()];
274: int *v = CAST(int*)map.get(n);
275: xassert(v && v == n->value);
276:
277: if (rand() % 10 == 0) {
278:
279: delete n->value;
280: n->value = new int(0);
281: map.add(n, n->value);
282: }
283: }
284: }
285:
286: else if (op <= 90) {
287: Node *n = new Node;
288: int *v = CAST(int*)map.get(n);
289: xassert(!v);
290: delete n;
291: }
292:
293: else if (op <= 100) {
294:
295: int k;
296: for (k=0; k < stack.length(); k++) {
297: stack[k]->found = false;
298: }
299:
300:
301: int numFound = 0;
302:
303: PtrMap<Node,int>::Iter iter(map);
304: for (; !iter.isDone(); iter.adv()) {
305: Node *n = CAST(Node*)iter.key();
306: int *v = CAST(int*)iter.value();
307:
308: xassert(v == n->value);
309: xassert(n->found == false);
310: n->found = true;
311: numFound++;
312: }
313:
314:
315: for (k=0; k < stack.length(); k++) {
316: xassert(stack[k]->found == true);
317: }
318: xassert(numFound == stack.length());
319: }
320: }
321:
322: xassert(map.getNumEntries() == stack.length());
323:
324: avgprobes[i] = ((double)VoidPtrMap::probes) / ((double)VoidPtrMap::lookups);
325: printf(" %4d %5d %7d %7d %6d %g\n",
326: i,
327: iters2,
328: map.getNumEntries(),
329: VoidPtrMap::lookups,
330: VoidPtrMap::probes,
331: avgprobes[i]);
332:
333: VoidPtrMap::probes = 0;
334: VoidPtrMap::lookups = 0;
335: }
336:
337:
338: qsort(avgprobes, ITERS1, sizeof(avgprobes[0]), doubleCompar);
339: printf("median avgprobe: %g\n", avgprobes[ITERS1/2]);
340:
341:
342: }
343:
344:
345: struct A {
346: int x;
347: A(int x0) : x(x0) {}
348: };
349:
350: void test2()
351: {
352: printf("test2: testing PtrSet\n");
353:
354: PtrSet<A> s;
355: xassert(s.isEmpty());
356: xassert(s.getNumEntries() == 0);
357:
358: A *a1 = new A(1);
359: s.add(a1);
360: xassert(s.isNotEmpty());
361: xassert(s.getNumEntries() == 1);
362:
363: A *a2 = new A(2);
364: s.add(a2);
365: xassert(s.isNotEmpty());
366: xassert(s.getNumEntries() == 2);
367:
368: xassert(s.contains(a1));
369: xassert(s.contains(a2));
370:
371: s.empty();
372:
373: xassert(!s.contains(a1));
374: xassert(!s.contains(a2));
375: xassert(s.isEmpty());
376: xassert(s.getNumEntries() == 0);
377:
378: A *a3 = new A(3);
379: s.add(a3);
380: xassert(s.isNotEmpty());
381: xassert(s.getNumEntries() == 1);
382: }
383:
384:
385: void entry()
386: {
387: printf("testing vptrmap\n");
388: test1();
389: test2();
390: printf("vptrmap is ok\n");
391: }
392:
393:
394: USUAL_MAIN
395:
396:
Start cpp section to elk/sm_breaker.cpp[1
/1
]
1: #line 15547 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12: void ackackack(int*) {}
13:
14: void breaker()
15: {
16: static int i=0;
17: int a=1;
18:
19: ackackack(&a);
20: i++;
21: }
22:
23:
24:
25:
26:
27:
Start cpp section to elk/sm_crc.cpp[1
/1
]
1: #line 15575 "./lpsrc/sm.pak"
2:
3:
4:
5:
6: /* crc32h.c -- package to compute 32-bit CRC one byte at a time using */
7: /* the high-bit first (Big-Endian) bit ordering convention */
8: /* */
9: /* Synopsis: */
10: /* gen_crc_table() -- generates a 256-word table containing all CRC */
11: /* remainders for every possible 8-bit byte. It */
12: /* must be executed (once) before any CRC updates. */
13: /* */
14: /* unsigned update_crc(crc_accum, data_blk_ptr, data_blk_size) */
15: /* unsigned crc_accum; char *data_blk_ptr; int data_blk_size; */
16: /* Returns the updated value of the CRC accumulator after */
17: /* processing each byte in the addressed block of data. */
18: /* */
19: /* It is assumed that an unsigned long is at least 32 bits wide and */
20: /* that the predefined type char occupies one 8-bit byte of storage. */
21: /* */
22: /* The generator polynomial used for this version of the package is */
23: /* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 */
24: /* as specified in the Autodin/Ethernet/ADCCP protocol standards. */
25: /* Other degree 32 polynomials may be substituted by re-defining the */
26: /* symbol POLYNOMIAL below. Lower degree polynomials must first be */
27: /* multiplied by an appropriate power of x. The representation used */
28: /* is that the coefficient of x^0 is stored in the LSB of the 32-bit */
29: /* word and the coefficient of x^31 is stored in the most significant */
30: /* bit. The CRC is to be appended to the data most significant byte */
31: /* first. For those protocols in which bytes are transmitted MSB */
32: /* first and in the same order as they are encountered in the block */
33: /* this convention results in the CRC remainder being transmitted with */
34: /* the coefficient of x^31 first and with that of x^0 last (just as */
35: /* would be done by a hardware shift register mechanization). */
36: /* */
37: /* The table lookup technique was adapted from the algorithm described */
38: /* by Avram Perez, Byte-wise CRC Calculations, IEEE Micro 3, 40 (1983).*/
39:
40:
41:
42: static unsigned long crc_table[256];
43:
44: void gen_crc_table()
45: /* generate the table of CRC remainders for all possible bytes */
46: { register int i, j; register unsigned long crc_accum;
47: for ( i = 0; i < 256; i++ )
48: { crc_accum = ( (unsigned long) i << 24 );
49: for ( j = 0; j < 8; j++ )
50: { if ( crc_accum & 0x80000000L )
51: crc_accum =
52: ( crc_accum << 1 ) ^ POLYNOMIAL;
53: else
54: crc_accum =
55: ( crc_accum << 1 ); }
56: crc_table[i] = crc_accum; }
57: return; }
58:
59: unsigned long update_crc(unsigned long crc_accum, char const *data_blk_ptr,
60: int data_blk_size)
61: /* update the CRC on the data block one byte at a time */
62: { register int i, j;
63: for ( j = 0; j < data_blk_size; j++ )
64: { i = ( (int) ( crc_accum >> 24) ^ *data_blk_ptr++ ) & 0xff;
65: crc_accum = ( crc_accum << 8 ) ^ crc_table[i]; }
66: return crc_accum; }
67:
68:
69:
70: static int made_table = 0;
71: unsigned long crc32(unsigned char const *data, int length)
72: {
73: if (!made_table) {
74: gen_crc_table();
75: made_table = 1;
76: }
77:
78: return update_crc(0xFFFFFFFF, (char*)data, length);
79: }
80:
81:
82:
83:
84:
85:
86:
87:
88:
89: int errors=0;
90:
91: void testCrc(char const *data, int length, unsigned long crc)
92: {
93: unsigned long val = crc32((unsigned char*)data, length);
94: printf("computed crc is 0x%08lX, expected is 0x%08lX\n",
95: val, ~crc);
96: if (val != ~crc) {
97: errors++;
98: }
99: }
100:
101:
102: int main(int argc, char *argv[])
103: {
104:
105: if (argc >= 2) {
106: FILE *fp = fopen(argv[1], "r");
107: if (!fp) {
108: printf("error opening %s: %m\n", argv[1]);
109: return 2;
110: }
111:
112:
113: fseek(fp, 0, SEEK_END);
114: int len = ftell(fp);
115: fseek(fp, 0, SEEK_SET);
116:
117:
118: unsigned char *buf = (unsigned char*)malloc(len);
119: if (fread(buf, 1, len, fp) != (size_t)len) {
120: printf("read error, or short count..\n");
121: return 2;
122: }
123:
124:
125: long val = crc32(buf, len);
126: printf("crc32: 0x%08lX\n", val);
127:
128: return 0;
129: }
130:
131: /* 40 Octets filled with "0" */
132: /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = 864d7f99 */
133: char pkt_data1[48]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
135: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
136: 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
137: 0x00,0x00,0x00,0x28,0x86,0x4d,0x7f,0x99};
138:
139: /* 40 Octets filled with "1" */
140: /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = c55e457a */
141: char pkt_data2[48]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
142: 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
143: 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
144: 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
145: 0x00,0x00,0x00,0x28,0xc5,0x5e,0x45,0x7a};
146:
147: /* 40 Octets counting: 1 to 40 */
148: /* CPCS-UU = 0, CPI = 0, Length = 40, CRC-32 = bf671ed0 */
149: char pkt_data3[48]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
150: 0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
151: 0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,
152: 0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
153: 0x00,0x00,0x00,0x28,0xbf,0x67,0x1e,0xd0};
154:
155: /* 40 Octets counting: 1 to 40 */
156: /* CPCS-UU = 11, CPI = 22, CRC-32 = acba602a */
157: char pkt_data4[48]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
158: 0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
159: 0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,
160: 0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
161: 0x11,0x22,0x00,0x28,0xac,0xba,0x60,0x2a};
162:
163: testCrc(pkt_data1, 44, 0x864d7f99);
164: testCrc(pkt_data2, 44, 0xc55e457a);
165: testCrc(pkt_data3, 44, 0xbf671ed0);
166: testCrc(pkt_data4, 44, 0xacba602a);
167:
168: return errors;
169: }
170:
171:
172:
173:
174:
Start cpp section to elk/sm_datablok.cpp[1
/1
]
1: #line 15750 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: byte const DataBlock::endpost = 0xBB;
20:
21:
22: void DataBlock::init(int allocatedSize)
23: {
24: xassert(allocatedSize >= 0);
25: dataLen = 0;
26: allocated = allocatedSize;
27: if (allocated) {
28: data = allocate(allocated);
29: }
30: else {
31: data = NULL;
32: }
33:
34: SELFCHECK();
35: }
36:
37:
38: STATICDEF byte *DataBlock::allocate(int size)
39: {
40: byte *ret = new byte[size+1];
41: ret[size] = endpost;
42: return ret;
43: }
44:
45:
46: void DataBlock::selfCheck() const
47: {
48: if (!( 0 <= dataLen && dataLen <= allocated )) {
49: breaker();
50: }
51: xassert(0 <= dataLen && dataLen <= allocated);
52: xassert( (data==NULL) == (allocated==0) );
53: xassert( data==NULL || data[allocated]==endpost );
54: }
55:
56:
57: DataBlock::DataBlock(int allocatedSize)
58: {
59: init(allocatedSize);
60: SELFCHECK();
61: }
62:
63:
64: DataBlock::DataBlock(char const *srcString)
65: {
66: init(0);
67: setFromString(srcString);
68: SELFCHECK();
69: }
70:
71:
72: void DataBlock::ctor(byte const *srcData, int dataLen)
73: {
74: init(0);
75: setFromBlock(srcData, dataLen);
76: SELFCHECK();
77: }
78:
79:
80: void DataBlock::ctor(byte const *srcData, int srcDataLen, int allocatedSize)
81: {
82: init(allocatedSize);
83: dataLen = srcDataLen;
84: std::memcpy(data, srcData, dataLen);
85: SELFCHECK();
86: }
87:
88:
89: DataBlock::DataBlock(DataBlock const &obj)
90: {
91: init(obj.allocated);
92: copyCtorShared(obj);
93: }
94:
95: void DataBlock::copyCtorShared(DataBlock const &obj)
96: {
97: dataLen = obj.dataLen;
98: if (dataLen > 0) {
99: std::memcpy(data, obj.data, dataLen);
100: }
101: SELFCHECK();
102: }
103:
104:
105: DataBlock::DataBlock(DataBlock const &obj, int minToAllocate)
106: {
107: init(max(obj.getAllocated(), minToAllocate));
108: copyCtorShared(obj);
109: }
110:
111:
112: DataBlock::~DataBlock()
113: {
114: try {
115: SELFCHECK();
116: if (data) {
117: delete[] data;
118: }
119: }
120: CAUTIOUS_RELAY
121: }
122:
123:
124: bool DataBlock::allEqual(DataBlock const &obj) const
125: {
126: SELFCHECK();
127: return allocated == obj.allocated &&
128: dataEqual(obj);
129: }
130:
131:
132: bool DataBlock::dataEqual(DataBlock const &obj) const
133: {
134: SELFCHECK();
135: if (dataLen != obj.dataLen ||
136: (dataLen > 0 &&
137: 0 != std::memcmp(data, obj.data, dataLen))) {
138: return false;
139: }
140: else {
141: return true;
142: }
143: }
144:
145:
146:
147: void DataBlock::setDataLen(int newLen)
148: {
149: SELFCHECK();
150: xassert(0 <= newLen && newLen <= allocated);
151: dataLen = newLen;
152: SELFCHECK();
153: }
154:
155:
156: void DataBlock::setAllocated(int newAllocated)
157: {
158: SELFCHECK();
159: xassert(newAllocated >= 0);
160: if (allocated != newAllocated) {
161:
162: byte *newData = NULL;
163: if (newAllocated > 0) {
164: newData = allocate(newAllocated);
165: }
166:
167:
168: if (dataLen > newAllocated) {
169: dataLen = newAllocated;
170: }
171:
172:
173: if (dataLen > 0) {
174: std::memcpy(newData, data, dataLen);
175: }
176:
177:
178: delete[] data;
179: data = newData;
180: allocated = newAllocated;
181: }
182: SELFCHECK();
183: }
184:
185:
186: void DataBlock::ensureAtLeast(int minAllocated)
187: {
188: if (allocated < minAllocated) {
189: setAllocated(minAllocated);
190: }
191: }
192:
193:
194: void DataBlock::growDataLen(int changeAmount)
195: {
196: ensureAtLeast(getDataLen() + changeAmount);
197: changeDataLen(changeAmount);
198: }
199:
200:
201: void DataBlock::addNull()
202: {
203: SELFCHECK();
204: data[dataLen] = 0;
205: setDataLen(dataLen + 1);
206: SELFCHECK();
207: }
208:
209:
210: void DataBlock::setFromString(char const *srcString)
211: {
212: SELFCHECK();
213: int len = std::strlen(srcString)+1;
214:
215: setFromBlock((byte const*)srcString, len);
216: SELFCHECK();
217: }
218:
219: void DataBlock::setFromBlock(byte const *srcData, int len)
220: {
221: SELFCHECK();
222: if (len > allocated) {
223: setAllocated(len);
224: }
225: setDataLen(len);
226: if (len > 0) {
227: std::memcpy(data, srcData, len);
228: }
229: SELFCHECK();
230: }
231:
232:
233: DataBlock& DataBlock::operator= (DataBlock const &obj)
234: {
235: SELFCHECK();
236: if (this != &obj) {
237: setAllocated(obj.allocated);
238: dataLen = obj.dataLen;
239: std::memcpy(data, obj.data, dataLen);
240: }
241: SELFCHECK();
242: return *this;
243: }
244:
245:
246: void DataBlock::print(char const *label, int bytesPerLine) const
247: {
248: xassert(bytesPerLine >= 1);
249: SELFCHECK();
250:
251: if (label) {
252: printf("---- %s, length = %d, crc32 = 0x%lX ---- {\n",
253: label, getDataLen(),
254: crc32(getDataC(), getDataLen()));
255: }
256:
257: int cursor = 0;
258: while (cursor < getDataLen()) {
259: int linelen = min(bytesPerLine, getDataLen() - cursor);
260: xassert(linelen >= 1);
261:
262: printf(" ");
263: printHexLine(getDataC() + cursor, linelen, bytesPerLine);
264: printf(" ");
265: printPrintableLine(getDataC() + cursor, linelen);
266: printf("\n");
267:
268: cursor += linelen;
269: }
270:
271: if (label) {
272: printf("}\n");
273: }
274: SELFCHECK();
275: }
276:
277:
278:
279:
280: STATICDEF void DataBlock::printHexLine(byte const *data, int length, int linelen)
281: {
282: xassert(data != NULL &&
283: length >= 1 &&
284: linelen >= length);
285:
286: for (int i=0; i<linelen; i++) {
287: if (i < length) {
288: printf("%02X ", (byte)*data);
289: data++;
290: }
291: else {
292: printf(" ");
293: }
294: }
295: }
296:
297:
298:
299:
300: STATICDEF void DataBlock::printPrintableLine(byte const *data, int length,
301: char unprintable)
302: {
303: xassert(data != NULL &&
304: length >= 1);
305:
306: while (length--) {
307: if (isprint(*data)) {
308: printf("%c", *data);
309: }
310: else {
311: printf("%c", unprintable);
312: }
313: data++;
314: }
315: }
316:
317:
318:
319: void DataBlock::print(char const *label) const
320: {
321: enum { MARGIN = 70 };
322:
323: if (label) {
324: printf("------ %s (length=%d) -------\n", label, getDataLen());
325: }
326:
327: byte *p = data;
328: int i;
329: int column=0;
330: for (i=0; i<dataLen; i++, p++) {
331: if (isprint(*p)) {
332: if (*p != '\\') {
333: column += printf("%c", *p);
334: }
335: else {
336: printf("\\\\");
337: }
338: }
339: else {
340: column += printf("\\x%02X", *p);
341: }
342:
343: if (column >= MARGIN && (i+1) < dataLen) {
344: printf("\\\n");
345: column = 0;
346: }
347: }
348:
349:
350: if (column != 0) {
351: printf("\n");
352: }
353:
354: if (label) {
355: printf("------ end of %s -------\n", label);
356: }
357: }
358:
359:
360:
361: void DataBlock::dontPrint(char const *, int) const
362: {}
363:
364:
365: void DataBlock::writeToFile(char const *fname) const
366: {
367: FILE *fp = fopen(fname, "wb");
368: if (!fp) {
369: xsyserror("fopen", fname);
370: }
371:
372:
373:
374:
375: if ((int)fwrite(getDataC(), 1, getDataLen(), fp) != getDataLen()) {
376: xsyserror("fwrite", fname);
377: }
378:
379: if (fclose(fp) != 0) {
380: xsyserror("fclose", fname);
381: }
382: }
383:
384:
385: void DataBlock::readFromFile(char const *fname)
386: {
387: FILE *fp = fopen(fname, "rb");
388: if (!fp) {
389: xsyserror("fopen", fname);
390: }
391:
392:
393: if (fseek(fp, 0, SEEK_END) != 0) {
394: xsyserror("fseek", fname);
395: }
396:
397: long len = ftell(fp);
398: if (len < 0) {
399: xsyserror("ftell", fname);
400: }
401:
402: setAllocated(len);
403:
404:
405: if (fseek(fp, 0, SEEK_SET) != 0) {
406: xsyserror("fseek", fname);
407: }
408:
409: if ((long)fread(getData(), 1, len, fp) != len) {
410: xsyserror("fread", fname);
411: }
412:
413: setDataLen(len);
414:
415: if (fclose(fp) != 0) {
416: xsyserror("fclose", fname);
417: }
418: }
419:
420:
421:
422:
423:
424: int doit()
425: {
426:
427: {
428:
429: {
430: DataBlock b(260);
431: for (int i=0; i<260; i++) {
432: b.getData()[i] = (byte)i;
433: }
434: b.setDataLen(260);
435: b.print("all bytes plus 4 extra");
436: }
437:
438: DataBlock block("yadda smacker");
439: xassert(block.getDataLen() == 14);
440:
441: DataBlock block2((byte*)"yadda smacker", 13, 14);
442: block2.addNull();
443: xassert(block == block2);
444:
445: DataBlock block3;
446: block3 = block2;
447: xassert(block3 == block);
448:
449: block3.setAllocated(5);
450: block2.setAllocated(25);
451: xassert(block3 != block2);
452:
453:
454: block.writeToFile("tempfile.blk");
455: DataBlock block4;
456: block4.readFromFile("tempfile.blk");
457: xassert(block == block4);
458:
459:
460: try {
461: {
462: DataBlock b(block);
463: b.getData()[block.getAllocated()] = 0;
464:
465: printf("this should cause an assertion failure:\n");
466:
467: }
468: return printf("failed to detect overrun\n");
469: }
470: catch (...) {}
471: }
472:
473: printf("test succeeded\n");
474: return 0;
475: }
476:
477: int main()
478: {
479: try {
480: return doit();
481: }
482: catch (xBase &x) {
483: return printf("failed: %s\n", x.why());
484: }
485: }
486:
487:
488:
Start cpp section to elk/sm_exc.cpp[1
/1
]
1: #line 16239 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15: bool xBase::logExceptions = true;
16: int xBase::creationCount = 0;
17:
18:
19: xBase::xBase(char const *m)
20: : msg(m)
21: {
22: if (logExceptions) {
23: std::clog << "Exception thrown: " << m << std::endl;
24: }
25:
26:
27:
28: creationCount++;
29: }
30:
31:
32: xBase::xBase(xBase const &obj)
33: : msg(obj.msg)
34: {
35: creationCount++;
36: }
37:
38:
39: xBase::~xBase()
40: {
41: creationCount--;
42: }
43:
44:
45:
46:
47:
48:
49:
50:
51:
52: bool unwinding()
53: {
54: return xBase::creationCount != 0;
55: }
56:
57:
58:
59: bool unwinding_other(xBase const &)
60: {
61:
62: return xBase::creationCount > 1;
63: }
64:
65:
66: void xBase::insert(std::ostream &os) const
67: {
68: os << why();
69: }
70:
71:
72: void xbase(char const *msg)
73: {
74: xBase x(msg);
75: THROW(x);
76: }
77:
78:
79:
80: x_assert::x_assert(char const *cond, char const *fname, int line)
81: : xBase(sm_stringb(
82: "Assertion failed: " << cond <<
83: ", file " << fname <<
84: " line " << line)),
85: condition(cond),
86: filename(fname),
87: lineno(line)
88: {}
89:
90: x_assert::x_assert(x_assert const &obj)
91: : xBase(obj),
92: condition(obj.condition),
93: filename(obj.filename),
94: lineno(obj.lineno)
95: {}
96:
97: x_assert::~x_assert()
98: {}
99:
100:
101:
102: void x_assert_fail(char const *cond, char const *file, int line)
103: {
104: THROW(x_assert(cond, file, line));
105: }
106:
107:
108:
109: xFormat::xFormat(char const *cond)
110: : xBase(sm_stringb("Formatting error: " << cond)),
111: condition(cond)
112: {}
113:
114: xFormat::xFormat(xFormat const &obj)
115: : xBase(obj),
116: condition(obj.condition)
117: {}
118:
119: xFormat::~xFormat()
120: {}
121:
122:
123: void xformat(char const *condition)
124: {
125: xFormat x(condition);
126: THROW(x);
127: }
128:
129: void formatAssert_fail(char const *cond, char const *file, int line)
130: {
131: xFormat x(sm_stringc << "format assertion failed, "
132: << file << ":" << line << ": "
133: << cond);
134: THROW(x);
135: }
136:
137:
138:
139: XOpen::XOpen(char const *fname)
140: : xBase(sm_stringc << "failed to open file: " << fname),
141: filename(fname)
142: {}
143:
144: XOpen::XOpen(XOpen const &obj)
145: : xBase(obj),
146: DMEMB(filename)
147: {}
148:
149: XOpen::~XOpen()
150: {}
151:
152:
153: void throw_XOpen(char const *fname)
154: {
155: XOpen x(fname);
156: THROW(x);
157: }
158:
159:
160:
161:
162:
163: int main()
164: {
165: xBase x("yadda");
166: std::cout << x << std::endl;
167:
168: try {
169: THROW(x);
170: }
171: catch (xBase &x) {
172: std::cout << "caught xBase: " << x << std::endl;
173: }
174:
175: return 0;
176: }
177:
178:
179:
Start cpp section to elk/sm_missing.cpp[1
/1
]
1: #line 16419 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10: int missing_stricmp(char const *s1, char const *s2)
11: {
12: while (*s1 && *s2) {
13:
14:
15:
16: int d = tolower(*s1) - tolower(*s2);
17: if (d != 0) {
18: return d;
19: }
20: s1++;
21: s2++;
22: }
23:
24:
25: return *s1 - *s2;
26: }
Start cpp section to elk/sm_nonport.cpp[1
/1
]
1: #line 16446 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32: void sleep(unsigned sec) {
33: Sleep(sec * 1000);
34: return;
35: }
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63: NonportFailFunc nonportFail = defaultNonportFail;
64:
65: void defaultNonportFail(char const *, char const *)
66: {}
67:
68:
69: inline void fail(char const *call, char const *ctx=NULL)
70: {
71: nonportFail(call, ctx);
72: }
73:
74:
75: void setRawMode(bool raw)
76: {
77: # ifdef _WIN32
78:
79:
80: # else
81: int res;
82: if (raw) {
83:
84: res = system("stty -echo raw");
85: }
86: else {
87:
88: res = system("stty echo -raw");
89: }
90:
91: if (res != 0) {
92:
93: }
94: # endif
95: }
96:
97:
98:
99:
100: char getConsoleChar()
101: {
102: # ifdef _WIN32
103:
104: return (char)getch();
105:
106: # else
107:
108: int ch = getchar();
109: if (ch == EOF) {
110: fail("getchar", "getConsoleChar");
111: }
112: return ch;
113: # endif
114: }
115:
116:
117:
118:
119: long getMilliseconds()
120: {
121: # ifdef _WIN32
122:
123: return GetTickCount();
124:
125: # else
126:
127:
128:
129: struct timeval tv;
130: gettimeofday(&tv, NULL);
131:
132:
133:
134:
135:
136: return tv.tv_sec * 1000 + tv.tv_usec / 1000;
137: # endif
138: }
139:
140:
141: bool limitFileAccess(char const *fname)
142: {
143:
144: if (chmod(fname, 0600) != 0) {
145: fail("chmod", fname);
146: return false;
147: }
148: else {
149: return true;
150: }
151: }
152:
153:
154: bool createDirectory(char const *dirname)
155: {
156: int res;
157: # ifdef _WIN32
158:
159: res = mkdir(dirname);
160: # else
161:
162: res = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR);
163: # endif
164:
165: if (res != 0) {
166: fail("mkdir", dirname);
167: return false;
168: }
169: else {
170: return true;
171: }
172: }
173:
174:
175: bool changeDirectory(char const *dirname)
176: {
177: if (0!=chdir(dirname)) {
178: fail("chdir", dirname);
179: return false;
180: }
181: else {
182: return true;
183: }
184: }
185:
186:
187: bool getCurrentDirectory(char *dirname, int len)
188: {
189: bool ok = getcwd(dirname, len) != NULL;
190: if (!ok) {
191: fail("getcwd");
192: }
193: return ok;
194: }
195:
196:
197: bool removeFile(char const *fname)
198: {
199: bool ok = unlink(fname) == 0;
200: if (!ok) {
201: fail("unlink", fname);
202: }
203: return ok;
204: }
205:
206:
207:
208:
209:
210: void getCurrentDate(int &month, int &day, int &year)
211: {
212:
213:
214: #if !defined(__CYGWIN__)
215: tzset();
216: #endif
217:
218:
219: time_t unixTime;
220: time(&unixTime);
221:
222:
223: struct tm *t = localtime(&unixTime);
224:
225:
226: month = t->tm_mon + 1;
227: day = t->tm_mday;
228: year = t->tm_year + 1900;
229: }
230:
231:
232: void portableSleep(unsigned seconds)
233: {
234:
235: sleep(seconds);
236: }
237:
238:
239: /*
240: void getCurrentUsername(char *buf, int buflen)
241: {
242: #ifdef _WIN32
243: DWORD len = buflen;
244: if (!GetUserName(buf, &len)) {
245: fail("GetUserName");
246: std::strncpy(buf, "(unknown)", buflen);
247: }
248:
249: #else
250: #if 0
251: char temp[L_cuserid];
252: cuserid(temp);
253: #endif
254:
255: char const *temp;
256: struct passwd *pw = getpwuid(geteuid());
257: if (!pw) {
258: fail("getpwuid(geteuid())");
259: temp = "(unknown)";
260: }
261: else {
262: temp = pw->pw_name;
263: }
264:
265: std::strncpy(buf, temp, buflen);
266: #endif
267: }
268: */
269:
270:
271: static void nonechoLoop(char *buf, int len)
272: {
273: int cursor = 0;
274: for(;;) {
275: char ch = getConsoleChar();
276: switch (ch) {
277: case '\r':
278: buf[cursor] = 0;
279: return;
280:
281: case '\b':
282: if (cursor > 0) {
283: cursor--;
284: }
285: break;
286:
287: default:
288: buf[cursor++] = ch;
289: if (cursor >= len-1) {
290:
291: buf[len-1] = 0;
292: return;
293: }
294: break;
295: }
296: }
297: }
298:
299:
300: void readNonechoString(char *buf, int len, char const *prompt)
301: {
302: std::cout << prompt;
303: std::cout.flush();
304:
305: setRawMode(true);
306:
307: try {
308: nonechoLoop(buf, len);
309: }
310: catch (...) {
311: setRawMode(false);
312: throw;
313: }
314:
315: setRawMode(false);
316:
317: std::cout << "\n";
318: std::cout.flush();
319: }
320:
321:
322: void applyToCwdContents(PerFileFunc func, void *extra)
323: {
324: applyToDirContents(".", func, extra);
325: }
326:
327:
328: void applyToDirContents(char const *dirName,
329: PerFileFunc func, void *extra)
330: {
331:
332:
333:
334:
335:
336:
337: #if defined(_WIN32) && !defined(__BORLANDC__)
338: struct _finddata_t fb;
339: char* buf = new char[std::strlen(dirName)+5];
340: std::strcpy(buf, dirName);
341: if (buf[std::strlen(buf)-1] != '\\') strcat(buf, "\\");
342: strcat(buf, "*");
343: long handle = _findfirst(buf, &fb);
344: delete buf;
345: int done = (handle == -1);
346: if (handle == -1 && errno != ENOENT)
347: fail("_findfirst", dirName);
348: while (!done) {
349: if (!func(fb.name, extra)) {
350: break;
351: }
352: done = _findnext(handle, &fb);
353: }
354: if (handle != -1) {
355: if (_findclose(handle)) fail("_findclose", dirName);
356: }
357:
358: #else
359: DIR *dir = opendir(dirName);
360: if (!dir) {
361: fail("opendir", dirName);
362: return;
363: }
364:
365: for(;;) {
366:
367: struct dirent *ent = readdir(dir);
368: if (!ent) {
369: break;
370: }
371:
372: if (!func(ent->d_name, extra)) {
373: break;
374: }
375: }
376:
377: if (closedir(dir) != 0) {
378: fail("closedir", dirName);
379: }
380: #endif
381: }
382:
383:
384: bool isDirectory(char const *path)
385: {
386: struct stat st;
387: if (0!=stat(path, &st)) {
388: fail("stat", path);
389: return false;
390: }
391: #if defined(_WIN32) && !defined(__BORLANDC__)
392: return !!(st.st_mode & _S_IFDIR);
393: #else
394: return S_ISDIR(st.st_mode);
395: #endif
396: }
397:
398:
399: bool fileOrDirectoryExists(char const *path)
400: {
401: struct stat st;
402: if (0!=stat(path, &st)) {
403: return false;
404: }
405: else {
406: return true;
407: }
408: }
409:
410:
411:
412:
413: bool ensurePath(char const *filename, bool isDirectory)
414: {
415:
416: int len = std::strlen(filename);
417: char *temp = new char[len+1];
418: std::strcpy(temp, filename);
419:
420: if (isDirectory) {
421: len++;
422: }
423:
424:
425:
426: for (int i=1; i < len; i++) {
427: if (strchr(DIRSLASHES, temp[i])) {
428:
429: temp[i] = '\0';
430: if (!fileOrDirectoryExists(temp)) {
431:
432: if (!createDirectory(temp)) {
433: delete[] temp;
434: return false;
435: }
436: }
437: temp[i] = DIRSLASH;
438: }
439: }
440:
441:
442: delete[] temp;
443: return true;
444: }
445:
446:
447:
448: bool hsrcHelper()
449: {
450: /*
451: #ifdef __UNIX__
452:
453: int fd = open("/dev/random", O_RDONLY);
454: if (fd < 0) {
455: return false;
456: }
457:
458:
459: if (close(fd) < 0) {
460: perror("close");
461: return false;
462: }
463:
464: return true;
465:
466: #else
467: return false;
468: #endif
469: */
470: return false;
471: }
472:
473: bool hasSystemCryptoRandom()
474: {
475: static bool cached = false;
476: static bool cachedAnswer;
477:
478: if (!cached) {
479: cachedAnswer = hsrcHelper();
480: cached = true;
481: }
482:
483: return cachedAnswer;
484: }
485:
486:
487:
488:
489:
490:
491:
492:
493: unsigned getSystemCryptoRandom()
494: {
495: /*
496: #ifdef __UNIX__
497:
498: int fd = open("/dev/random", O_RDONLY);
499: if (!fd) {
500: perror("open");
501: exit(2);
502: }
503:
504:
505: union {
506: unsigned ret;
507: char c[4];
508: };
509: int got = 0;
510:
511: while (got < 4) {
512: int ct = read(fd, c+got, 4-got);
513: if (ct < 0) {
514: perror("read");
515: exit(2);
516: }
517: if (ct == 0) {
518: fprintf(stderr, "got 0 bytes from /dev/random.. it's supposed to block!!\n");
519: exit(2);
520: }
521: got += ct;
522: }
523:
524: if (close(fd) < 0) {
525: perror("close");
526: exit(2);
527: }
528:
529: return ret;
530:
531: #else
532: fprintf(stderr, "no system crypto random function available!\n");
533: exit(2);
534: return 0;
535: #endif
536: */
537: fprintf(stderr, "no system crypto random function available!\n");
538: exit(2);
539: return 0;
540:
541: }
542:
543:
544:
545: int getProcessId()
546: {
547: #ifdef __UNIX__
548: return getpid();
549:
550: #else
551: return GetCurrentProcessId();
552:
553: #endif
554: }
555:
556:
557:
558:
559:
560:
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572:
573: static int counting_output_function(void *extra, int ch)
574: {
575:
576: int *ct = (int*)extra;
577: (*ct)++;
578: return 0;
579: }
580:
581:
582: int vnprintf(char const *format, va_list args)
583: {
584: #ifdef HAS_C99_VSNPRINTF
585:
586: return vsnprintf(NULL, 0, format, args);
587:
588: #else
589:
590: int count = 0;
591: general_vprintf(counting_output_function, &count, format, args);
592: return count;
593: #endif
594: }
595:
596:
597: int nprintf(char const *format, ...)
598: {
599: va_list args;
600: va_start(args, format);
601: int ret = vnprintf(format, args);
602: va_end(args);
603: return ret;
604: }
605:
606:
607:
608:
609:
610:
611:
612:
613:
614: bool printFirst10(char const *name, void *extra)
615: {
616: int &count = *((int*)extra);
617: count++;
618: if (count <= 10) {
619: printf(" %s\n", name);
620: return true;
621: }
622: else {
623: return false;
624: }
625: }
626:
627:
628: bool printIt(char const *name, void*)
629: {
630: printf("%s\n", name);
631: return true;
632: }
633:
634:
635: void testingFail(char const *call, char const *ctx)
636: {
637: printf("FAIL: call=%s, ctx=%s, errno=%d\n",
638: call, (ctx? ctx : "(null)"), errno);
639: }
640:
641:
642: void nprintfVector(char const *format, ...)
643: {
644: va_list args;
645:
646:
647: va_start(args, format);
648: int est = vnprintf(format, args);
649: va_end(args);
650:
651:
652: char *buf = new char[est+1 + 50 /*safety margin*/];
653:
654:
655: va_start(args, format);
656: int len = vsprintf(buf, format, args);
657: va_end(args);
658:
659: if (len > est) {
660: printf("nprintf failed to conservatively estimate!\n");
661: printf(" format: %s\n", format);
662: printf(" estimate: %d\n", est);
663: printf(" actual: %d\n", len);
664: exit(2);
665: }
666:
667: if (len != est) {
668:
669:
670:
671: printf("nprintf overestimate:\n");
672: printf(" format: %s\n", format);
673: printf(" estimate: %d\n", est);
674: printf(" actual: %d\n", len);
675: }
676:
677: delete[] buf;
678: }
679:
680:
681: int main(int argc, char **argv)
682: {
683: nonportFail = testingFail;
684:
685: char s[4];
686: s[0] = '-';
687: s[1] = 'l';
688: s[2] = 's';
689: s[3] = 0;
690: if (0!=std::strcmp(s, "-ls")) {
691: printf("std::strcmp failed!\n");
692: return 4;
693: }
694:
695:
696: bool interactive = false;
697: for (int i=1; i<argc; i++) {
698: if (0==std::strcmp("-ls", argv[i])) {
699:
700: applyToCwdContents(printIt);
701: return 0;
702: }
703: else if (0==std::strcmp("-noninteractive", argv[i])) {
704:
705: interactive = false;
706: }
707: else {
708: printf("unknown option: %s\n", argv[i]);
709: return 2;
710: }
711: }
712:
713:
714:
715:
716:
717:
718:
719:
720:
721:
722: long startTime = getMilliseconds();
723:
724: if (interactive) {
725: printf("Type some characters; you should see each\n"
726: "character echoed once as you type it (q to stop):\n");
727: setRawMode(true);
728: char ch;
729: do {
730: ch = getConsoleChar();
731: printf("%c", ch);
732: } while (ch != 'q');
733:
734: setRawMode(false);
735:
736: printf("\n\nYou typed for %ld milliseconds\n",
737: getMilliseconds() - startTime);
738: }
739:
740: limitFileAccess("chmod.test");
741:
742: printf("if the current dir contains a file called "
743: "chmod.test, I just attempted to limit\n"
744: "its access to just the owner\n");
745:
746: createDirectory("test.dir");
747:
748:
749: bool didFirst=false;
750: if (!changeDirectory("test.dir") || (didFirst=true, false) ||
751: !changeDirectory("..")) {
752: printf("failed while trying to chdir to %s\n",
753: (didFirst? ".." : "test.dir"));
754: }
755:
756:
757: if (!fileOrDirectoryExists("test.dir")) {
758: printf("test.dir didn't get created?\n");
759: }
760:
761: printf("what's more, I just tried to mkdir & chdir test.dir\n");
762:
763:
764: if (!ensurePath("test.dir/a/b/c/d", false /*isDirectory*/)) {
765: printf("ensurePath test.dir/a/b/c/d failed\n");
766: }
767:
768:
769: printf("listing of first 10 files in this directory:\n");
770: {
771: int count = 0;
772: applyToCwdContents(printFirst10, &count);
773: }
774:
775:
776: {
777: int m, d, y;
778: getCurrentDate(m, d, y);
779:
780: printf("I think the date is (m/d/yyyy): %d/%d/%d\n",
781: m, d, y);
782: }
783:
784:
785: printf("sleeping for 1 second...\n");
786: portableSleep(1);
787:
788: /*
789:
790: char buf[80];
791: getCurrentUsername(buf, 80);
792: printf("current user name is: %s\n", buf);
793: */
794:
795: if (interactive) {
796:
797: printf("Type something and press Enter; it won't be echoed (yet):\n");
798: readNonechoString(buf, 80, " > ");
799: printf("You typed: %s\n", buf);
800: }
801:
802:
803: printf("hasSystemCryptoRandom: ");
804: if (!hasSystemCryptoRandom()) {
805: printf("no\n");
806: }
807: else {
808: printf("yes\n");
809:
810: printf("three random numbers: %u %u %u\n",
811: getSystemCryptoRandom(),
812: getSystemCryptoRandom(),
813: getSystemCryptoRandom());
814: }
815:
816: printf("testing nprintf...\n");
817: nprintfVector("simple");
818: nprintfVector("a %s more", "little");
819: nprintfVector("some %4d more %s complicated %c stuff",
820: 33, "yikes", 'f');
821: nprintfVector("%f", 3.4);
822:
823: printf("nonport works\n");
824: return 0;
825: }
826:
827:
828:
829:
830:
831:
832: void limitFileAccess(char const *fname)
833: {
834:
835:
836: #ifndef S_IRGRP
837:
838: return;
839: #else
840:
841:
842:
843:
844:
845:
846: chmod(fname, S_IRUSR | S_IWUSR);
847: # endif
848: }
849:
850:
851:
852: struct ffblk fb;
853: int done = findfirst("*", &fb, 0);
854: while (!done) {
855: if (!func(fb.ff_name, extra)) {
856: break;
857: }
858: done = findnext(&fb);
859: }
860:
861: struct _finddata_t fb;
862: long handle = _findfirst("*", &fb);
863: int done = (handle == -1);
864: while (!done) {
865: if (!func(fb.name, extra)) {
866: break;
867: }
868: done = _findnext(handle, &fb);
869: }
870: if (handle != -1) _findclose(handle);
871:
872:
873:
874:
875:
876:
Start cpp section to elk/sm_str.cpp[1
/1
]
1: #line 17323 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26: char * const sm_string::empty = "";
27:
28:
29: sm_string::sm_string(char const *src, int length)
30: {
31: s=empty;
32: setlength(length);
33: std::memcpy(s, src, length);
34: }
35:
36:
37: void sm_string::dup(char const *src)
38: {
39: if (!src || src[0]==0) {
40: s = empty;
41: }
42: else {
43: s = new char[ std::strlen(src) + 1 ];
44: xassert(s);
45: std::strcpy(s, src);
46: }
47: }
48:
49: void sm_string::kill()
50: {
51: if (s != empty) {
52: delete s;
53: }
54: }
55:
56:
57: sm_string::sm_string(Flatten&)
58: : s(empty)
59: {}
60:
61: void sm_string::xfer(Flatten &flat)
62: {
63: flat.xferCharString(s);
64: }
65:
66:
67: int sm_string::length() const
68: {
69: xassert(s);
70: return std::strlen(s);
71: }
72:
73: bool sm_string::contains(char c) const
74: {
75: xassert(s);
76: return !!strchr(s, c);
77: }
78:
79:
80: sm_string sm_string::subsm_string(int startIndex, int len) const
81: {
82: xassert(startIndex >= 0 &&
83: len >= 0 &&
84: startIndex + len <= length());
85:
86: return sm_string(s+startIndex, len);
87: }
88:
89:
90: sm_string &sm_string::setlength(int length)
91: {
92: kill();
93: if (length > 0) {
94: s = new char[ length+1 ];
95: xassert(s);
96: s[length] = 0;
97: s[0] = 0;
98: }
99: else {
100: xassert(length == 0);
101: s = empty;
102: }
103: return *this;
104: }
105:
106:
107: int sm_string::compareTo(sm_string const &src) const
108: {
109: return compareTo(src.s);
110: }
111:
112: int sm_string::compareTo(char const *src) const
113: {
114: if (src == NULL) {
115: src = empty;
116: }
117: return std::strcmp(s, src);
118: }
119:
120:
121: sm_string sm_string::operator&(sm_string const &tail) const
122: {
123: sm_string dest(length() + tail.length());
124: std::strcpy(dest.s, s);
125: strcat(dest.s, tail.s);
126: return dest;
127: }
128:
129: sm_string& sm_string::operator&=(sm_string const &tail)
130: {
131: return *this = *this & tail;
132: }
133:
134:
135: void sm_string::readdelim(std::istream &is, char const *delim)
136: {
137: sm_stringBuilder sb;
138: sb.readdelim(is, delim);
139: operator= (sb);
140: }
141:
142:
143: void sm_string::write(std::ostream &os) const
144: {
145: os << s;
146: }
147:
148:
149: void sm_string::selfCheck() const
150: {
151: if (s != empty) {
152: checkHeapNode(s);
153: }
154: }
155:
156:
157:
158: sm_stringBuilder::sm_stringBuilder(int len)
159: {
160: init(len);
161: }
162:
163: void sm_stringBuilder::init(int initSize)
164: {
165: size = initSize + EXTRA_SPACE + 1;
166: s = new char[size];
167: end = s;
168: end[initSize] = 0;
169: }
170:
171:
172: void sm_stringBuilder::dup(char const *str)
173: {
174: int len = std::strlen(str);
175: init(len);
176: std::strcpy(s, str);
177: end += len;
178: }
179:
180:
181: sm_stringBuilder::sm_stringBuilder(char const *str)
182: {
183: dup(str);
184: }
185:
186:
187: sm_stringBuilder::sm_stringBuilder(char const *str, int len)
188: {
189: init(len);
190: std::memcpy(s, str, len);
191: end += len;
192: }
193:
194:
195: sm_stringBuilder& sm_stringBuilder::operator=(char const *src)
196: {
197: if (s != src) {
198: kill();
199: dup(src);
200: }
201: return *this;
202: }
203:
204:
205: sm_stringBuilder& sm_stringBuilder::setlength(int newlen)
206: {
207: kill();
208: init(newlen);
209: return *this;
210: }
211:
212:
213: void sm_stringBuilder::adjustend(char* newend)
214: {
215: xassert(s <= newend && newend < s + size);
216:
217: end = newend;
218: *end = 0;
219: }
220:
221:
222: sm_stringBuilder& sm_stringBuilder::operator&= (char const *tail)
223: {
224: append(tail, std::strlen(tail));
225: return *this;
226: }
227:
228: void sm_stringBuilder::append(char const *tail, int len)
229: {
230: ensure(length() + len);
231:
232: std::memcpy(end, tail, len);
233: end += len;
234: *end = 0;
235: }
236:
237:
238: sm_stringBuilder& sm_stringBuilder::indent(int amt)
239: {
240: xassert(amt >= 0);
241: ensure(length() + amt);
242:
243: std::memset(end, ' ', amt);
244: end += amt;
245: *end = 0;
246:
247: return *this;
248: }
249:
250:
251: void sm_stringBuilder::grow(int newMinLength)
252: {
253:
254: int newMinSize = newMinLength + EXTRA_SPACE + 1;
255:
256:
257: int suggest = size * 3 / 2;
258:
259:
260: newMinSize = max(newMinSize, suggest);
261:
262:
263: int len = length();
264:
265:
266: char *temp = new char[newMinSize];
267: xassert(len+1 <= newMinSize);
268: std::memcpy(temp, s, len+1);
269: delete[] s;
270: s = temp;
271:
272:
273: end = s + len;
274: size = newMinSize;
275: }
276:
277:
278: sm_stringBuilder& sm_stringBuilder::operator<< (char c)
279: {
280: ensure(length() + 1);
281: *(end++) = c;
282: *end = 0;
283: return *this;
284: }
285:
286:
287:
288: sm_stringBuilder& sm_stringBuilder::operator<< (Argtype arg) \
289: { \
290: char buf[60]; /* big enough for all types */ \
291: int len = sprintf(buf, fmt, arg); \
292: if (len >= 60) { \
293: abort(); /* too big */ \
294: } \
295: return *this << buf; \
296: }
297:
298: MAKE_LSHIFT(long, "%ld")
299: MAKE_LSHIFT(unsigned long, "%lu")
300: MAKE_LSHIFT(float, "%g")
301: MAKE_LSHIFT(double, "%g")
302: MAKE_LSHIFT(void*, "%p")
303:
304: MAKE_LSHIFT(unsigned long long, "%llu")
305: MAKE_LSHIFT(long long, "%ll")
306:
307:
308: MAKE_LSHIFT(long double, "%Lg")
309:
310:
311:
312:
313: sm_stringBuilder& sm_stringBuilder::operator<< (
314: sm_stringBuilder::Hex const &h)
315: {
316: char buf[32];
317: int len = sprintf(buf, "0x%lX", h.value);
318: if (len >= 20) {
319: abort();
320: }
321: return *this << buf;
322:
323:
324:
325:
326:
327: }
328:
329:
330: sm_stringBuilder& sm_stringBuilder::operator<< (Manipulator manip)
331: {
332: return manip(*this);
333: }
334:
335:
336:
337: void sm_stringBuilder::readdelim(std::istream &is, char const *delim)
338: {
339: char c;
340: is.get(c);
341: while (!is.eof() &&
342: (!delim || !strchr(delim, c))) {
343: *this << c;
344: is.get(c);
345: }
346: }
347:
348:
349:
350:
351: sm_string toString(type val) \
352: { \
353: return sm_stringc << val; \
354: }
355:
356: TOSTRING(int)
357: TOSTRING(unsigned)
358: TOSTRING(char)
359: TOSTRING(long)
360: TOSTRING(float)
361:
362:
363:
364:
365:
366: sm_string toString(char const *str)
367: {
368: if (!str) {
369: return sm_string("(null)");
370: }
371: else {
372: return sm_string(str);
373: }
374: }
375:
376:
377:
378: sm_string sm_stringf(char const *format, ...)
379: {
380: va_list args;
381: va_start(args, format);
382: sm_string ret = vsm_stringf(format, args);
383: va_end(args);
384: return ret;
385: }
386:
387:
388: sm_string vsm_stringf(char const *format, va_list args)
389: {
390:
391:
392:
393: va_list args2;
394: va_copy(args2, args);
395: int est = vnprintf(format, args2);
396: va_end(args2);
397:
398:
399: sm_string ret(est+1);
400:
401:
402: int len = vsprintf(ret.pchar(), format, args);
403:
404:
405:
406:
407: if (len > est) {
408:
409:
410: static char const msg[] =
411: "fatal error: vnprintf failed to provide a conservative estimate,\n"
412: "memory is most likely corrupted\n";
413: fprintf(stderr, msg);
414: abort();
415: }
416:
417:
418: return ret;
419: }
420:
421:
422:
423:
424:
425:
426:
427: void test(unsigned long val)
428: {
429:
430:
431: std::cout << sm_stringb(val << " in hex: " << SBHex(val)) << std::endl;
432: }
433:
434: int main()
435: {
436:
437: test(64);
438: test(0xFFFFFFFF);
439: test(0);
440: test((unsigned long)(-1));
441: test(1);
442:
443: std::cout << "sm_stringf: " << sm_stringf("int=%d hex=%X str=%s char=%c float=%f",
444: 5, 0xAA, "hi", 'f', 3.4) << std::endl;
445:
446: std::cout << "tests passed\n";
447:
448: return 0;
449: }
450:
451:
452:
Start cpp section to elk/sm_strtokp.cpp[1
/1
]
1: #line 17776 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11: StrtokParse::StrtokParse(char const *str, char const *delim)
12: {
13: xassert(str != NULL);
14:
15:
16: buf = str;
17:
18:
19: int ct=0;
20: char *tok = std::strtok(buf.pchar(), delim);
21: while (tok) {
22: ct++;
23: tok = std::strtok(NULL, delim);
24: }
25:
26:
27: buf = str;
28:
29:
30: _tokc = ct;
31: if (ct) {
32: _tokv = new char*[ct+1];
33: _tokv[ct] = NULL;
34: }
35: else {
36: _tokv = NULL;
37: }
38:
39:
40: ct=0;
41: tok = std::strtok(buf.pchar(), delim);
42: while (tok) {
43: _tokv[ct] = tok;
44: ct++;
45: tok = std::strtok(NULL, delim);
46: }
47:
48:
49: xassert(ct == _tokc);
50: }
51:
52:
53: StrtokParse::~StrtokParse()
54: {
55:
56:
57: if (_tokv) {
58: delete _tokv;
59: }
60: }
61:
62:
63: void StrtokParse::validate(int which) const
64: {
65: xassert((unsigned)which < (unsigned)_tokc);
66: }
67:
68:
69: char const *StrtokParse::tokv(int which) const
70: {
71: validate(which);
72: return _tokv[which];
73: }
74:
75:
76: sm_string StrtokParse::
77: reassemble(int firstTok, int lastTok, char const *original) const
78: {
79: int left = offset(firstTok);
80: int right = offset(lastTok) + std::strlen(tokv(lastTok));
81:
82: return sm_string(original + left, right-left);
83: }
84:
85:
86: sm_string StrtokParse::
87: join(int firstTok, int lastTok, char const *separator) const
88: {
89: sm_stringBuilder sb;
90:
91: for (int i=firstTok; i<=lastTok; i++) {
92: if (i > firstTok) {
93: sb << separator;
94: }
95: sb << tokv(i);
96: }
97:
98: return sb;
99: }
100:
101:
102: int StrtokParse::offset(int which) const
103: {
104: return tokv(which) - (char const*)buf;
105: }
Start cpp section to elk/sm_syserr.cpp[1
/1
]
1: #line 17882 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9: char const * const xSysError::reasonStrings[] = {
10: "No error occurred",
11: "File not found",
12: "Path not found",
13: "Access denied",
14: "Out of memory (maybe)",
15: "Invalid pointer address",
16: "Invalid data format",
17: "Invalid argument",
18: "Attempt to modify read-only data",
19: "The object already exists",
20: "Resource is temporarily unavailable",
21: "Resource is busy",
22: "File name is invalid (too long, or bad chars, or ...)",
23: "Unknown or unrecognized error",
24: "(bug -- invalid reason code)"
25: };
26:
27:
28: STATICDEF char const *xSysError::
29: getReasonString(xSysError::Reason r)
30: {
31:
32:
33:
34: #ifdef __BORLANDC__
35: #if TABLESIZE(reasonStrings) != NUM_REASONS+1
36: #error table and enumeration do not match
37: #endif
38: #endif
39:
40: if ((unsigned)r < NUM_REASONS) {
41: return reasonStrings[r];
42: }
43: else {
44: return reasonStrings[NUM_REASONS];
45: }
46: }
47:
48:
49: xSysError::xSysError(xSysError::Reason r, int sysCode, char const *sysReason,
50: char const *syscall, char const *ctx)
51: : xBase(constructWhyString(r, sysReason, syscall, ctx)),
52: reason(r),
53: reasonString(getReasonString(r)),
54: sysErrorCode(sysCode),
55: sysReasonString(sysReason),
56: syscallName(syscall),
57: context(ctx)
58: {}
59:
60:
61: STATICDEF sm_string xSysError::
62: constructWhyString(xSysError::Reason r, char const *sysReason,
63: char const *syscall, char const *ctx)
64: {
65: xassert(syscall);
66:
67:
68: sm_stringBuilder sb;
69: sb << syscall << ": ";
70:
71:
72: if (r != R_UNKNOWN) {
73: sb << getReasonString(r);
74: }
75: else if ((sysReason != NULL) && (sysReason[0] != 0)) {
76: sb << sysReason;
77: }
78: else {
79:
80: sb << getReasonString(r);
81: }
82:
83:
84: if (ctx != NULL) {
85: sb << ", " << ctx;
86: }
87:
88: return sb;
89: }
90:
91:
92: xSysError::xSysError(xSysError const &obj)
93: : xBase(obj),
94: reason(obj.reason),
95: reasonString(obj.reasonString),
96: sysErrorCode(obj.sysErrorCode),
97: sysReasonString(obj.sysReasonString),
98: syscallName(obj.syscallName),
99: context(obj.context)
100: {}
101:
102:
103: xSysError::~xSysError()
104: {}
105:
106:
107: STATICDEF void xSysError::
108: xsyserror(char const *syscallName, char const *context)
109: {
110:
111: int code = getSystemErrorCode();
112:
113:
114: sm_string sysMsg;
115: Reason r = portablize(code, sysMsg);
116:
117:
118: xSysError obj(r, code, sysMsg, syscallName, context);
119:
120:
121: THROW(obj);
122: }
123:
124:
125: sm_string sysErrorCodeString(int systemErrorCode, char const *syscallName,
126: char const *context)
127: {
128: sm_string sysMsg;
129: xSysError::Reason r = xSysError::portablize(systemErrorCode, sysMsg);
130: return xSysError::constructWhyString(
131: r, sysMsg,
132: syscallName, context);
133: }
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146: STATICDEF int xSysError::getSystemErrorCode()
147: {
148: int ret = GetLastError();
149:
150:
151:
152:
153:
154:
155:
156:
157:
158: #ifdef MT
159: # error something is fishy with multithreaded..
160: #endif
161:
162:
163:
164: #if 0
165: if (ret == ERROR_SUCCESS) {
166:
167:
168:
169:
170: return errno;
171: }
172: #endif
173:
174: return ret;
175: }
176:
177:
178: STATICDEF xSysError::Reason xSysError::portablize(int sysErrorCode, sm_string &sysMsg)
179: {
180:
181:
182:
183:
184:
185:
186: sysMsg = NULL;
187:
188:
189: static struct S {
190: int code;
191: Reason reason;
192: } const arr[] = {
193: { ERROR_SUCCESS, R_NO_ERROR },
194: { ERROR_FILE_NOT_FOUND, R_FILE_NOT_FOUND },
195: { ERROR_PATH_NOT_FOUND, R_PATH_NOT_FOUND },
196: { ERROR_ACCESS_DENIED, R_ACCESS_DENIED },
197: { ERROR_NOT_ENOUGH_MEMORY, R_OUT_OF_MEMORY },
198: { ERROR_OUTOFMEMORY, R_OUT_OF_MEMORY },
199: { ERROR_INVALID_BLOCK, R_SEGFAULT },
200: { ERROR_BAD_FORMAT, R_FORMAT },
201: { ERROR_INVALID_DATA, R_INVALID_ARGUMENT },
202: { ERROR_WRITE_PROTECT, R_READ_ONLY },
203: { ERROR_ALREADY_EXISTS, R_ALREADY_EXISTS },
204:
205: { ERROR_BUSY, R_BUSY },
206: };
207:
208: loopi(TABLESIZE(arr)) {
209: if (arr[i].code == sysErrorCode) {
210:
211: return arr[i].reason;
212: }
213: }
214:
215:
216: return R_UNKNOWN;
217: }
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246: STATICDEF int xSysError::getSystemErrorCode()
247: {
248: return errno;
249: }
250:
251:
252: STATICDEF xSysError::Reason xSysError::portablize(int sysErrorCode, sm_string &sysMsg)
253: {
254: sysMsg = std::strerror(sysErrorCode);
255:
256:
257: static struct S {
258: int code;
259: Reason reason;
260: } const arr[] = {
261: { EZERO, R_NO_ERROR },
262: { ENOFILE, R_FILE_NOT_FOUND },
263: { ENOPATH, R_PATH_NOT_FOUND },
264: { EACCES, R_ACCESS_DENIED },
265: { ENOMEM, R_OUT_OF_MEMORY },
266: { EINVMEM, R_SEGFAULT },
267: { EINVFMT, R_FORMAT },
268: { EINVAL, R_INVALID_ARGUMENT },
269: { EROFS, R_READ_ONLY },
270: { EEXIST, R_ALREADY_EXISTS },
271: { EAGAIN, R_AGAIN },
272: { EBUSY, R_BUSY },
273: { ENAMETOOLONG, R_INVALID_FILENAME },
274: };
275:
276: loopi(TABLESIZE(arr)) {
277: if (arr[i].code == sysErrorCode) {
278:
279: return arr[i].reason;
280: }
281: }
282:
283:
284: return R_UNKNOWN;
285: }
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299: try { \
300: if (failingCall) { \
301: std::cout << "ERROR: " #failingCall " should have failed\n"; \
302: } \
303: else { \
304: /* got an error to test */ \
305: xsyserror(#failingCall); \
306: } \
307: } \
308: catch (xSysError &x) { \
309: if (x.reason != xSysError::expectedCode) { \
310: std::cout << "ERROR: " #failingCall " returned '" \
311: << x.reasonString << "' but '" \
312: << xSysError::getReasonString(xSysError::expectedCode) \
313: << "' was expected\n"; \
314: errors++; \
315: } \
316: }
317:
318: void entry()
319: {
320: int errors = 0;
321: xBase::logExceptions = false;
322:
323:
324:
325:
326:
327: TRY_FAIL(changeDirectory("some.strange.name/yadda"),
328: R_PATH_NOT_FOUND);
329:
330: TRY_FAIL(createDirectory("/tmp"),
331: R_ALREADY_EXISTS);
332:
333: TRY_FAIL(isDirectory("doesnt.exist"),
334: R_FILE_NOT_FOUND);
335:
336: if (errors == 0) {
337: std::cout << "success!\n";
338: }
339: else {
340: std::cout << errors << " error(s)\n";
341: }
342: }
343:
344: USUAL_MAIN
345:
346:
347:
Start cpp section to elk/sm_warn.cpp[1
/1
]
1: #line 18230 "./lpsrc/sm.pak"
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: WarningHandler warningHandler = defaultWarningHandler;
14:
15: WarnLevel logWarnLevel = (WarnLevel)(WARN_ALL - WARN_DEBUG);
16: WarnLevel displayWarnLevel = WARN_NONE;
17:
18: WarnLevel logWarnLevel = WARN_ALL;
19: WarnLevel displayWarnLevel = WARN_ALL;
20:
21:
22:
23: void warning(WarnLevel level, char const *message)
24: {
25: warningHandler(level, message);
26: }
27:
28:
29: void defaultWarningHandler(WarnLevel level, char const *message)
30: {
31: if (level & WARN_DEBUG) {
32:
33: breaker();
34: }
35:
36: if (level & logWarnLevel) {
37: defaultWarningLogger(level, message);
38: }
39:
40: if (level & logWarnLevel) {
41: defaultWarningPrinter(level, message);
42: }
43: }
44:
45:
46: void defaultWarningLogger(WarnLevel /*level*/, char const *message)
47: {
48: static FILE *logfile = NULL;
49: static bool failedToOpen = false;
50:
51: if (!logfile && !failedToOpen) {
52: logfile = fopen("warning.log", "a");
53: if (!logfile) {
54:
55: failedToOpen = true;
56: }
57: else {
58:
59: time_t t;
60: time(&t);
61: int len = fprintf(logfile, "\nLog started at %s", ctime(&t));
62:
63:
64:
65: while (len--) {
66: fprintf(logfile, "-");
67: }
68: fprintf(logfile, "\n");
69: }
70: }
71:
72: if (logfile) {
73:
74: fprintf(logfile, "warning: %s\n", message);
75: fflush(logfile);
76: }
77: }
78:
79:
80: void defaultWarningPrinter(WarnLevel /*level*/, char const *message)
81: {
82: fprintf(stderr, "warning: %s\n", message);
83: fflush(stderr);
84: }
85:
86:
87:
88:
89:
90: