Quick Links:

bal | bbl | bdl | bsl

Component bsla_format
[Package bsla]

Provide a macro to indicate that a return value is a format string. More...

Outline
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 nth arg.
BSLA_FORMAT_IS_ACTIVE 1 if BSLA_FORMAT is active and 0 otherwise
See also:
Component 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);
                                                                      ~~^