xref: /plan9-contrib/sys/src/cmd/spin/msc_tcl.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
1 /***** spin: msc_tcl.c *****/
2 
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  */
8 
9 #include <stdlib.h>
10 #include "spin.h"
11 #include "version.h"
12 
13 #define MW	500	/* page width */
14 #define RH	100	/* right margin */
15 #define WW	 80	/* distance between process lines */
16 #define HH	 12	/* vertical distance between steps */
17 #define LW	  2	/* line width of message arrows */
18 
19 #define RVC	"darkred"	/* rendezvous arrows */
20 #define MPC	"darkblue"	/* asynchronous message passing arrow */
21 #define GRC	"lightgrey"	/* grid lines */
22 
23 static int	MH = 600;	/* anticipated page-length */
24 static FILE	*pfd;
25 static char	**I;		/* initial procs */
26 static int	*D,*R;		/* maps between depth (stepnr) and ldepth (msc-step) */
27 static short	*M;		/* x location of each box at index y */
28 static short	*T;		/* y index of match for each box at index y */
29 static char	**L;		/* text labels */
30 static int	ProcLine[256];	/* active processes */
31 static int	UsedLine[256];	/* process line has at least one entry */
32 static int	ldepth = 1;
33 static int	maxx, TotSteps = 2*4096; /* max nr of steps for simulation output */
34 static float	Scaler = (float) 1.0;
35 
36 static int	xscale = 2;
37 static int	yscale = 1;
38 static int	no_box;
39 
40 extern int	ntrail, s_trail, prno, depth;
41 extern short	Have_claim;
42 extern Symbol	*oFname;
43 
44 extern void	exit(int);
45 extern void	putpostlude(void);
46 
47 static void	putpages(void);
48 
49 static void
psline(int x0,int y0,int x1,int y1,char * color)50 psline(int x0, int y0, int x1, int y1, char *color)
51 {	char *side = "last";
52 
53 	if (x0 == x1)	/* gridline */
54 	{	fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags grid -width 1 \n",
55 			xscale*(x0+1)*WW-20, yscale*y0+20,
56 			xscale*(x1+1)*WW-20, yscale*y1+20, color);
57 		fprintf(pfd, ".c lower grid\n");
58 	} else
59 	{	int xm = xscale*(x0+1)*WW + (xscale*(x1 - x0)*WW)/2 - 20;	/* mid x */
60 
61 		if (y1 - y0  <= HH+20)
62 		{	y1 = y0+20; /* close enough to horizontal - looks better */
63 		}
64 
65 		fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
66 			xscale*(x0+1)*WW-20, yscale*y0+20+10,
67 			xm,                  yscale*y0+20+10, color, LW);
68 
69 		if (y1 != y0+20)
70 		{	fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
71 				xm, yscale*y0+20+10,
72 				xm, yscale*y1+20-10, color, LW);
73 		}
74 
75 		fprintf(pfd, ".c create line %d %d %d %d -fill %s -width %d ",
76 			xm,                  yscale*y1+20-10,
77 			xscale*(x1+1)*WW-20, yscale*y1+20-10, color, LW);
78 
79 		if (strcmp(color, RVC) == 0)
80 		{	side = "both";
81 		}
82 		fprintf(pfd, "-arrow %s -arrowshape {5 5 5} -tags mesg\n", side);
83 		fprintf(pfd, ".c raise mesg\n");
84 	}
85 }
86 
87 static void
colbox(int ix,int iy,int w,int h_unused,char * color)88 colbox(int ix, int iy, int w, int h_unused, char *color)
89 {	int x = ix*WW;
90 	int y = iy*HH;
91 
92 	if (ix < 0 || ix > 255)
93 	{	fprintf(stderr, "saw ix=%d\n", ix);
94 		fatal("msc_tcl: unexpected\n", (char *) 0);
95 	}
96 
97 	if (ProcLine[ix] < iy)
98 	{	/* if (ProcLine[ix] > 0) */
99 		{	psline(ix-1, ProcLine[ix]*HH+HH+4,
100 			       ix-1, iy*HH-HH, GRC);
101 		}
102 		fprintf(pfd, "# ProcLine[%d] from %d to %d (Used %d nobox %d)\n",
103 			ix, ProcLine[ix], iy, UsedLine[ix], no_box);
104 		ProcLine[ix] = iy;
105 	} else
106 	{	fprintf(pfd, "# ProcLine[%d] stays at %d (Used %d nobox %d)\n",
107 			ix, ProcLine[ix], UsedLine[ix], no_box);
108 	}
109 
110 	if (UsedLine[ix])
111 	{	no_box = 2;
112 	}
113 
114 	if (strcmp(color, "black") == 0)
115 	{	if (no_box == 0)	/* shadow */
116 		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill black\n",
117 				xscale*x-(xscale*4*w/3)-20+4, (yscale*y-10)+20+2,
118 				xscale*x+(xscale*4*w/3)-20,   (yscale*y+10)+20+2);
119 		}
120 	} else
121 	{	if (no_box == 0)	/* box with outline */
122 		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill ivory\n",
123 				xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
124 				xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
125 			UsedLine[ix]++;
126 		} else			/* no outline */
127 		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill white -width 0\n",
128 				xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
129 				xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
130 	}	}
131 	if (no_box > 0)
132 	{	no_box--;
133 	}
134 }
135 
136 static void
stepnumber(int i)137 stepnumber(int i)
138 {	int y = (yscale*i*HH) + 20;
139 
140 	fprintf(pfd, ".c create text %d %d -fill #eef -text \"%d\"\n",
141 		-10+(xscale*WW)/2, y, i);
142 
143 	/* horizontal dashed grid line */
144 	fprintf(pfd, ".c create line %d %d %d %d -fill #eef -dash {6 4}\n",
145 		-20+WW*xscale, y, (maxx+1)*WW*xscale-20, y);
146 }
147 
148 static void
spitbox(int ix,int y,char * s)149 spitbox(int ix, int y, char *s)
150 {	float bw;	/* box width */
151 	char d[256], *t, *z;
152 	int a, i, x = ix+1;
153 	char *color = "black";
154 
155 	if (y > 0)
156 	{	stepnumber(y);
157 	}
158 
159 	bw = (float)1.8*(float)strlen(s);	/* guess at default font width */
160 	colbox(x, y, (int) (bw+1.0), 5, "black");
161 	if (s[0] == '~')
162 	{	switch (s[1]) {
163 		default :
164 		case 'R': color = "red";   break;
165 		case 'B': color = "blue";  break;
166 		case 'G': color = "green"; break;
167 		}
168 		s += 2;
169 	} else if (strchr(s, '!'))
170 	{	color = "ivory";
171 	} else if (strchr(s, '?'))
172 	{	color = "azure";
173 	} else
174 	{	color = "pink";
175 		if (sscanf(s, "%d:%250s", &a, d) == 2
176 		&&  a >= 0 && a < TotSteps)
177 		{	if (!I[a]  || strlen(I[a]) <= strlen(s))
178 			{	I[a] = (char *) emalloc((int) strlen(s)+1);
179 			}
180 			strcpy(I[a], s);
181 	}	}
182 
183 	colbox(x, y, (int) bw, 4, color);
184 
185 	z = t = (char *) emalloc(2*strlen(s)+1);
186 
187 	for (i = 0; i < (int) strlen(s); i++)
188 	{	if (s[i] == '\n')
189 		{	continue;
190 		}
191 		if (s[i] == '[' || s[i] == ']')
192 		{	*t++ = '\\';
193 		}
194 		*t++ = s[i];
195 	}
196 
197 	fprintf(pfd, ".c create text %d %d -text \"%s\"\n",
198 		xscale*x*WW-20, yscale*y*HH+20, z);
199 }
200 
201 static void
putpages(void)202 putpages(void)
203 {	int i, lasti=0; float nmh;
204 
205 	if (maxx*xscale*WW > MW-RH/2)
206 	{	Scaler = (float) (MW-RH/2) / (float) (maxx*xscale*WW);
207 		nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
208 		fprintf(pfd, "# Scaler %f, MH %d\n", Scaler, MH);
209 	}
210 	if (ldepth >= TotSteps)
211 	{	ldepth = TotSteps-1;
212 	}
213 
214 /* W: (maxx+2)*xscale*WW  */
215 /* H: ldepth*HH*yscale+50 */
216 	fprintf(pfd, "wm title . \"scenario\"\n");
217 	fprintf(pfd, "wm geometry . %dx600+650+100\n", (maxx+2)*xscale*WW);
218 
219 	fprintf(pfd, "canvas .c -width 800 -height 800 \\\n");
220 	fprintf(pfd, "	-scrollregion {0c -1c 30c 100c} \\\n");
221 	fprintf(pfd, "	-xscrollcommand \".hscroll set\" \\\n");
222 	fprintf(pfd, "	-yscrollcommand \".vscroll set\" \\\n");
223 	fprintf(pfd, "	-bg white -relief raised -bd 2\n");
224 
225 	fprintf(pfd, "scrollbar .vscroll -relief sunken ");
226 	fprintf(pfd, " -command \".c yview\"\n");
227 	fprintf(pfd, "scrollbar .hscroll -relief sunken -orient horiz ");
228 	fprintf(pfd, " -command \".c xview\"\n");
229 
230 	fprintf(pfd, "pack append . \\\n");
231 	fprintf(pfd, "	.vscroll {right filly} \\\n");
232 	fprintf(pfd, "	.hscroll {bottom fillx} \\\n");
233 	fprintf(pfd, "	.c {top expand fill}\n");
234 
235 	fprintf(pfd, ".c yview moveto 0\n");
236 
237 	for (i = TotSteps-1; i >= 0; i--)
238 	{	if (I[i])
239 		{	spitbox(i, -1, I[i]);
240 	}	}
241 
242 	for (i = 0; i <= ldepth; i++)
243 	{	if (!M[i] && !L[i])
244 		{	continue;	/* no box */
245 		}
246 		if (T[i] > 0)		/* arrow */
247 		{	if (T[i] == i)	/* rv handshake */
248 			{	psline(	M[lasti], lasti*HH,
249 					M[i],     i*HH, RVC);
250 			} else
251 			{	psline(	M[i],     i*HH,
252 					M[T[i]],  T[i]*HH, MPC);
253 		}	}
254 		if (L[i])
255 		{	spitbox(M[i], i, L[i]);
256 			lasti = i;
257 	}	}
258 }
259 
260 static void
putbox(int x)261 putbox(int x)
262 {
263 	if (ldepth >= TotSteps)
264 	{	fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n",
265 			TotSteps);
266 		putpostlude();
267 	}
268 	M[ldepth] = x;
269 	if (x > maxx)
270 	{	maxx = x;
271 		fprintf(pfd, "# maxx %d\n", x);
272 	}
273 }
274 
275 /* functions called externally: */
276 
277 extern int WhatSeed(void);
278 
279 void
putpostlude(void)280 putpostlude(void)
281 {	char cmd[512];
282 
283 	putpages();
284 	fprintf(pfd, ".c lower grid\n");
285 	fprintf(pfd, ".c raise mesg\n");
286 	fclose(pfd);
287 
288 	fprintf(stderr, "seed used: -n%d\n", WhatSeed());
289 	sprintf(cmd, "wish -f %s.tcl &", oFname?oFname->name:"msc");
290 	fprintf(stderr, "%s\n", cmd);
291 	(void) unlink("pan.pre");
292 	exit (system(cmd));
293 }
294 
295 void
putprelude(void)296 putprelude(void)
297 {	char snap[256]; FILE *fd;
298 
299 	sprintf(snap, "%s.tcl", oFname?oFname->name:"msc");
300 	if (!(pfd = fopen(snap, MFLAGS)))
301 	{	fatal("cannot create file '%s'", snap);
302 	}
303 	if (s_trail)
304 	{	if (ntrail)
305 		sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail);
306 		else
307 		sprintf(snap, "%s.trail", oFname?oFname->name:"msc");
308 		if (!(fd = fopen(snap, "r")))
309 		{	snap[strlen(snap)-2] = '\0';
310 			if (!(fd = fopen(snap, "r")))
311 				fatal("cannot open trail file", (char *) 0);
312 		}
313 		TotSteps = 1;
314 		while (fgets(snap, 256, fd)) TotSteps++;
315 		fclose(fd);
316 	}
317 	TotSteps *= 2;
318 	R = (int   *) emalloc(TotSteps * sizeof(int));
319 	D = (int   *) emalloc(TotSteps * sizeof(int));
320 	M = (short *) emalloc(TotSteps * sizeof(short));
321 	T = (short *) emalloc(TotSteps * sizeof(short));
322 	L = (char **) emalloc(TotSteps * sizeof(char *));
323 	I = (char **) emalloc(TotSteps * sizeof(char *));
324 }
325 
326 void
putarrow(int from,int to)327 putarrow(int from, int to)
328 {
329 	/* from rv if from == to */
330 	/* which means that D[from] == D[to] */
331 	/* which means that T[x] == x */
332 
333 	if (from    < TotSteps
334 	&&  to      < TotSteps
335 	&&  D[from] < TotSteps)
336 	{	T[D[from]] = D[to];
337 	}
338 }
339 
340 void
pstext(int x,char * s)341 pstext(int x, char *s)
342 {	char *tmp = emalloc((int) strlen(s)+1);
343 
344 	strcpy(tmp, s);
345 	if (depth == 0)
346 	{	I[x] = tmp;
347 	} else
348 	{	if (depth >= TotSteps || ldepth >= TotSteps)
349 		{	fprintf(stderr, "spin: error: max nr of %d steps exceeded\n",
350 				TotSteps);
351 			fatal("use -uN to limit steps", (char *) 0);
352 		}
353 		putbox(x);
354 		D[depth] = ldepth;
355 		R[ldepth] = depth;
356 		L[ldepth] = tmp;
357 		ldepth += 2;
358 	}
359 }
360 
361 void
dotag(FILE * fd,char * s)362 dotag(FILE *fd, char *s)
363 {	extern int columns, notabs; extern RunList *X_lst;
364 	int i = (!strncmp(s, "MSC: ", 5))?5:0;
365 	int pid = s_trail ? (prno - Have_claim) : (X_lst?X_lst->pid:0);
366 
367 	if (pid < 0) { pid = 0; }
368 
369 	if (columns == 2)
370 	{	pstext(pid, &s[i]);
371 	} else
372 	{	if (!notabs)
373 		{	printf("  ");
374 			for (i = 0; i <= pid; i++)
375 			{	printf("    ");
376 		}	}
377 		fprintf(fd, "%s", s);
378 		fflush(fd);
379 	}
380 }
381