/* strutil.c - String utility functions
 *
 * Copyright (C) 2005, 2007  Oskar Liljeblad
 *
 * 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 3 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 Library 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <config.h>
#include <sys/types.h>	/* POSIX: ssize_t */
#include <stdlib.h>	/* C89: malloc */
#include <stdbool.h>	/* Gnulib, POSIX, C99 */
#include <string.h>	/* C89 */
#include "xalloc.h"	/* Gnulib */

/* Allocate a string that is N duplicates of STR. */
char *
strdupn(const char *str, size_t n)
{
    char *out;
    size_t len;

    len = strlen(str);
    out = malloc(n*len+1);
    if (out != NULL) {
    	out[n*len] = '\0';
    	for (; n > 0; n--)   
            memcpy(out+(n-1)*len, str, len);
    }

    return out;
}

char *
xstrdupn(const char *str, size_t n)
{
    char *out;
    out = strdupn(str, n);
    if (out == NULL)
        xalloc_die();
    return out;
}   

/* Improve: return string position or word index in csv where value was found
 */
bool
string_in_csv(const char *csv, char sep, const char *value)
{
    const char *p0;
    const char *p1;
    size_t len;
    
    len = strlen(value);
    for (p0 = csv; (p1 = strchr(p0, sep)) != NULL; p0 = p1+1) {
        if (p1-p0 == len && strncmp(p0, value, len) == 0)
            return true;                                 
    }
    if (strcmp(p0, value) == 0)
        return true;
    
    return false;
}

/* ends_with AKA strrightcmp
 * Improve: return <,=,> 0 just like str* functions.
 */
bool
ends_with(const char *str, const char *end)
{
    ssize_t diff = strlen(str) - strlen(end);
    return diff >= 0 && strcmp(str+diff, end);   
}

/* ends_with_nocase AKA strrightcasecmp
 * Improve: return <,=,> 0 just like str* functions.
 */
bool
ends_with_nocase(const char *str, const char *end)
{
    ssize_t diff = strlen(str) - strlen(end);
    return diff >= 0 && strcasecmp(str+diff, end) == 0;
}

/* chomp(buf,len)
 * Remove trailing newline (LF or CR LF) from a string STR, update the
 * length LEN.
 */
size_t
chomp(char *buf, size_t len)
{
    if (len >= 1 && buf[len-1] == '\n') {
        if (len >= 2 && buf[len-2] == '\r') {    
            len -= 2;
        } else {
            len -= 1;
        }
        buf[len] = '\0';
    }
    return len;
}


/* Concatenate two file names.
 * An empty path component ("") is equivalent to the current directory,
 * but will not yield "./" when concatenated.
 * This function does not use the file system in any way.
 * Therefore it belongs in strutil.c, not some other file.
 */
char *
concat_filenames(const char *p1, const char *p2)
{
    size_t l1;
    size_t l2;
    char *out;

    if (*p1 == '\0' && *p2 == '\0')
        return xstrdup(".");
    if (*p1 == '\0')
        return xstrdup(p2);
    if (*p2 == '\0')
        return xstrdup(p1);

    l1 = strlen(p1);
    l2 = strlen(p2);

    if (p1[l1-1] == '/')
        l1--;

    out = xmalloc(l1+1+l2+1);
    memcpy(out, p1, l1);
    out[l1] = '/';
    memcpy(out+l1+1, p2, l2+1);
    return out;
}

/* Replace all occurences of in with out in str. */
void
strreplace(char *str, char in, char out)
{
    for (; *str != '\0'; str++) {
	if (*str == in)
	    *str = out;
    }
}
