~ubuntu-branches/ubuntu/oneiric/apparmor/oneiric-updates

« back to all changes in this revision

Viewing changes to deprecated/management/profile-editor/src/wxStyledTextCtrl/PropSet.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-08-10 18:12:34 UTC
  • mfrom: (1.1.19 upstream) (8.1.5 oneiric)
  • Revision ID: james.westby@ubuntu.com-20110810181234-0ph4qatrdx2xskzg
Tags: 2.7.0~beta1+bzr1774-1
* New upstream devel snapshot:
  - drop 0002-lp750381.patch, taken upstream.
  - drop 0004-lp754889.patch, taken upstream.
  - drop 0005-lp761217.patch, taken upstream.
  - drop 0100-manpage-typo.patch, taken upstream.
  - drop 0101-declarations.patch, solved differently upstream.
  - drop 0102-manpage-release-name.patch, taken upstream.
  - drop 0103-kfreebsd-compile.patch, taken upstream.
  - drop define-path-max.patch, taken upstream.
  - drop indep-build.patch, taken upstream.
  - debian/libapparmor1.manpages: add new function man pages.
* Merge with Ubuntu:
  - drop 0104-python-aa-status.patch, taken upstream.
  - drop 0105-lightdm.patch, taken upstream.
  - drop 0106-lp810270.patch, taken upstream.
  - drop 0107-lp767308.patch, taken upstream.
  - drop 0108-gnome-mimeinfo.patch, taken upstream.
  - drop 0109-add-profile-repo-info.patch, taken upstream.
* Add af_names-generation.patch to allow arbitrary socket.h file location.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// SciTE - Scintilla based Text Editor
2
 
/** @file PropSet.cxx
3
 
 ** A Java style properties file module.
4
 
 **/
5
 
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6
 
// The License.txt file describes the conditions under which this software may be distributed.
7
 
 
8
 
// Maintain a dictionary of properties
9
 
 
10
 
#include <stdlib.h>
11
 
#include <string.h>
12
 
#include <stdio.h>
13
 
 
14
 
#include "Platform.h"
15
 
 
16
 
#include "PropSet.h"
17
 
 
18
 
// The comparison and case changing functions here assume ASCII
19
 
// or extended ASCII such as the normal Windows code page.
20
 
 
21
 
static inline char MakeUpperCase(char ch) {
22
 
        if (ch < 'a' || ch > 'z')
23
 
                return ch;
24
 
        else
25
 
                return static_cast<char>(ch - 'a' + 'A');
26
 
}
27
 
 
28
 
static inline bool IsLetter(char ch) {
29
 
        return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
30
 
}
31
 
 
32
 
inline bool IsASpace(unsigned int ch) {
33
 
    return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
34
 
}
35
 
 
36
 
int CompareCaseInsensitive(const char *a, const char *b) {
37
 
        while (*a && *b) {
38
 
                if (*a != *b) {
39
 
                        char upperA = MakeUpperCase(*a);
40
 
                        char upperB = MakeUpperCase(*b);
41
 
                        if (upperA != upperB)
42
 
                                return upperA - upperB;
43
 
                }
44
 
                a++;
45
 
                b++;
46
 
        }
47
 
        // Either *a or *b is nul
48
 
        return *a - *b;
49
 
}
50
 
 
51
 
int CompareNCaseInsensitive(const char *a, const char *b, size_t len) {
52
 
        while (*a && *b && len) {
53
 
                if (*a != *b) {
54
 
                        char upperA = MakeUpperCase(*a);
55
 
                        char upperB = MakeUpperCase(*b);
56
 
                        if (upperA != upperB)
57
 
                                return upperA - upperB;
58
 
                }
59
 
                a++;
60
 
                b++;
61
 
                len--;
62
 
        }
63
 
        if (len == 0)
64
 
                return 0;
65
 
        else
66
 
                // Either *a or *b is nul
67
 
                return *a - *b;
68
 
}
69
 
 
70
 
bool EqualCaseInsensitive(const char *a, const char *b) {
71
 
        return 0 == CompareCaseInsensitive(a, b);
72
 
}
73
 
 
74
 
// Since the CaseInsensitive functions declared in SString
75
 
// are implemented here, I will for now put the non-inline
76
 
// implementations of the SString members here as well, so
77
 
// that I can quickly see what effect this has.
78
 
 
79
 
SString::SString(int i) : sizeGrowth(sizeGrowthDefault) {
80
 
        char number[32];
81
 
        sprintf(number, "%0d", i);
82
 
        s = StringAllocate(number);
83
 
        sSize = sLen = (s) ? strlen(s) : 0;
84
 
}
85
 
 
86
 
SString::SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) {
87
 
        char number[32];
88
 
        sprintf(number, "%.*f", precision, d);
89
 
        s = StringAllocate(number);
90
 
        sSize = sLen = (s) ? strlen(s) : 0;
91
 
}
92
 
 
93
 
bool SString::grow(lenpos_t lenNew) {
94
 
        while (sizeGrowth * 6 < lenNew) {
95
 
                sizeGrowth *= 2;
96
 
        }
97
 
        char *sNew = new char[lenNew + sizeGrowth + 1];
98
 
        if (sNew) {
99
 
                if (s) {
100
 
                        memcpy(sNew, s, sLen);
101
 
                        delete []s;
102
 
                }
103
 
                s = sNew;
104
 
                s[sLen] = '\0';
105
 
                sSize = lenNew + sizeGrowth;
106
 
        }
107
 
        return sNew != 0;
108
 
}
109
 
 
110
 
SString &SString::assign(const char *sOther, lenpos_t sSize_) {
111
 
        if (!sOther) {
112
 
                sSize_ = 0;
113
 
        } else if (sSize_ == measure_length) {
114
 
                sSize_ = strlen(sOther);
115
 
        }
116
 
        if (sSize > 0 && sSize_ <= sSize) {     // Does not allocate new buffer if the current is big enough
117
 
                if (s && sSize_) {
118
 
                        memcpy(s, sOther, sSize_);
119
 
                }
120
 
                s[sSize_] = '\0';
121
 
                sLen = sSize_;
122
 
        } else {
123
 
                delete []s;
124
 
                s = StringAllocate(sOther, sSize_);
125
 
                if (s) {
126
 
                        sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow
127
 
                        sLen = sSize_;
128
 
                } else {
129
 
                        sSize = sLen = 0;
130
 
                }
131
 
        }
132
 
        return *this;
133
 
}
134
 
 
135
 
bool SString::operator==(const SString &sOther) const {
136
 
        if ((s == 0) && (sOther.s == 0))
137
 
                return true;
138
 
        if ((s == 0) || (sOther.s == 0))
139
 
                return false;
140
 
        return strcmp(s, sOther.s) == 0;
141
 
}
142
 
 
143
 
bool SString::operator==(const char *sOther) const {
144
 
        if ((s == 0) && (sOther == 0))
145
 
                return true;
146
 
        if ((s == 0) || (sOther == 0))
147
 
                return false;
148
 
        return strcmp(s, sOther) == 0;
149
 
}
150
 
 
151
 
SString SString::substr(lenpos_t subPos, lenpos_t subLen) const {
152
 
        if (subPos >= sLen) {
153
 
                return SString();                                       // return a null string if start index is out of bounds
154
 
        }
155
 
        if ((subLen == measure_length) || (subPos + subLen > sLen)) {
156
 
                subLen = sLen - subPos;         // can't substr past end of source string
157
 
        }
158
 
        return SString(s, subPos, subPos + subLen);
159
 
}
160
 
 
161
 
SString &SString::lowercase(lenpos_t subPos, lenpos_t subLen) {
162
 
        if ((subLen == measure_length) || (subPos + subLen > sLen)) {
163
 
                subLen = sLen - subPos;         // don't apply past end of string
164
 
        }
165
 
        for (lenpos_t i = subPos; i < subPos + subLen; i++) {
166
 
                if (s[i] < 'A' || s[i] > 'Z')
167
 
                        continue;
168
 
                else
169
 
                        s[i] = static_cast<char>(s[i] - 'A' + 'a');
170
 
        }
171
 
        return *this;
172
 
}
173
 
 
174
 
SString &SString::uppercase(lenpos_t subPos, lenpos_t subLen) {
175
 
        if ((subLen == measure_length) || (subPos + subLen > sLen)) {
176
 
                subLen = sLen - subPos;         // don't apply past end of string
177
 
        }
178
 
        for (lenpos_t i = subPos; i < subPos + subLen; i++) {
179
 
                if (s[i] < 'a' || s[i] > 'z')
180
 
                        continue;
181
 
                else
182
 
                        s[i] = static_cast<char>(s[i] - 'a' + 'A');
183
 
        }
184
 
        return *this;
185
 
}
186
 
 
187
 
SString &SString::append(const char *sOther, lenpos_t sLenOther, char sep) {
188
 
        if (!sOther) {
189
 
                return *this;
190
 
        }
191
 
        if (sLenOther == measure_length) {
192
 
                sLenOther = strlen(sOther);
193
 
        }
194
 
        int lenSep = 0;
195
 
        if (sLen && sep) {      // Only add a separator if not empty
196
 
                lenSep = 1;
197
 
        }
198
 
        lenpos_t lenNew = sLen + sLenOther + lenSep;
199
 
        // Conservative about growing the buffer: don't do it, unless really needed
200
 
        if ((lenNew < sSize) || (grow(lenNew))) {
201
 
                if (lenSep) {
202
 
                        s[sLen] = sep;
203
 
                        sLen++;
204
 
                }
205
 
                memcpy(&s[sLen], sOther, sLenOther);
206
 
                sLen += sLenOther;
207
 
                s[sLen] = '\0';
208
 
        }
209
 
        return *this;
210
 
}
211
 
 
212
 
SString &SString::insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther) {
213
 
        if (!sOther || pos > sLen) {
214
 
                return *this;
215
 
        }
216
 
        if (sLenOther == measure_length) {
217
 
                sLenOther = strlen(sOther);
218
 
        }
219
 
        lenpos_t lenNew = sLen + sLenOther;
220
 
        // Conservative about growing the buffer: don't do it, unless really needed
221
 
        if ((lenNew < sSize) || grow(lenNew)) {
222
 
                lenpos_t moveChars = sLen - pos + 1;
223
 
                for (lenpos_t i = moveChars; i > 0; i--) {
224
 
                        s[pos + sLenOther + i - 1] = s[pos + i - 1];
225
 
                }
226
 
                memcpy(s + pos, sOther, sLenOther);
227
 
                sLen = lenNew;
228
 
        }
229
 
        return *this;
230
 
}
231
 
 
232
 
/**
233
 
 * Remove @a len characters from the @a pos position, included.
234
 
 * Characters at pos + len and beyond replace characters at pos.
235
 
 * If @a len is 0, or greater than the length of the string
236
 
 * starting at @a pos, the string is just truncated at @a pos.
237
 
 */
238
 
void SString::remove(lenpos_t pos, lenpos_t len) {
239
 
        if (pos >= sLen) {
240
 
                return;
241
 
        }
242
 
        if (len < 1 || pos + len >= sLen) {
243
 
                s[pos] = '\0';
244
 
                sLen = pos;
245
 
        } else {
246
 
                for (lenpos_t i = pos; i < sLen - len + 1; i++) {
247
 
                        s[i] = s[i+len];
248
 
                }
249
 
                sLen -= len;
250
 
        }
251
 
}
252
 
 
253
 
bool SString::startswith(const char *prefix) {
254
 
        lenpos_t lenPrefix = strlen(prefix);
255
 
        if (lenPrefix > sLen) {
256
 
                return false;
257
 
        }
258
 
        return strncmp(s, prefix, lenPrefix) == 0;
259
 
}
260
 
 
261
 
bool SString::endswith(const char *suffix) {
262
 
        lenpos_t lenSuffix = strlen(suffix);
263
 
        if (lenSuffix > sLen) {
264
 
                return false;
265
 
        }
266
 
        return strncmp(s + sLen - lenSuffix, suffix, lenSuffix) == 0;
267
 
}
268
 
 
269
 
int SString::search(const char *sFind, lenpos_t start) const {
270
 
        if (start < sLen) {
271
 
                const char *sFound = strstr(s + start, sFind);
272
 
                if (sFound) {
273
 
                        return sFound - s;
274
 
                }
275
 
        }
276
 
        return -1;
277
 
}
278
 
 
279
 
int SString::substitute(char chFind, char chReplace) {
280
 
        int c = 0;
281
 
        char *t = s;
282
 
        while (t) {
283
 
                t = strchr(t, chFind);
284
 
                if (t) {
285
 
                        *t = chReplace;
286
 
                        t++;
287
 
                        c++;
288
 
                }
289
 
        }
290
 
        return c;
291
 
}
292
 
 
293
 
int SString::substitute(const char *sFind, const char *sReplace) {
294
 
        int c = 0;
295
 
        lenpos_t lenFind = strlen(sFind);
296
 
        lenpos_t lenReplace = strlen(sReplace);
297
 
        int posFound = search(sFind);
298
 
        while (posFound >= 0) {
299
 
                remove(posFound, lenFind);
300
 
                insert(posFound, sReplace, lenReplace);
301
 
                posFound = search(sFind, posFound + lenReplace);
302
 
                c++;
303
 
        }
304
 
        return c;
305
 
}
306
 
 
307
 
char *SContainer::StringAllocate(lenpos_t len) {
308
 
        if (len != measure_length) {
309
 
                return new char[len + 1];
310
 
        } else {
311
 
                return 0;
312
 
        }
313
 
}
314
 
 
315
 
char *SContainer::StringAllocate(const char *s, lenpos_t len) {
316
 
        if (s == 0) {
317
 
                return 0;
318
 
        }
319
 
        if (len == measure_length) {
320
 
                len = strlen(s);
321
 
        }
322
 
        char *sNew = new char[len + 1];
323
 
        if (sNew) {
324
 
                memcpy(sNew, s, len);
325
 
                sNew[len] = '\0';
326
 
        }
327
 
        return sNew;
328
 
}
329
 
 
330
 
// End SString functions
331
 
 
332
 
bool PropSet::caseSensitiveFilenames = false;
333
 
 
334
 
PropSet::PropSet() {
335
 
        superPS = 0;
336
 
        for (int root = 0; root < hashRoots; root++)
337
 
                props[root] = 0;
338
 
}
339
 
 
340
 
PropSet::~PropSet() {
341
 
        superPS = 0;
342
 
        Clear();
343
 
}
344
 
 
345
 
void PropSet::Set(const char *key, const char *val, int lenKey, int lenVal) {
346
 
        if (!*key)      // Empty keys are not supported
347
 
                return;
348
 
        if (lenKey == -1)
349
 
                lenKey = static_cast<int>(strlen(key));
350
 
        if (lenVal == -1)
351
 
                lenVal = static_cast<int>(strlen(val));
352
 
        unsigned int hash = HashString(key, lenKey);
353
 
        for (Property *p = props[hash % hashRoots]; p; p = p->next) {
354
 
                if ((hash == p->hash) &&
355
 
                        ((strlen(p->key) == static_cast<unsigned int>(lenKey)) &&
356
 
                                (0 == strncmp(p->key, key, lenKey)))) {
357
 
                        // Replace current value
358
 
                        delete [](p->val);
359
 
                        p->val = StringDup(val, lenVal);
360
 
                        return;
361
 
                }
362
 
        }
363
 
        // Not found
364
 
        Property *pNew = new Property;
365
 
        if (pNew) {
366
 
                pNew->hash = hash;
367
 
                pNew->key = StringDup(key, lenKey);
368
 
                pNew->val = StringDup(val, lenVal);
369
 
                pNew->next = props[hash % hashRoots];
370
 
                props[hash % hashRoots] = pNew;
371
 
        }
372
 
}
373
 
 
374
 
void PropSet::Set(const char *keyVal) {
375
 
        while (IsASpace(*keyVal))
376
 
                keyVal++;
377
 
        const char *endVal = keyVal;
378
 
        while (*endVal && (*endVal != '\n'))
379
 
                endVal++;
380
 
        const char *eqAt = strchr(keyVal, '=');
381
 
        if (eqAt) {
382
 
                Set(keyVal, eqAt + 1, eqAt-keyVal, endVal - eqAt - 1);
383
 
        } else if (*keyVal) {   // No '=' so assume '=1'
384
 
                Set(keyVal, "1", endVal-keyVal, 1);
385
 
        }
386
 
}
387
 
 
388
 
void PropSet::Unset(const char *key, int lenKey) {
389
 
        if (!*key)      // Empty keys are not supported
390
 
                return;
391
 
        if (lenKey == -1)
392
 
                lenKey = static_cast<int>(strlen(key));
393
 
        unsigned int hash = HashString(key, lenKey);
394
 
        Property *pPrev = NULL;
395
 
        for (Property *p = props[hash % hashRoots]; p; p = p->next) {
396
 
                if ((hash == p->hash) &&
397
 
                        ((strlen(p->key) == static_cast<unsigned int>(lenKey)) &&
398
 
                                (0 == strncmp(p->key, key, lenKey)))) {
399
 
                        if (pPrev)
400
 
                                pPrev->next = p->next;
401
 
                        else
402
 
                                props[hash % hashRoots] = p->next;
403
 
                        if (p == enumnext)
404
 
                                enumnext = p->next; // Not that anyone should mix enum and Set / Unset.
405
 
                        delete [](p->key);
406
 
                        delete [](p->val);
407
 
                        delete p;
408
 
                        return;
409
 
                } else {
410
 
                        pPrev = p;
411
 
                }
412
 
        }
413
 
}
414
 
 
415
 
void PropSet::SetMultiple(const char *s) {
416
 
        const char *eol = strchr(s, '\n');
417
 
        while (eol) {
418
 
                Set(s);
419
 
                s = eol + 1;
420
 
                eol = strchr(s, '\n');
421
 
        }
422
 
        Set(s);
423
 
}
424
 
 
425
 
SString PropSet::Get(const char *key) {
426
 
        unsigned int hash = HashString(key, strlen(key));
427
 
        for (Property *p = props[hash % hashRoots]; p; p = p->next) {
428
 
                if ((hash == p->hash) && (0 == strcmp(p->key, key))) {
429
 
                        return p->val;
430
 
                }
431
 
        }
432
 
        if (superPS) {
433
 
                // Failed here, so try in base property set
434
 
                return superPS->Get(key);
435
 
        } else {
436
 
                return "";
437
 
        }
438
 
}
439
 
 
440
 
bool PropSet::IncludesVar(const char *value, const char *key) {
441
 
        const char *var = strstr(value, "$(");
442
 
        while (var) {
443
 
                if (isprefix(var + 2, key) && (var[2 + strlen(key)] == ')')) {
444
 
                        // Found $(key) which would lead to an infinite loop so exit
445
 
                        return true;
446
 
                }
447
 
                var = strstr(var + 2, ")");
448
 
                if (var)
449
 
                        var = strstr(var + 1, "$(");
450
 
        }
451
 
        return false;
452
 
}
453
 
 
454
 
 
455
 
// There is some inconsistency between GetExpanded("foo") and Expand("$(foo)").
456
 
// A solution is to keep a stack of variables that have been expanded, so that
457
 
// recursive expansions can be skipped.  For now I'll just use the C++ stack
458
 
// for that, through a recursive function and a simple chain of pointers.
459
 
 
460
 
struct VarChain {
461
 
        VarChain(const char*var_=NULL, const VarChain *link_=NULL): var(var_), link(link_) {}
462
 
 
463
 
        bool contains(const char *testVar) const {
464
 
                return (var && (0 == strcmp(var, testVar)))
465
 
                        || (link && link->contains(testVar));
466
 
        }
467
 
 
468
 
        const char *var;
469
 
        const VarChain *link;
470
 
};
471
 
 
472
 
static int ExpandAllInPlace(PropSet &props, SString &withVars, int maxExpands, const VarChain &blankVars = VarChain()) {
473
 
        int varStart = withVars.search("$(");
474
 
        while ((varStart >= 0) && (maxExpands > 0)) {
475
 
                int varEnd = withVars.search(")", varStart+2);
476
 
                if (varEnd < 0) {
477
 
                        break;
478
 
                }
479
 
 
480
 
                // For consistency, when we see '$(ab$(cde))', expand the inner variable first,
481
 
                // regardless whether there is actually a degenerate variable named 'ab$(cde'.
482
 
                int innerVarStart = withVars.search("$(", varStart+2);
483
 
                while ((innerVarStart > varStart) && (innerVarStart < varEnd)) {
484
 
                        varStart = innerVarStart;
485
 
                        innerVarStart = withVars.search("$(", varStart+2);
486
 
                }
487
 
 
488
 
                SString var(withVars.c_str(), varStart + 2, varEnd);
489
 
                SString val = props.Get(var.c_str());
490
 
 
491
 
                if (blankVars.contains(var.c_str())) {
492
 
                        val.clear(); // treat blankVar as an empty string (e.g. to block self-reference)
493
 
                }
494
 
 
495
 
                if (--maxExpands >= 0) {
496
 
                        maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars));
497
 
                }
498
 
 
499
 
                withVars.remove(varStart, varEnd-varStart+1);
500
 
                withVars.insert(varStart, val.c_str(), val.length());
501
 
 
502
 
                varStart = withVars.search("$(");
503
 
        }
504
 
 
505
 
        return maxExpands;
506
 
}
507
 
 
508
 
 
509
 
SString PropSet::GetExpanded(const char *key) {
510
 
        SString val = Get(key);
511
 
        ExpandAllInPlace(*this, val, 100, VarChain(key));
512
 
        return val;
513
 
}
514
 
 
515
 
SString PropSet::Expand(const char *withVars, int maxExpands) {
516
 
        SString val = withVars;
517
 
        ExpandAllInPlace(*this, val, maxExpands);
518
 
        return val;
519
 
}
520
 
 
521
 
int PropSet::GetInt(const char *key, int defaultValue) {
522
 
        SString val = GetExpanded(key);
523
 
        if (val.length())
524
 
                return val.value();
525
 
        return defaultValue;
526
 
}
527
 
 
528
 
bool isprefix(const char *target, const char *prefix) {
529
 
        while (*target && *prefix) {
530
 
                if (*target != *prefix)
531
 
                        return false;
532
 
                target++;
533
 
                prefix++;
534
 
        }
535
 
        if (*prefix)
536
 
                return false;
537
 
        else
538
 
                return true;
539
 
}
540
 
 
541
 
static bool IsSuffix(const char *target, const char *suffix, bool caseSensitive) {
542
 
        size_t lentarget = strlen(target);
543
 
        size_t lensuffix = strlen(suffix);
544
 
        if (lensuffix > lentarget)
545
 
                return false;
546
 
        if (caseSensitive) {
547
 
                for (int i = static_cast<int>(lensuffix) - 1; i >= 0; i--) {
548
 
                        if (target[i + lentarget - lensuffix] != suffix[i])
549
 
                                return false;
550
 
                }
551
 
        } else {
552
 
        for (int i = static_cast<int>(lensuffix) - 1; i >= 0; i--) {
553
 
                if (MakeUpperCase(target[i + lentarget - lensuffix]) !=
554
 
                        MakeUpperCase(suffix[i]))
555
 
                        return false;
556
 
        }
557
 
        }
558
 
        return true;
559
 
}
560
 
 
561
 
SString PropSet::GetWild(const char *keybase, const char *filename) {
562
 
        for (int root = 0; root < hashRoots; root++) {
563
 
                for (Property *p = props[root]; p; p = p->next) {
564
 
                        if (isprefix(p->key, keybase)) {
565
 
                                char * orgkeyfile = p->key + strlen(keybase);
566
 
                                char *keyfile = NULL;
567
 
 
568
 
                                if (strstr(orgkeyfile, "$(") == orgkeyfile) {
569
 
                                        char *cpendvar = strchr(orgkeyfile, ')');
570
 
                                        if (cpendvar) {
571
 
                                                *cpendvar = '\0';
572
 
                                                SString s = GetExpanded(orgkeyfile + 2);
573
 
                                                *cpendvar = ')';
574
 
                                                keyfile = StringDup(s.c_str());
575
 
                                        }
576
 
                                }
577
 
                                char *keyptr = keyfile;
578
 
 
579
 
                                if (keyfile == NULL)
580
 
                                        keyfile = orgkeyfile;
581
 
 
582
 
                                for (;;) {
583
 
                                        char *del = strchr(keyfile, ';');
584
 
                                        if (del == NULL)
585
 
                                                del = keyfile + strlen(keyfile);
586
 
                                        char delchr = *del;
587
 
                                        *del = '\0';
588
 
                                        if (*keyfile == '*') {
589
 
                                                if (IsSuffix(filename, keyfile + 1, caseSensitiveFilenames)) {
590
 
                                                        *del = delchr;
591
 
                                                        delete []keyptr;
592
 
                                                        return p->val;
593
 
                                                }
594
 
                                        } else if (0 == strcmp(keyfile, filename)) {
595
 
                                                *del = delchr;
596
 
                                                delete []keyptr;
597
 
                                                return p->val;
598
 
                                        }
599
 
                                        if (delchr == '\0')
600
 
                                                break;
601
 
                                        *del = delchr;
602
 
                                        keyfile = del + 1;
603
 
                                }
604
 
                                delete []keyptr;
605
 
 
606
 
                                if (0 == strcmp(p->key, keybase)) {
607
 
                                        return p->val;
608
 
                                }
609
 
                        }
610
 
                }
611
 
        }
612
 
        if (superPS) {
613
 
                // Failed here, so try in base property set
614
 
                return superPS->GetWild(keybase, filename);
615
 
        } else {
616
 
                return "";
617
 
        }
618
 
}
619
 
 
620
 
 
621
 
 
622
 
// GetNewExpand does not use Expand as it has to use GetWild with the filename for each
623
 
// variable reference found.
624
 
SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
625
 
        char *base = StringDup(GetWild(keybase, filename).c_str());
626
 
        char *cpvar = strstr(base, "$(");
627
 
        int maxExpands = 1000;  // Avoid infinite expansion of recursive definitions
628
 
        while (cpvar && (maxExpands > 0)) {
629
 
                char *cpendvar = strchr(cpvar, ')');
630
 
                if (cpendvar) {
631
 
                        int lenvar = cpendvar - cpvar - 2;      // Subtract the $()
632
 
                        char *var = StringDup(cpvar + 2, lenvar);
633
 
                        SString val = GetWild(var, filename);
634
 
                        if (0 == strcmp(var, keybase))
635
 
                                val.clear(); // Self-references evaluate to empty string
636
 
                        size_t newlenbase = strlen(base) + val.length() - lenvar;
637
 
                        char *newbase = new char[newlenbase];
638
 
                        strncpy(newbase, base, cpvar - base);
639
 
                        strcpy(newbase + (cpvar - base), val.c_str());
640
 
                        strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
641
 
                        delete []var;
642
 
                        delete []base;
643
 
                        base = newbase;
644
 
                }
645
 
                cpvar = strstr(base, "$(");
646
 
                maxExpands--;
647
 
        }
648
 
        SString sret = base;
649
 
        delete []base;
650
 
        return sret;
651
 
}
652
 
 
653
 
void PropSet::Clear() {
654
 
        for (int root = 0; root < hashRoots; root++) {
655
 
                Property *p = props[root];
656
 
                while (p) {
657
 
                        Property *pNext = p->next;
658
 
                        p->hash = 0;
659
 
                        delete []p->key;
660
 
                        p->key = 0;
661
 
                        delete []p->val;
662
 
                        p->val = 0;
663
 
                        delete p;
664
 
                        p = pNext;
665
 
                }
666
 
                props[root] = 0;
667
 
        }
668
 
}
669
 
 
670
 
char *PropSet::ToString() {
671
 
        size_t len=0;
672
 
        for (int r = 0; r < hashRoots; r++) {
673
 
                for (Property *p = props[r]; p; p = p->next) {
674
 
                        len += strlen(p->key) + 1;
675
 
                        len += strlen(p->val) + 1;
676
 
                }
677
 
        }
678
 
        if (len == 0)
679
 
                len = 1;        // Return as empty string
680
 
        char *ret = new char [len];
681
 
        if (ret) {
682
 
                char *w = ret;
683
 
                for (int root = 0; root < hashRoots; root++) {
684
 
                        for (Property *p = props[root]; p; p = p->next) {
685
 
                                strcpy(w, p->key);
686
 
                                w += strlen(p->key);
687
 
                                *w++ = '=';
688
 
                                strcpy(w, p->val);
689
 
                                w += strlen(p->val);
690
 
                                *w++ = '\n';
691
 
                        }
692
 
                }
693
 
                ret[len-1] = '\0';
694
 
        }
695
 
        return ret;
696
 
}
697
 
 
698
 
/**
699
 
 * Initiate enumeration.
700
 
 */
701
 
bool PropSet::GetFirst(char **key, char **val) {
702
 
        for (int i = 0; i < hashRoots; i++) {
703
 
                for (Property *p = props[i]; p; p = p->next) {
704
 
                        if (p) {
705
 
                                *key = p->key;
706
 
                                *val = p->val;
707
 
                                enumnext = p->next; // GetNext will begin here ...
708
 
                                enumhash = i;             // ... in this block
709
 
                                return true;
710
 
                        }
711
 
                }
712
 
        }
713
 
        return false;
714
 
}
715
 
 
716
 
/**
717
 
 * Continue enumeration.
718
 
 */
719
 
bool PropSet::GetNext(char ** key, char ** val) {
720
 
        bool firstloop = true;
721
 
 
722
 
        // search begins where we left it : in enumhash block
723
 
        for (int i = enumhash; i < hashRoots; i++) {
724
 
                if (!firstloop)
725
 
                        enumnext = props[i]; // Begin with first property in block
726
 
                // else : begin where we left
727
 
                firstloop = false;
728
 
 
729
 
                for (Property *p = enumnext; p; p = p->next) {
730
 
                        if (p) {
731
 
                                *key = p->key;
732
 
                                *val = p->val;
733
 
                                enumnext = p->next; // for GetNext
734
 
                                enumhash = i;
735
 
                                return true;
736
 
                        }
737
 
                }
738
 
        }
739
 
        return false;
740
 
}
741
 
 
742
 
/**
743
 
 * Creates an array that points into each word in the string and puts \0 terminators
744
 
 * after each word.
745
 
 */
746
 
static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) {
747
 
        int prev = '\n';
748
 
        int words = 0;
749
 
        // For rapid determination of whether a character is a separator, build
750
 
        // a look up table.
751
 
        bool wordSeparator[256];
752
 
        for (int i=0;i<256; i++) {
753
 
                wordSeparator[i] = false;
754
 
        }
755
 
        wordSeparator['\r'] = true;
756
 
        wordSeparator['\n'] = true;
757
 
        if (!onlyLineEnds) {
758
 
                wordSeparator[' '] = true;
759
 
                wordSeparator['\t'] = true;
760
 
        }
761
 
        for (int j = 0; wordlist[j]; j++) {
762
 
                int curr = static_cast<unsigned char>(wordlist[j]);
763
 
                if (!wordSeparator[curr] && wordSeparator[prev])
764
 
                        words++;
765
 
                prev = curr;
766
 
        }
767
 
        char **keywords = new char *[words + 1];
768
 
        if (keywords) {
769
 
                words = 0;
770
 
                prev = '\0';
771
 
                size_t slen = strlen(wordlist);
772
 
                for (size_t k = 0; k < slen; k++) {
773
 
                        if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) {
774
 
                                if (!prev) {
775
 
                                        keywords[words] = &wordlist[k];
776
 
                                        words++;
777
 
                                }
778
 
                        } else {
779
 
                                wordlist[k] = '\0';
780
 
                        }
781
 
                        prev = wordlist[k];
782
 
                }
783
 
                keywords[words] = &wordlist[slen];
784
 
                *len = words;
785
 
        } else {
786
 
                *len = 0;
787
 
        }
788
 
        return keywords;
789
 
}
790
 
 
791
 
void WordList::Clear() {
792
 
        if (words) {
793
 
                delete []list;
794
 
                delete []words;
795
 
                delete []wordsNoCase;
796
 
        }
797
 
        words = 0;
798
 
        wordsNoCase = 0;
799
 
        list = 0;
800
 
        len = 0;
801
 
        sorted = false;
802
 
        sortedNoCase = false;
803
 
}
804
 
 
805
 
void WordList::Set(const char *s) {
806
 
        list = StringDup(s);
807
 
        sorted = false;
808
 
        sortedNoCase = false;
809
 
        words = ArrayFromWordList(list, &len, onlyLineEnds);
810
 
        wordsNoCase = new char * [len + 1];
811
 
        memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));
812
 
}
813
 
 
814
 
char *WordList::Allocate(int size) {
815
 
        list = new char[size + 1];
816
 
        list[size] = '\0';
817
 
        return list;
818
 
}
819
 
 
820
 
void WordList::SetFromAllocated() {
821
 
        sorted = false;
822
 
        sortedNoCase = false;
823
 
        words = ArrayFromWordList(list, &len, onlyLineEnds);
824
 
        wordsNoCase = new char * [len + 1];
825
 
        memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));
826
 
}
827
 
 
828
 
int cmpString(const void *a1, const void *a2) {
829
 
        // Can't work out the correct incantation to use modern casts here
830
 
        return strcmp(*(char**)(a1), *(char**)(a2));
831
 
}
832
 
 
833
 
int cmpStringNoCase(const void *a1, const void *a2) {
834
 
        // Can't work out the correct incantation to use modern casts here
835
 
        return CompareCaseInsensitive(*(char**)(a1), *(char**)(a2));
836
 
}
837
 
 
838
 
static void SortWordList(char **words, unsigned int len) {
839
 
        qsort(reinterpret_cast<void*>(words), len, sizeof(*words),
840
 
              cmpString);
841
 
}
842
 
 
843
 
static void SortWordListNoCase(char **wordsNoCase, unsigned int len) {
844
 
        qsort(reinterpret_cast<void*>(wordsNoCase), len, sizeof(*wordsNoCase),
845
 
              cmpStringNoCase);
846
 
}
847
 
 
848
 
bool WordList::InList(const char *s) {
849
 
        if (0 == words)
850
 
                return false;
851
 
        if (!sorted) {
852
 
                sorted = true;
853
 
                SortWordList(words, len);
854
 
                for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
855
 
                        starts[k] = -1;
856
 
                for (int l = len - 1; l >= 0; l--) {
857
 
                        unsigned char indexChar = words[l][0];
858
 
                        starts[indexChar] = l;
859
 
                }
860
 
        }
861
 
        unsigned char firstChar = s[0];
862
 
        int j = starts[firstChar];
863
 
        if (j >= 0) {
864
 
                while (words[j][0] == firstChar) {
865
 
                        if (s[1] == words[j][1]) {
866
 
                                const char *a = words[j] + 1;
867
 
                                const char *b = s + 1;
868
 
                                while (*a && *a == *b) {
869
 
                                        a++;
870
 
                                        b++;
871
 
                                }
872
 
                                if (!*a && !*b)
873
 
                                        return true;
874
 
                        }
875
 
                        j++;
876
 
                }
877
 
        }
878
 
        j = starts['^'];
879
 
        if (j >= 0) {
880
 
                while (words[j][0] == '^') {
881
 
                        const char *a = words[j] + 1;
882
 
                        const char *b = s;
883
 
                        while (*a && *a == *b) {
884
 
                                a++;
885
 
                                b++;
886
 
                        }
887
 
                        if (!*a)
888
 
                                return true;
889
 
                        j++;
890
 
                }
891
 
        }
892
 
        return false;
893
 
}
894
 
 
895
 
/** similar to InList, but word s can be a substring of keyword.
896
 
 * eg. the keyword define is defined as def~ine. This means the word must start
897
 
 * with def to be a keyword, but also defi, defin and define are valid.
898
 
 * The marker is ~ in this case.
899
 
 */
900
 
bool WordList::InListAbbreviated(const char *s, const char marker) {
901
 
        if (0 == words)
902
 
                return false;
903
 
        if (!sorted) {
904
 
                sorted = true;
905
 
                SortWordList(words, len);
906
 
                for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
907
 
                        starts[k] = -1;
908
 
                for (int l = len - 1; l >= 0; l--) {
909
 
                        unsigned char indexChar = words[l][0];
910
 
                        starts[indexChar] = l;
911
 
                }
912
 
        }
913
 
        unsigned char firstChar = s[0];
914
 
        int j = starts[firstChar];
915
 
        if (j >= 0) {
916
 
                while (words[j][0] == firstChar) {
917
 
                        bool isSubword = false;
918
 
                        int start = 1;
919
 
                        if (words[j][1] == marker) {
920
 
                                isSubword = true;
921
 
                                start++;
922
 
                        }
923
 
                        if (s[1] == words[j][start]) {
924
 
                                const char *a = words[j] + start;
925
 
                                const char *b = s + 1;
926
 
                                while (*a && *a == *b) {
927
 
                                        a++;
928
 
                                        if (*a == marker) {
929
 
                                                isSubword = true;
930
 
                                                a++;
931
 
                                        }
932
 
                                        b++;
933
 
                                }
934
 
                                if ((!*a || isSubword) && !*b)
935
 
                                        return true;
936
 
                        }
937
 
                        j++;
938
 
                }
939
 
        }
940
 
        j = starts['^'];
941
 
        if (j >= 0) {
942
 
                while (words[j][0] == '^') {
943
 
                        const char *a = words[j] + 1;
944
 
                        const char *b = s;
945
 
                        while (*a && *a == *b) {
946
 
                                a++;
947
 
                                b++;
948
 
                        }
949
 
                        if (!*a)
950
 
                                return true;
951
 
                        j++;
952
 
                }
953
 
        }
954
 
        return false;
955
 
}
956
 
 
957
 
/**
958
 
 * Returns an element (complete) of the wordlist array which has
959
 
 * the same beginning as the passed string.
960
 
 * The length of the word to compare is passed too.
961
 
 * Letter case can be ignored or preserved (default).
962
 
 */
963
 
const char *WordList::GetNearestWord(const char *wordStart, int searchLen, bool ignoreCase /*= false*/, SString wordCharacters /*='/0' */, int wordIndex /*= -1 */) {
964
 
        int start = 0; // lower bound of the api array block to search
965
 
        int end = len - 1; // upper bound of the api array block to search
966
 
        int pivot; // index of api array element just being compared
967
 
        int cond; // comparison result (in the sense of strcmp() result)
968
 
        const char *word; // api array element just being compared
969
 
 
970
 
        if (0 == words)
971
 
                return NULL;
972
 
        if (ignoreCase) {
973
 
                if (!sortedNoCase) {
974
 
                        sortedNoCase = true;
975
 
                        SortWordListNoCase(wordsNoCase, len);
976
 
                }
977
 
                while (start <= end) { // binary searching loop
978
 
                        pivot = (start + end) >> 1;
979
 
                        word = wordsNoCase[pivot];
980
 
                        cond = CompareNCaseInsensitive(wordStart, word, searchLen);
981
 
                        if (!cond) {
982
 
                                // find first word
983
 
                                start = pivot;
984
 
                                while (start > 0 && !CompareNCaseInsensitive(wordStart, wordsNoCase[start-1], searchLen)) {
985
 
                                        start--;
986
 
                                }
987
 
                                // find last word
988
 
                                end = pivot;
989
 
                                while (end < len-1 && !CompareNCaseInsensitive(wordStart, wordsNoCase[end+1], searchLen)) {
990
 
                                        end++;
991
 
                                }
992
 
 
993
 
                                // Finds first word in a series of equal words
994
 
                                for (pivot = start; pivot <= end; pivot++) {
995
 
                                        word = wordsNoCase[pivot];
996
 
                                        if (!wordCharacters.contains(word[searchLen])) {
997
 
                                                if (wordIndex <= 0) // Checks if a specific index was requested
998
 
                                                        return word; // result must not be freed with free()
999
 
                                                wordIndex--;
1000
 
                                        }
1001
 
                                }
1002
 
                                return NULL;
1003
 
                        }
1004
 
                        else if (cond > 0)
1005
 
                                start = pivot + 1;
1006
 
                        else if (cond < 0)
1007
 
                                end = pivot - 1;
1008
 
                }
1009
 
        } else { // preserve the letter case
1010
 
                if (!sorted) {
1011
 
                        sorted = true;
1012
 
                        SortWordList(words, len);
1013
 
                }
1014
 
                while (start <= end) { // binary searching loop
1015
 
                        pivot = (start + end) >> 1;
1016
 
                        word = words[pivot];
1017
 
                        cond = strncmp(wordStart, word, searchLen);
1018
 
                        if (!cond) {
1019
 
                                // find first word
1020
 
                                start = pivot;
1021
 
                                while (start > 0 && !strncmp(wordStart, words[start-1], searchLen)) {
1022
 
                                        start--;
1023
 
                                }
1024
 
                                // find last word
1025
 
                                end = pivot;
1026
 
                                while (end < len-1 && !strncmp(wordStart, words[end+1], searchLen)) {
1027
 
                                        end++;
1028
 
                                }
1029
 
 
1030
 
                                // Finds first word in a series of equal words
1031
 
                                pivot = start;
1032
 
                                while (pivot <= end) {
1033
 
                                        word = words[pivot];
1034
 
                                        if (!wordCharacters.contains(word[searchLen])) {
1035
 
                                                if (wordIndex <= 0) // Checks if a specific index was requested
1036
 
                                                        return word; // result must not be freed with free()
1037
 
                                                wordIndex--;
1038
 
                                        }
1039
 
                                        pivot++;
1040
 
                                }
1041
 
                                return NULL;
1042
 
                        }
1043
 
                        else if (cond > 0)
1044
 
                                start = pivot + 1;
1045
 
                        else if (cond < 0)
1046
 
                                end = pivot - 1;
1047
 
                }
1048
 
        }
1049
 
        return NULL;
1050
 
}
1051
 
 
1052
 
/**
1053
 
 * Find the length of a 'word' which is actually an identifier in a string
1054
 
 * which looks like "identifier(..." or "identifier" and where
1055
 
 * there may be extra spaces after the identifier that should not be
1056
 
 * counted in the length.
1057
 
 */
1058
 
static unsigned int LengthWord(const char *word, char otherSeparator) {
1059
 
        // Find a '('. If that fails go to the end of the string.
1060
 
        const char *endWord = strchr(word, '(');
1061
 
        if (!endWord && otherSeparator)
1062
 
                endWord = strchr(word, otherSeparator);
1063
 
        if (!endWord)
1064
 
                endWord = word + strlen(word);
1065
 
        // Last case always succeeds so endWord != 0
1066
 
 
1067
 
        // Drop any space characters.
1068
 
        if (endWord > word) {
1069
 
                endWord--;      // Back from the '(', otherSeparator, or '\0'
1070
 
                // Move backwards over any spaces
1071
 
                while ((endWord > word) && (IsASpace(*endWord))) {
1072
 
                        endWord--;
1073
 
                }
1074
 
        }
1075
 
        return endWord - word;
1076
 
}
1077
 
 
1078
 
/**
1079
 
 * Returns elements (first words of them) of the wordlist array which have
1080
 
 * the same beginning as the passed string.
1081
 
 * The length of the word to compare is passed too.
1082
 
 * Letter case can be ignored or preserved (default).
1083
 
 * If there are more words meeting the condition they are returned all of
1084
 
 * them in the ascending order separated with spaces.
1085
 
 *
1086
 
 * NOTE: returned buffer has to be freed with delete[].
1087
 
 */
1088
 
char *WordList::GetNearestWords(
1089
 
    const char *wordStart,
1090
 
    int searchLen,
1091
 
    bool ignoreCase /*= false*/,
1092
 
    char otherSeparator /*= '\0'*/,
1093
 
    bool exactLen /*=false*/) {
1094
 
        unsigned int wordlen; // length of the word part (before the '(' brace) of the api array element
1095
 
        SString wordsNear;
1096
 
        wordsNear.setsizegrowth(1000);
1097
 
        int start = 0; // lower bound of the api array block to search
1098
 
        int end = len - 1; // upper bound of the api array block to search
1099
 
        int pivot; // index of api array element just being compared
1100
 
        int cond; // comparison result (in the sense of strcmp() result)
1101
 
 
1102
 
        if (0 == words)
1103
 
                return NULL;
1104
 
        if (ignoreCase) {
1105
 
                if (!sortedNoCase) {
1106
 
                        sortedNoCase = true;
1107
 
                        SortWordListNoCase(wordsNoCase, len);
1108
 
                }
1109
 
                while (start <= end) { // Binary searching loop
1110
 
                        pivot = (start + end) / 2;
1111
 
                        cond = CompareNCaseInsensitive(wordStart, wordsNoCase[pivot], searchLen);
1112
 
                        if (!cond) {
1113
 
                                // Find first match
1114
 
                                while ((pivot > start) &&
1115
 
                                        (0 == CompareNCaseInsensitive(wordStart,
1116
 
                                                wordsNoCase[pivot-1], searchLen))) {
1117
 
                                        --pivot;
1118
 
                                }
1119
 
                                // Grab each match
1120
 
                                while ((pivot <= end) &&
1121
 
                                        (0 == CompareNCaseInsensitive(wordStart,
1122
 
                                                wordsNoCase[pivot], searchLen))) {
1123
 
                                        wordlen = LengthWord(wordsNoCase[pivot], otherSeparator) + 1;
1124
 
                                        ++pivot;
1125
 
                                        if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
1126
 
                                                continue;
1127
 
                                        wordsNear.append(wordsNoCase[pivot-1], wordlen, ' ');
1128
 
                                }
1129
 
                                return wordsNear.detach();
1130
 
                        } else if (cond < 0) {
1131
 
                                end = pivot - 1;
1132
 
                        } else if (cond > 0) {
1133
 
                                start = pivot + 1;
1134
 
                        }
1135
 
                }
1136
 
        } else {        // Preserve the letter case
1137
 
                if (!sorted) {
1138
 
                        sorted = true;
1139
 
                        SortWordList(words, len);
1140
 
                }
1141
 
                while (start <= end) { // Binary searching loop
1142
 
                        pivot = (start + end) / 2;
1143
 
                        cond = strncmp(wordStart, words[pivot], searchLen);
1144
 
                        if (!cond) {
1145
 
                                // Find first match
1146
 
                                while ((pivot > start) &&
1147
 
                                        (0 == strncmp(wordStart,
1148
 
                                                words[pivot-1], searchLen))) {
1149
 
                                        --pivot;
1150
 
                                }
1151
 
                                // Grab each match
1152
 
                                while ((pivot <= end) &&
1153
 
                                        (0 == strncmp(wordStart,
1154
 
                                                words[pivot], searchLen))) {
1155
 
                                        wordlen = LengthWord(words[pivot], otherSeparator) + 1;
1156
 
                                        ++pivot;
1157
 
                                        if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
1158
 
                                                continue;
1159
 
                                        wordsNear.append(words[pivot-1], wordlen, ' ');
1160
 
                                }
1161
 
                                return wordsNear.detach();
1162
 
                        } else if (cond < 0) {
1163
 
                                end = pivot - 1;
1164
 
                        } else if (cond > 0) {
1165
 
                                start = pivot + 1;
1166
 
                        }
1167
 
                }
1168
 
        }
1169
 
        return NULL;
1170
 
}