format(): sprintf semantics in CFEngine

Posted by Mahesh Kumar
May 16, 2013

If you are a programmer, you probably know and maybe even love the sprintf family of functions, which format output based on a format specification and on some input data. Here’s a description of the formats available in the GNU libc implementation.

I wrote an implementation called format() which will be in the upcoming 3.5.0 release. The format() function offers string and number formatting. To reduce the chance of security compromises, you can’t print pointer offsets or single characters for instance. The available specifiers are:

  • %s: print a string
  • %d: print an integers
  • %o and %x: same as %d but in octal and hexadecimal representations, respectively
  • %f: print a real number

In addition you can use the standard width specifiers. Briefly (feel free to try other variations):

body common control { bundlesequence => { run }; }

bundle agent run
{

  vars:

    "a"
      string => format("%10.10s", "x"),
      comment => "pad input to 10 spaces; print no more than 10 characters";

    "b"
      string => format("%-10.10s", "x"),
      comment => "left-indent input and pad to 10 spaces; print no more than 10 characters";

    "c"
      string => format("%04d", 1),
      comment => "format as integer, padded with zeroes on the left to 4 digits";

    "d"
      string => format("%07.2f", 1),
      comment => "format as floating point with two digits of precision, padded with zeroes on the left to 7 characters total";

    "e"
      string => format("hello %s, my IP is %s", $(sys.policy_hub), $(sys.ipv4)),
      comment => "format with two input variables";

  reports:

    "%10.10s on 'x' => '$(a)'";

    "%-10.10s on 'x' => '$(b)'";

    "%04d on '1' => '$(c)'";

    "%07.2f on '1' => '$(d)'";

    "hello my IP is... => '$(e)'";
}

Which produces (this agent is not bootstrapped so the policy hub is undefined):

 2013-05-16T11:43:53-0400 notice: R: %10.10s on 'x' => '         x'
 2013-05-16T11:43:53-0400 notice: R: %-10.10s on 'x' => 'x         '
 2013-05-16T11:43:53-0400 notice: R: %04d on '1' => '0001'
 2013-05-16T11:43:53-0400 notice: R: %07.2f on '1' => '0001.00'
 2013-05-16T11:43:53-0400 notice: R: hello my IP is... => 'hello undefined, my IP is 127.0.0.1'

I hope you enjoy this new function!