Skip to content
Snippets Groups Projects
Select Git revision
  • eb3ae75237ebb07b947b18e5f2491425f7b4fe8f
  • master default protected
  • streebog
  • gost28147
  • master-updates
  • ed448
  • shake256
  • curve448
  • ecc-sqrt
  • gosthash94cp
  • cmac64
  • block16-refactor
  • siv-mode
  • cmac-layout
  • delete-des-compat
  • delete-rsa_blind
  • aes-struct-layout
  • release-3.4-fixes
  • struct-layout
  • attribute-deprecated
  • rename-data-symbols
  • nettle_3.5.1_release_20190627
  • nettle_3.5_release_20190626
  • nettle_3.5rc1
  • nettle_3.4.1_release_20181204
  • nettle_3.4.1rc1
  • nettle_3.4_release_20171119
  • nettle_3.4rc2
  • nettle_3.4rc1
  • nettle_3.3_release_20161001
  • nettle_3.2_release_20160128
  • nettle_3.1.1_release_20150424
  • nettle_3.1_release_20150407
  • nettle_3.1rc3
  • nettle_3.1rc2
  • nettle_3.1rc1
  • nettle_3.0_release_20140607
  • nettle_2.7.1_release_20130528
  • nettle_2.7_release_20130424
  • nettle_2.6_release_20130116
  • nettle_2.5_release_20120707
41 results

plan.html

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    s-string.c 22.80 KiB
    /*
     * $Id: s-string.c,v 1.20 1998/07/08 13:57:47 ceder Exp $
     * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996  Lysator Academic Computer Association.
     *
     * This file is part of the LysKOM server.
     * 
     * LysKOM 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 1, or (at your option) 
     * any later version.
     * 
     * LysKOM 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 LysKOM; see the file COPYING.  If not, write to
     * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
     * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
     * MA 02139, USA.
     *
     * Please mail bug reports to bug-lyskom@lysator.liu.se. 
     */
    /*
     *  s-string.c  --  Routines for manipulating objects of type String.
     *
     *
     *  Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996	Lysator Computer Club,
     *			Linkoping University,  Sweden
     *
     *  Everyone is granted permission to copy, modify and redistribute
     *  this code, provided the people they give it to can.
     *
     *
     *  Author:	Thomas Bellman
     *		Lysator Computer Club
     *		Linkoping University
     *		Sweden
     *
     *  email:	Bellman@Lysator.LiU.SE
     *
     *
     *  Any opinions expressed in this code are the author's PERSONAL opinions,
     *  and does NOT, repeat NOT, represent any official standpoint of Lysator,
     *  even if so stated.
     */
    
    static const char *
    rcsid = "$Id: s-string.c,v 1.20 1998/07/08 13:57:47 ceder Exp $";
    
    #include <sys/types.h>
    #include <stdio.h>
    #include <ctype.h>
    #include <assert.h>
    #include <limits.h>
    #ifdef HAVE_STDDEF_H
    #  include <stddef.h>
    #endif
    #if STDC_HEADERS || HAVE_STRING_H
    #  include <string.h>
    #  if !STDC_HEADERS && HAVE_MEMORY_H
    #    include <memory.h>
    #  endif
    #else /* not STDC_HEADERS and not HAVE_STRING_H */
    #  include <strings.h>
       /* memory.h and strings.h conflict on some systems.  */
    #endif /* not STDC_HEADERS and not HAVE_STRING_H */
    
    #include "misc-types.h"
    #include "s-collat-tabs.h"
    #include "s-string.h"
    #include "rcs.h"
    USE(rcsid);
    
    
    #define	EXPORT			/* To emphasize objects that are exported */
    
    
    /*  The empty String  */
    EXPORT  const String	EMPTY_STRING	= EMPTY_STRING_i;
    
    
    static free_function	x_free		= NULL;
    static malloc_function	x_malloc	= NULL;
    static realloc_function	x_realloc	= NULL;
    
    
    
    /*
     *  Functions to manipulate strings of type 'String'.
     *  All these functions return a value of type Success, which is
     *  an enum of OK an FAILURE (do NOT trust the order of these!).
     *
     *  All functions automatically allocates (and deallocates) any
     *  necessary storage, using the storage management functions
     *  defined by the s_set_storage_management() call.
     */
    
    
    /*  Macro to reallocate new storage.  Works even if PTR is a
     *  nil pointer.	*/
    #define REALLOC_0(ptr, size)	(((ptr) == NULL)		\
    					? MALLOC_0 (size)	\
    					: (*x_realloc) ((ptr), size))
    
    /*  Free storage.  Works even if PTR is a nil pointer.	*/
    #define FREE_0(ptr)		(((ptr) == NULL)	       \
    					? 0		       \
    					: ((*x_free) (ptr), ptr))
    
    #define MALLOC_0(size)		((*x_malloc) (size))
    
    
    /*
     *  Set the functions to use for storage management.  These must
     *  be call compatible with the normal functions malloc(),
     *  realloc() and free().
     */
    EXPORT  void
    s_set_storage_management (malloc_function	new_malloc,
    			  realloc_function	new_realloc,
    			  free_function		new_free)
    
    {
        x_malloc = new_malloc;
        x_realloc = new_realloc;
        x_free = new_free;
    }
    
    
    
    /*
     *  Create an object of type String from an ordinary C string.
     */
    EXPORT  Success
    s_crea_str (String	* dest_string,
    	    const char	* c_string    )
    
    {
        String_size		  length;
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before actually using it.  */
    
        length = strlen(c_string);
    
        temp_ptr = MALLOC_0 (length);
        if (temp_ptr == NULL)
        {
    	return FAILURE;
        }
    
        FREE_0 (dest_string->string);
        dest_string->string = temp_ptr;
        
        strncpy((char *)dest_string->string, c_string, length);
        dest_string->len = length;
    
        return OK;
    }
    
    /*
     * Create a string from a buffer. The contents of the buffer
     * are copied into the new string.
     */
    
    EXPORT  Success
    s_mem_crea_str (String	    	     * dest_string,
    	    	const unsigned char  * buffer,
    	    	String_size   	       length)
    {
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before actually using it.  */
    
        temp_ptr = MALLOC_0 (length);
        if (temp_ptr == NULL)
        {
    	return FAILURE;
        }
    
        FREE_0 (dest_string->string);
        dest_string->string = temp_ptr;
        
        memcpy(dest_string->string, buffer, length);
        dest_string->len = length;
    
        return OK;
    }
    
    
    /*
     * Create a string of a given size. The contents of the string
     * are unspecified. The LysKOM-server uses this to get a string
     * of a fixed size into which it can fread() data. This is probably
     * not a good idea since it relies heavily on the implementation
     * of strings. However, by using this function, those places are
     * easy to identify if the implementation should be done differently.
     */
    
    EXPORT  Success
    s_size_crea_str(String      *result,
    		String_size length)
    {
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before actually using it.  */
    
        temp_ptr = MALLOC_0 (length);
        if (temp_ptr == NULL)
        {
    	return FAILURE;
        }
    
        FREE_0 (result->string);
        result->string = temp_ptr;
        result->len = length;
    
        return OK;
    }
    
    
    /*
     *  Return a temporary String from a C string, i e return a struct
     *  pointing to the actual C string.  Suitable for sending a 'String'
     *  object as parameter to a function (IF that function does not modify
     *  its parameter).  Note that normally String variables should be set
     *  by s_crea_str(), to deallocate the memory used by it.
     */
    EXPORT  String
    s_fcrea_str (const char   * c_string)
    
    {
        String	temp;
    
        /* Cast needed to make compiler not warn about assignment from
         * const pointer to non-const pointer.  Sigh...		*/
        temp.string = (unsigned char *)c_string;
        temp.len = strlen(c_string);
        return  temp;
    }
    
    
    
    /*
     *  Free's the space used by a String object.  The object is
     *  set to EMPTY_STRING.
     */
    EXPORT  void
    s_clear (String   * str)
    {
        FREE_0 (str->string);
        *str = EMPTY_STRING;
    }
    
    
    
    /*
     *  Copy SOURCE_STRING to DEST_STRING.  Old value of DEST_STRING is
     *  retained if an error was encountered.  If 'foo' is a separate
     *  String, then it is legal to do  's_strcpy(&foo, foo)'.
     */
    EXPORT  Success
    s_strcpy (String	* dest_string,
    	  const String	  source_string)
    
    {
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before actually using it.  */
    
        if (s_strlen(source_string) == 0)
        {
    	s_clear (dest_string);
    	return OK;
        }
    
        /* (Re-)allocate memory */
        temp_ptr = REALLOC_0 (dest_string->string, s_strlen(source_string));
        if (temp_ptr == NULL)
    	return FAILURE;
        dest_string->string = temp_ptr;
        
        /* Copy the string */
        memcpy (dest_string->string,
    	    source_string.string,
    	    s_strlen (source_string));
        dest_string->len = s_strlen (source_string);
    
        return OK;
    }
    
    
    
    /*
     *  In String STR remove the characters starting with number FIRST
     *  and ending with number LAST, inclusive.  If FIRST > LAST, then
     *  no characters are removed.
     */
    extern  Success
    s_strdel (String	* str,
    	  String_size	  first,
    	  String_size	  last )
    
    {
        String_size		i;	/* Just an index in a loop */
    
    
        assert (   first >= 0  &&  first <= s_strlen (*str)
    	    && last >= -1  &&  last < s_strlen (*str));
    
        for ( i = last + 1 ;  i < s_strlen(*str) ;  i++ )
    	str->string [i-(last-first+1)] = str->string [i];
    
        str->len -= last-first+1;
    
        return  OK;
    }
    
    
    
    /*
     *  Append SOURCE_STRING to the end of DEST_STRING.  DEST_STRING is not
     *  changed if an error is encountered.
     */
    EXPORT  Success
    s_strcat (String	* dest_string,
    	  const String	  source_string)
    
    {
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before actually using it.  */
    
        /* (Re-)alloc space for new string */
        temp_ptr = REALLOC_0 (dest_string->string,
    			  dest_string->len + source_string.len);
        if (temp_ptr == NULL)
        {
    	return FAILURE;
        }
        dest_string->string = temp_ptr;
    
        /* Append SOURCE_STRING to *DEST_STRING */
        memcpy (dest_string->string + s_strlen (*dest_string),
    	    source_string.string,
    	    s_strlen (source_string));
        dest_string->len += source_string.len;
    
        return OK;
    }
    
    
    
    /*
     *  Extract a substring from SOURCE_STRING, starting with char no
     *  START_CHAR and ending with char no END_CHAR.  First character
     *  is character no 0.  If END_CHAR < START_CHAR, then DEST_STRING
     *  is set to 'EMPTY_STRING'.  If END_CHAR is equal to the macro
     *  'END_OF_STRING', then the substring reaches to the last character
     *  in SOURCE_STRING.
     */
    EXPORT  Success
    s_substr (String	* dest_string,
    	  const String	  source_string,
    	  String_size	  start_char,
    	  String_size	  end_char)
    
    {
        String_size		  sub_len;	/* Length of substring */
        void		* temp_ptr;	/* To hold result from malloc/realloc
    					 * before really using it.  */
    
        if (end_char == END_OF_STRING)
    	end_char = s_strlen(source_string)-1;
    
        assert (    start_char >= 0  &&  end_char >= -1
    	    &&  start_char <= s_strlen (source_string)
    	    &&  end_char < s_strlen (source_string));
    
        sub_len = end_char - start_char + 1;
    
        /* Will the substring be empty? */
        if (sub_len <= 0)
        {
    	s_clear (dest_string);	/* Free and set to EMPTY_STRING */
    	return OK;
        }
    
        /* (Re-)allocate space for substring */
        temp_ptr = REALLOC_0(dest_string->string, sub_len);
        if (temp_ptr == NULL)
        {
    	return FAILURE;
        }
        dest_string->string = temp_ptr;
    
        /* Copy substring to DEST_STRING */
        memcpy (dest_string->string,
    	    source_string.string + start_char,
    	    sub_len);
        dest_string->len = sub_len;
    
        return OK;
    }
    
    
    
    /*
     *  Fast extraction of a substring.  Returns an object of type
     *  String wich points into SOURCE_STRING.  Thus you should NEVER
     *  modify the result of this function.  (Raw character modifying
     *  is OK if you know what you are doing, but never use anything
     *  that might call free or realloc on it.)  If END_CHAR is equal
     *  to the macro 'END_OF_STRING', then the substring reaches to
     *  the last character in SOURCE_STRING.
     */
    EXPORT  String
    s_fsubstr (const String	  source_string,
    	   String_size	  start_char,
    	   String_size	  end_char	)
    
    {
        String	sub_string;	/* Substring struct */
    
    
        if (end_char == END_OF_STRING)
    	end_char = s_strlen(source_string)-1;
    
        assert (    start_char >= 0  &&  end_char >= -1
    	    &&  start_char <= s_strlen (source_string)
    	    &&  end_char < s_strlen (source_string));
    
        sub_string.len = end_char - start_char + 1;
    
        /* Is the substring empty? */
        if (sub_string.len < 1)
        {
    	return EMPTY_STRING;
        }
    
        sub_string.string = source_string.string + start_char;
    
        return sub_string;
    }
    
    
    
    /*
     *  Returns -1 if ARG is negative, 0 if 0 and +1 if positive.
     *  Used in the string comparison routines.
     */
    static  int
    sign (int  arg)
    {
        if (arg < 0)
    	return  -1;
        else if (arg == 0)
    	return   0;
        else
    	return  1;
    }
    
    
    
    /*
     *  Compares two strings.  Returns -1 if STR1 is lexically less
     *  than STR2, +1 if STR1 is greater than STR2, and 0 if they are
     *  equal.
     */
    EXPORT  int
    s_strcmp (String   str1,
    	  String   str2)
    
    {
        String_size		index;
        String_size		shortest;	/* Length of the shortest string */
        int			retval_based_on_lengths;
    
    
        retval_based_on_lengths = sign(str1.len - str2.len);
    
        if (str1.len < str2.len)
    	shortest = str1.len;
        else
    	shortest = str2.len;
    
        
        /*  If they point to the same string, then we only have to
         *  compare the lengths.	*/
        if (str1.string == str2.string)
    	return  retval_based_on_lengths;
    
    
        /* Find first diff:ing character (in [index]) */
        index = 0;
        while (  (index < shortest)
    	   && (str1.string[index] == str2.string[index]) )
    	index++;
    
        /* If no diff:ing char, then the shortest is the "smallest" */
        if (index >= shortest)
    	return  retval_based_on_lengths;
        else  /* ...else check which character was the "smallest". */
    	return  sign(str1.string[index] - str2.string[index]);
    
    }
    
    
    
    /*
     *  Makes INDEX (type char) positive.  Those that are negative,
     *  result in a positive number above the other numbers.  This
     *  works as if bitcopying a 2's complement nuber to an unsigned
     *  number.
     *
     *  NOTE:  This code might need to be modified for some architectures.
     */
    #define POS_INDEX(index)	((unsigned char)(index))
    
    /*
     *  Compares two strings with user specified collation order.
     *  Returns the same values as s_srcmp().
     *  COLLAT_TAB is a table of collating values for every char.
     */
    EXPORT  int
    s_usr_strcmp (String	 str1,
    	      String     str2,
    	      char     * collat_tab)
    
    {
        String_size		index;
        String_size		shortest;	/* Length of the shortest string */
        int			retval_based_on_lengths;
    
    
        retval_based_on_lengths = sign(str1.len - str2.len);
    
        if (str1.len < str2.len)
    	shortest = str1.len;
        else
    	shortest = str2.len;
    
        
        /*  If they point to the same string, then we only have to
         *  compare the lengths.	*/
        if (str1.string == str2.string)
    	return  retval_based_on_lengths;
    
    
        /* Find first diff:ing character (in [index-1]) */
        index = 0;
        while (   (index < shortest)
    	   && ( collat_tab [ POS_INDEX( str1.string [index] )]
    	       == collat_tab [ POS_INDEX( str2.string [index] )]) )
    	index++;
    
        
        /* If no diff:ing char, then the shortest is the "smallest" */
        if (index >= shortest)
    	return  retval_based_on_lengths;
    
        /* ...else check which character was the "smallest". */
        else
    	return  sign( collat_tab [ POS_INDEX( str1.string[index] )]
    		     - collat_tab [ POS_INDEX( str2.string[index] )] );
    
    }
    
    
    
    /*
     *  Checks if STR1 is the exact beginning of STR2, e g if STR1
     *  is "foobar" and STR2 is "foobarf" then the result is TRUE.
     */
    EXPORT  Bool
    s_strhead (String	str1,
    	   String	str2)
    
    {
        String_size		i;	/*  Index in comparison loop  */
    
    
        /*  If STR1 is longer than STR2, then it can't be a head.	*/
        if (s_strlen(str1) > s_strlen(str2))
    	return  FALSE;
    
        /*  If they point to the same string, then STR1 is a head
         *  of STR2.  (We have already compared the lengths.)	*/
        if (str1.string == str2.string)
    	return  TRUE;
    
        /*  Check character by character  */
        for ( i = 0 ;  i < s_strlen(str1) ;  i++)
    	if (str1.string[i] != str2.string[i])
    	    return FALSE;	/* Diff. found, so not head. */
    
        /*  No differences found  */
        return  TRUE;
    }
    
    
    
    /*
     *  Checks if STR1 is the exact beginning of STR2, but uses a
     *  user specified collating sequence for comparison (as in
     *  s_usr_strcmp()).
     */
    EXPORT  Bool
    s_usr_strhead (String	str1,
    	       String	str2,
    	       char	collat_tab [ COLLAT_TAB_SIZE ])
    
    {
        String_size		i;	/*  Index in comparison loop  */
    
    
        /*  If STR1 is longer than STR2, then it can't be a head.	*/
        if (s_strlen(str1) > s_strlen(str2))
    	return  FALSE;
    
        /*  If they point to the same string, then STR1 is a head
         *  of STR2.  (We have already compared the lengths.)	*/
        if (str1.string == str2.string)
    	return  TRUE;
    
        /*  Check character by character  */
        for ( i = 0 ;  i < s_strlen(str1) ;  i++)
        {
    	if (  collat_tab [ POS_INDEX( str1.string[i] )]
    	    != collat_tab [ POS_INDEX( str2.string[i] )] )
    	{
    	    return FALSE;	/* Diff. found, so not head. */
    	}
        }
        
        /*  No differences found  */
        return  TRUE;
    }
    
    
    
    
    /*
     *  From STR strip all trailing characters that can be found
     *  in STRIP_STRING.
     */
    extern  String
    s_strip_trailing (String	  str,
    		  const String	  strip_string)
    
    {
        while (  s_strlen (str) > 0
    	   && s_strchr (strip_string,
    			str.string[s_strlen(str) - 1], 0) != -1)
    	str.len--;
        return  str;
    }
    
    
    
    
    /*
     *  Returns the index of the first occurrence in the String STR
     *  of the character CH, starting at position STAR_POS.  Returns
     *  -1 if no occurrence.
     */
    EXPORT  String_size
    s_strchr (const String	  str,
    	  unsigned char	  ch,
    	  String_size	  start_pos)
    
    {
        unsigned char	* ptr;
    
        assert (start_pos >= 0  &&  start_pos <= s_strlen (str));
    
        ptr = memchr (str.string + start_pos, ch, s_strlen (str) - start_pos);
        if (ptr == NULL)
    	return  -1;
        else
    	return  ptr - str.string;
    }
    
    
    
    /*
     *  Returns the index of the last occurrence in the String STR
     *  of the character CH, starting at position START_POS.  Returns
     *  -1 if no occurrence.
     */
    EXPORT  String_size
    s_strrchr (const String	  str,
    	   unsigned char  ch,
    	   String_size	  start_pos)
    
    {
        String_size		index;
    
        if (start_pos == END_OF_STRING)
    	start_pos = s_strlen (str) - 1;
    
        assert (start_pos >= -1  &&  start_pos < s_strlen (str));
    
        index = start_pos;
        while (index >= 0  &&  str.string[index] != ch)
    	index--;
    
        return  index;	/* This will be -1 if not found. */
    }
    
    
    
    
    /*
     *  Return the index of the first occurrence in the String LOOK_IN
     *  of any of the characters in the String SEARCH_FOR, or -1 if none.
     */
    extern  String_size
    s_strpbrk (const String	  look_in,
    	   const String	  search_for)
    
    {
        String_size		  i;
    
        for ( i = 0 ;  i < s_strlen (look_in) ;  i++ )
    	if (s_strchr (search_for, look_in.string[i], 0) != -1)
    	    return  i;
    
        return  -1;
    }
    
    
    
    
    /*
     *  Find the first character in LOOK_IN that *is* present in
     *  SEARCH_FOR, and return its index, or the length of LOOK_IN if
     *  it contains only characters that are not present in SEARCH_FOR.
     */
    extern  String_size
    s_strcspn (const String	  look_in,
    	   const String	  search_for)
    
    {
        String_size		  i;
    
        i = 0;
        while (  i < s_strlen (look_in)
    	   && s_strchr (search_for, look_in.string[i], 0) == -1)
    	i++;
        return  i;
    }
    
    
    
    
    /*
     *  Find the first character in LOOK_IN that is *not* present in
     *  SKIP_CHARS, and return its index, or the length of LOOK_IN if
     *  it contains only characters that are present in SKIP_CHARS.
     */
    extern  String_size
    s_strspn (const String	  look_in,
    	  const String	  skip_chars)
    
    {
        String_size		  i;
    
        i = 0;
        while (  i < s_strlen (look_in)
    	   && s_strchr (skip_chars, look_in.string[i], 0) != -1)
    	i++;
        return  i;
    }
    
    
    
    
    
    /*
     *  Pick out the first token from SOURCE separated by one or more
     *  of the characters in SEPARATORS, starting in position START_POS.
     *
     *  More specifically: start in position START_POS and skip over
     *  separator characters (any of those present in SEPARATORS).
     *  Extract the substring starting with the first non-separator,
     *  and ending the character immediately before the first separator
     *  following.  *start_pos will be the index of the first separator
     *  character after the token.
     *
     *  Note that the return value actually points into SOURCE.  It
     *  is not separately allocated.
     */
    EXPORT  String
    s_strtok (const String	  source,
    	  String_size	* start_pos,
    	  const String	  separators)
    
    {
        String_size		first_char;	/* First character in token */
        String_size		end_char;	/* First character after token */
    
    
        /* Check of parameters - we might save some time on this */
        if (   (*start_pos >= s_strlen(source))
    	|| ((s_empty(separators) == TRUE) 
    	    || (s_empty(source) == TRUE)) )
        {
    	return  EMPTY_STRING;
        }
    
        /* Skip leading separators */
        first_char = *start_pos;
        while (  (first_char < s_strlen(source))
    	   && (s_strchr (separators, source.string[first_char], 0) != -1) )
    	first_char++;
    
        /* End of source string?  Then we can stop here. */
        if (first_char >= s_strlen(source))
        {
    	*start_pos = first_char;
    	return  EMPTY_STRING;
        }
    
        /* Find next separator */
        end_char = first_char;
        while (  (end_char < s_strlen(source))
    	   && (s_strchr (separators, source.string[end_char], 0) == -1) )
    	end_char++;
    
        /* OK, we're practically done. */
        *start_pos = end_char;
        return  s_fsubstr(source, first_char, end_char-1);
    }
    
    
    
    
    /****************************************************
     *	Misc. routines using our String type.	    *
     ****************************************************/
    
    
    /*
     *  Convert a char to a number in base BASE.
     */
    static  int
    char2digit (const char	ch,
    	    const int	base)
    {
        int			  index;
        static const char	* translate_table	=
    				"0123456789abcdefghijklmnopqrstuvwxyz";
        int			  c = (unsigned char)ch;
    
        index = 0;
        while (  (index < base)
    	   && (  translate_table[index]
    	       != (isalpha(c) ? tolower(c) : ch)))
    	index++;
    
        if (index >= base)
    	return  -1;
        else
    	return  index;
    }
    
    
    
    /*
     *  Convert the String STR to a long, using the base BASE.
     *  Leading blanks are skipped according to isblank() in <ctype.h>.
     *  The index of the first character that couldn't be used to form
     *  the number is returned in *FIRST_ILL_CHAR.  Returns -1 in
     *  *first_ill_char if there was an error in the parameters.
     *  BASE may be in the range 2..36
     */
    #define MAXBASE	36
    EXPORT  long
    s_strtol (const String	  str,
    	  String_size	* first_ill_char,
    	  const int	  base		)
    
    {
        long		  number	= 0;	/* The result */
        int			  sign		= 0;	/* Sign o' the times :-) */
        String_size		  char_no;
        int			  digit;
    
    
        assert (base >= 2  &&  base <= MAXBASE);
    
        if (s_empty(str))
        {
    	*first_ill_char = -1;
    	return  0;
        }
    
    
        /* Skip all blanks */
        char_no = 0;
        while ( (char_no < s_strlen(str)) && isspace(str.string[char_no]) )
    	char_no++;
    
        /* Find any sign character (+ or -) */
        if (str.string[char_no] == '+')
        {
    	sign = 1;
    	char_no++;
        }
        else if (str.string[char_no] == '-')
        {
    	sign = -1;
    	char_no++;
        }
    
        while (   (char_no < s_strlen(str))
    	   && ((digit = char2digit(str.string[char_no], base)) != -1) )
        {
    	number = number * base + digit;
    	char_no++;
        }
    
        *first_ill_char = char_no++;
        if (sign != -1)
    	return  number;
        else
    	return  -number;
    }
    
    
    
    
    /************************************************
     *	Input/Output routines for String	*
     ************************************************/
    
    
    
    /*
     *  Outputs the string STR on the stream STREAM.  No information
     *  about the length of the string is output.
     */
    EXPORT  Success
    s_fputs (FILE		* stream,
    	 const String	  str)
    
    {
        String_size		i;
    
        for ( i = 0 ;  i < str.len ;  i++ )
    	putc (str.string[i], stream);
    
        return OK;
    }
    
    
    /*
     * Create an ordinary C string from a String.
     * The pointer returned will point to a '\0'-terminated character
     * array which is obtained with the malloc-function supplied to
     * s_set_storage_management(). It should be freed by the caller.
     * NULL is returned if there is an error. The String may contain
     * '\0's, but the resulting string will be truncated at the first
     * '\0'. Thou shalt not depend on this behaviour. Later versions
     * might substitute "foobar" for '\0's.
     */
    
    EXPORT  char *
    s_crea_c_str(const String  source)
    {
        char *dest;
    
        dest = MALLOC_0( 1 + s_strlen(source) );
    
        if ( dest == NULL )
    	return NULL;
    
        memcpy(dest, source.string, s_strlen(source));
        dest[ s_strlen(source) ] = '\0';
        return dest;
    }