NetBSD/gnu/usr.bin/groff/libXdvi/parse.c

420 lines
8.9 KiB
C

/*
* parse.c
*
* parse dvi input
*/
#include <X11/Xos.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <ctype.h>
#include "DviP.h"
static int StopSeen = 0;
static ParseDrawFunction(), ParseDeviceControl();
static push_env(), pop_env();
#define HorizontalMove(dw, delta) ((dw)->dvi.state->x += (delta))
#define charWidth(fi,c) (\
(fi)->per_char ?\
(fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
:\
(fi)->max_bounds.width\
)
int charExists (fi, c)
XFontStruct *fi;
int c;
{
XCharStruct *p;
if (c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2)
return 0;
p = fi->per_char + (c - fi->min_char_or_byte2);
return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
|| p->ascent != 0 || p->descent != 0 || p->attributes != 0);
}
ParseInput(dw)
register DviWidget dw;
{
int n, k;
int c;
char Buffer[BUFSIZ];
int NextPage;
int prevFont;
int otherc;
StopSeen = 0;
/*
* make sure some state exists
*/
if (!dw->dvi.state)
push_env (dw);
for (;;) {
switch (DviGetC(dw, &c)) {
case '\n':
break;
case ' ': /* when input is text */
case 0: /* occasional noise creeps in */
break;
case '{': /* push down current environment */
push_env(dw);
break;
case '}':
pop_env(dw);
break;
/*
* two motion digits plus a character
*/
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
HorizontalMove(dw, (c-'0')*10 +
DviGetC(dw,&otherc)-'0');
/* fall through */
case 'c': /* single ascii character */
DviGetC(dw,&c);
if (c == ' ')
break;
Buffer[0] = c;
Buffer[1] = '\0';
goto FunnyCharacter;
case 'C':
GetWord(dw, Buffer, BUFSIZ);
FunnyCharacter:
prevFont = -1;
c = -1;
{
DviCharNameMap *map;
int i;
map = QueryFontMap (dw, dw->dvi.state->font_number);
if (map) {
c = DviCharIndex (map, Buffer);
if (c == -1) {
for (i = 1; map = QueryFontMap (dw, i); i++)
if (map->special)
if ((c = DviCharIndex (map, Buffer)) != -1) {
prevFont = dw->dvi.state->font_number;
dw->dvi.state->font_number = i;
break;
}
}
}
}
if (c == -1)
break;
NumberedCharacter:
/*
* quick and dirty extents calculation:
*/
if (dw->dvi.state->y + 24 >= dw->dvi.extents.y1 &&
dw->dvi.state->y - 24 <= dw->dvi.extents.y2 &&
dw->dvi.state->x + 24 >= dw->dvi.extents.x1 &&
dw->dvi.state->x - 24 <= dw->dvi.extents.x2)
{
register XFontStruct *font;
register XTextItem *text;
if (!dw->dvi.display_enable)
break;
if (dw->dvi.state->y != dw->dvi.cache.y ||
dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE)
FlushCharCache (dw);
/*
* load a new font, if the current block is not empty,
* step to the next.
*/
if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
dw->dvi.cache.font_number != dw->dvi.state->font_number)
{
dw->dvi.cache.font_size = dw->dvi.state->font_size;
dw->dvi.cache.font_number = dw->dvi.state->font_number;
dw->dvi.cache.font = QueryFont (dw,
dw->dvi.cache.font_number,
dw->dvi.cache.font_size);
if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
++dw->dvi.cache.index;
if (dw->dvi.cache.index >= dw->dvi.cache.max)
FlushCharCache (dw);
dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
}
}
if (dw->dvi.cache.x != dw->dvi.state->x) {
if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
++dw->dvi.cache.index;
if (dw->dvi.cache.index >= dw->dvi.cache.max)
FlushCharCache (dw);
dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
}
}
font = dw->dvi.cache.font;
text = &dw->dvi.cache.cache[dw->dvi.cache.index];
if (text->nchars == 0) {
text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
text->delta = dw->dvi.state->x - dw->dvi.cache.x;
if (font != dw->dvi.font) {
text->font = font->fid;
dw->dvi.font = font;
} else
text->font = None;
dw->dvi.cache.x += text->delta;
}
if (charExists(font, c)) {
dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
++text->nchars;
dw->dvi.cache.x += charWidth(font,c);
}
}
if (prevFont != -1)
dw->dvi.state->font_number = prevFont;
break;
case 'D': /* draw function */
GetLine(dw, Buffer, BUFSIZ);
if (dw->dvi.display_enable)
ParseDrawFunction(dw, Buffer);
break;
case 's': /* ignore fractional sizes */
n = GetNumber(dw);
dw->dvi.state->font_size = n;
break;
case 'f':
n = GetNumber(dw);
dw->dvi.state->font_number = n;
break;
case 'H': /* absolute horizontal motion */
k = GetNumber(dw);
HorizontalGoto(dw, k);
break;
case 'h': /* relative horizontal motion */
k = GetNumber(dw);
HorizontalMove(dw, k);
break;
case 'w': /* word space */
break;
case 'V':
n = GetNumber(dw);
VerticalGoto(dw, n);
break;
case 'v':
n = GetNumber(dw);
VerticalMove(dw, n);
break;
case 'P': /* new spread */
break;
case 'p': /* new page */
(void) GetNumber(dw);
NextPage = dw->dvi.current_page + 1;
RememberPagePosition(dw, NextPage);
FlushCharCache (dw);
return(NextPage);
case 'N':
c = GetNumber(dw);
goto NumberedCharacter;
case 'n': /* end of line */
GetNumber(dw);
GetNumber(dw);
HorizontalGoto(dw, 0);
break;
case '+': /* continuation of X device control */
case '#': /* comment */
GetLine(dw, NULL, 0);
break;
case 'x': /* device control */
ParseDeviceControl(dw);
break;
case EOF:
dw->dvi.last_page = dw->dvi.current_page;
FlushCharCache (dw);
return dw->dvi.current_page;
default:
break;
}
}
}
static
push_env(dw)
DviWidget dw;
{
DviState *new;
new = (DviState *) malloc (sizeof (*new));
if (dw->dvi.state)
*new = *(dw->dvi.state);
else {
new->font_size = 10;
new->font_number = 1;
new->x = 0;
new->y = 0;
}
new->next = dw->dvi.state;
dw->dvi.state = new;
}
static
pop_env(dw)
DviWidget dw;
{
DviState *old;
old = dw->dvi.state;
dw->dvi.state = old->next;
free ((char *) old);
}
static
InitTypesetter (dw)
DviWidget dw;
{
while (dw->dvi.state)
pop_env (dw);
push_env (dw);
FlushCharCache (dw);
}
#define DRAW_ARGS_MAX 128
static
ParseDrawFunction(dw, buf)
DviWidget dw;
char *buf;
{
int v[DRAW_ARGS_MAX];
int i;
char *ptr;
v[0] = v[1] = v[2] = v[3] = 0;
if (buf[0] == '\0')
return;
ptr = buf+1;
for (i = 0; i < DRAW_ARGS_MAX; i++) {
if (sscanf(ptr, "%d", v + i) != 1)
break;
while (*ptr == ' ')
ptr++;
while (*ptr != '\0' && *ptr != ' ')
ptr++;
}
switch (buf[0]) {
case 'l': /* draw a line */
DrawLine(dw, v[0], v[1]);
break;
case 'c': /* circle */
DrawCircle(dw, v[0]);
break;
case 'C':
DrawFilledCircle(dw, v[0]);
break;
case 'e': /* ellipse */
DrawEllipse(dw, v[0], v[1]);
break;
case 'E':
DrawFilledEllipse(dw, v[0], v[1]);
break;
case 'a': /* arc */
DrawArc(dw, v[0], v[1], v[2], v[3]);
break;
case 'p':
DrawPolygon(dw, v, i);
break;
case 'P':
DrawFilledPolygon(dw, v, i);
break;
case '~': /* wiggly line */
DrawSpline(dw, v, i);
break;
case 't':
dw->dvi.line_thickness = v[0];
break;
case 'f':
if (i > 0 && v[0] >= 0 && v[0] <= DVI_FILL_MAX)
dw->dvi.fill = v[0];
break;
default:
#if 0
warning("unknown drawing function %s", buf);
#endif
break;
}
if (buf[0] == 'e') {
if (i > 0)
dw->dvi.state->x += v[0];
}
else {
while (--i >= 0) {
if (i & 1)
dw->dvi.state->y += v[i];
else
dw->dvi.state->x += v[i];
}
}
}
static
ParseDeviceControl(dw) /* Parse the x commands */
DviWidget dw;
{
char str[20], str1[50], buf[50];
int c, n;
extern int LastPage, CurrentPage;
GetWord (dw, str, 20);
switch (str[0]) { /* crude for now */
case 'T': /* output device */
GetWord(dw, str, 20);
break;
case 'i': /* initialize */
InitTypesetter (dw);
break;
case 't': /* trailer */
break;
case 'p': /* pause -- can restart */
break;
case 's': /* stop */
StopSeen = 1;
return;
case 'r': /* resolution when prepared */
SetDeviceResolution (dw, GetNumber (dw));
break;
case 'f': /* font used */
n = GetNumber(dw);
GetWord(dw, str, 20);
GetLine(dw, str1, 50);
SetFontPosition(dw, n, str, str1);
break;
case 'H': /* char height */
break;
case 'S': /* slant */
break;
}
while (DviGetC(dw,&c) != '\n') /* skip rest of input line */
if (c == EOF)
return;
return;
}
/*
Local Variables:
c-indent-level: 8
c-continued-statement-offset: 8
c-brace-offset: -8
c-argdecl-indent: 8
c-label-offset: -8
c-tab-always-indent: nil
End:
*/