1/*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2015, Axel D��rfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "PatternEvaluator.h"
9
10#include <ctype.h>
11#include <stdlib.h>
12#include <string.h>
13
14
15
16// #pragma mark - PatternEvaluator
17
18
19/*static*/ BString
20PatternEvaluator::Evaluate(const char* pattern, PlaceholderMapper& mapper)
21{
22	BString result;
23	BString before;
24	bool isBefore = false;
25	bool isAfter = false;
26	bool hadResult = false;
27	bool began = false;
28
29	while (*pattern != '\0') {
30		// find next placeholder
31		const char* placeholder = strchr(pattern, '%');
32		size_t length = 0;
33		if (placeholder != NULL)
34			length = placeholder - pattern;
35		else
36			length = INT_MAX;
37
38		// append skipped chars
39		if (placeholder != pattern) {
40			if (isBefore) {
41				before.SetTo(pattern, length);
42				isBefore = false;
43			} else if (!isAfter || hadResult) {
44				result.Append(pattern, length);
45				isBefore = false;
46				before.SetTo(NULL);
47				isAfter = false;
48			}
49		}
50		if (placeholder == NULL)
51			return result;
52
53		pattern = placeholder + 1;
54
55		// check for special placeholders
56		switch (pattern[0]) {
57			case '%':
58				// An escaped '%'
59				result += '%';
60				pattern++;
61				continue;
62			case '<':
63				// An optional before string
64				isBefore = began = true;
65				hadResult = false;
66				pattern++;
67				continue;
68			case '>':
69				// An optional after string
70				isAfter = true;
71				began = false;
72				before.SetTo(NULL);
73				pattern++;
74				continue;
75			case '-':
76				// End of any other section; ignore
77				pattern++;
78				isBefore = false;
79				isAfter = false;
80				continue;
81		}
82		// Count non alpha numeric characters to the before section
83		while (pattern[0] != '\0' && !isalnum(pattern[0])) {
84			before.Append(pattern[0], 1);
85			pattern++;
86		}
87
88		// parse a number, if there is one
89		int64 number = 0;
90		bool hasNumber = false;
91		if (isdigit(*pattern)) {
92			char* numberEnd;
93			number = strtoll(pattern, &numberEnd, 10);
94			pattern = numberEnd;
95			hasNumber = true;
96		}
97
98		BString mappedValue;
99		if (*pattern != '\0' && mapper.MapPlaceholder(*pattern,
100				number, hasNumber, mappedValue)) {
101			// mapped successfully -- append the replacement string
102			if (began && !mappedValue.IsEmpty())
103				hadResult = true;
104			if (!before.IsEmpty() && !mappedValue.IsEmpty()) {
105				result += before;
106				before.SetTo(NULL);
107			}
108
109			result += mappedValue;
110			pattern++;
111		} else {
112			// something went wrong -- just append the literal part of the
113			// pattern
114			result.Append(placeholder, length);
115		}
116	}
117
118	return result;
119}
120
121
122// #pragma mark - PlaceholderMapper
123
124
125PatternEvaluator::PlaceholderMapper::~PlaceholderMapper()
126{
127}
128