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