Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
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 
51 template<class ENUM, class VAL, class INFO>
52 void EST_TValuedEnumI<ENUM,VAL,INFO>::initialise(const void *vdefs)
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 
72 template<class ENUM, class VAL, class INFO>
73 void 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 
110 template<class ENUM, class VAL, class INFO>
112 {
113  if (this->definitions)
114  delete[] this->definitions;
115 }
116 
117 template<class ENUM, class VAL, class INFO>
119 {
120 return this->ndefinitions;
121 }
122 
123 template<class ENUM, class VAL, class INFO>
124 VAL 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 
135 template<class ENUM, class VAL, class INFO>
136 INFO &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 
151 template<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 
160 template<class ENUM, class VAL, class INFO>
161 ENUM 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 
173 template<class ENUM>
174 EST_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 
300 template<class ENUM>
301 EST_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