/* * parse.c * * parse dvi input */ #include #include #include #include #include #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: */