/*-
* Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: word.c,v 1.7 1998/11/11 05:47:05 fjoe Exp $
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "merc.h"
#include "db/db.h"
#include "db/lang.h"
#include "db/word.h"
#define wordhash(s) hashstr(s, 16, MAX_WORD_HASH)
const char* word_form_lookup(varr **hashp, const char *word, int num);
static int cmpword(const void *p1, const void *p2);
WORD_DATA *word_new(int lang)
{
WORD_DATA *w = calloc(1, sizeof(WORD_DATA));
w->base = str_empty;
w->f.nsize = sizeof(char*);
w->f.nstep = 4;
w->lang = lang;
return w;
}
WORD_DATA *word_add(varr **hashp, WORD_DATA *w)
{
WORD_DATA *wnew;
varr *v;
int hash;
if (IS_NULLSTR(w->name))
return NULL;
v = hashp[hash = wordhash(w->name)];
if (v == NULL)
v = hashp[hash] = varr_new(sizeof(WORD_DATA), 4);
if (varr_bsearch(v, w, cmpword))
return NULL;
wnew = varr_enew(v);
*wnew = *w;
varr_qsort(v, cmpword);
return varr_bsearch(v, w, cmpword);
}
void word_del(varr **hashp, const char *name)
{
varr *v;
WORD_DATA *w;
if (IS_NULLSTR(name))
return;
v = hashp[wordhash(name)];
if (v == NULL)
return;
if ((w = varr_bsearch(v, &name, cmpword)) == NULL)
return;
word_free(w);
w->name = NULL;
varr_qsort(v, cmpword);
v->nused--;
}
WORD_DATA *word_lookup(varr **hashp, const char *name)
{
if (IS_NULLSTR(name))
return NULL;
return varr_bsearch(hashp[wordhash(name)], &name, cmpword);
}
void word_form_add(WORD_DATA* w, int fnum, const char *s)
{
const char **p = varr_touch(&w->f, fnum);
if (*p)
free_string(*p);
*p = str_dup(s);
}
void word_form_del(WORD_DATA *w, int fnum)
{
const char **p = varr_get(&w->f, fnum);
if (*p)
free_string(*p);
*p = NULL;
}
void word_free(WORD_DATA *w)
{
int i;
free_string(w->name);
free_string(w->base);
for (i = 0; i < w->f.nused; i++)
free_string(VARR_GET(&w->f, i));
}
const char *word_gender(int lang, const char *word, int gender)
{
LANG_DATA *l = varr_get(&langs, lang);
if (l == NULL)
return word;
return word_form_lookup(l->hash_genders, word,
(gender + SEX_MAX - 1) % SEX_MAX);
}
const char *word_case(int lang, const char *word, int num)
{
LANG_DATA *l = varr_get(&langs, lang);
if (l == NULL)
return word;
return word_form_lookup(l->hash_cases, word, num);
}
/* local functions */
const char* word_form_lookup(varr **hashp, const char *word, int num)
{
int hash;
varr *v;
WORD_DATA *w;
char **p;
static char buf[MAX_STRING_LENGTH];
if (IS_NULLSTR(word) || num == 0)
return word;
hash = wordhash(word);
if ((v = hashp[hash]) == NULL
|| (w = varr_bsearch(v, &word, cmpword)) == NULL
|| (p = varr_get(&w->f, num)) == NULL
|| IS_NULLSTR(*p))
return word;
if (**p != '-')
return *p;
strnzcpy(buf, w->base, sizeof(buf));
strnzcat(buf, *p + 1, sizeof(buf));
return buf;
}
/* reverse order (otherwise word_del will not work) */
int cmpword(const void *p1, const void *p2)
{
return -str_cmp(((WORD_DATA*) p1)->name, ((WORD_DATA*) p2)->name);
}