// bsla_format.h                                                      -*-C++-*-
#ifndef INCLUDED_BSLA_FORMAT
#define INCLUDED_BSLA_FORMAT

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

//@PURPOSE: Provide a macro to indicate that a return value is a format string.
//
//@MACROS:
//  BSLA_FORMAT(FMT_IDX): validate 'printf'-style format spec. in 'n'th arg.
//  BSLA_FORMAT_IS_ACTIVE: 1 if 'BSLA_FORMAT' is active and 0 otherwise
//
//@SEE_ALSO: bsla_annotations
//
//@DESCRIPTION: This component provides a preprocessor macro to indicate that
// an indexed argument of a function is a 'printf'-style format specification,
// and that the function will return a 'printf'-style format string with an
// equivalent specification.
//
///Macro Reference
///---------------
//: 'BSLA_FORMAT(FMT_IDX)'
//:     This annotation specifies that the so-annotated function takes an
//:     argument that is a valid format string for a 'printf'-style function
//:     and returns a format string that is consistent with that format.  This
//:     allows format strings manipulated by translation functions to be
//:     checked against arguments.  Without this annotation, attempting to
//:     manipulate the format string via this kind of function might generate
//:     warnings about non-literal formats, or fail to generate warnings about
//:     mismatched arguments.
//
//: 'BSLA_FORMAT_IS_ACTIVE'
//:     The macro 'BSLA_FORMAT_IS_ACTIVE' is defined to 0 when 'BSLA_FORMAT'
//:     expands to nothing and 1 otherwise.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: A Language Translator Function
///- - - - - - - - - - - - - - - - - - - - -
// First, we define an 'enum', 'Language', to indicate the choice of languages:
//..
//  enum Language {
//      e_ENGLISH,
//      e_SPANISH,
//      e_DUTCH,
//      e_FRENCH };
//..
// Then, we define a function, 'prefixName', which will take a format string
// and prefix it with the word 'name' in the selected language.  The
// 'BSLA_FORMAT' annotation indicates that the result will be a pointer to a
// 'printf'-style format string equivalent to the format string passed to the
// third argument:
//..
//  const char *prefixName(char *buf, Language lang, const char *format)
//                                                              BSLA_FORMAT(3);
//  const char *prefixName(char *buf, Language lang, const char *format)
//      // Create a buffer beginning with the word 'name' translated to the
//      // specified 'lang', followed by the specified format string 'format',
//      // using the specified 'buf' for memory.
//  {
//      const char *name = "";
//      switch (lang) {
//        case e_ENGLISH: name = "Name";   break;
//        case e_SPANISH: name = "Nombre"; break;
//        case e_DUTCH:   name = "Naam";   break;
//        case e_FRENCH:  name = "Nom";    break;
//      }
//      ::strcpy(buf, name);
//      ::strcat(buf, ": ");
//      ::strcat(buf, format);
//
//      return buf;
//  }
//..
// Next, in 'main', we call 'printf' and 'sscanf' using the return value of
// 'prefixName'.  No warnings occur when correct arguments are passed:
//..
//  char buffer[1000];
//  ::printf(prefixName(buffer, e_SPANISH, "%s\n"), "Michael Bloomberg");
//
//  char name[100];
//  ::sscanf("Emmanuel Macron", prefixName(buffer, e_FRENCH, "%s"), name);
//..
// Now, we call 'printf' and 'sscanf' passing arguments that won't match the
// resulting format string:
//..
//  ::printf(prefixName(buffer, e_ENGLISH, "%s\n"), 2.7);
//  int x;
//  ::sscanf("Sharon den Adel", prefixName(buffer, e_DUTCH, "%s"), &x);
//..
// Finally, we observe the following warning messages with g++:
//..
//  .../bsla/bsla_format.t.cpp:306:56: warning: format '%s' expects argument
//   of type 'char*', but argument 2 has type 'double' [-Wformat=]
//       ::printf(prefixName(buffer, e_ENGLISH, "%s\n"), 2.7);
//                                                          ^
//  .../bsla_format.t.cpp:308:70: warning: format '%s' expects argument of
//   type 'char*', but argument 3 has type 'int*' [-Wformat=]
//       ::sscanf("Sharon den Adel", prefixName(buffer, e_DUTCH, "%s"), &x);
//                                                                      ~~^
//..

#include <bsls_platform.h>

#if defined(BSLS_PLATFORM_CMP_GNU)   ||                                      \
    defined(BSLS_PLATFORM_CMP_CLANG) ||                                      \
    defined(BSLS_PLATFORM_CMP_IBM)
    #define BSLA_FORMAT(FMT_IDX) __attribute__((format_arg(FMT_IDX)))

    #define BSLA_FORMAT_IS_ACTIVE 1
#else
    #define BSLA_FORMAT(FMT_IDX)

    #define BSLA_FORMAT_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 ----------------------------------