/*
 * Copyright (c) 2004-2005, Stefan Walter
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 *     * Redistributions of source code must retain the above 
 *       copyright notice, this list of conditions and the 
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the 
 *       above copyright notice, this list of conditions and 
 *       the following disclaimer in the documentation and/or 
 *       other materials provided with the distribution.
 *     * The names of contributors to this software may not be 
 *       used to endorse or promote products derived from this 
 *       software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 *
 * CONTRIBUTORS
 *  Stef Walter <stef@memberwebs.com>
 *
 * 
 * PORTIONS FROM OPENBSD: -------------------------------------------------
 *
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 



#include "usuals.h"
#include "compat.h"

#include <ctype.h>
#include <stdlib.h>

#ifndef HAVE_REALLOCF

void* reallocf(void* ptr, size_t size)
{
	void* ret = realloc(ptr, size);

	if(!ret && size)
		free(ptr);

	return ret;
}

#endif

#ifndef HAVE_STRLWR
char* strlwr(char* s)
{
    char* t = s;
    while(*t)
    {
        *t = tolower(*t);
        t++;
    }
    return s;
}
#endif 

#ifndef HAVE_STRUPR
char* strupr(char* s)
{
    char* t = s;
    while(*t)
    {
        *t = toupper(*t);
        t++;
    }
    return s;
}
#endif 

#ifndef HAVE_STRLCPY

size_t strlcpy(char* dst, const char* src, size_t siz)
{
	char* d = dst;
    const char* s = src;
    size_t n = siz;

    /* Copy as many bytes as will fit */
    if(n != 0 && --n != 0) 
	{
       	do 
		{
           	if((*d++ = *s++) == 0)
               	break;
        } 
		while(--n != 0);
    }
                                                                                
    /* Not enough room in dst, add NUL and traverse rest of src */
    if(n == 0) 
	{
      	if(siz != 0)
           	*d = '\0';              /* NUL-terminate dst */
        while (*s++)
         	;
    }
                                                                                
    return s - src - 1;    /* count does not include NUL */
}

#endif
                                                                                
#ifndef HAVE_STRLCAT
                                                                                
size_t strlcat(char* dst, const char* src, size_t siz)
{
    char* d = dst;
    const char* s = src;
    size_t n = siz;
    size_t dlen;
                                                                                
    /* Find the end of dst and adjust bytes left but don't go past end */
    while(n-- != 0 && *d != '\0')
     	d++;
    dlen = d - dst;
    n = siz - dlen;
                                                                                
    if(n == 0)
        return dlen + strlen(s);
    while(*s != '\0') 
    {
        if(n != 1) 
        {
            *d++ = *s;
            n--; 
        }
        
        s++;
    }

    *d = '\0';
                                                                                
    return dlen + (s - src);       /* count does not include NUL */
}

#endif

#ifndef HAVE_STRCASESTR

const char* strcasestr(const char *s, const char *find)
{
    char c, sc;
    size_t len;

    if((c = *find++) != 0)
    {
        c = tolower((unsigned char)c);
        len = strlen(find);
        do 
        {
            do 
            {
                if((sc = *s++) == 0)
                    return (NULL);
            } 
            while((char)tolower((unsigned char)sc) != c);
        } 
        while (strncasecmp(s, find, len) != 0);
        s--;
    }
    return((const char*)s);
}

#endif

#ifndef HAVE_SETENV

#include <stdio.h>

int setenv(const char* name, const char* value, int overwrite)
{
	char* t;
	int r;
	if(getenv(name) && !overwrite)
		return 0;
	t = (char*)malloc((strlen(name) + strlen(value) + 2) * sizeof(char));
	if(!t) return -1;
	sprintf(t, "%s=%s", name, value);
	r = putenv(t);
	if(r != 0)
		free(t);
	return r;
}

#endif

#ifndef HAVE_DAEMON

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>

int daemon(int nochdir, int noclose)
{
	struct sigaction osa, sa;
	int oerrno, fd, osa_ok;
	pid_t newgrp;

	/* A SIGHUP may be thrown when the parent exits below. */
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = SIG_IGN;
	sa.sa_flags = 0;
	osa_ok = sigaction(SIGHUP, &sa, &osa);
    
	switch(fork()) 
	{
	case -1:
		return -1;
	case 0:
		break;
	default:
		_exit(0);
	}

	newgrp = setsid();
	oerrno = errno;
	if(osa_ok != -1)
		sigaction(SIGHUP, &osa, NULL);
	if(newgrp == -1) 
	{
		errno = oerrno;
		return -1;
	}
	if(!nochdir)
		chdir("/");
        if(!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) 
	{
		dup2(fd, STDIN_FILENO);
		dup2(fd, STDOUT_FILENO);
		dup2(fd, STDERR_FILENO);
		if(fd > 2)
			close(fd);
        }
        return 0;

}

#endif

#ifndef HAVE_GETLINE

ssize_t getline(char** lineptr, size_t* n, FILE* stream)
{
    return getdelim(lineptr, n, '\n', stream);
}

#endif

#ifndef HAVE_GETDELIM

ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream)
{
    size_t written = 0;
    int allocated, ch;
    ssize_t ret = -1;
    char* p;
    
    if(!n || !lineptr || !stream)
    {
        errno = EINVAL;
        return -1;
    }
    
    /* Track whether we allocated this or not */
    allocated = !(*lineptr);
    
#ifdef HAVE_FLOCKFILE
    /* Affects performance on Solaris. */
    flockfile(stream);
#endif
    
    for(;;) 
    {
        if(!*lineptr)
            *n = 0;
        
        /* Reallocate if we need more space */
        if(written == *n - 1) 
        {
            *n = *n ? *n * 2 : 256;
            if(!(p = (char*)realloc(*lineptr, *n)))
            {
                if(allocated && *lineptr)
                    free(*lineptr);
                errno = ENOMEM;
                ret = -1;
                goto finally;
            }
            *lineptr = p;
        }
        
        while(written < *n - 1)
        {
#ifdef HAVE_FLOCKFILE
            ch = getc_unlocked(stream);
#else
            ch = fgetc(stream);
#endif

            if(ferror(stream)) 
            {
                if(allocated && *lineptr)
                    free(*lineptr);
                ret = -1;
                goto finally;
            }

            if(ch != EOF)
                (*lineptr)[written++] = ch;
            
            /* Done, null terminate, return */
            if(ch == EOF || ch == delim)
            {
                (*lineptr)[written] = 0;
                ret = written ? written : -1;
                goto finally;
            }
        }
    }    
finally:
    
#ifdef HAVE_FLOCKFILE
    funlockfile(stream);
#endif
    return ret;
}

#endif

#ifndef HAVE_ERR_H

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

extern char** __argv;

static const char* calc_prog_name()
{
	static char prognamebuf[256];
	static int prepared = 0;

	if(!prepared)
	{
		const char* beg = strrchr(__argv[0], '\\');
		const char* temp = strrchr(__argv[0], '/');
		beg = (beg > temp) ? beg : temp;
		beg = (beg) ? beg + 1 : __argv[0];

		temp = strrchr(__argv[0], '.');
		temp = (temp > beg) ? temp : __argv[0] + strlen(__argv[0]);

		if((temp - beg) > 255)
			temp = beg + 255;

		strncpy(prognamebuf, beg, temp - beg);
		prognamebuf[temp - beg] = 0;
		prepared = 1;
	}

	return prognamebuf;
}

static FILE* err_file; /* file to use for error output */

/*
 * This is declared to take a `void *' so that the caller is not required
 * to include <stdio.h> first.  However, it is really a `FILE *', and the
 * manual page documents it as such.
 */
void err_set_file(void *fp)
{
	if (fp)
		err_file = fp;
	else
		err_file = stderr;
}

void err(int eval, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	verrc(eval, errno, fmt, ap);
	va_end(ap);
}

void verr(int eval, const char *fmt, va_list ap)
{
	verrc(eval, errno, fmt, ap);
}

void errc(int eval, int code, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	verrc(eval, code, fmt, ap);
	va_end(ap);
}

void verrc(int eval, int code, const char *fmt, va_list ap)
{
	if (err_file == 0)
		err_set_file((FILE *)0);
	fprintf(err_file, "%s: ", calc_prog_name());
	if (fmt != NULL) {
		vfprintf(err_file, fmt, ap);
		fprintf(err_file, ": ");
	}
	fprintf(err_file, "%s\n", strerror(code));
	exit(eval);
}

void errx(int eval, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	verrx(eval, fmt, ap);
	va_end(ap);
}

void verrx(int eval, const char *fmt, va_list ap)
{
	if (err_file == 0)
		err_set_file((FILE *)0);
	fprintf(err_file, "%s: ", calc_prog_name());
	if (fmt != NULL)
		vfprintf(err_file, fmt, ap);
	fprintf(err_file, "\n");
	exit(eval);
}

void warn(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vwarnc(errno, fmt, ap);
	va_end(ap);
}

void vwarn(const char *fmt, va_list ap)
{
	vwarnc(errno, fmt, ap);
}

void warnc(int code, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vwarnc(code, fmt, ap);
	va_end(ap);
}

void vwarnc(int code, const char *fmt, va_list ap)
{
	if (err_file == 0)
		err_set_file((FILE *)0);
	fprintf(err_file, "%s: ", calc_prog_name());
	if (fmt != NULL) 
	{
		vfprintf(err_file, fmt, ap);
		fprintf(err_file, ": ");
	}
	fprintf(err_file, "%s\n", strerror(code));
}

void warnx(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vwarnx(fmt, ap);
	va_end(ap);
}

void vwarnx(const char *fmt, va_list ap)
{
	if(err_file == 0)
		err_set_file((FILE*)0);
	fprintf(err_file, "%s: ", calc_prog_name());
	if(fmt != NULL)
		vfprintf(err_file, fmt, ap);
	fprintf(err_file, "\n");
}

#endif

