2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
7 * George Konstantoulakis <gkon@inaccessnetworks.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Say numbers and dates (maybe words one day too)
24 * \author Mark Spencer <markster@digium.com>
26 * \note 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr) George Konstantoulakis <gkon@inaccessnetworks.com>
28 * \note 2007-02-08 : Support for Georgian added by Alexander Shaduri <ashaduri@gmail.com>,
29 * Next Generation Networks (NGN).
30 * \note 2007-03-20 : Support for Thai added by Dome C. <dome@tel.co.th>,
31 * IP Crossing Co., Ltd.
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38 #include <netinet/in.h>
44 #include <iso/limits_iso.h>
47 #include "asterisk/file.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/say.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/localtime.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/app.h"
55 /* Forward declaration */
56 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
59 static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
62 char fnbuf[10], asciibuf[20] = "letters/ascii";
67 while (str[num] && !res) {
77 fn = "letters/exclaimation-point";
83 fn = "letters/dollar";
92 fn = "letters/equals";
101 fn = "letters/space";
113 strcpy(fnbuf, "digits/X");
119 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
120 strcpy(fnbuf, "letters/X");
124 if ((fn && ast_fileexists(fn, NULL, lang) > 0) ||
125 (snprintf(asciibuf + 13, sizeof(asciibuf) - 13, "%d", str[num]) > 0 && ast_fileexists(asciibuf, NULL, lang) > 0 && (fn = asciibuf))) {
126 res = ast_streamfile(chan, fn, lang);
128 if ((audiofd > -1) && (ctrlfd > -1))
129 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
131 res = ast_waitstream(chan, ints);
133 ast_stopstream(chan);
141 static int say_phonetic_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
149 while (str[num] && !res) {
159 fn = "letters/exclaimation-point";
165 fn = "letters/dollar";
174 fn = "letters/equals";
180 fn = "letters/slash";
183 fn = "letters/space";
194 strcpy(fnbuf, "digits/X");
198 default: /* '9' falls here... */
200 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
201 strcpy(fnbuf, "phonetic/X_p");
205 if (fn && ast_fileexists(fn, NULL, lang) > 0) {
206 res = ast_streamfile(chan, fn, lang);
208 if ((audiofd > -1) && (ctrlfd > -1))
209 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
211 res = ast_waitstream(chan, ints);
213 ast_stopstream(chan);
221 static int say_digit_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
228 while (str[num] && !res) {
250 strcpy(fnbuf, "digits/X");
255 if (fn && ast_fileexists(fn, NULL, lang) > 0) {
256 res = ast_streamfile(chan, fn, lang);
258 if ((audiofd > -1) && (ctrlfd > -1))
259 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
261 res = ast_waitstream(chan, ints);
263 ast_stopstream(chan);
271 /* Forward declarations */
272 /*! \page Def_syntaxlang Asterisk Language Syntaxes supported
273 \note Not really language codes.
274 For these language codes, Asterisk will change the syntax when
275 saying numbers (and in some cases dates and voicemail messages
279 \arg \b en - English (US)
280 \arg \b en_GB - English (British)
281 \arg \b es - Spanish, Mexican
286 \arg \b no - Norwegian
288 \arg \b pt - Portuguese
289 \arg \b pt_BR - Portuguese (Brazil)
291 \arg \b tw - Taiwanese / Chinese
293 \arg \b ge - Georgian
294 \arg \b hu - Hungarian
297 For Some languages the numbers differ for gender and plural.
298 \arg Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
299 \arg use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
300 use the option argument 'p' for plural enumerations like in German
302 Date/Time functions currently have less languages supported than saynumber().
304 \todo Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
306 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
309 Portuguese sound files needed for Time/Date functions:
320 Spanish sound files needed for Time/Date functions:
325 Italian sound files needed for Time/Date functions:
331 /* Forward declarations of language specific variants of ast_say_number_full */
332 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
333 static int ast_say_number_full_cz(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
334 static int ast_say_number_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
335 static int ast_say_number_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
336 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
337 static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
338 static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
339 static int ast_say_number_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
340 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
341 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
342 static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
343 static int ast_say_number_full_pl(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
344 static int ast_say_number_full_pt(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
345 static int ast_say_number_full_se(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
346 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
347 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
348 static int ast_say_number_full_ru(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
349 static int ast_say_number_full_ge(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
350 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
351 static int ast_say_number_full_th(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
353 /* Forward declarations of language specific variants of ast_say_enumeration_full */
354 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
355 static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
356 static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
357 static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
359 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
360 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
361 static int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
362 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
363 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
364 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
365 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
366 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
367 static int ast_say_date_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
368 static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
369 static int ast_say_date_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
370 static int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
372 static int ast_say_date_with_format_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
373 static int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
374 static int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
375 static int ast_say_date_with_format_es(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
376 static int ast_say_date_with_format_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
377 static int ast_say_date_with_format_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
378 static int ast_say_date_with_format_it(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
379 static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
380 static int ast_say_date_with_format_pl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
381 static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
382 static int ast_say_date_with_format_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
383 static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
384 static int ast_say_date_with_format_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
386 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
387 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
388 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
389 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
390 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
391 static int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
392 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
393 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
394 static int ast_say_time_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
395 static int ast_say_time_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
396 static int ast_say_time_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
397 static int ast_say_time_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
399 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
400 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
401 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
402 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
403 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
404 static int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
405 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
406 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
407 static int ast_say_datetime_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
408 static int ast_say_datetime_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
409 static int ast_say_datetime_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
410 static int ast_say_datetime_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
412 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
413 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
414 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
415 static int ast_say_datetime_from_now_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
416 static int ast_say_datetime_from_now_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
418 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
421 if ((res = ast_streamfile(chan, file, lang)))
422 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
424 res = ast_waitstream(chan, ints);
428 /*! \brief ast_say_number_full: call language-specific functions */
429 /* Called from AGI */
430 static int say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
432 if (!strcasecmp(language, "en") ) { /* English syntax */
433 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
434 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */
435 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
436 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
437 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
438 } else if (!strcasecmp(language, "de") ) { /* German syntax */
439 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
440 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */
441 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
442 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */
443 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
444 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */
445 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
446 } else if (!strcasecmp(language, "fr") ) { /* French syntax */
447 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
448 } else if (!strcasecmp(language, "he") ) { /* Hebrew syntax */
449 return(ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd));
450 } else if (!strcasecmp(language, "hu") ) { /* Hungarian syntax */
451 return(ast_say_number_full_hu(chan, num, ints, language, audiofd, ctrlfd));
452 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */
453 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
454 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */
455 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
456 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */
457 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
458 } else if (!strcasecmp(language, "pt") || !strcasecmp(language, "pt_BR")) { /* Portuguese syntax */
459 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
460 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */
461 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
462 } else if (!strcasecmp(language, "tw") || !strcasecmp(language, "zh") ) { /* Taiwanese / Chinese syntax */
463 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
464 } else if (!strcasecmp(language, "gr") ) { /* Greek syntax */
465 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd));
466 } else if (!strcasecmp(language, "ru") ) { /* Russian syntax */
467 return(ast_say_number_full_ru(chan, num, ints, language, options, audiofd, ctrlfd));
468 } else if (!strcasecmp(language, "th") ) { /* Thai syntax */
469 return(ast_say_number_full_th(chan, num, ints, language, audiofd, ctrlfd));
470 } else if (!strcasecmp(language, "ge") ) { /* Georgian syntax */
471 return(ast_say_number_full_ge(chan, num, ints, language, options, audiofd, ctrlfd));
474 /* Default to english */
475 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
478 /*! \brief ast_say_number_full_en: English syntax */
479 /* This is the default syntax, if no other syntax defined in this file is used */
480 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
486 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
488 while (!res && (num || playh)) {
490 ast_copy_string(fn, "digits/minus", sizeof(fn));
491 if ( num > INT_MIN ) {
497 ast_copy_string(fn, "digits/hundred", sizeof(fn));
499 } else if (num < 20) {
500 snprintf(fn, sizeof(fn), "digits/%d", num);
502 } else if (num < 100) {
503 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
507 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
511 if (num < 1000000) { /* 1,000,000 */
512 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
516 snprintf(fn, sizeof(fn), "digits/thousand");
518 if (num < 1000000000) { /* 1,000,000,000 */
519 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
523 ast_copy_string(fn, "digits/million", sizeof(fn));
525 ast_debug(1, "Number '%d' is too big for me\n", num);
532 if (!ast_streamfile(chan, fn, language)) {
533 if ((audiofd > -1) && (ctrlfd > -1))
534 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
536 res = ast_waitstream(chan, ints);
538 ast_stopstream(chan);
544 static int exp10_int(int power)
547 for (x=0;x<power;x++)
552 /*! \brief ast_say_number_full_cz: Czech syntax */
554 * 1m,2m - gender male
555 * 1w,2w - gender female
559 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
561 * for each number 10^(3n + 3) exist 3 files represented as:
562 * 1 tousand = jeden tisic = 1_E3
563 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
564 * 5,6,... tousands = pet,sest,... tisic = 5_E3
570 * tousand, milion are gender male, so 1 and 2 is 1m 2m
571 * miliard is gender female, so 1 and 2 is 1w 2w
573 static int ast_say_number_full_cz(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
583 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
588 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
590 while (!res && (num || playh)) {
592 ast_copy_string(fn, "digits/minus", sizeof(fn));
593 if ( num > INT_MIN ) {
598 } else if (num < 3 ) {
599 snprintf(fn, sizeof(fn), "digits/%d%c", num, options[0]);
602 } else if (num < 20) {
603 snprintf(fn, sizeof(fn), "digits/%d", num);
606 } else if (num < 100) {
607 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
609 } else if (num < 1000) {
610 hundered = num / 100;
611 if ( hundered == 1 ) {
612 ast_copy_string(fn, "digits/1sto", sizeof(fn));
613 } else if ( hundered == 2 ) {
614 ast_copy_string(fn, "digits/2ste", sizeof(fn));
616 res = ast_say_number_full_cz(chan, hundered, ints, language, options, audiofd, ctrlfd);
619 if (hundered == 3 || hundered == 4) {
620 ast_copy_string(fn, "digits/sta", sizeof(fn));
621 } else if ( hundered > 4 ) {
622 ast_copy_string(fn, "digits/set", sizeof(fn));
625 num -= (hundered * 100);
626 } else { /* num > 1000 */
627 length = (int)log10(num)+1;
628 while ( (length % 3 ) != 1 ) {
631 left = num / (exp10_int(length-1));
634 case 9: options = "w"; /* 1,000,000,000 gender female */
636 default : options = "m"; /* others are male */
639 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
640 res = ast_say_number_full_cz(chan, left, ints, language, options, audiofd, ctrlfd);
644 if ( left >= 5 ) { /* >= 5 have the same declesion */
645 snprintf(fn, sizeof(fn), "digits/5_E%d", length - 1);
646 } else if ( left >= 2 && left <= 4 ) {
647 snprintf(fn, sizeof(fn), "digits/2-4_E%d", length - 1);
648 } else { /* left == 1 */
649 snprintf(fn, sizeof(fn), "digits/1_E%d", length - 1);
651 num -= left * (exp10_int(length-1));
654 if (!ast_streamfile(chan, fn, language)) {
655 if ((audiofd > -1) && (ctrlfd > -1)) {
656 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
658 res = ast_waitstream(chan, ints);
661 ast_stopstream(chan);
667 /*! \brief ast_say_number_full_da: Danish syntax */
669 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
671 static int ast_say_number_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
676 int cn = 1; /* +1 = commune; -1 = neuter */
679 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
681 if (options && !strncasecmp(options, "n", 1)) cn = -1;
683 while (!res && (num || playh || playa )) {
684 /* The grammar for Danish numbers is the same as for English except
686 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
687 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
688 * "one-and twenty" and 68 is "eight-and sixty".
689 * - "million" is different in singular and plural form
690 * - numbers > 1000 with zero as the third digit from last have an
691 * "and" before the last two digits, i.e. 2034 is "two thousand and
692 * four-and thirty" and 1000012 is "one million and twelve".
695 ast_copy_string(fn, "digits/minus", sizeof(fn));
696 if ( num > INT_MIN ) {
702 ast_copy_string(fn, "digits/hundred", sizeof(fn));
705 ast_copy_string(fn, "digits/and", sizeof(fn));
707 } else if (num == 1 && cn == -1) {
708 ast_copy_string(fn, "digits/1N", sizeof(fn));
710 } else if (num < 20) {
711 snprintf(fn, sizeof(fn), "digits/%d", num);
713 } else if (num < 100) {
716 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
719 snprintf(fn, sizeof(fn), "digits/%d", num);
724 int hundreds = num / 100;
726 ast_copy_string(fn, "digits/1N", sizeof(fn));
728 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
731 num -= 100 * hundreds;
737 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
741 ast_copy_string(fn, "digits/thousand", sizeof(fn));
743 if (num < 1000000000) {
744 int millions = num / 1000000;
745 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
749 ast_copy_string(fn, "digits/million", sizeof(fn));
751 ast_copy_string(fn, "digits/millions", sizeof(fn));
754 ast_debug(1, "Number '%d' is too big for me\n", num);
758 if (num && num < 100)
763 if (!ast_streamfile(chan, fn, language)) {
764 if ((audiofd > -1) && (ctrlfd > -1))
765 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
767 res = ast_waitstream(chan, ints);
769 ast_stopstream(chan);
775 /*! \brief ast_say_number_full_de: German syntax */
777 In addition to English, the following sounds are required:
779 "1-and" through "9-and"
782 NB "1" is recorded as 'eins'
784 static int ast_say_number_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
787 int mf = 1; /* +1 = male and neuter; -1 = female */
791 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
793 if (options && (!strncasecmp(options, "f", 1)))
796 while (!res && num) {
797 /* The grammar for German numbers is the same as for English except
799 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
800 * "one-and twenty" and 68 is "eight-and sixty".
801 * - "one" varies according to gender
802 * - 100 is 'hundert', however all other instances are 'ein hundert'
803 * - 1000 is 'tausend', however all other instances are 'ein tausend'
804 * - 1000000 is always 'eine million'
805 * - "million" is different in singular and plural form
808 ast_copy_string(fn, "digits/minus", sizeof(fn));
809 if ( num > INT_MIN ) {
814 } else if (num < 100 && t) {
815 ast_copy_string(fn, "digits/and", sizeof(fn));
817 } else if (num == 1 && mf == -1) {
818 snprintf(fn, sizeof(fn), "digits/%dF", num);
820 } else if (num < 20) {
821 snprintf(fn, sizeof(fn), "digits/%d", num);
823 } else if (num < 100) {
826 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
829 snprintf(fn, sizeof(fn), "digits/%d", num);
832 } else if (num == 100 && t == 0) {
833 ast_copy_string(fn, "digits/hundred", sizeof(fn));
835 } else if (num < 1000) {
836 int hundreds = num / 100;
839 ast_copy_string(fn, "digits/1N", sizeof(fn));
841 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
843 ast_copy_string(fna, "digits/hundred", sizeof(fna));
845 } else if (num == 1000 && t == 0) {
846 ast_copy_string(fn, "digits/thousand", sizeof(fn));
848 } else if (num < 1000000) {
849 int thousands = num / 1000;
852 if (thousands == 1) {
853 ast_copy_string(fn, "digits/1N", sizeof(fn));
854 ast_copy_string(fna, "digits/thousand", sizeof(fna));
856 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
859 ast_copy_string(fn, "digits/thousand", sizeof(fn));
861 } else if (num < 1000000000) {
862 int millions = num / 1000000;
866 ast_copy_string(fn, "digits/1F", sizeof(fn));
867 ast_copy_string(fna, "digits/million", sizeof(fna));
869 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
872 ast_copy_string(fn, "digits/millions", sizeof(fn));
874 } else if (num <= INT_MAX) {
875 int billions = num / 1000000000;
876 num = num % 1000000000;
879 ast_copy_string(fn, "digits/1F", sizeof(fn));
880 ast_copy_string(fna, "digits/milliard", sizeof(fna));
882 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
886 ast_copy_string(fn, "digits/milliards", sizeof(fn));
889 ast_debug(1, "Number '%d' is too big for me\n", num);
893 if (!ast_streamfile(chan, fn, language)) {
894 if ((audiofd > -1) && (ctrlfd > -1))
895 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
897 res = ast_waitstream(chan, ints);
899 ast_stopstream(chan);
901 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
902 if ((audiofd > -1) && (ctrlfd > -1))
903 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
905 res = ast_waitstream(chan, ints);
907 ast_stopstream(chan);
915 /*! \brief ast_say_number_full_en_GB: British and Norwegian syntax */
917 In addition to American English, the following sounds are required: "and"
919 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
926 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
928 while (!res && (num || playh || playa )) {
930 ast_copy_string(fn, "digits/minus", sizeof(fn));
931 if ( num > INT_MIN ) {
937 ast_copy_string(fn, "digits/hundred", sizeof(fn));
940 ast_copy_string(fn, "digits/and", sizeof(fn));
942 } else if (num < 20) {
943 snprintf(fn, sizeof(fn), "digits/%d", num);
945 } else if (num < 100) {
946 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
948 } else if (num < 1000) {
949 int hundreds = num / 100;
950 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
953 num -= 100 * hundreds;
956 } else if (num < 1000000) {
957 res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd);
960 ast_copy_string(fn, "digits/thousand", sizeof(fn));
962 if (num && num < 100)
964 } else if (num < 1000000000) {
965 int millions = num / 1000000;
966 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd);
969 ast_copy_string(fn, "digits/million", sizeof(fn));
971 if (num && num < 100)
974 ast_debug(1, "Number '%d' is too big for me\n", num);
979 if (!ast_streamfile(chan, fn, language)) {
980 if ((audiofd > -1) && (ctrlfd > -1))
981 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
983 res = ast_waitstream(chan, ints);
985 ast_stopstream(chan);
991 /*! \brief ast_say_number_full_es: Spanish syntax */
993 Requires a few new audios:
994 1F.gsm: feminine 'una'
995 21.gsm thru 29.gsm, cien.gsm, mil.gsm, millon.gsm, millones.gsm, 100.gsm, 200.gsm, 300.gsm, 400.gsm, 500.gsm, 600.gsm, 700.gsm, 800.gsm, 900.gsm, y.gsm
997 static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1001 int mf = 0; /* +1 = male; -1 = female */
1004 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1007 if (!strncasecmp(options, "f", 1))
1009 else if (!strncasecmp(options, "m", 1))
1013 while (!res && num) {
1015 ast_copy_string(fn, "digits/minus", sizeof(fn));
1016 if ( num > INT_MIN ) {
1022 ast_copy_string(fn, "digits/and", sizeof(fn));
1024 } else if (num == 1) {
1026 snprintf(fn, sizeof(fn), "digits/%dF", num);
1028 snprintf(fn, sizeof(fn), "digits/%dM", num);
1030 snprintf(fn, sizeof(fn), "digits/%d", num);
1032 } else if (num < 31) {
1033 snprintf(fn, sizeof(fn), "digits/%d", num);
1035 } else if (num < 100) {
1036 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1040 } else if (num == 100) {
1041 ast_copy_string(fn, "digits/100", sizeof(fn));
1043 } else if (num < 200) {
1044 ast_copy_string(fn, "digits/100-and", sizeof(fn));
1048 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1050 } else if (num < 2000) {
1052 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1054 if (num < 1000000) {
1055 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1059 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1061 if (num < 2147483640) {
1062 if ((num/1000000) == 1) {
1063 res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
1066 ast_copy_string(fn, "digits/million", sizeof(fn));
1068 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1071 ast_copy_string(fn, "digits/millions", sizeof(fn));
1075 ast_debug(1, "Number '%d' is too big for me\n", num);
1083 if (!ast_streamfile(chan, fn, language)) {
1084 if ((audiofd > -1) && (ctrlfd > -1))
1085 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1087 res = ast_waitstream(chan, ints);
1089 ast_stopstream(chan);
1097 /*! \brief ast_say_number_full_fr: French syntax */
1098 /* Extra sounds needed:
1101 static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1106 int mf = 1; /* +1 = male; -1 = female */
1109 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1111 if (options && !strncasecmp(options, "f", 1))
1114 while (!res && (num || playh || playa)) {
1116 ast_copy_string(fn, "digits/minus", sizeof(fn));
1117 if ( num > INT_MIN ) {
1123 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1126 ast_copy_string(fn, "digits/et", sizeof(fn));
1128 } else if (num == 1) {
1130 snprintf(fn, sizeof(fn), "digits/%dF", num);
1132 snprintf(fn, sizeof(fn), "digits/%d", num);
1134 } else if (num < 21) {
1135 snprintf(fn, sizeof(fn), "digits/%d", num);
1137 } else if (num < 70) {
1138 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1139 if ((num % 10) == 1) playa++;
1141 } else if (num < 80) {
1142 ast_copy_string(fn, "digits/60", sizeof(fn));
1143 if ((num % 10) == 1) playa++;
1145 } else if (num < 100) {
1146 ast_copy_string(fn, "digits/80", sizeof(fn));
1148 } else if (num < 200) {
1149 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1151 } else if (num < 1000) {
1152 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1155 } else if (num < 2000) {
1156 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1158 } else if (num < 1000000) {
1159 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1162 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1164 } else if (num < 1000000000) {
1165 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1168 ast_copy_string(fn, "digits/million", sizeof(fn));
1169 num = num % 1000000;
1171 ast_debug(1, "Number '%d' is too big for me\n", num);
1175 if (!ast_streamfile(chan, fn, language)) {
1176 if ((audiofd > -1) && (ctrlfd > -1))
1177 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1179 res = ast_waitstream(chan, ints);
1181 ast_stopstream(chan);
1190 /* Check doc/lang/hebrew-digits.txt for information about the various
1191 * recordings required to make this translation work properly */
1192 #define SAY_NUM_BUF_SIZE 256
1193 static int ast_say_number_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1196 int state = 0; /* no need to save anything */
1197 int mf = -1; /* +1 = Masculin; -1 = Feminin */
1200 char fn[SAY_NUM_BUF_SIZE] = "";
1202 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: started. num: %d, options=\"%s\"\n", num, options);
1205 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1207 if (options && !strncasecmp(options, "m", 1)) {
1210 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: num: %d, state=%d, options=\"%s\", mf=%d\n", num, state, options, mf);
1212 /* Do we have work to do? */
1213 while (!res && (num || (state > 0))) {
1214 /* first type of work: play a second sound. In this loop
1215 * we can only play one sound file at a time. Thus playing
1216 * a second one requires repeating the loop just for the
1217 * second file. The variable 'state' remembers where we were.
1218 * state==0 is the normal mode and it means that we continue
1219 * to check if the number num has yet anything left.
1221 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: num: %d, state=%d, options=\"%s\", mf=%d, tmpnum=%d\n", num, state, options, mf, tmpnum);
1225 } else if (state == 2) {
1226 if ((num >= 11) && (num < 21)) {
1228 snprintf(fn, sizeof(fn), "digits/ve");
1230 snprintf(fn, sizeof(fn), "digits/uu");
1235 snprintf(fn, sizeof(fn), "digits/ve");
1238 snprintf(fn, sizeof(fn), "digits/uu");
1242 snprintf(fn, sizeof(fn), "digits/ve");
1244 snprintf(fn, sizeof(fn), "digits/uu");
1248 snprintf(fn, sizeof(fn), "digits/ve");
1251 snprintf(fn, sizeof(fn), "digits/ve");
1254 snprintf(fn, sizeof(fn), "digits/ve");
1257 snprintf(fn, sizeof(fn), "digits/ve");
1260 snprintf(fn, sizeof(fn), "digits/uu");
1263 snprintf(fn, sizeof(fn), "digits/ve");
1266 snprintf(fn, sizeof(fn), "digits/ve");
1271 } else if (state == 3) {
1272 snprintf(fn, sizeof(fn), "digits/1k");
1274 } else if (num < 0) {
1275 snprintf(fn, sizeof(fn), "digits/minus");
1277 } else if (num < 20) {
1279 snprintf(fn, sizeof(fn), "digits/%d", num);
1281 snprintf(fn, sizeof(fn), "digits/%dm", num);
1284 } else if ((num < 100) && (num >= 20)) {
1285 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1290 } else if ((num >= 100) && (num < 1000)) {
1292 snprintf(fn, sizeof(fn), "digits/%d00", tmpnum);
1293 num = num - (tmpnum * 100);
1294 if ((num > 0) && (num < 11)) {
1297 } else if ((num >= 1000) && (num < 10000)) {
1298 tmpnum = num / 1000;
1299 snprintf(fn, sizeof(fn), "digits/%dk", tmpnum);
1300 num = num - (tmpnum * 1000);
1301 if ((num > 0) && (num < 11)) {
1304 } else if (num < 20000) {
1305 snprintf(fn, sizeof(fn), "digits/%dm", (num / 1000));
1308 } else if (num < 1000000) {
1309 res = ast_say_number_full_he(chan, num / 1000, ints, language, "m", audiofd, ctrlfd);
1313 snprintf(fn, sizeof(fn), "digits/1k");
1315 if ((num > 0) && (num < 11)) {
1318 } else if (num < 2000000) {
1319 snprintf(fn, sizeof(fn), "digits/million");
1320 num = num % 1000000;
1321 if ((num > 0) && (num < 11)) {
1324 } else if (num < 3000000) {
1325 snprintf(fn, sizeof(fn), "digits/twomillion");
1326 num = num - 2000000;
1327 if ((num > 0) && (num < 11)) {
1330 } else if (num < 1000000000) {
1331 res = ast_say_number_full_he(chan, num / 1000000, ints, language, "m", audiofd, ctrlfd);
1335 snprintf(fn, sizeof(fn), "digits/million");
1336 num = num % 1000000;
1337 if ((num > 0) && (num < 11)) {
1341 ast_debug(1, "Number '%d' is too big for me\n", num);
1346 if (!ast_streamfile(chan, fn, language)) {
1347 if ((audiofd > -1) && (ctrlfd > -1)) {
1348 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1350 res = ast_waitstream(chan, ints);
1353 ast_stopstream(chan);
1359 /*! \brief ast_say_number_full_hu: Hungarian syntax */
1360 /* Extra sounds need:
1364 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1370 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1374 like english, except numbers up to 29 are from 2 words.
1375 10 and first word of 1[1-9] and 20 and first word of 2[1-9] are different.
1378 while(!res && (num || playh)) {
1380 ast_copy_string(fn, "digits/minus", sizeof(fn));
1381 if ( num > INT_MIN ) {
1387 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1389 } else if (num < 11 || num == 20) {
1390 snprintf(fn, sizeof(fn), "digits/%d", num);
1392 } else if (num < 20) {
1393 ast_copy_string(fn, "digits/10en", sizeof(fn));
1395 } else if (num < 30) {
1396 ast_copy_string(fn, "digits/20on", sizeof(fn));
1398 } else if (num < 100) {
1399 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1403 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1407 if (num < 1000000) { /* 1,000,000 */
1408 res = ast_say_number_full_hu(chan, num / 1000, ints, language, audiofd, ctrlfd);
1412 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1414 if (num < 1000000000) { /* 1,000,000,000 */
1415 res = ast_say_number_full_hu(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1419 ast_copy_string(fn, "digits/million", sizeof(fn));
1421 ast_debug(1, "Number '%d' is too big for me\n", num);
1428 if(!ast_streamfile(chan, fn, language)) {
1429 if ((audiofd > -1) && (ctrlfd > -1))
1430 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1432 res = ast_waitstream(chan, ints);
1434 ast_stopstream(chan);
1440 /*! \brief ast_say_number_full_it: Italian */
1441 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1449 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1454 Like english, numbers up to 20 are a single 'word', and others
1455 compound, but with exceptions.
1456 For example 21 is not twenty-one, but there is a single word in 'it'.
1457 Idem for 28 (ie when a the 2nd part of a compund number
1458 starts with a vowel)
1460 There are exceptions also for hundred, thousand and million.
1461 In english 100 = one hundred, 200 is two hundred.
1462 In italian 100 = cento , like to say hundred (without one),
1463 200 and more are like english.
1465 Same applies for thousand:
1466 1000 is one thousand in en, 2000 is two thousand.
1467 In it we have 1000 = mille , 2000 = 2 mila
1469 For million(s) we use the plural, if more than one
1470 Also, one million is abbreviated in it, like on-million,
1471 or 'un milione', not 'uno milione'.
1472 So the right file is provided.
1475 while (!res && (num || playh)) {
1477 ast_copy_string(fn, "digits/minus", sizeof(fn));
1478 if ( num > INT_MIN ) {
1484 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1486 } else if (num < 20) {
1487 snprintf(fn, sizeof(fn), "digits/%d", num);
1489 } else if (num == 21) {
1490 snprintf(fn, sizeof(fn), "digits/%d", num);
1492 } else if (num == 28) {
1493 snprintf(fn, sizeof(fn), "digits/%d", num);
1495 } else if (num == 31) {
1496 snprintf(fn, sizeof(fn), "digits/%d", num);
1498 } else if (num == 38) {
1499 snprintf(fn, sizeof(fn), "digits/%d", num);
1501 } else if (num == 41) {
1502 snprintf(fn, sizeof(fn), "digits/%d", num);
1504 } else if (num == 48) {
1505 snprintf(fn, sizeof(fn), "digits/%d", num);
1507 } else if (num == 51) {
1508 snprintf(fn, sizeof(fn), "digits/%d", num);
1510 } else if (num == 58) {
1511 snprintf(fn, sizeof(fn), "digits/%d", num);
1513 } else if (num == 61) {
1514 snprintf(fn, sizeof(fn), "digits/%d", num);
1516 } else if (num == 68) {
1517 snprintf(fn, sizeof(fn), "digits/%d", num);
1519 } else if (num == 71) {
1520 snprintf(fn, sizeof(fn), "digits/%d", num);
1522 } else if (num == 78) {
1523 snprintf(fn, sizeof(fn), "digits/%d", num);
1525 } else if (num == 81) {
1526 snprintf(fn, sizeof(fn), "digits/%d", num);
1528 } else if (num == 88) {
1529 snprintf(fn, sizeof(fn), "digits/%d", num);
1531 } else if (num == 91) {
1532 snprintf(fn, sizeof(fn), "digits/%d", num);
1534 } else if (num == 98) {
1535 snprintf(fn, sizeof(fn), "digits/%d", num);
1537 } else if (num < 100) {
1538 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1542 if ((num / 100) > 1) {
1543 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1546 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1550 if (num < 1000000) { /* 1,000,000 */
1552 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1557 if ((tempnum / 1000) < 2)
1558 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1559 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1560 ast_copy_string(fn, "digits/thousands", sizeof(fn));
1562 if (num < 1000000000) { /* 1,000,000,000 */
1563 if ((num / 1000000) > 1)
1564 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1569 if ((tempnum / 1000000) < 2)
1570 ast_copy_string(fn, "digits/million", sizeof(fn));
1572 ast_copy_string(fn, "digits/millions", sizeof(fn));
1574 ast_debug(1, "Number '%d' is too big for me\n", num);
1581 if (!ast_streamfile(chan, fn, language)) {
1582 if ((audiofd > -1) && (ctrlfd > -1))
1583 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1585 res = ast_waitstream(chan, ints);
1587 ast_stopstream(chan);
1593 /*! \brief ast_say_number_full_nl: dutch syntax */
1594 /* New files: digits/nl-en
1596 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1603 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1604 while (!res && (num || playh )) {
1606 ast_copy_string(fn, "digits/minus", sizeof(fn));
1607 if ( num > INT_MIN ) {
1613 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1615 } else if (num < 20) {
1616 snprintf(fn, sizeof(fn), "digits/%d", num);
1618 } else if (num < 100) {
1621 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1625 ast_copy_string(fn, "digits/nl-en", sizeof(fn));
1627 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1630 } else if (num < 200) {
1631 /* hundred, not one-hundred */
1632 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1634 } else if (num < 1000) {
1635 snprintf(fn, sizeof(fn), "digits/%d", num / 100);
1640 /* thousand, not one-thousand */
1642 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1643 } else if (num < 10000) { /* 1,100 to 9,9999 */
1644 res = ast_say_number_full_nl(chan, num / 100, ints, language, audiofd, ctrlfd);
1648 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1650 if (num < 1000000) { /* 1,000,000 */
1651 res = ast_say_number_full_nl(chan, num / 1000, ints, language, audiofd, ctrlfd);
1655 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1657 if (num < 1000000000) { /* 1,000,000,000 */
1658 res = ast_say_number_full_nl(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1662 ast_copy_string(fn, "digits/million", sizeof(fn));
1664 ast_debug(1, "Number '%d' is too big for me\n", num);
1672 if (!ast_streamfile(chan, fn, language)) {
1673 if ((audiofd > -1) && (ctrlfd > -1))
1674 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1676 res = ast_waitstream(chan, ints);
1678 ast_stopstream(chan);
1684 /*! \brief ast_say_number_full_no: Norwegian syntax */
1686 In addition to American English, the following sounds are required: "and", "1N"
1688 static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1693 int cn = 1; /* +1 = commune; -1 = neuter */
1697 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1699 if (options && !strncasecmp(options, "n", 1)) cn = -1;
1701 while (!res && (num || playh || playa )) {
1702 /* The grammar for Norwegian numbers is the same as for English except
1703 * for the following:
1704 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1705 * "and" before the last two digits, i.e. 2034 is "two thousand and
1706 * thirty-four" and 1000012 is "one million and twelve".
1709 ast_copy_string(fn, "digits/minus", sizeof(fn));
1710 if ( num > INT_MIN ) {
1716 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1719 ast_copy_string(fn, "digits/and", sizeof(fn));
1721 } else if (num == 1 && cn == -1) {
1722 ast_copy_string(fn, "digits/1N", sizeof(fn));
1724 } else if (num < 20) {
1725 snprintf(fn, sizeof(fn), "digits/%d", num);
1727 } else if (num < 100) {
1728 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1730 } else if (num < 1000) {
1731 int hundreds = num / 100;
1733 ast_copy_string(fn, "digits/1N", sizeof(fn));
1735 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1738 num -= 100 * hundreds;
1741 } else if (num < 1000000) {
1742 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1745 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1747 if (num && num < 100)
1749 } else if (num < 1000000000) {
1750 int millions = num / 1000000;
1751 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1754 ast_copy_string(fn, "digits/million", sizeof(fn));
1756 if (num && num < 100)
1759 ast_debug(1, "Number '%d' is too big for me\n", num);
1764 if (!ast_streamfile(chan, fn, language)) {
1765 if ((audiofd > -1) && (ctrlfd > -1))
1766 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1768 res = ast_waitstream(chan, ints);
1770 ast_stopstream(chan);
1777 char *separator_dziesiatek;
1781 char *dziesiatki[10];
1786 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1792 return odm->rzedy[rzad - 1][0];
1793 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5)
1794 return odm->rzedy[rzad - 1][1];
1796 return odm->rzedy[rzad - 1][2];
1799 static char* pl_append(char* buffer, char* str)
1801 strcpy(buffer, str);
1802 buffer += strlen(str);
1806 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1808 char file_name[255] = "digits/";
1809 strcat(file_name, fn);
1810 ast_debug(1, "Trying to play: %s\n", file_name);
1811 if (!ast_streamfile(chan, file_name, language)) {
1812 if ((audiofd > -1) && (ctrlfd > -1))
1813 ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1815 ast_waitstream(chan, ints);
1817 ast_stopstream(chan);
1820 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1822 /* Initialise variables to allow compilation on Debian-stable, etc */
1832 if (i == 0 && rzad > 0) {
1836 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1840 m1000E6 = i % 1000000000;
1841 i1000E6 = i / 1000000000;
1843 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1845 m1000E3 = m1000E6 % 1000000;
1846 i1000E3 = m1000E6 / 1000000;
1848 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1850 m1000 = m1000E3 % 1000;
1851 i1000 = m1000E3 / 1000;
1853 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1859 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1861 if ( m100 > 0 && m100 <=9 ) {
1863 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1865 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1866 } else if (m100 % 10 == 0) {
1867 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1868 } else if (m100 <= 19 ) {
1869 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1870 } else if (m100 != 0) {
1871 if (odm->separator_dziesiatek[0]==' ') {
1872 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1873 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1877 b = pl_append(b, odm->dziesiatki[m100 / 10]);
1878 b = pl_append(b, odm->separator_dziesiatek);
1879 b = pl_append(b, odm->cyfry2[m100 % 10]);
1880 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1885 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1889 /* ast_say_number_full_pl: Polish syntax */
1890 static int ast_say_number_full_pl(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1900 1000000000.2 miliardy
1901 1000000000.5 miliardow
1965 70m siedemdziesieciu
1977 90m dziewiedziesieciu
1979 and combinations of eg.: 20_1, 30m_3m, etc...
1983 char *zenski_cyfry[] = {"0", "1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1985 char *zenski_cyfry2[] = {"0", "1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1987 char *meski_cyfry[] = {"0", "1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1989 char *meski_cyfry2[] = {"0", "1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1991 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1993 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1995 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1997 char *nijaki_cyfry[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
1999 char *nijaki_cyfry2[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
2001 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
2003 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
2005 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
2007 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
2009 /* Initialise variables to allow compilation on Debian-stable, etc */
2012 static odmiana *odmiana_nieosobowa = NULL;
2013 static odmiana *odmiana_meska = NULL;
2014 static odmiana *odmiana_zenska = NULL;
2016 if (odmiana_nieosobowa == NULL) {
2017 odmiana_nieosobowa = ast_malloc(sizeof(*odmiana_nieosobowa));
2019 odmiana_nieosobowa->separator_dziesiatek = " ";
2021 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
2022 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
2023 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
2024 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
2025 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
2026 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
2029 if (odmiana_zenska == NULL) {
2030 odmiana_zenska = ast_malloc(sizeof(*odmiana_zenska));
2032 odmiana_zenska->separator_dziesiatek = " ";
2034 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
2035 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
2036 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
2037 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
2038 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
2039 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
2042 if (odmiana_meska == NULL) {
2043 odmiana_meska = ast_malloc(sizeof(*odmiana_meska));
2045 odmiana_meska->separator_dziesiatek = " ";
2047 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
2048 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
2049 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
2050 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
2051 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
2052 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
2056 if (strncasecmp(options, "f", 1) == 0)
2058 else if (strncasecmp(options, "m", 1) == 0)
2061 o = odmiana_nieosobowa;
2063 o = odmiana_nieosobowa;
2065 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
2069 /* ast_say_number_full_pt: Portuguese syntax */
2070 /* Extra sounds needed: */
2071 /* For feminin all sound files end with F */
2072 /* 100E for 100+ something */
2073 /* 1000000S for plural */
2074 /* pt-e for 'and' */
2075 static int ast_say_number_full_pt(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2079 int mf = 1; /* +1 = male; -1 = female */
2083 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2085 if (options && !strncasecmp(options, "f", 1))
2088 while (!res && num ) {
2090 ast_copy_string(fn, "digits/minus", sizeof(fn));
2091 if ( num > INT_MIN ) {
2096 } else if (num < 20) {
2097 if ((num == 1 || num == 2) && (mf < 0))
2098 snprintf(fn, sizeof(fn), "digits/%dF", num);
2100 snprintf(fn, sizeof(fn), "digits/%d", num);
2102 } else if (num < 100) {
2103 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2107 } else if (num < 1000) {
2109 ast_copy_string(fn, "digits/100", sizeof(fn));
2111 ast_copy_string(fn, "digits/100E", sizeof(fn));
2113 if (mf < 0 && num > 199)
2114 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
2116 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
2121 } else if (num < 1000000) {
2123 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
2127 ast_copy_string(fn, "digits/1000", sizeof(fn));
2128 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100)))
2131 } else if (num < 1000000000) {
2132 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
2136 ast_copy_string(fn, "digits/1000000", sizeof(fn));
2138 ast_copy_string(fn, "digits/1000000S", sizeof(fn));
2140 if ((num % 1000000) &&
2142 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
2143 /* no hundreds and below */
2144 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
2146 num = num % 1000000;
2148 /* number is too big */
2149 ast_log(LOG_WARNING, "Number '%d' is too big to say.", num);
2153 if (!ast_streamfile(chan, fn, language)) {
2154 if ((audiofd > -1) && (ctrlfd > -1))
2155 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2157 res = ast_waitstream(chan, ints);
2159 ast_stopstream(chan);
2161 if (!res && playh) {
2162 res = wait_file(chan, ints, "digits/pt-e", language);
2163 ast_stopstream(chan);
2170 /*! \brief ast_say_number_full_se: Swedish syntax */
2171 static int ast_say_number_full_se(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2176 int cn = 1; /* +1 = commune; -1 = neuter */
2178 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2179 if (options && !strncasecmp(options, "n", 1)) cn = -1;
2181 while (!res && (num || playh)) {
2183 ast_copy_string(fn, "digits/minus", sizeof(fn));
2184 if ( num > INT_MIN ) {
2190 ast_copy_string(fn, "digits/hundred", sizeof(fn));
2192 } else if (num < 20) {
2193 snprintf(fn, sizeof(fn), "digits/%d", num);
2195 } else if (num < 100) {
2196 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2198 } else if (num == 1 && cn == -1) { /* En eller ett? */
2199 ast_copy_string(fn, "digits/1N", sizeof(fn));
2203 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2207 if (num < 1000000) { /* 1,000,000 */
2208 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2213 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2215 if (num < 1000000000) { /* 1,000,000,000 */
2216 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2221 ast_copy_string(fn, "digits/million", sizeof(fn));
2223 ast_debug(1, "Number '%d' is too big for me\n", num);
2230 if (!ast_streamfile(chan, fn, language)) {
2231 if ((audiofd > -1) && (ctrlfd > -1))
2232 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2234 res = ast_waitstream(chan, ints);
2235 ast_stopstream(chan);
2242 /*! \brief ast_say_number_full_tw: Taiwanese / Chinese syntax */
2243 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2249 int last_length = 0;
2253 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2255 while (!res && (num || playh || playt || playz)) {
2257 ast_copy_string(fn, "digits/minus", sizeof(fn));
2258 if ( num > INT_MIN ) {
2264 snprintf(fn, sizeof(fn), "digits/0");
2268 ast_copy_string(fn, "digits/hundred", sizeof(fn));
2271 snprintf(fn, sizeof(fn), "digits/thousand");
2273 } else if (num < 10) {
2274 snprintf(buf, 10, "%d", num);
2275 if (last_length - strlen(buf) > 1 && last_length != 0) {
2276 last_length = strlen(buf);
2280 if (strcasecmp(language,"twz") == 0)
2281 snprintf(fn, sizeof(fn), "digits/%d", num);
2283 snprintf(fn, sizeof(fn), "digits/%d", num);
2285 } else if (num < 100) {
2286 snprintf(buf, 10, "%d", num);
2287 if (last_length - strlen(buf) > 1 && last_length != 0) {
2288 last_length = strlen(buf);
2292 last_length = strlen(buf);
2293 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2297 snprintf(buf, 10, "%d", num);
2298 if (last_length - strlen(buf) > 1 && last_length != 0) {
2299 last_length = strlen(buf);
2303 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
2305 snprintf(buf, 10, "%d", num);
2306 ast_log(LOG_DEBUG, "Number '%d' %d %d\n", num, (int)strlen(buf), last_length);
2307 last_length = strlen(buf);
2308 num -= ((num / 100) * 100);
2309 } else if (num < 10000){
2310 snprintf(buf, 10, "%d", num);
2311 snprintf(fn, sizeof(fn), "digits/%d", (num / 1000));
2313 snprintf(buf, 10, "%d", num);
2314 ast_log(LOG_DEBUG, "Number '%d' %d %d\n", num, (int)strlen(buf), last_length);
2315 last_length = strlen(buf);
2316 num -= ((num / 1000) * 1000);
2317 } else if (num < 100000000) { /* 100,000,000 */
2318 res = ast_say_number_full_tw(chan, num / 10000, ints, language, audiofd, ctrlfd);
2321 snprintf(buf, 10, "%d", num);
2322 ast_log(LOG_DEBUG, "Number '%d' %d %d\n", num, (int)strlen(buf), last_length);
2323 num -= ((num / 10000) * 10000);
2324 last_length = strlen(buf);
2325 snprintf(fn, sizeof(fn), "digits/wan");
2327 if (num < 1000000000) { /* 1,000,000,000 */
2328 res = ast_say_number_full_tw(chan, num / 100000000, ints, language, audiofd, ctrlfd);
2331 snprintf(buf, 10, "%d", num);
2332 ast_log(LOG_DEBUG, "Number '%d' %d %d\n", num, (int)strlen(buf), last_length);
2333 last_length = strlen(buf);
2334 num -= ((num / 100000000) * 100000000);
2335 snprintf(fn, sizeof(fn), "digits/yi");
2337 ast_debug(1, "Number '%d' is too big for me\n", num);
2343 if (!ast_streamfile(chan, fn, language)) {
2344 if ((audiofd > -1) && (ctrlfd > -1))
2345 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2347 res = ast_waitstream(chan, ints);
2349 ast_stopstream(chan);
2356 /*! \brief determine last digits for thousands/millions (ru) */
2357 static int get_lastdigits_ru(int num) {
2360 } else if (num < 100) {
2361 return get_lastdigits_ru(num % 10);
2362 } else if (num < 1000) {
2363 return get_lastdigits_ru(num % 100);
2365 return 0; /* number too big */
2369 /*! \brief ast_say_number_full_ru: Russian syntax */
2370 /*! \brief additional files:
2371 n00.gsm (one hundred, two hundred, ...)
2374 thousands-i.gsm (tisyachi)
2375 million-a.gsm (milliona)
2381 where 'n' from 1 to 9
2383 static int ast_say_number_full_ru(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2389 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2391 while (!res && (num)) {
2393 ast_copy_string(fn, "digits/minus", sizeof(fn));
2394 if ( num > INT_MIN ) {
2399 } else if (num < 20) {
2400 if (options && strlen(options) == 1 && num < 3) {
2401 snprintf(fn, sizeof(fn), "digits/%d%s", num, options);
2403 snprintf(fn, sizeof(fn), "digits/%d", num);
2406 } else if (num < 100) {
2407 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 10));
2409 } else if (num < 1000){
2410 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 100));
2412 } else if (num < 1000000) { /* 1,000,000 */
2413 lastdigits = get_lastdigits_ru(num / 1000);
2415 if (lastdigits < 3) {
2416 res = ast_say_number_full_ru(chan, num / 1000, ints, language, "f", audiofd, ctrlfd);
2418 res = ast_say_number_full_ru(chan, num / 1000, ints, language, NULL, audiofd, ctrlfd);
2422 if (lastdigits == 1) {
2423 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2424 } else if (lastdigits > 1 && lastdigits < 5) {
2425 ast_copy_string(fn, "digits/thousands-i", sizeof(fn));
2427 ast_copy_string(fn, "digits/thousands", sizeof(fn));
2430 } else if (num < 1000000000) { /* 1,000,000,000 */
2431 lastdigits = get_lastdigits_ru(num / 1000000);
2433 res = ast_say_number_full_ru(chan, num / 1000000, ints, language, NULL, audiofd, ctrlfd);
2436 if (lastdigits == 1) {
2437 ast_copy_string(fn, "digits/million", sizeof(fn));
2438 } else if (lastdigits > 1 && lastdigits < 5) {
2439 ast_copy_string(fn, "digits/million-a", sizeof(fn));
2441 ast_copy_string(fn, "digits/millions", sizeof(fn));
2445 ast_debug(1, "Number '%d' is too big for me\n", num);
2449 if (!ast_streamfile(chan, fn, language)) {
2450 if ((audiofd > -1) && (ctrlfd > -1))
2451 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2453 res = ast_waitstream(chan, ints);
2455 ast_stopstream(chan);
2461 static int ast_say_number_full_th(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2467 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2469 while(!res && (num || playh)) {
2471 ast_copy_string(fn, "digits/lop", sizeof(fn));
2472 if ( num > INT_MIN ) {
2478 ast_copy_string(fn, "digits/roi", sizeof(fn));
2480 } else if (num < 100) {
2481 if ((num <= 20) || ((num % 10) == 1)) {
2482 snprintf(fn, sizeof(fn), "digits/%d", num);
2485 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2488 } else if (num < 1000) {
2489 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2492 } else if (num < 10000) { /* 10,000 */
2493 res = ast_say_number_full_th(chan, num / 1000, ints, language, audiofd, ctrlfd);
2497 ast_copy_string(fn, "digits/pan", sizeof(fn));
2498 } else if (num < 100000) { /* 100,000 */
2499 res = ast_say_number_full_th(chan, num / 10000, ints, language, audiofd, ctrlfd);
2503 ast_copy_string(fn, "digits/muan", sizeof(fn));
2504 } else if (num < 1000000) { /* 1,000,000 */
2505 res = ast_say_number_full_th(chan, num / 100000, ints, language, audiofd, ctrlfd);
2509 ast_copy_string(fn, "digits/san", sizeof(fn));
2511 res = ast_say_number_full_th(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2515 ast_copy_string(fn, "digits/larn", sizeof(fn));
2518 if(!ast_streamfile(chan, fn, language)) {
2519 if ((audiofd > -1) && (ctrlfd > -1))
2520 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2522 res = ast_waitstream(chan, ints);
2524 ast_stopstream(chan);
2530 /*! \brief ast_say_enumeration_full: call language-specific functions */
2531 /* Called from AGI */
2532 static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2534 if (!strcasecmp(language, "en") ) { /* English syntax */
2535 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2536 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
2537 return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
2538 } else if (!strcasecmp(language, "de") ) { /* German syntax */
2539 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2540 } else if (!strcasecmp(language, "he")) { /* Hebrew syntax */
2541 return (ast_say_enumeration_full_he(chan, num, ints, language, options, audiofd, ctrlfd));
2544 /* Default to english */
2545 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2548 /*! \brief ast_say_enumeration_full_en: English syntax */
2549 /* This is the default syntax, if no other syntax defined in this file is used */
2550 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2555 while (!res && num) {
2557 ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
2558 if ( num > INT_MIN ) {
2563 } else if (num < 20) {
2564 snprintf(fn, sizeof(fn), "digits/h-%d", num);
2566 } else if (num < 100) {
2567 int tens = num / 10;
2570 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2572 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2574 } else if (num < 1000) {
2575 int hundreds = num / 100;
2577 if (hundreds > 1 || t == 1) {
2578 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2583 ast_copy_string(fn, "digits/hundred", sizeof(fn));
2585 ast_copy_string(fn, "digits/h-hundred", sizeof(fn));
2587 } else if (num < 1000000) {
2588 int thousands = num / 1000;
2590 if (thousands > 1 || t == 1) {
2591 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2596 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2598 ast_copy_string(fn, "digits/h-thousand", sizeof(fn));
2601 } else if (num < 1000000000) {
2602 int millions = num / 1000000;
2603 num = num % 1000000;
2605 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2609 ast_copy_string(fn, "digits/million", sizeof(fn));
2611 ast_copy_string(fn, "digits/h-million", sizeof(fn));
2613 } else if (num < INT_MAX) {
2614 int billions = num / 1000000000;
2615 num = num % 1000000000;
2617 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2621 ast_copy_string(fn, "digits/billion", sizeof(fn));
2623 ast_copy_string(fn, "digits/h-billion", sizeof(fn));
2625 } else if (num == INT_MAX) {
2626 ast_copy_string(fn, "digits/h-last", sizeof(fn));
2629 ast_debug(1, "Number '%d' is too big for me\n", num);
2634 if (!ast_streamfile(chan, fn, language)) {
2635 if ((audiofd > -1) && (ctrlfd > -1)) {
2636 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2638 res = ast_waitstream(chan, ints);
2641 ast_stopstream(chan);
2647 /*! \brief ast_say_enumeration_full_da: Danish syntax */
2648 static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2650 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2652 char fn[256] = "", fna[256] = "";
2655 if (options && !strncasecmp(options, "f", 1)) {
2657 } else if (options && !strncasecmp(options, "n", 1)) {
2664 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2666 while (!res && num) {
2668 ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
2669 if ( num > INT_MIN ) {
2674 } else if (num < 100 && t) {
2675 ast_copy_string(fn, "digits/and", sizeof(fn));
2677 } else if (num < 20) {
2678 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2680 } else if (num < 100) {
2681 int ones = num % 10;
2683 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2686 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2689 } else if (num == 100 && t == 0) {
2690 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2692 } else if (num < 1000) {
2693 int hundreds = num / 100;
2695 if (hundreds == 1) {
2696 ast_copy_string(fn, "digits/1N", sizeof(fn));
2698 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2701 ast_copy_string(fna, "digits/hundred", sizeof(fna));
2703 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2706 } else if (num < 1000000) {
2707 int thousands = num / 1000;
2709 if (thousands == 1) {
2711 ast_copy_string(fn, "digits/1N", sizeof(fn));
2712 ast_copy_string(fna, "digits/thousand", sizeof(fna));
2715 ast_copy_string(fn, "digits/1N", sizeof(fn));
2716 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2718 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2722 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2727 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2729 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2733 } else if (num < 1000000000) {
2734 int millions = num / 1000000;
2735 num = num % 1000000;
2736 if (millions == 1) {
2738 ast_copy_string(fn, "digits/1F", sizeof(fn));
2739 ast_copy_string(fna, "digits/million", sizeof(fna));
2741 ast_copy_string(fn, "digits/1N", sizeof(fn));
2742 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);