//-----------------------------------------------------------------------------
// Copyright © 2005 - Philip Howard - All rights reserved
//
// This program 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
// of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//-----------------------------------------------------------------------------
// package	libh/string
// homepage	http://libh.slashusr.org/
//-----------------------------------------------------------------------------
// author	Philip Howard
// email	libh at ipal dot org
// homepage	http://phil.ipal.org/
//-----------------------------------------------------------------------------
// This file is best viewed using a fixed spaced font such as Courier
// and in a display at least 120 columns wide.
//-----------------------------------------------------------------------------

__DEFINE_BEGIN__
//-----------------------------------------------------------------------------
// struct       strpla_s
// typedef      strpla_t, strpla_p
//
// purpose      Define a value containing a string pointer, length, and
//		allocation length.
//-----------------------------------------------------------------------------
struct strpla_s {
    char *	ptr				;
    size_t	len				;
    size_t	alen				;
};
typedef struct strpla_s		strpla_t	;
typedef struct strpla_s *	strpla_p	;

__DEFINE_END__

__FMACRO_BEGIN__
//-----------------------------------------------------------------------------
// macro        strpla
//
// purpose      Create a struct strpla_s value consisting of a string pointer,
//              length, and allocation length.
//
// arguments    1 (char *) string pointer
//              2 (size_t) string length
//		3 (size_t) allocation length
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla(p,l,a) ({							\
	struct strpla_s libh__spls;						\
	libh__spls.ptr = (p);							\
	libh__spls.len = (l);							\
	libh__spls.alen = (a);							\
	libh__spls;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_null
//
// purpose	Make a null value strpla.
//-----------------------------------------------------------------------------
#define strpla_null strpla((NULL),0,0)

//-----------------------------------------------------------------------------
// macro        strpla_ptr
//
// purpose      Extract the string pointer from a strpla_s value.
//-----------------------------------------------------------------------------
#define strpla_ptr(s) ((s).ptr)

//-----------------------------------------------------------------------------
// macro        strpla_len
//
// purpose      Extract the string length from a strpla_s value.
//-----------------------------------------------------------------------------
#define strpla_len(s) ((s).len)

//-----------------------------------------------------------------------------
// macro        strpla_alen
//
// purpose      Extract the allocation length from a strpla_s value.
//-----------------------------------------------------------------------------
#define strpla_alen(s) ((s).alen)

//-----------------------------------------------------------------------------
// macro        strpla_end
//
// purpose      Extract the string end pointer from a strpla_s value.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_end(s) ({							\
	struct strpla_s libh__spls;						\
	libh__spls = (s);							\
	libh__spls.len + libh__spls.ptr;					\
})

//-----------------------------------------------------------------------------
// macro        strpla_aend
//
// purpose      Extract the allocation end pointer from a struct strpl_s.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_aend(s) ({							\
	struct strpla_s libh__spls;						\
	libh__spls = (s);							\
	libh__spls.alen + libh__spls.ptr;					\
})

//-----------------------------------------------------------------------------
// macro	strpla_strpl
//
// purpose	Convert a strpla value to a strpl value.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_strpl(s) ({							\
	struct strpla_s libh__strpla;						\
	struct strpl_s libh__strpl;						\
	libh__strpl.ptr = libh__strpla.ptr;					\
	libh__strpl.len = libh__strpla.len;					\
	libh__strpl;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_strpe
//
// purpose	Convert a strpla value to a strpe value.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_strpe(s) ({							\
	struct strpla_s libh__strpla;						\
	struct strpe_s libh__strpe;						\
	libh__strpe.ptr = libh__strpla.ptr;					\
	libh__strpe.end = libh__strpla.len + libh__strpla.ptr;			\
	libh__strpe;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_strpea
//
// purpose	Convert a strpla value to a strpea value.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_strpea(s) ({							\
	struct strpla_s libh__strpla;						\
	struct strpea_s libh__strpea;						\
	libh__strpea.ptr = libh__strpla.ptr;					\
	libh__strpea.end = libh__strpla.len + libh__strpla.ptr;			\
	libh__strpea.aend = libh__strpla.alen + libh__strpla.ptr;		\
	libh__strpea;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_trim
//
// purpose	Trim the memory allocation of a pointed to strpla struct to
//		the size of the current string length, plus one for space to
//		append a null termination character.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_trim(p) ({							\
	struct strpla_s *libh__speap;						\
	char *libh__ptr;							\
	libh__speap = (p);							\
	libh__ptr = realloc( libh__speap->ptr, libh__speap->len + 1 );		\
	if ( libh__ptr ) {							\
		libh__speap->ptr = libh__ptr;					\
		libh__speap->alen = libh__speap->len + 1;			\
	}									\
})

//-----------------------------------------------------------------------------
// macro	strpla_new
//
// purpose	Allocate new string space of the specified size and return a
//		strpla value using this allocation.
//
// note		If the returned value is assigned to a struct strpla, that
//		struct strpla must not have any existing allocation of string
//		space or this will create a memory leak.  This is intended for
//		first time initialization.
//
// note		If memory allocation fails, or the requested size is 0, the
//		returned value will have a NULL pointer and zero length.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_new(s) ({							\
	struct strpla_s libh__spea;						\
	size_t libh__alen;							\
	libh__alen = (s);							\
	libh__spea.ptr = libh__alen ? malloc( libh__alen ) : (NULL);		\
	libh__spea.alen = libh__spea.ptr ? libh__alen : 0;			\
	libh__spea.len = 0;							\
	libh__spea;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_realloc
//
// purpose	Reallocate memory for the pointed to strpla struct to the
//		specified size, if the current string will fit.  If the string
//		will not fit, make no changes.
//
// yields	0 - string fits in size, reallocation performed
//		1 - string does not fit, reallocation not performed
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_realloc(p,s) ({							\
	struct strpla_s *libh__speap;						\
	char *libh__ptr;							\
	size_t libh__size;							\
	libh__speap = (p);							\
	libh__size = (s);							\
	libh__speap->len >= libh__size ? ({					\
		libh__ptr = realloc( libh__speap->ptr, libh__size );		\
		if ( libh__ptr || ! libh__size ) {				\
			libh__speap->ptr = libh__ptr;				\
			libh__speap->alen = libh__ptr + libh__size;		\
		}								\
	0; }) : 1;								\
})

//-----------------------------------------------------------------------------
// macro	strpla_free
//
// purpose	Free memory allocated for string space in the specified struct
//		strpla.
//
// note		This macro is "multiple evaluation safe".  All expressions
//		passed as arguments will only be evaluated once.
//-----------------------------------------------------------------------------
#define strpla_free(p) ({							\
	struct strpla_s *libh__speap;						\
	libh__speap = (p);							\
	if ( libh__speap->ptr && libh__speap->alen ) {				\
		free( libh__speap->ptr );					\
		libh__speap->ptr = (NULL);					\
		libh__speap->len = 0;						\
		libh__speap->alen = 0;						\
	}									\
	libh__speap;								\
})

__FMACRO_END__

