e16/dox/format.c

897 lines
19 KiB
C
Raw Normal View History

#include "dox.h"
static int num_pages = 0;
static Page *page = NULL;
static char *fdat_ptr = NULL;
static int fdat_size = 0;
static char *fdat = NULL;
static int fdgetc(void);
static void fdjump(int count);
static int
fdgetc(void)
{
int val;
if (fdat_ptr >= (fdat + fdat_size))
return EOF;
val = (int)(*fdat_ptr);
fdat_ptr++;
return val;
}
static void
fdjump(int count)
{
fdat_ptr += count;
if (fdat_ptr < fdat)
fdat_ptr = fdat;
if (fdat_ptr >= (fdat + fdat_size))
fdat_ptr = (fdat + fdat_size) - 1;
}
void
AddPage(Object * obj)
{
num_pages++;
page = realloc(page, sizeof(Page) * (num_pages));
page[num_pages - 1].name = NULL;
page[num_pages - 1].count = 0;
page[num_pages - 1].obj = NULL;
page[num_pages - 1].columns = 1;
page[num_pages - 1].background = NULL;
page[num_pages - 1].padding = 2;
page[num_pages - 1].linkr = DEFAULT_LINKCOLOR_R;
page[num_pages - 1].linkg = DEFAULT_LINKCOLOR_G;
page[num_pages - 1].linkb = DEFAULT_LINKCOLOR_B;
if ((obj) && (obj->type == PAGE))
{
Page *pg;
pg = (Page *) (obj->object);
if (pg->name)
page[num_pages - 1].name = pg->name;
page[num_pages - 1].columns = pg->columns;
page[num_pages - 1].padding = pg->padding;
page[num_pages - 1].linkr = pg->linkr;
page[num_pages - 1].linkg = pg->linkg;
page[num_pages - 1].linkb = pg->linkb;
if (pg->background)
page[num_pages - 1].background = pg->background;
}
}
void
AddObject(Object * obj)
{
page[num_pages - 1].count++;
page[num_pages - 1].obj =
realloc(page[num_pages - 1].obj,
sizeof(Object) * (page[num_pages - 1].count));
page[num_pages - 1].obj[page[num_pages - 1].count - 1].type =
obj->type;
page[num_pages - 1].obj[page[num_pages - 1].count - 1].object =
obj->object;
}
void
BuildObj(Object * obj, char *var, char *param)
{
static Page *pg = NULL;
static P_ *p = NULL;
static Font_ *fn = NULL;
static Img_ *img = NULL;
switch (obj->type)
{
case IMG:
if (!obj->object)
{
img = obj->object = malloc(sizeof(Img_));
img->src = NULL;
img->src2 = NULL;
img->src3 = NULL;
img->x = 0;
img->y = 0;
img->link = NULL;
img->w = 0;
img->h = 0;
}
if (!strcmp(var, "x"))
img->x = atoi(param);
else if (!strcmp(var, "y"))
img->y = atoi(param);
else if (!strcmp(var, "src"))
img->src = strdup(param);
else if (!strcmp(var, "src2"))
img->src2 = strdup(param);
else if (!strcmp(var, "src3"))
img->src3 = strdup(param);
else if (!strcmp(var, "href"))
img->link = strdup(param);
break;
case BR:
break;
case FONT:
if (!obj->object)
{
fn = obj->object = malloc(sizeof(Font_));
fn->face = NULL;
fn->r = 0;
fn->g = 0;
fn->b = 0;
}
if (!strcmp(var, "face"))
fn->face = strdup(param);
else if (!strcmp(var, "color"))
{
char hex[3] = "00";
if (param[0] == '#')
{
hex[0] = param[1];
hex[1] = param[2];
sscanf(hex, "%x", &(fn->r));
hex[0] = param[3];
hex[1] = param[4];
sscanf(hex, "%x", &(fn->g));
hex[0] = param[5];
hex[1] = param[6];
sscanf(hex, "%x", &(fn->b));
}
}
break;
case P:
if (!obj->object)
{
p = obj->object = malloc(sizeof(P_));
p->align = 0;
}
if (!strcmp(var, "align"))
{
if ((strlen(param) > 0) && (param[strlen(param) - 1] == '%'))
param[strlen(param) - 1] = 0;
p->align = atof(param);
}
break;
case TEXT:
break;
case PAGE:
if (!obj->object)
{
pg = obj->object = malloc(sizeof(Page));
pg->columns = 1;
pg->padding = 1;
pg->name = NULL;
pg->background = NULL;
pg->linkr = DEFAULT_LINKCOLOR_R;
pg->linkg = DEFAULT_LINKCOLOR_G;
pg->linkb = DEFAULT_LINKCOLOR_B;
}
if (!strcmp(var, "columns"))
pg->columns = atoi(param);
else if (!strcmp(var, "padding"))
pg->padding = atoi(param);
else if (!strcmp(var, "name"))
pg->name = strdup(param);
else if (!strcmp(var, "background"))
pg->background = strdup(param);
else if (!strcmp(var, "linkcolor"))
{
char hex[3] = "00";
if (param[0] == '#')
{
hex[0] = param[1];
hex[1] = param[2];
sscanf(hex, "%x", &(pg->linkr));
hex[0] = param[3];
hex[1] = param[4];
sscanf(hex, "%x", &(pg->linkg));
hex[0] = param[5];
hex[1] = param[6];
sscanf(hex, "%x", &(pg->linkb));
}
}
break;
default:
break;
}
}
int
GetNextTag(Object * obj)
{
char s[65536];
int i = 0, wd = 0;
int val;
char intag = 0;
char havobj = 0;
for (;;)
{
val = fdgetc();
if (val == EOF)
return 0;
if (intag)
{
if (val == '>')
intag = 0;
s[i++] = (char)val;
if (s[i - 1] == '\n')
s[i - 1] = ' ';
if (s[i - 1] == '>')
s[i - 1] = ' ';
if (s[i - 1] == ' ')
{
if (i == 1)
i = 0;
else
{
s[i - 1] = 0;
if (!havobj)
{
if (wd == 0)
{
if (!strcmp(s, "page"))
obj->type = PAGE;
else if (!strcmp(s, "img"))
obj->type = IMG;
else if (!strcmp(s, "br"))
obj->type = BR;
else if (!strcmp(s, "font"))
obj->type = FONT;
else if (!strcmp(s, "p"))
obj->type = P;
havobj = 1;
}
i = 0;
}
else
{
char w1[1024];
char w2[1024];
int j = 0;
w1[0] = 0;
w2[0] = 0;
while ((s[j]) && (s[j] != '='))
{
w1[j] = s[j];
j++;
}
w1[j] = 0;
if (j < (int)strlen(s))
strcpy(w2, &(s[j + 1]));
BuildObj(obj, w1, w2);
i = 0;
}
wd++;
}
}
if (!intag)
return 1;
}
if (val == '<')
intag = 1;
}
return 1;
}
char *
GetTextUntilTag(void)
{
char s[65536];
int i = 0;
int val;
for (;;)
{
val = fdgetc();
if (val == EOF)
{
s[i] = 0;
if (strlen(s) < 1)
return NULL;
return strdup(s);
}
s[i++] = (char)val;
if (s[i - 1] == '\n')
s[i - 1] = ' ';
if ((i == 1) && (s[0] == ' '))
i--;
else if (s[i - 1] == '<')
{
s[i - 1] = 0;
fdjump(-1);
if (strlen(s) < 1)
return NULL;
return strdup(s);
}
if ((i > 2) && (s[i - 2] == ' ') && (s[i - 1] == ' '))
i--;
if (i > 65530)
return NULL;
}
return NULL;
}
int
GetObjects(FILE * f)
{
static char have_font = 0;
static char in_para = 0;
Object obj;
char *txt;
char buf[4096];
int count;
fdat = NULL;
fdat_size = 0;
while ((count = fread(buf, 1, 4096, f)) > 0)
{
if (!fdat)
fdat = malloc(count);
else
fdat = realloc(fdat, (fdat_size + count));
memcpy(fdat + fdat_size, buf, count);
fdat_size += count;
}
fdat_ptr = fdat;
if (page)
{
int i;
for (i = 0; i < num_pages; i++)
{
int j;
if (page[i].name)
free(page[i].name);
if (page[i].background)
free(page[i].background);
for (j = 0; j < page[i].count; j++)
{
switch (page[i].obj[j].type)
{
case IMG:
if (((Img_ *)page[i].obj[j].object)->src)
free(((Img_ *)page[i].obj[j].object)->src);
if (((Img_ *)page[i].obj[j].object)->src2)
free(((Img_ *)page[i].obj[j].object)->src2);
if (((Img_ *)page[i].obj[j].object)->src3)
free(((Img_ *)page[i].obj[j].object)->src3);
if (((Img_ *)page[i].obj[j].object)->link)
free(((Img_ *)page[i].obj[j].object)->link);
break;
case BR:
break;
case FONT:
if (((Font_ *)page[i].obj[j].object)->face)
free(((Font_ *)page[i].obj[j].object)->face);
break;
case P:
break;
case TEXT:
break;
case PAGE:
break;
}
if (page[i].obj[j].object)
free(page[i].obj[j].object);
}
if (page[i].obj)
free(page[i].obj);
}
free(page);
num_pages = 0;
page = NULL;
have_font = 0;
in_para = 0;
}
obj.object = NULL;
for (;;)
{
if ((have_font) && (in_para))
{
txt = GetTextUntilTag();
if (txt)
{
obj.type = TEXT;
obj.object = (void *)txt;
}
else
{
if (!GetNextTag(&obj))
{
if (fdat)
free(fdat);
return 0;
}
}
}
else
{
if (!GetNextTag(&obj))
{
if (fdat)
free(fdat);
return 0;
}
}
if (obj.type == PAGE)
{
in_para = 0;
have_font = 0;
AddPage(&obj);
}
else if (page)
AddObject(&obj);
if (obj.type == IMG)
in_para = 0;
if (obj.type == P)
in_para = 1;
if (obj.type == FONT)
have_font = 1;
obj.object = NULL;
}
free(fdat);
}
int
FixPage(int p)
{
if (p < 0)
return 0;
if (p >= num_pages)
return num_pages - 1;
return p;
}
int
GetPage(char *name)
{
int i;
for (i = 0; i < num_pages; i++)
{
if ((page[i].name) && (!strcmp(name, page[i].name)))
return i;
}
return -1;
}
void
GetLinkColors(int page_num, int *r, int *g, int *b)
{
if (page_num < 0)
{
*r = DEFAULT_LINKCOLOR_R;
*g = DEFAULT_LINKCOLOR_G;
*b = DEFAULT_LINKCOLOR_B;
}
else
{
*r = page[page_num].linkr;
*g = page[page_num].linkg;
*b = page[page_num].linkb;
}
}
Link *
RenderPage(Window win, int page_num, int w, int h)
{
Link *ll = NULL;
Page *pg;
TextState ts;
int i, col_w, col_h;
int x, y;
int justification = 0;
int firstp = 1;
ImlibImage *im;
int wastext = 0;
ts.fontname = NULL;
ts.style.orientation = FONT_TO_RIGHT;
ts.style.mode = MODE_WRAP_WORD;
ts.style.justification = 0;
ts.style.spacing = 0;
ts.font = NULL;
ts.fg_col.r = 0;
ts.fg_col.g = 0;
ts.fg_col.b = 0;
ts.bg_col.r = 0;
ts.bg_col.g = 0;
ts.bg_col.b = 0;
ts.effect = 0;
ts.efont = NULL;
ts.xfont = NULL;
ts.xfontset = 0;
ts.xfontset_ascent = 0;
ts.height = 0;
pg = &(page[page_num]);
x = pg->padding;
y = pg->padding;
col_w = ((w - (pg->padding * (pg->columns + 1))) / pg->columns);
col_h = h - (pg->padding * 2);
if (pg->background)
{
char tmp[4096];
sprintf(tmp, "%s/%s", docdir, pg->background);
im = Imlib_load_image(id, tmp);
if (im)
{
Imlib_paste_image(id, im, win, 0, 0, w, h);
Imlib_destroy_image(id, im);
}
}
for (i = 0; i < pg->count; i++)
{
char s[32768], ss[32768], wd[4096], *txt;
Img_ *img;
Font_ *fn;
P_ *p;
int wc, eol, eot;
int link = -1, lx, lw;
switch (pg->obj[i].type)
{
case IMG:
img = pg->obj[i].object;
if (img->src)
{
char tmp[4096];
sprintf(tmp, "%s/%s", docdir, img->src);
im = Imlib_load_image(id, tmp);
if (im)
{
img->w = im->rgb_width;
img->h = im->rgb_height;
Imlib_paste_image(id, im, win, img->x, img->y,
im->rgb_width, im->rgb_height);
Imlib_destroy_image(id, im);
}
if (img->link)
{
Link *l;
l = malloc(sizeof(Link));
l->name = strdup(img->link);
l->x = img->x;
l->y = img->y;
l->w = img->w;
l->h = img->h;
l->next = ll;
ll = l;
}
}
break;
case BR:
if (!wastext)
y += ts.height;
wastext = 0;
break;
case FONT:
fn = pg->obj[i].object;
ts.fontname = NULL;
ts.style.orientation = FONT_TO_RIGHT;
ts.style.mode = MODE_WRAP_WORD;
ts.style.justification = 0;
ts.style.spacing = 0;
if (ts.font)
Fnlib_free_font(fd, ts.font);
ts.font = NULL;
ts.fg_col.r = 0;
ts.fg_col.g = 0;
ts.fg_col.b = 0;
ts.bg_col.r = 0;
ts.bg_col.g = 0;
ts.bg_col.b = 0;
ts.effect = 0;
if (ts.efont)
Efont_free(ts.efont);
ts.efont = NULL;
if (ts.xfont)
XFreeFont(disp, ts.xfont);
ts.xfont = NULL;
if (ts.xfontset)
XFreeFontSet(disp, ts.xfontset);
ts.xfontset = NULL;
ts.xfontset_ascent = 0;
ts.height = 0;
ts.fontname = fn->face;
ts.fg_col.r = fn->r;
ts.fg_col.g = fn->g;
ts.fg_col.b = fn->b;
TextStateLoadFont(&ts);
break;
case P:
p = pg->obj[i].object;
if (p)
justification = (int)((p->align / 100) * 1024);
else
justification = 0;
if (!firstp)
y += ts.height;
else
firstp = 0;
break;
case TEXT:
txt = pg->obj[i].object;
wc = 1;
ss[0] = 0;
s[0] = 0;
eol = 0;
eot = 0;
for (;;)
{
char *txt_disp;
int tw, th, xspace;
int off, j;
int sx, sy, ssx, ssy;
char link_txt[1024];
char link_link[1024];
wd[0] = 0;
word(txt, wc, wd);
if (!wd[0])
eol = 1;
else
{
if (wd[0] == '_')
{
link = strlen(s);
for (j = 1; wd[j] != '('; j++)
wd[j - 1] = wd[j];
wd[j - 1] = 0;
j++;
strcpy(link_link, &(wd[j]));
link_link[strlen(link_link) - 1] = 0;
strcpy(link_txt, wd);
TextSize(&ts, link_txt, &lw, &th, 17);
TextSize(&ts, s, &lx, &th, 17);
}
}
wc++;
eot++;
strcpy(ss, s);
strcat(s, wd);
if (!eol)
strcat(s, " ");
xspace = col_w;
off = 0;
sx = x + off;
sy = y;
ssx = sx + col_w - 1;
ssy = sy + ts.height - 1;
for (j = 0; j < pg->count; j++)
{
if (pg->obj[j].type == IMG)
{
img = pg->obj[j].object;
if ((img->w > 0) && (img->h > 0))
{
int ix, iy, iix, iiy;
ix = img->x;
iy = img->y;
iix = img->x + img->w - 1;
iiy = img->y + img->h - 1;
if ((iy <= ssy) && (iiy >= sy))
{
if ((ix >= sx) && (ix <= ssx))
{
if ((iix >= sx) && (iix <= ssx))
{
if (((ix + iix) / 2) > ((sx + ssx) / 2))
ssx = ix - 1;
else
sx = iix + 1;
}
else
{
ssx = ix - 1;
}
}
else if ((iix >= sx) && (iix <= ssx))
{
sx = iix + 1;
}
}
}
}
}
off = sx - x;
xspace = (ssx - sx) + 1;
if (xspace < 0)
xspace = 0;
TextSize(&ts, s, &tw, &th, 17);
txt_disp = ss;
if (eot == 1)
txt_disp = s;
if (((tw > xspace) || (eol)) && (strlen(txt_disp) > 0))
{
txt_disp[strlen(txt_disp) - 1] = 0;
if ((eot == 1) && (tw > xspace))
{
char p1[4096];
int point = 0, cnt = 0;
while (txt_disp[(point + cnt)])
{
p1[cnt] = txt_disp[point + cnt];
cnt++;
p1[cnt] = 0;
TextSize(&ts, p1, &tw, &th, 17);
if ((tw > xspace) || (!txt_disp[(point + cnt)]))
{
if (txt_disp[(point + cnt)])
{
point = point + cnt - 1;
p1[cnt - 1] = 0;
cnt = 0;
}
else
{
point = point + cnt;
p1[cnt] = 0;
cnt = 0;
}
wastext = 1;
TextDraw(&ts, win, p1, x + off, y,
xspace, 99999, 17, justification);
y += ts.height;
if (y >= (h - (pg->padding + ts.height - (ts.height - ts.xfontset_ascent))))
{
y = pg->padding;
x += col_w + pg->padding;
}
xspace = col_w;
off = 0;
sx = x + off;
sy = y;
ssx = sx + col_w - 1;
ssy = sy + ts.height - 1;
for (j = 0; j < pg->count; j++)
{
if (pg->obj[j].type == IMG)
{
img = pg->obj[j].object;
if ((img->w > 0) && (img->h > 0))
{
int ix,
iy,
iix,
iiy;
ix = img->x;
iy = img->y;
iix = img->x + img->w - 1;
iiy = img->y + img->h - 1;
if ((iy <= ssy) && (iiy >= sy))
{
if ((ix >= sx) && (ix <= ssx))
{
if ((iix >= sx) && (iix <= ssx))
{
if (((ix + iix) / 2) > ((sx + ssx) / 2))
ssx = ix - 1;
else
sx = iix + 1;
}
else
{
ssx = ix - 1;
}
}
else if ((iix >= sx) && (iix <= ssx))
{
sx = iix + 1;
}
}
}
}
}
off = sx - x;
xspace = (ssx - sx) + 1;
if (xspace < 0)
xspace = 0;
}
}
}
else
{
if ((tw > xspace) && (eot != 1))
wc--;
wastext = 1;
TextDraw(&ts, win, txt_disp, x + off, y,
xspace, 99999, 17, justification);
if (link >= 0)
{
int rr, gg, bb;
int r, g, b;
int extra;
GC gc;
XGCValues gcv;
gc = XCreateGC(disp, win, 0, &gcv);
rr = ts.fg_col.r;
gg = ts.fg_col.g;
bb = ts.fg_col.b;
r = ts.fg_col.r = pg->linkr;
g = ts.fg_col.g = pg->linkg;
b = ts.fg_col.b = pg->linkb;
XSetForeground(disp, gc,
Imlib_best_color_match(id, &r, &g, &b));
TextSize(&ts, txt_disp, &tw, &th, 17);
extra = ((xspace - tw) * justification) >> 10;
TextDraw(&ts, win, link_txt, x + off + lx + extra, y,
99999, 99999, 17, 0);
XDrawLine(disp, win, gc,
x + off + lx + extra,
y + ts.xfontset_ascent,
x + off + lx + lw + extra,
y + ts.xfontset_ascent);
ts.fg_col.r = rr;
ts.fg_col.g = gg;
ts.fg_col.b = bb;
link = -1;
XFreeGC(disp, gc);
{
Link *l;
l = malloc(sizeof(Link));
l->name = strdup(link_link);
l->x = x + off + lx + extra;
l->y = y;
l->w = lw;
l->h = ts.height;
l->next = ll;
ll = l;
}
}
y += ts.height;
if (y >= (h - (pg->padding + ts.height - (ts.height - ts.xfontset_ascent))))
{
y = pg->padding;
x += col_w + pg->padding;
}
}
eot = 0;
s[0] = 0;
}
if (eol)
break;
}
break;
default:
break;
}
if (y >= (h - (pg->padding + ts.height - (ts.height - ts.xfontset_ascent))))
{
y = pg->padding;
x += col_w + pg->padding;
}
}
if (ts.font)
Fnlib_free_font(fd, ts.font);
if (ts.efont)
Efont_free(ts.efont);
if (ts.xfont)
XFreeFont(disp, ts.xfont);
if (ts.xfontset)
XFreeFontSet(disp, ts.xfontset);
return ll;
}