Skip to content
Snippets Groups Projects
say.c 168 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			} else if (num < 2000) {
    				num = num % 1000;
    				snprintf(fn, sizeof(fn), "digits/thousand");
    
    					res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
    
    					snprintf(fn, sizeof(fn), "digits/thousand");
    
    				} else {
    					if (num < 2147483640) {
    						if ((num/1000000) == 1) {
    
    							res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
    							if (res)
    								return res;
    							snprintf(fn, sizeof(fn), "digits/million");
    
    							res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
    							if (res)
    								return res;
    							snprintf(fn, sizeof(fn), "digits/millions");
    
    						}
    						num = num % 1000000;
    					} else {
    						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    						res = -1;
    					}
    				}
    			}
    		}
    
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1))
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    
    /*--- ast_say_number_full_fr: French syntax */
    
    /* 	Extra sounds needed:
     	1F: feminin 'une'
     	et: 'and' */
    
    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)
    
    	int mf = 1;                            /* +1 = male; -1 = female */
    
    	char fn[256] = "";
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    	
    	if (options && !strncasecmp(options, "f",1))
    		mf = -1;
    
    
    	while(!res && (num || playh || playa)) {
    
    		if (num < 0) {
    			snprintf(fn, sizeof(fn), "digits/minus");
    			if ( num > INT_MIN ) {
    				num = -num;
    			} else {
    				num = 0;
    			}	
    		} else if (playh) {
    
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			playh = 0;
    		} else if (playa) {
    			snprintf(fn, sizeof(fn), "digits/et");
    			playa = 0;
    
    		} else if (num == 1) {
    			if (mf < 0)
    				snprintf(fn, sizeof(fn), "digits/%dF", num);
    			else
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    
    		} else if (num < 21) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 70) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
    			if ((num % 10) == 1) playa++;
    			num = num % 10;
    		} else if (num < 80) {
    			snprintf(fn, sizeof(fn), "digits/60");
    			if ((num % 10) == 1) playa++;
    			num = num - 60;
    		} else if (num < 100) {
    			snprintf(fn, sizeof(fn), "digits/80");
    			num = num - 80;
    		} else if (num < 200) {
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			num = num - 100;
    		} else if (num < 1000) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    			playh++;
    			num = num % 100;
    		} else if (num < 2000) {
    			snprintf(fn, sizeof(fn), "digits/thousand");
    			num = num - 1000;
    		} else if (num < 1000000) {
    
    			res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
    
    			if (res)
    				return res;
    			snprintf(fn, sizeof(fn), "digits/thousand");
    			num = num % 1000;
    		} else	if (num < 1000000000) {
    
    			res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
    
    			if (res)
    				return res;
    			snprintf(fn, sizeof(fn), "digits/million");
    			num = num % 1000000;
    		} else {
    			ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    			res = -1;
    		}
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1))
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    	}
    	return res;
    }
    
    /*--- ast_say_number_full_it:  Italian */
    
    static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
    
    	int res = 0;
    	int playh = 0;
    	int tempnum = 0;
    	char fn[256] = "";
    
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    		/*
    		Italian support
    
    
    		Like english, numbers up to 20 are a single 'word', and others
    
    		For example 21 is not twenty-one, but there is a single word in 'it'.
    
    		Idem for 28 (ie when a the 2nd part of a compund number
    
    		There are exceptions also for hundred, thousand and million.
    
    		In english 100 = one hundred, 200 is two hundred.
    		In italian 100 = cento , like to say hundred (without one),
    		200 and more are like english.
    		
    
    		1000 is one thousand in en, 2000 is two thousand.
    		In it we have 1000 = mille , 2000 = 2 mila 
    
    		For million(s) we use the plural, if more than one
    		Also, one million is abbreviated in it, like on-million,
    		or 'un milione', not 'uno milione'.
    		So the right file is provided.
    		*/
    
    
    			if (num < 0) {
    				snprintf(fn, sizeof(fn), "digits/minus");
    				if ( num > INT_MIN ) {
    					num = -num;
    				} else {
    					num = 0;
    				}	
    			} else if (playh) {
    
    				snprintf(fn, sizeof(fn), "digits/hundred");
    				playh = 0;
    			} else if (num < 20) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 21) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 28) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 31) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 38) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 41) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 48) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 51) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 58) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 61) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 68) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 71) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 78) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 81) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 88) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 91) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 98) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num < 100) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    				num -= ((num / 10) * 10);
    			} else {
    				if (num < 1000) {
    					if ((num / 100) > 1) {
    						snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    						playh++;
    					} else {
    						snprintf(fn, sizeof(fn), "digits/hundred");
    					}
    					num -= ((num / 100) * 100);
    				} else {
    					if (num < 1000000) { /* 1,000,000 */
    						if ((num/1000) > 1)
    
    							res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
    
    						if (res)
    							return res;
    						tempnum = num;
    						num = num % 1000;
    						if ((tempnum / 1000) < 2)
    							snprintf(fn, sizeof(fn), "digits/thousand");
    						else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
    							snprintf(fn, sizeof(fn), "digits/thousands");
    					} else {
    						if (num < 1000000000) { /* 1,000,000,000 */
    							if ((num / 1000000) > 1)
    
    								res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    
    							if (res)
    								return res;
    							tempnum = num;
    							num = num % 1000000;
    							if ((tempnum / 1000000) < 2)
    								snprintf(fn, sizeof(fn), "digits/million");
    							else
    								snprintf(fn, sizeof(fn), "digits/millions");
    						} else {
    							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    							res = -1;
    						}
    					}
    				}
    			}
    			if (!res) {
    				if(!ast_streamfile(chan, fn, language)) {
    
    					if ((audiofd > -1) && (ctrlfd > -1))
    
    						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    					else
    						res = ast_waitstream(chan, ints);
    				}
    				ast_stopstream(chan);
    			}
    		}
    	return res;
    
    /*--- ast_say_number_full_nl: dutch syntax */
    /* New files: digits/nl-en
    
    static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
    
    	char fn[256] = "";
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    		if (num < 0) {
    			snprintf(fn, sizeof(fn), "digits/minus");
    			if ( num > INT_MIN ) {
    				num = -num;
    			} else {
    				num = 0;
    			}	
    		} else if (playh) {
    
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			playh = 0;
    		} else if (num < 20) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			units = num % 10;
    			if (units > 0) {
    				res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
    				if (res)
    					return res;
    				num = num - units;
    				snprintf(fn, sizeof(fn), "digits/nl-en");
    			} else {
    				snprintf(fn, sizeof(fn), "digits/%d", num - units);
    				num = 0;
    			}
    		} else {
    			if (num < 1000) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    				playh++;
    				num -= ((num / 100) * 100);
    			} else {
    				if (num < 1000000) { /* 1,000,000 */
    					res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
    					if (res)
    						return res;
    					num = num % 1000;
    					snprintf(fn, sizeof(fn), "digits/thousand");
    				} else {
    					if (num < 1000000000) { /* 1,000,000,000 */
    						res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    						if (res)
    							return res;
    						num = num % 1000000;
    						snprintf(fn, sizeof(fn), "digits/million");
    					} else {
    						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    						res = -1;
    					}
    				}
    			}
    		}
    
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1))
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    
    /*--- ast_say_number_full_no: Norwegian syntax */
    /* New files:
     In addition to American English, the following sounds are required:  "and", "1N"
     */
    
    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)
    
    {
    	int res = 0;
    	int playh = 0;
    	int playa = 0;
    
    	int cn = 1;		/* +1 = commune; -1 = neuter */
    
    	char fn[256] = "";
    	
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    	
    	if (options && !strncasecmp(options, "n",1)) cn = -1;
    
    	while(!res && (num || playh || playa )) {
    		/* The grammar for Norwegian numbers is the same as for English except
    		* for the following:
    
    		* - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
    
    		*   "and" before the last two digits, i.e. 2034 is "two thousand and
    		*   thirty-four" and 1000012 is "one million and twelve".
    		*/
    
    		if (num < 0) {
    			snprintf(fn, sizeof(fn), "digits/minus");
    			if ( num > INT_MIN ) {
    				num = -num;
    			} else {
    				num = 0;
    			}	
    		} else if (playh) {
    
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			playh = 0;
    		} else if (playa) {
    			snprintf(fn, sizeof(fn), "digits/and");
    			playa = 0;
    		} else if (num == 1 && cn == -1) {
    			snprintf(fn, sizeof(fn), "digits/1N");
    			num = 0;
    		} else if (num < 20) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    			num -= ((num / 10) * 10);
    		} else if (num < 1000) {
    			int hundreds = num / 100;
    			if (hundreds == 1)
    				snprintf(fn, sizeof(fn), "digits/1N");
    			else
    				snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
    
    			playh++;
    			num -= 100 * hundreds;
    			if (num)
    				playa++;
    		} else 	if (num < 1000000) {
    			res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
    			if (res)
    				return res;
    			snprintf(fn, sizeof(fn), "digits/thousand");
    			num = num % 1000;
    			if (num && num < 100)
    				playa++;
    		} else 	if (num < 1000000000) {
    				int millions = num / 1000000;
    				res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
    				if (res)
    					return res;
    				snprintf(fn, sizeof(fn), "digits/million");
    				num = num % 1000000;
    				if (num && num < 100)
    					playa++;
    		} else {
    				ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    				res = -1;
    		}
    		
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1)) 
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else  
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    	}
    	return res;
    }
    
    
    typedef struct {  
    	char *separator_dziesiatek;
    	char *cyfry[10];
    	char *cyfry2[10];
    	char *setki[10];
    	char *dziesiatki[10];
    	char *nastki[10];  
    	char *rzedy[3][3];
    } odmiana;
    
    static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
    {
    	if (rzad==0)
    		return "";
     
    	if (i==1)
    		return odm->rzedy[rzad - 1][0];
    	if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
    		return odm->rzedy[rzad - 1][1];
    	else
    		return odm->rzedy[rzad - 1][2];
    }
    
    static char* pl_append(char* buffer, char* str)
    {
    	strcpy(buffer, str);
    	buffer += strlen(str); 
    	return buffer;
    }
    
    
    static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
    
    {    
    	char file_name[255] = "digits/";
    	strcat(file_name, fn);
    	ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
    	if (!ast_streamfile(chan, file_name, language)) {
    
    		if ((audiofd > -1) && (ctrlfd > -1))
    
    			ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    		else
    			ast_waitstream(chan, ints);
    	}
    	ast_stopstream(chan);
    }
    
    
    static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
    
    {
    	/* Initialise variables to allow compilation on Debian-stable, etc */
    	int m1000E6 = 0;
    	int i1000E6 = 0;
    	int m1000E3 = 0;
    	int i1000E3 = 0;
    	int m1000 = 0;
    	int i1000 = 0;
    	int m100 = 0;
    	int i100 = 0;
    	
    	if (i == 0 && rzad > 0) { 
    		return;
    	}
    	if (i == 0) {
    		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
    	}
    
    	m1000E6 = i % 1000000000;
    	i1000E6 = i / 1000000000;
    
    	powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
    
    	m1000E3 = m1000E6 % 1000000;
    	i1000E3 = m1000E6 / 1000000;
    
    	powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
    
    	m1000 = m1000E3 % 1000;
    	i1000 = m1000E3 / 1000;
    
    	powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
    
    	m100 = m1000 % 100;
    	i100 = m1000 / 100;
    	
    	if (i100>0)
    		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
    
    	if ( m100 > 0 && m100 <=9 ) {
    		if (m1000>0)
    			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
    		else
    			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
    	} else if (m100 % 10 == 0) {
    		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
    	} else if (m100 <= 19 ) {
    		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
    	} else if (m100 != 0) {
    		if (odm->separator_dziesiatek[0]==' ') {
    			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
    			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
    		} else {
    			char buf[10];
    			char *b = buf;
    			b = pl_append(b, odm->dziesiatki[m100 / 10]);  
    			b = pl_append(b, odm->separator_dziesiatek);  
    			b = pl_append(b, odm->cyfry2[m100 % 10]); 
    			pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
    		}
    	} 
    
    	if (rzad > 0) {
    		pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
    	}
    }
    
    
    /* ast_say_number_full_pl: Polish syntax */
    
    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)
    
    /*
    Sounds needed:
    0		zero
    1		jeden
    10		dziesiec
    100		sto
    1000		tysiac
    1000000		milion
    1000000000	miliard
    1000000000.2	miliardy
    1000000000.5	miliardow
    1000000.2	miliony
    1000000.5	milionow
    1000.2		tysiace
    1000.5		tysiecy
    100m		stu
    10m		dziesieciu
    11		jedenascie
    11m		jedenastu
    12		dwanascie
    12m		dwunastu
    13		trzynascie
    13m		trzynastu
    14		czternascie
    14m		czternastu
    15		pietnascie
    15m		pietnastu
    16		szesnascie
    16m		szesnastu
    17		siedemnascie
    17m		siedemnastu
    18		osiemnascie
    18m		osiemnastu
    19		dziewietnascie
    19m		dziewietnastu
    1z		jedna
    2		dwie
    20		dwadziescia
    200		dwiescie
    200m		dwustu
    20m		dwudziestu
    2-1m		dwaj
    2-2m		dwoch
    2z		dwie
    3		trzy
    30		trzydziesci
    300		trzysta
    300m		trzystu
    30m		trzydziestu
    3-1m		trzej
    3-2m		trzech
    4		cztery
    40		czterdziesci
    400		czterysta
    400m		czterystu
    40m		czterdziestu
    4-1m		czterej
    4-2m		czterech
    5		piec
    50		piecdziesiat
    500		piecset
    500m		pieciuset
    50m		piedziesieciu
    5m		pieciu
    6		szesc
    60		szescdziesiat
    600		szescset
    600m		szesciuset
    60m		szescdziesieciu
    6m		szesciu
    7		siedem
    70		siedemdziesiat
    700		siedemset
    700m		siedmiuset
    70m		siedemdziesieciu
    7m		siedmiu
    8		osiem
    80		osiemdziesiat
    800		osiemset
    800m		osmiuset
    80m		osiemdziesieciu
    8m		osmiu
    9		dziewiec
    90		dziewiecdziesiat
    900		dziewiecset
    900m		dziewieciuset
    90m		dziewiedziesieciu
    9m		dziewieciu
    and combinations of eg.: 20_1, 30m_3m, etc...
    
    */
    {
    	char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
    
    	char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
    
    	char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
    
    	char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
    
    	char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
    
    	char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
    
    	char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
    
    	char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
    
    	char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
    
    	/* Initialise variables to allow compilation on Debian-stable, etc */
    	odmiana *o;
    
    	static odmiana *odmiana_nieosobowa = NULL; 
    	static odmiana *odmiana_meska = NULL; 
    	static odmiana *odmiana_zenska = NULL; 
    
    	if (odmiana_nieosobowa == NULL) {
    		odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
    
    		odmiana_nieosobowa->separator_dziesiatek = "_";
    
    		memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
    		memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
    		memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
    		memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
    		memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
    		memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
    	}
    
    	if (odmiana_zenska == NULL) {
    		odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
    
    
    		odmiana_zenska->separator_dziesiatek = " ";
    
    
    		memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
    		memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
    		memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
    		memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
    		memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
    		memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
    	}
    
    	if (odmiana_meska == NULL) {
    		odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
    
    
    		odmiana_meska->separator_dziesiatek = " ";
    
    
    		memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
    		memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
    		memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
    		memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
    		memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
    		memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
    	}
    
    	if (options) {
    		if (strncasecmp(options, "f", 1) == 0)
    			o = odmiana_zenska;
    		else if (strncasecmp(options, "m", 1) == 0)
    			o = odmiana_meska;
    		else
    			o = odmiana_nieosobowa;
    	} else
    		o = odmiana_nieosobowa;
    
    
    	powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
    
    /* ast_say_number_full_pt: Portuguese syntax */
    /* 	Extra sounds needed: */
    /* 	For feminin all sound files end with F */
    /*	100E for 100+ something */
    /*	1000000S for plural */
    /*	pt-e for 'and' */
    
    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)
    
    	int mf = 1;                            /* +1 = male; -1 = female */
    
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    
    	if (options && !strncasecmp(options, "f",1))
    		mf = -1;
    
    	while(!res && num ) {
    
    		if (num < 0) {
    			snprintf(fn, sizeof(fn), "digits/minus");
    			if ( num > INT_MIN ) {
    				num = -num;
    			} else {
    				num = 0;
    			}	
    		} else if (num < 20) {
    
    			if ((num == 1 || num == 2) && (mf < 0))
    				snprintf(fn, sizeof(fn), "digits/%dF", num);
    			else
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
    			if (num % 10)
    				playh = 1;
    			num = num % 10;
    		} else if (num < 1000) {
    			if (num == 100)
    				snprintf(fn, sizeof(fn), "digits/100");
    			else if (num < 200)
    				snprintf(fn, sizeof(fn), "digits/100E");
    			else {
    				if (mf < 0 && num > 199)
    					snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
    				else
    					snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
    				if (num % 100)
    					playh = 1;
    			}
    			num = num % 100;
    		} else if (num < 1000000) {
    			if (num > 1999) {
    				res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
    				if (res)
    					return res;
    			}
    			snprintf(fn, sizeof(fn), "digits/1000");
    			if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
    				playh = 1;
    			num = num % 1000;
    		} else if (num < 1000000000) {
    			res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
    			if (res)
    				return res;
    			if (num < 2000000)
    				snprintf(fn, sizeof(fn), "digits/1000000");
    			else
    				snprintf(fn, sizeof(fn), "digits/1000000S");
     
    			if ((num % 1000000) &&
    
    				((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
    
    				(!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
    				playh = 1;
    			num = num % 1000000;
    		}
    
    		if (!res) {
    			if (!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1))
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);	
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    
    		if (!res && playh) {
    			res = wait_file(chan, ints, "digits/pt-e", language);
    			ast_stopstream(chan);
    			playh = 0;
    		}
    
    /*--- ast_say_number_full_se: Swedish syntax */
    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)
    
    {
    	int res = 0;
    	int playh = 0;
    	char fn[256] = "";
    
    	int cn = 1;		/* +1 = commune; -1 = neuter */
    
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    	if (options && !strncasecmp(options, "n",1)) cn = -1;
    
    	while(!res && (num || playh)) {
    
    		if (num < 0) {
    			snprintf(fn, sizeof(fn), "digits/minus");
    			if ( num > INT_MIN ) {
    				num = -num;
    			} else {
    
    			}	
    		} else if (playh) {
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			playh = 0;
    		} else if (num < 20) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    			num -= ((num / 10) * 10);
    		} else if (num == 1 && cn == -1) {	/* En eller ett? */
    		 	snprintf(fn, sizeof(fn), "digits/1N");
    			num = 0;
    		} else {
    			if (num < 1000){
    				snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    				playh++;
    				num -= ((num / 100) * 100);
    
    				if (num < 1000000) { /* 1,000,000 */
    					res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
    					if (res) {
    						return res;
    					}
    					num = num % 1000;
    					snprintf(fn, sizeof(fn), "digits/thousand");
    
    					if (num < 1000000000) {	/* 1,000,000,000 */
    						res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
    						if (res) {
    
    						num = num % 1000000;
    						snprintf(fn, sizeof(fn), "digits/million");
    					} else {
    						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    						res = -1;
    
    		}
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    
    				if ((audiofd > -1) && (ctrlfd > -1))
    
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    				ast_stopstream(chan);
    			}
    		}
    
    /*--- ast_say_number_full_tw: Taiwanese syntax */
    
    static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
    
    {
    	int res = 0;
    	int playh = 0;
    	char fn[256] = "";
    	if (!num)
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    	while(!res && (num || playh)) {
    
    			if (num < 0) {
    				snprintf(fn, sizeof(fn), "digits/minus");
    				if ( num > INT_MIN ) {
    					num = -num;
    				} else {
    					num = 0;
    				}	
    			} else if (playh) {
    
    				snprintf(fn, sizeof(fn), "digits/hundred");
    				playh = 0;
    			} else	if (num < 10) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else	if (num < 100) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    				num -= ((num / 10) * 10);
    			} else {
    				if (num < 1000){
    					snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    					playh++;
    					num -= ((num / 100) * 100);
    				} else {
    					if (num < 1000000) { /* 1,000,000 */
    
    						res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
    
    						if (res)
    							return res;
    						num = num % 1000;
    						snprintf(fn, sizeof(fn), "digits/thousand");
    					} else {
    						if (num < 1000000000) {	/* 1,000,000,000 */
    
    							res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    
    							if (res)
    								return res;
    							num = num % 1000000;
    							snprintf(fn, sizeof(fn), "digits/million");
    						} else {
    							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    							res = -1;
    						}
    					}
    				}
    			}
    			if (!res) {
    				if(!ast_streamfile(chan, fn, language)) {
    
    					if ((audiofd > -1) && (ctrlfd > -1))
    
    						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    					else
    						res = ast_waitstream(chan, ints);
    				}
    				ast_stopstream(chan);
    			}
    	}
    	return res;
    }
    
    
    /*--- ast_say_enumeration_full: call language-specific functions */
    /* Called from AGI */
    int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
    {
    	if (!strcasecmp(language,"en") ) {	/* English syntax */
    	   return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
    
    	} else if (!strcasecmp(language, "da") ) {	/* Danish syntax */
    	   return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
    
    	} else if (!strcasecmp(language, "de") ) {	/* German syntax */
    	   return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
    	} 
    	
    	/* Default to english */
    	return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));