/*
 * OpenComal -- a free Comal implementation
 *
 * This file is part of the OpenComal package.
 * (c) Copyright 1992-2024 Jos Visser <josvisser66@gmail.com>
 *
 * The OpenComal package is covered by the GNU General Public
 * License. See doc/LICENSE for more information.
 */

/* OpenComal's ID routines */

#include "pdcglob.h"
#include "pdcmisc.h"
#include "pdcstr.h"

PRIVATE struct id_rec *id_root = NULL;

/* With id_eql you can compare two identifiers by their handles. The caller
 * gets 1 if they are equal and 0 if the two identifiers are unequal.
 * STRCMP is used instead of pointer comparision because pointers to the
 * same memory location can take different values on an 8086 CPU environment. 
 */

PUBLIC int id_eql(struct id_rec *id1, struct id_rec *id2) {
    return (strcmp(id1->id_name, id2->id_name) == 0) ? 1 : 0;
}


/*
 * This private function install builds a new record in memory for the
 * specified id name. Memory is allocated from the free pool.
 */

PRIVATE struct id_rec *id_create(char *name) {
    struct id_rec *work;
    long l = my_strlen(name);

    work = GETCORE(MISC_POOL, struct id_rec);
    work->left = work->right = NULL;
    work->id_name = my_strdup(MISC_POOL, name);

    switch (work->id_name[l - 1]) {
        case '#':
            work->type = V_INT;
            break;
        case '$':
            work->type = V_STRING;
            break;
        default:
            work->type = V_FLOAT;
            break;
    }

    return work;
}

/*
 * The next routine does the horse work of searching and installing an
 * identifier.
 */
PRIVATE struct id_rec *id_horse(char *idname) {
    struct id_rec *walk;
    struct id_rec *lastone = NULL;
    struct id_rec *installed;
    enum {
        atroot, overleft, overright
    } lastchoice = atroot;
    int found;

    for (walk = id_root, found = 0; walk != NULL && !found;) {
        int cmp = strcmp(idname, walk->id_name);

        lastone = walk;

        if (cmp < 0) {
            lastchoice = overleft;
            walk = walk->left;
        } else if (cmp > 0) {
            lastchoice = overright;
            walk = walk->right;
        } else
            found = 1;
    }

    if (found)
        return walk;

    installed = id_create(idname);

    if (lastchoice == atroot)
        return (id_root = installed);
    else if (lastchoice == overleft)
        return (lastone->left = installed);
    else
        return (lastone->right = installed);
}


/* id_search searches for an identifier and if it is not present installs it.
 * A handle for the identifier is returned.
 */

PUBLIC struct id_rec *id_search(char *id) {
    char idname[MAX_IDLEN];
    register int i;

    for (i = 0; i < MAX_IDLEN; idname[i++] = '\0');

    strncpy(idname, id, MAX_IDLEN - 1);
    strlwr(idname);
    return id_horse(idname);
}
