strans/vi.c
2026-02-09 09:24:50 +09:00

149 lines
3.2 KiB
C

#include "dat.h"
#include "fn.h"
static struct {
Rune base;
Rune tone[5]; /* s f r x j */
} vitone[] = {
{L'a', {L'á', L'à', L'', L'ã', L''}},
{L'â', {L'', L'', L'', L'', L''}},
{L'ă', {L'', L'', L'', L'', L''}},
{L'e', {L'é', L'è', L'', L'', L''}},
{L'ê', {L'ế', L'', L'', L'', L''}},
{L'i', {L'í', L'ì', L'', L'ĩ', L''}},
{L'o', {L'ó', L'ò', L'', L'õ', L''}},
{L'ô', {L'', L'', L'', L'', L''}},
{L'ơ', {L'', L'', L'', L'', L''}},
{L'u', {L'ú', L'ù', L'', L'ũ', L''}},
{L'ư', {L'', L'', L'', L'', L''}},
{L'y', {L'ý', L'', L'', L'', L''}},
{L'A', {L'Á', L'À', L'', L'Ã', L''}},
{L'Â', {L'', L'', L'', L'', L''}},
{L'Ă', {L'', L'', L'', L'', L''}},
{L'E', {L'É', L'È', L'', L'', L''}},
{L'Ê', {L'', L'', L'', L'', L''}},
{L'I', {L'Í', L'Ì', L'', L'Ĩ', L''}},
{L'O', {L'Ó', L'Ò', L'', L'Õ', L''}},
{L'Ô', {L'', L'', L'', L'', L''}},
{L'Ơ', {L'', L'', L'', L'', L''}},
{L'U', {L'Ú', L'Ù', L'', L'Ũ', L''}},
{L'Ư', {L'', L'', L'', L'', L''}},
{L'Y', {L'Ý', L'', L'', L'', L''}},
};
static int tonetab[128] = {
['s'] = 1, ['f'] = 2, ['r'] = 3, ['x'] = 4, ['j'] = 5,
};
#define Istone(c) ((c) < 128 && tonetab[(c)] > 0)
#define Toneidx(c) (tonetab[(c)] - 1)
static int
isvowel(Rune c)
{
int i;
for(i = 0; i < nelem(vitone); i++)
if(vitone[i].base == c)
return 1;
return 0;
}
static Rune
removetone(Rune c)
{
int i, j;
for(i = 0; i < nelem(vitone); i++){
if(vitone[i].base == c)
return c;
for(j = 0; j < 5; j++)
if(vitone[i].tone[j] == c)
return vitone[i].base;
}
return c;
}
static Rune
applytone(Rune c, int tidx)
{
int i;
Rune base;
base = removetone(c);
for(i = 0; i < nelem(vitone); i++)
if(vitone[i].base == base)
return vitone[i].tone[tidx];
return c;
}
Emit
transvi(Im *im, Rune c)
{
Emit e;
Str mapped, pre;
int i, tidx, vi, last, penult;
Rune v, b1, b2;
if(!Istone(c) && c != 'z')
return transmap(im, c);
memset(&e, 0, sizeof e);
if(im->pre.n == 0){
sputr(&e.s, c);
return e;
}
if(im->pre.r[im->pre.n - 1] == '\\'){
pre = im->pre;
pre.n--;
if(!mapget(im->l->map, &pre, &mapped))
mapped = pre;
sputr(&mapped, c);
e.eat = 1;
e.s = mapped;
return e;
}
if(!mapget(im->l->map, &im->pre, &mapped))
mapped = im->pre;
last = -1;
penult = -1;
for(i = 0; i < mapped.n; i++){
v = removetone(mapped.r[i]);
if(isvowel(v)){
penult = last;
last = i;
}
}
vi = -1;
if(last >= 0){
if(last < mapped.n - 1 || penult < 0)
vi = last;
else{
b1 = removetone(mapped.r[penult]);
b2 = removetone(mapped.r[last]);
if((b1 == 'o' || b1 == 'O') && (b2 == 'a' || b2 == 'A' || b2 == 'e' || b2 == 'E'))
vi = last;
else if((b1 == 'u' || b1 == 'U') && (b2 == 'y' || b2 == 'Y'))
vi = last;
else
vi = penult;
}
}
if(vi < 0){
e.eat = 1;
e.s = mapped;
sputr(&e.s, c);
return e;
}
if(c == 'z')
mapped.r[vi] = removetone(mapped.r[vi]);
else{
tidx = Toneidx(c);
mapped.r[vi] = applytone(mapped.r[vi], tidx);
}
e.eat = 1;
e.next = mapped;
return e;
}