4

For reasons beyond the scope of this question, assume I have a pre-allocated set of discontinuous memory buffers. I want to be able to print a formatted string into as many buffers as it takes to hold all the characters. I don't want to dynamically allocate a buffer large enough to hold the generated string.

Is there any way to get snprintf to "resume" on the first discarded character? Or a way to get that effect, without reimplementing the whole format parsing code from the stdlib?

Conceptually:

int nwritten = snprintf(message_buf[nextbuf++], MAX_MSG_LEN, fmt_string, var1, var2);
while (nwritten > MAX_MSG_LEN) {
   already_written += MAX_MSG_LEN;
   //It didn't fit in one buffer, write any remaining characters to the next buffer.
   nwritten = snprintf_REMAINDER(message_buf[nextbuf++], already_written, MAX_MSG_LEN,
                                 fmt_string, var1, var2);
}

With that code, these inputs

 MAX_MSG_LEN = 16;
 fmt_string = "%s: %.2f";
 char* var1 = "percent complete";
 float var2 = 45.6;
 char msgbuf[N][MAX_MSG_LEN];
 nextbuf = already_written = 0;

should result in
msgbuf[0] containing "percent complet" and
msgbuf[1] containing "e: 45.06"

How do I implement snprintf_REMAINDER ?

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
AShelly
  • 34,686
  • 15
  • 91
  • 152
  • There is no way, as there is no correlation between the data and the format string. It could even stop in the middle of a parameter. It's all or nothing. If you know the format string, then you might be able to inspect the string what was already written, but I doubt it's worth the hassel. – Devolus Apr 13 '21 at 07:02
  • `write any remaining characters` I do not understand, will there always be zero remaining characters? If it didn't fit the buffer, the buffer will be full, what else is there to write? `Conceptually:` Can you provide more _real_ code, with a full function that takes input and some testing output you expect? `snprintf(message_buf[nextbuf++]` is `message_buf` an array of pointers? I think it's usual that buffer is an array of characters. – KamilCuk Apr 13 '21 at 07:13
  • what environment are you using, is it POSIX, or maybe GNU-like? – tstanisl Apr 13 '21 at 09:25
  • Do you use standard streams or file streams? If not, many (embedded) toolchains allow you to overwrite normal stream output functions. You could define your own file handle open, write and close functions which would perform the necessary buffering, and then use standard `fprintf` to format strings. – user694733 Apr 13 '21 at 12:38
  • Example added, @KamilCuk. Gnu-like environment. No streams. For the purposes of this question the goal is to fill a series of fixed-length buffers. You can assume they are consumed by `do_magic(message_buf);` – AShelly Apr 13 '21 at 18:56
  • 2
    Are [glibc custom streams](https://www.gnu.org/software/libc/manual/html_mono/libc.html#Custom-Streams) a possible option? – Nate Eldredge Apr 13 '21 at 18:58
  • Oh, that might work. I was about to reply to @Devolus that of course there must be a way, because the only data that needs to be persistent across calls is A) the last character in the format string that was output and B) in the case that character is a `%`, how many chars of the formatted variable were output. We could track that info inside a custom stream "cookie". – AShelly Apr 13 '21 at 19:12
  • `fopencookie`, sadly, usually uses dynamic allocation ([on newlib](https://github.com/eblot/newlib/blob/master/newlib/libc/stdio/fopencookie.c#L220)) but anyway `with no dynamic memory allocation allowed` roll your own sbrk with static buffer and ta da – KamilCuk Apr 13 '21 at 19:56
  • Just write the full buffer and shift to insert zero bytes once every 16 characters. Your input buffer `char msgbuf[N][MAX_MSG_LEN];` is continuous. – KamilCuk Apr 13 '21 at 20:05
  • 1
    I've got a YX problem here. I want to do Y: print the characters discarded by a `snprintf` into a different buffer, without allocating a bigger buffer to hold the whole thing. I keep getting answers about X - a highly simplified example of the software engineering problem I face. I don't want help solving my engineering problem, I want to know if there's a relatively straightforward way of doing the thing I asked about. – AShelly Apr 13 '21 at 21:03
  • 1
    Then I think by omission you've got the answer to that question: No. – Nate Eldredge Apr 14 '21 at 01:00

0 Answers0