1/*---------------------------------------------------------------------------*
2 *  SymbolTable.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20#include "SR_SymbolTable.h"
21#include "plog.h"
22#include "pmemory.h"
23
24
25static const char* MTAG = __FILE__;
26
27ESR_ReturnCode ST_Init(SymbolTable **ptr)
28{
29  ESR_ReturnCode rc;
30
31  if (ptr == NULL)
32  {
33    PLogError(L("ESR_INVALID_ARGUMENT"));
34    return ESR_INVALID_ARGUMENT;
35  }
36  *ptr = NEW(SymbolTable, MTAG);
37
38  if (*ptr == NULL)
39  {
40    PLogError(L("ESR_OUT_OF_MEMORY"));
41    return ESR_OUT_OF_MEMORY;
42  }
43  CHKLOG(rc, HashMapCreate(&(*ptr)->hashmap));
44
45  (*ptr)->num_special_symbols = 0;
46
47  /* init the memory for the hashtable */
48  return ST_reset(*ptr);
49CLEANUP:
50  return rc;
51}
52
53ESR_ReturnCode ST_Free(SymbolTable *self)
54{
55  ESR_ReturnCode rc;
56
57  if (self == NULL)
58  {
59    PLogError(L("ESR_INVALID_ARGUMENT"));
60    return ESR_INVALID_ARGUMENT;
61  }
62
63  /* free all the slots that were used
64     and remove all hashtable entries */
65  ST_reset(self);
66
67  /* delete the hash table */
68  if (self->hashmap)
69    CHKLOG(rc, HashMapDestroy(self->hashmap));
70
71  /* delete the symbol table */
72  if (self != NULL)
73    FREE(self);
74  return ESR_SUCCESS;
75CLEANUP:
76  return rc;
77}
78
79ESR_ReturnCode ST_putKeyValue(SymbolTable* self, const LCHAR* key, const LCHAR* value)
80{
81  Symbol* symbol;
82  LCHAR* buf;
83  ESR_ReturnCode rc;
84
85  if (self == NULL || key == NULL || value == NULL)
86  {
87    PLogError(L("ESR_INVALID_ARGUMENT"));
88    return ESR_INVALID_ARGUMENT;
89  }
90  /* reuse the old entry if it exists
91   but if no old entry exists for this key then I need to create a new one */
92  rc = HashMapGet(self->hashmap, key, (void**) & buf);
93  if (rc == ESR_NO_MATCH_ERROR)
94  {
95    CHKLOG(rc, ST_getSymbolSlot(self, &symbol));
96
97    /* copy the key */
98    MEMCHK(rc, LSTRLEN(key), MAX_SEMPROC_KEY);
99    LSTRCPY(symbol->key, key);
100
101    /* creates a new entry if it does not already exist */
102    CHKLOG(rc, HashMapPut(self->hashmap, symbol->key, symbol->value));
103
104    /* for later */
105    buf = symbol->value;
106  }
107  else if (rc != ESR_SUCCESS)
108    return rc;
109
110  if (LSTRLEN(value) >= MAX_SEMPROC_VALUE)
111    PLogError("Warning: chopping length of value len %d > %d (%s)\n", LSTRLEN(value), MAX_SEMPROC_VALUE, value);
112  LSTRNCPY(buf, value, MAX_SEMPROC_VALUE);
113  buf[MAX_SEMPROC_VALUE-1] = 0;
114  /* MEMCHK(rc, LSTRLEN(value), MAX_SEMPROC_VALUE);
115     LSTRCPY(buf, value); */
116  return ESR_SUCCESS;
117CLEANUP:
118  return rc;
119}
120
121ESR_ReturnCode ST_Copy(SymbolTable* self, HashMap* dst)
122{
123  static const LCHAR* _MTAG = L("semproc.st.copy");
124  size_t i, size;
125  LCHAR *pkey;
126  LCHAR *pvalue;
127  LCHAR *copyValue;
128
129  if (!dst) return ESR_INVALID_ARGUMENT;
130
131  HashMapGetSize(self->hashmap, &size);
132  for (i = 0;i < size;i++)
133  {
134    HashMapGetKeyAtIndex(self->hashmap, i, &pkey);
135    HashMapGet(self->hashmap, pkey, (void **)&pvalue);
136    /* add one more space */
137    copyValue = (LCHAR*) CALLOC(LSTRLEN(pvalue) + 1, sizeof(LCHAR), _MTAG);
138    if (!copyValue)
139    {
140      PLogError(L("ESR_OUT_OF_MEMORY"));
141      return ESR_OUT_OF_MEMORY;
142    }
143    LSTRCPY(copyValue, pvalue);
144    HashMapPut(dst, pkey, copyValue);
145  }
146  return ESR_SUCCESS;
147}
148
149ESR_ReturnCode ST_getKeyValue(SymbolTable* self, const LCHAR* key, LCHAR** value)
150{
151  ESR_ReturnCode rc;
152  LCHAR *dot;
153  size_t i;
154
155  if (self == NULL || key == NULL || value == NULL)
156  {
157    PLogError(L("ESR_INVALID_ARGUMENT"));
158    return ESR_INVALID_ARGUMENT;
159  }
160
161  rc = HashMapGet(self->hashmap, key, (void**)value);
162
163  if (rc == ESR_SUCCESS || rc != ESR_NO_MATCH_ERROR)
164    return rc;
165
166  if (rc == ESR_NO_MATCH_ERROR)
167  {
168    /* handle SPECIAL CASEs */
169    for (i = 0;i < self->num_special_symbols; i++)
170    {
171      /* try as is */
172      if (!LSTRCMP(key, self->SpecialSymbols[i].key))
173      {
174        *value = self->SpecialSymbols[i].value;
175        return ESR_SUCCESS;
176      }
177
178      /* try without dot */
179      dot = LSTRCHR(key, L('.'));
180      if (dot)
181        key = ++dot;
182
183      /* is it a match? */
184      if (!LSTRCMP(key, self->SpecialSymbols[i].key))
185      {
186        *value = self->SpecialSymbols[i].value;
187        return ESR_SUCCESS;
188      }
189    }
190  }
191
192  *value = UNDEFINED_SYMBOL;
193  return ESR_SUCCESS;
194}
195
196ESR_ReturnCode ST_getSymbolSlot(SymbolTable* ptr, Symbol** slot)
197{
198  ESR_ReturnCode rc;
199
200  if (ptr == NULL || slot == NULL)
201  {
202    PLogError(L("ESR_INVALID_ARGUMENT"));
203    return ESR_INVALID_ARGUMENT;
204  }
205
206  *slot = ptr->next++;
207  MEMCHK(rc, ptr->next, &ptr->Symbols[MAX_SYMBOLS-1]);
208  return ESR_SUCCESS;
209CLEANUP:
210  return rc;
211}
212
213ESR_ReturnCode ST_reset(SymbolTable *ptr)
214{
215  int i;
216  ESR_ReturnCode rc;
217
218  if (ptr == NULL)
219  {
220    PLogError(L("ESR_INVALID_ARGUMENT"));
221    return ESR_INVALID_ARGUMENT;
222  }
223  CHKLOG(rc, HashMapRemoveAll(ptr->hashmap));
224  ptr->next = &ptr->Symbols[0];
225  for (i = 0; i < MAX_SYMBOLS; i++)
226  {
227    ptr->Symbols[i].key[0] = 0;
228    ptr->Symbols[i].value[0] = 0;
229  }
230  return ESR_SUCCESS;
231CLEANUP:
232  return rc;
233}
234
235ESR_ReturnCode ST_reset_all(SymbolTable *ptr)
236{
237  int i;
238  ESR_ReturnCode rc;
239
240  if (ptr == NULL)
241  {
242    PLogError(L("ESR_INVALID_ARGUMENT"));
243    return ESR_INVALID_ARGUMENT;
244  }
245  CHKLOG(rc, HashMapRemoveAll(ptr->hashmap));
246  ptr->next = &ptr->Symbols[0
247                           ];
248  for (i = 0; i < MAX_SYMBOLS; i++)
249  {
250    ptr->Symbols[i].key[0] = 0;
251    ptr->Symbols[i].value[0] = 0;
252  }
253  for (i = 0; i < MAX_SPECIAL_SYMBOLS; i++)
254  {
255    ptr->SpecialSymbols[i].key[0] = 0;
256    ptr->SpecialSymbols[i].value[0] = 0;
257  }
258  ptr->num_special_symbols = 0;
259  return ESR_SUCCESS;
260CLEANUP:
261  return rc;
262}
263
264ESR_ReturnCode ST_putSpecialKeyValue(SymbolTable* self, const LCHAR* key, const LCHAR* value)
265{
266  size_t i;
267
268  if (self == NULL || key == NULL || value == NULL)
269  {
270    PLogError(L("ESR_INVALID_ARGUMENT"));
271    return ESR_INVALID_ARGUMENT;
272  }
273
274  /* see if already there, and overwrite */
275  for (i = 0;i < self->num_special_symbols;i++)
276  {
277    if (!LSTRCMP(self->SpecialSymbols[i].key, key))
278    {
279      LSTRCPY(self->SpecialSymbols[i].value, value);
280      return ESR_SUCCESS;
281    }
282  }
283
284  if (self->num_special_symbols < MAX_SPECIAL_SYMBOLS)
285  {
286    LSTRCPY(self->SpecialSymbols[self->num_special_symbols].key, key);
287    LSTRCPY(self->SpecialSymbols[self->num_special_symbols].value, value);
288    ++self->num_special_symbols;
289    return ESR_SUCCESS;
290  }
291  PLogError(L("Semproc: Symbol table has too many special symbols"));
292  return ESR_BUFFER_OVERFLOW;
293}
294