summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-01-08 10:47:34 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-01-08 10:47:34 -0600
commiteaaec3ec0947c82d1d94039fb25c57fa33134b87 (patch)
treef935b9c7943b8026b8553debd37e32685ea9a9d6
parent5f5b6293926e29c6c2101f8921c808333260b9b9 (diff)
downloadpx4-nuttx-eaaec3ec0947c82d1d94039fb25c57fa33134b87.tar.gz
px4-nuttx-eaaec3ec0947c82d1d94039fb25c57fa33134b87.tar.bz2
px4-nuttx-eaaec3ec0947c82d1d94039fb25c57fa33134b87.zip
Add lib_libfgets() to better support the small differences between gets(), gets_s(), and fgets()
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/libc/lib_internal.h7
-rw-r--r--nuttx/libc/stdio/Make.defs11
-rw-r--r--nuttx/libc/stdio/lib_fgets.c143
-rw-r--r--nuttx/libc/stdio/lib_gets.c57
-rw-r--r--nuttx/libc/stdio/lib_gets_s.c66
-rw-r--r--nuttx/libc/stdio/lib_libfgets.c252
7 files changed, 297 insertions, 242 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index cfe4e52c2..ef93b992c 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -6390,4 +6390,7 @@
("x") (2014-1-7)
* include/threads.h: First crude cut at a C11 threads.h header
file (just maps to pthreads) (2014-1-7).
+ * libc/stdio/lib_libfgets.c: Common implementation supports all
+ of the slightly different requirements of gets(), gets_s(), and
+ fgets() (2014-1-7).
diff --git a/nuttx/libc/lib_internal.h b/nuttx/libc/lib_internal.h
index ae6ec7b06..bf73b72a4 100644
--- a/nuttx/libc/lib_internal.h
+++ b/nuttx/libc/lib_internal.h
@@ -1,7 +1,7 @@
/****************************************************************************
* libc/lib_internal.h
*
- * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -184,6 +184,11 @@ ssize_t lib_fwrite(FAR const void *ptr, size_t count, FAR FILE *stream);
ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream);
+/* Defined in lib_libfgets.c */
+
+FAR char *lib_fgets(FAR char *buf, int buflen, FILE *stream,
+ bool keepnl, bool consume);
+
/* Defined in lib_libfflush.c */
ssize_t lib_fflush(FAR FILE *stream, bool bforce);
diff --git a/nuttx/libc/stdio/Make.defs b/nuttx/libc/stdio/Make.defs
index 2a6ea8563..c0a523091 100644
--- a/nuttx/libc/stdio/Make.defs
+++ b/nuttx/libc/stdio/Make.defs
@@ -57,11 +57,12 @@ ifneq ($(CONFIG_NFILE_STREAMS),0)
CSRCS += lib_fopen.c lib_fclose.c lib_fread.c lib_libfread.c lib_fseek.c
CSRCS += lib_ftell.c lib_fsetpos.c lib_fgetpos.c lib_fgetc.c lib_fgets.c
-CSRCS += lib_gets_s.c lib_gets.c lib_fwrite.c lib_libfwrite.c lib_fflush.c
-CSRCS += lib_libflushall.c lib_libfflush.c lib_rdflush.c lib_wrflush.c
-CSRCS += lib_fputc.c lib_puts.c lib_fputs.c lib_ungetc.c lib_vprintf.c
-CSRCS += lib_fprintf.c lib_vfprintf.c lib_stdinstream.c lib_stdoutstream.c
-CSRCS += lib_perror.c lib_feof.c lib_ferror.c lib_clearerr.c
+CSRCS += lib_gets_s.c lib_gets.c lib_libfgets.c lib_fwrite.c lib_libfwrite.c
+CSRCS += lib_fflush.c lib_libflushall.c lib_libfflush.c lib_rdflush.c
+CSRCS += lib_wrflush.c lib_fputc.c lib_puts.c lib_fputs.c lib_ungetc.c
+CSRCS += lib_vprintf.c lib_fprintf.c lib_vfprintf.c lib_stdinstream.c
+CSRCS += lib_stdoutstream.c lib_perror.c lib_feof.c lib_ferror.c
+CSRCS += lib_clearerr.c
endif
endif
diff --git a/nuttx/libc/stdio/lib_fgets.c b/nuttx/libc/stdio/lib_fgets.c
index 198e44be5..3aff54db9 100644
--- a/nuttx/libc/stdio/lib_fgets.c
+++ b/nuttx/libc/stdio/lib_fgets.c
@@ -1,7 +1,7 @@
/****************************************************************************
* libc/stdio/lib_fgets.c
*
- * Copyright (C) 2007-2008, 2011-2013 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2008, 2011-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -39,58 +39,12 @@
#include <nuttx/config.h>
-#include <stdbool.h>
#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <debug.h>
-/****************************************************************************
- * Definitions
- ****************************************************************************/
-/* Some environments may return CR as end-of-line, others LF, and others
- * both. If not specified, the logic here assumes either (but not both) as
- * the default.
- */
-
-#if defined(CONFIG_EOL_IS_CR)
-# undef CONFIG_EOL_IS_LF
-# undef CONFIG_EOL_IS_BOTH_CRLF
-# undef CONFIG_EOL_IS_EITHER_CRLF
-#elif defined(CONFIG_EOL_IS_LF)
-# undef CONFIG_EOL_IS_CR
-# undef CONFIG_EOL_IS_BOTH_CRLF
-# undef CONFIG_EOL_IS_EITHER_CRLF
-#elif defined(CONFIG_EOL_IS_BOTH_CRLF)
-# undef CONFIG_EOL_IS_CR
-# undef CONFIG_EOL_IS_LF
-# undef CONFIG_EOL_IS_EITHER_CRLF
-#elif defined(CONFIG_EOL_IS_EITHER_CRLF)
-# undef CONFIG_EOL_IS_CR
-# undef CONFIG_EOL_IS_LF
-# undef CONFIG_EOL_IS_BOTH_CRLF
-#else
-# undef CONFIG_EOL_IS_CR
-# undef CONFIG_EOL_IS_LF
-# undef CONFIG_EOL_IS_BOTH_CRLF
-# define CONFIG_EOL_IS_EITHER_CRLF 1
-#endif
-
-/****************************************************************************
- * Private Type Declarations
- ****************************************************************************/
+#include "lib_internal.h"
/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
+ * Pre-processor Definitions
****************************************************************************/
/****************************************************************************
@@ -98,7 +52,7 @@
****************************************************************************/
/****************************************************************************
- * Global Functions
+ * Public Functions
****************************************************************************/
/****************************************************************************
@@ -115,92 +69,7 @@
char *fgets(FAR char *buf, int buflen, FILE *stream)
{
- int nch = 0;
-
- /* Sanity checks */
-
- if (!stream || !buf || buflen < 1 || stream->fs_fd < 0)
- {
- return NULL;
- }
-
- if (buflen < 2)
- {
- *buf = '\0';
- return buf;
- }
-
- /* Read characters until we have a full line. On each the loop we must
- * be assured that there are two free bytes in the line buffer: One for
- * the next character and one for the null terminator.
- */
-
- for(;;)
- {
- /* Get the next character */
-
- int ch = fgetc(stream);
-
- /* Check for end-of-line. This is tricky only in that some
- * environments may return CR as end-of-line, others LF, and
- * others both.
- */
-
-#if defined(CONFIG_EOL_IS_LF) || defined(CONFIG_EOL_IS_BOTH_CRLF)
- if (ch == '\n')
-#elif defined(CONFIG_EOL_IS_CR)
- if (ch == '\r')
-#else /* elif defined(CONFIG_EOL_IS_EITHER_CRLF) */
- if (ch == '\n' || ch == '\r')
-#endif
- {
- /* The newline is stored in the buffer along with the null
- * terminator.
- */
-
- buf[nch++] = '\n';
- buf[nch] = '\0';
- return buf;
- }
-
- /* Check for end-of-file */
-
- else if (ch == EOF)
- {
- /* End of file with no data? */
-
- if (!nch)
- {
- /* Yes.. return NULL as the end of file mark */
-
- return NULL;
- }
- else
- {
- /* Terminate the line */
-
- buf[nch] = '\0';
- return buf;
- }
- }
-
- /* Otherwise, check if the character is printable and, if so, put the
- * character in the line buffer
- */
-
- else if (isprint(ch))
- {
- buf[nch++] = ch;
-
- /* Check if there is room for another character and the line's
- * null terminator. If not then we have to end the line now.
- */
+ /* Let lib_fgets() do the heavy lifting */
- if (nch + 1 >= buflen)
- {
- buf[nch] = '\0';
- return buf;
- }
- }
- }
+ return lib_fgets(buf, buflen, stream, true, false);
}
diff --git a/nuttx/libc/stdio/lib_gets.c b/nuttx/libc/stdio/lib_gets.c
index 39c31d273..e9e36987b 100644
--- a/nuttx/libc/stdio/lib_gets.c
+++ b/nuttx/libc/stdio/lib_gets.c
@@ -37,40 +37,15 @@
* Included Files
****************************************************************************/
-#include <stdio.h>
-#include <limits.h>
-#include <string.h>
-
-/****************************************************************************
- * Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Type Declarations
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Global Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Global Constant Data
- ****************************************************************************/
+#include <nuttx/config.h>
-/****************************************************************************
- * Global Variables
- ****************************************************************************/
+#include <stdint.h>
+#include <stdio.h>
-/****************************************************************************
- * Private Constant Data
- ****************************************************************************/
+#include "lib_internal.h"
/****************************************************************************
- * Private Variables
+ * Pre-processor Definitions
****************************************************************************/
/****************************************************************************
@@ -96,25 +71,7 @@
FAR char *gets(FAR char *s)
{
- /* gets is ALMOST the same as fgets using stdin and no length limit
- * (hence, the unsafeness of gets). So let fgets do most of the work.
- */
+ /* Let lib_fgets() do the heavy lifting */
- FAR char *ret = fgets(s, INT_MAX, stdin);
- if (ret)
- {
- /* Another subtle difference from fgets is that gets replaces
- * end-of-line markers with null terminators. We will do that as
- * a second step (with some loss in performance).
- */
-
- int len = strlen(ret);
- if (len > 0 && ret[len-1] == '\n')
- {
- ret[len-1] = '\0';
- }
- }
-
- return ret;
+ return lib_fgets(s, RSIZE_MAX, stdin, false, false);
}
-
diff --git a/nuttx/libc/stdio/lib_gets_s.c b/nuttx/libc/stdio/lib_gets_s.c
index 95816b080..3f9ecc0cb 100644
--- a/nuttx/libc/stdio/lib_gets_s.c
+++ b/nuttx/libc/stdio/lib_gets_s.c
@@ -37,40 +37,15 @@
* Included Files
****************************************************************************/
-#include <stdio.h>
-#include <limits.h>
-#include <string.h>
-
-/****************************************************************************
- * Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Type Declarations
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Global Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Global Constant Data
- ****************************************************************************/
+#include <nuttx/config.h>
-/****************************************************************************
- * Global Variables
- ****************************************************************************/
+#include <stdio.h>
+#include <stdint.h>
-/****************************************************************************
- * Private Constant Data
- ****************************************************************************/
+#include "lib_internal.h"
/****************************************************************************
- * Private Variables
+ * Pre-processor Definitions
****************************************************************************/
/****************************************************************************
@@ -88,9 +63,10 @@
* gets() reads a line from stdin into the buffer pointed to by s until
* either a terminating newline or EOF, which it replaces with '\0'. Reads
* at most n-1 characters from stdin into the array pointed to by str until
- * new-line character, end-of-file condition, or read error. A null
- * character is written immediately after the last character read into the
- * array, or to str[0] if no characters were read.
+ * new-line character, end-of-file condition, or read error. The newline
+ * character, if encountered, is not saved in the arraay. A NUL character
+ * is written immediately after the last character read into the array, or
+ * to str[0] if no characters were read.
*
* If n is zero or is greater than RSIZE_MAX, a null character is written
* to str[0] but the function reads and discards characters from stdin
@@ -99,30 +75,22 @@
*
* If n-1 characters have been read, continues reading and discarding the
* characters from stdin until new-line character, end-of-file condition,
- * or read error (not implemented).
+ * or read error.
*
**************************************************************************/
FAR char *gets_s(FAR char *s, rsize_t n)
{
- /* gets is equivalent to fgets using stdin. So let fgets do most of the
- * work.
- */
+ /* Handle the case where n is out of range as required */
- FAR char *ret = fgets(s, n, stdin);
- if (ret)
+ if (n < 1 || n > RSIZE_MAX)
{
- /* A subtle difference from fgets is that gets_s replaces end-of-line
- * markers with null terminators. We will do that as a second step
- * (with some loss in performance).
- */
+ /* Set n=1, i.e., room only for the NUL terminator */
- int len = strlen(ret);
- if (len > 0 && ret[len-1] == '\n')
- {
- ret[len-1] = '\0';
- }
+ n = 1;
}
- return ret;
+ /* Then let lib_fgets() do the heavy lifting */
+
+ return lib_fgets(s, n, stdin, false, true);
}
diff --git a/nuttx/libc/stdio/lib_libfgets.c b/nuttx/libc/stdio/lib_libfgets.c
new file mode 100644
index 000000000..6a8cdeb44
--- /dev/null
+++ b/nuttx/libc/stdio/lib_libfgets.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+ * libc/stdio/lib_libfgets.c
+ *
+ * Copyright (C) 2007-2008, 2011-2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <debug.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Some environments may return CR as end-of-line, others LF, and others
+ * both. If not specified, the logic here assumes either (but not both) as
+ * the default.
+ */
+
+#if defined(CONFIG_EOL_IS_CR)
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_LF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_BOTH_CRLF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_EITHER_CRLF
+#elif defined(CONFIG_EOL_IS_EITHER_CRLF)
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+#else
+# undef CONFIG_EOL_IS_CR
+# undef CONFIG_EOL_IS_LF
+# undef CONFIG_EOL_IS_BOTH_CRLF
+# define CONFIG_EOL_IS_EITHER_CRLF 1
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: consume_eol
+ *
+ * Description:
+ * If 'consume' is true, then consume_eol() will read and discard bytes from
+ * 'stream' until an EOF or a newline encountered or until a read error
+ * occurs.
+ *
+ **************************************************************************/
+
+static void consume_eol(FILE *stream, bool consume)
+{
+ if (consume)
+ {
+ int ch;
+
+ do
+ {
+ ch = fgetc(stream);
+ }
+#if defined(CONFIG_EOL_IS_LF) || defined(CONFIG_EOL_IS_BOTH_CRLF)
+ while (ch != EOF && ch != '\n');
+#elif defined(CONFIG_EOL_IS_CR)
+ while (ch != EOF && ch != '\r');
+#else /* elif defined(CONFIG_EOL_IS_EITHER_CRLF) */
+ while (ch != EOF && ch != '\n' && ch != '\r');
+#endif
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_fgets
+ *
+ * Description:
+ * lib_fgets() implements the core logic for both fgets() and gets_s().
+ * lib_fgets() reads in at most one less than 'buflen' characters from
+ * stream and stores them into the buffer pointed to by 'buf'. Reading
+ * stops after an EOF or a newline encountered or after a read error
+ * occurs.
+ *
+ * If a newline is read, it is stored into the buffer only if 'keepnl' is
+ * set true. A null terminator is always stored after the last character
+ * in the buffer.
+ *
+ * If 'buflen'-1 bytes were read into 'buf' without encountering an EOF
+ * or newline then the following behavior depends on the value of
+ * 'consume': If consume is true, then lib_fgets() will continue reading
+ * bytes and discarding them until an EOF or a newline encountered or
+ * until a read error occurs. Otherwise, lib_fgets() returns with the
+ * remaining of the incoming stream buffer.
+ *
+ **************************************************************************/
+
+FAR char *lib_fgets(FAR char *buf, int buflen, FILE *stream,
+ bool keepnl, bool consume)
+{
+ int nch = 0;
+
+ /* Sanity checks */
+
+ if (!stream || !buf || stream->fs_fd < 0)
+ {
+ return NULL;
+ }
+
+ /* Make sure that we have a buffer and space for at least one character */
+
+ if (buflen < 1)
+ {
+ consume_eol(stream, consume);
+ return NULL;
+ }
+
+ /* Make sure that we have space for something in addition to the NUL
+ * terminator.
+ */
+
+ if (buflen < 2)
+ {
+ *buf = '\0';
+ consume_eol(stream, consume);
+ return buf;
+ }
+
+ /* Read characters until we have a full line. On each the loop we must
+ * be assured that there are two free bytes in the line buffer: One for
+ * the next character and one for the null terminator.
+ */
+
+ for(;;)
+ {
+ /* Get the next character */
+
+ int ch = fgetc(stream);
+
+ /* Check for end-of-line. This is tricky only in that some
+ * environments may return CR as end-of-line, others LF, and
+ * others both.
+ */
+
+#if defined(CONFIG_EOL_IS_LF) || defined(CONFIG_EOL_IS_BOTH_CRLF)
+ if (ch == '\n')
+#elif defined(CONFIG_EOL_IS_CR)
+ if (ch == '\r')
+#else /* elif defined(CONFIG_EOL_IS_EITHER_CRLF) */
+ if (ch == '\n' || ch == '\r')
+#endif
+ {
+ if (keepnl)
+ {
+ /* Store newline is stored in the buffer */
+
+ buf[nch++] = '\n';
+ }
+
+ /* Terminate the string */
+
+ buf[nch] = '\0';
+ return buf;
+ }
+
+ /* Check for end-of-file */
+
+ else if (ch == EOF)
+ {
+ /* End of file with no data? */
+
+ if (!nch)
+ {
+ /* Yes.. return NULL as the end of file mark */
+
+ return NULL;
+ }
+ else
+ {
+ /* No, terminate the accumulated string */
+
+ buf[nch] = '\0';
+ return buf;
+ }
+ }
+
+ /* Otherwise, check if the character is printable and, if so, put the
+ * character in the line buffer
+ */
+
+ else if (isprint(ch))
+ {
+ buf[nch++] = ch;
+
+ /* Check if there is room for another character and the line's
+ * NUL terminator. If not then we have to end the line now,
+ * perhaps consuming any data up to the end-of-line.
+ */
+
+ if (nch + 1 >= buflen)
+ {
+ buf[nch] = '\0';
+ consume_eol(stream, consume);
+ return buf;
+ }
+ }
+ }
+}