avr-libc vfprintf_P() return value

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 

The avr-libc 2.0.0 documentation says:

vfprintf returns the number of characters written to stream, or EOF in case of an error. Currently, this will only happen if stream has not been opened with write intent.

Yet whilst the function below otherwise works fine, the module's static int timed_msg_len seems always seems to be set to zero. Am I doing something stupid, or have I misunderstood the usage?

void displayTimedMsg_P ( uint8_t pos, float sec, const char * fmt_P, ... ) {
    va_list args;

    lcdSetCursorAddress ( pos );
    timed_msg_pos = pos;

    va_start ( args, fmt_P );
    timed_msg_len = vfprintf_P ( stdout, fmt_P, args );
    va_end ( args );

    timerSet ( TIMER_MSG_DISPLAY, sec );
}

Thanks in advance, Martin

Last Edited: Fri. Aug 14, 2020 - 11:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

None of this need be a mystery. The source of vfprintf_P(), like everything in AVR-LibC is open:

 

http://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/libc/stdio/vfprintf_p.c?revision=1944&view=markup

 

obviously that in turn is simply returning what comes from vfprintf() which is:

 

http://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/libc/stdio/vfprintf.c?revision=2191&view=markup

 

So it uses the "len" field in the FILE structure of the active stream. At 294 (assuming the default printf()) it does:

 

stream->len = 0;

 

then at the very end:

 

return stream->len;

 

all the output is through putc() so it's obviously relying on putc() to increment stream->len. putc() in turn (moving into the realsm of Asm) is:

 

http://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/libc/stdio/putc.S?revision=1944&view=markup

 

which in turn is just using fputc():

 

http://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/libc/stdio/fputc.c?revision=1944&view=markup

 

and in that one sees:

 

49 } else {
50 if (stream->put(c, stream) == 0) {
51 stream->len++;
52 return c;
53 } else
54 return EOF;

 

so that includes the stream->len++

 

So it's difficult to see how this would not be returning the output length to vfprintf_P(). What happens when you simulate your way through this? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many thanks for the useful pointers; i'll investigate further...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK problem solved. Thanks to those links I now understand much better the role played by fputc().

 

The problem was due to me not realising that my naive character output function (below) also needs to update the stream structure ...

void lcdStdout ( void ) {
    fdevopen ( lcdPut, dummyGetFn );                                // associate stdout with LCD
}

static int lcdPut ( char c, FILE *fp ) {                            // send printf() output to LCD
    while ( lcdPutChar ( c ) );                                     // if FIFO full then keep trying
    return c;
}

The updated version simply adds the following line to lcdPut:

    fp->len += 1;                                                   // update stream.len

And now vfprintf_P returns the correct value.

Last Edited: Fri. Aug 14, 2020 - 12:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The proper way is for lcdPut to return 0 on success. That's what fputc() expects.

 

Edit to add:

 

The avr-libc documentation you linked to mentions this in fdevopen:

 

If the put function pointer is provided, the stream is opened with write intent. The function passed as put shall take two arguments, the first a character to write to the device, and the second a pointer to FILE, and shall return 0 if the output was successful, and a nonzero value if the character could not be sent to the device.

(Emphasis mine.) 

Last Edited: Fri. Aug 14, 2020 - 06:57 PM