15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Protocol Buffers - Google's data interchange format
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2008 Google Inc.  All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/protobuf/
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: kenton@google.com (Kenton Varda)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <google/protobuf/stubs/substitute.h>
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <google/protobuf/stubs/strutil.h>
35ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <google/protobuf/stubs/stl_util.h>
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace google {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace protobuf {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace strings {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using internal::SubstituteArg;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the number of args in arg_array which were passed explicitly
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to Substitute().
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = 0;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (args_array[count] != NULL && args_array[count]->size() != -1) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++count;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return count;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Substitute(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* format,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg0, const SubstituteArg& arg1,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg2, const SubstituteArg& arg3,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg4, const SubstituteArg& arg5,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg6, const SubstituteArg& arg7,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg8, const SubstituteArg& arg9) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string result;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       arg5, arg6, arg7, arg8, arg9);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SubstituteAndAppend(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string* output, const char* format,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg0, const SubstituteArg& arg1,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg2, const SubstituteArg& arg3,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg4, const SubstituteArg& arg5,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg6, const SubstituteArg& arg7,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SubstituteArg& arg8, const SubstituteArg& arg9) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SubstituteArg* const args_array[] = {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, NULL
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine total size needed.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int size = 0;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; format[i] != '\0'; i++) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (format[i] == '$') {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ascii_isdigit(format[i+1])) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int index = format[i+1] - '0';
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (args_array[index]->size() == -1) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GOOGLE_LOG(DFATAL)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "strings::Substitute format string invalid: asked for \"$"
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << index << "\", but only " << CountSubstituteArgs(args_array)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << " args were given.  Full format string was: \""
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << CEscape(format) << "\".";
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size += args_array[index]->size();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++i;  // Skip next char.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (format[i+1] == '$') {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++size;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++i;  // Skip next char.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GOOGLE_LOG(DFATAL)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "Invalid strings::Substitute() format string: \""
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << CEscape(format) << "\".";
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++size;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size == 0) return;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build the string.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int original_size = output->size();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLStringResizeUninitialized(output, original_size + size);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* target = string_as_array(output) + original_size;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; format[i] != '\0'; i++) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (format[i] == '$') {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ascii_isdigit(format[i+1])) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const SubstituteArg* src = args_array[format[i+1] - '0'];
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(target, src->data(), src->size());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        target += src->size();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++i;  // Skip next char.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (format[i+1] == '$') {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *target++ = '$';
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++i;  // Skip next char.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *target++ = format[i];
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GOOGLE_DCHECK_EQ(target - output->data(), output->size());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace strings
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace protobuf
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace google
135