/*
 * libkarma/pathedit.c
 *
 * Pathname editing
 *
 * Copyright (c) Enrique Vidal 2005, adapted from "tr.c", 
 * Copyright (c) ams@wiw.org (Abhijit Menon-Sen) 1998.
 *
 * You may distribute and modify this program under the terms of 
 * the GNU GPL, version 2 or later.
 */

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

#define ins(p, c) *p++ = c
#define next(p) *p++

int isodigit (char d);
char esc(char c);
char *expand(char *str);
void tr(char *str, char *orig, char *sub, char *del, int squeezeRep);

int isodigit (char d)
{
    if ('0' <= d && d <= '7') { return 1; }
    return 0;
}

char esc(char c)
{
    switch (c) {
        case 'a': c = '\a'; break;
        case 'b': c = '\b'; break;
        case 'f': c = '\f'; break;
        case 'n': c = '\n'; break;
        case 'r': c = '\r'; break;
        case 't': c = '\t'; break;
        case 'v': c = '\v'; break;
        default:  break;
    }
    return (c);
}

char *expand(char *str)
{
    static char buf[512], num[8];
    char i, j=0, k, *o = buf, *p = num;
    int a, class = 0;

    while ((i = next(str))) {
        switch (i) {
            case '\\':
                if (!(k = next(str))) {
                    fprintf(stderr, "hanging '\\'.\n");
                    exit(1);
                } else if (tolower(k) == 'x') {
                    p = num;
                    if ((k = next(str)) == 0 || !isxdigit(k)) {
                        fprintf(stderr, "parse error in \\x.\n");
                        exit(1);
                    }
                    *p++ = k; *p = 0; a = strtol(num, NULL, 16);
                    if ((k = next(str)) == 0 || !isxdigit(k)) {
                        ins(o, (char)a); str--;
                    } else {
                        *p++ = k; *p = 0; a = strtol(num, NULL, 16);
                        ins(o, (char)a);
                    }
                } else if (isodigit(k)) {
                    p = num;
                    *p++ = k; *p = 0; a = strtol(num, NULL, 8);
                    if ((k = next(str)) == 0 || !isodigit(k)) {
                        ins(o, (char)a); str--;
                    } else {
                        *p++ = k; *p = 0; a = strtol(num, NULL, 8);
                        if ((k = next(str)) == 0 || !isodigit(k)) {
                            ins(o, (char)a); str--;
                        } else {
                            *p++ = k; *p = 0; a = strtol(num, NULL, 8);
                            ins(o, (char)a);
                        }
                    }
                }
                else { ins(o, esc(k)); }
                break;
            case '[':
                if (++class > 1) {
                    fprintf(stderr, "* Literal [ inside character class.\n");
                    exit(1);
                }
                break;
            case '.':
                if (!class) { ins(o, '.'); }
                else {
                    for (a = 0x20; a < 0x7f; ++a) { ins(o, (char)a); }
                }
                break;
            case '-':
                if (!class || (k = next(str)) == ']') {
                    ins(o, '-');
                    if (class) { class--; }
                } else {
                    if (j < k) {
                        for (i = j+1; i <= k; ++i) { ins(o, i); }
                    } else if (k < j) {
                        for (i = j-1; i >= k; --i) { ins(o, i); }
                    }
                }
                break;
            case ']':
                if (--class) {
                    fprintf(stderr,"* literal ] outside character class.\n");
                    exit(1);
                }
                break;
            default:
                ins(o, i);
        }
        j = i;
    }
    ins(o, 0);
    return (buf);
}

void tr(char *str, char *orig, char *sub, char *del, int squeezeRep)
{
    char c, a[1024], b[1024], d[1024];
    int tab[256], i, cc, s1, s2;
    char *q, *p=str;

    for (i = 0; i < 256; ++i) {
        tab[i] = i;
    }
    strcpy(a, expand(orig));
    strcpy(b, expand(sub));
    strcpy(d, expand(del));
    s1 = strlen(a);
    s2 = strlen(b);

    for (i = 0; i < s1; ++i) {
        cc=(int)a[i]; cc = (cc<0)?cc+256:cc;
        tab[cc] = i < s2 ? b[i] : b[s2 - 1];
/*      tab[(int)a[i]] = i < s2 ? b[i] : b[s2 - 1]; */
    }
    while ((c = *str)) {
        cc = (c<0)?c+256:c;
        *str++ = tab[cc];
    }
/*  /////////////// Moved AFTER delete
    if (squeezeRep) {
        q=str=p;
        while ((c = *str)) {
            *str++;
            if ((c != *str) || (strchr(b, c)==NULL)) {*q++; *q=*str;}
        }
    }
*/
    if(del && (strlen(del)>0)) {
        q=str=p;
        while ((c = *str)) {
            if ((strchr(d, c)==NULL)) *q++=*str;
            str++;
        }
        *q='\0';
    }
    if (squeezeRep) {
        q=str=p;
        while ((c = *str)) {
            str++;
            if ((c != *str) || (strchr(b, c)==NULL)) {q++; *q=*str;}
        }
    }
}
/* -------------------------- End pathname editing -------------------------- */
