int vfprintf(FAR FILE *stream, FAR const IPTR char *fmt, va_list ap)
{
    struct lib_stdoutstream_s stdoutstream;
    int  n = ERROR;

    if (stream)
    {
        /* Wrap the stream in a stream object and let lib_vsprintf
         * do the work.
         */

        lib_stdoutstream(&stdoutstream, stream);

        /* Hold the stream semaphore throughout the lib_vsprintf
         * call so that this thread can get its entire message out
         * before being pre-empted by the next thread.
         */

        lib_take_semaphore(stream);
        n = lib_vsprintf(&stdoutstream.public, fmt, ap);
        lib_give_semaphore(stream);
    }

    return n;
}
Beispiel #2
0
int lib_rdflush(FAR FILE *stream)
{
  if (!stream)
    {
      set_errno(EBADF);
      return ERROR;
    }

  /* Get exclusive access to the stream */

  lib_take_semaphore(stream);

  /* If the buffer is currently being used for read access, then discard all
   * of the read-ahead data.  We do not support concurrent buffered read/write
   * access.
   */

  if (stream->fs_bufread != stream->fs_bufstart)
    {
      /* Now adjust the stream pointer to account for the read-ahead data that
       * was not actually read by the user.
       */

#if CONFIG_NUNGET_CHARS > 0
      off_t rdoffset = stream->fs_bufread - stream->fs_bufpos + stream->fs_nungotten;
#else
      off_t rdoffset = stream->fs_bufread - stream->fs_bufpos;
#endif
      /* Mark the buffer as empty (do this before calling fseek() because fseek()
       * also calls this function).
       */

      stream->fs_bufpos = stream->fs_bufread = stream->fs_bufstart;
#if CONFIG_NUNGET_CHARS > 0
      stream->fs_nungotten = 0;
#endif
      /* Then seek to the position corresponding to the last data read by the user */

      if (fseek(stream, -rdoffset, SEEK_CUR) < 0)
        {
          lib_give_semaphore(stream);
          return ERROR;
        }
    }

  lib_give_semaphore(stream);
  return OK;
}
Beispiel #3
0
static off_t lib_getrdoffset(FAR FILE *stream)
{
  off_t rdoffset = 0;
  lib_take_semaphore(stream);

  if (stream->fs_bufread != stream->fs_bufstart)
    {
#if CONFIG_NUNGET_CHARS > 0
      rdoffset = stream->fs_bufread - stream->fs_bufpos + stream->fs_nungotten;
#else
      rdoffset = stream->fs_bufread - stream->fs_bufpos;
#endif
    }

  lib_give_semaphore(stream);
  return rdoffset;
}
Beispiel #4
0
int puts(FAR const char *s)
{
  FILE *stream = stdout;
  int nwritten;
  int nput = EOF;
  int ret;

  /* Write the string (the next two steps must be atomic) */

  lib_take_semaphore(stream);

  /* Write the string without its trailing '\0' */

  nwritten = fputs(s, stream);
  if (nwritten > 0)
    {
      /* Followed by a newline */

      char newline = '\n';
      ret = lib_fwrite(&newline, 1, stream);
      if (ret > 0)
        {
          nput = nwritten + 1;

          /* Flush the buffer after the newline is output if line buffering
           * is enabled.
           */

          if ((stream->fs_flags & __FS_FLAG_LBF) != 0)
            {
              ret = lib_fflush(stream, true);
              if (ret < 0)
                {
                  nput = EOF;
                }
            }
        }
    }

  lib_give_semaphore(stdout);
  return nput;
}
Beispiel #5
0
int puts(FAR const char *s)
{
  FILE *stream = stdout;
  int nwritten;
  int nput = EOF;
  int ret;

  /* Write the string (the next two steps must be atomic) */

  lib_take_semaphore(stream);

  /* Write the string without its trailing '\0' */

  nwritten = fputs(s, stream);
  if (nwritten > 0)
    {
      /* Followed by a newline */

      char newline = '\n';
      ret = lib_fwrite(&newline, 1, stream);
      if (ret > 0)
        {
          nput = nwritten + 1;

          /* Flush the buffer after the newline is output. */

#ifdef CONFIG_STDIO_LINEBUFFER
          ret = lib_fflush(stream, true);
          if (ret < 0)
            {
              nput = EOF;
            }
#endif
        }
    }

  lib_give_semaphore(stdout);
  return nput;
}
ssize_t lib_fwrite(FAR const void *ptr, size_t count, FAR FILE *stream)
#if CONFIG_STDIO_BUFFER_SIZE > 0
{
  FAR const unsigned char *start = ptr;
  FAR const unsigned char *src   = ptr;
  ssize_t ret = ERROR;
  unsigned char *dest;

  /* Make sure that writing to this stream is allowed */

  if (stream == NULL)
    {
      set_errno(EBADF);
      return ret;
    }

  if ((stream->fs_oflags & O_WROK) == 0)
    {
      set_errno(EBADF);
      goto errout;
    }

  /* Get exclusive access to the stream */

  lib_take_semaphore(stream);

  /* If the buffer is currently being used for read access, then
   * discard all of the read-ahead data.  We do not support concurrent
   * buffered read/write access.
   */

  if (lib_rdflush(stream) < 0)
    {
      goto errout_with_semaphore;
    }

  /* Loop until all of the bytes have been buffered */

  while (count > 0)
    {
      /* Determine the number of bytes left in the buffer */

      size_t gulp_size = stream->fs_bufend - stream->fs_bufpos;

      /* Will the user data fit into the amount of buffer space
       * that we have left?
       */

      if (gulp_size > count)
        {
          /* Yes, clip the gulp to the size of the user data */

          gulp_size = count;
        }

      /* Adjust the number of bytes remaining to be transferred
       * on the next pass through the loop (might be zero).
       */

      count -= gulp_size;

      /* Transfer the data into the buffer */

      for (dest = stream->fs_bufpos; gulp_size > 0; gulp_size--)
        {
          *dest++ = *src++;
        }

      stream->fs_bufpos = dest;

      /* Is the buffer full? */

      if (dest >= stream->fs_bufend)
        {
          /* Flush the buffered data to the IO stream */

          int bytes_buffered = lib_fflush(stream, false);
          if (bytes_buffered < 0)
            {
              goto errout_with_semaphore;
            }
        }
    }

  /* Return the number of bytes written */

  ret = src - start;

errout_with_semaphore:
  lib_give_semaphore(stream);

errout:
  if (ret < 0)
    {
      stream->fs_flags |= __FS_FLAG_ERROR;
    }

  return ret;
}
ssize_t lib_fflush(FAR FILE *stream, bool bforce)
{
#if CONFIG_STDIO_BUFFER_SIZE > 0
  FAR const unsigned char *src;
  ssize_t bytes_written;
  ssize_t nbuffer;

  /* Return EBADF if the file is not opened for writing */

  if (stream->fs_fd < 0 || (stream->fs_oflags & O_WROK) == 0)
    {
      return -EBADF;
    }

  /* Make sure that we have exclusive access to the stream */

  lib_take_semaphore(stream);

  /* Make sure that the buffer holds valid data */

  if (stream->fs_bufpos  != stream->fs_bufstart)
    {
       /* Make sure that the buffer holds buffered write data.  We do not
        * support concurrent read/write buffer usage.
        */

       if (stream->fs_bufread != stream->fs_bufstart)
        {
          /* The buffer holds read data... just return zero meaning "no bytes
           * remaining in the buffer."
           */

          lib_give_semaphore(stream);
          return 0;
        }

      /* How many bytes of write data are used in the buffer now */

      nbuffer = stream->fs_bufpos - stream->fs_bufstart;

      /* Try to write that amount */

      src = stream->fs_bufstart;
      do
        {
          /* Perform the write */

          bytes_written = write(stream->fs_fd, src, nbuffer);
          if (bytes_written < 0)
            {
              /* Write failed.  The cause of the failure is in 'errno'.
               * returned the negated errno value.
               */

              lib_give_semaphore(stream);
              return -get_errno();
            }

          /* Handle partial writes.  fflush() must either return with
           * an error condition or with the data successfully flushed
           * from the buffer.
           */

          src     += bytes_written;
          nbuffer -= bytes_written;
        }
      while (bforce && nbuffer > 0);

      /* Reset the buffer position to the beginning of the buffer */

      stream->fs_bufpos = stream->fs_bufstart;

      /* For the case of an incomplete write, nbuffer will be non-zero
       * It will hold the number of bytes that were not written.
       * Move the data down in the buffer to handle this (rare) case
       */

      while (nbuffer)
       {
         *stream->fs_bufpos++ = *src++;
         --nbuffer;
       }
    }

  /* Restore normal access to the stream and return the number of bytes
   * remaining in the buffer.
   */

  lib_give_semaphore(stream);
  return stream->fs_bufpos - stream->fs_bufstart;
#else
  /* Return no bytes remaining in the buffer */

  return 0;
#endif
}
Beispiel #8
0
ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream)
{
  unsigned char *dest  = (unsigned char*)ptr;
  ssize_t        bytes_read;
#if CONFIG_STDIO_BUFFER_SIZE > 0
  int            ret;
#endif

  /* Make sure that reading from this stream is allowed */

  if (!stream || (stream->fs_oflags & O_RDOK) == 0)
    {
      set_errno(EBADF);
      bytes_read = -1;
    }
  else
    {
      /* The stream must be stable until we complete the read */

      lib_take_semaphore(stream);

#if CONFIG_NUNGET_CHARS > 0
      /* First, re-read any previously ungotten characters */

      while ((stream->fs_nungotten > 0) && (count > 0))
        {
          /* Decrement the count of ungotten bytes to get an index */

          stream->fs_nungotten--;

          /* Return the last ungotten byte */

          *dest++ = stream->fs_ungotten[stream->fs_nungotten];

          /* That's one less byte that we have to read */

          count--;
        }
#endif

#if CONFIG_STDIO_BUFFER_SIZE > 0
      /* If the buffer is currently being used for write access, then
       * flush all of the buffered write data.  We do not support concurrent
       * buffered read/write access.
       */

      ret = lib_wrflush(stream);
      if (ret < 0)
        {
          lib_give_semaphore(stream);
          return ret;
        }

      /* Now get any other needed chars from the buffer or the file. */

      while (count > 0)
        {
          /* Is there readable data in the buffer? */

          while ((count > 0) && (stream->fs_bufpos < stream->fs_bufread))
            {
              /* Yes, copy a byte into the user buffer */

              *dest++ = *stream->fs_bufpos++;
              count--;
            }

          /* The buffer is empty OR we have already supplied the number of
           * bytes requested in the read.  Check if we need to read
           * more from the file.
           */

          if (count > 0)
            {
              size_t buffer_available;

              /* We need to read more data into the buffer from the file */

              /* Mark the buffer empty */

              stream->fs_bufpos = stream->fs_bufread = stream->fs_bufstart;

              /* How much space is available in the buffer? */

              buffer_available = stream->fs_bufend - stream->fs_bufread;

              /* Will the number of bytes that we need to read fit into
               * the buffer space that is available? If the read size is
               * larger than the buffer, then read some of the data
               * directly into the user's buffer.
               */

              if (count > buffer_available)
                {
                  bytes_read = read(stream->fs_fd, dest, count);
                  if (bytes_read < 0)
                    {
                      /* An error occurred on the read.  The error code is
                       * in the 'errno' variable.
                       */

                      goto errout_with_errno;
                    }
                  else if (bytes_read == 0)
                    {
                      /* We are at the end of the file.  But we may already
                       * have buffered data.  In that case, we will report
                       * the EOF indication later.
                       */

                      goto shortread;
                    }
                  else
                    {
                      /* Some bytes were read. Adjust the dest pointer */

                      dest  += bytes_read;

                      /* Were all of the requested bytes read? */

                      if ((size_t)bytes_read < count)
                        {
                          /* No.  We must be at the end of file. */

                          goto shortread;
                        }
                      else
                        {
                          /* Yes.  We are done. */

                          count = 0;
                        }
                    }
                }
              else
                {
                  /* The number of bytes required to satisfy the read
                   * is less than or equal to the size of the buffer
                   * space that we have left. Read as much as we can
                   * into the buffer.
                   */

                  bytes_read = read(stream->fs_fd, stream->fs_bufread, buffer_available);
                  if (bytes_read < 0)
                    {
                      /* An error occurred on the read.  The error code is
                       * in the 'errno' variable.
                       */

                      goto errout_with_errno;
                    }
                  else if (bytes_read == 0)
                    {
                      /* We are at the end of the file.  But we may already
                       * have buffered data.  In that case, we will report
                       * the EOF indication later.
                       */

                      goto shortread;
                    }
                  else
                    {
                      /* Some bytes were read */

                      stream->fs_bufread += bytes_read;
                    }
                }
            }
        }
#else
      /* Now get any other needed chars from the file. */

      while (count > 0)
        {
          bytes_read = read(stream->fs_fd, dest, count);
          if (bytes_read < 0)
            {
              /* An error occurred on the read.  The error code is
               * in the 'errno' variable.
               */

              goto errout_with_errno;
            }
          else if (bytes_read == 0)
            {
              /* We are at the end of the file.  But we may already
               * have buffered data.  In that case, we will report
               * the EOF indication later.
               */

              break;
            }
          else
            {
              dest  += bytes_read;
              count -= bytes_read;
            }
        }
#endif
      /* Here after a successful (but perhaps short) read */

#if CONFIG_STDIO_BUFFER_SIZE > 0
    shortread:
#endif
      bytes_read = dest - (unsigned char*)ptr;

      /* Set or clear the EOF indicator.  If we get here because of a
       * short read and the total number of* bytes read is zero, then
       * we must be at the end-of-file.
       */

      if (bytes_read > 0)
        {
          stream->fs_flags &= ~__FS_FLAG_EOF;
        }
      else
        {
          stream->fs_flags |= __FS_FLAG_EOF;
        }

      lib_give_semaphore(stream);
    }

  return bytes_read;

/* Error exits */

errout_with_errno:
  stream->fs_flags |= __FS_FLAG_ERROR;
  lib_give_semaphore(stream);
  return -get_errno();
}
Beispiel #9
0
int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size)
{
	FAR unsigned char *newbuf;
	uint8_t flags;
	int errcode;

	/* Verify arguments */
	/* Make sure that a valid mode was provided */

	if (mode != _IOFBF && mode != _IOLBF && mode != _IONBF) {
		errcode = EINVAL;
		goto errout;
	}

	/* If a buffer pointer is provided, then it must have a non-zero size */

	if (buffer != NULL && size == 0) {
		errcode = EINVAL;
		goto errout;
	}

	/* My assumption is that if size is zero for modes {_IOFBF, _IOLBF} the
	 * caller is only attempting to change the buffering mode.  In this case,
	 * the existing buffer should be re-used (if there is one).  If there is no
	 * existing buffer, then I suppose we should allocate one of the default
	 * size?
	 */

	if ((mode == _IOFBF || mode == _IOLBF) && size == 0 && stream->fs_bufstart == NULL) {
		size = BUFSSIZ;
	}

	/* A non-zero size (or a non-NULL buffer) with mode = _IONBF makes no
	 * sense but is, apparently, permissible. We simply force the buffer to
	 * NULL and size to zero in this case without complaining.
	 */

	else if (mode == _IONBF) {
		buffer = NULL;
		size = 0;
	}

	/* Make sure that we have exclusive access to the stream */

	lib_take_semaphore(stream);

	/* setvbuf() may only be called AFTER the file has been opened and BEFORE
	 * any operations have been performed on the string.
	 */

	/* Return EBADF if the file is not open */

	if (stream->fs_fd < 0) {
		errcode = EBADF;
		goto errout_with_semaphore;
	}

	/* Return EBUSY if operations have already been performed on the buffer.
	 * Here we really only verify that there is no valid data in the existing
	 * buffer.
	 *
	 * REVIST:  There could be race conditions here, could there not?
	 */

	if (stream->fs_bufpos != stream->fs_bufstart) {
		errcode = EBUSY;
		goto errout_with_semaphore;
	}

	/* Initialize by clearing related flags.  We try to avoid any permanent
	 * changes to the stream structure until we know that we will be
	 * successful.
	 */

	flags = stream->fs_flags & ~(__FS_FLAG_LBF | __FS_FLAG_UBF);

	/* Allocate a new buffer if one is needed or reuse the existing buffer it
	 * is appropriate to do so.
	 */

	switch (mode) {
	case _IOLBF:
		flags |= __FS_FLAG_LBF;

		/* Fall through */

	case _IOFBF:
		/* Use the existing buffer if size == 0 */

		if (size > 0) {
			/* A new buffer is needed.  Did the caller provide the buffer
			 * memory?
			 */

			if (buffer != NULL) {
				newbuf = (FAR unsigned char *)buffer;

				/* Indicate that we have an I/O buffer managed by the caller of
				 * setvbuf.
				 */

				flags |= __FS_FLAG_UBF;
			} else {
				newbuf = (FAR unsigned char *)lib_malloc(size);
				if (newbuf == NULL) {
					errcode = ENOMEM;
					goto errout_with_semaphore;
				}
			}
		} else {
			/* Re-use the existing buffer and retain some existing flags.
			 * This supports changing the buffering mode without changing
			 * the buffer.
			 */

			DEBUGASSERT(stream->fs_bufstart != NULL);
			flags |= stream->fs_flags & __FS_FLAG_UBF;
			goto reuse_buffer;
		}

		break;

	case _IONBF:
		/* No buffer needed... We must be performing unbuffered I/O */

		newbuf = NULL;
		break;

	default:
		PANIC();
	}

	/* Do not release the previous buffer if it was allocated by the user
	 * on a previous call to setvbuf().
	 */

	if (stream->fs_bufstart != NULL && (stream->fs_flags & __FS_FLAG_UBF) == 0) {
		lib_free(stream->fs_bufstart);
	}

	/* Set the new buffer information */

	stream->fs_bufstart = newbuf;
	stream->fs_bufpos = newbuf;
	stream->fs_bufread = newbuf;
	stream->fs_bufend = newbuf + size;

	/* Update the stream flags and return success */

reuse_buffer:

	stream->fs_flags = flags;
	lib_give_semaphore(stream);
	return OK;

errout_with_semaphore:
	lib_give_semaphore(stream);

errout:
	set_errno(errcode);
	return ERROR;
}