From 6a14fe48c61536241f4071b75df0bf8773c72e42 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 18 Apr 2012 15:57:45 +0000 Subject: Disable line buffering if the file is opened in binary mode; Also fix a couple of fopen/fdopen bugs git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4630 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/ChangeLog | 7 ++ nuttx/fs/fs_fdopen.c | 2 +- nuttx/include/fcntl.h | 49 ++++---- nuttx/include/nuttx/fs/fs.h | 2 +- nuttx/include/sys/stat.h | 11 +- nuttx/lib/lib_internal.h | 5 + nuttx/lib/stdio/lib_fopen.c | 231 +++++++++++++++++++++++++++--------- nuttx/lib/stdio/lib_fputc.c | 4 +- nuttx/lib/stdio/lib_fputs.c | 4 +- nuttx/lib/stdio/lib_libnoflush.c | 4 +- nuttx/lib/stdio/lib_lowoutstream.c | 4 +- nuttx/lib/stdio/lib_memoutstream.c | 4 +- nuttx/lib/stdio/lib_nulloutstream.c | 4 +- nuttx/lib/stdio/lib_puts.c | 6 +- nuttx/lib/stdio/lib_rawoutstream.c | 4 +- nuttx/lib/stdio/lib_stdoutstream.c | 26 +++- 16 files changed, 263 insertions(+), 104 deletions(-) diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 6b30a3174..6457739f4 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -2663,4 +2663,11 @@ initial check-in is just a stm3210e-eval driver with renaming). * sched/sched_setscheduler.c: Correct successful return value (Contributed by Richard Cochran). + * include/fcntl.h and lib/stdio: Ignore CONFIG_STDIO_LINEBUFFER is the + file was opened in binary mode. + * lib/stdio/lib_fopen.c: Correct an error in parsing open mode string. The + plus sign may not appear right after the basic mode. For example, "r+", "rb+", + and "r+b" are all value open strings and mean the same thing. + * lib/stdio/lib_fopen.c: Correct return errno value from f_open() and + f_fdopen() if the open mode string is invalid. diff --git a/nuttx/fs/fs_fdopen.c b/nuttx/fs/fs_fdopen.c index 4d3f79894..9ee543a88 100644 --- a/nuttx/fs/fs_fdopen.c +++ b/nuttx/fs/fs_fdopen.c @@ -237,7 +237,7 @@ FAR struct file_struct *fs_fdopen(int fd, int oflags, FAR _TCB *tcb) */ stream->fs_filedes = fd; - stream->fs_oflags = oflags; + stream->fs_oflags = (uint16_t)oflags; sem_post(&slist->sl_sem); return stream; diff --git a/nuttx/include/fcntl.h b/nuttx/include/fcntl.h index b6440d085..1af4c3372 100644 --- a/nuttx/include/fcntl.h +++ b/nuttx/include/fcntl.h @@ -1,8 +1,8 @@ /******************************************************************************** * include/fcntl.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,24 +51,33 @@ /* open flag settings for open() (and related APIs) */ -#define O_RDONLY 0x01 /* Open for read access */ -#define O_WRONLY 0x02 /* Open for write access */ -#define O_RDWR 0x03 /* Open for both read & write access */ -#define O_CREAT 0x04 /* Create file/sem/mq object */ -#define O_EXCL 0x08 /* Name must not exist when opened */ -#define O_APPEND 0x10 /* Keep contents, append to end */ -#define O_TRUNC 0x20 /* Delete contents */ -#define O_NONBLOCK 0x40 /* Don't wait for data */ -#define O_NDELAY O_NONBLOCK -#define O_SYNC 0x80 /* Synchronize output on write */ -#define O_DSYNC O_SYNC - -#define O_RSYNC 0x00 /* Sychronize input on read */ -#define O_ACCMODE 0x00 /* Required by POSIX */ -#define O_NOCTTY 0x00 /* Reqired by POSIX */ - -#define O_RDOK O_RDONLY /* Not POSIX */ -#define O_WROK O_WRONLY /* Not POSIX */ +#define O_RDONLY (1 << 0) /* Open for read access (only) */ +#define O_RDOK O_RDONLY /* Read access is permitted (non-standard) */ +#define O_WRONLY (1 << 1) /* Open for write access (only) */ +#define O_WROK O_WRONLY /* Write access is permitted (non-standard) */ +#define O_RDWR (O_RDOK|O_WROK) /* Open for both read & write access */ +#define O_CREAT (1 << 2) /* Create file/sem/mq object */ +#define O_EXCL (1 << 3) /* Name must not exist when opened */ +#define O_APPEND (1 << 4) /* Keep contents, append to end */ +#define O_TRUNC (1 << 5) /* Delete contents */ +#define O_NONBLOCK (1 << 6) /* Don't wait for data */ +#define O_NDELAY O_NONBLOCK /* Synonym for O_NONBLOCK */ +#define O_SYNC (1 << 7) /* Synchronize output on write */ +#define O_DSYNC O_SYNC /* Equivalent to OSYNC in NuttX */ +#define O_BINARY (1 << 8) /* Open the file in binary (untranslated) mode. */ + +/* Unsupported, but required open flags */ + +#define O_RSYNC 0 /* Synchronize input on read */ +#define O_ACCMODE 0 /* Required by POSIX */ +#define O_NOCTTY 0 /* Required by POSIX */ +#defone O_TEXT 0 /* Open the file in text (translated) mode. */ + +/* This is the highest bit number used in the open flags bitset. Bits above + * this bit number may be used within NuttX for other, internal purposes. + */ + +#define _O_MAXBIT 8 /* fcntl() commands */ diff --git a/nuttx/include/nuttx/fs/fs.h b/nuttx/include/nuttx/fs/fs.h index 5b62e69d8..3f111a7b9 100644 --- a/nuttx/include/nuttx/fs/fs.h +++ b/nuttx/include/nuttx/fs/fs.h @@ -270,7 +270,7 @@ struct filelist struct file_struct { int fs_filedes; /* File descriptor associated with stream */ - mode_t fs_oflags; /* Open mode flags */ + uint16_t fs_oflags; /* Open mode flags */ #if CONFIG_NUNGET_CHARS > 0 uint8_t fs_nungotten; /* The number of characters buffered for ungetc */ unsigned char fs_ungotten[CONFIG_NUNGET_CHARS]; diff --git a/nuttx/include/sys/stat.h b/nuttx/include/sys/stat.h index bb166e7e2..5aa827f86 100644 --- a/nuttx/include/sys/stat.h +++ b/nuttx/include/sys/stat.h @@ -1,8 +1,8 @@ /**************************************************************************** * include/sys/stat.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,10 +47,9 @@ * Definitions ****************************************************************************/ -/* mode_t bit settings (most of these do not apply to Nuttx). - * This assumes that the full size of a mode_t is 16-bits. - * (However, mode_t must be size 'int' because it is promoted - * to size int when passed in varargs). +/* mode_t bit settings (most of these do not apply to Nuttx). This assumes + * that the full size of a mode_t is 16-bits. (However, mode_t must be size + * 'int' because it is promoted to size int when passed in varargs). */ #define S_IXOTH 0000001 /* Permissions for others: RWX */ diff --git a/nuttx/lib/lib_internal.h b/nuttx/lib/lib_internal.h index 29d49303d..c3d9bfd18 100644 --- a/nuttx/lib/lib_internal.h +++ b/nuttx/lib/lib_internal.h @@ -53,6 +53,11 @@ /**************************************************************************** * Definitions ****************************************************************************/ +/* This configuration directory is used in environment variable processing + * when we need to reference the user's home directory. There are no user + * directories in NuttX so, by default, this always refers to the root + * directory. + */ #ifndef CONFIG_LIB_HOMEDIR # define CONFIG_LIB_HOMEDIR "/" diff --git a/nuttx/lib/stdio/lib_fopen.c b/nuttx/lib/stdio/lib_fopen.c index f90951fe2..52e44c59d 100644 --- a/nuttx/lib/stdio/lib_fopen.c +++ b/nuttx/lib/stdio/lib_fopen.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_fopen.c * - * Copyright (C) 2007-2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,6 +48,25 @@ #include "lib_internal.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum open_mode_e +{ + MODE_NONE = 0, /* No access mode determined */ + MODE_R, /* "r" or "rb" open for reading */ + MODE_W, /* "w" or "wb" open for writing, truncating or creating file */ + MODE_A, /* "a" or "ab" open for writing, appending to file */ + MODE_RPLUS, /* "r+", "rb+", or "r+b" open for update (reading and writing) */ + MODE_WPLUS, /* "w+", "wb+", or "w+b" open for update, truncating or creating file */ + MODE_APLUS, /* "a+", "ab+", or "a+b" open for update, appending to file */ +}; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -58,77 +77,159 @@ static int lib_mode2oflags(FAR const char *mode) { - int oflags = 0; - if (mode) + enum open_mode_e state; + int oflags; + + /* Verify that a mode string was provided. No error is */ + + if (!mode) + { + goto errout; + } + + /* Parse the mode string to determine the corresponding open flags */ + + state = MODE_NONE; + oflags = 0; + + for (; *mode; mode++) { - while(*mode) + switch (*mode) { - switch (*mode) - { - /* Open for read access */ + /* Open for read access ("r", "r[+]", "r[b]", "r[b+]", or "r[+b]") */ - case 'r' : - if (*(mode + 1) == '+') - { - /* Open for read/write access */ + case 'r' : + if (state == MODE_NONE) + { + /* Open for read access */ - oflags |= O_RDWR; - mode++; - } - else - { - /* Open for read access */ + oflags = O_RDOK; + state = MODE_R; + } + else + { + goto errout; + } + break; - oflags |= O_RDOK; - } - break; + /* Open for write access ("w", "w[+]", "w[b]", "w[b+]", or "w[+b]") */ - /* Open for write access? */ + case 'w' : + if (state == MODE_NONE) + { + /* Open for write access, truncating any existing file */ - case 'w' : - if (*(mode + 1) == '+') - { - /* Open for write read/access, truncating any existing file */ + oflags = O_WROK|O_CREAT|O_TRUNC; + state = MODE_W; + } + else + { + goto errout; + } + break; - oflags |= O_RDWR|O_CREAT|O_TRUNC; - mode++; - } - else - { - /* Open for write access, truncating any existing file */ + /* Open for write/append access ("a", "a[+]", "a[b]", "a[b+]", or "a[+b]") */ - oflags |= O_WROK|O_CREAT|O_TRUNC; - } - break; + case 'a' : + if (state == MODE_NONE) + { + /* Write to the end of the file */ + + oflags = O_WROK|O_CREAT|O_APPEND; + state = MODE_A; + } + else + { + goto errout; + } + break; - /* Open for write/append access? */ + /* Open for update access ("[r]+", "[rb]+]", "[r]+[b]", "[w]+", + * "[wb]+]", "[w]+[b]", "[a]+", "[ab]+]", "[a]+[b]") + */ - case 'a' : - if (*(mode + 1) == '+') - { - /* Read from the beginning of the file; write to the end */ + case '+' : + switch (state) + { + case MODE_R: + { + /* Retain any binary mode selection */ - oflags |= O_RDWR|O_CREAT|O_APPEND; - mode++; - } - else - { - /* Write to the end of the file */ + oflags &= O_BINARY; - oflags |= O_WROK|O_CREAT|O_APPEND; + /* Open for read/write access */ + + oflags |= O_RDWR; + state = MODE_RPLUS; } - break; + break; + + case MODE_W: + { + /* Retain any binary mode selection */ + + oflags &= O_BINARY; + + /* Open for write read/access, truncating any existing file */ + + oflags |= O_RDWR|O_CREAT|O_TRUNC; + state = MODE_WPLUS; + } + break; - /* Open for binary access? */ + case MODE_A: + { + /* Retain any binary mode selection */ - case 'b' : - default: - break; - } - mode++; + oflags &= O_BINARY; + + /* Read from the beginning of the file; write to the end */ + + oflags |= O_RDWR|O_CREAT|O_APPEND; + state = MODE_APLUS; + } + break; + + default: + goto errout; + break; + } + break; + + /* Open for binary access ("[r]b", "[r]b[+]", "[r+]b", "[w]b", + * "[w]b[+]", "[w+]b", "[a]b", "[a]b[+]", "[a+]b") + */ + + case 'b' : + if (state != MODE_NONE) + { + /* The file is opened in binary mode */ + + oflags |= O_BINARY; + } + else + { + goto errout; + } + break; + + /* Unrecognized or unsupported mode */ + + default: + goto errout; + break; } } + return oflags; + +/* Both fopen and fdopen should fail with errno == EINVAL if the mode + * string is invalid. + */ + +errout: + set_errno(EINVAL); + return ERROR; } /**************************************************************************** @@ -141,7 +242,18 @@ static int lib_mode2oflags(FAR const char *mode) FAR FILE *fdopen(int fd, FAR const char *mode) { - return fs_fdopen(fd, lib_mode2oflags(mode), NULL); + FAR FILE *ret = NULL; + int oflags; + + /* Map the open mode string to open flags */ + + oflags = lib_mode2oflags(mode); + if (oflags >= 0) + { + ret = fs_fdopen(fd, oflags, NULL); + } + + return ret; } /**************************************************************************** @@ -154,9 +266,16 @@ FAR FILE *fopen(FAR const char *path, FAR const char *mode) int oflags; int fd; - /* Open the file */ + /* Map the open mode string to open flags */ oflags = lib_mode2oflags(mode); + if (oflags < 0) + { + return NULL; + } + + /* Open the file */ + fd = open(path, oflags, 0666); /* If the open was successful, then fdopen() the fil using the file diff --git a/nuttx/lib/stdio/lib_fputc.c b/nuttx/lib/stdio/lib_fputc.c index 917fcc10a..121161f10 100644 --- a/nuttx/lib/stdio/lib_fputc.c +++ b/nuttx/lib/stdio/lib_fputc.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_fputc.c * - * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007, 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fputs.c b/nuttx/lib/stdio/lib_fputs.c index 34d12c15e..2d6217d4a 100644 --- a/nuttx/lib/stdio/lib_fputs.c +++ b/nuttx/lib/stdio/lib_fputs.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_fputs.c * - * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007, 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_libnoflush.c b/nuttx/lib/stdio/lib_libnoflush.c index 370a1e8f7..e3b891153 100644 --- a/nuttx/lib/stdio/lib_libnoflush.c +++ b/nuttx/lib/stdio/lib_libnoflush.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_libnoflush.c * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_lowoutstream.c b/nuttx/lib/stdio/lib_lowoutstream.c index 3b3d467b2..726bd84d7 100644 --- a/nuttx/lib/stdio/lib_lowoutstream.c +++ b/nuttx/lib/stdio/lib_lowoutstream.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_lowoutstream.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_memoutstream.c b/nuttx/lib/stdio/lib_memoutstream.c index dca8456e8..007ab8976 100644 --- a/nuttx/lib/stdio/lib_memoutstream.c +++ b/nuttx/lib/stdio/lib_memoutstream.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_memoutstream.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_nulloutstream.c b/nuttx/lib/stdio/lib_nulloutstream.c index f92cb0f33..520df459e 100644 --- a/nuttx/lib/stdio/lib_nulloutstream.c +++ b/nuttx/lib/stdio/lib_nulloutstream.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_nulloutstream.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_puts.c b/nuttx/lib/stdio/lib_puts.c index 088d0f043..e63a63917 100644 --- a/nuttx/lib/stdio/lib_puts.c +++ b/nuttx/lib/stdio/lib_puts.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_puts.c * - * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007, 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -112,7 +112,7 @@ int puts(FAR const char *s) { nput = nwritten + 1; - /* Flush the buffer after the newline is output */ + /* Flush the buffer after the newline is output. */ #ifdef CONFIG_STDIO_LINEBUFFER ret = lib_fflush(stream, true); diff --git a/nuttx/lib/stdio/lib_rawoutstream.c b/nuttx/lib/stdio/lib_rawoutstream.c index bea47f3ce..ce9d33280 100644 --- a/nuttx/lib/stdio/lib_rawoutstream.c +++ b/nuttx/lib/stdio/lib_rawoutstream.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_rawoutstream.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_stdoutstream.c b/nuttx/lib/stdio/lib_stdoutstream.c index 99fae11b2..12e78ce53 100644 --- a/nuttx/lib/stdio/lib_stdoutstream.c +++ b/nuttx/lib/stdio/lib_stdoutstream.c @@ -37,6 +37,8 @@ * Included Files ****************************************************************************/ +#include + #include "lib_internal.h" /**************************************************************************** @@ -95,14 +97,32 @@ int stdoutstream_flush(FAR struct lib_outstream_s *this) void lib_stdoutstream(FAR struct lib_stdoutstream_s *stdoutstream, FAR FILE *stream) { + /* Select the put operation */ + stdoutstream->public.put = stdoutstream_putc; + + /* Select the correct flush operation. This flush is only called when + * a newline is encountered in the output stream. However, we do not + * want to support this line buffering behavior if the stream was + * opened in binary mode. In binary mode, the newline has no special + * meaning. + */ + #ifdef CONFIG_STDIO_LINEBUFFER #if CONFIG_STDIO_BUFFER_SIZE > 0 - stdoutstream->public.flush = stdoutstream_flush; -#else - stdoutstream->public.flush = lib_noflush; + if ((stream->fs_oflags & O_BINARY) == 0) + { + stdoutstream->public.flush = stdoutstream_flush; + } + else #endif + { + stdoutstream->public.flush = lib_noflush; + } #endif + + /* Set the number of bytes put to zero and remember the stream */ + stdoutstream->public.nput = 0; stdoutstream->stream = stream; } -- cgit v1.2.3