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