Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "common.h"

/*
 *  WARNING!  This turns all upper case names into lower case
 *  local ones.
 */

/* predeclared */
static String   *getdbfiles(void);
static int      translate(char*, char**, String*, String*);
static int      lookup(String**, String*, String*);
static int      compare(String*, char*);
static char*    mklower(char*);

static int debug;
static int from;
static char *namefiles = "namefiles";
#define DEBUG if(debug)

/* loop through the names to be translated */
void
main(int argc, char *argv[])
{
        String *s;
        String *alias;          /* the alias for the name */
        char **names;           /* names of this system */
        String *files;          /* list of files to search */
        int i, rv;
        char *p;

        ARGBEGIN {
        case 'd':
                debug = 1;
                break;
        case 'f':
                from = 1;
                break;
        case 'n':
                namefiles = ARGF();
                break;
        } ARGEND
        if (chdir(UPASLIB) < 0) {
                perror("translate(chdir):");
                exit(1);
        }

        /* get environmental info */
        names = sysnames_read();
        files = getdbfiles();
        alias = s_new();

        /* loop through the names to be translated (from standard input) */
        for(i=0; i<argc; i++) {
                s = unescapespecial(s_copy(mklower(argv[i])));
                if(strchr(s_to_c(s), '!') == 0)
                        rv = translate(s_to_c(s), names, files, alias);
                else
                        rv = -1;
                if(from){
                        if (rv >= 0 && *s_to_c(alias) != '\0'){
                                p = strchr(s_to_c(alias), '\n');
                                if(p)
                                        *p = 0;
                                p = strchr(s_to_c(alias), '!');
                                if(p) {
                                        *p = 0;
                                        print("%s", s_to_c(alias));
                                } else {
                                        p = strchr(s_to_c(alias), '@');
                                        if(p)
                                                print("%s", p+1);
                                        else
                                                print("%s", s_to_c(alias));
                                }
                        }
                } else {
                        if (rv < 0 || *s_to_c(alias) == '\0')
                                print("local!%s\n", s_to_c(s));
                        else {
                                /* this must be a write, not a print */
                                write(1, s_to_c(alias), strlen(s_to_c(alias)));
                        }
                }
                s_free(s);
        }
        exits(0);
}

/* get the list of dbfiles to search */
static String *
getdbfiles(void)
{
        Sinstack *sp;
        String *files = s_new();
        char *nf;

        if(from)
                nf = "fromfiles";
        else
                nf = namefiles;

        /* system wide aliases */
        if ((sp = s_allocinstack(nf)) != 0){
                while(s_rdinstack(sp, files))
                        s_append(files, " ");
                s_freeinstack(sp);
        }


        DEBUG print("files are %s\n", s_to_c(files));

        return files;
}

/* loop through the translation files */
static int
translate(char *name,           /* name to translate */
        char **namev,           /* names of this system */
        String *files,          /* names of system alias files */
        String *alias)          /* where to put the alias */
{
        String *file = s_new();
        String **fullnamev;
        int n, rv;

        rv = -1;

        DEBUG print("translate(%s, %s, %s)\n", name,
                s_to_c(files), s_to_c(alias));

        /* create the full name to avoid loops (system!name) */
        for(n = 0; namev[n]; n++)
                ;
        fullnamev = (String**)malloc(sizeof(String*)*(n+2));
        n = 0;
        fullnamev[n++] = s_copy(name);
        for(; *namev; namev++){
                fullnamev[n] = s_copy(*namev);
                s_append(fullnamev[n], "!");
                s_append(fullnamev[n], name);
                n++;
        }
        fullnamev[n] = 0;

        /* look at system-wide names */
        s_restart(files);
        while (s_parse(files, s_restart(file)) != 0) {
                if (lookup(fullnamev, file, alias)==0) {
                        rv = 0;
                        goto out;
                }
        }

out:
        for(n = 0; fullnamev[n]; n++)
                s_free(fullnamev[n]);
        s_free(file);
        free(fullnamev);
        return rv;
}

/*
 *  very dumb conversion to bang format
 */
static String*
attobang(String *token)
{
        char *p;
        String *tok;

        p = strchr(s_to_c(token), '@');
        if(p == 0)
                return token;

        p++;
        tok = s_copy(p);
        s_append(tok, "!");
        s_nappend(tok, s_to_c(token), p - s_to_c(token) - 1);

        return tok;
}

/*  Loop through the entries in a translation file looking for a match.
 *  Return 0 if found, -1 otherwise.
 */
static int
lookup(
        String **namev,
        String *file,
        String *alias)  /* returned String */
{
        String *line = s_new();
        String *token = s_new();
        String *bangtoken;
        int i, rv = -1;
        char *name =  s_to_c(namev[0]);
        Sinstack *sp;

        DEBUG print("lookup(%s, %s, %s, %s)\n", s_to_c(namev[0]), s_to_c(namev[1]),
                s_to_c(file), s_to_c(alias));

        s_reset(alias);
        if ((sp = s_allocinstack(s_to_c(file))) == 0)
                return -1;

        /* look for a match */
        while (s_rdinstack(sp, s_restart(line))!=0) {
                DEBUG print("line is %s\n", s_to_c(line));
                s_restart(token);
                if (s_parse(s_restart(line), token)==0)
                        continue;
                if (compare(token, "#include")==0){
                        if(s_parse(line, s_restart(token))!=0) {
                                if(lookup(namev, line, alias) == 0)
                                        break;
                        }
                        continue;
                }
                if (compare(token, name)!=0)
                        continue;
                /* match found, get the alias */
                while(s_parse(line, s_restart(token))!=0) {
                        bangtoken = attobang(token);

                        /* avoid definition loops */
                        for(i = 0; namev[i]; i++)
                                if(compare(bangtoken, s_to_c(namev[i]))==0) {
                                        s_append(alias, "local");
                                        s_append(alias, "!");
                                        s_append(alias, name);
                                        break;
                                }

                        if(namev[i] == 0)
                                s_append(alias, s_to_c(token));
                        s_append(alias, "\n");

                        if(bangtoken != token)
                                s_free(bangtoken);
                }
                rv = 0;
                break;
        }
        s_free(line);
        s_free(token);
        s_freeinstack(sp);
        return rv;
}

#define lower(c) ((c)>='A' && (c)<='Z' ? (c)-('A'-'a'):(c))

/* compare two Strings (case insensitive) */
static int
compare(String *s1,
        char *p2)
{
        char *p1 = s_to_c(s1);
        int rv;

        DEBUG print("comparing %s to %s\n", p1, p2);
        while((rv = lower(*p1) - lower(*p2)) == 0) {
                if (*p1 == '\0')
                        break;
                p1++;
                p2++;
        }
        return rv;
}

static char*
mklower(char *name)
{
        char *p;
        char c;

        for(p = name; *p; p++){
                c = *p;
                *p = lower(c);
        }
        return name;
}