patterncMinor
C hack: replace printf to collect output and return complete string by using a line buffer
Viewed 0 times
collectlinereturnreplaceoutputcompleteusinghackandprintf
Problem
I have this great C program I'd like to embed into an iOS app. One passes command line arguments to it and the results are printed to
Now I'd like to just edit
I implemented a solution by using a line buffer to collect all the
The charm of this solution is - it's kind of tcl'ish: just throw everything into a text line, and if it's complete, store it. Now do that as long as necessary and return the whole bunch at the end.
C code:
With the replacement
And the function when we complete one output line (everywhere
```
// Output line is now complete: copy to return buffer and reset line buffer.
static void tprntNewLine()
{
size_t newSize;
long remainingLenOutBuffer;
char *newOutBuffer;
remainingLenOutBuffer
stdout via printf and fputs - like with all the good old Unix programs.Now I'd like to just edit
main and the print functions to use my own printf function which collects all the output that normally goes to stdout and return it at the end.I implemented a solution by using a line buffer to collect all the
printfs until the newline. And a dynamic char array whereto I copy when an output line is finished.The charm of this solution is - it's kind of tcl'ish: just throw everything into a text line, and if it's complete, store it. Now do that as long as necessary and return the whole bunch at the end.
C code:
#include
#include
#include
#include
// outLineBuffer collects one output line by several calls to tprntf
#define initialSizeOfReturnBuffer 10 // reduced for testing (would be 16*1024)
#define incrSizeOfReturnBuffer 5 // reduced for testing (would be 1024*1024)
#define outLineBufferMaxSize 4095
char outLineBuffer[sizeof(char)*outLineBufferMaxSize] = "";
char *tReturnString;
size_t sizeOfReturnBuffer, curPosOutBuffer = 0, lenOutLine = 0;With the replacement
tprntf for all the original printf and fputs:// replace printf with this to collect the parts of one output line.
static int tprntf(const char *format, ...)
{
const size_t maxLen = sizeof(char)*outLineBufferMaxSize;
va_list arg;
int done;
va_start (arg, format);
done = vsnprintf (&outLineBuffer[lenOutLine], maxLen-lenOutLine, format, arg);
va_end (arg);
lenOutLine = strlen(outLineBuffer);
return done;
}And the function when we complete one output line (everywhere
\n is printed):```
// Output line is now complete: copy to return buffer and reset line buffer.
static void tprntNewLine()
{
size_t newSize;
long remainingLenOutBuffer;
char *newOutBuffer;
remainingLenOutBuffer
Solution
Bug
Your code in
Suppose at entry to the function, these are the values of your variables:
And then you get an
You will increase the size of your output buffer from
After that, you will then try to copy 80 bytes from
You need to change your reallocation amount to ensure that it is at least enough to hold the length of the line you are trying to append. For example:
Style issues
-
Typically, constants that are
to
-
There's no need to use
Your code in
tprntNewLine() doesn't guarantee that tReturnString is large enough to hold the output string.Suppose at entry to the function, these are the values of your variables:
sizeOfReturnBuffer = 10;
curPosOutBuffer = 0;And then you get an
outLine whose length is 80. After this piece of code:if (remainingLenOutBuffer < 0) {
newSize = sizeOfReturnBuffer + sizeof(char)*incrSizeOfReturnBuffer;
if ((newOutBuffer = realloc(tReturnString, newSize)) != 0) {
tReturnString = newOutBuffer;
sizeOfReturnBuffer = newSize;
} else {
lenOutLine += remainingLenOutBuffer; //just write part that is still available
remainingLenOutBuffer = 0;
}
}You will increase the size of your output buffer from
10 to 15 (because you only add incrSizeOfReturnBuffer to the current size).After that, you will then try to copy 80 bytes from
outLine into your 15 byte buffer:snprintf(&tReturnString[curPosOutBuffer], lenOutLine+1, "%s\n", outLineBuffer);You need to change your reallocation amount to ensure that it is at least enough to hold the length of the line you are trying to append. For example:
if (remainingLenOutBuffer < 0) {
int neededSize = -remainingLenOutBuffer;
if (neededSize < incrSizeOfReturnBuffer)
neededSize = incrSizeOfReturnBuffer;
newSize = sizeOfReturnBuffer + neededSize;
// ...Style issues
-
Typically, constants that are
#defined are in capital letters and in snake_case. So I would change:#define initialSizeOfReturnBuffer 10to
#define INITIAL_SIZE_OF_RETURN_BUFFER 10-
There's no need to use
sizeof(char). It's always 1.Code Snippets
sizeOfReturnBuffer = 10;
curPosOutBuffer = 0;if (remainingLenOutBuffer < 0) {
newSize = sizeOfReturnBuffer + sizeof(char)*incrSizeOfReturnBuffer;
if ((newOutBuffer = realloc(tReturnString, newSize)) != 0) {
tReturnString = newOutBuffer;
sizeOfReturnBuffer = newSize;
} else {
lenOutLine += remainingLenOutBuffer; //just write part that is still available
remainingLenOutBuffer = 0;
}
}snprintf(&tReturnString[curPosOutBuffer], lenOutLine+1, "%s\n", outLineBuffer);if (remainingLenOutBuffer < 0) {
int neededSize = -remainingLenOutBuffer;
if (neededSize < incrSizeOfReturnBuffer)
neededSize = incrSizeOfReturnBuffer;
newSize = sizeOfReturnBuffer + neededSize;
// ...#define initialSizeOfReturnBuffer 10Context
StackExchange Code Review Q#113651, answer score: 5
Revisions (0)
No revisions yet.