xref: /haiku/src/apps/terminal/PatternEvaluator.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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
20 PatternEvaluator::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 
125 PatternEvaluator::PlaceholderMapper::~PlaceholderMapper()
126 {
127 }
128