#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include "ttf2tfm.h"
#include "ligkern.h"
#include "ttfenc.h"
#include "texenc.h"
#include "newobj.h"
#include "errormsg.h"
static char *
paramstring(char **curp)
{
register char *p, *q;
p = *curp;
while (*p && !isspace(*p))
p++;
q = *curp;
if (*p != '\0')
*p++ = '\0';
while (isspace(*p))
p++;
*curp = p;
return q;
}
static kern *
rmkernmatch(kern *k,
char *s)
{
kern *nk;
while (k && strcmp(k->succ, s) == 0)
k = k->next;
if (k)
{
for (nk = k; nk; nk = nk->next)
while (nk->next && strcmp(nk->next->succ, s) == 0)
nk->next = nk->next->next;
}
return k;
}
static void
rmkern(char *s1, char *s2,
ttfinfo *ti,
Font *fnt)
{
if (ti == NULL)
{
if (strcmp(s1, "*") == 0)
{
for (ti = fnt->charlist; ti; ti = ti->next)
rmkern(s1, s2, ti, fnt);
return;
}
else
{
ti = findadobe(s1, fnt->charlist);
if (ti == NULL)
return;
}
}
if (strcmp(s2, "*") == 0)
ti->kerns = NULL;
else
ti->kerns = rmkernmatch(ti->kerns, s2);
}
static void
addkern(char *s1, char *s2,
Font *fnt)
{
ttfinfo *ti1 = findadobe(s1, fnt->charlist);
ttfinfo *ti2 = findadobe(s2, fnt->charlist);
if (ti1 && ti2 && !ti1->kerns)
{
ttfptr *ap = (ttfptr *)mymalloc(sizeof (ttfptr));
ap->next = ti2->kern_equivs;
ap->ch = ti1;
ti2->kern_equivs = ap;
}
}
void
checkligkern(char *s, Font *fnt)
{
char *mlist[5];
char *os;
char *orig_s, *pos;
size_t offset[5];
int n;
os = newstring(s);
orig_s = s;
s++;
while (isspace(*s))
s++;
if (strncmp(s, "LIGKERN", 7) == 0)
{
fnt->sawligkern = True;
s += 7;
while (isspace(*s))
s++;
pos = s;
while (*pos)
{
for (n = 0; n < 5;)
{
if (*pos == '\0')
break;
offset[n] = pos - orig_s;
mlist[n] = paramstring(&pos);
if (strcmp(mlist[n], ";") == 0)
break;
n++;
}
if (n > 4)
boops(os, pos - orig_s, "Too many parameters in lig kern data.");
if (n < 3)
boops(os, pos - orig_s, "Too few parameters in lig kern data.");
if (n == 3 && strcmp(mlist[1], "{}") == 0)
rmkern(mlist[0], mlist[2], (ttfinfo *)0, fnt);
else if (n == 3 && strcmp(mlist[1], "<>") == 0)
addkern(mlist[0], mlist[2], fnt);
else if (n == 3 && strcmp(mlist[0], "||") == 0 &&
strcmp(mlist[1], "=") == 0)
{
ttfinfo *ti = findadobe("||", fnt->charlist);
if (fnt->boundarychar != -1)
boops(os, offset[0], "Multiple boundary character commands?");
if (sscanf(mlist[2], "%d", &n) != 1)
boops(os, offset[2],
"Expected number assignment for boundary char.");
if (n < 0 || n > 0xFF)
boops(os, offset[2], "Boundary character number must be 0..0xFF.");
fnt->boundarychar = n;
if (ti == NULL)
oops("Internal error: boundary char.");
ti->outcode = n;
}
else if (n == 4)
{
int op = -1;
ttfinfo *ti;
for (n = 0; encligops[n]; n++)
if (strcmp(mlist[2], encligops[n]) == 0)
{
op = n;
break;
}
if (op < 0)
boops(os, offset[2], "Bad ligature op specified.");
if (NULL != (ti = findadobe(mlist[0], fnt->charlist)))
{
lig *lig;
if (findadobe(mlist[2], fnt->charlist))
rmkern(mlist[0], mlist[1], ti, fnt);
if (strcmp(mlist[3], "||") == 0)
boops(os, offset[3], "You can't lig to the boundary character!");
if (!fnt->fixedpitch)
{
for (lig = ti->ligs; lig; lig = lig->next)
if (strcmp(lig->succ, mlist[1]) == 0)
break;
if (lig == NULL)
{
lig = newlig();
lig->succ = newstring(mlist[1]);
lig->next = ti->ligs;
ti->ligs = lig;
}
lig->sub = newstring(mlist[3]);
lig->op = op;
if (strcmp(mlist[1], "||") == 0)
{
lig->boundleft = 1;
if (strcmp(mlist[0], "||") == 0)
boops(os, offset[0],
"You can't lig boundarychar boundarychar!");
}
else
lig->boundleft = 0;
}
}
}
else
boops(os, offset[0], "Bad form in LIGKERN command.");
}
}
free(os);
}
void
getligkerndefaults(Font *fnt)
{
int i;
char *buffer;
for (i = 0; staticligkern[i]; i++)
{
buffer = newstring(staticligkern[i]);
checkligkern(buffer, fnt);
free(buffer);
}
}