2

I'd like to write a wrapper function for the mvwprint/mvwchgat ncurses functions which prints the message in the specified window and then changes its attributes.

However, mvwchgat needs to know how many characters it should change - and I have no idea how to tell mvwchgat how long the formatted string is, since a strlen() on, for instance, "abc%d" obviously returns 5, because strlen doesn't know what %d stands for ...

Addicted
  • 1,568
  • 1
  • 15
  • 24
Uncle Dolan
  • 65
  • 1
  • 6
  • Can't you get the formatted string and then count how long it is? sprintf prints and strlen measures. – Mikhail May 10 '12 at 12:05

2 Answers2

9

In C99 or C11, you can use a line like this:

length = snprintf(NULL, 0, format_string, args);

From the manual of snprintf (emphasis mine):

The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.

Since we are giving snprintf 0 as the size, then the output is always truncated and the output of snprintf would be the number of characters that would have been written, which is basically the length of the string.

In C89, you don't have snprintf. A workaround is to create a temporary file, or if you are in *nix open /dev/null and write something like this:

FILE *throw_away = fopen("/dev/null", "w"); /* On windows should be "NUL" but I haven't tested */
if (throw_away)
{
    fprintf(throw_away, "<format goes here>%n", <args go here>, &length);
    fclose(throw_away);
} /* else, try opening a temporary file */
Shahbaz
  • 42,684
  • 17
  • 103
  • 166
  • Sounds nice :) And now, just to clarify: There is no way to do this in C89? – Uncle Dolan May 10 '12 at 13:04
  • @UncleDolan, see my edit. I admit it is not the most elegant, but I have to think more for a better option. – Shahbaz May 10 '12 at 13:11
  • @Shahbaz Nevermind, I've just asked out of interest and because someone told me that I as a beginner should stick to the C89 standard because it would improve my coding style, though I don't really know whether this is true ... – Uncle Dolan May 10 '12 at 16:29
  • @UncleDolan, I don't think so. C99 is an improvement over C89 and it's actually 13 years old now! It's not something that is bad/immature. I encourage you to use it. (I didn't even know `snprintf` wasn't in C89 by they way!) – Shahbaz May 10 '12 at 16:43
  • 1
    @shabaz: You can even do without writing to /dev/null first. Given that the filesystem is large enough for any string, you can just do: `len = fprintf(tmpfile, fmt, ...);` and then: malloc(len+1); rewind, fread() the entire string in one sweep. And fclose(tmpfile), of course. – wildplasser Jul 31 '12 at 16:44
  • Smart solution. I hadn't thought that. Thank you. – Ari Malinen Feb 01 '15 at 19:07
-1

You can't know in advance how long your string will be:

printf("abc%d", 0); //4 chars
printf("abc%d", 111111111);//12 chars

All with the same format string.

The only sure way is to sprintf the text in question into a buffer, strlen(buffer) the result and printf("%s", buffer); the result to screen.

This solution avoids double formatting at the cost of allocating long enough buffer.

Agent_L
  • 3,722
  • 22
  • 24
  • And how do you know how long is a long enough buffer? Unless you have the final size, you cannot create a buffer large enough for it. – Shahbaz May 10 '12 at 12:57