1 /*************************************************************************/
2 /*                                                                       */
3 /*                  Language Technologies Institute                      */
4 /*                     Carnegie Mellon University                        */
5 /*                        Copyright (c) 1999                             */
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 /*  CARNEGIE MELLON UNIVERSITY 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 CARNEGIE MELLON UNIVERSITY 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:  Alan W Black (awb@cs.cmu.edu)                    */
34 /*               Date:  December 1999                                    */
35 /*************************************************************************/
36 /*                                                                       */
37 /*  Typed values                                                          */
38 /*                                                                       */
39 /*************************************************************************/
40 
41 /* ----------------------------------------------------------------- */
42 /*           The English TTS System "Flite+hts_engine"               */
43 /*           developed by HTS Working Group                          */
44 /*           http://hts-engine.sourceforge.net/                      */
45 /* ----------------------------------------------------------------- */
46 /*                                                                   */
47 /*  Copyright (c) 2005-2013  Nagoya Institute of Technology          */
48 /*                           Department of Computer Science          */
49 /*                                                                   */
50 /*                2005-2008  Tokyo Institute of Technology           */
51 /*                           Interdisciplinary Graduate School of    */
52 /*                           Science and Engineering                 */
53 /*                                                                   */
54 /* All rights reserved.                                              */
55 /*                                                                   */
56 /* Redistribution and use in source and binary forms, with or        */
57 /* without modification, are permitted provided that the following   */
58 /* conditions are met:                                               */
59 /*                                                                   */
60 /* - Redistributions of source code must retain the above copyright  */
61 /*   notice, this list of conditions and the following disclaimer.   */
62 /* - Redistributions in binary form must reproduce the above         */
63 /*   copyright notice, this list of conditions and the following     */
64 /*   disclaimer in the documentation and/or other materials provided */
65 /*   with the distribution.                                          */
66 /* - Neither the name of the HTS working group nor the names of its  */
67 /*   contributors may be used to endorse or promote products derived */
68 /*   from this software without specific prior written permission.   */
69 /*                                                                   */
70 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND            */
71 /* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,       */
72 /* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF          */
73 /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          */
74 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */
75 /* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          */
76 /* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
77 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
78 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
79 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   */
80 /* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY    */
81 /* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
82 /* POSSIBILITY OF SUCH DAMAGE.                                       */
83 /* ----------------------------------------------------------------- */
84 
85 #include "cst_math.h"
86 #include "cst_file.h"
87 #include "cst_val.h"
88 #include "cst_string.h"
89 
new_val()90 static cst_val *new_val()
91 {
92     return cst_alloc(struct cst_val_struct,1);
93 }
94 
int_val(int i)95 cst_val *int_val(int i)
96 {
97     cst_val *v = new_val();
98     CST_VAL_TYPE(v) = CST_VAL_TYPE_INT;
99     CST_VAL_INT(v) = i;
100     return v;
101 }
102 
float_val(float f)103 cst_val *float_val(float f)
104 {
105     cst_val *v = new_val();
106     CST_VAL_TYPE(v) = CST_VAL_TYPE_FLOAT;
107     CST_VAL_FLOAT(v) = f;
108     return v;
109 }
110 
string_val(const char * s)111 cst_val *string_val(const char *s)
112 {
113     cst_val *v = new_val();
114     CST_VAL_TYPE(v) = CST_VAL_TYPE_STRING;
115     /* would be nice to note if this is a deletable string or not */
116     CST_VAL_STRING_LVAL(v) = cst_strdup(s);
117     return v;
118 }
119 
cons_val(const cst_val * a,const cst_val * b)120 cst_val *cons_val(const cst_val *a, const cst_val *b)
121 {
122     cst_val *v = new_val();
123     CST_VAL_CAR(v)=((!a || cst_val_consp(a)) ?
124 		    (cst_val *)(void *)a:val_inc_refcount(a));
125     CST_VAL_CDR(v)=((!b || cst_val_consp(b)) ?
126 		    (cst_val *)(void *)b:val_inc_refcount(b));
127     return v;
128 }
129 
val_new_typed(int type,void * vv)130 cst_val *val_new_typed(int type,void *vv)
131 {
132     cst_val *v = new_val();
133     CST_VAL_TYPE(v) = type;
134     CST_VAL_VOID(v) = vv;
135     return v;
136 }
137 
delete_val_list(cst_val * v)138 void delete_val_list(cst_val *v)
139 {
140     if (v)
141     {
142 	if (cst_val_consp(v))
143 	{
144 	    delete_val_list(CST_VAL_CDR(v));
145 	    cst_free(v);
146 	}
147 	else
148 	    delete_val(v);
149     }
150 }
151 
delete_val(cst_val * v)152 void delete_val(cst_val *v)
153 {
154     if (v)
155     {
156 	if (cst_val_consp(v))
157 	{
158 	    delete_val(CST_VAL_CAR(v));
159 	    delete_val(CST_VAL_CDR(v));
160 	    cst_free(v);
161 	}
162 	else if (val_dec_refcount(v) == 0)
163 	{
164 	    if (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING)
165 		cst_free(CST_VAL_VOID(v));
166 	    else if (CST_VAL_TYPE(v) >= CST_VAL_TYPE_FIRST_FREE)
167             {
168                 if (cst_val_defs[CST_VAL_TYPE(v)/2].delete_function)
169                     (cst_val_defs[CST_VAL_TYPE(v)/2].delete_function)
170                         (CST_VAL_VOID(v));
171             }
172             cst_free(v);
173 	}
174     }
175 }
176 
177 /* Accessor functions */
val_int(const cst_val * v)178 int val_int(const cst_val *v)
179 {
180     if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT))
181 	return CST_VAL_INT(v);
182     else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
183 	return (int)CST_VAL_FLOAT(v);
184     else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
185 	return atoi(CST_VAL_STRING(v));
186     else
187     {
188 	cst_errmsg("VAL: tried to access int in %d typed val\n",
189 		   (v ? CST_VAL_TYPE(v) : -1));
190 	cst_error();
191     }
192     return 0;
193 }
194 
val_float(const cst_val * v)195 float val_float(const cst_val *v)
196 {
197     if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT))
198 	return (float)CST_VAL_INT(v);
199     else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
200 	return CST_VAL_FLOAT(v);
201     else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
202 	return cst_atof(CST_VAL_STRING(v));
203     else
204     {
205 	cst_errmsg("VAL: tried to access float in %d typed val\n",
206 		   (v ? CST_VAL_TYPE(v) : -1));
207 	cst_error();
208     }
209     return 0;
210 }
211 
val_string(const cst_val * v)212 const char *val_string(const cst_val *v)
213 {
214     if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
215 	return CST_VAL_STRING(v);
216     else
217     {
218 	cst_errmsg("VAL: tried to access string in %d typed val\n",
219 		   (v ? CST_VAL_TYPE(v) : -1));
220 	cst_error();
221     }
222     return 0;
223 }
224 
val_car(const cst_val * v)225 const cst_val *val_car(const cst_val *v)
226 {
227     if (v && cst_val_consp(v))
228 	return CST_VAL_CAR(v);
229     else
230     {
231 	cst_errmsg("VAL: tried to access car in %d typed val\n",
232 		   (v ? CST_VAL_TYPE(v) : -1));
233 	cst_error();
234     }
235     return 0;
236 }
237 
val_cdr(const cst_val * v)238 const cst_val *val_cdr(const cst_val *v)
239 {
240     if (v && cst_val_consp(v))
241 	return CST_VAL_CDR(v);
242     else
243     {
244 	cst_errmsg("VAL: tried to access cdr in %d typed val\n",
245 		   (v ? CST_VAL_TYPE(v) : -1));
246 	cst_error();
247     }
248     return 0;
249 }
250 
val_generic(const cst_val * v,int type,const char * stype)251 void *val_generic(const cst_val *v, int type, const char *stype)
252 {   /* a generic access function that checks the expected type */
253     if (v && CST_VAL_TYPE(v) == type)
254 	return CST_VAL_VOID(v);
255     else
256     {
257         cst_errmsg("VAL: tried to access %s in %d type val\n",
258                        stype,
259                        (v ? CST_VAL_TYPE(v) : -1));
260         cst_error();
261     }
262     return NULL;
263 }
264 
val_void(const cst_val * v)265 void *val_void(const cst_val *v)
266 {
267     /* The scary, do anything function, this shouldn't be called by mortals */
268     if ((v == NULL) ||
269 	(CST_VAL_TYPE(v) == CST_VAL_TYPE_CONS) ||
270 	(CST_VAL_TYPE(v) == CST_VAL_TYPE_INT) ||
271 	(CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
272     {
273 	cst_errmsg("VAL: tried to access void in %d typed val\n",
274 		   (v ? CST_VAL_TYPE(v) : -1));
275 	cst_error();
276 	return NULL;
277     }
278     else
279 	return CST_VAL_VOID(v);
280 }
281 
cst_val_consp(const cst_val * v)282 int cst_val_consp(const cst_val *v)
283 {
284     /* To keep a val cell down to 8 bytes we identify non-cons cells */
285     /* with non-zero values in the least significant bit of the first */
286     /* address in the cell (this is a standard technique used on Lisp */
287     /* machines                                                       */
288 #if 0
289     void *t;
290     int t1;
291 
292     /* Hmm this still isn't right (it can be) but this isn't it */
293     t = CST_VAL_CAR(v);
294     t1 = *(int *)&t;
295 
296     if ((t1&0x1) == 0)
297 	return TRUE;
298     else
299 	return FALSE;
300 #endif
301     const cst_val_atom *t;
302 
303     t = (const cst_val_atom *)v;
304     if (t->type % 2 == 0)
305       return TRUE;
306     else
307       return FALSE;
308 }
309 
set_cdr(cst_val * v1,const cst_val * v2)310 const cst_val *set_cdr(cst_val *v1, const cst_val *v2)
311 {
312     /* destructive set cdr, be careful you have a pointer to current cdr */
313 
314     if (!cst_val_consp(v1))
315     {
316 	cst_errmsg("VAL: tried to set cdr of non-consp cell\n");
317 	cst_error();
318 	return NULL;
319     }
320     else
321     {
322 	val_dec_refcount(CST_VAL_CDR(v1));
323 	val_inc_refcount(v1);
324 	CST_VAL_CDR(v1) = (cst_val *)v2;
325     }
326     return v1;
327 }
328 
set_car(cst_val * v1,const cst_val * v2)329 const cst_val *set_car(cst_val *v1, const cst_val *v2)
330 {
331     /* destructive set car, be careful you have a pointer to current cdr */
332 
333     if (!cst_val_consp(v1))
334     {
335 	cst_errmsg("VAL: tried to set car of non-consp cell\n");
336 	cst_error();
337 	return NULL;
338     }
339     else
340     {
341 	val_dec_refcount(CST_VAL_CAR(v1));
342 	val_inc_refcount(v1);
343 	CST_VAL_CAR(v1) = (cst_val *)v2;
344     }
345     return v1;
346 }
347 
348 #ifndef FLITE_PLUS_HTS_ENGINE
val_print(cst_file fd,const cst_val * v)349 void val_print(cst_file fd,const cst_val *v)
350 {
351     const cst_val *p;
352 
353     if (v == NULL)
354 	cst_fprintf(fd,"[null]");
355     else if (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT)
356 	cst_fprintf(fd,"%d",val_int(v));
357     else if (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT)
358 	cst_fprintf(fd,"%f",val_float(v));
359     else if (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING)
360 	cst_fprintf(fd,"%s",val_string(v));
361     else if (cst_val_consp(v))
362     {
363 	cst_fprintf(fd,"(");
364 	for (p=v; p; )
365 	{
366 	    val_print(fd,val_car(p));
367 	    p=val_cdr(p);
368 	    if (p)
369 		cst_fprintf(fd," ");
370 	}
371 	cst_fprintf(fd,")");
372     }
373     else
374 	cst_fprintf(fd,"[Val %s 0x%p]",
375 		cst_val_defs[CST_VAL_TYPE(v)/2].name,CST_VAL_VOID(v));
376 }
377 #endif /* !FLITE_PLUS_HTS_ENGINE */
378 
val_reverse(cst_val * l)379 cst_val *val_reverse(cst_val *l)
380 {
381     cst_val *n,*np,*nl;
382     for (nl=0,n=l; n; nl=n,n=np)
383     {
384 	np=CST_VAL_CDR(n);
385 	CST_VAL_CDR(n) = nl;
386     }
387     return nl;
388 }
389 
val_append(cst_val * l1,cst_val * l2)390 cst_val *val_append(cst_val *l1, cst_val *l2)
391 {
392     /* Destructively add l2 to the end of l1 return l1 */
393     cst_val *t;
394 
395     if (l1 == 0)
396 	return l2;
397     else
398     {
399 	for (t=l1; val_cdr(t); t=CST_VAL_CDR(t));
400 	CST_VAL_CDR(t) = l2;
401 	return l1;
402     }
403 }
404 
val_length(const cst_val * l)405 int val_length(const cst_val *l)
406 {
407     const cst_val *n;
408     int i;
409 
410     for (i=0,n=l; n; n=val_cdr(n))
411 	i++;
412 
413     return i;
414 }
415 
val_equal(const cst_val * v1,const cst_val * v2)416 int val_equal(const cst_val *v1, const cst_val *v2)
417 {
418     if (v1 == v2)
419 	return TRUE;  /* its eq so its equal */
420     else if (v1 == 0)
421 	return FALSE;
422     else if (CST_VAL_TYPE(v1) == CST_VAL_TYPE(v2))
423     {
424 	if (cst_val_consp(v1))
425 	    return ((val_equal(val_car(v1),val_car(v2))) &&
426 		    (val_equal(val_cdr(v1),val_cdr(v2))));
427 	else if (CST_VAL_TYPE(v1) == CST_VAL_TYPE_INT)
428 	    return (val_int(v1) == val_int(v2));
429 	else if (CST_VAL_TYPE(v1) == CST_VAL_TYPE_FLOAT)
430 	    return (val_float(v1) == val_float(v2));
431 	else if (CST_VAL_TYPE(v1) == CST_VAL_TYPE_STRING)
432 	    return (cst_streq(CST_VAL_STRING(v1),CST_VAL_STRING(v2)));
433 	else
434 	    return CST_VAL_VOID(v1) == CST_VAL_VOID(v2);
435     }
436     else
437 	return FALSE;
438 }
439 
val_less(const cst_val * v1,const cst_val * v2)440 int val_less(const cst_val *v1, const cst_val *v2)
441 {
442     return val_float(v1) < val_float(v2);
443 }
444 
val_greater(const cst_val * v1,const cst_val * v2)445 int val_greater(const cst_val *v1,const cst_val *v2)
446 {
447     return val_float(v1) > val_float(v2);
448 }
449 
val_member(const cst_val * v1,const cst_val * l)450 int val_member(const cst_val *v1,const cst_val *l)
451 {
452     const cst_val *i;
453 
454     for (i=l; i; i=val_cdr(i))
455     {
456 	if (val_equal(val_car(i),v1))
457 	    return TRUE;
458     }
459     return FALSE;
460 }
461 
val_member_string(const char * v1,const cst_val * l)462 int val_member_string(const char *v1,const cst_val *l)
463 {
464     const cst_val *i;
465 
466     for (i=l; i; i=val_cdr(i))
467     {
468 	if (cst_streq(v1,val_string(val_car(i))))
469 	    return TRUE;
470     }
471     return FALSE;
472 }
473 
val_inc_refcount(const cst_val * b)474 cst_val *val_inc_refcount(const cst_val *b)
475 {
476     cst_val *wb;
477 
478     /* Well I was lying, they're not really const, but this is the place */
479     /* where breaking const is reasonable                              */
480     wb = (cst_val *)(void *)b;
481 
482     if (CST_VAL_REFCOUNT(wb) == -1)
483 	/* or is a cons cell in the text segment, how do I do that ? */
484 	return wb;
485     else if (!cst_val_consp(wb)) /* we don't ref count cons cells */
486 	CST_VAL_REFCOUNT(wb) += 1;
487     return wb;
488 }
489 
val_dec_refcount(const cst_val * b)490 int val_dec_refcount(const cst_val *b)
491 {
492     cst_val *wb;
493 
494     wb = (cst_val *)(void *)b;
495 
496     if (CST_VAL_REFCOUNT(wb) == -1)
497 	/* or is a cons cell in the text segment, how do I do that ? */
498 	return -1;
499     else if (cst_val_consp(wb)) /* we don't ref count cons cells */
500 	return 0;
501     else if (CST_VAL_REFCOUNT(wb) == 0)
502     {
503 	/* Otherwise, trying to free a val outside an
504            item/relation/etc has rather the opposite effect from what
505            you might have intended... */
506 	return 0;
507     }
508     else
509     {
510 	CST_VAL_REFCOUNT(wb) -= 1;
511 	return 	CST_VAL_REFCOUNT(wb);
512     }
513 }
514 
cst_utf8_explode(const cst_string * utf8string)515 cst_val *cst_utf8_explode(const cst_string *utf8string)
516 {
517     /* return a list of utf-8 characters as strings */
518     const unsigned char *xxx = (const unsigned char *)utf8string;
519     cst_val *chars=NULL;
520     int i, l=0;
521     char utf8char[5];
522 
523     for (i=0; xxx[i]; i++)
524     {
525         if (xxx[i] < 0x80)  /* one byte */
526         {
527             sprintf(utf8char,"%c",xxx[i]);
528             l = 1;
529         }
530         else if (xxx[i] < 0xe0) /* two bytes */
531         {
532             sprintf(utf8char,"%c%c",xxx[i],xxx[i+1]);
533             i++;
534             l = 2;
535         }
536         else if (xxx[i] < 0xff) /* three bytes */
537         {
538             sprintf(utf8char,"%c%c%c",xxx[i],xxx[i+1],xxx[i+2]);
539             i++; i++;
540             l = 3;
541         }
542         else
543         {
544             sprintf(utf8char,"%c%c%c%c",xxx[i],xxx[i+1],xxx[i+2],xxx[i+3]);
545             i++; i++; i++;
546             l = 4;
547         }
548         chars = cons_val(string_val(utf8char),chars);
549     }
550     return val_reverse(chars);
551 
552 }
553 
val_stringp(const cst_val * v)554 int val_stringp(const cst_val *v)
555 {
556     if (cst_val_consp(v))
557         return FALSE;
558     else if (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING)
559         return TRUE;
560     else
561         return FALSE;
562 }
563 
val_assoc_string(const char * v1,const cst_val * al)564 const cst_val *val_assoc_string(const char *v1,const cst_val *al)
565 {
566     const cst_val *i;
567 
568     for (i=al; i; i=val_cdr(i))
569     {
570 	if (cst_streq(v1,val_string(val_car(val_car(i)))))
571 	    return val_car(i);
572     }
573     return NULL;
574 }
575 
cst_implode(const cst_val * sl)576 cst_string *cst_implode(const cst_val *sl)
577 {
578     const cst_val *v;
579     int l=0;
580     char *s;
581 
582     for (v=sl; v; v=val_cdr(v))
583     {
584         if (val_stringp(val_car(v)))
585             l += cst_strlen(val_string(val_car(v)));
586     }
587 
588     s = cst_alloc(cst_string,l+1);
589 
590     for (v=sl; v; v=val_cdr(v))
591     {
592         if (val_stringp(val_car(v)))
593             cst_sprintf(s,"%s%s",s,val_string(val_car(v)));
594 
595     }
596 
597     return s;
598 }
599