/* $Id: identifier.c,v 1.12 2009/01/27 15:40:22 potyra Exp $ 
 *
 * Copyright (C) 2007-2009 FAUcc Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

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

#include "identifier.h"

struct identifier {
	struct identifier *prev;
	struct identifier *next;

	const char *string;
};

static struct identifier *hash_first[IDENTIFIER_HASH_SIZE];
static struct identifier *hash_last[IDENTIFIER_HASH_SIZE];


unsigned int
identifier_hash(const char *_n)
{
	const unsigned char *n = (const unsigned char *) _n;
	unsigned int sum;

	while (*n == '_') {
		n++;
	}

	sum = 0;
	while (*n) {
		if ('0' <= *n && *n <= '9') {
			sum *= 10;
			sum += *n - '0';
		} else {
			sum <<= 5;
			sum += *n & 0x1f;
		}
		n++;
	}
	sum %= IDENTIFIER_HASH_SIZE;

	return sum;
}

const char *
identifier_new(const char *n)
{
	struct identifier *id;
	unsigned int hash;

	hash = identifier_hash(n);

	for (id = hash_first[hash]; ; id = id->next) {
		if (! id) {
			/* New entry. */
			id = malloc(sizeof(*id));
			assert(id);

			id->string = strdup(n);
			assert(id->string);

			id->prev = hash_last[hash];
			id->next = NULL;
			if (id->prev) {
				id->prev->next = id;
			} else {
				hash_first[hash] = id;
			}
			hash_last[hash] = id;
			break;
		}
		if (strcmp(n, id->string) == 0) {
			/* Entry found. */
			break;
		}
	}

	return id->string;
}

const char *
identifier_tmp(void)
{
	static unsigned int count = 0;
	char name[20];

	sprintf(name, "__%u", count++);

	return identifier_new(name);
}

int
identifier_is_tmp(const char *name)
{
	unsigned int i;

	if (name[0] != '_') return 0;
	if (name[1] != '_') return 0;
	for (i = 2; name[i]; i++) {
		if (! isdigit(name[i])) return 0;
	}
	return 1;
}

const char *
identifier_dup(const char *n)
{
	return n;
}

void
identifier_free(const char *n)
{
}
