// bsla_printf.h                                                      -*-C++-*-
#ifndef INCLUDED_BSLA_PRINTF
#define INCLUDED_BSLA_PRINTF

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a macro to indicate 'printf'-style arguments.
//
//@MACROS:
//  BSLA_PRINTF(FMTIDX, STARTIDX): validate 'printf' format and arguments
//  BSLA_PRINTF_IS_ACTIVE: 1 if 'BSLA_PRINTF' is active and 0 otherwise
//
//@SEE_ALSO: bsla_annotations
//
//@DESCRIPTION: This component provides a preprocessor macro that allows the
// designation of a given function argument as a 'printf'-style format string,
// and arguments starting at a certain index in the argument list to be
// formatted according to that string.
//
///Macro Reference
///---------------
//: 'BSLA_PRINTF(FMTIDX, STARTIDX)'
//:     This annotation instructs the compiler to perform additional
//:     compile-time checks on so-annotated functions that take 'printf'-style
//:     arguments, which should be type-checked against a format string.  The
//:     'FMTIDX' parameter is the one-based index to the 'const char *' format
//:     string.  The 'STARTIDX' parameter is the one-based index to the first
//:     variable argument to type-check against that format string.  For
//:     example:
//..
//  extern int my_printf(void *obj, const char *format, ...) BSLA_PRINTF(2, 3);
//..
//
//: 'BSLA_PRINTF_IS_ACTIVE'
//:     The macro 'BSLA_PRINTF_IS_ACTIVE' is defined to 0 for compilers where
//:     'BSLA_PRINTF' expands to nothing, and 1 otherwise.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: 'printf'-Like Function That Returns a 'bsl::string' by Value
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// First, we define a function, 'strPrintf', that takes a variable number of
// arguments.  The second argument is the format string, and we annotate it
// with 'BSLA_PRINTF':
//..
//  std::string strPrintf(size_t *numChars, const char *format, ...)
//                                                           BSLA_PRINTF(2, 3);
//  std::string strPrintf(size_t *numChars, const char *format, ...)
//      // Do a 'sprintf'-style write to a 'std::string' and return the string
//      // by value.  Ensure that the write can't overflow unless memory or
//      // address space is exhausted.  The specified '*numChars' is the number
//      // of characters written, the specified 'format' is the 'printf'-style
//      // format string, and the specified '...' is the variable-length list
//      // of arguments to be formatted.
//  {
//      std::string ret = " ";
//
//      va_list ap;
//      va_start(ap, format);
//
//      // 'vsnprintf' returns the number of characters that WOULD have been
//      // written (not including the terminating '\0') had the buffer been
//      // long enough.
//
//      *numChars = ::vsnprintf(&ret[0], 1, format, ap);
//      va_end(ap);
//
//      ret.resize(*numChars + 1);
//
//      va_start(ap, format);
//      *numChars = ::vsnprintf(&ret[0], *numChars + 1, format, ap);
//      va_end(ap);
//
//      BSLS_ASSERT(::strlen(ret.c_str()) == *numChars);
//
//      ret.resize(*numChars);
//      return ret;
//  }
//..
// Then, in 'main', we call the function correctly a couple of times:
//..
//      size_t len;
//      std::string s;
//
//      s = strPrintf(&len, "%s %s %s %g\n", "woof", "meow", "arf", 23.5);
//      assert("woof meow arf 23.5\n" == s);
//      assert(19 == len);
//      assert(len == s.length());
//
//      s = strPrintf(&len, "%s %s %s %s %s %s %s %s %s\n",
//                             "The", "rain", "in", "Spain", "falls", "mainly",
//                                                       "in", "the", "plain");
//      assert("The rain in Spain falls mainly in the plain\n" == s);
//      assert(44 == len);
//      assert(len == s.length());
//..
// Now, we call it with too many arguments and of the wrong type:
//..
//      s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
//..
// Finally, we observe the compiler warnings with clang:
//..
//  .../bsla_printf.t.cpp:328:41: warning: format specifies type 'int' but the
//  argument has type 'const char *' [-Wformat]
//      s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
//                           ~~         ^~~~~
//                           %s
//  .../bsla_printf.t.cpp:328:48: warning: format specifies type 'double' but
//  the argument has type 'int' [-Wformat]
//      s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
//                              ~~             ^~
//                              %d
//  .../bsla_printf.t.cpp:328:52: warning: format specifies type 'double' but
//  the argument has type 'int' [-Wformat]
//      s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
//                                 ~~              ^~
//                                 %d
//  .../bsla_printf.t.cpp:328:56: warning: data argument not used by format
//  string [-Wformat-extra-args]
//      s = strPrintf(&len, "%c %f %g", "arf", 27, 32, 65, 27);
//                          ~~~~~~~~~~                 ^
//..

#include <bsls_platform.h>

#if defined(BSLS_PLATFORM_CMP_GNU)   ||                                      \
    defined(BSLS_PLATFORM_CMP_CLANG) ||                                      \
    defined(BSLS_PLATFORM_CMP_HP)    ||                                      \
    defined(BSLS_PLATFORM_CMP_IBM)
    #define BSLA_PRINTF(fmt, arg) __attribute__((format(printf, fmt, arg)))

    #define BSLA_PRINTF_IS_ACTIVE 1
#else
    #define BSLA_PRINTF(fmt, arg)

    #define BSLA_PRINTF_IS_ACTIVE 0
#endif

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------