ps_msc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /***** spin: ps_msc.c *****/
  10. /* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */
  11. /* All Rights Reserved. This software is for educational purposes only. */
  12. /* No guarantee whatsoever is expressed or implied by the distribution of */
  13. /* this code. Permission is given to distribute this code provided that */
  14. /* this introductory message is not removed and no monies are exchanged. */
  15. /* Software written by Gerard J. Holzmann. For tool documentation see: */
  16. /* http://spinroot.com/ */
  17. /* Send all bug-reports and/or questions to: bugs@spinroot.com */
  18. /* The Postscript generation code below was written by Gerard J. Holzmann */
  19. /* in June 1997. Parts of the prolog template are based on similar boiler */
  20. /* plate in the Tcl/Tk distribution. This code is used to support Spin's */
  21. /* option -M for generating a Postscript file from a simulation run. */
  22. #include "spin.h"
  23. #include "version.h"
  24. /* extern void free(void *); */
  25. static char *PsPre[] = {
  26. "%%%%Pages: (atend)",
  27. "%%%%PageOrder: Ascend",
  28. "%%%%DocumentData: Clean7Bit",
  29. "%%%%Orientation: Portrait",
  30. "%%%%DocumentNeededResources: font Courier-Bold",
  31. "%%%%EndComments",
  32. "",
  33. "%%%%BeginProlog",
  34. "50 dict begin",
  35. "",
  36. "/baseline 0 def",
  37. "/height 0 def",
  38. "/justify 0 def",
  39. "/lineLength 0 def",
  40. "/spacing 0 def",
  41. "/stipple 0 def",
  42. "/strings 0 def",
  43. "/xoffset 0 def",
  44. "/yoffset 0 def",
  45. "",
  46. "/ISOEncode {",
  47. " dup length dict begin",
  48. " {1 index /FID ne {def} {pop pop} ifelse} forall",
  49. " /Encoding ISOLatin1Encoding def",
  50. " currentdict",
  51. " end",
  52. " /Temporary exch definefont",
  53. "} bind def",
  54. "",
  55. "/AdjustColor {",
  56. " CL 2 lt {",
  57. " currentgray",
  58. " CL 0 eq {",
  59. " .5 lt {0} {1} ifelse",
  60. " } if",
  61. " setgray",
  62. " } if",
  63. "} bind def",
  64. "",
  65. "/DrawText {",
  66. " /stipple exch def",
  67. " /justify exch def",
  68. " /yoffset exch def",
  69. " /xoffset exch def",
  70. " /spacing exch def",
  71. " /strings exch def",
  72. " /lineLength 0 def",
  73. " strings {",
  74. " stringwidth pop",
  75. " dup lineLength gt {/lineLength exch def} {pop} ifelse",
  76. " newpath",
  77. " } forall",
  78. " 0 0 moveto (TXygqPZ) false charpath",
  79. " pathbbox dup /baseline exch def",
  80. " exch pop exch sub /height exch def pop",
  81. " newpath",
  82. " translate",
  83. " lineLength xoffset mul",
  84. " strings length 1 sub spacing mul height add yoffset mul translate",
  85. " justify lineLength mul baseline neg translate",
  86. " strings {",
  87. " dup stringwidth pop",
  88. " justify neg mul 0 moveto",
  89. " stipple {",
  90. " gsave",
  91. " /char (X) def",
  92. " {",
  93. " char 0 3 -1 roll put",
  94. " currentpoint",
  95. " gsave",
  96. " char true charpath clip StippleText",
  97. " grestore",
  98. " char stringwidth translate",
  99. " moveto",
  100. " } forall",
  101. " grestore",
  102. " } {show} ifelse",
  103. " 0 spacing neg translate",
  104. " } forall",
  105. "} bind def",
  106. "%%%%EndProlog",
  107. "%%%%BeginSetup",
  108. "/CL 2 def",
  109. "%%%%IncludeResource: font Courier-Bold",
  110. "%%%%EndSetup",
  111. 0,
  112. };
  113. static int MH = 600; /* page height - can be scaled */
  114. static int oMH = 600; /* page height - not scaled */
  115. #define MW 500 /* page width */
  116. #define LH 100 /* bottom margin */
  117. #define RH 100 /* right margin */
  118. #define WW 50 /* distance between process lines */
  119. #define HH 8 /* vertical distance between steps */
  120. #define PH 14 /* height of process-tag headers */
  121. static FILE *pfd;
  122. static char **I; /* initial procs */
  123. static int *D,*R; /* maps between depth and ldepth */
  124. static int16_t *M; /* x location of each box at index y */
  125. static int16_t *T; /* y index of match for each box at index y */
  126. static char **L; /* text labels */
  127. static char *ProcLine; /* active processes */
  128. static int pspno = 0; /* postscript page */
  129. static int ldepth = 1;
  130. static int maxx, TotSteps = 2*4096; /* max nr of steps, about 40 pages */
  131. static float Scaler = (float) 1.0;
  132. extern int ntrail, s_trail, pno, depth;
  133. extern Symbol *oFname;
  134. extern void exit(int);
  135. void putpages(void);
  136. void spitbox(int, int, int, char *);
  137. void
  138. putlegend(void)
  139. {
  140. fprintf(pfd, "gsave\n");
  141. fprintf(pfd, "/Courier-Bold findfont 8 scalefont ");
  142. fprintf(pfd, "ISOEncode setfont\n");
  143. fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
  144. fprintf(pfd, "%d %d [\n", MW/2, LH+oMH+ 5*HH);
  145. fprintf(pfd, " (%s -- %s -- MSC -- %d)\n] 10 -0.5 0.5 0 ",
  146. SpinVersion, oFname?oFname->name:"", pspno);
  147. fprintf(pfd, "false DrawText\ngrestore\n");
  148. }
  149. void
  150. startpage(void)
  151. { int i;
  152. pspno++;
  153. fprintf(pfd, "%%%%Page: %d %d\n", pspno, pspno);
  154. putlegend();
  155. for (i = TotSteps-1; i >= 0; i--)
  156. { if (!I[i]) continue;
  157. spitbox(i, RH, -PH, I[i]);
  158. }
  159. fprintf(pfd, "save\n");
  160. fprintf(pfd, "10 %d moveto\n", LH+oMH+5);
  161. fprintf(pfd, "%d %d lineto\n", RH+MW, LH+oMH+5);
  162. fprintf(pfd, "%d %d lineto\n", RH+MW, LH);
  163. fprintf(pfd, "10 %d lineto\n", LH);
  164. fprintf(pfd, "closepath clip newpath\n");
  165. fprintf(pfd, "%f %f translate\n",
  166. (float) RH, (float) LH);
  167. memset(ProcLine, 0, 256*sizeof(char));
  168. if (Scaler != 1.0)
  169. fprintf(pfd, "%f %f scale\n", Scaler, Scaler);
  170. }
  171. void
  172. putprelude(void)
  173. { char snap[256]; FILE *fd;
  174. sprintf(snap, "%s.ps", oFname?oFname->name:"msc");
  175. if (!(pfd = fopen(snap, MFLAGS)))
  176. fatal("cannot create file '%s'", snap);
  177. fprintf(pfd, "%%!PS-Adobe-2.0\n");
  178. fprintf(pfd, "%%%%Creator: %s\n", SpinVersion);
  179. fprintf(pfd, "%%%%Title: MSC %s\n", oFname?oFname->name:"--");
  180. fprintf(pfd, "%%%%BoundingBox: 119 154 494 638\n");
  181. ntimes(pfd, 0, 1, PsPre);
  182. if (s_trail)
  183. { if (ntrail)
  184. sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail);
  185. else
  186. sprintf(snap, "%s.trail", oFname?oFname->name:"msc");
  187. if (!(fd = fopen(snap, "r")))
  188. { snap[strlen(snap)-2] = '\0';
  189. if (!(fd = fopen(snap, "r")))
  190. fatal("cannot open trail file", (char *) 0);
  191. }
  192. TotSteps = 1;
  193. while (fgets(snap, 256, fd)) TotSteps++;
  194. fclose(fd);
  195. }
  196. TotSteps += 10;
  197. R = (int *) emalloc(TotSteps * sizeof(int));
  198. D = (int *) emalloc(TotSteps * sizeof(int));
  199. M = (int16_t *) emalloc(TotSteps * sizeof(int16_t));
  200. T = (int16_t *) emalloc(TotSteps * sizeof(int16_t));
  201. L = (char **) emalloc(TotSteps * sizeof(char *));
  202. I = (char **) emalloc(TotSteps * sizeof(char *));
  203. ProcLine = (char *) emalloc(1024 * sizeof(char));
  204. startpage();
  205. }
  206. void
  207. putpostlude(void)
  208. { putpages();
  209. fprintf(pfd, "%%%%Trailer\n");
  210. fprintf(pfd, "end\n");
  211. fprintf(pfd, "%%%%Pages: %d\n", pspno);
  212. fprintf(pfd, "%%%%EOF\n");
  213. fclose(pfd);
  214. /* stderr, in case user redirected output */
  215. fprintf(stderr, "spin: wrote %d pages into '%s.ps'\n",
  216. pspno, oFname?oFname->name:"msc");
  217. exit(0);
  218. }
  219. void
  220. psline(int x0, int iy0, int x1, int iy1, float r, float g, float b, int w)
  221. { int y0 = MH-iy0;
  222. int y1 = MH-iy1;
  223. if (y1 > y0) y1 -= MH;
  224. fprintf(pfd, "gsave\n");
  225. fprintf(pfd, "%d %d moveto\n", x0*WW, y0);
  226. fprintf(pfd, "%d %d lineto\n", x1*WW, y1);
  227. fprintf(pfd, "%d setlinewidth\n", w);
  228. fprintf(pfd, "0 setlinecap\n");
  229. fprintf(pfd, "1 setlinejoin\n");
  230. fprintf(pfd, "%f %f %f setrgbcolor AdjustColor\n", r,g,b);
  231. fprintf(pfd, "stroke\ngrestore\n");
  232. }
  233. void
  234. colbox(int x, int y, int w, int h, float r, float g, float b)
  235. { fprintf(pfd, "%d %d moveto\n", x - w, y-h);
  236. fprintf(pfd, "%d %d lineto\n", x + w, y-h);
  237. fprintf(pfd, "%d %d lineto\n", x + w, y+h);
  238. fprintf(pfd, "%d %d lineto\n", x - w, y+h);
  239. fprintf(pfd, "%d %d lineto\n", x - w, y-h);
  240. fprintf(pfd, "%f %f %f setrgbcolor AdjustColor\n", r,g,b);
  241. fprintf(pfd, "closepath fill\n");
  242. }
  243. void
  244. putgrid(int p)
  245. { int i;
  246. for (i = p ; i >= 0; i--)
  247. { if (!ProcLine[i])
  248. { psline(i, 0, i, MH-1, (float) (0.4), (float) (0.4), (float) (1.0), 1);
  249. ProcLine[i] = 1;
  250. } }
  251. }
  252. void
  253. putarrow(int from, int to)
  254. {
  255. T[D[from]] = D[to];
  256. }
  257. void
  258. stepnumber(int i)
  259. { int y = MH-(i*HH)%MH;
  260. fprintf(pfd, "gsave\n");
  261. fprintf(pfd, "/Courier-Bold findfont 6 scalefont ");
  262. fprintf(pfd, "ISOEncode setfont\n");
  263. fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
  264. fprintf(pfd, "%d %d [\n", -40, y);
  265. fprintf(pfd, " (%d)\n] 10 -0.5 0.5 0 ", R[i]);
  266. fprintf(pfd, "false DrawText\ngrestore\n");
  267. fprintf(pfd, "%d %d moveto\n", -20, y);
  268. fprintf(pfd, "%d %d lineto\n", M[i]*WW, y);
  269. fprintf(pfd, "1 setlinewidth\n0 setlinecap\n1 setlinejoin\n");
  270. fprintf(pfd, "0.92 0.92 0.92 setrgbcolor AdjustColor\n");
  271. fprintf(pfd, "stroke\n");
  272. }
  273. void
  274. spitbox(int x, int dx, int y, char *s)
  275. { float r,g,b, bw; int a; char d[256];
  276. if (!dx)
  277. { stepnumber(y);
  278. putgrid(x);
  279. }
  280. bw = (float)2.7*(float)strlen(s);
  281. colbox(x*WW+dx, MH-(y*HH)%MH, (int) (bw+1.0),
  282. 5, (float) 0.,(float) 0.,(float) 0.);
  283. if (s[0] == '~')
  284. { switch (s[1]) {
  285. case 'B': r = (float) 0.2; g = (float) 0.2; b = (float) 1.;
  286. break;
  287. case 'G': r = (float) 0.2; g = (float) 1.; b = (float) 0.2;
  288. break;
  289. case 'R':
  290. default : r = (float) 1.; g = (float) 0.2; b = (float) 0.2;
  291. break;
  292. }
  293. s += 2;
  294. } else if (strchr(s, '!'))
  295. { r = (float) 1.; g = (float) 1.; b = (float) 1.;
  296. } else if (strchr(s, '?'))
  297. { r = (float) 0.; g = (float) 1.; b = (float) 1.;
  298. } else
  299. { r = (float) 1.; g = (float) 1.; b = (float) 0.;
  300. if (!dx
  301. && sscanf(s, "%d:%250s", &a, d) == 2 /* was &d */
  302. && a >= 0 && a < TotSteps)
  303. { if (!I[a]
  304. || strlen(I[a]) <= strlen(s))
  305. I[a] = emalloc((int) strlen(s)+1);
  306. strcpy(I[a], s);
  307. } }
  308. colbox(x*WW+dx, MH-(y*HH)%MH, (int) bw, 4, r,g,b);
  309. fprintf(pfd, "gsave\n");
  310. fprintf(pfd, "/Courier-Bold findfont 8 scalefont ");
  311. fprintf(pfd, "ISOEncode setfont\n");
  312. fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
  313. fprintf(pfd, "%d %d [\n", x*WW+dx, MH-(y*HH)%MH);
  314. fprintf(pfd, " (%s)\n] 10 -0.5 0.5 0 ", s);
  315. fprintf(pfd, "false DrawText\ngrestore\n");
  316. }
  317. void
  318. putpages(void)
  319. { int i, lasti=0; float nmh;
  320. if (maxx*WW > MW-RH/2)
  321. { Scaler = (float) (MW-RH/2) / (float) (maxx*WW);
  322. fprintf(pfd, "%f %f scale\n", Scaler, Scaler);
  323. nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
  324. }
  325. for (i = TotSteps-1; i >= 0; i--)
  326. { if (!I[i]) continue;
  327. spitbox(i, 0, 0, I[i]);
  328. }
  329. if (ldepth >= TotSteps) ldepth = TotSteps-1;
  330. for (i = 0; i <= ldepth; i++)
  331. { if (!M[i] && !L[i]) continue; /* no box here */
  332. if (6+i*HH >= MH*pspno)
  333. { fprintf(pfd, "showpage\nrestore\n"); startpage(); }
  334. if (T[i] > 0) /* red arrow */
  335. { int reali = i*HH;
  336. int realt = T[i]*HH;
  337. int topop = (reali)/MH; topop *= MH;
  338. reali -= topop; realt -= topop;
  339. if (M[i] == M[T[i]] && reali == realt)
  340. /* an rv handshake */
  341. psline( M[lasti], reali+2-3*HH/2,
  342. M[i], reali,
  343. (float) 1.,(float) 0.,(float) 0., 2);
  344. else
  345. psline( M[i], reali,
  346. M[T[i]], realt,
  347. (float) 1.,(float) 0.,(float) 0., 2);
  348. if (realt >= MH) T[T[i]] = -i;
  349. } else if (T[i] < 0) /* arrow from prev page */
  350. { int reali = (-T[i])*HH;
  351. int realt = i*HH;
  352. int topop = (realt)/MH; topop *= MH;
  353. reali -= topop; realt -= topop;
  354. psline( M[-T[i]], reali,
  355. M[i], realt,
  356. (float) 1., (float) 0., (float) 0., 2);
  357. }
  358. if (L[i])
  359. { spitbox(M[i], 0, i, L[i]);
  360. /* free(L[i]); */
  361. lasti = i;
  362. }
  363. }
  364. fprintf(pfd, "showpage\nrestore\n");
  365. }
  366. void
  367. putbox(int x)
  368. {
  369. if (ldepth >= TotSteps)
  370. { fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n",
  371. TotSteps);
  372. putpostlude();
  373. }
  374. M[ldepth] = x;
  375. if (x > maxx) maxx = x;
  376. }
  377. void
  378. pstext(int x, char *s)
  379. { char *tmp = emalloc((int) strlen(s)+1);
  380. strcpy(tmp, s);
  381. if (depth == 0)
  382. I[x] = tmp;
  383. else
  384. { putbox(x);
  385. if (depth >= TotSteps || ldepth >= TotSteps)
  386. { fprintf(stderr, "max nr of %d steps exceeded\n",
  387. TotSteps);
  388. fatal("aborting", (char *) 0);
  389. }
  390. D[depth] = ldepth;
  391. R[ldepth] = depth;
  392. L[ldepth] = tmp;
  393. ldepth += 2;
  394. }
  395. }
  396. void
  397. dotag(FILE *fd, char *s)
  398. { extern int columns, notabs; extern RunList *X;
  399. int i = (!strncmp(s, "MSC: ", 5))?5:0;
  400. int pid = s_trail ? pno : (X?X->pid:0);
  401. if (columns == 2)
  402. pstext(pid, &s[i]);
  403. else
  404. { if (!notabs)
  405. { printf(" ");
  406. for (i = 0; i <= pid; i++)
  407. printf(" ");
  408. }
  409. fprintf(fd, "%s", s);
  410. fflush(fd);
  411. }
  412. }