blob: 340be5e8f85feffafc6b27cfec11c0cd125cef12 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17// Author: kenton@google.com (Kenton Varda)
18
19#include <google/protobuf/stubs/substitute.h>
20#include <google/protobuf/stubs/strutil.h>
21#include <google/protobuf/stubs/stl_util-inl.h>
22
23namespace google {
24namespace protobuf {
25namespace strings {
26
27using internal::SubstituteArg;
28
29// Returns the number of args in arg_array which were passed explicitly
30// to Substitute().
31static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
32 int count = 0;
33 while (args_array[count] != NULL && args_array[count]->size() != -1) {
34 ++count;
35 }
36 return count;
37}
38
39string Substitute(
40 const char* format,
41 const SubstituteArg& arg0, const SubstituteArg& arg1,
42 const SubstituteArg& arg2, const SubstituteArg& arg3,
43 const SubstituteArg& arg4, const SubstituteArg& arg5,
44 const SubstituteArg& arg6, const SubstituteArg& arg7,
45 const SubstituteArg& arg8, const SubstituteArg& arg9) {
46 string result;
47 SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
48 arg5, arg6, arg7, arg8, arg9);
49 return result;
50}
51
52void SubstituteAndAppend(
53 string* output, const char* format,
54 const SubstituteArg& arg0, const SubstituteArg& arg1,
55 const SubstituteArg& arg2, const SubstituteArg& arg3,
56 const SubstituteArg& arg4, const SubstituteArg& arg5,
57 const SubstituteArg& arg6, const SubstituteArg& arg7,
58 const SubstituteArg& arg8, const SubstituteArg& arg9) {
59 const SubstituteArg* const args_array[] = {
60 &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, NULL
61 };
62
63 // Determine total size needed.
64 int size = 0;
65 for (int i = 0; format[i] != '\0'; i++) {
66 if (format[i] == '$') {
67 if (ascii_isdigit(format[i+1])) {
68 int index = format[i+1] - '0';
69 if (args_array[index]->size() == -1) {
70 GOOGLE_LOG(DFATAL)
71 << "strings::Substitute format string invalid: asked for \"$"
72 << index << "\", but only " << CountSubstituteArgs(args_array)
73 << " args were given. Full format string was: \""
74 << CEscape(format) << "\".";
75 return;
76 }
77 size += args_array[index]->size();
78 ++i; // Skip next char.
79 } else if (format[i+1] == '$') {
80 ++size;
81 ++i; // Skip next char.
82 } else {
83 GOOGLE_LOG(DFATAL)
84 << "Invalid strings::Substitute() format string: \""
85 << CEscape(format) << "\".";
86 return;
87 }
88 } else {
89 ++size;
90 }
91 }
92
93 if (size == 0) return;
94
95 // Build the string.
96 int original_size = output->size();
97 STLStringResizeUninitialized(output, original_size + size);
98 char* target = string_as_array(output) + original_size;
99 for (int i = 0; format[i] != '\0'; i++) {
100 if (format[i] == '$') {
101 if (ascii_isdigit(format[i+1])) {
102 const SubstituteArg* src = args_array[format[i+1] - '0'];
103 memcpy(target, src->data(), src->size());
104 target += src->size();
105 ++i; // Skip next char.
106 } else if (format[i+1] == '$') {
107 *target++ = '$';
108 ++i; // Skip next char.
109 }
110 } else {
111 *target++ = format[i];
112 }
113 }
114
115 GOOGLE_DCHECK_EQ(target - output->data(), output->size());
116}
117
118} // namespace strings
119} // namespace protobuf
120} // namespace google