Index: ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/language/c/libc/string/current/ChangeLog,v retrieving revision 1.11 diff -u -5 -p -r1.11 ChangeLog --- ChangeLog 29 Jan 2009 17:49:53 -0000 1.11 +++ ChangeLog 11 May 2010 16:23:29 -0000 @@ -1,5 +1,14 @@ +2010-05-10 Ross Younger + + * 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 * tests/memchr.c (main): Rename to cyg_user_start if main isn't going to be called. * tests/memcmp1.c (main): Ditto. Index: cdl/string.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/language/c/libc/string/current/cdl/string.cdl,v retrieving revision 1.8 diff -u -5 -p -r1.8 string.cdl --- cdl/string.cdl 29 Jan 2009 17:49:53 -0000 1.8 +++ cdl/string.cdl 11 May 2010 16:23:29 -0000 @@ -164,10 +164,20 @@ cdl_package CYGPKG_LIBC_STRING { compile strdup.cxx description " 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 no_define description " @@ -200,11 +210,11 @@ cdl_package CYGPKG_LIBC_STRING { cdl_option CYGPKG_LIBC_STRING_TESTS { 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." } } Index: include/string.h =================================================================== RCS file: /cvs/ecos/ecos/packages/language/c/libc/string/current/include/string.h,v retrieving revision 1.5 diff -u -5 -p -r1.5 string.h --- include/string.h 29 Jan 2009 17:49:53 -0000 1.5 +++ include/string.h 11 May 2010 16:23:29 -0000 @@ -153,10 +153,18 @@ strlen( const char * ); #ifndef __STRICT_ANSI__ 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 /* INLINE FUNCTIONS */ Index: include/stringsupp.hxx =================================================================== RCS file: /cvs/ecos/ecos/packages/language/c/libc/string/current/include/stringsupp.hxx,v retrieving revision 1.5 diff -u -5 -p -r1.5 stringsupp.hxx --- include/stringsupp.hxx 29 Jan 2009 17:49:53 -0000 1.5 +++ include/stringsupp.hxx 11 May 2010 16:23:29 -0000 @@ -210,8 +210,16 @@ __strlen( const char * ); // NB This is a BSD function __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 Index: src/strnlen.cxx =================================================================== RCS file: src/strnlen.cxx diff -N src/strnlen.cxx --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/strnlen.cxx 11 May 2010 16:23:29 -0000 @@ -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 // Configuration header + +// INCLUDES + +#include // Common type definitions +#include // Tracing support +#include // Assertion support +#include // Header for this file +#include // Compiler definitions such as size_t, NULL etc. +#include // 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 Index: tests/strnlen.c =================================================================== RCS file: tests/strnlen.c diff -N tests/strnlen.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/strnlen.c 11 May 2010 16:23:29 -0000 @@ -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 +#include +#include +#include +#include +#include +#include + + +// 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