/***************************************************************************
 * LPRng - An Extended Print Spooler System
 *
 * Copyright 1988-2001, Patrick Powell, San Diego, CA
 *     papowell@lprng.com
 * See LICENSE for conditions of use.
 *
 ***************************************************************************/

 static char *const _id =
"$Id: safestrutil.c,v 1.2 2002/04/02 04:38:40 papowell Exp papowell $";

#include "portable.h"
#include "safemalloc.h"
#include "safestrutil.h"

/**************************************************************
 * Bombproof versions of string functions
 **************************************************************/

int safestrlen( const char *s1 )
{
	return( s1? strlen(s1) : 0 );
}

/* case insensitive compare for OS without it */
int safestrcasecmp (const char *s1, const char *s2)
{
	int c1, c2, d = 0;
	if( (s1 == s2) ) return(0);
	if( (s1 == 0 ) && s2 ) return( -1 );
	if( s1 && (s2 == 0 ) ) return( 1 );
	for (;;) {
		c1 = *((unsigned char *)s1); s1++;
		c2 = *((unsigned char *)s2); s2++;
		if( isupper(c1) ) c1 = tolower(c1);
		if( isupper(c2) ) c2 = tolower(c2);
		if( (d = (c1 - c2 )) || c1 == 0 ) break;
	}
	return( d );
}

/* case insensitive compare for OS without it */
int safestrncasecmp (const char *s1, const char *s2, int len )
{
	int c1, c2, d = 0;
	if( (s1 == s2) && s1 == 0 ) return(0);
	if( (s1 == 0 ) && s2 ) return( -1 );
	if( s1 && (s2 == 0 ) ) return( 1 );
	for (;len>0;--len){
		c1 = *((unsigned char *)s1); s1++;
		c2 = *((unsigned char *)s2); s2++;
		if( isupper(c1) ) c1 = tolower(c1);
		if( isupper(c2) ) c2 = tolower(c2);
		if( (d = (c1 - c2 )) || c1 == 0 ) return(d);
	}
	return( 0 );
}

/* perform safe comparison, even with null pointers */
int safestrcmp( const char *s1, const char *s2 )
{
	if( (s1 == s2) ) return(0);
	if( (s1 == 0 ) && s2 ) return( -1 );
	if( s1 && (s2 == 0 ) ) return( 1 );
	return( strcmp(s1, s2) );
}


/* perform safe comparison, even with null pointers */
int safestrncmp( const char *s1, const char *s2, int len )
{
	if( (s1 == s2) && s1 == 0 ) return(0);
	if( (s1 == 0 ) && s2 ) return( -1 );
	if( s1 && (s2 == 0 ) ) return( 1 );
	return( strncmp(s1, s2, len) );
}


/* perform safe strchr, even with null pointers */
char *safestrchr( const char *s1, int c )
{
	if( s1 ) return( strchr( s1, c ) );
	return( 0 );
}


/* perform safe strrchr, even with null pointers */
char *safestrrchr( const char *s1, int c )
{
	if( s1 ) return( strrchr( s1, c ) );
	return( 0 );
}


/* perform safe strchr, even with null pointers */
char *safestrpbrk( const char *s1, const char *s2 )
{
	if( s1 && s2 ) return( strpbrk( s1, s2 ) );
	return( 0 );
}


/* perform safe strstr, even with null pointers */
char *safestrstr( const char *s1, const char *s2 )
{
	if( s1 && s2 ) return( strstr( s1, s2 ) );
	return( 0 );
}

/* lowercase and uppercase (destructive) a string */
void lowercase( char *s )
{
	int c;
	if( s ){
		for( ; (c = cval(s)); ++s ){
			if( isupper(c) ) *s = tolower(c);
		}
	}
}
void uppercase( char *s )
{
	int c;
	if( s ){
		for( ; (c = cval(s)); ++s ){
			if( islower(c) ) *s = toupper(c);
		}
	}
}

/*
 * Trunc str - remove trailing white space (destructive)
 */

char *trunc_str( char *s)
{
	int len = safestrlen(s);
	if( len ){
		while( len > 0 && isspace(cval(s+len-1)) ) --len;
		s[len] = 0;
	}
	return( s );
}

int Lastchar( char *s )
{
	int c = 0, n = safestrlen(s);
	if( n ){
		c = cval(s+n-1);
	}
	return(c);
}

#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LOWER "abcdefghijklmnopqrstuvwxyz"
#define DIGIT "01234567890"
#define SAFE "-_."
#define LESS_SAFE SAFE "@/:()=,+-%"

const char *Is_clean_name( const char *s )
{
	int c;
	if( s ){
		for( ; (c = cval(s)); ++s ){
			if( !(isalnum(c) || safestrchr( SAFE, c )) ) return( s );
		}
	}
	return( 0 );
}

void Clean_name( char *s )
{
	int c;
	if( s ){
		for( ; (c = cval(s)); ++s ){
			if( !(isalnum(c) || safestrchr( SAFE, c )) ) *s = '_';
		}
	}
}

/*
 * Find a possible bad character in a line
 */

int Is_meta( int c, const char * safe_chars )
{
	return( !( isspace(c) || isalnum( c )
		|| (safe_chars && safestrchr(safe_chars,c))
		|| safestrchr( LESS_SAFE, c ) ) );
}

const char *Find_meta( const char *s, const char *safe_chars )
{
	int c = 0;
	if( s ){
		for( ; (c = cval(s)); ++s ){
			if( Is_meta( c, safe_chars ) ) return( s );
		}
		s = 0;
	}
	return( s );
}

void Clean_meta( char *t, const char *safe_chars )
{
	char *s = t;
	if( t ){
		while( (s = safestrchr(s,'\\')) ) *s = '/';
		s = t;
		for( s = t; (s =(char *)Find_meta( s, safe_chars )); ++s ){
			*s = '_';
		}
	}
}


/*
 * char *Make_pathname( char *dir, char *filename )
 *  - makes a full pathname from the dir and file part
 */

char *Make_pathname( const char *dir,  const char *filename, MEMPASS )
{
	char *s, *path = 0;
	if( filename == 0 ){
		path = 0;
	} else if( filename[0] == '/' ){
		path = safestrdup(filename,MEMPASSED);
	} else if( dir ){
		path = safestrdup3(dir,"/",filename,MEMPASSED);
	} else {
		path = safestrdup2("./",filename,MEMPASSED);
	}
	if( (s = path) ) while((s = strstr(s,"//"))) memmove(s,s+1,safestrlen(s)+1 );
	return(path);
}

/*
 * safeunlink - this is a silly place to put it...
 */
int safeunlink( const char *s )
{
	if( s ) return( unlink(s) );
	return(0);
}

/*
  safer versions of strncat and strncp
 */
char *mystrncat( char *s1, const char *s2, int len )
{
	int size;
	if( len > 0 ){
		s1[len-1] = 0;
		size = safestrlen( s1 );
		len -= size;
		if( s2 && len > 0  ){
			strncpy( s1+size, s2, len-1 );
		}
	}
	return( s1 );
}
char *mystrncpy( char *s1, const char *s2, int len )
{
	--len;
	s1[0] = 0;
	if( s2 && len > 0 ){
		strncpy( s1, s2, len );
		s1[len] = 0;
	}
	return( s1 );
}
