ps_msc.c 11 KB

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