1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "utils/strings/substitute.h"
18 
19 #include <algorithm>
20 
21 #include "utils/base/logging.h"
22 
23 namespace libtextclassifier3 {
24 namespace strings {
25 
Substitute(const StringPiece format,const std::vector<StringPiece> & args,std::string * output)26 bool Substitute(const StringPiece format, const std::vector<StringPiece>& args,
27                 std::string* output) {
28   // Determine total size needed.
29   size_t size = 0;
30   for (size_t i = 0; i < format.size(); i++) {
31     if (format[i] == '$') {
32       if (i + 1 >= format.size()) {
33         TC3_LOG(ERROR) << "Invalid format string: " << format.ToString();
34         return false;
35       } else if (isdigit(format[i + 1])) {
36         int index = format[i + 1] - '0';
37         if (static_cast<size_t>(index) >= args.size()) {
38           TC3_LOG(ERROR) << "Asked for " << index << ", but only "
39                          << args.size() << " arguments given";
40           return false;
41         }
42         size += args[index].size();
43         ++i;  // Skip next char.
44       } else if (format[i + 1] == '$') {
45         ++size;
46         ++i;  // Skip next char.
47       } else {
48         TC3_LOG(ERROR) << "Invalid format string: " << format.ToString();
49         return false;
50       }
51     } else {
52       ++size;
53     }
54   }
55 
56   if (size == 0) {
57     output->clear();
58     return true;
59   }
60 
61   // Build the string.
62   output->resize(size);
63   char* target = &(*output)[0];
64   for (size_t i = 0; i < format.size(); i++) {
65     if (format[i] == '$') {
66       if (isdigit(format[i + 1])) {
67         const StringPiece src = args[format[i + 1] - '0'];
68         target = std::copy(src.data(), src.data() + src.size(), target);
69         ++i;  // Skip next char.
70       } else if (format[i + 1] == '$') {
71         *target++ = '$';
72         ++i;  // Skip next char.
73       }
74     } else {
75       *target++ = format[i];
76     }
77   }
78   return true;
79 }
80 
Substitute(const StringPiece format,const std::vector<StringPiece> & args)81 std::string Substitute(const StringPiece format,
82                        const std::vector<StringPiece>& args) {
83   std::string result;
84   if (!Substitute(format, args, &result)) {
85     return "";
86   }
87   return result;
88 }
89 
90 }  // namespace strings
91 }  // namespace libtextclassifier3
92