Blame bibutils/str.c

Packit 89ede9
/*
Packit 89ede9
 * str.c
Packit 89ede9
 *
Packit 89ede9
 * Version: 2017-07-03
Packit 89ede9
 *
Packit 89ede9
 * Copyright (c) Chris Putnam 1999-2018
Packit 89ede9
 *
Packit 89ede9
 * Source code released under the GPL version 2
Packit 89ede9
 *
Packit 89ede9
 *
Packit 89ede9
 * routines for dynamically allocated strings
Packit 89ede9
 *
Packit 89ede9
 */
Packit 89ede9
#include <stdio.h>
Packit 89ede9
#include <stdlib.h>
Packit 89ede9
#include <stdarg.h>
Packit 89ede9
#include <string.h>
Packit 89ede9
#include <ctype.h>
Packit 89ede9
#include <limits.h>
Packit 89ede9
#include "is_ws.h"
Packit 89ede9
#include "str.h"
Packit 89ede9
Packit 89ede9
/* Do not use asserts in STR_NOASSERT defined */
Packit 89ede9
#ifdef STR_NOASSERT
Packit 89ede9
#define NDEBUG
Packit 89ede9
#endif
Packit 89ede9
#include <assert.h>
Packit 89ede9
Packit 89ede9
#define str_initlen (64)
Packit 89ede9
Packit 89ede9
Packit 89ede9
/* Clear memory in resize/free if STR_PARANOIA defined */
Packit 89ede9
Packit 89ede9
#ifndef STR_PARANOIA
Packit 89ede9
Packit 89ede9
static void 
Packit 89ede9
str_realloc( str *s, unsigned long minsize )
Packit 89ede9
{
Packit 89ede9
	char *newptr;
Packit 89ede9
	unsigned long size;
Packit 89ede9
	assert( s );
Packit 89ede9
	size = 2 * s->dim;
Packit 89ede9
	if (size < minsize) size = minsize;
Packit 89ede9
	newptr = (char *) realloc( s->data, sizeof( *(s->data) )*size );
Packit 89ede9
	if ( !newptr ) {
Packit 89ede9
		fprintf( stderr,"Error.  Cannot reallocate memory (%lu bytes) in str_realloc.\n", sizeof(*(s->data))*size );
Packit 89ede9
		exit( EXIT_FAILURE );
Packit 89ede9
	}
Packit 89ede9
	s->data = newptr;
Packit 89ede9
	s->dim = size;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* define as a no-op */
Packit 89ede9
#define str_nullify( s )
Packit 89ede9
Packit 89ede9
#else
Packit 89ede9
Packit 89ede9
static void 
Packit 89ede9
str_realloc( str *s, unsigned long minsize )
Packit 89ede9
{
Packit 89ede9
	char *newptr;
Packit 89ede9
	unsigned long size;
Packit 89ede9
	assert( s );
Packit 89ede9
	size = 2 * s->dim;
Packit 89ede9
	if ( size < minsize ) size = minsize;
Packit 89ede9
	newptr = (char *) malloc( sizeof( *(s->data) ) * size );
Packit 89ede9
	if ( !newptr ) {
Packit 89ede9
		fprintf( stderr, "Error.  Cannot reallocate memory (%lu bytes) in str_realloc.\n", sizeof(*(s->data))*size );
Packit 89ede9
		exit( EXIT_FAILURE );
Packit 89ede9
	}
Packit 89ede9
	if ( s->data ) {
Packit 89ede9
		str_nullify( s );
Packit 89ede9
		free( s->data );
Packit 89ede9
	}
Packit 89ede9
	s->data = newptr;
Packit 89ede9
	s->dim = size;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static inline void
Packit 89ede9
str_nullify( str *s )
Packit 89ede9
{
Packit 89ede9
	memset( s->data, 0, s->dim );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
#endif
Packit 89ede9
Packit 89ede9
void 
Packit 89ede9
str_init( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	s->dim = 0;
Packit 89ede9
	s->len = 0;
Packit 89ede9
	s->data = NULL;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_initstr( str *s, str *from )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( from );
Packit 89ede9
	str_init( s );
Packit 89ede9
	str_strcpy( s, from );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_initstrc( str *s, const char *initstr )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( initstr );
Packit 89ede9
	str_init( s );
Packit 89ede9
	str_strcpyc( s, initstr );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_initstrsc( str *s, ... )
Packit 89ede9
{
Packit 89ede9
	const char *c;
Packit 89ede9
	va_list ap;
Packit 89ede9
	str_init( s );
Packit 89ede9
	va_start( ap, s );
Packit 89ede9
	do {
Packit 89ede9
		c = va_arg( ap, const char * );
Packit 89ede9
		if ( c ) str_strcatc( s, c );
Packit 89ede9
	} while ( c );
Packit 89ede9
	va_end( ap );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
strs_init( str *s, ... )
Packit 89ede9
{
Packit 89ede9
	str *s2;
Packit 89ede9
	va_list ap;
Packit 89ede9
	str_init( s );
Packit 89ede9
	va_start( ap, s );
Packit 89ede9
	do {
Packit 89ede9
		s2 = va_arg( ap, str * );
Packit 89ede9
		if ( s2 ) str_init( s2 );
Packit 89ede9
	} while ( s2 );
Packit 89ede9
	va_end( ap );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/*
Packit 89ede9
 * This is currently a stub. Later it will
Packit 89ede9
 * report whether or not a str function
Packit 89ede9
 * could not be performed due to a memory
Packit 89ede9
 * error.
Packit 89ede9
 */
Packit 89ede9
int
Packit 89ede9
str_memerr( str *s )
Packit 89ede9
{
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_mergestrs( str *s, ... )
Packit 89ede9
{
Packit 89ede9
	va_list ap;
Packit 89ede9
	const char *cp;
Packit 89ede9
	str_empty( s );
Packit 89ede9
	va_start( ap, s );
Packit 89ede9
	do {
Packit 89ede9
		cp = va_arg( ap, const char * );
Packit 89ede9
		if ( cp ) str_strcatc( s, cp );
Packit 89ede9
	} while ( cp );
Packit 89ede9
	va_end( ap );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static void 
Packit 89ede9
str_initalloc( str *s, unsigned long minsize )
Packit 89ede9
{
Packit 89ede9
	unsigned long size = str_initlen;
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( minsize > str_initlen ) size = minsize;
Packit 89ede9
	s->data = (char *) malloc (sizeof( *(s->data) ) * size);
Packit 89ede9
	if ( !s->data ) {
Packit 89ede9
		fprintf(stderr,"Error.  Cannot allocate memory in str_initalloc, requested %lu characters.\n", size );
Packit 89ede9
		exit( EXIT_FAILURE );
Packit 89ede9
	}
Packit 89ede9
	s->data[0]='\0';
Packit 89ede9
	s->dim=size;
Packit 89ede9
	s->len=0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
str *
Packit 89ede9
str_new( void )
Packit 89ede9
{
Packit 89ede9
	str *s = (str *) malloc( sizeof( *s ) );
Packit 89ede9
	if ( s )
Packit 89ede9
		str_initalloc( s, str_initlen );
Packit 89ede9
	return s;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void 
Packit 89ede9
str_free( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->data ) {
Packit 89ede9
		str_nullify( s );
Packit 89ede9
		free( s->data );
Packit 89ede9
	}
Packit 89ede9
	s->dim = 0;
Packit 89ede9
	s->len = 0;
Packit 89ede9
	s->data = NULL;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
strs_free( str *s, ... )
Packit 89ede9
{
Packit 89ede9
	str *s2;
Packit 89ede9
	va_list ap;
Packit 89ede9
	str_free( s );
Packit 89ede9
	va_start( ap, s );
Packit 89ede9
	do {
Packit 89ede9
		s2 = va_arg( ap, str * );
Packit 89ede9
		if ( s2 ) str_free( s2 );
Packit 89ede9
	} while ( s2 );
Packit 89ede9
	va_end( ap );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_delete( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	str_free( s );
Packit 89ede9
	free( s );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_empty( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->data ) {
Packit 89ede9
		str_nullify( s );
Packit 89ede9
		s->data[0] = '\0';
Packit 89ede9
	}
Packit 89ede9
	s->len = 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
strs_empty( str *s, ... )
Packit 89ede9
{
Packit 89ede9
	str *s2;
Packit 89ede9
	va_list ap;
Packit 89ede9
	str_empty( s );
Packit 89ede9
	va_start( ap, s );
Packit 89ede9
	do {
Packit 89ede9
		s2 = va_arg( ap, str * );
Packit 89ede9
		if ( s2 ) str_empty( s2 );
Packit 89ede9
	} while ( s2 );
Packit 89ede9
	va_end( ap );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_addchar( str *s, char newchar )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( newchar=='\0' ) return; /* appending '\0' is a null operation */
Packit 89ede9
	if ( !s->data || s->dim==0 ) 
Packit 89ede9
		str_initalloc( s, str_initlen );
Packit 89ede9
	if ( s->len + 2 > s->dim ) 
Packit 89ede9
		str_realloc( s, s->len*2 );
Packit 89ede9
	s->data[s->len++] = newchar;
Packit 89ede9
	s->data[s->len] = '\0';
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* str_addutf8
Packit 89ede9
 *
Packit 89ede9
 * Add potential multibyte character to s starting at pointer p.
Packit 89ede9
 * Multibyte Unicode characters have the high bit set.
Packit 89ede9
 *
Packit 89ede9
 * Since we can progress more than one byte at p, return the
Packit 89ede9
 * properly updated pointer p.
Packit 89ede9
 */
Packit 89ede9
const char *
Packit 89ede9
str_addutf8( str *s, const char *p )
Packit 89ede9
{
Packit 89ede9
	if ( ! ((*p) & 128 ) ) {
Packit 89ede9
		str_addchar( s, *p );
Packit 89ede9
		p++;
Packit 89ede9
	} else {
Packit 89ede9
		while ( ((*p) & 128) ) {
Packit 89ede9
			str_addchar( s, *p );
Packit 89ede9
			p++;
Packit 89ede9
		}
Packit 89ede9
	}
Packit 89ede9
	return p;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
char *
Packit 89ede9
str_cstr( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	return s->data;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void 
Packit 89ede9
str_fprintf( FILE *fp, str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->data ) fprintf( fp, "%s", s->data );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_prepend( str *s, const char *addstr )
Packit 89ede9
{
Packit 89ede9
	unsigned long lenaddstr, i;
Packit 89ede9
	assert( s && addstr );
Packit 89ede9
	lenaddstr = strlen( addstr );
Packit 89ede9
	if ( lenaddstr==0 ) return;
Packit 89ede9
	if ( !s->data || !s->dim )
Packit 89ede9
		str_initalloc( s, lenaddstr+1 );
Packit 89ede9
	else {
Packit 89ede9
		if ( s->len + lenaddstr  + 1 > s->dim )
Packit 89ede9
			str_realloc( s, s->len + lenaddstr + 1 );
Packit 89ede9
		for ( i=s->len+lenaddstr-1; i>=lenaddstr; i-- )
Packit 89ede9
			s->data[i] = s->data[i-lenaddstr];
Packit 89ede9
	}
Packit 89ede9
	strncpy( s->data, addstr, lenaddstr );
Packit 89ede9
	s->len += lenaddstr;
Packit 89ede9
	s->data[ s->len ] = '\0';
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static inline void
Packit 89ede9
str_strcat_ensurespace( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	unsigned long m = s->len + n + 1;
Packit 89ede9
	if ( !s->data || !s->dim )
Packit 89ede9
		str_initalloc( s, m );
Packit 89ede9
	else if ( s->len + n + 1 > s->dim )
Packit 89ede9
		str_realloc( s, m );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static inline void 
Packit 89ede9
str_strcat_internal( str *s, const char *addstr, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	str_strcat_ensurespace( s, n );
Packit 89ede9
	strncat( &(s->data[s->len]), addstr, n );
Packit 89ede9
	s->len += n;
Packit 89ede9
	s->data[s->len]='\0';
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_strcat( str *s, str *from )
Packit 89ede9
{
Packit 89ede9
	assert ( s && from );
Packit 89ede9
	if ( !from->data ) return;
Packit 89ede9
	else str_strcat_internal( s, from->data, from->len );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_strcatc( str *s, const char *from )
Packit 89ede9
{
Packit 89ede9
	unsigned long n;
Packit 89ede9
	assert( s && from );
Packit 89ede9
	n = strlen( from );
Packit 89ede9
	str_strcat_internal( s, from, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_segcat( str *s, char *startat, char *endat )
Packit 89ede9
{
Packit 89ede9
	unsigned long n;
Packit 89ede9
	char *p;
Packit 89ede9
Packit 89ede9
	assert( s && startat && endat );
Packit 89ede9
	assert( (size_t) startat < (size_t) endat );
Packit 89ede9
Packit 89ede9
	if ( startat==endat ) return;
Packit 89ede9
Packit 89ede9
	n = 0;
Packit 89ede9
	p = startat;
Packit 89ede9
	while ( p!=endat ) {
Packit 89ede9
		n++;
Packit 89ede9
		p++;
Packit 89ede9
	}
Packit 89ede9
Packit 89ede9
	str_strcat_internal( s, startat, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_indxcat( str *s, char *p, unsigned long start, unsigned long stop )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s && p );
Packit 89ede9
	assert( start <= stop );
Packit 89ede9
	for ( i=start; i
Packit 89ede9
		str_addchar( s, p[i] );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* str_cpytodelim()
Packit 89ede9
 *     term      = string of characters to be used as terminators
Packit 89ede9
 *     finalstep = set to non-zero to position return value past the
Packit 89ede9
 *                 terminating character
Packit 89ede9
 */
Packit 89ede9
char *
Packit 89ede9
str_cpytodelim( str *s, char *p, const char *delim, unsigned char finalstep )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	str_empty( s );
Packit 89ede9
	return str_cattodelim( s, p, delim, finalstep );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* str_cpytodelim()
Packit 89ede9
 *     term      = string of characters to be used as terminators
Packit 89ede9
 *     finalstep = set to non-zero to position return value past the
Packit 89ede9
 *                 terminating character
Packit 89ede9
 */
Packit 89ede9
char *
Packit 89ede9
str_cattodelim( str *s, char *p, const char *delim, unsigned char finalstep )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	while ( p && *p && !strchr( delim, *p ) ) {
Packit 89ede9
		str_addchar( s, *p );
Packit 89ede9
		p++;
Packit 89ede9
	}
Packit 89ede9
	if ( p && *p && finalstep ) p++;
Packit 89ede9
	return p;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static inline void
Packit 89ede9
str_strcpy_ensurespace( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	unsigned long m = n + 1;
Packit 89ede9
	if ( !s->data || !s->dim )
Packit 89ede9
		str_initalloc( s, m );
Packit 89ede9
	else if ( m > s->dim )
Packit 89ede9
		str_realloc( s, m );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static inline void
Packit 89ede9
str_strcpy_internal( str *s, const char *p, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	str_strcpy_ensurespace( s, n );
Packit 89ede9
	strncpy( s->data, p, n );
Packit 89ede9
	s->data[n] = '\0';
Packit 89ede9
	s->len = n;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_strcpy( str *s, str *from )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( from );
Packit 89ede9
	if ( s==from ) return;
Packit 89ede9
	else if ( !from || from->len==0 ) str_empty( s );
Packit 89ede9
	else str_strcpy_internal( s, from->data, from->len );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void 
Packit 89ede9
str_strcpyc( str *s, const char *from )
Packit 89ede9
{
Packit 89ede9
	unsigned long n;
Packit 89ede9
	assert( s && from );
Packit 89ede9
	n = strlen( from );
Packit 89ede9
	str_strcpy_internal( s, from, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* str_segcpy( s, start, end );
Packit 89ede9
 *
Packit 89ede9
 * copies [start,end) into s
Packit 89ede9
 */
Packit 89ede9
void
Packit 89ede9
str_segcpy( str *s, char *startat, char *endat )
Packit 89ede9
{
Packit 89ede9
	unsigned long n;
Packit 89ede9
	char *p;
Packit 89ede9
Packit 89ede9
	assert( s && startat && endat );
Packit 89ede9
	assert( ((size_t) startat) <= ((size_t) endat) );
Packit 89ede9
Packit 89ede9
	if ( startat==endat ) {
Packit 89ede9
		str_empty( s );
Packit 89ede9
		return;
Packit 89ede9
	}
Packit 89ede9
Packit 89ede9
	n = 0;
Packit 89ede9
	p = startat;
Packit 89ede9
	while ( p!=endat ) {
Packit 89ede9
		p++;
Packit 89ede9
		n++;
Packit 89ede9
	}
Packit 89ede9
Packit 89ede9
	str_strcpy_internal( s, startat, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/*
Packit 89ede9
 * str_indxcpy( s, in, start, stop );
Packit 89ede9
 *
Packit 89ede9
 * copies in[start,stop) (excludes stop) into s
Packit 89ede9
 */
Packit 89ede9
void
Packit 89ede9
str_indxcpy( str *s, char *p, unsigned long start, unsigned long stop )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s && p );
Packit 89ede9
	assert( start <= stop );
Packit 89ede9
	if ( start == stop ) {
Packit 89ede9
		str_empty( s );
Packit 89ede9
		return;
Packit 89ede9
	}
Packit 89ede9
	str_strcpy_ensurespace( s, stop-start+1 );
Packit 89ede9
	for ( i=start; i
Packit 89ede9
		s->data[i-start] = p[i];
Packit 89ede9
	s->len = stop-start;
Packit 89ede9
	s->data[s->len] = '\0';
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
str *
Packit 89ede9
str_strdup( str *from )
Packit 89ede9
{
Packit 89ede9
	str *s = str_new();
Packit 89ede9
	if ( s )
Packit 89ede9
		str_strcpy( s, from );
Packit 89ede9
	return s;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
str *
Packit 89ede9
str_strdupc( const char *from )
Packit 89ede9
{
Packit 89ede9
	str *s = str_new();
Packit 89ede9
	if ( s )
Packit 89ede9
		str_strcpyc( s, from );
Packit 89ede9
	return s;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_segdel( str *s, char *p, char *q )
Packit 89ede9
{
Packit 89ede9
	str tmp1, tmp2;
Packit 89ede9
	char *r;
Packit 89ede9
	assert( s );
Packit 89ede9
	r = &(s->data[s->len]);
Packit 89ede9
	str_init( &tmp1 );
Packit 89ede9
	str_init( &tmp2 );
Packit 89ede9
	str_segcpy( &tmp1, s->data, p );
Packit 89ede9
	str_segcpy( &tmp2, q, r );
Packit 89ede9
	str_empty( s );
Packit 89ede9
	if ( tmp1.data ) str_strcat( s, &tmp1 );
Packit 89ede9
	if ( tmp2.data ) str_strcat( s, &tmp2 );
Packit 89ede9
	str_free( &tmp2 );
Packit 89ede9
	str_free( &tmp1 );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/*
Packit 89ede9
 * str_findreplace()
Packit 89ede9
 *
Packit 89ede9
 *   if replace is "" or NULL, then delete find
Packit 89ede9
 */
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_findreplace( str *s, const char *find, const char *replace )
Packit 89ede9
{
Packit 89ede9
	long diff;
Packit 89ede9
	size_t findstart, searchstart;
Packit 89ede9
	size_t p1, p2;
Packit 89ede9
	size_t find_len, rep_len, curr_len;
Packit 89ede9
	char empty[2] = "";
Packit 89ede9
	unsigned long minsize;
Packit 89ede9
	char *p;
Packit 89ede9
	int n = 0;
Packit 89ede9
Packit 89ede9
	assert( s && find );
Packit 89ede9
	if ( !s->data || !s->dim ) return n;
Packit 89ede9
	if ( !replace ) replace = empty;
Packit 89ede9
Packit 89ede9
	find_len = strlen( find );
Packit 89ede9
	rep_len  = strlen( replace );
Packit 89ede9
	diff     = rep_len - find_len;
Packit 89ede9
	if ( diff < 0 ) diff = 0;
Packit 89ede9
Packit 89ede9
	searchstart=0;
Packit 89ede9
	while ((p=strstr(s->data + searchstart,find))!=NULL) {
Packit 89ede9
		curr_len = strlen(s->data);
Packit 89ede9
		findstart=(size_t) p - (size_t) s->data;
Packit 89ede9
		minsize = curr_len + diff + 1;
Packit 89ede9
		if (s->dim <= minsize) str_realloc( s, minsize );
Packit 89ede9
		if ( find_len > rep_len ) {
Packit 89ede9
			p1 = findstart + rep_len;
Packit 89ede9
			p2 = findstart + find_len;
Packit 89ede9
			while( s->data[p2] )
Packit 89ede9
				s->data[p1++]=s->data[p2++];
Packit 89ede9
			s->data[p1]='\0';
Packit 89ede9
			n++;
Packit 89ede9
		} else if ( find_len < rep_len ) {
Packit 89ede9
			for ( p1=curr_len; p1>=findstart+find_len; p1-- )
Packit 89ede9
				s->data[p1+diff] = s->data[p1];
Packit 89ede9
			n++;
Packit 89ede9
		}
Packit 89ede9
		for (p1=0; p1
Packit 89ede9
			s->data[findstart+p1]=replace[p1];
Packit 89ede9
		searchstart = findstart + rep_len; 
Packit 89ede9
		s->len += rep_len - find_len;
Packit 89ede9
	}
Packit 89ede9
	return n;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
Packit 89ede9
/* str_fget()
Packit 89ede9
 *   returns 0 if we're done, 1 if we're not done
Packit 89ede9
 *   extracts line by line (regardless of end characters)
Packit 89ede9
 *   and feeds from buf....
Packit 89ede9
 */
Packit 89ede9
int
Packit 89ede9
str_fget( FILE *fp, char *buf, int bufsize, int *pbufpos, str *outs )
Packit 89ede9
{
Packit 89ede9
	int  bufpos = *pbufpos, done = 0;
Packit 89ede9
	char *ok;
Packit 89ede9
	assert( fp && outs );
Packit 89ede9
	str_empty( outs );
Packit 89ede9
	while ( !done ) {
Packit 89ede9
		while ( buf[bufpos] && buf[bufpos]!='\r' && buf[bufpos]!='\n' )
Packit 89ede9
			str_addchar( outs, buf[bufpos++] );
Packit 89ede9
		if ( buf[bufpos]=='\0' ) {
Packit 89ede9
			ok = fgets( buf, bufsize, fp );
Packit 89ede9
			bufpos=*pbufpos=0;
Packit 89ede9
			if ( !ok && feof(fp) ) { /* end-of-file */
Packit 89ede9
				buf[bufpos] = 0;
Packit 89ede9
				if ( outs->len==0 ) return 0; /*nothing in out*/
Packit 89ede9
				else return 1; /*one last out */
Packit 89ede9
			}
Packit 89ede9
		} else if ( buf[bufpos]=='\r' || buf[bufpos]=='\n' ) done=1;
Packit 89ede9
	}
Packit 89ede9
	if ( ( buf[bufpos]=='\n' && buf[bufpos+1]=='\r') ||
Packit 89ede9
	     ( buf[bufpos]=='\r' && buf[bufpos+1]=='\n') ) bufpos+=2;
Packit 89ede9
	else if ( buf[bufpos]=='\n' || buf[bufpos]=='\r' ) bufpos+=1; 
Packit 89ede9
	*pbufpos = bufpos;
Packit 89ede9
	return 1;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_toupper( str *s )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s );
Packit 89ede9
	for ( i=0; i<s->len; ++i )
Packit 89ede9
		s->data[i] = toupper( (unsigned char)s->data[i] );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_tolower( str *s )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s );
Packit 89ede9
	for ( i=0; i<s->len; ++i )
Packit 89ede9
		s->data[i] = tolower( (unsigned char)s->data[i] );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/* str_swapstrings( s1, s2 )
Packit 89ede9
 * be sneaky and swap internal string data from one
Packit 89ede9
 * string to another
Packit 89ede9
 */
Packit 89ede9
void
Packit 89ede9
str_swapstrings( str *s1, str *s2 )
Packit 89ede9
{
Packit 89ede9
	char *tmpp;
Packit 89ede9
	int tmp;
Packit 89ede9
Packit 89ede9
	assert( s1 && s2 );
Packit 89ede9
Packit 89ede9
	/* swap dimensioning info */
Packit 89ede9
	tmp = s1->dim;
Packit 89ede9
	s1->dim = s2->dim;
Packit 89ede9
	s2->dim = tmp;
Packit 89ede9
Packit 89ede9
	/* swap length info */
Packit 89ede9
	tmp = s1->len;
Packit 89ede9
	s1->len = s2->len;
Packit 89ede9
	s2->len = tmp;
Packit 89ede9
Packit 89ede9
	/* swap data */
Packit 89ede9
	tmpp = s1->data;
Packit 89ede9
	s1->data = s2->data;
Packit 89ede9
	s2->data = tmpp;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_trimstartingws( str *s )
Packit 89ede9
{
Packit 89ede9
	char *p, *q;
Packit 89ede9
	int n;
Packit 89ede9
Packit 89ede9
	assert( s );
Packit 89ede9
Packit 89ede9
	if ( s->len==0 || !is_ws( s->data[0] ) ) return;
Packit 89ede9
Packit 89ede9
	n = 0;
Packit 89ede9
	p = s->data;
Packit 89ede9
	while ( is_ws( *p ) ) p++;
Packit 89ede9
Packit 89ede9
	q = s->data;
Packit 89ede9
	while ( *p ) {
Packit 89ede9
		*q++ = *p++;
Packit 89ede9
		n++;
Packit 89ede9
	}
Packit 89ede9
	*q = '\0';
Packit 89ede9
Packit 89ede9
	s->len = n;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_trimendingws( str *s )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	while ( s->len > 0 && is_ws( s->data[s->len-1] ) ) {
Packit 89ede9
		s->data[s->len-1] = '\0';
Packit 89ede9
		s->len--;
Packit 89ede9
	}
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_match_first( str *s, char ch )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( !s->len ) return 0;
Packit 89ede9
	if ( s->data[0] == ch ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_match_end( str *s, char ch )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( !s->len ) return 0;
Packit 89ede9
	if ( s->data[ s->len - 1 ] == ch ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_trimbegin( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	char *p, *q;
Packit 89ede9
Packit 89ede9
	assert( s );
Packit 89ede9
Packit 89ede9
	if ( n==0 ) return;
Packit 89ede9
	if ( s->len==0 ) return;
Packit 89ede9
	if ( n >= s->len ) {
Packit 89ede9
		str_empty( s );
Packit 89ede9
		return;
Packit 89ede9
	}
Packit 89ede9
Packit 89ede9
	p = s->data;
Packit 89ede9
	while ( n-- > 0 ) p++;
Packit 89ede9
Packit 89ede9
	n = 0;
Packit 89ede9
	q = s->data;
Packit 89ede9
	while ( *p ) {
Packit 89ede9
		*q++ = *p++;
Packit 89ede9
		n++;
Packit 89ede9
	}
Packit 89ede9
	*q = '\0';
Packit 89ede9
Packit 89ede9
	s->len = n;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_trimend( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
Packit 89ede9
	if ( n==0 ) return;
Packit 89ede9
	if ( n >= s->len ) {
Packit 89ede9
		str_empty( s );
Packit 89ede9
		return;
Packit 89ede9
	}
Packit 89ede9
Packit 89ede9
	s->len -= n;
Packit 89ede9
	s->data[ s->len ] = '\0';
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_pad( str *s, unsigned long len, char ch )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s );
Packit 89ede9
	for ( i=s->len; i
Packit 89ede9
		str_addchar( s, ch );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_copyposlen( str *s, str *in, unsigned long pos, unsigned long len )
Packit 89ede9
{
Packit 89ede9
	unsigned long i, max;
Packit 89ede9
	assert( s );
Packit 89ede9
	str_empty( s );
Packit 89ede9
	max = pos+len;
Packit 89ede9
	if ( max > in->len ) max = in->len;
Packit 89ede9
	for ( i=pos; i
Packit 89ede9
		str_addchar( s, in->data[i] );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
static void
Packit 89ede9
str_check_case( str *s, int *lowercase, int *uppercase )
Packit 89ede9
{
Packit 89ede9
	int i;
Packit 89ede9
	assert( s );
Packit 89ede9
	*lowercase = 0;
Packit 89ede9
	*uppercase = 0;
Packit 89ede9
	if ( s->len < 1 ) return;
Packit 89ede9
	for ( i=0; i<s->len && !( *lowercase && *uppercase ); ++i ) {
Packit 89ede9
		if ( isalpha( (unsigned char)s->data[i] ) ) {
Packit 89ede9
			if ( isupper( (unsigned char)s->data[i] ) ) *uppercase += 1;
Packit 89ede9
			else if ( islower( (unsigned char)s->data[i] ) ) *lowercase += 1;
Packit 89ede9
		}
Packit 89ede9
	}
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_is_mixedcase( str *s )
Packit 89ede9
{
Packit 89ede9
	int lowercase, uppercase;
Packit 89ede9
	str_check_case( s, &lowercase, &uppercase );
Packit 89ede9
	if ( lowercase > 0 && uppercase > 0 ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_is_lowercase( str *s )
Packit 89ede9
{
Packit 89ede9
	int lowercase, uppercase;
Packit 89ede9
	str_check_case( s, &lowercase, &uppercase );
Packit 89ede9
	if ( lowercase > 0 && uppercase == 0 ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_is_uppercase( str *s )
Packit 89ede9
{
Packit 89ede9
	int lowercase, uppercase;
Packit 89ede9
	str_check_case( s, &lowercase, &uppercase );
Packit 89ede9
	if ( lowercase == 0 && uppercase > 0 ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_stripws( str *s )
Packit 89ede9
{
Packit 89ede9
	unsigned long len = 0;
Packit 89ede9
	char *p, *q;
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->len ) {
Packit 89ede9
		p = q = s->data;
Packit 89ede9
		while ( *p ) {
Packit 89ede9
			if ( !is_ws( *p ) ) {
Packit 89ede9
				*q = *p;
Packit 89ede9
				q++;
Packit 89ede9
				len++;
Packit 89ede9
			}
Packit 89ede9
			p++;
Packit 89ede9
		}
Packit 89ede9
		*q = '\0';
Packit 89ede9
	}
Packit 89ede9
	s->len = len;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strcmp( const str *s, const str *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 && t->len == 0 ) return 0;
Packit 89ede9
	if ( s->len == 0 ) return strcmp( "", t->data );
Packit 89ede9
	if ( t->len == 0 ) return strcmp( s->data, "" );
Packit 89ede9
	return strcmp( s->data, t->data );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strcmpc( const str *s, const char *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 ) return strcmp( "", t );
Packit 89ede9
	return strcmp( s->data, t );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strncmp( const str *s, const str *t, size_t n )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 && t->len == 0 ) return 0;
Packit 89ede9
	if ( s->len == 0 ) return strncmp( "", t->data, n );
Packit 89ede9
	if ( t->len == 0 ) return strncmp( s->data, "", n );
Packit 89ede9
	return strncmp( s->data, t->data, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strncmpc( const str *s, const char *t, size_t n )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 ) return strncmp( "", t, n );
Packit 89ede9
	return strncmp( s->data, t, n );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strcasecmp( const str *s, const str *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 && t->len == 0 ) return 0;
Packit 89ede9
	if ( s->len == 0 ) return strcasecmp( "", t->data );
Packit 89ede9
	if ( t->len == 0 ) return strcasecmp( s->data, "" );
Packit 89ede9
	return strcasecmp( s->data, t->data );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_strcasecmpc( const str *s, const char *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 ) return strcasecmp( "", t );
Packit 89ede9
	return strcasecmp( s->data, t );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
char *
Packit 89ede9
str_strstr( const str *s, const str *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 && t->len == 0 ) return strstr( "", "" );
Packit 89ede9
	if ( s->len == 0 ) return strstr( "", t->data );
Packit 89ede9
	if ( t->len == 0 ) return strstr( s->data, "" );
Packit 89ede9
	return strstr( s->data, t->data );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
char *
Packit 89ede9
str_strstrc( const str *s, const char *t )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( t );
Packit 89ede9
	if ( s->len == 0 ) return strstr( "", t );
Packit 89ede9
	return strstr( s->data, t );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_reverse( str *s )
Packit 89ede9
{
Packit 89ede9
	unsigned long i, max;
Packit 89ede9
	char tmp;
Packit 89ede9
	assert( s );
Packit 89ede9
	max = s->len / 2;
Packit 89ede9
	for ( i=0; i
Packit 89ede9
		tmp = s->data[ i ];
Packit 89ede9
		s->data[ i ] = s->data[ s->len - 1 - i ];
Packit 89ede9
		s->data[ s->len - 1 - i ] = tmp;
Packit 89ede9
	}
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_fgetline( str *s, FILE *fp )
Packit 89ede9
{
Packit 89ede9
	int ch, eol = 0;
Packit 89ede9
	assert( s );
Packit 89ede9
	assert( fp );
Packit 89ede9
	str_empty( s );
Packit 89ede9
	if ( feof( fp ) ) return 0;
Packit 89ede9
	while ( !feof( fp ) && !eol ) {
Packit 89ede9
		ch = fgetc( fp );
Packit 89ede9
		if ( ch == EOF ) {
Packit 89ede9
			if ( s->len ) return 1;
Packit 89ede9
			else return 0;
Packit 89ede9
		}
Packit 89ede9
		else if ( ch == '\n' ) eol = 1;
Packit 89ede9
		else if ( ch == '\r' ) {
Packit 89ede9
			ch = fgetc( fp );
Packit 89ede9
			if ( ch != '\n' ) ungetc( ch, fp );
Packit 89ede9
			eol = 1;
Packit 89ede9
		} else {
Packit 89ede9
			str_addchar( s, (char) ch );
Packit 89ede9
		}
Packit 89ede9
	}
Packit 89ede9
	return 1;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
/*
Packit 89ede9
 * s = "Hi!\0", s.len = 3
Packit 89ede9
 *
Packit 89ede9
 * str_char( s, 0 ) = 'H'  str_revchar( s, 0 ) = '!'
Packit 89ede9
 * str_char( s, 1 ) = 'i'  str_revchar( s, 1 ) = 'i'
Packit 89ede9
 * str_char( s, 2 ) = '!'  str_revchar( s, 2 ) = 'H'
Packit 89ede9
 * str_char( s, 3 ) = '\0' str_revchar( s, 3 ) = '\0'
Packit 89ede9
 */
Packit 89ede9
char
Packit 89ede9
str_char( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->len==0 || n >= s->len ) return '\0';
Packit 89ede9
	return s->data[ n ];
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
char
Packit 89ede9
str_revchar( str *s, unsigned long n )
Packit 89ede9
{
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( s->len==0 || n >= s->len ) return '\0';
Packit 89ede9
	return s->data[ s->len - n - 1];
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_makepath( str *path, const char *dirname, const char *filename, char sep )
Packit 89ede9
{
Packit 89ede9
	assert( path );
Packit 89ede9
	if ( dirname ) str_strcpyc( path, dirname );
Packit 89ede9
	else str_empty( path );
Packit 89ede9
Packit 89ede9
	if ( path->len && path->data[path->len-1]!=sep )
Packit 89ede9
		str_addchar( path, sep );
Packit 89ede9
Packit 89ede9
	if ( filename ) str_strcatc( path, filename );
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
void
Packit 89ede9
str_fill( str *s, unsigned long n, char fillchar )
Packit 89ede9
{
Packit 89ede9
	unsigned long i;
Packit 89ede9
	assert( s );
Packit 89ede9
	if ( !s->data || s->dim==0 )
Packit 89ede9
		str_initalloc( s, n+1 );
Packit 89ede9
	if ( n + 1 > s->dim )
Packit 89ede9
		str_realloc( s, n+1 );
Packit 89ede9
	for ( i=0; i
Packit 89ede9
		s->data[i] = fillchar;
Packit 89ede9
	s->data[n] = '\0';
Packit 89ede9
	s->len = n;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_has_value( str *s )
Packit 89ede9
{
Packit 89ede9
	if ( !s || s->len==0 ) return 0;
Packit 89ede9
	return 1;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
int
Packit 89ede9
str_is_empty( str *s )
Packit 89ede9
{
Packit 89ede9
	if ( !s || s->len==0 ) return 1;
Packit 89ede9
	return 0;
Packit 89ede9
}
Packit 89ede9
Packit 89ede9
unsigned long
Packit 89ede9
str_strlen( str *s )
Packit 89ede9
{
Packit 89ede9
	if ( !s ) return 0;
Packit 89ede9
	else return s->len;
Packit 89ede9
}