/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2012  Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/

#include "header.h"

#include <zstring.h>
#include <zdebug.h>

#ifdef LEAK_DEBUG_LIST
struct zstring *debug_zconcatesc(char *file, int line, char *s1, ...){
#else
struct zstring *zconcatesc(char *s1, ...){
#endif
    va_list l;
    size_t len;
    char  *d;
    char *s, *c;
    struct zstring *zs;

    va_start(l, s1);
    s = s1;
    len = 0;
    do {
        if (s != s1) len++;
        for (c = s; *c != '\0'; c++){
            switch(*c){
                case ';':
                case '\\':
                case '\r':
                case '\n':
                    len += 2;
                    break;
                default:
                    len++;
                    break;
            }
        }
    }while ((s = va_arg(l, char *)) != NULL);
    va_end(l);
    len++;

#ifdef LEAK_DEBUG_LIST
    zs = debug_g_malloc(file, line, sizeof(struct zstring));
    zs->str = d = debug_g_malloc(file, line, len);
    zs->file = file;
    zs->line = line;
#else
    zs = g_malloc(sizeof(struct zstring));
    zs->str = d = g_malloc(len);
#endif    

    va_start(l, s1);
    s = s1;
    len = 0;
    do {
        if (s != s1) *d++ = ';';
        for (c = s; *c != '\0'; c++){
            switch(*c){
                case ';':
                    *d++ = '\\';
                    *d++ = ';';
                    break;
                case '\\':
                    *d++ = '\\';
                    *d++ = '\\';
                    break;
                case '\r':
                    *d++ = '\\';
                    *d++ = 'r';
                    break;
                case '\n':
                    *d++ = '\\';
                    *d++ = 'n';
                    break;
                default:
                    *d++ = *c;
                    break;
            }
        }
    }while ((s = va_arg(l, char *)) != NULL);
    va_end(l);
    *d = '\0';
    return zs;
}

#ifdef LEAK_DEBUG_LIST
struct zstring *debug_zstrdup(char *file, int line, const char *str){
#else
struct zstring *zstrdup(const char *str){
#endif
    int len;
    struct zstring *zs;

    len = strlen(str);
#ifdef LEAK_DEBUG_LIST
    zs = debug_g_malloc(file, line, sizeof(struct zstring));
    zs->str = debug_g_malloc(file, line, len + 1);
    zs->file = file;
    zs->line = line;
#else
    zs = g_malloc(sizeof(struct zstring));
    zs->str = g_malloc(len + 1);
#endif    
    memcpy(zs->str, str, len + 1);
    return zs;
}

char *ztokenize(struct zstring *zstr, int first){
    int backslash=0;
    int i;
    char c, *d, *buf;
    int len;

    if (first) zstr->tokenpos = 0;
    len = strlen(zstr->str + zstr->tokenpos) + zstr->tokenpos;
    if (zstr->tokenpos > len) return NULL;
    if (zstr->tokenpos < 0) return NULL;
    buf = d = zstr->str + zstr->tokenpos;

    for (i = zstr->tokenpos; i < len; i++){
        c = zstr->str[i];
        if (backslash){
            backslash = 0;
            switch(c){
                case '\\':
                case ';':
                    break;
                case 'r':
                    c = '\r';
                    break;
                case 'n':
                    c = '\n';
                    break;
                default: /* error */
                    error("bad escape \\%c\n", c);
                    break;
            }
        }else{
            switch (c){
                case '\\':
                    backslash = 1;
                    continue;
                case ';':
                    zstr->tokenpos = i + 1;
                    *d='\0';
                    return buf;
                default:
                    break;
            }
        }
        *d++ = c;
    }
    zstr->tokenpos = -1;
    *d='\0';
    return buf;
}

void zfree(struct zstring *zstr){
    g_free(zstr->str);
    zstr->str = NULL;
    g_free(zstr);
}

int ztokens(struct zstring *zstr){
    int backslash=0;
    int tokens=1;
    char *c;

    for (c = zstr->str; *c != '\0'; c++){
        if (backslash){
            backslash = 0;
            continue;
        }

        switch (*c){
            case '\\':
                backslash = 1;
                break;
            case ';':
                tokens++;
                break;
        }
    }
    return tokens;
}

int zwrite(int fd, struct zstring *zs){
#ifdef Z_MSC_MINGW
	zinternal("zwrite unimplemented");
	return -1;
#else
	int ret;
    gchar *c;
    
    c = g_strconcat(zs->str, "\n", NULL);
	zfree(zs);
	ret = write(fd, c, strlen(c));
    g_free(c);
	return ret;
#endif
}


#if 0
int main(){
    char *c;
    zchar *z;
    int i;

    c = zconcatesc("aa", ";", "", NULL);
    printf("c='%s'\n", c);
    z = zstrdup(c);
    printf("z='%s'\n", z);

    i = 0;
    for (c = ztokenize(z, 1); c != NULL; c = ztokenize(z, 0)){
        printf("%d='%s'\n", i, c);
        i++;
    }
    zfree(z);
    return 0;
}
#endif
