ps_msc.c 12 KB

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