Net2/usr/src/usr.bin/groff/libXdvi/parse.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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:
*/