//-----------------------------------------------------------------------------
// Copyright © 2003 - 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.
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

#include "string_lib.h"

//-----------------------------------------------------------------------------
// functions	str_select_*[_va]
//
// purpose	Select a substring from a given string based on a command set
//		specified in a control string which can use arguments of the
//		function call, and return the substring by various methods.
//
// control string command set characters:
//
//	^	Set the cursor to the beginning of the given string.
//	
//	$	Set the cursor to the end of the given string.
//	
//	[	Set the substring begin pointer to the current cursor and
//		include the delimiter it points to.
//	
//	(	Set the substring begin pointer to the current cursor and
//		exclude the delimiter it points to.
//	
//	{	Set the substring begin pointer to the current cursor and
//		exclude the delimiter it points to as well as any leading
//		whitespace characters.
//
//	}	Set the substring end pointer to the current cursor and
//		exclude the delimiter it points to as well as any trailing
//		whitespace characters.
//
//	)	Set the substring end pointer to the current cursor and
//		exclude the delimiter it points to.
//	
//	]	Set the substring end pointer to the current cursor and
//		include the delimiter it points to.
//	
//	w W	Specify the next search is for a group of whitespace
//		characters, where one or more of any combination together
//		is considered to be a single delimiter.
//	
//	n N	Specify the next search is for a newline, which may also
//		include a carriage return if there is one before the newline.
//		Characters formfeed and vertical tab also count as newline
//		characters.
//
//	,	Specify the next search is for a ',' character without using
//		an argument to pass the character code.
//
//	.	Specify the next search is for a '.' character without using
//		an argument to pass the character code.
//	
//	/	Specify the next search is for a '/' character without using
//		an argument to pass the character code.
//
//	:	Specify the next search is for a ':' character without using
//		an argument to pass the character code.
//
//	;	Specify the next search is for a ';' character without using
//		an argument to pass the character code.
//
//	@	Specify the next search is for a '@' character without using
//		an argument to pass the character code.
//
//	|	Specify the next search is for a '|' character without using
//		an argument to pass the character code.
//	
//	=	Specify the next search is for the character that immediately
//		follows this = in the control string.
//
//	c C	Specify the next search is for a single character given in an
//		argument as (int).
//
//	l L	Specify the next search is for a single character in a list of
//		characters given in a string argument as (const char *).
//	
//	t T	Specify the next search is for a single character that when
//		used to index a character table/array yields a non-zero value.
//		The case insensitive flag does not apply to a search by
//		character table.
//	
//	x X	When used with L or T, specifies that the test for the
//		delimiter character is inverted, that is, for L, the first
//		character NOT in the list, and for T, the delimiter is the
//		first character NOT in the table (e.g. has a table value of 0).
//	
//	s S	Specify the next search is for a string given in an argument as
//		(const char *).
//	
//	m M	Specify the next search is for a string given in non-terminated
//		form in two arguments as (const char *) and (size_t).
//	
//	i I	When used with S or M, specifies that the test for the
//		delimiter character string is done case-insensitive.
//
//	&	Specify that if a search is incomplete (fewer delimiters are
//		found than requested) then the current delimiter state is not
//		changed.
//
//	*	Specify that if a search is incomplete (fewer delimiters are
//		found than requested) then the current delimiter state is set
//		to the last delimiter found.
//
//		If neither & nor * is specified, and a search is incomplete,
//		then the current delimiter is set to the end of the subject
//		string in the specified direction.
//
//	?	Specify that if the next delimiter follows immediately with
//		no characters between the current delimiter and the next,
//		then skip to the next delimiter without counting it, otherwise
//		it would be counted.  This will be done even if the count is
//		zero.  This is useful for pre-skipping leading whitespace.
//
//	#	Specify that the next search is to be repeated a number of
//		times where the number is given in an argument as (int).
//	
//	digits	Specify that the next search is to be repeated a number of
//		times where the number is the value represented by the decimal
//		digits.
//	
//	>	Specify to do a forward search now.
//	
//	<	Specify to do a reverse search now.
//
// Various functions differ in how they return the selected substring and
// receive the variable arguments:
//
// str_select_dup()
//	allocates space for the selected substring, copies the substring to
//	that space, and returns a pointer to it.  The caller is responsible for
//	freeing the space when it no longer needs it.  The original string is
//	not modified.
//
// str_select_dup_va()
//	works like str_select_dup() except that it receives the arguments in
//	va_list.
//
// str_select_cut()
//	terminates the selected substring in place in the given string, and
//	returns a pointer to it.  The original string is therefore modified by
//	that termination.  If the original string was allocated, the caller
//	must not free it until the substring is no longer needed.
//
// str_select_cut_va()
//	works like str_select_cut() except that it receives the arguments in
//	va_list.
//
// str_select_cpy()
//	copies the selected substring, truncated to fit in the space given by
//	the caller, with termination always included.  The original string is
//	not modified.
//
// str_select_cpy_va()
//	works like str_select_cpy() except that it receives the arguments in
//	va_list.
//
// str_select_app()
//	appends the selected substring, truncated to fit at the end of the
//	existing terminated string in the space given by the caller, with
//	termination always included.  The original string is not modified.
//
// str_select_app_va()
//	works like str_select_app() except that it receives the arguments in
//	va_list.
//
// str_select_ptr()
//	stores the pointer and end pointer to the unterminated selected
//	substring within the original string, into the locations specified by
//	the caller, and returns the length of the substring.  The original
//	string is not modified.  If the original string was allocated, the
//	caller must not free it until the substring is no longer needed.
//
// str_select_ptr_va()
//	works like str_select_ptr() except that it receives the arguments in
//	va_list.
//
// examples:
//
// To remove the directory path and extension from a file name:
//	str_select_dup( fullname, "$1c<($1c<)", '/', '.' ) ... or simply:
//	str_select_dup( fullname, "$/<($1.<)" )
//
// To extract the directory from a path (aka dirname):
//	str_select_dup( fullpath, "$1c<)", '/' ) ... or simply:
//	str_select_dup( fullpath, "$/<)" )
//
// To extract the base name from a path (aka basename):
//	str_select_dup( fullpath, "$1c<(", '/' ) ... or simply:
//	str_select_dup( fullpath, "$/<(" )
//
// To extract the username part of an email address:
//	str_select_dup( email, "^1c>)", '@' ) ... or simply:
//	str_select_dup( email, "^@>)" )
//
// To extract the hostname part of an email address:
//	str_select_dup( email, "^1c>(", '@' ) ... or simply:
//	str_select_dup( email, "^@>(" )
//
// To extract the second level domain from a fully qualified domain name:
//	str_select_dup( fqdn, "$2c<(", '.' ) ... or simply:
//	str_select_dup( fqdn, "$2.<(" )
//
// To extract an email address from within <>:
//	str_select_dup( email, "$c!>(^c!<)", '<', '>' );
//-----------------------------------------------------------------------------

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

__PROTO_BEGIN__
//-----------------------------------------------------------------------------
// function	str_select_cut_va
//
// arguments	1 (char *) string to select a substring from
//		2 (char *) selection command string
//		3 (va_list) arguments used by command string
//
// returns	(char *) pointer to substring within original string
//-----------------------------------------------------------------------------
char *
str_select_cut_va (
    char *		arg_string
    ,
    char *		arg_control
    ,
    va_list		arg_var_args
    )
__PROTO_END__
{
    char *		ss_ptr		;
    size_t		ss_len		;

    ss_len = str_select_ptr_va( & ss_ptr, NULL, arg_string, arg_control, arg_var_args );
    if ( ss_len != ~0 ) {
	ss_ptr[ss_len] = 0;
    } else {
	ss_ptr = NULL;
    }
    return ss_ptr;
}

