Fruit's git repositories f00f / argloos spreek.c
argloos

Tree @argloos (Download .tar.gz)

spreek.c @argloosraw · history · blame

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "f00f.h"

const byte * const cijfer[] = {
	"nul", "één", "twee", "drie", "vier",
	"vijf", "zes", "zeven", "acht", "negen",
	"tien", "elf", "twaalf", "dertien", "veertien",
	"vijftien", "zestien", "zeventien", "achttien", "negentien"
};

const byte * const cijferordinaal[] = {
	"nul", "eer", "twee", "der", "vier",
	"vijf", "zes", "zeven", "acht", "negen",
	"tien", "elf", "twaalf", "dertien", "veertien",
	"vijftien", "zestien", "zeventien", "achttien", "negentien"
};

const byte * const tiental[] = {
	"", "", "twintig", "dertig", "veertig",
	"vijftig", "zestig", "zeventig", "tachtig", "negentig"
};

const byte * const factor[] = {
	"", "duizend",
	"miljoen", "miljard",
	"biljoen", "biljard",
	"triljoen", "triljard",
	"quadriljoen", "quadriljard",
	"quintiljoen", "quintiljard"
};

const byte * const voorvoegsel[] = {
	"yocto", "zepto", "atto", "femto", "pico", "nano", "micro", "milli",
	"",
	"kilo", "mega", "giga", "tera", "peta", "exa", "zetta", "yotta"
};

const byte * const eenheid[NRDIMENSIES] = {
	"meter",
	"gram",
	"seconde",
	"ampère",
	"kelvin",
	"candela",
	"mol",

	"euro",
	"bit",

	"joule",
	"volt",
	"farad",
	"pascal",
	"hertz",
	"ohm",
	"tesla",
	"newton",
	"coulomb",
	"watt",
	"weber",
	"becquerel",
	"sievert",
	"henry",
};

void spreek_honderdtal(splitbuf_t *spreek, int n) {
	int h, t, c;

	h = n / 100;
	t = (n / 10) % 10;
	c = n % 10;

	if(t == 1) {
		t = 0;
		c += 10;
	}

	if(h) {
		if(h != 1)
			qstrcat(spreek, cijfer[h]);
		qstrcat(spreek, "honderd");
	}

	if(t) {
		if(c) {
			qstrcat(spreek, cijfer[c]);
			if(cijfer[c][strlen(cijfer[c]) - 1] == 'e')
				qstrcat(spreek, "ën");
			else
				qstrcat(spreek, "en");
		}
		qstrcat(spreek, tiental[t]);
	} else {
		if(!(c == 0 && h != 0))
			qstrcat(spreek, cijfer[c]);
	}
}

int stukje_int(byte *stukje, int len) {
	int i = 0;

	while(len--) {
		i *= 10;
		i += *stukje++ - '0';
	}

	return i;
}


void spreek_geheel(splitbuf_t *spreek, byte *geheel) {
	int l, e, x;

	l = strlen(geheel) - 1;

	if(!l && *geheel == '0') {
		qstrcat(spreek, "nul");
		return;
	}

	if(l == 3 && stukje_int(geheel, 2) > 10 && stukje_int(geheel + 1, 1)) {
		spreek_honderdtal(spreek, stukje_int(geheel, 2));
		qstrcat(spreek, "honderd");
		l -= 2;
		geheel += 2;
		if(!stukje_int(geheel, 2))
			l -= 5;
	}

	for(e = l / 3; e >= 0; e--) {
		if(stukje_int(geheel, x = l % 3 + 1)) {
			spreek_honderdtal(spreek, stukje_int(geheel, x));
			qstrcat(spreek, factor[e]);
			l -= x;
			geheel += x;
		}
	}
}

void spreek_honderdtalordinaal(splitbuf_t *spreek, int n) {
	int h, t, c;
	const byte *e = "";

	h = n / 100;
	t = (n / 10) % 10;
	c = n % 10;

	if(t == 1) {
		t = 0;
		c += 10;
	}

	if(h) {
		if(h != 1)
			qstrcat(spreek, cijfer[h]);
		qstrcat(spreek, e = "honderd");
	}

	if(t) {
		if(c) {
			qstrcat(spreek, cijfer[c]);
			if(cijfer[c][strlen(cijfer[c]) - 1] == 'e')
				qstrcat(spreek, "ën");
			else
				qstrcat(spreek, "en");
		}
		qstrcat(spreek, e = tiental[t]);
	} else {
		if(!(c == 0 && h != 0))
			qstrcat(spreek, e = cijferordinaal[c]);
	}
	
	if(strchr("efnrs", e[strlen(e) - 1]))
		qstrcat(spreek, "de");
	else
		qstrcat(spreek, "ste");
}

void spreek_cijfertjes(splitbuf_t *spreek, byte *cijfertjes) {
	while(*cijfertjes) {
		qstrcat(spreek, cijfer[*cijfertjes++ - '0']);
		if(*cijfertjes)
			qstrcat(spreek, " ");
	}
}

void spreek_real(splitbuf_t *spreek, real getal) {
	byte *geprint, *geheel, *fractie, *exponent;
	unsigned long long int fractint;
	int exp;
	
	if(isnan(getal)) {
		qstrcat(spreek, "geen getal");
		return;
	}

	if(signbit(getal)) {
		qstrcat(spreek, "min ");
		getal = -getal;
	}

	if(isinf(getal)) {
		qstrcat(spreek, "oneindig");
		return;
	}

	if(asprintf((char **)&geprint, "%.15Lg", getal) == -1)
		return;

	geheel = geprint;
	exponent = strchr(geprint, 'e');
	if(exponent)
		*exponent++ = '\0';
	fractie = strchr(geprint, '.');
	if(fractie)
		*fractie++ = '\0';

	spreek_geheel(spreek, geheel);

	if(fractie) {
		sscanf(fractie, "%Lu", &fractint);
		qstrcat(spreek, " komma ");

		if (fractint < 10000UL && *fractie != '0')
			spreek_geheel(spreek, fractie);
		else
			spreek_cijfertjes(spreek, fractie);
	}

	if(exponent) {
		exp = atoi(exponent);
		qstrcat(spreek, " maal tien tot de ");
		if(abs(exp) < 1000) {
			if(exp < 0)
				qstrcat(spreek, "min ");
			spreek_honderdtalordinaal(spreek, abs(exp));
		} else {
			qstrcat(spreek, "macht ");
			if(exp < 0)
				qstrcat(spreek, "min ");
			spreek_real(spreek, abs(exp));
		}
	}

/*
	if(getal > 1.0e-14) {
		if(l >= 0)
			qstrcat(spreek, " ");

		if(isnoemer(getal, 2.0)) {
			qstrcat(spreek, cijfer[(int)(getal * 2.0 + 0.1)]);
			qstrcat(spreek, " half");
		}
		else if(isnoemer(getal, 3.0)) {
			qstrcat(spreek, cijfer[(int)(getal * 3.0 + 0.1)]);
			qstrcat(spreek, " derde");
		}
		else if(isnoemer(getal, 4.0)) {
			qstrcat(spreek, cijfer[(int)(getal * 4.0 + 0.1)]);
			qstrcat(spreek, " kwart");
		} else {
			for(i = 5; i < 1000; i++) {
				if(isnoemer(getal, (real)i)) {
					qstrcat(spreek, h = spreek_honderdtal(getal * (real)i + 0.1));
					free(h);
					qstrcat(spreek, " ");
					qstrcat(spreek, h = spreek_honderdtal(i));
					free(h);
					if(strchr("efnrs", spreek[strlen(spreek) - 1]))
						qstrcat(spreek, "de");
					else
						qstrcat(spreek, "ste");
					break;
				}
			}

			if(i >= 1000) {
				if(l < 0)
					qstrcat(spreek, "nul ");

				qstrcat(spreek, "komma");

				sprintf(cijfertjes, "%.14Lf", getal);

				for(c = cijfertjes + strlen(cijfertjes) - 1; *c == '0'; c--)
					*c = '\0';

				for(c = cijfertjes + 2; *c; c++) {
					qstrcat(spreek, " ");
					qstrcat(spreek, cijfer[*c - '0']);
				}
			}
		}
	} else {
		if(l < 0)
			qstrcat(spreek, "nul");
	}
*/
	free(geprint);
}

void spreek_echt(splitbuf_t *spreek, echt_t getal) {
	bool pernodig;
	int i, j;

	if(getal.dim[DIM_MASSA]) {
		getal.echt *= pow(0.001, getal.dim[DIM_MASSA]);
		getal.imag *= pow(0.001, getal.dim[DIM_MASSA]);
	}

	if(!(getal.echt == 0.0 && getal.imag != 0.0)) {
		spreek_real(spreek, getal.echt);
	}

	if(getal.imag != 0.0) {
		if(getal.echt != 0.0) {
			qstrcat(spreek, " ");
			if(getal.echt != 0.0 && getal.imag > 0.0)
				qstrcat(spreek, "plus ");
		}
		spreek_real(spreek, getal.imag);
		qstrcat(spreek, " i");
	}

	if(!isdimensieloos(getal)) {
		for(j = 0; j < NRDIMENSIES; j++) {
			i = eenheidvolgorde[j];
			if(getal.dim[i] > 0) {
				qstrcat(spreek, " ");
				if(i == DIM_LENGTE) {
					if(getal.dim[i] == 2)
						qstrcat(spreek, "vierkante ");
					else if(getal.dim[i] == 3)
						qstrcat(spreek, "kubieke ");
				}
				if(i == DIM_MASSA)
					qstrcat(spreek, "kilo");
				qstrcat(spreek, eenheid[i]);
				if(getal.dim[i] == 2 && i != DIM_LENGTE)
					qstrcat(spreek, " kwadraat");
				else if(getal.dim[i] > 3 || (getal.dim[i] > 1 && i != DIM_LENGTE)) {
					qstrcat(spreek, " tot de ");
					if(getal.dim[i] < 1000) {
						spreek_honderdtalordinaal(spreek, getal.dim[i]);
					} else {
						qstrcat(spreek, "macht ");
						spreek_real(spreek, getal.dim[i]);
					}
				}
			}
		}
		pernodig = TRUE;
		for(j = 0; j < NRDIMENSIES; j++) {
			i = eenheidvolgorde[j];
			if(getal.dim[i] < 0) {
				if(pernodig) {
					qstrcat(spreek, " per");
					pernodig = FALSE;
				}
				qstrcat(spreek, " ");
				if(i == DIM_LENGTE) {
					if(-getal.dim[i] == 2)
						qstrcat(spreek, "vierkante ");
					else if(-getal.dim[i] == 3)
						qstrcat(spreek, "kubieke ");
				}
				if(i == DIM_MASSA)
					qstrcat(spreek, "kilo");
				qstrcat(spreek, eenheid[i]);
				if(-getal.dim[i] == 2 && i != DIM_LENGTE)
					qstrcat(spreek, " kwadraat");
				else if(-getal.dim[i] > 3 || (-getal.dim[i] > 1 && i != DIM_LENGTE)) {
					qstrcat(spreek, " tot de ");
					if(getal.dim[i] < 1000) {
						spreek_honderdtalordinaal(spreek, -getal.dim[i]);
					} else {
						qstrcat(spreek, "macht ");
						spreek_real(spreek, -getal.dim[i]);
					}
				}
			}
		}
	}
}