Edinburgh Speech Tools 2.4-release
EST_TNamedEnum.cc
1 /************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1996,1997 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /************************************************************************/
33 /* Author: Richard Caley (rjc@cstr.ed.ac.uk) */
34 /* Date: Fri Feb 28 1997 */
35 /************************************************************************/
36 /* */
37 /* A template class which allows names (const char *s) to be */
38 /* associated with enums, providing conversion. */
39 /* */
40 /************************************************************************/
41
42#include <cstdlib>
43#include <iostream>
44#include <cstdio>
45#include "EST_walloc.h"
46#include "EST_TNamedEnum.h"
47
48// This only takes a void * because I can't manage to get the
49// parameter declaration in the definition past gcc with the actual type.
50
51template<class ENUM, class VAL, class INFO>
53{
54 int n=0;
56 const defn *defs = (const defn *)vdefs;
57
58 for(n=1; defs[n].token != defs[0].token; n++)
59 ;
60
61 this->ndefinitions = n;
62 this->definitions = new defn[n];
63
64 this->definitions[0] = defs[0];
65 for(n=1; defs[n].token != defs[0].token; n++)
66 this->definitions[n] = defs[n];
67
68 this->p_unknown_enum = defs[n].token;
69 this->p_unknown_value = defs[n].values[0];
70}
71
72template<class ENUM, class VAL, class INFO>
73void EST_TValuedEnumI<ENUM,VAL,INFO>::initialise(const void *vdefs, ENUM (*conv)(const char *))
74{
75 int n=0;
76 // const struct EST_TValuedEnumDefinition<const char *,VAL,INFO> *defs = (const struct EST_TValuedEnumDefinition<const char *,VAL,INFO> *)vdefs;
77
79 const _EST_TMPNAME *defs = (const _EST_TMPNAME *)vdefs;
80
81 // fprintf(stderr, "start setup\n");
82
83 for(n=1; strcmp(defs[n].token, defs[0].token) != 0; n++)
84 {
85 //const char *a = defs[0].token;
86 // const char *b = defs[n].token;
87 // fprintf(stderr, ": %d '%s' '%s'\n", n, defs[n].token, defs[0].token);
88 }
89
90 this->ndefinitions = n;
92 this->definitions = new defn[n];
93
94 this->definitions[0].token = conv(defs[0].token);
95 for(int i=0; i<NAMED_ENUM_MAX_SYNONYMS; i++)
96 this->definitions[0].values[i] = defs[0].values[i];
97 this->definitions[0].info = defs[0].info;
98 for(n=1; strcmp(defs[n].token, defs[0].token) != 0; n++)
99 {
100 this->definitions[n].token = conv(defs[n].token);
101 for(int i2=0; i2<NAMED_ENUM_MAX_SYNONYMS; i2++)
102 this->definitions[n].values[i2] = defs[n].values[i2];
103 this->definitions[n].info = defs[n].info;
104 }
105
106 this->p_unknown_enum = conv(defs[n].token);
107 this->p_unknown_value = defs[n].values[0];
108}
109
110template<class ENUM, class VAL, class INFO>
112{
113 if (this->definitions)
114 delete[] this->definitions;
115}
116
117template<class ENUM, class VAL, class INFO>
119{
120return this->ndefinitions;
121}
122
123template<class ENUM, class VAL, class INFO>
124VAL EST_TValuedEnumI<ENUM,VAL,INFO>::value (ENUM token, int n) const
125{
126 int i;
127
128 for(i=0; i<this->ndefinitions; i++)
129 if (this->definitions[i].token == token)
130 return this->definitions[i].values[n];
131
132 return this->p_unknown_value;
133}
134
135template<class ENUM, class VAL, class INFO>
136INFO &EST_TValuedEnumI<ENUM,VAL,INFO>::info (ENUM token) const
137{
138 int i;
139
140 for(i=0; i<this->ndefinitions; i++)
141 if (this->definitions[i].token == token)
142 return this->definitions[i].info;
143
144 cerr << "Fetching info for invalid entry\n";
145 abort();
146
147 static INFO dummyI;
148 return dummyI;
149}
150
151template<class ENUM, class VAL, class INFO>
153{
154 if (n>=0 && n < this->ndefinitions)
155 return this->definitions[n].token;
156
157 return this->p_unknown_enum;
158}
159
160template<class ENUM, class VAL, class INFO>
161ENUM EST_TValuedEnumI<ENUM,VAL,INFO>::token (VAL value) const
162{
163 int i,j;
164
165 for(i=0; i<this->ndefinitions; i++)
166 for(j=0; j<NAMED_ENUM_MAX_SYNONYMS && this->definitions[i].values[j] ; j++)
167 if (eq_vals(this->definitions[i].values[j], value))
168 return this->definitions[i].token;
169
170 return this->p_unknown_enum;
171}
172
173template<class ENUM>
174EST_read_status EST_TNamedEnum<ENUM>::priv_load(EST_String name, EST_TNamedEnum<ENUM> *definitive)
175{
177#define LINE_LENGTH (1024)
178 EST_String line(NULL, 'x', LINE_LENGTH);
179 char *buffer = (char *)line;
180 EST_String tokens[NAMED_ENUM_MAX_SYNONYMS+2];
181 FILE *file;
182 char quote = '\0';
183 int have_unknown=0;
184 int n=0;
185
186 if ((file=fopen(name, "rb"))==NULL)
187 return misc_read_error;
188
189 if (this->definitions)
190 delete[] this->definitions;
191
192 this->ndefinitions= -1;
193 this->definitions=NULL;
194
195 buffer[LINE_LENGTH-1] = 'x';
196
197 while (fgets(buffer, LINE_LENGTH, file))
198 {
199 if ( buffer[LINE_LENGTH-1] != 'x')
200 {
201 cerr << "line too long .. '" << buffer << "'\n";
202 return wrong_format;
203 }
204
205 if (this->ndefinitions>=0 && quote != '\0' && buffer[0] == '=')
206 {
207 // definition by number
208
209 if ( n>= this->ndefinitions)
210 {
211 cerr << "too many definitions\n";
212 return wrong_format;
213 }
214
215 int ntokens = split(line, tokens, NAMED_ENUM_MAX_SYNONYMS+2, RXwhite, '"');
216 this->definitions[n].token = (ENUM)atoi(tokens[0].after(0,1));
217
218 for(int i=1; i<ntokens; i++)
219 this->definitions[n].values[i-1] = wstrdup(tokens[i].unquote_if_needed(quote));
220 for(int j=ntokens-1 ; j< NAMED_ENUM_MAX_SYNONYMS; j++)
221 this->definitions[n].values[j]=NULL;
222
223 n++;
224 }
225 else if (have_unknown && this->ndefinitions>=0 && quote != '\0' && buffer[0] == quote)
226 {
227 // definition by standard name
228 if (!definitive)
229 {
230 cerr << "can't use names in this definition\n";
231 return wrong_format;
232 }
233 if ( n>= this->ndefinitions)
234 {
235 cerr << "too many definitions\n";
236 return wrong_format;
237 }
238
239 int ntokens = split(line, tokens, NAMED_ENUM_MAX_SYNONYMS+2, RXwhite, quote);
240
241 this->definitions[n].token = definitive->token(tokens[0].unquote(quote));
242
243 for(int i=1; i<ntokens; i++)
244 this->definitions[n].values[i-1] = wstrdup(tokens[i].unquote_if_needed(quote));
245 for(int j=ntokens-1 ; j< NAMED_ENUM_MAX_SYNONYMS; j++)
246 this->definitions[n].values[j]=NULL;
247
248 n++;
249 }
250 else
251 {
252 // parameter
253
254 int mlen;
255 int eq = line.search("=", 1, mlen);
256
257 if (eq <0)
258 {
259 cerr << "bad header line '" << line;
260 return wrong_format;
261 }
262
263 EST_String key(line.before(eq));
264
265 if (key == "quote")
266 {
267 quote = line[eq+1];
268 // cout << "quote = '" << quote << "'\n";
269 }
270 else if (key == "number")
271 {
272 this->ndefinitions=atoi(line.after(eq,1));
273 // cout << "n = '" << ndefinitions << "'\n";
274 this->definitions = new Defn[this->ndefinitions];
275 for(int i=0; i<this->ndefinitions; i++)
276 this->definitions[i].values[0] =NULL;
277 n=0;
278 }
279 else if (key == "unknown")
280 {
281 this->p_unknown_enum=(ENUM)atoi(line.after(eq,1));
282 // cout << "unknown = '" << p_unknown_enum << "'\n";
283 have_unknown=1;
284 }
285 else
286 {
287 cerr << "bad header line '" << line;
288 return wrong_format;
289 }
290
291 }
292 }
293
294
295 fclose(file);
296
297 return format_ok;
298}
299
300template<class ENUM>
301EST_write_status EST_TNamedEnum<ENUM>::priv_save(EST_String name, EST_TNamedEnum<ENUM> *definitive, char quote) const
302{
303 FILE *file;
304
305 if ((file=fopen(name, "wb"))==NULL)
306 return write_fail;
307
308 fprintf(file, "unknown=%d\n", this->p_unknown_enum);
309 fprintf(file, "quote=%c\n", quote);
310 fprintf(file, "number=%d\n", this->ndefinitions);
311
312 for(int i=0; i<this->ndefinitions; i++)
313 if (this->definitions[i].values[0])
314 {
315 if (definitive)
316 fprintf(file, "%s ", (const char *)EST_String(definitive->name(this->definitions[i].token)).quote(quote));
317 else
318 fprintf(file, "=%d ", (int)this->definitions[i].token);
319
320 for(int j=0; j<NAMED_ENUM_MAX_SYNONYMS && this->definitions[i].values[j] != NULL; j++)
321 fprintf(file, "%s ", (const char *) EST_String(this->definitions[i].values[j]).quote_if_needed(quote));
322
323 fputc('\n', file);
324 }
325
326 fclose(file);
327
328 return write_ok;
329}
330
EST_String quote(const char quotec) const
Return the string in quotes with internal quotes protected.
Definition: EST_String.cc:1029