parse.c revision 65912f00
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(DviWidget dw)
75{
76	int		n, k;
77	int		c;
78	char		Buffer[BUFSIZ];
79	int		NextPage;
80	int		prevFont;
81	int		otherc;
82	unsigned char	tc;
83
84	/*
85	 * make sure some state exists
86	 */
87
88	if (!dw->dvi.state)
89	    push_env (dw);
90	for (;;) {
91		switch (DviGetC(dw, &c)) {
92		case '\n':
93			break;
94		case ' ':	/* when input is text */
95		case 0:		/* occasional noise creeps in */
96			break;
97		case '{':	/* push down current environment */
98			push_env(dw);
99			break;
100		case '}':
101			pop_env(dw);
102			break;
103		/*
104		 * two motion digits plus a character
105		 */
106		case '0': case '1': case '2': case '3': case '4':
107		case '5': case '6': case '7': case '8': case '9':
108			HorizontalMove(dw, (c-'0')*10 +
109					   DviGetC(dw,&otherc)-'0');
110			/* fall through */
111		case 'c':	/* single ascii character */
112			(void) DviGetC(dw,&c);
113		    	if (c == ' ')
114			    break;
115			tc = c;
116			PutCharacters (dw, &tc, 1);
117			break;
118		case 'C':
119			GetWord(dw, Buffer, BUFSIZ);
120			{
121	    	    	    DviCharNameMap	*map;
122			    int			i;
123			    unsigned char	*ligature;
124
125			    c = -1;
126	    	    	    map = QueryFontMap (dw, dw->dvi.state->font_number);
127	    	    	    if (map)
128			    {
129		    	    	c = DviCharIndex (map, Buffer);
130				if (c == -1)
131				{
132				    ligature = DviCharIsLigature (map, Buffer);
133				    if (ligature) {
134					i = strlen ((char *) ligature);
135					PutCharacters (dw, ligature, i);
136					break;
137   				    }
138				}
139			    }
140			    prevFont = -1;
141	    	    	    if (c == -1) {
142			    	for (i = 1; (map = QueryFontMap (dw, i)); i++)
143				    if (map->special)
144				    	if ((c = DviCharIndex (map, Buffer)) != -1) {
145					    prevFont = dw->dvi.state->font_number;
146					    dw->dvi.state->font_number = i;
147					    break;
148				    	}
149			    }
150			    if (c != -1)
151			    {
152				tc = c;
153				PutCharacters (dw, &tc, 1);
154			    }
155			    if (prevFont != -1)
156				dw->dvi.state->font_number = prevFont;
157			}
158			break;
159		case 'D':	/* draw function */
160			GetLine(dw, Buffer, BUFSIZ);
161			ParseDrawFunction(dw, Buffer);
162			break;
163		case 's':	/* ignore fractional sizes */
164			n = GetNumber(dw);
165			if (!dw->dvi.size_scale)
166			{
167			    static int	guesses[] = { 1, 4, 100, 1000, 1 };
168			    int		i;
169
170			    for (i = 0; i < 4; i++)
171				if (8 <= n/guesses[i] && n/guesses[i] <= 24)
172				{
173				    break;
174				}
175    			    dw->dvi.size_scale = guesses[i];
176			}
177			dw->dvi.state->font_size = n;
178			dw->dvi.state->line_width = n * (dw->dvi.device_resolution /
179							 (720 * dw->dvi.size_scale));
180			break;
181		case 'f':
182			n = GetNumber(dw);
183			dw->dvi.state->font_number = n;
184			break;
185		case 'H':	/* absolute horizontal motion */
186			k = GetNumber(dw);
187			HorizontalGoto(dw, k);
188			break;
189		case 'h':	/* relative horizontal motion */
190			k = GetNumber(dw);
191			HorizontalMove(dw, k);
192			break;
193		case 'w':	/* word space */
194			break;
195		case 'V':
196			n = GetNumber(dw);
197			VerticalGoto(dw, n);
198			break;
199		case 'v':
200			n = GetNumber(dw);
201			VerticalMove(dw, n);
202			break;
203		case 'P':	/* new spread */
204			break;
205		case 'p':	/* new page */
206			(void) GetNumber(dw);
207			NextPage = dw->dvi.current_page + 1;
208			RememberPagePosition(dw, NextPage);
209			FlushCharCache (dw);
210			return(NextPage);
211		case 'n':	/* end of line */
212			GetNumber(dw);
213			GetNumber(dw);
214			HorizontalGoto(dw, 0);
215			break;
216		case '#':	/* comment */
217		case 'F':	/* file info */
218			GetLine(dw, NULL, 0);
219			break;
220		case 't':	/* text */
221			GetLine(dw, Buffer, BUFSIZ);
222			PutCharacters (dw, (unsigned char *)Buffer,
223				       strlen (Buffer));
224			dw->dvi.state->x = ToDevice (dw, dw->dvi.cache.x);
225			break;
226		case 'x':	/* device control */
227			ParseDeviceControl(dw);
228			break;
229		case EOF:
230			dw->dvi.last_page = dw->dvi.current_page;
231			FlushCharCache (dw);
232			return dw->dvi.current_page;
233		default:
234			GetLine (dw, Buffer, BUFSIZ);
235			fprintf (stderr, "Unknown command %s\n", Buffer);
236			break;
237		}
238	}
239}
240
241static void
242push_env(DviWidget dw)
243{
244	DviState	*new;
245
246	new = (DviState *) XtMalloc (sizeof (*new));
247	if (dw->dvi.state)
248		*new = *(dw->dvi.state);
249	else {
250		new->font_size = 10 * dw->dvi.size_scale;
251		new->font_number = 1;
252		new->line_style = 0;
253		new->line_width = 10;
254		new->x = 0;
255		new->y = 0;
256	}
257	new->next = dw->dvi.state;
258	dw->dvi.state = new;
259}
260
261static void
262pop_env(DviWidget dw)
263{
264	DviState	*old;
265
266	old = dw->dvi.state;
267	dw->dvi.state = old->next;
268	XtFree ((char *) old);
269}
270
271static void
272InitTypesetter (DviWidget dw)
273{
274	while (dw->dvi.state)
275		pop_env (dw);
276	dw->dvi.size_scale = dw->dvi.size_scale_set;
277	push_env (dw);
278	FlushCharCache (dw);
279}
280
281static void
282SetFont (DviWidget dw)
283{
284    dw->dvi.cache.font_size = dw->dvi.state->font_size;
285    dw->dvi.cache.font_number = dw->dvi.state->font_number;
286    dw->dvi.cache.font = QueryFont (dw,
287			  dw->dvi.cache.font_number,
288			  dw->dvi.cache.font_size);
289}
290
291static void
292PutCharacters (DviWidget dw, unsigned char *src, int len)
293{
294    int	    xx, yx;
295    int	    fx, fy;
296    char    *dst;
297    int	    c;
298
299    xx = ToX(dw, dw->dvi.state->x);
300    yx = ToX(dw, dw->dvi.state->y);
301    fy = FontSizeInPixels (dw, dw->dvi.state->font_size);
302    fx = fy * len;
303    /*
304     * quick and dirty extents calculation:
305     */
306    if (yx + fy >= dw->dvi.extents.y1 &&
307	yx - fy <= dw->dvi.extents.y2 &&
308	xx + fx >= dw->dvi.extents.x1 &&
309	xx - fx <= dw->dvi.extents.x2)
310    {
311#ifdef USE_XFT
312	XftFont	    *font;
313	DviTextItem *text;
314#else
315	register XFontStruct	*font;
316	register XTextItem		*text;
317#endif
318
319	if (!dw->dvi.display_enable)
320	    return;
321
322	if (yx != dw->dvi.cache.y ||
323	    dw->dvi.cache.char_index + len > DVI_CHAR_CACHE_SIZE)
324	    FlushCharCache (dw);
325	/*
326	 * load a new font, if the current block is not empty,
327	 * step to the next.
328	 */
329	if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
330	    dw->dvi.cache.font_number != dw->dvi.state->font_number)
331	{
332	    SetFont (dw);
333	    if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
334		++dw->dvi.cache.index;
335		if (dw->dvi.cache.index >= dw->dvi.cache.max)
336		    FlushCharCache (dw);
337		dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
338	    }
339	}
340	if (xx != dw->dvi.cache.x) {
341	    if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
342		++dw->dvi.cache.index;
343		if (dw->dvi.cache.index >= dw->dvi.cache.max)
344		    FlushCharCache (dw);
345		dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
346	    }
347	}
348	if (!dw->dvi.cache.font)
349	    SetFont (dw);
350	text = &dw->dvi.cache.cache[dw->dvi.cache.index];
351	font = dw->dvi.cache.font;
352	dst = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
353	if (text->nchars == 0) {
354	    text->chars = dst;
355#ifdef USE_XFT
356	    text->x = xx;
357#else
358	    text->delta = xx - dw->dvi.cache.x;
359#endif
360#ifdef USE_XFT
361	    text->font = font;
362#endif
363	    if (font != dw->dvi.font) {
364#ifndef USE_XFT
365		text->font = font->fid;
366#endif
367		dw->dvi.font = font;
368	    }
369#ifndef USE_XFT
370	    else
371		text->font = None;
372#endif
373	    dw->dvi.cache.x = xx;
374	}
375	dw->dvi.cache.char_index += len;
376	text->nchars += len;
377	while (len--)
378	{
379	    c = *src++;
380	    *dst++ = c;
381	    if (font)
382		dw->dvi.cache.x += charWidth(dw,font,c);
383	}
384    }
385}
386
387static void
388ParseDrawFunction(DviWidget dw, char *buf)
389{
390    int	n, m, n1, m1;
391
392    SetGCForDraw (dw);
393    switch (buf[0]) {
394    case 'l':				/* draw a line */
395	sscanf(buf+1, "%d %d", &n, &m);
396	DrawLine(dw, n, m);
397	break;
398    case 'c':				/* circle */
399	sscanf(buf+1, "%d", &n);
400	DrawCircle(dw, n);
401	break;
402    case 'e':				/* ellipse */
403	sscanf(buf+1, "%d %d", &m, &n);
404	DrawEllipse(dw, m, n);
405	break;
406    case 'a':				/* arc */
407	sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
408	DrawArc(dw, n, m, n1, m1);
409	break;
410    case '~':				/* wiggly line */
411	DrawSpline(dw, buf+1,1);
412	break;
413    case 't':				/* line width */
414	sscanf(buf+1, "%d", &n);
415	dw->dvi.state->line_width = n;
416	break;
417    case 's':				/* line style */
418	sscanf(buf+1, "%d", &n);
419	/* XXX */
420	break;
421    default:
422	/* warning("unknown drawing function %s", buf); */
423	break;
424    }
425}
426
427extern int LastPage, CurrentPage;
428
429static void
430ParseDeviceControl(DviWidget dw)	/* Parse the x commands */
431{
432    char str[20], str1[50];
433    int c, n;
434
435    GetWord (dw, str, 20);
436    switch (str[0]) {			/* crude for now */
437    case 'T':				/* output device */
438	GetWord(dw, str, 20);
439	break;
440    case 'i':				/* initialize */
441	InitTypesetter (dw);
442	break;
443    case 't':				/* trailer */
444	break;
445    case 'p':				/* pause -- can restart */
446	break;
447    case 's':				/* stop */
448	return;
449    case 'r':				/* resolution when prepared */
450	SetDeviceResolution (dw, GetNumber (dw));
451	break;
452    case 'f':				/* font used */
453	n = GetNumber(dw);
454	GetWord(dw, str, 20);
455	GetLine(dw, str1, 50);
456	SetFontPosition(dw, n, str, str1);
457	break;
458    case 'H':				/* char height */
459	break;
460    case 'S':				/* slant */
461	break;
462    }
463    while (DviGetC(dw,&c) != '\n')		/* skip rest of input line */
464	    if (c == EOF)
465		    return;
466}
467