# HG changeset patch # User jlarmour # Date 1273595179 0 # Node ID ae816c83f0825beba7d88bd2e372306e926278cf # Parent 041821fb542760629ee096d4dbc4e88f8d69395a * 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. diff --git a/packages/language/c/libc/string/current/ChangeLog b/packages/language/c/libc/string/current/ChangeLog --- 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 + + * 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 diff --git a/packages/language/c/libc/string/current/cdl/string.cdl b/packages/language/c/libc/string/current/cdl/string.cdl --- 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." diff --git a/packages/language/c/libc/string/current/include/string.h b/packages/language/c/libc/string/current/include/string.h --- 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 diff --git a/packages/language/c/libc/string/current/include/stringsupp.hxx b/packages/language/c/libc/string/current/include/stringsupp.hxx --- 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 diff --git a/packages/language/c/libc/string/current/src/strnlen.cxx b/packages/language/c/libc/string/current/src/strnlen.cxx 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 // 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 diff --git a/packages/language/c/libc/string/current/tests/strnlen.c b/packages/language/c/libc/string/current/tests/strnlen.c 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 +#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