changeset 2949:ae816c83f082

* include/string.h: Declare strnlen. * include/stringsupp.hxx: Declare __strnlen. * src/strnlen.cxx, tests/strnlen.c: Created. * cdl/string.cdl (CYGFUN_LIBC_STRING_GNU_STRNLEN): New option, compiles strnlen.cxx. (CYGPKG_LIBC_STRING_TESTS): Add strnlen test.
author jlarmour
date Tue, 11 May 2010 16:26:19 +0000
parents 041821fb5427
children dc8e6a281225
files packages/language/c/libc/string/current/ChangeLog packages/language/c/libc/string/current/cdl/string.cdl packages/language/c/libc/string/current/include/string.h packages/language/c/libc/string/current/include/stringsupp.hxx packages/language/c/libc/string/current/src/strnlen.cxx packages/language/c/libc/string/current/tests/strnlen.c
diffstat 6 files changed, 303 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/packages/language/c/libc/string/current/ChangeLog
+++ b/packages/language/c/libc/string/current/ChangeLog
@@ -1,3 +1,12 @@
+2010-05-10  Ross Younger  <wry@ecoscentric.com>
+
+	* include/string.h: Declare strnlen.
+	* include/stringsupp.hxx: Declare __strnlen.
+	* src/strnlen.cxx, tests/strnlen.c: Created.
+	* cdl/string.cdl (CYGFUN_LIBC_STRING_GNU_STRNLEN): New option,
+	compiles strnlen.cxx.
+	(CYGPKG_LIBC_STRING_TESTS): Add strnlen test.
+
 2009-01-26  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* tests/memchr.c (main): Rename to cyg_user_start if main isn't
--- a/packages/language/c/libc/string/current/cdl/string.cdl
+++ b/packages/language/c/libc/string/current/cdl/string.cdl
@@ -166,6 +166,16 @@ cdl_package CYGPKG_LIBC_STRING {
                 This option indicates whether strdup() is to be supported."
     }
 
+    cdl_option CYGFUN_LIBC_STRING_GNU_STRNLEN {
+        display       "Provide strnlen() GNU extension"
+        flavor        bool
+        default_value 1
+        compile       strnlen.cxx
+        description   "
+            This option controls support for the strnlen() function.
+            (This is a GNU extension, not part of ANSI C.)"
+    }
+
     cdl_component CYGPKG_LIBC_STRING_OPTIONS {
         display "C library string functions build options"
         flavor  none
@@ -202,7 +212,7 @@ cdl_package CYGPKG_LIBC_STRING {
             display "C library string function tests"
             flavor  data
             no_define
-            calculated { "tests/memchr tests/memcmp1 tests/memcmp2 tests/memcpy1 tests/memcpy2 tests/memmove1 tests/memmove2 tests/memset tests/strcat1 tests/strcat2 tests/strchr tests/strcmp1 tests/strcmp2 tests/strcoll1 tests/strcoll2 tests/strcpy1 tests/strcpy2 tests/strcspn tests/strcspn tests/strlen tests/strncat1 tests/strncat2 tests/strncpy1 tests/strncpy2 tests/strpbrk tests/strrchr tests/strspn tests/strstr tests/strtok tests/strxfrm1 tests/strxfrm2" }
+            calculated { "tests/memchr tests/memcmp1 tests/memcmp2 tests/memcpy1 tests/memcpy2 tests/memmove1 tests/memmove2 tests/memset tests/strcat1 tests/strcat2 tests/strchr tests/strcmp1 tests/strcmp2 tests/strcoll1 tests/strcoll2 tests/strcpy1 tests/strcpy2 tests/strcspn tests/strcspn tests/strlen tests/strncat1 tests/strncat2 tests/strncpy1 tests/strncpy2 tests/strpbrk tests/strrchr tests/strspn tests/strstr tests/strtok tests/strxfrm1 tests/strxfrm2 tests/strnlen" }
             description   "
                 This option specifies the set of tests for the C library
                 string functions."
--- a/packages/language/c/libc/string/current/include/string.h
+++ b/packages/language/c/libc/string/current/include/string.h
@@ -155,6 +155,14 @@ extern char *
 strdup( const char * );
 #endif
 
+// This is a GNU extension
+#ifndef __STRICT_ANSI__
+# ifdef CYGFUN_LIBC_STRING_GNU_STRNLEN
+extern size_t
+strnlen( const char *, size_t );
+# endif
+#endif
+
 #ifdef __cplusplus
 }   /* extern "C" */
 #endif
--- a/packages/language/c/libc/string/current/include/stringsupp.hxx
+++ b/packages/language/c/libc/string/current/include/stringsupp.hxx
@@ -212,6 +212,14 @@
 __externC char *
 __strdup( const char * );
 
+// NB This is a GNU extension
+#ifndef __STRICT_ANSI__
+# ifdef CYGFUN_LIBC_STRING_GNU_STRNLEN
+__externC size_t
+__strnlen( const char *, size_t );
+# endif
+#endif
+
 #endif // CYGONCE_LIBC_STRING_STRINGSUPP_HXX multiple inclusion protection
 
 // EOF stringsupp.hxx
new file mode 100644
--- /dev/null
+++ b/packages/language/c/libc/string/current/src/strnlen.cxx
@@ -0,0 +1,134 @@
+//===========================================================================
+//
+//      strnlen.cxx
+//
+//      GNU extension strnlen() routine
+//
+//===========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998-2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//===========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    jlarmour, wry
+// Contributors: 
+// Date:         2010-05-10
+// Purpose:     
+// Description: 
+// Usage:       
+// Note:         Derivative work of strlen.cxx.
+//
+//####DESCRIPTIONEND####
+//
+//===========================================================================
+
+// CONFIGURATION
+
+#include <pkgconf/libc_string.h>   // Configuration header
+
+// INCLUDES
+
+#include <cyg/infra/cyg_type.h>    // Common type definitions
+#include <cyg/infra/cyg_trac.h>    // Tracing support
+#include <cyg/infra/cyg_ass.h>     // Assertion support
+#include <string.h>                // Header for this file
+#include <stddef.h>         // Compiler definitions such as size_t, NULL etc.
+#include <cyg/libc/string/stringsupp.hxx> // Useful string function support and
+                                          // prototypes
+
+// EXPORTED SYMBOLS
+
+externC size_t
+strnlen( const char *s , size_t maxlen ) CYGBLD_ATTRIB_WEAK_ALIAS(__strnlen);
+
+// FUNCTIONS
+
+size_t
+__strnlen( const char *s , size_t maxlen )
+{
+    int retval;
+    
+    CYG_REPORT_FUNCNAMETYPE( "__strnlen", "returning length %d" );
+    CYG_REPORT_FUNCARG1( "s=%08x", s );
+
+    CYG_CHECK_DATA_PTR( s, "s is not a valid pointer!" );
+
+#if defined(CYGIMP_LIBC_STRING_PREFER_SMALL_TO_FAST) || defined(__OPTIMIZE_SIZE__)
+    const char *start = s;
+    
+    while (*s && maxlen)
+        s++, maxlen--;
+    
+    retval = s - start;
+
+    CYG_REPORT_RETVAL( retval );
+
+    return retval;
+
+#else
+
+    const char *start = s;
+    CYG_WORD *aligned_addr;
+    
+    if (CYG_LIBC_STR_UNALIGNED (s))
+    {
+        while (*s && maxlen)
+            s++, maxlen--;
+        retval = s - start;
+
+        CYG_REPORT_RETVAL( retval );
+    
+        return retval;
+    }
+    
+    // If the string is word-aligned, we can check for the presence of 
+    // a null in each word-sized block.
+    
+    aligned_addr = (CYG_WORD *)s;
+    while (!CYG_LIBC_STR_DETECTNULL (*aligned_addr) && (maxlen>= sizeof(CYG_WORD)))
+        aligned_addr++, maxlen -= sizeof(CYG_WORD);
+    
+    // Once a null is detected, we check each byte in that block for a
+    // precise position of the null.
+    s = (char*)aligned_addr; 
+    while (*s && maxlen)
+        s++, maxlen--;
+    retval = s - start;
+
+    CYG_REPORT_RETVAL( retval );
+    
+    return retval;
+#endif // not defined(CYGIMP_LIBC_STRING_PREFER_SMALL_TO_FAST) ||
+       //     defined(__OPTIMIZE_SIZE__)
+} // __strnlen()
+
+// EOF strnlen.cxx
new file mode 100644
--- /dev/null
+++ b/packages/language/c/libc/string/current/tests/strnlen.c
@@ -0,0 +1,133 @@
+//=================================================================
+//
+//        strnlen.c
+//
+//        Testcase for C library strnlen()
+//
+//=================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2010 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//=================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     wry
+// Contributors:  
+// Date:          2010-05-10
+// Description:   Testing for C library strnlen() function
+//
+//
+//####DESCRIPTIONEND####
+
+// INCLUDES
+
+#include <pkgconf/isoinfra.h>
+#include <string.h>
+#include <stdarg.h>
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/libc/string/stringsupp.hxx>
+
+
+// FUNCTIONS
+
+void test_guts(char *buf, size_t real_len, size_t arg, size_t expected, int *nfails, int *ncases)
+{
+#if 0
+    // printf takes too much memory on some boards.
+    //diag_printf("testcase: buf `%s', len %u, n %u, expect %u\n", buf, real_len, arg, expected);
+#endif
+    size_t rv = strnlen(buf, arg);
+    if (rv != expected) {
+        CYG_TEST_FAIL("incorrect answer from strnlen case");
+#if 0
+        diag_printf("incorrect answer %u from case %u:%u (expected %u)", rv, real_len, arg, expected);
+#endif
+        ++*nfails;
+    }
+    ++*ncases;
+}
+
+void test(size_t strsize, int * nfails, int * ncases)
+{
+    int j;
+    char testbuf[1024];
+
+    CYG_ASSERTC(strsize <= sizeof(testbuf));
+    // Insist on checking the aligned-path code.
+    CYG_ASSERTC(!(CYG_LIBC_STR_UNALIGNED(testbuf)));
+
+    memset(testbuf, 'A', strsize);
+    testbuf[strsize] = 0;
+
+    for (j=1; j<(1+4*sizeof(CYG_WORD)) && j<=strsize; j++) {
+        // condition `j<=strsize' prevents underflow.
+        test_guts(testbuf, strsize, strsize-j, strsize-j, nfails, ncases);
+    }
+    for (j=0; j<(1+4*sizeof(CYG_WORD)); j++) {
+        test_guts(testbuf, strsize, strsize+j, strsize, nfails, ncases);
+    }
+}
+
+
+#if CYGINT_ISO_MAIN_STARTUP
+int main( int argc, char *argv[] )
+#else
+void cyg_user_start(void)
+#endif
+{
+#ifndef CYGFUN_LIBC_STRING_GNU_STRNLEN
+    CYG_TEST_NA("strnlen / CYGFUN_LIBC_STRING_GNU_STRNLEN disabled");
+#else
+
+    CYG_TEST_INIT();
+    CYG_TEST_INFO("strnlen exhaustive testing");
+#if defined(CYGIMP_LIBC_STRING_PREFER_SMALL_TO_FAST)
+    CYG_TEST_INFO("strnlen: NOTE: CYGIMP_LIBC_STRING_PREFER_SMALL_TO_FAST is defined");
+#endif
+
+    int t, nfails=0, ncases=0;
+
+#define DO(x) do { test(x, &nfails, &ncases); } while(0)
+    for (t=0; t<40; t++) DO(t);
+
+#if 0
+    diag_printf("strnlen: %u/%u cases passed", (ncases-nfails), ncases);
+#endif
+    if (!nfails) CYG_TEST_PASS("strnlen");
+    CYG_TEST_FINISH("strnlen");
+
+#endif
+} // main()
+
+
+// EOF strlen.c