1/*
2** interpret.c
3**
4** interprets and executes lines in the Xgc syntax.
5*/
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <X11/Intrinsic.h>
10#include <X11/StringDefs.h>
11#include "xgc.h"
12#include "tile"
13
14
15/* interpret(string)
16** -----------------
17** Takes string, which is a line written in the xgc syntax, figures
18** out what it means, and passes the buck to the right procedure.
19** That procedure gets called with feedback set to FALSE; interpret()
20** is only called if the user is selecting things interactively.
21**
22** This procedure will go away when I can figure out how to make yacc
23** and lex read from strings as well as files.
24*/
25
26void
27interpret(const char *string)
28{
29  char word1[20], word2[80];
30  int i;
31
32  sscanf(string,"%s",word1);
33  if (!strcmp(word1,"run")) run_test();
34
35  else {
36    sscanf(string,"%s %s",word1,word2);
37    print_if_recording(string);
38
39    /* So word1 is the first word on the line and word2 is the second.
40       Now the fun begins... */
41
42    if (!strcmp(word1,TestStuff.choice.text))  {
43      for (i=0;i<NUM_TESTS;++i) {
44	if (!strcmp(word2,(TestStuff.data)[i].text)) {
45	  change_test((TestStuff.data)[i].code,FALSE);
46	  break;
47	}
48      }
49    }
50    else if (!strcmp(word1,FunctionStuff.choice.text)) {
51      for (i=0;i<NUM_FUNCTIONS;++i) {
52	if (!strcmp(word2,(FunctionStuff.data)[i].text)) {
53	  GC_change_function((FunctionStuff.data)[i].code,FALSE);
54	  break;
55	}
56      }
57    }
58    else if (!strcmp(word1,LinestyleStuff.choice.text)) {
59      for (i=0;i<NUM_LINESTYLES;++i) {
60	if (!strcmp(word2,(LinestyleStuff.data)[i].text)) {
61	  GC_change_linestyle((LinestyleStuff.data)[i].code,FALSE);
62	  break;
63	}
64      }
65    }
66    else if (!strcmp(word1,"linewidth"))
67      GC_change_linewidth(atoi(word2),FALSE);
68    else if (!strcmp(word1,CapstyleStuff.choice.text)) {
69      for (i=0;i<NUM_CAPSTYLES;++i) {
70	if (!strcmp(word2,(CapstyleStuff.data)[i].text)) {
71	  GC_change_capstyle((CapstyleStuff.data)[i].code,FALSE);
72	  break;
73	}
74      }
75    }
76    else if (!strcmp(word1,JoinstyleStuff.choice.text)) {
77      for (i=0;i<NUM_JOINSTYLES;++i) {
78	if (!strcmp(word2,(JoinstyleStuff.data)[i].text)) {
79	  GC_change_joinstyle((JoinstyleStuff.data)[i].code,FALSE);
80	  break;
81	}
82      }
83    }
84    else if (!strcmp(word1,FillstyleStuff.choice.text)) {
85      for (i=0;i<NUM_FILLSTYLES;++i) {
86	if (!strcmp(word2,(FillstyleStuff.data)[i].text)) {
87	  GC_change_fillstyle((FillstyleStuff.data)[i].code,FALSE);
88	  break;
89	}
90      }
91    }
92    else if (!strcmp(word1,FillruleStuff.choice.text)) {
93      for (i=0;i<NUM_FILLRULES;++i) {
94	if (!strcmp(word2,(FillruleStuff.data)[i].text)) {
95	  GC_change_fillrule((FillruleStuff.data)[i].code,FALSE);
96	  break;
97	}
98      }
99    }
100    else if (!strcmp(word1,ArcmodeStuff.choice.text)) {
101      for (i=0;i<NUM_ARCMODES;++i) {
102	if (!strcmp(word2,(ArcmodeStuff.data)[i].text)) {
103	  GC_change_arcmode((ArcmodeStuff.data)[i].code,FALSE);
104	  break;
105	}
106      }
107    }
108    else if (!strcmp(word1,"planemask"))
109      GC_change_planemask((unsigned long) atoi(word2),FALSE);
110    else if (!strcmp(word1,"dashlist"))
111      GC_change_dashlist(atoi(word2),FALSE);
112    else if (!strcmp(word1,"font"))
113      GC_change_font(word2,FALSE);
114    else if (!strcmp(word1,"foreground"))
115      GC_change_foreground((unsigned long) atoi(word2),FALSE);
116    else if (!strcmp(word1,"background"))
117      GC_change_background((unsigned long) atoi(word2),FALSE);
118    else if (!strcmp(word1,"percent"))
119      change_percent(atoi(word2), FALSE);
120    else fprintf(stderr,"Ack... %s %s\n",word1,word2);
121  }
122}
123
124#ifdef notdef
125void
126interpret(const char *instring)
127{
128  FILE *inend;
129
130  print_if_recording(instring);
131  yyin = outend;
132  inend = fdopen(fildes[1],"w");
133  fprintf(inend,"%s",instring);
134  fclose(inend);
135  yyparse();
136}
137#endif
138
139#define select_correct_button(which,number) \
140  select_button(GCdescs[(which)],(number));
141
142/* GC_change_blahzee(foo,feedback)
143** ---------------------
144** Changes the blahzee field in xgc's GC to foo.  If feedback is TRUE,
145** changes the display to reflect this (makes it look like the user
146** selected the button, or typed in the text, or whatever).
147*/
148
149void
150GC_change_function(int function, Boolean feedback)
151{
152  XSetFunction(X.dpy,X.gc,function);
153  X.gcv.function = function;
154  if (feedback) select_correct_button(CFunction,function);
155}
156
157void
158GC_change_foreground(unsigned long foreground, Boolean feedback)
159{
160  char text[40];
161
162  XSetForeground(X.dpy,X.miscgc,foreground);
163  XCopyPlane(X.dpy,X.stipple,X.tile,X.miscgc,0,0,tile_width,tile_height,0,0,1);
164  XSetForeground(X.dpy,X.gc,foreground);
165  X.gcv.foreground = foreground;
166  XSetTile(X.dpy,X.gc,X.tile);
167  XSetTile(X.dpy,X.miscgc,X.tile);
168  if (feedback) {
169    snprintf(text, sizeof text, "%lu",foreground);
170    change_text(foregroundtext,text);
171  }
172}
173
174void
175GC_change_background(unsigned long background, Boolean feedback)
176{
177  char text[40];
178
179  XSetBackground(X.dpy,X.miscgc,background);
180  XCopyPlane(X.dpy,X.stipple,X.tile,X.miscgc,0,0,tile_width,tile_height,0,0,1);
181  XSetBackground(X.dpy,X.gc,background);
182  X.gcv.background = background;
183  XSetTile(X.dpy,X.gc,X.tile);
184  XSetTile(X.dpy,X.miscgc,X.tile);
185
186  /* Update the background of the test window NOW. */
187
188  XSetWindowBackground(X.dpy,XtWindow(test),background);
189  XClearWindow(X.dpy,XtWindow(test));
190
191  if (feedback) {
192    snprintf(text, sizeof text, "%lu",background);
193    change_text(backgroundtext,text);
194  }
195}
196
197void
198GC_change_linewidth(int linewidth, Boolean feedback)
199{
200  char text[40];
201
202  X.gcv.line_width = linewidth;
203  XChangeGC(X.dpy,X.gc,GCLineWidth,&X.gcv);
204  if (feedback) {
205    snprintf(text, sizeof text, "%d",linewidth);
206    change_text(linewidthtext,text);
207  }
208}
209
210void
211GC_change_linestyle(int linestyle, Boolean feedback)
212{
213  X.gcv.line_style = linestyle;
214  XChangeGC(X.dpy,X.gc,GCLineStyle,&X.gcv);
215  if (feedback) select_correct_button(CLinestyle,linestyle);
216}
217
218void
219GC_change_capstyle(int capstyle, Boolean feedback)
220{
221  X.gcv.cap_style = capstyle;
222  XChangeGC(X.dpy,X.gc,GCCapStyle,&X.gcv);
223  if (feedback) select_correct_button(CCapstyle,capstyle);
224}
225
226void
227GC_change_joinstyle(int joinstyle, Boolean feedback)
228{
229  X.gcv.join_style = joinstyle;
230  XChangeGC(X.dpy,X.gc,GCJoinStyle,&X.gcv);
231  if (feedback) select_correct_button(CJoinstyle,joinstyle);
232}
233
234void
235GC_change_fillstyle(int fillstyle, Boolean feedback)
236{
237  XSetFillStyle(X.dpy,X.gc,fillstyle);
238  X.gcv.fill_style = fillstyle;
239  if (feedback) select_correct_button(CFillstyle,fillstyle);
240}
241
242void
243GC_change_fillrule(int fillrule, Boolean feedback)
244{
245  XSetFillRule(X.dpy,X.gc,fillrule);
246  X.gcv.fill_rule = fillrule;
247  if (feedback) select_correct_button(CFillrule,fillrule);
248}
249
250void
251GC_change_arcmode(int arcmode, Boolean feedback)
252{
253  XSetArcMode(X.dpy,X.gc,arcmode);
254  X.gcv.arc_mode = arcmode;
255  if (feedback) select_correct_button(CArcmode,arcmode);
256}
257
258/* GC_change_dashlist(dashlist)
259** ----------------------------
260** Now this one's a bit tricky.  dashlist gets passed in as an int, but we
261** want to change it to an array of chars, like the GC likes it.
262** For example:
263**     119 => XXX_XXX_ => [3,1,3,1]
264*/
265
266void
267GC_change_dashlist(int dashlist, Boolean feedback)
268{
269  char dasharray[DASHLENGTH];	/* what we're going to pass to XSetDashes */
270  int dashnumber = 0;		/* which element of dasharray we're currently
271				   modifying */
272  int i;			/* which bit of the dashlist we're on */
273  int state = 1;		/* whether the list bit we checked was
274				   on (1) or off (0) */
275
276  /* Initialize the dasharray */
277
278  for (i = 0; i < DASHLENGTH; ++i) dasharray[i] = 0;
279
280  if (dashlist == 0) return;	/* having no dashes at all is bogus */
281
282  /* XSetDashes expects the dashlist to start with an on bit, so if it
283  ** doesn't, we keep on rotating it until it does */
284
285  while (!(dashlist&1)) dashlist /= 2;
286
287  /* Go through all the bits in dashlist, and update the dasharray
288  ** accordingly */
289
290  for (i = 0; i < DASHLENGTH; ++i) {
291    /* the following if statements checks to see if the bit we're looking
292    ** at as the same on or offness as the one before it (state).  If
293    ** so, we increment the length of the current dash. */
294
295    if (((dashlist&1<<i) && state) || (!(dashlist&1<<i) && !state))
296      ++dasharray[dashnumber];
297    else {
298      state = state^1;		/* reverse the state */
299      ++dasharray[++dashnumber]; /* start a new dash */
300    }
301  }
302
303  XSetDashes(X.dpy,X.gc,0,dasharray,dashnumber+1);
304  X.gcv.dashes = dashlist;
305
306  if (feedback) update_dashlist(dashlist);
307}
308
309void
310GC_change_planemask(unsigned long planemask, Boolean feedback)
311{
312  XSetPlaneMask(X.dpy,X.gc,planemask);
313  X.gcv.plane_mask = planemask;
314  if (feedback) update_planemask((long)planemask);
315}
316
317void
318change_test(int test, Boolean feedback)
319{
320  X.test = test;
321  if (feedback) select_button(testchoicedesc,test);
322}
323
324void
325GC_change_font(char *str, Boolean feedback)
326{
327  int num_fonts;		/* number of fonts that match the string */
328
329  XListFonts(X.dpy,str,1,&num_fonts); /* see if the font exists */
330
331  if (num_fonts) {
332    XSetFont(X.dpy,X.gc,XLoadFont(X.dpy,str));
333    if (feedback) change_text(fonttext,str);
334  }
335}
336
337void
338change_percent(int percent, Boolean feedback)
339{
340  /* Make sure that percent is valid */
341
342  if (percent < 1 || percent > 100) return;
343
344  X.percent = (float) percent / 100.0;
345
346  if (feedback) update_slider(percent);
347}
348