tek2plot.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1989,
  2. 1990, 1991, 1995, 1996, 1997, 1998, 1999, 2000, 2005, 2008, 2009, Free
  3. Software Foundation, Inc.
  4. The GNU plotutils package is free software. You may redistribute it
  5. and/or modify it under the terms of the GNU General Public License as
  6. published by the Free Software foundation; either version 2, or (at your
  7. option) any later version.
  8. The GNU plotutils package is distributed in the hope that it will be
  9. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with the GNU plotutils package; see the file COPYING. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  15. Boston, MA 02110-1301, USA. */
  16. /* This file is the main routine for GNU tek2plot. It reads a stream of
  17. Tektronix commands and draws graphics in real time by calling the
  18. appropriate routines in GNU libplot. Written by Robert S. Maier
  19. <rsm@math.arizona.edu>. Based on earlier work by Rich Murphey and by
  20. Edward Moy <moy@parc.xerox.com>.
  21. The table-driven parser is based on the one written by Ed at Berkeley in
  22. the mid-'80s. The parsing tables in Tektable.c are essentially the same
  23. as the ones he designed for his `tek2ps' utility and for the Tektronix
  24. emulator included in the X10 and X11 versions of xterm(1). */
  25. /* The basic reference on the features of the Tektronix 4014 with extended
  26. graphics module (EGM), which is what we emulate, is the 4014 Service
  27. Manual (Tektronix Part #070-1648-00, dated 8/74; there is also a User
  28. Manual [Part #070-1647-00]).
  29. The code below emulates the non-interactive features of a Tektronix 4014
  30. with EGM [Extended Graphics Module], though not the interactive ones
  31. such as GIN mode or status inquiry. It also doesn't support
  32. write-through mode or beam defocusing. It does support the ANSI color
  33. extensions (ISO-6429) recognized by the MS-DOS Kermit v2.31 Tektronix
  34. emulator. It also recognizes, and ignores, the VT340-style control
  35. sequences ESC [ ?38h (switch to Tektronix mode), ESC [ ?38l (switch to
  36. native mode), and ESC ^C (switch to native mode), which are used by some
  37. Tektronix emulators. */
  38. #include "sys-defines.h"
  39. #include "libcommon.h"
  40. #include "getopt.h"
  41. #include "fontlist.h"
  42. #include "plot.h"
  43. #include "Tekparse.h"
  44. const char *progname = "tek2plot"; /* name of this program */
  45. const char *written = "Written by Robert S. Maier.";
  46. const char *copyright = "Copyright (C) 2009 Free Software Foundation, Inc.";
  47. const char *usage_appendage = " [FILE]...\n\
  48. With no FILE, or when FILE is -, read standard input.\n";
  49. /* Default font, ideally monospaced. Each character in the font should
  50. ideally have a width equal to CHAR_WIDTH em, i.e. a width equal to
  51. CHAR_WIDTH times the font size. */
  52. #define CHAR_WIDTH 0.6 /* valid for Courier family, at least */
  53. #define DEFAULT_PS_FONT_NAME "Courier"
  54. #define DEFAULT_PCL_FONT_NAME "Courier"
  55. #define DEFAULT_HERSHEY_FONT_NAME "HersheySerif" /* not monospaced */
  56. /* Coordinates in Tek file should be in range [0..4095]x[0..3119]. So to
  57. center points within a virtual graphics display of size
  58. [0..4095]x[0..4095], we add 488 to each y coordinate. */
  59. #define TEK_WIDTH 4096
  60. #define YOFFSET 488
  61. /* Font size of the libplot marker symbol used to represent a `point', in
  62. Tek units. We represent a Tektronix point by marker symbol #1, i.e. a
  63. dot (filled circle), which by convention has diameter 3/32 times the
  64. font size. [See libplot/g_mark.c.] So to get a diameter of 1 Tek unit,
  65. we choose 10 here. */
  66. #define DOT_SIZE 10
  67. /* parse tables in Tektable.c */
  68. extern int Talptable[];
  69. extern int Tbestable[];
  70. extern int Tbyptable[];
  71. extern int Tesctable[];
  72. extern int Tipltable[];
  73. extern int Tplttable[];
  74. extern int Tpttable[];
  75. extern int Tspttable[];
  76. /* maximum size ANSI escape sequence we can handle */
  77. #define BUFFER_SIZE 128
  78. /* metrics for the four Tektronix fonts */
  79. struct Tek_Char
  80. {
  81. int hsize; /* in Tek units */
  82. int vsize; /* in Tek units */
  83. int charsperline;
  84. int nlines;
  85. };
  86. static const struct Tek_Char TekChar[4] =
  87. {
  88. {56, 88, 74, 35}, /* large */
  89. {51, 82, 81, 38}, /* #2 */
  90. {34, 53, 121, 58}, /* #3 */
  91. {31, 48, 133, 64}, /* small */
  92. };
  93. #define TEXT_BUFFER_SIZE 256 /* must be able to handle a full line */
  94. /* Tektronix line types */
  95. const char *linemodes[8] =
  96. {
  97. "solid", "dotted", "dotdashed", "shortdashed", "longdashed",
  98. "solid", "solid", "solid" /* final three treated as solid */
  99. };
  100. #define TEKHOME ((TekChar[fontsize].nlines - 1)\
  101. * TekChar[fontsize].vsize)
  102. #define MARGIN1 0 /* i.e. left edge */
  103. #define MARGIN2 1 /* i.e. half-way across page */
  104. enum { PENDOWN, PENUP };
  105. enum { NORTH = 04, SOUTH = 010, EAST = 01, WEST = 02 };
  106. #define PRINTABLE_ASCII(c) ((c >= 0x20) && (c <= 0x7E))
  107. #define BEL 07
  108. /* masks for coordinate-reading DFA */
  109. #define ONE_BIT (0x1)
  110. #define TWO_BITS (0x3)
  111. #define FOUR_BITS (0x0f)
  112. #define FIVE_BITS (0x1f)
  113. #define TEN_BITS (0x3ff)
  114. /* options */
  115. #define ARG_NONE 0
  116. #define ARG_REQUIRED 1
  117. #define ARG_OPTIONAL 2
  118. const char *optstring = "Op:F:W:T:";
  119. struct option long_options[] =
  120. {
  121. /* The most important option ("--display-type" is an obsolete variant) */
  122. { "output-format", ARG_REQUIRED, NULL, 'T'},
  123. { "display-type", ARG_REQUIRED, NULL, 'T' << 8 }, /* hidden */
  124. /* Other frequently used options */
  125. { "bg-color", ARG_REQUIRED, NULL, 'q' << 8 },
  126. { "bitmap-size", ARG_REQUIRED, NULL, 'B' << 8 },
  127. { "emulate-color", ARG_REQUIRED, NULL, 'e' << 8 },
  128. { "font-name", ARG_REQUIRED, NULL, 'F' },
  129. { "line-width", ARG_REQUIRED, NULL, 'W' },
  130. { "pen-color", ARG_REQUIRED, NULL, 'C' << 8 },
  131. { "max-line-length", ARG_REQUIRED, NULL, 'M' << 8 },
  132. { "page-number", ARG_REQUIRED, NULL, 'p' },
  133. { "page-size", ARG_REQUIRED, NULL, 'P' << 8 },
  134. { "position-chars", ARG_NONE, NULL, 'S' << 8 },
  135. { "rotation", ARG_REQUIRED, NULL, 'r' << 8},
  136. { "use-tek-fonts", ARG_NONE, NULL, 't' << 8 },
  137. /* Options relevant only to raw tek2plot (refers to metafile output) */
  138. { "portable-output", ARG_NONE, NULL, 'O' },
  139. /* Documentation options */
  140. { "help-fonts", ARG_NONE, NULL, 'f' << 8 },
  141. { "list-fonts", ARG_NONE, NULL, 'l' << 8 },
  142. { "version", ARG_NONE, NULL, 'V' << 8 },
  143. { "help", ARG_NONE, NULL, 'h' << 8 },
  144. { NULL, 0, NULL, 0}
  145. };
  146. /* null-terminated list of options, such as obsolete-but-still-maintained
  147. options or undocumented options, which we don't show to the user */
  148. const int hidden_options[] = { (int)('T' << 8), 0 };
  149. typedef struct
  150. {
  151. int red;
  152. int green;
  153. int blue;
  154. } Color;
  155. /* ANSI (ISO-6429) color extensions. Scheme is essentially:
  156. 0 = normal, 1 = bright
  157. foreground color (30-37) = 30 + colors
  158. where colors are 1=red, 2=green, 4=blue
  159. background color is similar, with `40' replacing `30'. */
  160. const Color ansi_color[16] =
  161. {
  162. {0x0000, 0x0000, 0x0000}, /* black, \033[0;30m */
  163. {0x8b8b, 0x0000, 0x0000}, /* red4 \033[0;31m */
  164. {0x0000, 0x8b8b, 0x0000}, /* green4 \033[0;32m */
  165. {0x8b8b, 0x8b8b, 0x0000}, /* yellow4 \033[0;33m */
  166. {0x0000, 0x0000, 0x8b8b}, /* blue4 \033[0;34m */
  167. {0x8b8b, 0x0000, 0x8b8b}, /* magenta4 \033[0;35m */
  168. {0x0000, 0x8b8b, 0x8b8b}, /* cyan4, \033[0;36m */
  169. {0x8b8b, 0x8b8b, 0x8b8b}, /* gray55 \033[0;37m */
  170. {0x4d4d, 0x4d4d, 0x4d4d}, /* gray30 \033[1;30m */
  171. {0xffff, 0x0000, 0x0000}, /* red \033[1;31m */
  172. {0x0000, 0xffff, 0x0000}, /* green \033[1;32m */
  173. {0xffff, 0xffff, 0x0000}, /* yellow \033[1;33m */
  174. {0x0000, 0x0000, 0xffff}, /* blue \033[1;34m */
  175. {0xffff, 0x0000, 0xffff}, /* magenta \033[1;35m */
  176. {0x0000, 0xffff, 0xffff}, /* cyan \033[1;36m */
  177. {0xffff, 0xffff, 0xffff} /* white \033[1;37m */
  178. };
  179. /* global variables set on command line, used in Tek parsing routine */
  180. bool position_indiv_chars = false; /* user may set this */
  181. bool single_page_is_requested = false; /* set if user uses -p option */
  182. bool use_tek_fonts = false; /* fonts tekfont0..tekfont3 available? */
  183. bool force_hershey_default = false; /* default font sh'd be Hershey? [kludge]*/
  184. char *font_name = NULL; /* initial font name, can be spec'd by user */
  185. char *pen_color = NULL; /* initial pen color, can be spec'd by user */
  186. double line_width = -1.0; /* initial line width, <0 means default */
  187. int requested_page = 0; /* user sets this via -p option */
  188. /* variables used in parser */
  189. bool plotter_open = false;
  190. bool plotter_opened = false;
  191. int cur_X = 0, cur_Y = 0; /* graphics cursor position in Tek coors */
  192. int current_page = 0; /* page count */
  193. /* forward references */
  194. bool getpoint (int *xcoor, int *ycoor, FILE *stream, int *badstatus, int *margin);
  195. bool read_plot (plPlotter *plotter, FILE *in_stream);
  196. int read_byte (FILE *stream, int *badstatus);
  197. void begin_page (plPlotter *plotter);
  198. void end_page (plPlotter *plotter);
  199. void set_font_size (plPlotter *plotter, int new_fontsize);
  200. void unread_byte (int byte, FILE *in_stream, int *badstatus);
  201. int
  202. main (int argc, char *argv[])
  203. {
  204. plPlotter *plotter;
  205. plPlotterParams *plotter_params;
  206. bool do_list_fonts = false; /* show a list of fonts? */
  207. bool show_fonts = false; /* supply help on fonts? */
  208. bool show_usage = false; /* show usage message? */
  209. bool show_version = false; /* show version message? */
  210. char *output_format = (char *)"meta"; /* default libplot output format */
  211. double local_line_width; /* temporary storage */
  212. int errcnt = 0; /* errors encountered */
  213. int local_page_number; /* temporary storage */
  214. int opt_index; /* long option index */
  215. int option; /* option character */
  216. int retval; /* return value */
  217. plotter_params = pl_newplparams ();
  218. while ((option = getopt_long (argc, argv, optstring, long_options, &opt_index)) != EOF)
  219. {
  220. if (option == 0)
  221. option = long_options[opt_index].val;
  222. switch (option)
  223. {
  224. case 'T': /* Output format, ARG REQUIRED */
  225. case 'T' << 8:
  226. output_format = (char *)xmalloc (strlen (optarg) + 1);
  227. strcpy (output_format, optarg);
  228. /* Kludge: if HP-GL[/2] output is requested, be sure to use a
  229. Hershey font as the default font, even though the Plotter
  230. nominally supports PS fonts. Reason: nominal != real. */
  231. if (strcasecmp (output_format, "hpgl") == 0)
  232. force_hershey_default = true;
  233. else
  234. force_hershey_default = false;
  235. break;
  236. case 'F': /* set the initial font */
  237. font_name = (char *)xmalloc (strlen (optarg) + 1);
  238. strcpy (font_name, optarg);
  239. break;
  240. case 'p': /* page number */
  241. if (sscanf (optarg, "%d", &local_page_number) <= 0
  242. || local_page_number < 0)
  243. {
  244. fprintf (stderr,
  245. "%s: error: the page number `%s' is bad (it should be a nonnegative integer)\n",
  246. progname, optarg);
  247. errcnt++;
  248. }
  249. else
  250. {
  251. requested_page = local_page_number;
  252. single_page_is_requested = true;
  253. }
  254. break;
  255. case 'W': /* set the initial line width */
  256. if (sscanf (optarg, "%lf", &local_line_width) <= 0)
  257. {
  258. fprintf (stderr,
  259. "%s: error: the line thickness `%s' is bad (it should be a number)\n",
  260. progname, optarg);
  261. errcnt++;
  262. break;
  263. }
  264. if (local_line_width < 0.0)
  265. fprintf (stderr, "%s: the request for a negative line thickness `%f' is disregarded\n",
  266. progname, local_line_width);
  267. else
  268. line_width = local_line_width;
  269. break;
  270. case 'O': /* Portable version of metafile output */
  271. pl_setplparam (plotter_params, "META_PORTABLE", (void *)"yes");
  272. break;
  273. /*---------------- Long options below here ----------------*/
  274. case 'e' << 8: /* Emulate color via grayscale */
  275. pl_setplparam (plotter_params, "EMULATE_COLOR", (void *)optarg);
  276. break;
  277. case 'q' << 8: /* Set the initial background color */
  278. pl_setplparam (plotter_params, "BG_COLOR", (void *)optarg);
  279. break;
  280. case 'B' << 8: /* Bitmap size */
  281. pl_setplparam (plotter_params, "BITMAPSIZE", (void *)optarg);
  282. break;
  283. case 'C' << 8: /* Set the initial pen color */
  284. pen_color = (char *)xmalloc (strlen (optarg) + 1);
  285. strcpy (pen_color, optarg);
  286. break;
  287. case 'M' << 8: /* Max line length */
  288. pl_setplparam (plotter_params, "MAX_LINE_LENGTH", (void *)optarg);
  289. break;
  290. case 'P' << 8: /* Page size */
  291. pl_setplparam (plotter_params, "PAGESIZE", (void *)optarg);
  292. break;
  293. case 'S' << 8: /* Position chars in text strings individually */
  294. position_indiv_chars = true;
  295. break;
  296. case 'r' << 8: /* Rotation angle */
  297. pl_setplparam (plotter_params, "ROTATION", (void *)optarg);
  298. break;
  299. case 't' << 8: /* Use Tektronix fonts (must be installed) */
  300. if (strcmp (output_format, "X") == 0)
  301. use_tek_fonts = true;
  302. break;
  303. case 'f' << 8: /* Fonts */
  304. show_fonts = true;
  305. break;
  306. case 'l' << 8: /* Fonts */
  307. do_list_fonts = true;
  308. break;
  309. case 'h' << 8: /* Help */
  310. show_usage = true;
  311. break;
  312. case 'V' << 8: /* Version */
  313. show_version = true;
  314. break;
  315. default:
  316. errcnt++;
  317. break;
  318. }
  319. }
  320. if (errcnt > 0)
  321. {
  322. fprintf (stderr, "Try `%s --help' for more information\n", progname);
  323. return EXIT_FAILURE;
  324. }
  325. if (show_version)
  326. {
  327. display_version (progname, written, copyright);
  328. return EXIT_SUCCESS;
  329. }
  330. if (do_list_fonts)
  331. {
  332. int success;
  333. success = list_fonts (output_format, progname);
  334. if (success)
  335. return EXIT_SUCCESS;
  336. else
  337. return EXIT_FAILURE;
  338. }
  339. if (show_fonts)
  340. {
  341. int success;
  342. success = display_fonts (output_format, progname);
  343. if (success)
  344. return EXIT_SUCCESS;
  345. else
  346. return EXIT_FAILURE;
  347. }
  348. if (show_usage)
  349. {
  350. display_usage (progname, hidden_options, usage_appendage, 2);
  351. return EXIT_SUCCESS;
  352. }
  353. /* turn off special interpretation of `erase' in GIF Plotters */
  354. pl_setplparam (plotter_params, "GIF_ANIMATION", (void *)"no");
  355. if ((plotter = pl_newpl_r (output_format, NULL, stdout, stderr,
  356. plotter_params)) == NULL)
  357. {
  358. fprintf (stderr, "%s: error: the plot device could not be created\n", progname);
  359. return EXIT_FAILURE;
  360. }
  361. retval = EXIT_SUCCESS;
  362. if (optind < argc)
  363. /* input files (or stdin) named explicitly on the command line */
  364. {
  365. for (; optind < argc; optind++)
  366. {
  367. FILE *data_file;
  368. if (strcmp (argv[optind], "-") == 0)
  369. data_file = stdin;
  370. else
  371. {
  372. data_file = fopen (argv[optind], "r");
  373. if (data_file == NULL)
  374. {
  375. fprintf (stderr, "%s: %s: %s\n", progname, argv[optind], strerror(errno));
  376. fprintf (stderr, "%s: this file is ignored.\n", progname);
  377. errno = 0; /* not quite fatal */
  378. retval = EXIT_FAILURE;
  379. continue; /* back to top of for loop */
  380. }
  381. }
  382. if (read_plot (plotter, data_file) == false)
  383. {
  384. fprintf (stderr, "%s: the input file `%s' could not be parsed\n",
  385. progname, argv[optind]);
  386. retval = EXIT_FAILURE;
  387. continue; /* back to top of for loop */
  388. }
  389. if (data_file != stdin) /* Don't close stdin */
  390. if (fclose (data_file) < 0)
  391. {
  392. fprintf (stderr,
  393. "%s: error: the input file `%s' could not be closed\n",
  394. progname, argv[optind]);
  395. return EXIT_FAILURE; /* exit immediately */
  396. }
  397. }
  398. } /* endfor */
  399. else
  400. /* no files/streams spec'd on the command line, just read stdin */
  401. {
  402. if (read_plot (plotter, stdin) == false)
  403. {
  404. fprintf (stderr, "%s: the input could not be parsed\n", progname);
  405. retval = EXIT_FAILURE;
  406. }
  407. }
  408. /* if nothing was emitted ... */
  409. if (plotter_opened == false)
  410. {
  411. if (single_page_is_requested == false)
  412. /* output a blank page */
  413. {
  414. begin_page (plotter);
  415. end_page (plotter);
  416. }
  417. else
  418. {
  419. if (requested_page >= current_page)
  420. {
  421. fprintf (stderr, "%s: the requested page does not exist\n", progname);
  422. retval = EXIT_FAILURE;
  423. }
  424. else
  425. /* page must have been seen, but was empty; output a blank page */
  426. {
  427. begin_page (plotter);
  428. end_page (plotter);
  429. }
  430. }
  431. }
  432. if (pl_deletepl_r (plotter) < 0)
  433. {
  434. fprintf (stderr, "%s: error: the plot device could not be deleted\n", progname);
  435. retval = EXIT_FAILURE;
  436. }
  437. pl_deleteplparams (plotter_params);
  438. return retval;
  439. }
  440. void
  441. unread_byte (int c, FILE *in_stream, int *badstatus)
  442. {
  443. if (*badstatus == 0)
  444. {
  445. if (ungetc (c, in_stream) == EOF) /* means error, not EOF */
  446. *badstatus = 2; /* treat as EOF anyway */
  447. }
  448. }
  449. int
  450. read_byte (FILE *in_stream, int *badstatus)
  451. {
  452. int i;
  453. if (*badstatus == 1) /* status = parse error */
  454. return 0;
  455. i = getc (in_stream);
  456. if (i == EOF)
  457. {
  458. *badstatus = 2; /* status = eof */
  459. return 0;
  460. }
  461. return (i & 0x7f); /* high bit ignored */
  462. }
  463. /* getpoint() reads a point (x,y) from the input stream, in Tektronix
  464. format, and returns it. A point is a pair of coordinates in the range
  465. 0..4095. Reading a point will normally require reading anywhere between
  466. 1 and 5 bytes from the input stream. This function contains internal
  467. state: several static variables.
  468. Return value indicates whether a point is successfully read. Failure to
  469. return a point may occur on account of a parsing problem or because of
  470. eof. In either of these two cases an error code is returned through
  471. `badstatus', signalling that parsing of the input stream should
  472. terminate.
  473. A point may also fail to be returned if the first byte that is read from
  474. the input stream is not a byte in the 0x20..0xff range. Normally, no
  475. byte in the range 0x00..0x1f range may be part of a point. So if such a
  476. byte is seen, it is pushed back on the stream and point-reading is
  477. aborted (no error code is returned through badstatus). Note that if the
  478. very first byte that is read is in this range, this function may return
  479. having read, in all, 0 bytes.
  480. An exception to the last rule: if any of the bytes CR, LF, or NUL is
  481. seen during the reading of a point, it is discarded and reading
  482. continues. So it is also possible that >5 bytes may be read in all.
  483. A possible side effect of calling getpoint(): if the MSB of the egm
  484. byte, which is one of the bytes that make up the point, is set, then the
  485. left-hand margin will be set to MARGIN2, i.e. to 2048. */
  486. bool
  487. getpoint (int *xcoor, int *ycoor, FILE *in_stream, int *badstatus, int *margin)
  488. {
  489. /* variables for the point-reading DFA, initialized */
  490. int status_one = 0, status_three = 0; /* 0=none, 1=seen one, 2=finished */
  491. bool got_lo_y = false;
  492. bool got_hi_x = false, got_hi_y = false;
  493. int lo_x = 0, lo_y = 0, hi_x = 0, hi_y = 0;
  494. bool got_egm = false;
  495. int egm = 0;
  496. int temp_three = 0;
  497. /* following variables are saved from point to point */
  498. static int saved_lo_y = 0, saved_hi_x = 0, saved_hi_y = 0;
  499. static bool margin_reset = false;
  500. int byte_read, type;
  501. if (*badstatus)
  502. return false;
  503. for ( ; ; )
  504. {
  505. byte_read = read_byte (in_stream, badstatus);
  506. if (*badstatus)
  507. return false;
  508. /* Ignore high bit (bit 8); bit pattern of next two bits (bits 7/6)
  509. determines what sort of coordinate byte we have. 1 = Hi_X or
  510. Hi_Y, 2 = Lo_X, 3 = Lo_Y or EGM; 0 usually means abort point.
  511. Coordinate bytes appear in order
  512. [Hi_Y] [EGM] [Lo_Y] [Hi_X] Lo_X.
  513. 1 3 3 1 2
  514. All save last are optional, except that if EGM or Hi_X is
  515. transmitted, also need need a Lo_Y. We remember old values of
  516. Hi_Y, Lo_Y, Hi_X, although not EGM or Lo_X, in our DFA. */
  517. type = (byte_read>>5) & TWO_BITS; /* type of byte */
  518. byte_read &= FIVE_BITS; /* mask off 5 relevant bits */
  519. switch (type)
  520. {
  521. case 0: /* interruption of point-reading (parse error?) */
  522. fprintf (stderr,
  523. "%s: an incomplete point in the input is ignored\n",
  524. progname);
  525. if (byte_read == '\n' || byte_read == '\r' || byte_read == '\0')
  526. continue; /* discard, on to next byte */
  527. else
  528. /* put unread byte back on stream; hope we can parse it later */
  529. unread_byte (byte_read, in_stream, badstatus);
  530. return false;
  531. case 1: /* Hi_Y or Hi_X */
  532. switch (status_one)
  533. {
  534. case 0:
  535. if (status_three)
  536. {
  537. hi_x = byte_read; /* 2nd = Hi_X */
  538. got_hi_x = true;
  539. if (status_three == 1)
  540. {
  541. lo_y = temp_three; /* Lo_Y */
  542. got_lo_y = true;
  543. }
  544. status_one = 2; /* no more 1's */
  545. status_three = 2; /* no more 3's */
  546. }
  547. else
  548. {
  549. hi_y = byte_read; /* 1st = Hi_Y */
  550. got_hi_y = true;
  551. status_one = 1;
  552. }
  553. break;
  554. case 1:
  555. if (status_three == 0)
  556. {
  557. fprintf (stderr,
  558. "%s: error: a point in the input has Hi_Y, Hi_X bytes with no Lo_Y between\n",
  559. progname);
  560. *badstatus = 1; /* parse error */
  561. return false;
  562. }
  563. if (status_three == 1)
  564. {
  565. lo_y = temp_three; /* Lo_Y */
  566. got_lo_y = true;
  567. }
  568. hi_x = byte_read; /* 2nd = Hi_X */
  569. got_hi_x = true;
  570. status_one = 2; /* no more 1's */
  571. status_three = 2; /* no more 3's */
  572. break;
  573. case 2:
  574. fprintf (stderr,
  575. "%s: error: a point in the input contains too many Hi_Y/Hi_X bytes\n",
  576. progname);
  577. *badstatus = 1; /* parse error */
  578. return false;
  579. }
  580. break;
  581. case 3: /* EGM or Lo_Y */
  582. switch (status_three)
  583. {
  584. case 0:
  585. if (status_one == 2)
  586. {
  587. fprintf (stderr,
  588. "%s: error: a point in the input has an EGM/Lo_Y byte after 2 Hi_X/Hi_Y bytes\n",
  589. progname);
  590. *badstatus = 1; /* parse error */
  591. return false;
  592. }
  593. else
  594. {
  595. temp_three = byte_read;
  596. status_three = 1;
  597. }
  598. break;
  599. case 1:
  600. if (status_one == 2)
  601. {
  602. fprintf (stderr,
  603. "%s: error: a point in the input has an EGM/Lo_Y byte after 2 Hi_X/Hi_Y bytes\n",
  604. progname);
  605. *badstatus = 1; /* parse error */
  606. return false;
  607. }
  608. egm = temp_three; /* 1st = EGM */
  609. got_egm = true;
  610. lo_y = byte_read; /* 2nd = Lo_Y */
  611. got_lo_y = true;
  612. status_three = 2;
  613. break;
  614. case 2:
  615. fprintf (stderr,
  616. "%s: error: a point in the input has too many EGM/Lo_Y bytes\n",
  617. progname);
  618. *badstatus = 1; /* parse error */
  619. return false;
  620. }
  621. break;
  622. case 2: /* Lo_X, final byte */
  623. {
  624. int low_res_x, low_res_y;
  625. int x, y;
  626. if (status_three == 1)
  627. {
  628. lo_y = temp_three; /* Lo_Y */
  629. got_lo_y = true;
  630. }
  631. lo_x = byte_read; /* Lo_X */
  632. lo_y = got_lo_y ? lo_y : saved_lo_y;
  633. hi_x = got_hi_x ? hi_x : saved_hi_x;
  634. hi_y = got_hi_y ? hi_y : saved_hi_y;
  635. saved_lo_y = lo_y;
  636. saved_hi_x = hi_x;
  637. saved_hi_y = hi_y;
  638. /* On a genuine Tektronix 4014, the MSB of the 5-bit EGM
  639. byte sets the margin to equal Margin2 (2048) */
  640. if ((egm >> 4) & ONE_BIT)
  641. {
  642. *margin = MARGIN2;
  643. if (margin_reset == false)
  644. fprintf (stderr,
  645. "%s: the left margin of the Tektronix was reset by the input\n",
  646. progname);
  647. margin_reset = true;
  648. }
  649. /* low_res is what we'd use on a pre-EGM Tektronix */
  650. low_res_x = (hi_x << 5) | lo_x;
  651. low_res_y = (hi_y << 5) | lo_y;
  652. x = (low_res_x << 2) | (egm & TWO_BITS);
  653. y = (low_res_y << 2) | ((egm >> 2) & TWO_BITS);
  654. *xcoor = x;
  655. *ycoor = y;
  656. return true; /* end of `case 2' in switch: success */
  657. }
  658. } /* end of switch */
  659. } /* end of while loop */
  660. /* NOTREACHED */
  661. }
  662. /* Parse a Tektronix stream and make appropriate libplot calls, paying
  663. attention to several global variables. Will output at least one
  664. openpl()..closepl(). */
  665. bool
  666. read_plot (plPlotter *plotter, FILE *in_stream)
  667. {
  668. /* variables for DFA */
  669. int *Tparsestate = Talptable; /* start in ALPHA mode */
  670. int *curstate = Talptable; /* for temporary storage (for `bypass' mode) */
  671. int pen = PENUP; /* pen up or pen down */
  672. int linetype = 0; /* in range 0..7, 0 means "solid" */
  673. int fontsize = 0; /* in range 0..3, 0 means large */
  674. int margin = MARGIN1; /* MARGIN1=left side, MARGIN2=halfway across */
  675. char text[TEXT_BUFFER_SIZE]; /* for storage of text strings */
  676. int badstatus = 0; /* 0=OK, 1=parse error, 2=eof */
  677. while (!badstatus) /* exit from loop only on parse error or eof */
  678. {
  679. int c;
  680. int x, y;
  681. c = read_byte (in_stream, &badstatus);
  682. if (badstatus)
  683. break; /* parse error or eof; exit from while loop */
  684. switch (Tparsestate[c])
  685. {
  686. /* Switch among 5 basic states: ALPHA, PLOT, POINT PLOT,
  687. SPECIAL POINT PLOT and INCREMENTAL PLOT. */
  688. case CASE_ALP_STATE: /* Enter ALPHA mode */
  689. Tparsestate = curstate = Talptable;
  690. break;
  691. case CASE_PLT_STATE: /* Enter PLOT mode */
  692. Tparsestate = curstate = Tplttable;
  693. c = read_byte (in_stream, &badstatus);
  694. /* do lookahead */
  695. if (c == BEL)
  696. /* no initial dark vector */
  697. pen = PENDOWN;
  698. else
  699. {
  700. pen = PENUP;
  701. unread_byte (c, in_stream, &badstatus);
  702. }
  703. break;
  704. case CASE_PT_STATE: /* Enter POINT PLOT mode */
  705. Tparsestate = curstate = Tpttable;
  706. break;
  707. case CASE_SPT_STATE: /* enter SPECIAL POINT PLOT mode */
  708. Tparsestate = curstate = Tspttable;
  709. break;
  710. case CASE_IPL_STATE: /* enter INCREMENTAL PLOT mode */
  711. Tparsestate = curstate = Tipltable;
  712. break;
  713. /*****************************************/
  714. /* ALPHA mode commands */
  715. case CASE_PRINT: /* printable character */
  716. {
  717. char *cp = text;
  718. int x_here, y_here, n;
  719. x_here = cur_X, y_here = cur_Y;
  720. /* push back, so we can read string as a unit */
  721. unread_byte (c, in_stream, &badstatus);
  722. if (badstatus)
  723. break;
  724. n = (position_indiv_chars ? 1 : TEXT_BUFFER_SIZE - 1);
  725. y = cur_Y;
  726. while (!badstatus && n-- > 0 && y == cur_Y)
  727. {
  728. c = read_byte (in_stream, &badstatus);
  729. if (badstatus)
  730. {
  731. break; /* end label on eof or read error */
  732. }
  733. if (!PRINTABLE_ASCII (c))
  734. {
  735. /* push back */
  736. unread_byte (c, in_stream, &badstatus);
  737. break; /* end label on non-ascii character */
  738. }
  739. *cp++ = c;
  740. /* following block is merely `cursor right' (cf. below) */
  741. {
  742. const struct Tek_Char *t = &TekChar[fontsize];
  743. int l;
  744. cur_X += t->hsize;
  745. if (cur_X > TEK_WIDTH)
  746. {
  747. l = cur_Y / t->vsize - 1;
  748. if (l < 0)
  749. {
  750. margin = !margin;
  751. l = t->nlines - 1;
  752. }
  753. cur_Y = l * t->vsize;
  754. cur_X = (margin == MARGIN1 ? 0 : TEK_WIDTH / 2);
  755. }
  756. }
  757. } /* end of string-reading while loop */
  758. *cp = '\0'; /* null-terminate string, and output it */
  759. if (current_page == requested_page || !single_page_is_requested)
  760. {
  761. if (plotter_open == false)
  762. begin_page (plotter);
  763. if (position_indiv_chars)
  764. /* string consists of a single char */
  765. {
  766. int halfwidth = TekChar[fontsize].hsize / 2;
  767. pl_move_r (plotter, x_here + halfwidth, y_here + YOFFSET);
  768. pl_alabel_r (plotter, 'c', 'b', text);
  769. }
  770. else
  771. {
  772. pl_move_r (plotter, x_here, y_here + YOFFSET);
  773. pl_alabel_r (plotter, 'l', 'b', text);
  774. }
  775. pl_move_r (plotter, cur_X, cur_Y);
  776. }
  777. } /* end of CASE_PRINT */
  778. break;
  779. /* PLOT mode commands */
  780. case CASE_PLT_VEC: /* PLT: vector */
  781. /* push back, so we can read vector as a unit */
  782. unread_byte (c, in_stream, &badstatus);
  783. if (getpoint (&x, &y, in_stream, &badstatus, &margin)
  784. && !badstatus)
  785. /* N.B. getpoint returns w/o having read c only if c=0x00..0x1f,
  786. so there's no chance of a infinite loop (see parsetable) */
  787. {
  788. if (current_page == requested_page || !single_page_is_requested)
  789. {
  790. if (pen == PENDOWN)
  791. {
  792. if (plotter_open == false)
  793. begin_page (plotter);
  794. pl_cont_r (plotter, x, y + YOFFSET);
  795. }
  796. else
  797. {
  798. /* N.B. Don't begin a new page just for a move() */
  799. if (plotter_open == true)
  800. pl_move_r (plotter, x, y + YOFFSET);
  801. }
  802. }
  803. cur_X = x;
  804. cur_Y = y;
  805. pen = PENDOWN;
  806. }
  807. break;
  808. /* POINT PLOT mode commands */
  809. case CASE_PT_POINT: /* PT: point */
  810. /* push back, so we can read vector as a unit */
  811. unread_byte (c, in_stream, &badstatus);
  812. if (getpoint (&x, &y, in_stream, &badstatus, &margin)
  813. && !badstatus)
  814. /* N.B. getpoint returns w/o having read c only if c=0x00..0x1f,
  815. so there's no chance of a infinite loop (see parsetable) */
  816. {
  817. if (current_page == requested_page || !single_page_is_requested)
  818. {
  819. if (plotter_open == false)
  820. begin_page (plotter);
  821. pl_fmarker_r (plotter,
  822. (double)x, (double)(y + YOFFSET),
  823. M_DOT, (double)DOT_SIZE);
  824. }
  825. cur_X = x;
  826. cur_Y = y;
  827. }
  828. break;
  829. /* SPECIAL POINT PLOT mode commands */
  830. case CASE_SPT_POINT: /* SPT: point */
  831. /* don't push back c (ignore intensity byte) */
  832. if (getpoint (&x, &y, in_stream, &badstatus, &margin)
  833. && !badstatus)
  834. /* N.B. getpoint returns w/o having read c only if c=0x00..0x1f,
  835. so there's no chance of a infinite loop (see parsetable) */
  836. {
  837. /* assume intensity is > 0 */
  838. if (current_page == requested_page || !single_page_is_requested)
  839. {
  840. if (plotter_open == false)
  841. begin_page (plotter);
  842. pl_fmarker_r (plotter,
  843. (double)x, (double)(y + YOFFSET),
  844. M_DOT, (double)(DOT_SIZE));
  845. }
  846. cur_X = x;
  847. cur_Y = y;
  848. }
  849. break;
  850. /* INCREMENTAL PLOT mode commands */
  851. case CASE_PENUP: /* IPL: penup */
  852. pen = PENUP;
  853. break;
  854. case CASE_PENDOWN: /* IPL: pendown */
  855. pen = PENDOWN;
  856. break;
  857. case CASE_IPL_POINT: /* IPL: point */
  858. x = cur_X;
  859. y = cur_Y;
  860. if (c & NORTH)
  861. y++;
  862. else if (c & SOUTH)
  863. y--;
  864. if (c & EAST)
  865. x++;
  866. else if (c & WEST)
  867. x--;
  868. if (current_page == requested_page || !single_page_is_requested)
  869. {
  870. if (pen == PENDOWN)
  871. {
  872. if (plotter_open == false)
  873. begin_page (plotter);
  874. pl_cont_r (plotter, x, y + YOFFSET);
  875. }
  876. else
  877. {
  878. /* N.B. Don't begin a new page just for a move() */
  879. if (plotter_open == true)
  880. pl_move_r (plotter, x, y + YOFFSET);
  881. }
  882. }
  883. cur_X = x;
  884. cur_Y = y;
  885. break;
  886. /****************************************/
  887. /* These switch the parsetable temporarily to one of three
  888. pseudo-states, while stashing the current state. */
  889. case CASE_BES_STATE: /* Byp: an escape char */
  890. Tparsestate = Tbestable;
  891. break;
  892. case CASE_BYP_STATE: /* set bypass condition */
  893. Tparsestate = Tbyptable;
  894. break;
  895. case CASE_ESC_STATE: /* ESC */
  896. Tparsestate = Tesctable;
  897. break;
  898. /*****************************************/
  899. /* Cursor motion, useful mostly in ALPHA mode. Some of these
  900. restore the stashed state (if any) and some do not. */
  901. case CASE_CR: /* CR */
  902. cur_X = (margin == MARGIN1 ? 0 : TEK_WIDTH / 2);
  903. Tparsestate = curstate = Talptable; /* switch to ALPHA mode */
  904. break;
  905. case CASE_BS: /* BS, cursor left */
  906. Tparsestate = curstate; /* clear bypass condition if any */
  907. {
  908. const struct Tek_Char *t;
  909. int x, l;
  910. x = (cur_X -= (t = &TekChar[fontsize])->hsize);
  911. if ((margin == MARGIN1 && x < 0)
  912. || (margin == MARGIN2 && x < TEK_WIDTH / 2))
  913. {
  914. if ((l = (cur_Y + (t->vsize - 1)) / t->vsize + 1) >=
  915. t->nlines)
  916. {
  917. margin = !margin;
  918. l = 0;
  919. }
  920. cur_Y = l * t->vsize;
  921. cur_X = (t->charsperline - 1) * t->hsize;
  922. }
  923. }
  924. break;
  925. case CASE_TAB: /* HT */
  926. Tparsestate = curstate; /* clear bypass condition if any */
  927. /* FALL THROUGH */
  928. case CASE_SP: /* SP, cursor right */
  929. {
  930. const struct Tek_Char *t = &TekChar[fontsize];
  931. int l;
  932. cur_X += t->hsize;
  933. if (cur_X > TEK_WIDTH)
  934. {
  935. l = cur_Y / t->vsize - 1;
  936. if (l < 0)
  937. {
  938. margin = !margin;
  939. l = t->nlines - 1;
  940. }
  941. cur_Y = l * t->vsize;
  942. cur_X = (margin == MARGIN1 ? 0 : TEK_WIDTH / 2);
  943. }
  944. }
  945. break;
  946. case CASE_LF: /* LF, cursor down */
  947. {
  948. const struct Tek_Char *t;
  949. int l;
  950. t = &TekChar[fontsize];
  951. if ((l = cur_Y / t->vsize - 1) < 0)
  952. {
  953. l = t->nlines - 1;
  954. if ((margin = !margin) != MARGIN1)
  955. {
  956. if (cur_X < TEK_WIDTH / 2)
  957. cur_X += TEK_WIDTH / 2;
  958. }
  959. else if (cur_X >= TEK_WIDTH / 2)
  960. cur_X -= TEK_WIDTH / 2;
  961. }
  962. cur_Y = l * t->vsize;
  963. }
  964. break;
  965. case CASE_UP: /* cursor up */
  966. Tparsestate = curstate; /* clear bypass condition if any */
  967. {
  968. const struct Tek_Char *t;
  969. int l;
  970. t = &TekChar[fontsize];
  971. if ((l = (cur_Y + (t->vsize - 1)) / t->vsize + 1) >= t->nlines)
  972. {
  973. l = 0;
  974. if ((margin = !margin) != MARGIN1)
  975. {
  976. if (cur_X < TEK_WIDTH / 2)
  977. cur_X += TEK_WIDTH / 2;
  978. }
  979. else if (cur_X >= TEK_WIDTH / 2)
  980. cur_X -= TEK_WIDTH / 2;
  981. }
  982. cur_Y = l * t->vsize;
  983. }
  984. break;
  985. /****************************************/
  986. /* Miscellaneous: functions we interpret as `next page',
  987. `set font size', and `set line type'. */
  988. case CASE_PAGE: /* page function, clears bypass cond. */
  989. /* do closepl to flush out page (if nonempty) */
  990. if (plotter_open == true)
  991. end_page (plotter);
  992. if (single_page_is_requested && current_page == requested_page)
  993. {
  994. badstatus = 2; /* requested page is finished, so signal eof */
  995. break; /* exit from while loop */
  996. }
  997. /* now beginning parse of a new Tektronix page */
  998. current_page++;
  999. /* special case: if only a single page is requested, and line
  1000. mode and font size have changed due to commands on previous
  1001. Tek pages, output them */
  1002. if (single_page_is_requested && current_page == requested_page)
  1003. {
  1004. if (linetype != 0)
  1005. {
  1006. if (plotter_open == false)
  1007. begin_page (plotter);
  1008. pl_linemod_r (plotter, linemodes[linetype]);
  1009. }
  1010. if (fontsize != 0)
  1011. {
  1012. if (plotter_open == false)
  1013. begin_page (plotter);
  1014. set_font_size (plotter, fontsize);
  1015. }
  1016. }
  1017. cur_X = 0;
  1018. cur_Y = TEKHOME; /* home pos. depends on fontsize */
  1019. break;
  1020. case CASE_CHAR_SIZE: /* select font size */
  1021. fontsize = c & 03;
  1022. if (current_page == requested_page || !single_page_is_requested)
  1023. {
  1024. if (plotter_open == false)
  1025. begin_page (plotter);
  1026. set_font_size (plotter, fontsize);
  1027. }
  1028. Tparsestate = curstate;
  1029. break;
  1030. case CASE_BEAM_VEC: /* select beam and vector types */
  1031. /* disregard beam type */
  1032. c &= 07;
  1033. if (c != linetype)
  1034. if (current_page == requested_page || !single_page_is_requested)
  1035. {
  1036. if (plotter_open == false)
  1037. begin_page (plotter);
  1038. linetype = c;
  1039. pl_linemod_r (plotter, linemodes[linetype]);
  1040. }
  1041. Tparsestate = curstate;
  1042. break;
  1043. /****************************************/
  1044. /* Things we ignore. */
  1045. case CASE_OSC: /* do osc escape */
  1046. /* ignore all bytes up to and including first non-ascii byte
  1047. (presumably BEL) */
  1048. do
  1049. c = read_byte (in_stream, &badstatus);
  1050. while (!badstatus && PRINTABLE_ASCII(c));
  1051. Tparsestate = curstate;
  1052. break;
  1053. case CASE_ANSI: /* parse an ANSI-style escape sequence */
  1054. {
  1055. char ansi[BUFFER_SIZE]; /* buffer for escape sequence */
  1056. char type = 0; /* `type' (i.e. final byte) */
  1057. int i; /* length of arg bytes, incl. separators */
  1058. i = 0;
  1059. for ( ; ; )
  1060. {
  1061. c = read_byte (in_stream, &badstatus);
  1062. if (badstatus)
  1063. break;
  1064. if ((c >= '0' && c <= '9') || c == ';'
  1065. || (i == 0 && c == '?'))
  1066. /* an arg byte, or a separator byte */
  1067. ansi[i++] = c;
  1068. else
  1069. {
  1070. type = c;
  1071. if (!(PRINTABLE_ASCII(type)))
  1072. badstatus = 1; /* parse error */
  1073. break;
  1074. }
  1075. if (i == BUFFER_SIZE)
  1076. {
  1077. fprintf (stderr,
  1078. "%s: error: an overly long ANSI escape sequence was encountered\n",
  1079. progname);
  1080. badstatus = 1; /* parse error */
  1081. break;
  1082. }
  1083. }
  1084. Tparsestate = curstate;
  1085. if (badstatus)
  1086. break;
  1087. if (i == 3 && (type == 'h' || type == 'l')
  1088. && (ansi[0] == '?' && ansi[1] == '3' && ansi[2] == '8'))
  1089. /* switch to Tek or VT100 mode, ignore */
  1090. break;
  1091. if (i == 4 && type == 'm'
  1092. && (ansi[0] == '0' || ansi[0] == '1')
  1093. && ansi[1] == ';' && ansi[2] == '3'
  1094. && ansi[3] >= '0' && ansi[3] <= '7')
  1095. /* set ANSI foreground color */
  1096. {
  1097. int intensity, color_index;
  1098. if (plotter_open == false)
  1099. begin_page (plotter);
  1100. intensity = ansi[0] - '0';
  1101. color_index = ansi[3] - '0';
  1102. pl_pencolor_r (plotter,
  1103. ansi_color[8 * intensity + color_index].red,
  1104. ansi_color[8 * intensity + color_index].green,
  1105. ansi_color[8 * intensity + color_index].blue);
  1106. break;
  1107. }
  1108. }
  1109. break;
  1110. case CASE_IGNORE: /* Esc: totally ignore CR, ESC, LF, ~ */
  1111. break;
  1112. /****************************************/
  1113. /* We interpret these as just restoring the stashed
  1114. state (if any). */
  1115. case CASE_REPORT: /* report address */
  1116. case CASE_VT_MODE: /* special return to vt102 mode */
  1117. case CASE_BEL: /* BEL */
  1118. case CASE_COPY: /* make copy */
  1119. case CASE_CURSTATE:
  1120. Tparsestate = curstate; /* clear bypass condition */
  1121. break;
  1122. case CASE_ASCII: /* select ASCII char set */
  1123. /* ignore for now */
  1124. Tparsestate = curstate;
  1125. break;
  1126. case CASE_APL: /* select APL char set */
  1127. /* ignore for now */
  1128. Tparsestate = curstate;
  1129. break;
  1130. case CASE_GIN: /* do Tek GIN mode */
  1131. Tparsestate = Tbyptable; /* Bypass mode */
  1132. break;
  1133. }
  1134. }
  1135. /* end parsing of this Tektronix stream */
  1136. if (plotter_open == true) /* close plotter, i.e. end page if any */
  1137. end_page (plotter);
  1138. current_page++; /* bump page count for next file if any */
  1139. return (badstatus == 2 ? true : false); /* OK to end parse at EOF */
  1140. }
  1141. void
  1142. set_font_size (plPlotter *plotter, int new_fontsize)
  1143. {
  1144. if (use_tek_fonts)
  1145. /* switch among Tektronix fonts (may not be available on all X servers) */
  1146. {
  1147. switch (new_fontsize)
  1148. {
  1149. case 0:
  1150. default:
  1151. pl_fontname_r (plotter, "tekfont0");
  1152. break;
  1153. case 1:
  1154. pl_fontname_r (plotter, "tekfont1");
  1155. break;
  1156. case 2:
  1157. pl_fontname_r (plotter, "tekfont2");
  1158. break;
  1159. case 3:
  1160. pl_fontname_r (plotter, "tekfont3");
  1161. break;
  1162. }
  1163. }
  1164. else
  1165. /* we presumably are using a scalable font */
  1166. pl_ffontsize_r (plotter,
  1167. (double)(TekChar[new_fontsize].hsize) / CHAR_WIDTH);
  1168. }
  1169. void
  1170. begin_page (plPlotter *plotter)
  1171. {
  1172. if (pl_openpl_r (plotter) < 0)
  1173. {
  1174. fprintf (stderr,
  1175. "%s: error: the plot device could not be opened\n",
  1176. progname);
  1177. exit (EXIT_FAILURE);
  1178. }
  1179. plotter_open = true;
  1180. plotter_opened = true;
  1181. /* set background color, set affine map from user frame to device frame */
  1182. pl_erase_r (plotter);
  1183. pl_space_r (plotter, 0, 0, TEK_WIDTH - 1, TEK_WIDTH - 1);
  1184. /* improve smoothness of plotted curves */
  1185. pl_joinmod_r (plotter, "round");
  1186. /* may be necessary if zero-length lines are to display as points */
  1187. pl_capmod_r (plotter, "round");
  1188. /* optionally initialize pen color, font, fontsize, line width */
  1189. if (pen_color)
  1190. pl_pencolorname_r (plotter, pen_color);
  1191. if (use_tek_fonts)
  1192. pl_fontname_r (plotter, "tekfont0");
  1193. else
  1194. {
  1195. if (font_name)
  1196. pl_fontname_r (plotter, font_name);
  1197. else
  1198. {
  1199. if (!force_hershey_default)
  1200. /* normal case */
  1201. {
  1202. if (pl_havecap_r (plotter, "PS_FONTS") == 1)
  1203. pl_fontname_r (plotter, DEFAULT_PS_FONT_NAME);
  1204. else if (pl_havecap_r (plotter, "PCL_FONTS") == 1)
  1205. pl_fontname_r (plotter, DEFAULT_PCL_FONT_NAME);
  1206. else
  1207. /* use Hershey font as a default */
  1208. pl_fontname_r (plotter, DEFAULT_HERSHEY_FONT_NAME);
  1209. }
  1210. else
  1211. /* forced to use Hershey font as a default, even if other fonts
  1212. are available (this happens for `-T hpgl'; see above) */
  1213. pl_fontname_r (plotter, DEFAULT_HERSHEY_FONT_NAME);
  1214. }
  1215. /* `large' is default size */
  1216. pl_ffontsize_r (plotter, (double)(TekChar[0].hsize) / CHAR_WIDTH);
  1217. }
  1218. if (line_width >= 0.0)
  1219. pl_flinewidth_r (plotter, line_width * TEK_WIDTH);
  1220. /* move to current position on page */
  1221. pl_move_r (plotter, cur_X, cur_Y + YOFFSET);
  1222. }
  1223. void
  1224. end_page (plPlotter *plotter)
  1225. {
  1226. if (pl_closepl_r (plotter) < 0)
  1227. {
  1228. fprintf (stderr,
  1229. "%s: error: the plot device could not be closed\n",
  1230. progname);
  1231. exit (EXIT_FAILURE);
  1232. }
  1233. plotter_open = false;
  1234. }