1/*	$NetBSD$	*/
2
3/*
4 * parse.c
5 *
6 * parse dvi input
7 */
8
9#include <X11/Xos.h>
10#include <X11/IntrinsicP.h>
11#include <X11/StringDefs.h>
12#include <stdio.h>
13#include <ctype.h>
14#include "DviP.h"
15
16static int StopSeen = 0;
17static void ParseDrawFunction(DviWidget, char *);
18static void ParseDeviceControl(DviWidget);
19static void push_env(DviWidget);
20static void pop_env(DviWidget);
21
22/* draw.c */
23extern int PutCharacter(DviWidget, char *);
24extern int PutNumberedCharacter(DviWidget, int);
25extern void HorizontalGoto(DviWidget, int);
26extern void Word(DviWidget);
27extern void VerticalGoto(DviWidget, int);
28extern void VerticalMove(DviWidget, int);
29extern void FlushCharCache(DviWidget);
30extern void Newline(DviWidget);
31extern void DrawLine(DviWidget, int, int);
32extern void DrawCircle(DviWidget, int);
33extern void DrawFilledCircle(DviWidget, int);
34extern void DrawEllipse(DviWidget, int, int);
35extern void DrawFilledEllipse(DviWidget, int, int);
36extern void DrawArc(DviWidget, int, int, int, int);
37extern void DrawPolygon(DviWidget, int *, int);
38extern void DrawFilledPolygon(DviWidget, int *, int);
39extern void DrawSpline(DviWidget, int *, int);
40
41/* Dvi.c */
42extern void SetDevice(DviWidget, const char *);
43
44/* page.c */
45extern void RememberPagePosition(DviWidget, int);
46
47/* font.c */
48extern void SetFontPosition(DviWidget, int, const char *, const char *);
49
50/* lex.c */
51extern int GetNumber(DviWidget);
52
53#define HorizontalMove(dw, delta)	((dw)->dvi.state->x += (delta))
54
55
56int
57ParseInput(register DviWidget dw)
58{
59	int		n, k;
60	int		c;
61	char		Buffer[BUFSIZ];
62	int		NextPage;
63	int		otherc;
64
65	StopSeen = 0;
66
67	/*
68	 * make sure some state exists
69	 */
70
71	if (!dw->dvi.state)
72	    push_env (dw);
73	for (;;) {
74		switch (DviGetC(dw, &c)) {
75		case '\n':
76			break;
77		case ' ':	/* when input is text */
78		case 0:		/* occasional noise creeps in */
79			break;
80		case '{':	/* push down current environment */
81			push_env(dw);
82			break;
83		case '}':
84			pop_env(dw);
85			break;
86		/*
87		 * two motion digits plus a character
88		 */
89		case '0': case '1': case '2': case '3': case '4':
90		case '5': case '6': case '7': case '8': case '9':
91			HorizontalMove(dw, (c-'0')*10 +
92					   DviGetC(dw,&otherc)-'0');
93			/* fall through */
94		case 'c':	/* single ascii character */
95			DviGetC(dw,&c);
96		    	if (c == ' ')
97			    break;
98			Buffer[0] = c;
99			Buffer[1] = '\0';
100			(void) PutCharacter (dw, Buffer);
101			break;
102		case 'C':
103			GetWord (dw, Buffer, BUFSIZ);
104			(void) PutCharacter (dw, Buffer);
105			break;
106		case 't':
107			Buffer[1] = '\0';
108			while (DviGetC (dw, &c) != EOF
109			       && c != ' ' && c != '\n') {
110				Buffer[0] = c;
111				HorizontalMove (dw, PutCharacter (dw, Buffer));
112			}
113			break;
114		case 'u':
115			n = GetNumber(dw);
116			Buffer[1] = '\0';
117			while (DviGetC (dw, &c) == ' ')
118				;
119			while (c != EOF && c != ' ' && c != '\n') {
120				Buffer[0] = c;
121				HorizontalMove (dw,
122						PutCharacter (dw, Buffer) + n);
123				DviGetC (dw, &c);
124			}
125			break;
126
127		case 'D':	/* draw function */
128			(void) GetLine(dw, Buffer, BUFSIZ);
129			if (dw->dvi.display_enable)
130				ParseDrawFunction(dw, Buffer);
131			break;
132		case 's':	/* ignore fractional sizes */
133			n = GetNumber(dw);
134			dw->dvi.state->font_size = n;
135			break;
136		case 'f':
137			n = GetNumber(dw);
138			dw->dvi.state->font_number = n;
139			break;
140		case 'H':	/* absolute horizontal motion */
141			k = GetNumber(dw);
142			HorizontalGoto(dw, k);
143			break;
144		case 'h':	/* relative horizontal motion */
145			k = GetNumber(dw);
146			HorizontalMove(dw, k);
147			break;
148		case 'w':	/* word space */
149			Word (dw);
150			break;
151		case 'V':
152			n = GetNumber(dw);
153			VerticalGoto(dw, n);
154			break;
155		case 'v':
156			n = GetNumber(dw);
157			VerticalMove(dw, n);
158			break;
159		case 'P':	/* new spread */
160			break;
161		case 'p':	/* new page */
162			(void) GetNumber(dw);
163			NextPage = dw->dvi.current_page + 1;
164			RememberPagePosition(dw, NextPage);
165			FlushCharCache (dw);
166			return(NextPage);
167		case 'N':
168			n = GetNumber(dw);
169			PutNumberedCharacter (dw, n);
170			break;
171		case 'n':	/* end of line */
172			GetNumber(dw);
173			GetNumber(dw);
174			Newline (dw);
175			HorizontalGoto(dw, 0);
176			break;
177		case 'F':       /* input files */
178		case '+':	/* continuation of X device control */
179		case 'm':	/* color */
180		case '#':	/* comment */
181			GetLine(dw, NULL, 0);
182			break;
183		case 'x':	/* device control */
184			ParseDeviceControl(dw);
185			break;
186		case EOF:
187			dw->dvi.last_page = dw->dvi.current_page;
188			FlushCharCache (dw);
189			return dw->dvi.current_page;
190		default:
191			break;
192		}
193	}
194}
195
196static void
197push_env(DviWidget dw)
198{
199	DviState	*new_state;
200
201	new_state = (DviState *) XtMalloc (sizeof (*new_state));
202	if (dw->dvi.state)
203		*new_state = *(dw->dvi.state);
204	else {
205		new_state->font_size = 10;
206		new_state->font_number = 1;
207		new_state->x = 0;
208		new_state->y = 0;
209	}
210	new_state->next = dw->dvi.state;
211	dw->dvi.state = new_state;
212}
213
214static void
215pop_env(DviWidget dw)
216{
217	DviState	*old;
218
219	old = dw->dvi.state;
220	dw->dvi.state = old->next;
221	XtFree ((char *) old);
222}
223
224static void
225InitTypesetter (DviWidget dw)
226{
227	while (dw->dvi.state)
228		pop_env (dw);
229	push_env (dw);
230	FlushCharCache (dw);
231}
232
233#define DRAW_ARGS_MAX 128
234
235static void
236ParseDrawFunction(DviWidget dw, char *buf)
237{
238	int v[DRAW_ARGS_MAX];
239	int i, no_move = 0;
240	char *ptr;
241
242	v[0] = v[1] = v[2] = v[3] = 0;
243
244	if (buf[0] == '\0')
245		return;
246	ptr = buf+1;
247
248	for (i = 0; i < DRAW_ARGS_MAX; i++) {
249		if (sscanf(ptr, "%d", v + i) != 1)
250			break;
251		while (*ptr == ' ')
252			ptr++;
253		while (*ptr != '\0' && *ptr != ' ')
254			ptr++;
255	}
256
257	switch (buf[0]) {
258	case 'l':				/* draw a line */
259		DrawLine(dw, v[0], v[1]);
260		break;
261	case 'c':				/* circle */
262		DrawCircle(dw, v[0]);
263		break;
264	case 'C':
265		DrawFilledCircle(dw, v[0]);
266		break;
267	case 'e':				/* ellipse */
268		DrawEllipse(dw, v[0], v[1]);
269		break;
270	case 'E':
271		DrawFilledEllipse(dw, v[0], v[1]);
272		break;
273	case 'a':				/* arc */
274		DrawArc(dw, v[0], v[1], v[2], v[3]);
275		break;
276	case 'p':
277		DrawPolygon(dw, v, i);
278		break;
279	case 'P':
280		DrawFilledPolygon(dw, v, i);
281		break;
282	case '~':				/* wiggly line */
283		DrawSpline(dw, v, i);
284		break;
285	case 't':
286		dw->dvi.line_thickness = v[0];
287		break;
288	case 'f':
289		if (i > 0 && v[0] >= 0 && v[0] <= DVI_FILL_MAX)
290			dw->dvi.fill = v[0];
291		no_move = 1;
292		break;
293	default:
294#if 0
295		warning("unknown drawing function %s", buf);
296#endif
297		no_move = 1;
298		break;
299	}
300
301	if (!no_move) {
302		if (buf[0] == 'e') {
303			if (i > 0)
304				dw->dvi.state->x += v[0];
305		}
306		else {
307			while (--i >= 0) {
308				if (i & 1)
309					dw->dvi.state->y += v[i];
310				else
311					dw->dvi.state->x += v[i];
312			}
313		}
314	}
315}
316
317static void
318ParseDeviceControl(DviWidget dw)		/* Parse the x commands */
319{
320        char str[20], str1[50];
321	int c, n;
322
323	GetWord (dw, str, 20);
324	switch (str[0]) {			/* crude for now */
325	case 'T':				/* output device */
326		GetWord (dw, str, 20);
327		SetDevice (dw, str);
328		break;
329	case 'i':				/* initialize */
330		InitTypesetter (dw);
331		break;
332	case 't':				/* trailer */
333		break;
334	case 'p':				/* pause -- can restart */
335		break;
336	case 's':				/* stop */
337		StopSeen = 1;
338		return;
339	case 'r':				/* resolution when prepared */
340		break;
341	case 'f':				/* font used */
342		n = GetNumber (dw);
343		GetWord (dw, str, 20);
344		GetLine (dw, str1, 50);
345		SetFontPosition (dw, n, str, str1);
346		break;
347	case 'H':				/* char height */
348		break;
349	case 'S':				/* slant */
350		break;
351	}
352	while (DviGetC (dw, &c) != '\n')	/* skip rest of input line */
353		if (c == EOF)
354			return;
355	return;
356}
357
358
359/*
360Local Variables:
361c-indent-level: 8
362c-continued-statement-offset: 8
363c-brace-offset: -8
364c-argdecl-indent: 8
365c-label-offset: -8
366c-tab-always-indent: nil
367End:
368*/
369