parse.c revision f80a6dcd
1/* $XConsortium: parse.c,v 1.13 94/04/17 20:43:36 keith Exp $ */
2/*
3
4Copyright (c) 1991  X Consortium
5
6Permission is hereby granted, free of charge, to any person obtaining
7a copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sublicense, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice shall be included
15in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
21OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of the X Consortium shall
26not be used in advertising or otherwise to promote the sale, use or
27other dealings in this Software without prior written authorization
28from the X Consortium.
29
30*/
31/* $XFree86: xc/programs/xditview/parse.c,v 1.5tsi Exp $ */
32
33/*
34 * parse.c
35 *
36 * parse dvi input
37 */
38
39#include <X11/Xos.h>
40#include <X11/IntrinsicP.h>
41#include <X11/StringDefs.h>
42#include <stdio.h>
43#include <ctype.h>
44#include "DviP.h"
45
46static void ParseDrawFunction(DviWidget dw, char *buf);
47static void ParseDeviceControl(DviWidget dw);
48static void PutCharacters(DviWidget dw, unsigned char *src, int len);
49static void push_env(DviWidget dw);
50static void pop_env(DviWidget dw);
51
52#define HorizontalMove(dw, delta)	((dw)->dvi.state->x += (delta))
53
54#ifdef USE_XFT
55static int
56charWidth (DviWidget dw, XftFont *font, char c)
57{
58    XGlyphInfo	extents;
59
60    XftTextExtents8 (XtDisplay (dw), font,
61		     (unsigned char *) &c, 1, &extents);
62    return extents.xOff;
63}
64#else
65#define charWidth(dw,fi,c) (\
66    (fi)->per_char ?\
67	(fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
68    :\
69	(fi)->max_bounds.width\
70)
71#endif
72
73int
74ParseInput(dw)
75    DviWidget	dw;
76{
77	int		n, k;
78	int		c;
79	char		Buffer[BUFSIZ];
80	int		NextPage;
81	int		prevFont;
82	int		otherc;
83	unsigned char	tc;
84
85	/*
86	 * make sure some state exists
87	 */
88
89	if (!dw->dvi.state)
90	    push_env (dw);
91	for (;;) {
92		switch (DviGetC(dw, &c)) {
93		case '\n':
94			break;
95		case ' ':	/* when input is text */
96		case 0:		/* occasional noise creeps in */
97			break;
98		case '{':	/* push down current environment */
99			push_env(dw);
100			break;
101		case '}':
102			pop_env(dw);
103			break;
104		/*
105		 * two motion digits plus a character
106		 */
107		case '0': case '1': case '2': case '3': case '4':
108		case '5': case '6': case '7': case '8': case '9':
109			HorizontalMove(dw, (c-'0')*10 +
110					   DviGetC(dw,&otherc)-'0');
111			/* fall through */
112		case 'c':	/* single ascii character */
113			(void) DviGetC(dw,&c);
114		    	if (c == ' ')
115			    break;
116			tc = c;
117			PutCharacters (dw, &tc, 1);
118			break;
119		case 'C':
120			GetWord(dw, Buffer, BUFSIZ);
121			{
122	    	    	    DviCharNameMap	*map;
123			    int			i;
124			    unsigned char	*ligature;
125
126			    c = -1;
127	    	    	    map = QueryFontMap (dw, dw->dvi.state->font_number);
128	    	    	    if (map)
129			    {
130		    	    	c = DviCharIndex (map, Buffer);
131				if (c == -1)
132				{
133				    ligature = DviCharIsLigature (map, Buffer);
134				    if (ligature) {
135					i = strlen ((char *) ligature);
136					PutCharacters (dw, ligature, i);
137					break;
138   				    }
139				}
140			    }
141			    prevFont = -1;
142	    	    	    if (c == -1) {
143			    	for (i = 1; (map = QueryFontMap (dw, i)); i++)
144				    if (map->special)
145				    	if ((c = DviCharIndex (map, Buffer)) != -1) {
146					    prevFont = dw->dvi.state->font_number;
147					    dw->dvi.state->font_number = i;
148					    break;
149				    	}
150			    }
151			    if (c != -1)
152			    {
153				tc = c;
154				PutCharacters (dw, &tc, 1);
155			    }
156			    if (prevFont != -1)
157				dw->dvi.state->font_number = prevFont;
158			}
159			break;
160		case 'D':	/* draw function */
161			GetLine(dw, Buffer, BUFSIZ);
162			ParseDrawFunction(dw, Buffer);
163			break;
164		case 's':	/* ignore fractional sizes */
165			n = GetNumber(dw);
166			if (!dw->dvi.size_scale)
167			{
168			    static int	guesses[] = { 1, 4, 100, 1000, 1 };
169			    int		i;
170
171			    for (i = 0; i < 4; i++)
172				if (8 <= n/guesses[i] && n/guesses[i] <= 24)
173				{
174				    break;
175				}
176    			    dw->dvi.size_scale = guesses[i];
177			}
178			dw->dvi.state->font_size = n;
179			dw->dvi.state->line_width = n * (dw->dvi.device_resolution /
180							 (720 * dw->dvi.size_scale));
181			break;
182		case 'f':
183			n = GetNumber(dw);
184			dw->dvi.state->font_number = n;
185			break;
186		case 'H':	/* absolute horizontal motion */
187			k = GetNumber(dw);
188			HorizontalGoto(dw, k);
189			break;
190		case 'h':	/* relative horizontal motion */
191			k = GetNumber(dw);
192			HorizontalMove(dw, k);
193			break;
194		case 'w':	/* word space */
195			break;
196		case 'V':
197			n = GetNumber(dw);
198			VerticalGoto(dw, n);
199			break;
200		case 'v':
201			n = GetNumber(dw);
202			VerticalMove(dw, n);
203			break;
204		case 'P':	/* new spread */
205			break;
206		case 'p':	/* new page */
207			(void) GetNumber(dw);
208			NextPage = dw->dvi.current_page + 1;
209			RememberPagePosition(dw, NextPage);
210			FlushCharCache (dw);
211			return(NextPage);
212		case 'n':	/* end of line */
213			GetNumber(dw);
214			GetNumber(dw);
215			HorizontalGoto(dw, 0);
216			break;
217		case '#':	/* comment */
218		case 'F':	/* file info */
219			GetLine(dw, NULL, 0);
220			break;
221		case 't':	/* text */
222			GetLine(dw, Buffer, BUFSIZ);
223			PutCharacters (dw, (unsigned char *)Buffer,
224				       strlen (Buffer));
225			dw->dvi.state->x = ToDevice (dw, dw->dvi.cache.x);
226			break;
227		case 'x':	/* device control */
228			ParseDeviceControl(dw);
229			break;
230		case EOF:
231			dw->dvi.last_page = dw->dvi.current_page;
232			FlushCharCache (dw);
233			return dw->dvi.current_page;
234		default:
235			GetLine (dw, Buffer, BUFSIZ);
236			fprintf (stderr, "Unknown command %s\n", Buffer);
237			break;
238		}
239	}
240}
241
242static void
243push_env(dw)
244	DviWidget	dw;
245{
246	DviState	*new;
247
248	new = (DviState *) XtMalloc (sizeof (*new));
249	if (dw->dvi.state)
250		*new = *(dw->dvi.state);
251	else {
252		new->font_size = 10 * dw->dvi.size_scale;
253		new->font_number = 1;
254		new->line_style = 0;
255		new->line_width = 10;
256		new->x = 0;
257		new->y = 0;
258	}
259	new->next = dw->dvi.state;
260	dw->dvi.state = new;
261}
262
263static void
264pop_env(dw)
265	DviWidget	dw;
266{
267	DviState	*old;
268
269	old = dw->dvi.state;
270	dw->dvi.state = old->next;
271	XtFree ((char *) old);
272}
273
274static void
275InitTypesetter (DviWidget dw)
276{
277	while (dw->dvi.state)
278		pop_env (dw);
279	dw->dvi.size_scale = dw->dvi.size_scale_set;
280	push_env (dw);
281	FlushCharCache (dw);
282}
283
284static void
285SetFont (DviWidget dw)
286{
287    dw->dvi.cache.font_size = dw->dvi.state->font_size;
288    dw->dvi.cache.font_number = dw->dvi.state->font_number;
289    dw->dvi.cache.font = QueryFont (dw,
290			  dw->dvi.cache.font_number,
291			  dw->dvi.cache.font_size);
292}
293
294static void
295PutCharacters (dw, src, len)
296    DviWidget	    dw;
297    unsigned char   *src;
298    int		    len;
299{
300    int	    xx, yx;
301    int	    fx, fy;
302    char    *dst;
303    int	    c;
304
305    xx = ToX(dw, dw->dvi.state->x);
306    yx = ToX(dw, dw->dvi.state->y);
307    fy = FontSizeInPixels (dw, dw->dvi.state->font_size);
308    fx = fy * len;
309    /*
310     * quick and dirty extents calculation:
311     */
312    if (yx + fy >= dw->dvi.extents.y1 &&
313	yx - fy <= dw->dvi.extents.y2 &&
314	xx + fx >= dw->dvi.extents.x1 &&
315	xx - fx <= dw->dvi.extents.x2)
316    {
317#ifdef USE_XFT
318	XftFont	    *font;
319	DviTextItem *text;
320#else
321	register XFontStruct	*font;
322	register XTextItem		*text;
323#endif
324
325	if (!dw->dvi.display_enable)
326	    return;
327
328	if (yx != dw->dvi.cache.y ||
329	    dw->dvi.cache.char_index + len > DVI_CHAR_CACHE_SIZE)
330	    FlushCharCache (dw);
331	/*
332	 * load a new font, if the current block is not empty,
333	 * step to the next.
334	 */
335	if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
336	    dw->dvi.cache.font_number != dw->dvi.state->font_number)
337	{
338	    SetFont (dw);
339	    if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
340		++dw->dvi.cache.index;
341		if (dw->dvi.cache.index >= dw->dvi.cache.max)
342		    FlushCharCache (dw);
343		dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
344	    }
345	}
346	if (xx != dw->dvi.cache.x) {
347	    if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
348		++dw->dvi.cache.index;
349		if (dw->dvi.cache.index >= dw->dvi.cache.max)
350		    FlushCharCache (dw);
351		dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
352	    }
353	}
354	if (!dw->dvi.cache.font)
355	    SetFont (dw);
356	text = &dw->dvi.cache.cache[dw->dvi.cache.index];
357	font = dw->dvi.cache.font;
358	dst = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
359	if (text->nchars == 0) {
360	    text->chars = dst;
361#ifdef USE_XFT
362	    text->x = xx;
363#else
364	    text->delta = xx - dw->dvi.cache.x;
365#endif
366#ifdef USE_XFT
367	    text->font = font;
368#endif
369	    if (font != dw->dvi.font) {
370#ifndef USE_XFT
371		text->font = font->fid;
372#endif
373		dw->dvi.font = font;
374	    }
375#ifndef USE_XFT
376	    else
377		text->font = None;
378#endif
379	    dw->dvi.cache.x = xx;
380	}
381	dw->dvi.cache.char_index += len;
382	text->nchars += len;
383	while (len--)
384	{
385	    c = *src++;
386	    *dst++ = c;
387	    if (font)
388		dw->dvi.cache.x += charWidth(dw,font,c);
389	}
390    }
391}
392
393static void
394ParseDrawFunction(dw, buf)
395	DviWidget	dw;
396	char		*buf;
397{
398    int	n, m, n1, m1;
399
400    SetGCForDraw (dw);
401    switch (buf[0]) {
402    case 'l':				/* draw a line */
403	sscanf(buf+1, "%d %d", &n, &m);
404	DrawLine(dw, n, m);
405	break;
406    case 'c':				/* circle */
407	sscanf(buf+1, "%d", &n);
408	DrawCircle(dw, n);
409	break;
410    case 'e':				/* ellipse */
411	sscanf(buf+1, "%d %d", &m, &n);
412	DrawEllipse(dw, m, n);
413	break;
414    case 'a':				/* arc */
415	sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
416	DrawArc(dw, n, m, n1, m1);
417	break;
418    case '~':				/* wiggly line */
419	DrawSpline(dw, buf+1,1);
420	break;
421    case 't':				/* line width */
422	sscanf(buf+1, "%d", &n);
423	dw->dvi.state->line_width = n;
424	break;
425    case 's':				/* line style */
426	sscanf(buf+1, "%d", &n);
427	/* XXX */
428	break;
429    default:
430	/* warning("unknown drawing function %s", buf); */
431	break;
432    }
433}
434
435extern int LastPage, CurrentPage;
436
437static void
438ParseDeviceControl(dw)				/* Parse the x commands */
439	DviWidget	dw;
440{
441    char str[20], str1[50];
442    int c, n;
443
444    GetWord (dw, str, 20);
445    switch (str[0]) {			/* crude for now */
446    case 'T':				/* output device */
447	GetWord(dw, str, 20);
448	break;
449    case 'i':				/* initialize */
450	InitTypesetter (dw);
451	break;
452    case 't':				/* trailer */
453	break;
454    case 'p':				/* pause -- can restart */
455	break;
456    case 's':				/* stop */
457	return;
458    case 'r':				/* resolution when prepared */
459	SetDeviceResolution (dw, GetNumber (dw));
460	break;
461    case 'f':				/* font used */
462	n = GetNumber(dw);
463	GetWord(dw, str, 20);
464	GetLine(dw, str1, 50);
465	SetFontPosition(dw, n, str, str1);
466	break;
467    case 'H':				/* char height */
468	break;
469    case 'S':				/* slant */
470	break;
471    }
472    while (DviGetC(dw,&c) != '\n')		/* skip rest of input line */
473	    if (c == EOF)
474		    return;
475}
476