posttek.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. /*
  2. *
  3. * posttek - PostScript translator for tektronix 4014 files
  4. *
  5. * A program that can be used to translate tektronix 4014 files into PostScript.
  6. * Most of the code was borrowed from the tektronix 4014 emulator that was written
  7. * for DMDs. Things have been cleaned up some, but there's still plently that
  8. * could be done.
  9. *
  10. * The PostScript prologue is copied from *prologue before any of the input files
  11. * are translated. The program expects that the following PostScript procedures
  12. * are defined in that file:
  13. *
  14. * setup
  15. *
  16. * mark ... setup -
  17. *
  18. * Handles special initialization stuff that depends on how the program
  19. * was called. Expects to find a mark followed by key/value pairs on the
  20. * stack. The def operator is applied to each pair up to the mark, then
  21. * the default state is set up.
  22. *
  23. * pagesetup
  24. *
  25. * page pagesetup -
  26. *
  27. * Does whatever is needed to set things up for the next page. Expects
  28. * to find the current page number on the stack.
  29. *
  30. * v
  31. *
  32. * mark dx1 dy1 ... dxn dyn x y v mark
  33. *
  34. * Draws the vector described by the numbers on the stack. The top two
  35. * numbers are the starting point. The rest are relative displacements
  36. * from the preceeding point. Must make sure we don't put too much on
  37. * the stack!
  38. *
  39. * t
  40. *
  41. * x y string t -
  42. *
  43. * Prints the string that's on the top of the stack starting at point
  44. * (x, y).
  45. *
  46. * p
  47. *
  48. * x y p -
  49. *
  50. * Marks the point (x, y) with a circle whose radius varies with the
  51. * current intensity setting.
  52. *
  53. * i
  54. *
  55. * percent focus i -
  56. *
  57. * Changes the size of the circle used to mark individual points to
  58. * percent of maximum for focused mode (focus=1) or defocused mode
  59. * (focus=0). The implementation leaves much to be desired!
  60. *
  61. * l
  62. *
  63. * mark array l mark
  64. *
  65. * Set the line drawing mode according to the description given in array.
  66. * The arrays that describe the different line styles are declared in
  67. * STYLES (file posttek.h). The array really belongs in the prologue!
  68. *
  69. * w
  70. *
  71. * n w -
  72. *
  73. * Adjusts the line width for vector drawing. Used to select normal (n=0)
  74. * or defocused (n=1) mode.
  75. *
  76. * f
  77. *
  78. * size f -
  79. *
  80. * Changes the size of the font that's used to print characters in alpha
  81. * mode. size is the tektronix character width and is used to choose an
  82. * appropriate point size in the current font.
  83. *
  84. * done
  85. *
  86. * done
  87. *
  88. * Makes sure the last page is printed. Only needed when we're printing
  89. * more than one page on each sheet of paper.
  90. *
  91. * The default line width is zero, which forces lines to be one pixel wide. That
  92. * works well on 'write to black' engines but won't be right for 'write to white'
  93. * engines. The line width can be changed using the -w option, or you can change
  94. * the initialization of linewidth in the prologue.
  95. *
  96. * Many default values, like the magnification and orientation, are defined in
  97. * the prologue, which is where they belong. If they're changed (by options), an
  98. * appropriate definition is made after the prologue is added to the output file.
  99. * The -P option passes arbitrary PostScript through to the output file. Among
  100. * other things it can be used to set (or change) values that can't be accessed by
  101. * other options.
  102. *
  103. */
  104. #include <stdio.h>
  105. #include <signal.h>
  106. #include <sys/types.h>
  107. #include <fcntl.h>
  108. #include "comments.h" /* PostScript file structuring comments */
  109. #include "gen.h" /* general purpose definitions */
  110. #include "path.h" /* for the prologue */
  111. #include "ext.h" /* external variable definitions */
  112. #include "posttek.h" /* control codes and other definitions */
  113. char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI";
  114. char *prologue = POSTTEK; /* default PostScript prologue */
  115. char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
  116. int formsperpage = 1; /* page images on each piece of paper */
  117. int copies = 1; /* and this many copies of each sheet */
  118. int charheight[] = CHARHEIGHT; /* height */
  119. int charwidth[] = CHARWIDTH; /* and width arrays for tek characters */
  120. int tekfont = TEKFONT; /* index into charheight[] and charwidth[] */
  121. char intensity[] = INTENSITY; /* special point intensity array */
  122. char *styles[] = STYLES; /* description of line styles */
  123. int linestyle = 0; /* index into styles[] */
  124. int linetype = 0; /* 0 for normal, 1 for defocused */
  125. int dispmode = ALPHA; /* current tektronix state */
  126. int points = 0; /* points making up the current vector */
  127. int characters = 0; /* characters waiting to be printed */
  128. int pen = UP; /* just for point plotting */
  129. int margin = 0; /* left edge - ALPHA state */
  130. Point cursor; /* should be current cursor position */
  131. Fontmap fontmap[] = FONTMAP; /* for translating font names */
  132. char *fontname = "Courier"; /* use this PostScript font */
  133. int page = 0; /* page we're working on */
  134. int printed = 0; /* printed this many pages */
  135. FILE *fp_in; /* read from this file */
  136. FILE *fp_out = stdout; /* and write stuff here */
  137. FILE *fp_acct = NULL; /* for accounting data */
  138. /*****************************************************************************/
  139. main(agc, agv)
  140. int agc;
  141. char *agv[];
  142. {
  143. /*
  144. *
  145. * A simple program that can be used to translate tektronix 4014 files into
  146. * PostScript. Most of the code was taken from the DMD tektronix 4014 emulator,
  147. * although things have been cleaned up some.
  148. *
  149. */
  150. argv = agv; /* so everyone can use them */
  151. argc = agc;
  152. prog_name = argv[0]; /* just for error messages */
  153. init_signals(); /* sets up interrupt handling */
  154. header(); /* PostScript header comments */
  155. options(); /* handle the command line options */
  156. setup(); /* for PostScript */
  157. arguments(); /* followed by each input file */
  158. done(); /* print the last page etc. */
  159. account(); /* job accounting data */
  160. exit(x_stat); /* nothing could be wrong */
  161. } /* End of main */
  162. /*****************************************************************************/
  163. init_signals()
  164. {
  165. /*
  166. *
  167. * Make sure we handle interrupts.
  168. *
  169. */
  170. if ( signal(SIGINT, interrupt) == SIG_IGN ) {
  171. signal(SIGINT, SIG_IGN);
  172. signal(SIGQUIT, SIG_IGN);
  173. signal(SIGHUP, SIG_IGN);
  174. } else {
  175. signal(SIGHUP, interrupt);
  176. signal(SIGQUIT, interrupt);
  177. } /* End else */
  178. signal(SIGTERM, interrupt);
  179. } /* End of init_signals */
  180. /*****************************************************************************/
  181. header()
  182. {
  183. int ch; /* return value from getopt() */
  184. int old_optind = optind; /* for restoring optind - should be 1 */
  185. /*
  186. *
  187. * Scans the option list looking for things, like the prologue file, that we need
  188. * right away but could be changed from the default. Doing things this way is an
  189. * attempt to conform to Adobe's latest file structuring conventions. In particular
  190. * they now say there should be nothing executed in the prologue, and they have
  191. * added two new comments that delimit global initialization calls. Once we know
  192. * where things really are we write out the job header, follow it by the prologue,
  193. * and then add the ENDPROLOG and BEGINSETUP comments.
  194. *
  195. */
  196. while ( (ch = getopt(argc, argv, optnames)) != EOF )
  197. if ( ch == 'L' )
  198. prologue = optarg;
  199. else if ( ch == '?' )
  200. error(FATAL, "");
  201. optind = old_optind; /* get ready for option scanning */
  202. fprintf(stdout, "%s", CONFORMING);
  203. fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
  204. fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
  205. fprintf(stdout, "%s %s\n", PAGES, ATEND);
  206. fprintf(stdout, "%s", ENDCOMMENTS);
  207. if ( cat(prologue) == FALSE )
  208. error(FATAL, "can't read %s", prologue);
  209. fprintf(stdout, "%s", ENDPROLOG);
  210. fprintf(stdout, "%s", BEGINSETUP);
  211. fprintf(stdout, "mark\n");
  212. } /* End of header */
  213. /*****************************************************************************/
  214. options()
  215. {
  216. int ch; /* value returned by getopt() */
  217. /*
  218. *
  219. * Reads and processes the command line options. Added the -P option so arbitrary
  220. * PostScript code can be passed through. Expect it could be useful for changing
  221. * definitions in the prologue for which options have not been defined.
  222. *
  223. */
  224. while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
  225. switch ( ch ) {
  226. case 'a': /* aspect ratio */
  227. fprintf(stdout, "/aspectratio %s def\n", optarg);
  228. break;
  229. case 'c': /* copies */
  230. copies = atoi(optarg);
  231. fprintf(stdout, "/#copies %s store\n", optarg);
  232. break;
  233. case 'f': /* use this PostScript font */
  234. fontname = get_font(optarg);
  235. fprintf(stdout, "/font /%s def\n", fontname);
  236. break;
  237. case 'm': /* magnification */
  238. fprintf(stdout, "/magnification %s def\n", optarg);
  239. break;
  240. case 'n': /* forms per page */
  241. formsperpage = atoi(optarg);
  242. fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
  243. fprintf(stdout, "/formsperpage %s def\n", optarg);
  244. break;
  245. case 'o': /* output page list */
  246. out_list(optarg);
  247. break;
  248. case 'p': /* landscape or portrait mode */
  249. if ( *optarg == 'l' )
  250. fprintf(stdout, "/landscape true def\n");
  251. else fprintf(stdout, "/landscape false def\n");
  252. break;
  253. case 'w': /* line width */
  254. fprintf(stdout, "/linewidth %s def\n", optarg);
  255. break;
  256. case 'x': /* shift horizontally */
  257. fprintf(stdout, "/xoffset %s def\n", optarg);
  258. break;
  259. case 'y': /* and vertically on the page */
  260. fprintf(stdout, "/yoffset %s def\n", optarg);
  261. break;
  262. case 'A': /* force job accounting */
  263. case 'J':
  264. if ( (fp_acct = fopen(optarg, "a")) == NULL )
  265. error(FATAL, "can't open accounting file %s", optarg);
  266. break;
  267. case 'C': /* copy file straight to output */
  268. if ( cat(optarg) == FALSE )
  269. error(FATAL, "can't read %s", optarg);
  270. break;
  271. case 'E': /* text font encoding */
  272. fontencoding = optarg;
  273. break;
  274. case 'L': /* PostScript prologue file */
  275. prologue = optarg;
  276. break;
  277. case 'P': /* PostScript pass through */
  278. fprintf(stdout, "%s\n", optarg);
  279. break;
  280. case 'R': /* special global or page level request */
  281. saverequest(optarg);
  282. break;
  283. case 'D': /* debug flag */
  284. debug = ON;
  285. break;
  286. case 'I': /* ignore FATAL errors */
  287. ignore = ON;
  288. break;
  289. case '?': /* don't know the option */
  290. error(FATAL, "");
  291. break;
  292. default: /* don't know what to do for ch */
  293. error(FATAL, "missing case for option %c", ch);
  294. break;
  295. } /* End switch */
  296. } /* End while */
  297. argc -= optind;
  298. argv += optind;
  299. } /* End of options */
  300. /*****************************************************************************/
  301. char *get_font(name)
  302. char *name; /* name the user asked for */
  303. {
  304. int i; /* for looking through fontmap[] */
  305. /*
  306. *
  307. * Called from options() to map a user's font name into a legal PostScript name.
  308. * If the lookup fails *name is returned to the caller. That should let you choose
  309. * any PostScript font.
  310. *
  311. */
  312. for ( i = 0; fontmap[i].name != NULL; i++ )
  313. if ( strcmp(name, fontmap[i].name) == 0 )
  314. return(fontmap[i].val);
  315. return(name);
  316. } /* End of get_font */
  317. /*****************************************************************************/
  318. setup()
  319. {
  320. /*
  321. *
  322. * Handles things that must be done after the options are read but before the
  323. * input files are processed.
  324. *
  325. */
  326. writerequest(0, stdout); /* global requests eg. manual feed */
  327. setencoding(fontencoding);
  328. fprintf(stdout, "setup\n");
  329. if ( formsperpage > 1 ) {
  330. if ( cat(formfile) == FALSE )
  331. error(FATAL, "can't read %s", formfile);
  332. fprintf(stdout, "%d setupforms\n", formsperpage);
  333. } /* End if */
  334. fprintf(stdout, "%s", ENDSETUP);
  335. } /* End of setup */
  336. /*****************************************************************************/
  337. arguments()
  338. {
  339. /*
  340. *
  341. * Makes sure all the non-option command line arguments are processed. If we get
  342. * here and there aren't any arguments left, or if '-' is one of the input files
  343. * we'll process stdin.
  344. *
  345. */
  346. if ( argc < 1 )
  347. statemachine(fp_in = stdin);
  348. else { /* at least one argument is left */
  349. while ( argc > 0 ) {
  350. if ( strcmp(*argv, "-") == 0 )
  351. fp_in = stdin;
  352. else if ( (fp_in = fopen(*argv, "r")) == NULL )
  353. error(FATAL, "can't open %s", *argv);
  354. statemachine(fp_in);
  355. if ( fp_in != stdin )
  356. fclose(fp_in);
  357. argc--;
  358. argv++;
  359. } /* End while */
  360. } /* End else */
  361. } /* End of arguments */
  362. /*****************************************************************************/
  363. done()
  364. {
  365. /*
  366. *
  367. * Finished with all the input files, so mark the end of the pages with a TRAILER
  368. * comment, make sure the last page prints, and add things like the PAGES comment
  369. * that can only be determined after all the input files have been read.
  370. *
  371. */
  372. fprintf(stdout, "%s", TRAILER);
  373. fprintf(stdout, "done\n");
  374. fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
  375. fprintf(stdout, "%s %d\n", PAGES, printed);
  376. } /* End of done */
  377. /*****************************************************************************/
  378. account()
  379. {
  380. /*
  381. *
  382. * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
  383. * is requested using the -A or -J options.
  384. *
  385. */
  386. if ( fp_acct != NULL )
  387. fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
  388. } /* End of account */
  389. /*****************************************************************************/
  390. statemachine(fp)
  391. FILE *fp; /* used to set fp_in */
  392. {
  393. /*
  394. *
  395. * Controls the translation of the next input file. Tektronix states (dispmode)
  396. * are typically changed in control() and esc().
  397. *
  398. */
  399. redirect(-1); /* get ready for the first page */
  400. formfeed();
  401. dispmode = RESET;
  402. while ( 1 )
  403. switch ( dispmode ) {
  404. case RESET:
  405. reset();
  406. break;
  407. case ALPHA:
  408. alpha();
  409. break;
  410. case GIN:
  411. gin();
  412. break;
  413. case GRAPH:
  414. graph();
  415. break;
  416. case POINT:
  417. case SPECIALPOINT:
  418. point();
  419. break;
  420. case INCREMENTAL:
  421. incremental();
  422. break;
  423. case EXIT:
  424. formfeed();
  425. return;
  426. } /* End switch */
  427. } /* End of statemachine */
  428. /*****************************************************************************/
  429. reset()
  430. {
  431. /*
  432. *
  433. * Called to reset things, typically only at the beginning of each input file.
  434. *
  435. */
  436. tekfont = -1;
  437. home();
  438. setfont(TEKFONT);
  439. setmode(ALPHA);
  440. } /* End of reset */
  441. /*****************************************************************************/
  442. alpha()
  443. {
  444. int c; /* next character */
  445. int x, y; /* cursor will be here when we're done */
  446. /*
  447. *
  448. * Takes care of printing characters in the current font.
  449. *
  450. */
  451. if ( (c = nextchar()) == OUTMODED )
  452. return;
  453. if ( (c < 040) && ((c = control(c)) <= 0) )
  454. return;
  455. x = cursor.x; /* where the cursor is right now */
  456. y = cursor.y;
  457. switch ( c ) {
  458. case DEL:
  459. return;
  460. case BS:
  461. if ((x -= charwidth[tekfont]) < margin)
  462. x = TEKXMAX - charwidth[tekfont];
  463. break;
  464. case NL:
  465. y -= charheight[tekfont];
  466. break;
  467. case CR:
  468. x = margin;
  469. break;
  470. case VT:
  471. if ((y += charheight[tekfont]) >= TEKYMAX)
  472. y = 0;
  473. break;
  474. case HT:
  475. case ' ':
  476. default:
  477. if ( characters++ == 0 )
  478. fprintf(fp_out, "%d %d (", cursor.x, cursor.y);
  479. switch ( c ) {
  480. case '(':
  481. case ')':
  482. case '\\':
  483. putc('\\', fp_out);
  484. default:
  485. putc(c, fp_out);
  486. } /* End switch */
  487. x += charwidth[tekfont];
  488. move(x, y);
  489. break;
  490. } /* End switch */
  491. if (x >= TEKXMAX) {
  492. x = margin;
  493. y -= charheight[tekfont];
  494. } /* End if */
  495. if (y < 0) {
  496. y = TEKYMAX - charheight[tekfont];
  497. x -= margin;
  498. margin = (TEKXMAX/2) - margin;
  499. if ((x += margin) > TEKXMAX)
  500. x -= margin;
  501. } /* End if */
  502. if ( y != cursor.y || x != cursor.x )
  503. text();
  504. move(x, y);
  505. } /* End of alpha */
  506. /*****************************************************************************/
  507. graph()
  508. {
  509. int c; /* next character */
  510. int b; /* for figuring out loy */
  511. int x, y; /* next point in the vector */
  512. static int hix, hiy; /* upper */
  513. static int lox, loy; /* and lower part of the address */
  514. static int extra; /* for extended addressing */
  515. /*
  516. *
  517. * Handles things when we're in GRAPH, POINT, or SPECIALPOINT mode.
  518. *
  519. */
  520. if ((c = nextchar()) < 040) {
  521. control(c);
  522. return;
  523. } /* End if */
  524. if ((c & 0140) == 040) { /* new hiy */
  525. hiy = c & 037;
  526. do
  527. if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
  528. return;
  529. while (c == 0);
  530. } /* End if */
  531. if ((c & 0140) == 0140) { /* new loy */
  532. b = c & 037;
  533. do
  534. if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
  535. return;
  536. while (c == 0);
  537. if ((c & 0140) == 0140) { /* no, it was extra */
  538. extra = b;
  539. loy = c & 037;
  540. do
  541. if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
  542. return;
  543. while (c == 0);
  544. } else loy = b;
  545. } /* End if */
  546. if ((c & 0140) == 040) { /* new hix */
  547. hix = c & 037;
  548. do
  549. if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED))
  550. return;
  551. while (c == 0);
  552. } /* End if */
  553. lox = c & 037; /* this should be lox */
  554. if (extra & 020)
  555. margin = TEKXMAX/2;
  556. x = (hix<<7) | (lox<<2) | (extra & 03);
  557. y = (hiy<<7) | (loy<<2) | ((extra & 014)>>2);
  558. if ( points > 100 ) { /* don't put too much on the stack */
  559. draw();
  560. points = 1;
  561. } /* End if */
  562. if ( points++ )
  563. fprintf(fp_out, "%d %d\n", cursor.x - x, cursor.y - y);
  564. move(x, y); /* adjust the cursor */
  565. } /* End of graph */
  566. /*****************************************************************************/
  567. point()
  568. {
  569. int c; /* next input character */
  570. /*
  571. *
  572. * Special point mode permits gray scaling by varying the size of the stored
  573. * point, which is controlled by an intensity character that preceeds each point
  574. * address.
  575. *
  576. */
  577. if ( dispmode == SPECIALPOINT ) {
  578. if ( (c = nextchar()) < 040 || c > 0175 )
  579. return(control(c));
  580. fprintf(fp_out, "%d %d i\n", intensity[c - ' '], c & 0100);
  581. } /* End if */
  582. graph();
  583. draw();
  584. } /* End of point */
  585. /*****************************************************************************/
  586. incremental()
  587. {
  588. int c; /* for the next few characters */
  589. int x, y; /* cursor position when we're done */
  590. /*
  591. *
  592. * Handles incremental plot mode. It's entered after the RS control code and is
  593. * used to mark points relative to our current position. It's typically followed
  594. * by one or two bytes that set the pen state and are used to increment the
  595. * current position.
  596. *
  597. */
  598. if ( (c = nextchar()) == OUTMODED )
  599. return;
  600. if ( (c < 040) && ((c = control(c)) <= 0) )
  601. return;
  602. x = cursor.x; /* where we are right now */
  603. y = cursor.y;
  604. if ( c & 060 )
  605. pen = ( c & 040 ) ? UP : DOWN;
  606. if ( c & 04 ) y++;
  607. if ( c & 010 ) y--;
  608. if ( c & 01 ) x++;
  609. if ( c & 02 ) x--;
  610. move(x, y);
  611. if ( pen == DOWN ) {
  612. points = 1;
  613. draw();
  614. } /* End if */
  615. } /* End of incremental */
  616. /*****************************************************************************/
  617. gin()
  618. {
  619. /*
  620. *
  621. * All we really have to do for GIN mode is make sure it's properly ended.
  622. *
  623. */
  624. control(nextchar());
  625. } /* End of gin */
  626. /*****************************************************************************/
  627. control(c)
  628. int c; /* check this control character */
  629. {
  630. /*
  631. *
  632. * Checks character c and does special things, like mode changes, that depend
  633. * not only on the character, but also on the current state. If the mode changed
  634. * becuase of c, OUTMODED is returned to the caller. In all other cases the
  635. * return value is c or 0, if c doesn't make sense in the current mode.
  636. *
  637. */
  638. switch ( c ) {
  639. case BEL:
  640. return(0);
  641. case BS:
  642. case HT:
  643. case VT:
  644. return(dispmode == ALPHA ? c : 0);
  645. case CR:
  646. if ( dispmode != ALPHA ) {
  647. setmode(ALPHA);
  648. ungetc(c, fp_in);
  649. return(OUTMODED);
  650. } else return(c);
  651. case FS:
  652. if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) {
  653. setmode(POINT);
  654. return(OUTMODED);
  655. } /* End if */
  656. return(0);
  657. case GS:
  658. if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) {
  659. setmode(GRAPH);
  660. return(OUTMODED);
  661. } /* End if */
  662. return(0);
  663. case NL:
  664. ungetc(CR, fp_in);
  665. return(dispmode == ALPHA ? c : 0);
  666. case RS:
  667. if ( dispmode != GIN ) {
  668. setmode(INCREMENTAL);
  669. return(OUTMODED);
  670. } /* End if */
  671. return(0);
  672. case US:
  673. if ( dispmode == ALPHA )
  674. return(0);
  675. setmode(ALPHA);
  676. return(OUTMODED);
  677. case ESC:
  678. return(esc());
  679. case OUTMODED:
  680. return(c);
  681. default:
  682. return(c < 040 ? 0 : c);
  683. } /* End switch */
  684. } /* End of control */
  685. /*****************************************************************************/
  686. esc()
  687. {
  688. int c; /* next input character */
  689. int ignore; /* skip it if nonzero */
  690. /*
  691. *
  692. * Handles tektronix escape code. Called from control() whenever an ESC character
  693. * is found in the input file.
  694. *
  695. */
  696. do {
  697. c = nextchar();
  698. ignore = 0;
  699. switch ( c ) {
  700. case CAN:
  701. return(0);
  702. case CR:
  703. ignore = 1;
  704. break;
  705. case ENQ:
  706. setmode(ALPHA);
  707. return(OUTMODED);
  708. case ETB:
  709. return(0);
  710. case FF:
  711. formfeed();
  712. setmode(ALPHA);
  713. return(OUTMODED);
  714. case FS:
  715. if ( (dispmode == INCREMENTAL) || ( dispmode == GIN) )
  716. return(0);
  717. setmode(SPECIALPOINT);
  718. return(OUTMODED);
  719. case SI:
  720. case SO:
  721. return(0);
  722. case SUB:
  723. setmode(GIN);
  724. return(OUTMODED);
  725. case OUTMODED:
  726. return(OUTMODED);
  727. case '8':
  728. case '9':
  729. case ':':
  730. case ';':
  731. setfont(c - '8');
  732. return(0);
  733. default:
  734. if ( c == '?' && dispmode == GRAPH )
  735. return(DEL);
  736. if ( (c<'`') || (c>'w') )
  737. break;
  738. c -= '`';
  739. if ( (c & 010) != linetype )
  740. fprintf(fp_out, "%d w\n", (linetype = (c & 010))/010);
  741. if ( ((c + 1) & 7) >= 6 )
  742. break;
  743. if ( (c + 1) & 7 )
  744. if ( (c & 7) != linestyle ) {
  745. linestyle = c & 7;
  746. setmode(dispmode);
  747. fprintf(fp_out, "%s l\n", styles[linestyle]);
  748. } /* End if */
  749. return(0);
  750. } /* End switch */
  751. } while (ignore);
  752. return(0);
  753. } /* End of esc */
  754. /*****************************************************************************/
  755. move(x, y)
  756. int x, y; /* move the cursor here */
  757. {
  758. /*
  759. *
  760. * Moves the cursor to the point (x, y).
  761. *
  762. */
  763. cursor.x = x;
  764. cursor.y = y;
  765. } /* End of move */
  766. /*****************************************************************************/
  767. setmode(mode)
  768. int mode; /* this should be the new mode */
  769. {
  770. /*
  771. *
  772. * Makes sure the current mode is properly ended and then sets dispmode to mode.
  773. *
  774. */
  775. switch ( dispmode ) {
  776. case ALPHA:
  777. text();
  778. break;
  779. case GRAPH:
  780. draw();
  781. break;
  782. case INCREMENTAL:
  783. pen = UP;
  784. break;
  785. } /* End switch */
  786. dispmode = mode;
  787. } /* End of setmode */
  788. /*****************************************************************************/
  789. home()
  790. {
  791. /*
  792. *
  793. * Makes sure the cursor is positioned at the upper left corner of the page.
  794. *
  795. */
  796. margin = 0;
  797. move(0, TEKYMAX);
  798. } /* End of home */
  799. /*****************************************************************************/
  800. setfont(newfont)
  801. int newfont; /* use this font next */
  802. {
  803. /*
  804. *
  805. * Generates the call to the procedure that's responsible for changing the
  806. * tektronix font (really just the size).
  807. *
  808. */
  809. if ( newfont != tekfont ) {
  810. setmode(dispmode);
  811. fprintf(fp_out, "%d f\n", charwidth[newfont]);
  812. } /* End if */
  813. tekfont = newfont;
  814. } /* End of setfont */
  815. /*****************************************************************************/
  816. text()
  817. {
  818. /*
  819. *
  820. * Makes sure any text we've put on the stack is printed.
  821. *
  822. */
  823. if ( dispmode == ALPHA && characters > 0 )
  824. fprintf(fp_out, ") t\n");
  825. characters = 0;
  826. } /* End of text */
  827. /*****************************************************************************/
  828. draw()
  829. {
  830. /*
  831. *
  832. * Called whenever we need to draw a vector or plot a point. Nothing will be
  833. * done if points is 0 or if it's 1 and we're in GRAPH mode.
  834. *
  835. */
  836. if ( points > 1 ) /* it's a vector */
  837. fprintf(fp_out, "%d %d v\n", cursor.x, cursor.y);
  838. else if ( points == 1 && dispmode != GRAPH )
  839. fprintf(fp_out, "%d %d p\n", cursor.x, cursor.y);
  840. points = 0;
  841. } /* End of draw */
  842. /*****************************************************************************/
  843. formfeed()
  844. {
  845. /*
  846. *
  847. * Usually called when we've finished the last page and want to get ready for the
  848. * next one. Also used at the beginning and end of each input file, so we have to
  849. * be careful about exactly what's done.
  850. *
  851. */
  852. setmode(dispmode); /* end any outstanding text or graphics */
  853. if ( fp_out == stdout ) /* count the last page */
  854. printed++;
  855. fprintf(fp_out, "cleartomark\n");
  856. fprintf(fp_out, "showpage\n");
  857. fprintf(fp_out, "saveobj restore\n");
  858. fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
  859. if ( ungetc(getc(fp_in), fp_in) == EOF )
  860. redirect(-1);
  861. else redirect(++page);
  862. fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
  863. fprintf(fp_out, "/saveobj save def\n");
  864. fprintf(fp_out, "mark\n");
  865. writerequest(printed+1, fp_out);
  866. fprintf(fp_out, "%d pagesetup\n", printed+1);
  867. fprintf(fp_out, "%d f\n", charwidth[tekfont]);
  868. fprintf(fp_out, "%s l\n", styles[linestyle]);
  869. home();
  870. } /* End of formfeed */
  871. /*****************************************************************************/
  872. nextchar()
  873. {
  874. int ch; /* next input character */
  875. /*
  876. *
  877. * Reads the next character from the current input file and returns it to the
  878. * caller. When we're finished with the file dispmode is set to EXIT and OUTMODED
  879. * is returned to the caller.
  880. *
  881. */
  882. if ( (ch = getc(fp_in)) == EOF ) {
  883. setmode(EXIT);
  884. ch = OUTMODED;
  885. } /* End if */
  886. return(ch);
  887. } /* End of nextchar */
  888. /*****************************************************************************/
  889. redirect(pg)
  890. int pg; /* next page we're printing */
  891. {
  892. static FILE *fp_null = NULL; /* if output is turned off */
  893. /*
  894. *
  895. * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
  896. * otherwise output goes to stdout.
  897. *
  898. */
  899. if ( pg >= 0 && in_olist(pg) == ON )
  900. fp_out = stdout;
  901. else if ( (fp_out = fp_null) == NULL )
  902. fp_out = fp_null = fopen("/dev/null", "w");
  903. } /* End of redirect */
  904. /*****************************************************************************/