PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/mjl_fork_1/src/plcore.c

#
C | 2312 lines | 1360 code | 400 blank | 552 comment | 282 complexity | 6975587107950c6b97c6a3899daff82b MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0
  1. /* $Id: plcore.c 6212 2005-04-27 06:44:27Z rlaboiss $
  2. Central dispatch facility for PLplot.
  3. Also contains the PLplot main data structures, external access
  4. routines, and initialization calls.
  5. This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
  6. Copyright (C) 2004 Joao Cardoso
  7. Copyright (C) 2004, 2005 Rafael Laboissiere
  8. Copyright (C) 2004 Andrew Ross
  9. Copyright (C) 2004 Andrew Roach
  10. Copyright (C) 2005 Alan W. Irwin
  11. Copyright (C) 2005 Thomas J. Duck
  12. This file is part of PLplot.
  13. PLplot is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Library Public License as published
  15. by the Free Software Foundation; either version 2 of the License, or
  16. (at your option) any later version.
  17. PLplot is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU Library General Public License for more details.
  21. You should have received a copy of the GNU Library General Public License
  22. along with PLplot; if not, write to the Free Software
  23. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. */
  25. #define DEBUG
  26. #define NEED_PLDEBUG
  27. #include "plcore.h"
  28. #ifdef ENABLE_DYNDRIVERS
  29. #include <ltdl.h>
  30. #endif
  31. /*--------------------------------------------------------------------------*\
  32. * Driver Interface
  33. *
  34. * These routines are the low-level interface to the driver -- all calls to
  35. * driver functions must pass through here. For implementing driver-
  36. * specific functions, the escape function is provided. The command stream
  37. * gets duplicated to the plot buffer here.
  38. *
  39. * All functions that result in graphics actually being plotted (rather than
  40. * just a change of state) are filtered as necessary before being passed on.
  41. * The default settings do not require any filtering, i.e. PLplot physical
  42. * coordinates are the same as the device physical coordinates (currently
  43. * this can't be changed anyway), and a global view equal to the entire page
  44. * is used.
  45. *
  46. * The reason one wants to put view-specific filtering here is that if
  47. * enabled, the plot buffer should receive the unfiltered data stream. This
  48. * allows a specific view to be used from an interactive device (e.g. TCL/TK
  49. * driver) but be restored to the full view at any time merely by
  50. * reprocessing the contents of the plot buffer.
  51. *
  52. * The metafile, on the other hand, *should* be affected by changes in the
  53. * view, since this is a crucial editing capability. It is recommended that
  54. * the initial metafile be created without a restricted global view, and
  55. * modification of the view done on a per-plot basis as desired during
  56. * subsequent processing.
  57. *
  58. \*--------------------------------------------------------------------------*/
  59. enum {AT_BOP, DRAWING, AT_EOP};
  60. /* Initialize device. */
  61. /* The plot buffer must be called last. */
  62. /* The following array of chars is used both here and in plsym.c for
  63. * translating the Greek characters from the #g escape sequences into
  64. * the Hershey and Unicode codings
  65. */
  66. const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
  67. void
  68. plP_init(void)
  69. {
  70. plsc->page_status = AT_EOP;
  71. (*plsc->dispatch_table->pl_init) ((struct PLStream_struct *) plsc);
  72. if (plsc->plbuf_write)
  73. plbuf_init(plsc);
  74. }
  75. /* End of page */
  76. /* The plot buffer must be called first. */
  77. /* Ignore instruction if already at eop. */
  78. void
  79. plP_eop(void)
  80. {
  81. int skip_driver_eop = 0;
  82. if (plsc->page_status == AT_EOP)
  83. return;
  84. plsc->page_status = AT_EOP;
  85. if (plsc->plbuf_write)
  86. plbuf_eop(plsc);
  87. /* Call user eop handler if present. */
  88. if (plsc->eop_handler != NULL)
  89. (*plsc->eop_handler) (plsc->eop_data, &skip_driver_eop);
  90. if (!skip_driver_eop)
  91. (*plsc->dispatch_table->pl_eop) ((struct PLStream_struct *) plsc);
  92. }
  93. /* Set up new page. */
  94. /* The plot buffer must be called last. */
  95. /* Ignore if already at bop. */
  96. /* It's not actually necessary to be AT_EOP here, so don't check for it. */
  97. void
  98. plP_bop(void)
  99. {
  100. int skip_driver_bop = 0;
  101. plP_subpInit();
  102. if (plsc->page_status == AT_BOP)
  103. return;
  104. plsc->page_status = AT_BOP;
  105. plsc->nplwin = 0;
  106. /* Call user bop handler if present. */
  107. if (plsc->bop_handler != NULL)
  108. (*plsc->bop_handler) (plsc->bop_data, &skip_driver_bop);
  109. if (!skip_driver_bop)
  110. (*plsc->dispatch_table->pl_bop) ((struct PLStream_struct *) plsc);
  111. if (plsc->plbuf_write)
  112. plbuf_bop(plsc);
  113. }
  114. /* Tidy up device (flush buffers, close file, etc). */
  115. void
  116. plP_tidy(void)
  117. {
  118. if (plsc->tidy) {
  119. (*plsc->tidy) (plsc->tidy_data);
  120. plsc->tidy = NULL;
  121. plsc->tidy_data = NULL;
  122. }
  123. (*plsc->dispatch_table->pl_tidy) ((struct PLStream_struct *) plsc);
  124. if (plsc->plbuf_write)
  125. plbuf_tidy(plsc);
  126. plsc->OutFile = NULL;
  127. }
  128. /* Change state. */
  129. void
  130. plP_state(PLINT op)
  131. {
  132. (*plsc->dispatch_table->pl_state) ((struct PLStream_struct *) plsc, op);
  133. if (plsc->plbuf_write)
  134. plbuf_state(plsc, op);
  135. }
  136. /* Escape function, for driver-specific commands. */
  137. void
  138. plP_esc(PLINT op, void *ptr)
  139. {
  140. (*plsc->dispatch_table->pl_esc) ((struct PLStream_struct *) plsc, op, ptr);
  141. if (plsc->plbuf_write)
  142. plbuf_esc(plsc, op, ptr);
  143. }
  144. /* Set up plot window parameters. */
  145. /* The plot buffer must be called first */
  146. /* Some drivers (metafile, Tk) need access to this data */
  147. void
  148. plP_swin(PLWindow *plwin)
  149. {
  150. PLWindow *w;
  151. PLINT clpxmi, clpxma, clpymi, clpyma;
  152. /* Provide plot buffer with unfiltered window data */
  153. if (plsc->plbuf_write)
  154. plbuf_esc(plsc, PLESC_SWIN, (void *) plwin);
  155. w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
  156. w->dxmi = plwin->dxmi;
  157. w->dxma = plwin->dxma;
  158. w->dymi = plwin->dymi;
  159. w->dyma = plwin->dyma;
  160. if (plsc->difilt) {
  161. xscl[0] = plP_dcpcx(w->dxmi);
  162. xscl[1] = plP_dcpcx(w->dxma);
  163. yscl[0] = plP_dcpcy(w->dymi);
  164. yscl[1] = plP_dcpcy(w->dyma);
  165. difilt(xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma);
  166. w->dxmi = plP_pcdcx(xscl[0]);
  167. w->dxma = plP_pcdcx(xscl[1]);
  168. w->dymi = plP_pcdcy(yscl[0]);
  169. w->dyma = plP_pcdcy(yscl[1]);
  170. }
  171. w->wxmi = plwin->wxmi;
  172. w->wxma = plwin->wxma;
  173. w->wymi = plwin->wymi;
  174. w->wyma = plwin->wyma;
  175. /* If the driver wants to process swin commands, call it now */
  176. /* It must use the filtered data, which it can get from *plsc */
  177. if (plsc->dev_swin) {
  178. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  179. PLESC_SWIN, NULL );
  180. }
  181. }
  182. /*--------------------------------------------------------------------------*\
  183. * Drawing commands.
  184. \*--------------------------------------------------------------------------*/
  185. /* Draw line between two points */
  186. /* The plot buffer must be called first so it gets the unfiltered data */
  187. void
  188. plP_line(short *x, short *y)
  189. {
  190. PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
  191. plsc->page_status = DRAWING;
  192. if (plsc->plbuf_write)
  193. plbuf_line(plsc, x[0], y[0], x[1], y[1]);
  194. if (plsc->difilt) {
  195. for (i = 0; i < npts; i++) {
  196. xscl[i] = x[i];
  197. yscl[i] = y[i];
  198. }
  199. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  200. plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline);
  201. }
  202. else {
  203. grline(x, y, npts);
  204. }
  205. }
  206. /* Draw polyline */
  207. /* The plot buffer must be called first */
  208. void
  209. plP_polyline(short *x, short *y, PLINT npts)
  210. {
  211. PLINT i, clpxmi, clpxma, clpymi, clpyma;
  212. plsc->page_status = DRAWING;
  213. if (plsc->plbuf_write)
  214. plbuf_polyline(plsc, x, y, npts);
  215. if (plsc->difilt) {
  216. for (i = 0; i < npts; i++) {
  217. xscl[i] = x[i];
  218. yscl[i] = y[i];
  219. }
  220. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  221. plP_pllclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  222. grpolyline);
  223. }
  224. else {
  225. grpolyline(x, y, npts);
  226. }
  227. }
  228. /* Fill polygon */
  229. /* The plot buffer must be called first */
  230. /* Here if the desired area fill capability isn't present, we mock up */
  231. /* something in software */
  232. static int foo;
  233. void
  234. plP_fill(short *x, short *y, PLINT npts)
  235. {
  236. PLINT i, clpxmi, clpxma, clpymi, clpyma;
  237. plsc->page_status = DRAWING;
  238. if (plsc->plbuf_write) {
  239. plsc->dev_npts = npts;
  240. plsc->dev_x = x;
  241. plsc->dev_y = y;
  242. plbuf_esc(plsc, PLESC_FILL, NULL);
  243. }
  244. /* Account for driver ability to do fills */
  245. if (plsc->patt == 0 && ! plsc->dev_fill0) {
  246. if ( ! foo) {
  247. plwarn("Driver does not support hardware solid fills, switching to software fill.\n");
  248. foo = 1;
  249. }
  250. plsc->patt = 8;
  251. plpsty(plsc->patt);
  252. }
  253. if (plsc->dev_fill1) {
  254. plsc->patt = -ABS(plsc->patt);
  255. }
  256. /* Perform fill. Here we MUST NOT allow the software fill to pass through the
  257. driver interface filtering twice, else we get the infamous 2*rotation for
  258. software fills on orientation swaps.
  259. */
  260. if (plsc->patt > 0)
  261. plfill_soft(x, y, npts);
  262. else {
  263. if (plsc->difilt) {
  264. for (i = 0; i < npts; i++) {
  265. xscl[i] = x[i];
  266. yscl[i] = y[i];
  267. }
  268. difilt(xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma);
  269. plP_plfclp(xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
  270. grfill);
  271. }
  272. else {
  273. grfill(x, y, npts);
  274. }
  275. }
  276. }
  277. /* Account for driver ability to draw text itself */
  278. /*
  279. #define DEBUG_TEXT
  280. */
  281. #define hex2dec( a ) isdigit(a) ? a - 48 : (toupper(a) - 65) + 10
  282. /*--------------------------------------------------------------------------*\
  283. * int text2num( char *text, char end, PLUNICODE *num)
  284. * char *text - pointer to the text to be parsed
  285. * char end - end character (i.e. ')' or ']' to stop parsing
  286. * PLUNICODE *num - pointer to an PLUNICODE to store the value
  287. *
  288. * Function takes a string, which can be either hex or decimal,
  289. * and converts it into an PLUNICODE, stopping at either a null,
  290. * or the character pointed to by 'end'. It is a bit brain-dead,
  291. * and probably should make more checks, but it works.
  292. \*--------------------------------------------------------------------------*/
  293. int text2num( const char *text, char end, PLUNICODE *num)
  294. {
  295. int base=10;
  296. unsigned short i=0;
  297. *num=0;
  298. if (text[1]=='x')
  299. {
  300. base=16;
  301. i=2;
  302. }
  303. while ((text[i]!=end)&&(text[i]!=0))
  304. {
  305. *num*=base;
  306. *num+=hex2dec(text[i]);
  307. i++;
  308. }
  309. return(i);
  310. }
  311. /*--------------------------------------------------------------------------*\
  312. * int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
  313. * char *text - pointer to the text to be parsed
  314. * unsigned char *hexdigit - pointer to hex value that is stored.
  315. * unsigned char *hexpower - pointer to hex power (left shift) that is stored.
  316. *
  317. * Function takes a pointer to a string, which is looked up in a table
  318. * to determine the corresponding FCI (font characterization integer)
  319. * hex digit value and hex power (left shift).
  320. * If the lookup succeeds, hexdigit and hexpower are set to the appropriate
  321. * values in the table, and the function returns the number of characters
  322. * in text that are consumed by the matching string in the table lookup.
  323. *
  324. * If the lookup fails, hexdigit is set to 0, hexpower is set to and
  325. * impossible value, and the function returns 0.
  326. \*--------------------------------------------------------------------------*/
  327. int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower)
  328. {
  329. typedef struct
  330. {
  331. char *ptext;
  332. unsigned char hexdigit;
  333. unsigned char hexpower;
  334. }
  335. TextLookupTable;
  336. /* This defines the various font control commands and the corresponding
  337. * hexdigit and hexpower in the FCI.
  338. */
  339. #define N_TextLookupTable 10
  340. const TextLookupTable lookup[N_TextLookupTable] = {
  341. {"<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY},
  342. {"<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY},
  343. {"<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY},
  344. {"<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY},
  345. {"<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY},
  346. {"<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE},
  347. {"<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE},
  348. {"<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE},
  349. {"<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT},
  350. {"<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT}
  351. };
  352. int i, length;
  353. for (i=0; i<N_TextLookupTable; i++) {
  354. length = strlen(lookup[i].ptext);
  355. if (! strncmp(text, lookup[i].ptext, length)) {
  356. *hexdigit = lookup[i].hexdigit;
  357. *hexpower = lookup[i].hexpower;
  358. return(length);
  359. }
  360. }
  361. *hexdigit = 0;
  362. *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
  363. return(0);
  364. }
  365. PLUNICODE unicode_buffer[1024];
  366. void
  367. plP_text(PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
  368. PLINT refx, PLINT refy, const char *string)
  369. {
  370. if (plsc->dev_text) { /* Does the device render it's own text ? */
  371. EscText args;
  372. short len=0;
  373. char skip;
  374. unsigned short i,j, k;
  375. PLUNICODE code;
  376. char esc;
  377. int idx;
  378. args.base = base;
  379. args.just = just;
  380. args.xform = xform;
  381. args.x = x;
  382. args.y = y;
  383. args.refx = refx;
  384. args.refy = refy;
  385. if (plsc->dev_unicode) { /* Does the device also understand unicode ? */
  386. PLINT ig;
  387. PLUNICODE fci, fcisave;
  388. unsigned char hexdigit, hexpower;
  389. if (string!=NULL) { /* If the string isn't blank, then we will continue */
  390. len=strlen(string); /* this length is only used in the loop counter, we will work out the length of the unicode string as we go */
  391. plgesc(&esc);
  392. /* At this stage we will do some translations into unicode, like conversion to
  393. * Greek , and will save other translations such as superscript for the driver to
  394. * do later on. As we move through the string and do the translations, we will get
  395. * rid of the esc character sequence, just replacing it with unicode.
  396. */
  397. /* Obtain FCI (font characterization integer) for start of string. */
  398. plgfci(&fci);
  399. for (j=i=0;i<len;i++) { /* Walk through the strings, and convert some stuff to unicode on the fly */
  400. skip=0;
  401. if (string[i]==esc) {
  402. switch(string[i+1]) {
  403. case '(': /* hershey code */
  404. i+=2+text2num(&string[i+2],')',&code);
  405. idx=plhershey2unicode(code);
  406. /* momentarily switch to symbol font. */
  407. fcisave = fci;
  408. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  409. unicode_buffer[j++]= fci;
  410. unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
  411. /* if unicode_buffer[j-1] corresponds to the escape character
  412. * must unescape it by appending one more. This will probably
  413. * always be necessary since it is likely unicode_buffer
  414. * will always have to contain escape characters that are
  415. * interpreted by the device driver.
  416. */
  417. if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
  418. fci = fcisave;
  419. unicode_buffer[j]= fci;
  420. skip=1;
  421. break;
  422. case '[': /* unicode */
  423. i+=2+text2num(&string[i+2],']',&code);
  424. /* momentarily switch to symbol font. */
  425. fcisave = fci;
  426. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  427. unicode_buffer[j++]= fci;
  428. unicode_buffer[j++]=code;
  429. /* if unicode_buffer[j-1] corresponds to the escape character
  430. * must unescape it by appending one more. This will probably
  431. * always be necessary since it is likely unicode_buffer
  432. * will always have to contain escape characters that are
  433. * interpreted by the device driver.
  434. */
  435. if (unicode_buffer[j-1]==esc) unicode_buffer[j++]=esc;
  436. fci = fcisave;
  437. unicode_buffer[j] = fci;
  438. skip=1;
  439. break;
  440. case '<': /* change font*/
  441. i+=2;
  442. if ('0' <= string[i] && string[i] <= '9' ) {
  443. i+=text2num(&string[i],'>', &code);
  444. if (code & PL_FCI_MARK) {
  445. /* code is a complete FCI (font characterization
  446. * integer): change FCI to this value.
  447. */
  448. fci = code;
  449. unicode_buffer[j]=fci;
  450. skip=1;
  451. }
  452. else {
  453. /* code is not complete FCI. Change
  454. * FCI with hex power in rightmost hex
  455. * digit and hex digit value in second rightmost
  456. * hex digit.
  457. */
  458. hexdigit = (code >> 4) & PL_FCI_HEXDIGIT_MASK;
  459. hexpower = code & PL_FCI_HEXPOWER_MASK;
  460. plP_hex2fci(hexdigit, hexpower, &fci);
  461. unicode_buffer[j]=fci;
  462. skip=1;
  463. }
  464. }
  465. else {
  466. /* align i on "<" because that is what text2fci
  467. * expects. */
  468. i--;
  469. i+=text2fci(&string[i], &hexdigit, &hexpower);
  470. if (hexpower < 7) {
  471. plP_hex2fci(hexdigit, hexpower, &fci);
  472. unicode_buffer[j]=fci;
  473. skip=1;
  474. }
  475. }
  476. break;
  477. case 'f': /* Deprecated Hershey-style font change*/
  478. case 'F': /* Deprecated Hershey-style font change*/
  479. /* We implement an approximate response here so that reasonable
  480. * results are obtained for unicode fonts, but this
  481. * method is deprecated and the #<nnn> or
  482. * #<command string> methods should be used instead
  483. * to change unicode fonts in mid-string.
  484. */
  485. fci = PL_FCI_MARK;
  486. if (string[i+2] == 'n') {
  487. /* medium, upright, sans-serif */
  488. plP_hex2fci(PL_FCI_SANS, PL_FCI_FAMILY, &fci);
  489. } else if (string[i+2] == 'r') {
  490. /* medium, upright, serif */
  491. plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
  492. } else if (string[i+2] == 'i') {
  493. /* medium, italic, serif */
  494. plP_hex2fci(PL_FCI_ITALIC, PL_FCI_STYLE, &fci);
  495. plP_hex2fci(PL_FCI_SERIF, PL_FCI_FAMILY, &fci);
  496. } else if (string[i+2] == 's') {
  497. /* medium, upright, script */
  498. plP_hex2fci(PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci);
  499. } else
  500. fci = PL_FCI_IMPOSSIBLE;
  501. if (fci != PL_FCI_IMPOSSIBLE){
  502. i+=2;
  503. unicode_buffer[j] = fci;
  504. skip = 1;
  505. }
  506. break;
  507. case 'g': /* Greek font */
  508. case 'G': /* Greek font */
  509. /* Get the index in the lookup table
  510. * 527 = upper case alpha displacement in Hershey Table
  511. * 627 = lower case alpha displacement in Hershey Table
  512. */
  513. /* momentarily switch to symbol font. */
  514. fcisave = fci;
  515. plP_hex2fci(PL_FCI_SYMBOL, PL_FCI_FAMILY, &fci);
  516. unicode_buffer[j++]= fci;
  517. ig = plP_strpos(plP_greek_mnemonic, string[i+2]);
  518. if (ig >= 0) {
  519. if (ig >= 24)
  520. ig = ig + 100 - 24;
  521. idx=plhershey2unicode(ig+527);
  522. unicode_buffer[j++]=(PLUNICODE)hershey_to_unicode_lookup_table[idx].Unicode;
  523. i+=2;
  524. skip=1; /* skip is set if we have copied something into the unicode table */
  525. }
  526. else {
  527. /* Use "unknown" unicode character if string[i+2] is not in
  528. * the Greek array.*/
  529. unicode_buffer[j++]=(PLUNICODE)0x00;
  530. i+=2;
  531. skip=1; /* skip is set if we have copied something into the unicode table */
  532. }
  533. fci = fcisave;
  534. unicode_buffer[j]= fci;
  535. break;
  536. }
  537. }
  538. if (skip==0) {
  539. #ifdef HAVE_LIBUNICODE
  540. unicode_char_t unichar;
  541. char* ptr =
  542. unicode_get_utf8 (string + i, &unichar);
  543. if (ptr == NULL) {
  544. char buf[80];
  545. strncpy (buf, string, 30);
  546. sprintf (buf, "UTF-8 string is malformed: %s%s",
  547. buf, strlen (string) > 30 ? "[...]" : "");
  548. plabort (buf);
  549. }
  550. unicode_buffer [j] = (PLUNICODE) unichar;
  551. i += ptr - (string + i) - 1;
  552. #else
  553. unicode_buffer[j]=string[i];
  554. #endif
  555. /* Search for escesc (an unescaped escape) in the input string
  556. * and adjust unicode_buffer accordingly).
  557. */
  558. if (unicode_buffer[j] == esc && string[i+1] == esc) {
  559. i++;
  560. unicode_buffer[++j] = esc;
  561. }
  562. }
  563. j++;
  564. }
  565. if (j > 0) {
  566. args.unicode_array_len=j; /* Much easier to set the length than work it out later :-) */
  567. args.unicode_array=&unicode_buffer[0]; /* Get address of the unicode buffer (even though it is currently static) */
  568. args.string=NULL; /* Since we are using unicode, we want this to be NULL */
  569. } else
  570. /* Don't print anything, if there is no unicode to print! */
  571. return;
  572. }
  573. } else {
  574. args.string = string;
  575. }
  576. if (plsc->plbuf_write)
  577. plbuf_esc(plsc, PLESC_HAS_TEXT, &args);
  578. plP_esc(PLESC_HAS_TEXT, &args);
  579. #ifndef DEBUG_TEXT
  580. } else {
  581. #endif
  582. plstr(base, xform, refx, refy, string);
  583. }
  584. }
  585. static void
  586. grline(short *x, short *y, PLINT npts)
  587. {
  588. (*plsc->dispatch_table->pl_line) ( (struct PLStream_struct *) plsc,
  589. x[0], y[0], x[1], y[1] );
  590. }
  591. static void
  592. grpolyline(short *x, short *y, PLINT npts)
  593. {
  594. (*plsc->dispatch_table->pl_polyline) ( (struct PLStream_struct *) plsc,
  595. x, y, npts );
  596. }
  597. static void
  598. grfill(short *x, short *y, PLINT npts)
  599. {
  600. plsc->dev_npts = npts;
  601. plsc->dev_x = x;
  602. plsc->dev_y = y;
  603. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  604. PLESC_FILL, NULL );
  605. }
  606. /*--------------------------------------------------------------------------*\
  607. * void difilt
  608. *
  609. * Driver interface filter -- passes all coordinates through a variety
  610. * of filters. These include filters to change :
  611. *
  612. * - mapping of meta to physical coordinates
  613. * - plot orientation
  614. * - window into plot (zooms)
  615. * - window into device (i.e set margins)
  616. *
  617. * The filters are applied in the order specified above. Because the
  618. * orientation change comes first, subsequent window specifications affect
  619. * the new coordinates (i.e. after a 90 degree flip, what was x is now y).
  620. * This is the only way that makes sense from a graphical interface
  621. * (e.g. TCL/TK driver).
  622. *
  623. * Where appropriate, the page clip limits are modified.
  624. \*--------------------------------------------------------------------------*/
  625. void
  626. difilt(PLINT *xscl, PLINT *yscl, PLINT npts,
  627. PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
  628. {
  629. PLINT i, x, y;
  630. /* Map meta coordinates to physical coordinates */
  631. if (plsc->difilt & PLDI_MAP) {
  632. for (i = 0; i < npts; i++) {
  633. xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
  634. yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
  635. }
  636. }
  637. /* Change orientation */
  638. if (plsc->difilt & PLDI_ORI) {
  639. for (i = 0; i < npts; i++) {
  640. x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
  641. y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
  642. xscl[i] = x;
  643. yscl[i] = y;
  644. }
  645. }
  646. /* Change window into plot space */
  647. if (plsc->difilt & PLDI_PLT) {
  648. for (i = 0; i < npts; i++) {
  649. xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
  650. yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
  651. }
  652. }
  653. /* Change window into device space and set clip limits */
  654. /* (this is the only filter that modifies them) */
  655. if (plsc->difilt & PLDI_DEV) {
  656. for (i = 0; i < npts; i++) {
  657. xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
  658. yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
  659. }
  660. *clpxmi = plsc->diclpxmi;
  661. *clpxma = plsc->diclpxma;
  662. *clpymi = plsc->diclpymi;
  663. *clpyma = plsc->diclpyma;
  664. }
  665. else {
  666. *clpxmi = plsc->phyxmi;
  667. *clpxma = plsc->phyxma;
  668. *clpymi = plsc->phyymi;
  669. *clpyma = plsc->phyyma;
  670. }
  671. }
  672. void
  673. sdifilt(short *xscl, short *yscl, PLINT npts,
  674. PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
  675. {
  676. int i;
  677. short x, y;
  678. /* Map meta coordinates to physical coordinates */
  679. if (plsc->difilt & PLDI_MAP) {
  680. for (i = 0; i < npts; i++) {
  681. xscl[i] = plsc->dimxax * xscl[i] + plsc->dimxb;
  682. yscl[i] = plsc->dimyay * yscl[i] + plsc->dimyb;
  683. }
  684. }
  685. /* Change orientation */
  686. if (plsc->difilt & PLDI_ORI) {
  687. for (i = 0; i < npts; i++) {
  688. x = plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb;
  689. y = plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb;
  690. xscl[i] = x;
  691. yscl[i] = y;
  692. }
  693. }
  694. /* Change window into plot space */
  695. if (plsc->difilt & PLDI_PLT) {
  696. for (i = 0; i < npts; i++) {
  697. xscl[i] = plsc->dipxax * xscl[i] + plsc->dipxb;
  698. yscl[i] = plsc->dipyay * yscl[i] + plsc->dipyb;
  699. }
  700. }
  701. /* Change window into device space and set clip limits */
  702. /* (this is the only filter that modifies them) */
  703. if (plsc->difilt & PLDI_DEV) {
  704. for (i = 0; i < npts; i++) {
  705. xscl[i] = plsc->didxax * xscl[i] + plsc->didxb;
  706. yscl[i] = plsc->didyay * yscl[i] + plsc->didyb;
  707. }
  708. *clpxmi = plsc->diclpxmi;
  709. *clpxma = plsc->diclpxma;
  710. *clpymi = plsc->diclpymi;
  711. *clpyma = plsc->diclpyma;
  712. }
  713. else {
  714. *clpxmi = plsc->phyxmi;
  715. *clpxma = plsc->phyxma;
  716. *clpymi = plsc->phyymi;
  717. *clpyma = plsc->phyyma;
  718. }
  719. }
  720. /*--------------------------------------------------------------------------*\
  721. * void pldi_ini
  722. *
  723. * Updates driver interface, making sure everything is in order.
  724. * Even if filter is not being used, the defaults need to be set up.
  725. \*--------------------------------------------------------------------------*/
  726. static void
  727. setdef_diplt()
  728. {
  729. plsc->dipxmin = 0.0;
  730. plsc->dipxmax = 1.0;
  731. plsc->dipymin = 0.0;
  732. plsc->dipymax = 1.0;
  733. }
  734. static void
  735. setdef_didev()
  736. {
  737. plsc->mar = 0.0;
  738. plsc->aspect = 0.0;
  739. plsc->jx = 0.0;
  740. plsc->jy = 0.0;
  741. }
  742. static void
  743. setdef_diori()
  744. {
  745. plsc->diorot = 0.;
  746. }
  747. static void
  748. pldi_ini(void)
  749. {
  750. if (plsc->level >= 1) {
  751. if (plsc->difilt & PLDI_MAP) /* Coordinate mapping */
  752. calc_dimap();
  753. if (plsc->difilt & PLDI_ORI) /* Orientation */
  754. calc_diori();
  755. else
  756. setdef_diori();
  757. if (plsc->difilt & PLDI_PLT) /* Plot window */
  758. calc_diplt();
  759. else
  760. setdef_diplt();
  761. if (plsc->difilt & PLDI_DEV) /* Device window */
  762. calc_didev();
  763. else
  764. setdef_didev();
  765. }
  766. }
  767. /*--------------------------------------------------------------------------*\
  768. * void pldid2pc
  769. *
  770. * Converts input values from relative device coordinates to relative plot
  771. * coordinates. This function must be called when selecting a plot window
  772. * from a display driver, since the coordinates chosen by the user are
  773. * necessarily device-specific.
  774. \*--------------------------------------------------------------------------*/
  775. void
  776. pldid2pc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  777. {
  778. PLFLT pxmin, pymin, pxmax, pymax;
  779. PLFLT sxmin, symin, sxmax, symax;
  780. PLFLT rxmin, rymin, rxmax, rymax;
  781. if (plsc->difilt & PLDI_DEV) {
  782. pldebug("pldid2pc",
  783. "Relative device coordinates (in): %f, %f, %f, %f\n",
  784. *xmin, *ymin, *xmax, *ymax);
  785. pxmin = plP_dcpcx(*xmin);
  786. pymin = plP_dcpcy(*ymin);
  787. pxmax = plP_dcpcx(*xmax);
  788. pymax = plP_dcpcy(*ymax);
  789. sxmin = (pxmin - plsc->didxb) / plsc->didxax;
  790. symin = (pymin - plsc->didyb) / plsc->didyay;
  791. sxmax = (pxmax - plsc->didxb) / plsc->didxax;
  792. symax = (pymax - plsc->didyb) / plsc->didyay;
  793. rxmin = plP_pcdcx(sxmin);
  794. rymin = plP_pcdcy(symin);
  795. rxmax = plP_pcdcx(sxmax);
  796. rymax = plP_pcdcy(symax);
  797. *xmin = (rxmin < 0) ? 0 : rxmin;
  798. *xmax = (rxmax > 1) ? 1 : rxmax;
  799. *ymin = (rymin < 0) ? 0 : rymin;
  800. *ymax = (rymax > 1) ? 1 : rymax;
  801. pldebug("pldid2pc",
  802. "Relative plot coordinates (out): %f, %f, %f, %f\n",
  803. rxmin, rymin, rxmax, rymax);
  804. }
  805. }
  806. /*--------------------------------------------------------------------------*\
  807. * void pldip2dc
  808. *
  809. * Converts input values from relative plot coordinates to relative
  810. * device coordinates.
  811. \*--------------------------------------------------------------------------*/
  812. void
  813. pldip2dc(PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax)
  814. {
  815. PLFLT pxmin, pymin, pxmax, pymax;
  816. PLFLT sxmin, symin, sxmax, symax;
  817. PLFLT rxmin, rymin, rxmax, rymax;
  818. if (plsc->difilt & PLDI_DEV) {
  819. pldebug("pldip2pc",
  820. "Relative plot coordinates (in): %f, %f, %f, %f\n",
  821. *xmin, *ymin, *xmax, *ymax);
  822. pxmin = plP_dcpcx(*xmin);
  823. pymin = plP_dcpcy(*ymin);
  824. pxmax = plP_dcpcx(*xmax);
  825. pymax = plP_dcpcy(*ymax);
  826. sxmin = pxmin * plsc->didxax + plsc->didxb;
  827. symin = pymin * plsc->didyay + plsc->didyb;
  828. sxmax = pxmax * plsc->didxax + plsc->didxb;
  829. symax = pymax * plsc->didyay + plsc->didyb;
  830. rxmin = plP_pcdcx(sxmin);
  831. rymin = plP_pcdcy(symin);
  832. rxmax = plP_pcdcx(sxmax);
  833. rymax = plP_pcdcy(symax);
  834. *xmin = (rxmin < 0) ? 0 : rxmin;
  835. *xmax = (rxmax > 1) ? 1 : rxmax;
  836. *ymin = (rymin < 0) ? 0 : rymin;
  837. *ymax = (rymax > 1) ? 1 : rymax;
  838. pldebug("pldip2pc",
  839. "Relative device coordinates (out): %f, %f, %f, %f\n",
  840. rxmin, rymin, rxmax, rymax);
  841. }
  842. }
  843. /*--------------------------------------------------------------------------*\
  844. * void plsdiplt
  845. *
  846. * Set window into plot space
  847. \*--------------------------------------------------------------------------*/
  848. void
  849. c_plsdiplt(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  850. {
  851. plsc->dipxmin = (xmin < xmax) ? xmin : xmax;
  852. plsc->dipxmax = (xmin < xmax) ? xmax : xmin;
  853. plsc->dipymin = (ymin < ymax) ? ymin : ymax;
  854. plsc->dipymax = (ymin < ymax) ? ymax : ymin;
  855. if (xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1.) {
  856. plsc->difilt &= ~PLDI_PLT;
  857. return;
  858. }
  859. plsc->difilt |= PLDI_PLT;
  860. pldi_ini();
  861. }
  862. /*--------------------------------------------------------------------------*\
  863. * void plsdiplz
  864. *
  865. * Set window into plot space incrementally (zoom)
  866. \*--------------------------------------------------------------------------*/
  867. void
  868. c_plsdiplz(PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax)
  869. {
  870. if (plsc->difilt & PLDI_PLT) {
  871. xmin = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmin;
  872. ymin = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymin;
  873. xmax = plsc->dipxmin + (plsc->dipxmax - plsc->dipxmin) * xmax;
  874. ymax = plsc->dipymin + (plsc->dipymax - plsc->dipymin) * ymax;
  875. }
  876. plsdiplt(xmin, ymin, xmax, ymax);
  877. }
  878. /*--------------------------------------------------------------------------*\
  879. * void calc_diplt
  880. *
  881. * Calculate transformation coefficients to set window into plot space.
  882. *
  883. * Note: if driver has requested to handle these commands itself, we must
  884. * send the appropriate escape command. If the driver succeeds it will
  885. * cancel the filter operation. The command is deferred until this point
  886. * to ensure that the driver has been initialized.
  887. \*--------------------------------------------------------------------------*/
  888. static void
  889. calc_diplt(void)
  890. {
  891. PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  892. if (plsc->dev_di) {
  893. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  894. PLESC_DI, NULL );
  895. }
  896. if ( ! (plsc->difilt & PLDI_PLT))
  897. return;
  898. pxmin = plP_dcpcx(plsc->dipxmin);
  899. pxmax = plP_dcpcx(plsc->dipxmax);
  900. pymin = plP_dcpcy(plsc->dipymin);
  901. pymax = plP_dcpcy(plsc->dipymax);
  902. pxlen = pxmax - pxmin;
  903. pylen = pymax - pymin;
  904. pxlen = MAX(1, pxlen);
  905. pylen = MAX(1, pylen);
  906. plsc->dipxax = plsc->phyxlen / (double) pxlen;
  907. plsc->dipyay = plsc->phyylen / (double) pylen;
  908. plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
  909. plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
  910. }
  911. /*--------------------------------------------------------------------------*\
  912. * void plgdiplt
  913. *
  914. * Retrieve current window into plot space
  915. \*--------------------------------------------------------------------------*/
  916. void
  917. c_plgdiplt(PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax)
  918. {
  919. *p_xmin = plsc->dipxmin;
  920. *p_xmax = plsc->dipxmax;
  921. *p_ymin = plsc->dipymin;
  922. *p_ymax = plsc->dipymax;
  923. }
  924. /*--------------------------------------------------------------------------*\
  925. * void plsdidev
  926. *
  927. * Set window into device space using margin, aspect ratio, and
  928. * justification. If you want to just use the previous value for any of
  929. * these, just pass in the magic value PL_NOTSET.
  930. *
  931. * It is unlikely that one should ever need to change the aspect ratio
  932. * but it's in there for completeness.
  933. \*--------------------------------------------------------------------------*/
  934. void
  935. c_plsdidev(PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy)
  936. {
  937. plsetvar(plsc->mar, mar);
  938. plsetvar(plsc->aspect, aspect);
  939. plsetvar(plsc->jx, jx);
  940. plsetvar(plsc->jy, jy);
  941. if (mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
  942. ! (plsc->difilt & PLDI_ORI)) {
  943. plsc->difilt &= ~PLDI_DEV;
  944. return;
  945. }
  946. plsc->difilt |= PLDI_DEV;
  947. pldi_ini();
  948. }
  949. /*--------------------------------------------------------------------------*\
  950. * void calc_didev
  951. *
  952. * Calculate transformation coefficients to set window into device space.
  953. * Calculates relative window bounds and calls plsdidxy to finish the job.
  954. \*--------------------------------------------------------------------------*/
  955. static void
  956. calc_didev(void)
  957. {
  958. PLFLT lx, ly, aspect, aspdev;
  959. PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
  960. PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
  961. if (plsc->dev_di) {
  962. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  963. PLESC_DI, NULL );
  964. }
  965. if ( ! (plsc->difilt & PLDI_DEV))
  966. return;
  967. /* Calculate aspect ratio of physical device */
  968. lx = plsc->phyxlen / plsc->xpmm;
  969. ly = plsc->phyylen / plsc->ypmm;
  970. aspdev = lx / ly;
  971. if (plsc->difilt & PLDI_ORI)
  972. aspect = plsc->aspori;
  973. else
  974. aspect = plsc->aspect;
  975. if (aspect <= 0.)
  976. aspect = plsc->aspdev;
  977. /* Failsafe */
  978. plsc->mar = (plsc->mar > 0.5) ? 0.5 : plsc->mar;
  979. plsc->mar = (plsc->mar < 0.0) ? 0.0 : plsc->mar;
  980. plsc->jx = (plsc->jx > 0.5) ? 0.5 : plsc->jx;
  981. plsc->jx = (plsc->jx < -0.5) ? -0.5 : plsc->jx;
  982. plsc->jy = (plsc->jy > 0.5) ? 0.5 : plsc->jy;
  983. plsc->jy = (plsc->jy < -0.5) ? -0.5 : plsc->jy;
  984. /* Relative device coordinates that neutralize aspect ratio difference */
  985. xlen = (aspect < aspdev) ? (aspect / aspdev) : 1.0;
  986. ylen = (aspect < aspdev) ? 1.0 : (aspdev / aspect);
  987. xlen *= (1.0 - 2.*plsc->mar);
  988. ylen *= (1.0 - 2.*plsc->mar);
  989. xmin = (1. - xlen) * (0.5 + plsc->jx);
  990. xmax = xmin + xlen;
  991. ymin = (1. - ylen) * (0.5 + plsc->jy);
  992. ymax = ymin + ylen;
  993. /* Calculate transformation coefficients */
  994. pxmin = plP_dcpcx(xmin);
  995. pxmax = plP_dcpcx(xmax);
  996. pymin = plP_dcpcy(ymin);
  997. pymax = plP_dcpcy(ymax);
  998. pxlen = pxmax - pxmin;
  999. pylen = pymax - pymin;
  1000. pxlen = MAX(1, pxlen);
  1001. pylen = MAX(1, pylen);
  1002. plsc->didxax = pxlen / (double) plsc->phyxlen;
  1003. plsc->didyay = pylen / (double) plsc->phyylen;
  1004. plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
  1005. plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
  1006. /* Set clip limits to conform to new page size */
  1007. plsc->diclpxmi = plsc->didxax * plsc->phyxmi + plsc->didxb;
  1008. plsc->diclpxma = plsc->didxax * plsc->phyxma + plsc->didxb;
  1009. plsc->diclpymi = plsc->didyay * plsc->phyymi + plsc->didyb;
  1010. plsc->diclpyma = plsc->didyay * plsc->phyyma + plsc->didyb;
  1011. }
  1012. /*--------------------------------------------------------------------------*\
  1013. * void plgdidev
  1014. *
  1015. * Retrieve current window into device space
  1016. \*--------------------------------------------------------------------------*/
  1017. void
  1018. c_plgdidev(PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy)
  1019. {
  1020. *p_mar = plsc->mar;
  1021. *p_aspect = plsc->aspect;
  1022. *p_jx = plsc->jx;
  1023. *p_jy = plsc->jy;
  1024. }
  1025. /*--------------------------------------------------------------------------*\
  1026. * void plsdiori
  1027. *
  1028. * Set plot orientation, specifying rotation in units of pi/2.
  1029. \*--------------------------------------------------------------------------*/
  1030. void
  1031. c_plsdiori(PLFLT rot)
  1032. {
  1033. plsc->diorot = rot;
  1034. if (rot == 0.) {
  1035. plsc->difilt &= ~PLDI_ORI;
  1036. pldi_ini();
  1037. return;
  1038. }
  1039. plsc->difilt |= PLDI_ORI;
  1040. pldi_ini();
  1041. }
  1042. /*--------------------------------------------------------------------------*\
  1043. * void calc_diori
  1044. *
  1045. * Calculate transformation coefficients to arbitrarily orient plot.
  1046. * Preserve aspect ratios so the output doesn't suck.
  1047. \*--------------------------------------------------------------------------*/
  1048. static void
  1049. calc_diori(void)
  1050. {
  1051. PLFLT r11, r21, r12, r22, cost, sint;
  1052. PLFLT x0, y0, lx, ly, aspect;
  1053. if (plsc->dev_di) {
  1054. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  1055. PLESC_DI, NULL );
  1056. }
  1057. if ( ! (plsc->difilt & PLDI_ORI))
  1058. return;
  1059. /* Center point of rotation */
  1060. x0 = (plsc->phyxma + plsc->phyxmi) / 2.;
  1061. y0 = (plsc->phyyma + plsc->phyymi) / 2.;
  1062. /* Rotation matrix */
  1063. r11 = cos(plsc->diorot * PI / 2.);
  1064. r21 = sin(plsc->diorot * PI / 2.);
  1065. r12 = -r21;
  1066. r22 = r11;
  1067. cost = ABS(r11);
  1068. sint = ABS(r21);
  1069. /* Flip aspect ratio as necessary. Grungy but I don't see a better way */
  1070. aspect = plsc->aspect;
  1071. if (aspect == 0.)
  1072. aspect = plsc->aspdev;
  1073. if (plsc->freeaspect)
  1074. plsc->aspori = aspect;
  1075. else
  1076. plsc->aspori = (aspect * cost + sint) / (aspect * sint + cost);
  1077. if ( ! (plsc->difilt & PLDI_DEV)) {
  1078. plsc->difilt |= PLDI_DEV;
  1079. setdef_didev();
  1080. }
  1081. calc_didev();
  1082. /* Compute scale factors */
  1083. lx = plsc->phyxlen;
  1084. ly = plsc->phyylen;
  1085. /* Transformation coefficients */
  1086. plsc->dioxax = r11;
  1087. plsc->dioxay = r21 * (lx / ly);
  1088. plsc->dioxb = (1. - r11) * x0 - r21 * y0 * (lx / ly);
  1089. plsc->dioyax = r12 * (ly / lx);
  1090. plsc->dioyay = r22;
  1091. plsc->dioyb = (1. - r22) * y0 - r12 * x0 * (ly / lx);
  1092. }
  1093. /*--------------------------------------------------------------------------*\
  1094. * void plgdiori
  1095. *
  1096. * Get plot orientation
  1097. \*--------------------------------------------------------------------------*/
  1098. void
  1099. c_plgdiori(PLFLT *p_rot)
  1100. {
  1101. *p_rot = plsc->diorot;
  1102. }
  1103. /*--------------------------------------------------------------------------*\
  1104. * void plsdimap
  1105. *
  1106. * Set up transformation from metafile coordinates. The size of the plot is
  1107. * scaled so as to preserve aspect ratio. This isn't intended to be a
  1108. * general-purpose facility just yet (not sure why the user would need it,
  1109. * for one).
  1110. \*--------------------------------------------------------------------------*/
  1111. void
  1112. c_plsdimap(PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
  1113. PLFLT dimxpmm, PLFLT dimypmm)
  1114. {
  1115. plsetvar(plsc->dimxmin, dimxmin);
  1116. plsetvar(plsc->dimxmax, dimxmax);
  1117. plsetvar(plsc->dimymin, dimymin);
  1118. plsetvar(plsc->dimymax, dimymax);
  1119. plsetvar(plsc->dimxpmm, dimxpmm);
  1120. plsetvar(plsc->dimypmm, dimypmm);
  1121. plsc->difilt |= PLDI_MAP;
  1122. pldi_ini();
  1123. }
  1124. /*--------------------------------------------------------------------------*\
  1125. * void calc_dimap
  1126. *
  1127. * Set up transformation from metafile coordinates. The size of the plot is
  1128. * scaled so as to preserve aspect ratio. This isn't intended to be a
  1129. * general-purpose facility just yet (not sure why the user would need it,
  1130. * for one).
  1131. \*--------------------------------------------------------------------------*/
  1132. static void
  1133. calc_dimap()
  1134. {
  1135. PLFLT lx, ly;
  1136. PLINT pxmin, pxmax, pymin, pymax;
  1137. PLFLT dimxlen, dimylen, pxlen, pylen;
  1138. if ((plsc->dimxmin == plsc->phyxmi) && (plsc->dimxmax == plsc->phyxma) &&
  1139. (plsc->dimymin == plsc->phyymi) && (plsc->dimymax == plsc->phyyma) &&
  1140. (plsc->dimxpmm == plsc->xpmm) && (plsc->dimypmm == plsc->ypmm)) {
  1141. plsc->difilt &= ~PLDI_MAP;
  1142. return;
  1143. }
  1144. /* Set default aspect ratio */
  1145. lx = (plsc->dimxmax - plsc->dimxmin + 1) / plsc->dimxpmm;
  1146. ly = (plsc->dimymax - plsc->dimymin + 1) / plsc->dimypmm;
  1147. plsc->aspdev = lx / ly;
  1148. /* Build transformation to correct physical coordinates */
  1149. dimxlen = plsc->dimxmax - plsc->dimxmin;
  1150. dimylen = plsc->dimymax - plsc->dimymin;
  1151. pxmin = plsc->phyxmi;
  1152. pxmax = plsc->phyxma;
  1153. pymin = plsc->phyymi;
  1154. pymax = plsc->phyyma;
  1155. pxlen = pxmax - pxmin;
  1156. pylen = pymax - pymin;
  1157. plsc->dimxax = pxlen / dimxlen;
  1158. plsc->dimyay = pylen / dimylen;
  1159. plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
  1160. plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
  1161. }
  1162. /*--------------------------------------------------------------------------*\
  1163. * void plflush()
  1164. *
  1165. * Flushes the output stream. Use sparingly, if at all.
  1166. \*--------------------------------------------------------------------------*/
  1167. void
  1168. c_plflush(void)
  1169. {
  1170. if (plsc->dev_flush) {
  1171. (*plsc->dispatch_table->pl_esc) ( (struct PLStream_struct *) plsc,
  1172. PLESC_FLUSH, NULL );
  1173. }
  1174. else {
  1175. if (plsc->OutFile != NULL)
  1176. fflush(plsc->OutFile);
  1177. }
  1178. }
  1179. /*--------------------------------------------------------------------------*\
  1180. * Startup routines.
  1181. \*--------------------------------------------------------------------------*/
  1182. /*--------------------------------------------------------------------------*\
  1183. * void pllib_init()
  1184. *
  1185. * Initialize library. Called internally by every startup routine.
  1186. * Everything you want to always be initialized before plinit() is called
  1187. * you should put here. E.g. dispatch table setup, rcfile read, etc.
  1188. \*--------------------------------------------------------------------------*/
  1189. void
  1190. pllib_init()
  1191. {
  1192. if (lib_initialized) return;
  1193. lib_initialized = 1;
  1194. #ifdef ENABLE_DYNDRIVERS
  1195. /* Create libltdl resources */
  1196. lt_dlinit();
  1197. #endif
  1198. /* Initialize the dispatch table with the info from the static drivers table
  1199. and the available dynamic drivers. */
  1200. plInitDispatchTable();
  1201. }
  1202. /*--------------------------------------------------------------------------*\
  1203. * void plstar(nx, ny)
  1204. *
  1205. * Initialize PLplot, passing in the windows/page settings.
  1206. \*--------------------------------------------------------------------------*/
  1207. void
  1208. c_plstar(PLINT nx, PLINT ny)
  1209. {
  1210. pllib_init();
  1211. if (plsc->level != 0)
  1212. plend1();
  1213. plssub(nx, ny);
  1214. c_plinit();
  1215. }
  1216. /*--------------------------------------------------------------------------*\
  1217. * void plstart(devname, nx, ny)
  1218. *
  1219. * Initialize PLplot, passing the device name and windows/page settings.
  1220. \*--------------------------------------------------------------------------*/
  1221. void
  1222. c_plstart(const char *devname, PLINT nx, PLINT ny)
  1223. {
  1224. pllib_init();
  1225. if (plsc->level != 0)
  1226. plend1();
  1227. plssub(nx, ny);
  1228. plsdev(devname);
  1229. c_plinit();
  1230. }
  1231. /*--------------------------------------------------------------------------*\
  1232. * void plinit()
  1233. *
  1234. * Initializes PLplot, using preset or default options.
  1235. \*--------------------------------------------------------------------------*/
  1236. void
  1237. c_plinit(void)
  1238. {
  1239. PLFLT def_arrow_x[6] = {-0.5, 0.5, 0.3, 0.5, 0.3, 0.5};
  1240. PLFLT def_arrow_y[6] = {0.0, 0.0, 0.2, 0.0, -0.2, 0.0};
  1241. PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
  1242. PLINT mk = 0, sp = 0, inc = 0, del = 2000;
  1243. pllib_init();
  1244. if (plsc->level != 0)
  1245. plend1();
  1246. /* Set stream number */
  1247. plsc->ipls = ipls;
  1248. /* Set up devices */
  1249. pllib_devinit();
  1250. /* Auxiliary stream setup */
  1251. plstrm_init();
  1252. /* Initialize device & first page */
  1253. plP_init();
  1254. plP_bop();
  1255. plsc->level = 1;
  1256. /* Calculate factor such that the character aspect ratio is preserved
  1257. * when the overall aspect ratio is changed, i.e., if portrait mode is
  1258. * requested (only honored for subset of drivers) or if the aspect ratio
  1259. * is specified in any way, or if a 90 deg rotation occurs with
  1260. * -freeaspect. */
  1261. /* Case where plsc->aspect has a value.... (e.g., -a aspect on the
  1262. * command line or 2nd parameter of plsdidev specified) */
  1263. if (plsc->aspect > 0.) {
  1264. lx = plsc->phyxlen / plsc->xpmm;
  1265. ly = plsc->phyylen / plsc->ypmm;
  1266. aspect_old = lx / ly;
  1267. aspect_new = plsc->aspect;
  1268. plsc->caspfactor = sqrt(aspect_old/aspect_new);
  1269. }
  1270. /* Case of 90 deg rotations with -freeaspect (this is also how portraite
  1271. * mode is implemented for the drivers that honor -portrait). */
  1272. else if (plsc->freeaspect && ABS(cos(plsc->diorot * PI / 2.)) <= 1.e-5) {
  1273. lx = plsc->phyxlen / plsc->xpmm;
  1274. ly = plsc->phyylen / plsc->ypmm;
  1275. aspect_old = lx / ly;
  1276. aspect_new = ly / lx;
  1277. plsc->caspfactor = sqrt(aspect_old/aspect_new);
  1278. }
  1279. else
  1280. plsc->caspfactor = 1.;
  1281. /* Load fonts */
  1282. plsc->cfont = 1;
  1283. plfntld(initfont);
  1284. /* Set up subpages */
  1285. plP_subpInit();
  1286. /* Set up number of allowed digits before switching to scientific notation */
  1287. /* The user can always change this */
  1288. if (plsc->xdigmax == 0)
  1289. plsc->xdigmax = 4;
  1290. if (plsc->ydigmax == 0)
  1291. plsc->ydigmax = 4;
  1292. if (plsc->zdigmax == 0)
  1293. plsc->zdigmax = 3;
  1294. /* Switch to graphics mode and set color and arrow style*/
  1295. plgra();
  1296. plcol(1);
  1297. plstyl(0, &mk, &sp);
  1298. plpat(1, &inc, &del);
  1299. plsvect(def_arrow_x, def_arrow_y, 6, 0);
  1300. /* Set clip limits. */
  1301. plsc->clpxmi = plsc->phyxmi;
  1302. plsc->clpxma = plsc->phyxma;
  1303. plsc->clpymi = plsc->phyymi;
  1304. plsc->clpyma = plsc->phyyma;
  1305. /* Page aspect ratio. */
  1306. lx = plsc->phyxlen / plsc->xpmm;
  1307. ly = plsc->phyylen / plsc->ypmm;
  1308. plsc->aspdev = lx / ly;
  1309. /* Initialize driver interface */
  1310. pldi_ini();
  1311. /* Apply compensating factor to original xpmm and ypmm so that
  1312. * character aspect ratio is preserved when overall aspect ratio
  1313. * is changed. This must appear here in the code because previous
  1314. * code in this routine and in routines that it calls must use the original
  1315. * values of xpmm and ypmm before the compensating factor is applied. */
  1316. plP_gpixmm(&xpmm_loc, &ypmm_loc);
  1317. plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor);
  1318. }
  1319. /*--------------------------------------------------------------------------*\
  1320. * void plend()
  1321. *
  1322. * End a plotting session for all open streams.
  1323. \*--------------------------------------------------------------------------*/
  1324. void
  1325. c_plend(void)
  1326. {
  1327. PLINT i;
  1328. if (lib_initialized == 0) return;
  1329. for (i = PL_NSTREAMS-1; i >= 0; i--) {
  1330. if (pls[i] != NULL) {
  1331. plsstrm(i);
  1332. c_plend1();
  1333. }
  1334. }
  1335. plfontrel();
  1336. #ifdef ENABLE_DYNDRIVERS
  1337. /* Release the libltdl resources */
  1338. lt_dlexit();
  1339. /* Free up memory allocated to the dispatch tables */
  1340. for (i = 0; i < npldynamicdevices; i++) {
  1341. free_mem(loadable_device_list[i].devnam);
  1342. free_mem(loadable_device_list[i].description);
  1343. free_mem(loadable_device_list[i].drvnam);
  1344. free_mem(loadable_device_list[i].tag);
  1345. }
  1346. free_mem(loadable_device_list);
  1347. for (i = 0; i < nloadabledrivers; i++) {
  1348. free_mem(loadable_driver_list[i].drvnam);
  1349. }
  1350. free_mem(loadable_driver_list);
  1351. for (i = nplstaticdevices; i < npldrivers; i++) {
  1352. free_mem(dispatch_table[i]->pl_MenuStr);
  1353. free_mem(dispatch_table[i]->pl_DevName);
  1354. free_mem(dispatch_table[i]);
  1355. }
  1356. #endif
  1357. for (i = 0; i < nplstaticdevices; i++) {
  1358. free_mem(dispatch_table[i]);
  1359. }
  1360. free_mem(dispatch_table);
  1361. plP_FreeDrvOpts();
  1362. lib_initialized = 0;
  1363. }
  1364. /*--------------------------------------------------------------------------*\
  1365. * void plend1()
  1366. *
  1367. * End a plotting session for the current stream only. After the stream is
  1368. * ended the memory associated with the stream's PLStream data structure is
  1369. * freed (for stream > 0), and the stream counter is set to 0 (the default).
  1370. \*--------------------------------------------------------------------------*/
  1371. void
  1372. c_plend1(void)
  1373. {
  1374. if (plsc->level > 0) {
  1375. plP_eop();
  1376. plP_tidy();
  1377. plsc->level = 0;
  1378. }
  1379. /* Move from plP_tidy because FileName may be set even if level == 0 */
  1380. if (plsc->FileName)
  1381. free_mem(plsc->FileName);
  1382. /* Free all malloc'ed stream memory */
  1383. free_mem(plsc->cmap0);
  1384. free_mem(plsc->cmap1);
  1385. free_mem(plsc->plwindow);
  1386. free_mem(plsc->geometry);
  1387. free_mem(plsc->dev);
  1388. free_mem(plsc->BaseName);
  1389. if (plsc->program) free_mem(plsc->program);
  1390. if (plsc->server_name) free_mem(plsc->server_name);
  1391. if (plsc->server_host) free_mem(plsc->server_host);
  1392. if (plsc->server_port) free_mem(plsc->server_port);
  1393. if (plsc->user) free_mem(plsc->user);
  1394. if (plsc->plserver) free_mem(plsc->plserver);
  1395. if (plsc->auto_path) free_mem(plsc->auto_path);
  1396. if (plsc->arrow_x) free_mem(plsc->arrow_x);
  1397. if (plsc->arrow_y) free_mem(plsc->arrow_y);
  1398. /* Free malloc'ed stream if not in initial stream, else clear it out */
  1399. if (ipls > 0) {
  1400. free_mem(plsc);
  1401. pls[ipls] = NULL;
  1402. plsstrm(0);
  1403. }
  1404. else {
  1405. memset((char *) pls[ipls], 0, sizeof(PLStream));
  1406. }
  1407. }
  1408. /*--------------------------------------------------------------------------*\
  1409. * void plsstrm
  1410. *
  1411. * Set stream number. If the data structure for a new stream is
  1412. * unallocated, we allocate it here.
  1413. \*--------------------------------------------------------------------------*/
  1414. void
  1415. c_plsstrm(PLINT strm)
  1416. {
  1417. if (strm < 0 || strm >= PL_NSTREAMS) {
  1418. fprintf(stderr,
  1419. "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
  1420. (int) strm, PL_NSTREAMS);
  1421. }
  1422. else {
  1423. ipls = strm;
  1424. if (pls[ipls] == NULL) {
  1425. pls[ipls] = (PLStream *) malloc((size_t) sizeof(PLStream));
  1426. if (pls[ipls] == NULL)
  1427. plexit("plsstrm: Out of memory.");
  1428. memset((char *) pls[ipls], 0, sizeof(PLStream));
  1429. }
  1430. plsc = pls[ipls];
  1431. plsc->ipls = ipls;
  1432. }
  1433. }
  1434. /*--------------------------------------------------------------------------*\
  1435. * void plgstrm
  1436. *
  1437. * Get current stream number.
  1438. \*--------------------------------------------------------------------------*/
  1439. void
  1440. c_plgstrm(PLINT *p_strm)
  1441. {
  1442. *p_strm = ipls;
  1443. }
  1444. /*--------------------------------------------------------------------------*\
  1445. * void plmkstrm
  1446. *
  1447. * Creates a new stream and makes it the default. Differs from using
  1448. * plsstrm(), in that a free stream number is found, and returned.
  1449. *
  1450. * Unfortunately, I /have/ to start at stream 1 and work upward, since
  1451. * stream 0 is preallocated. One of the BIG flaws in the PLplot API is
  1452. * that no initial, library-opening call is required. So stream 0 must be
  1453. * preallocated, and there is no simple way of determining whether it is
  1454. * already in use or not.
  1455. \*--------------------------------------------------------------------------*/
  1456. void
  1457. c_plmkstrm(PLINT *p_strm)
  1458. {
  1459. int i;
  1460. for (i = 1; i < PL_NSTREAMS; i++) {
  1461. if (pls[i] == NULL)
  1462. break;
  1463. }
  1464. if (i == PL_NSTREAMS) {
  1465. fprintf(stderr, "plmkstrm: Cannot create new stream\n");
  1466. *p_strm = -1;
  1467. }
  1468. else {
  1469. *p_strm = i;
  1470. plsstrm(i);
  1471. }
  1472. plstrm_init();
  1473. }
  1474. /*--------------------------------------------------------------------------*\
  1475. * void plstrm_init
  1476. *
  1477. * Does required startup initialization of a stream. Should be called right
  1478. * after creating one (for allocating extra memory, etc). Users shouldn't
  1479. * need to call this directly.
  1480. *
  1481. * This function can be called multiple times for a given stream, in which
  1482. * case only the first call produces any effect. For streams >= 1, which
  1483. * are created dynamically, this is called by the routine that allocates
  1484. * the stream. Stream 0, which is preallocated, is much harder to deal with
  1485. * because any of a number of different calls may be the first call to the
  1486. * library. This is handled by just calling plstrm_init() from every
  1487. * function that might be called first. Sucks, but it should work.
  1488. \*--------------------------------------------------------------------------*/
  1489. void
  1490. plstrm_init(void)
  1491. {
  1492. if ( ! plsc->initialized) {
  1493. plsc->initialized = 1;
  1494. if (plsc->cmap0 == NULL)
  1495. plscmap0n(0);
  1496. if (plsc->cmap1 == NULL)
  1497. plscmap1n(0);
  1498. }
  1499. }
  1500. /*--------------------------------------------------------------------------*\
  1501. * pl_cpcolor
  1502. *
  1503. * Utility to copy one PLColor to another.
  1504. \*--------------------------------------------------------------------------*/
  1505. void
  1506. pl_cpcolor(PLColor *to, PLColor *from)
  1507. {
  1508. to->r = from->r;
  1509. to->g = from->g;
  1510. to->b = from->b;
  1511. }
  1512. /*--------------------------------------------------------------------------*\
  1513. * void plcpstrm
  1514. *
  1515. * Copies state parameters from the reference stream to the current stream.
  1516. * Tell driver interface to map device coordinates unless flags == 1.
  1517. *
  1518. * This function is used for making save files of selected plots (e.g.
  1519. * from the TK driver). After initializing, you can get a copy of the
  1520. * current plot to the specified device by switching to this stream and
  1521. * issuing a plcpstrm() and a plreplot(), with calls to plbop() and
  1522. * pleop() as appropriate. The plot buffer must have previously been
  1523. * enabled (done automatically by some display drivers, such as X).
  1524. \*--------------------------------------------------------------------------*/
  1525. void
  1526. c_plcpstrm(PLINT iplsr, PLINT flags)
  1527. {
  1528. int i;
  1529. PLStream *plsr;
  1530. plsr = pls[iplsr];
  1531. if (plsr == NULL) {
  1532. fprintf(stderr, "plcpstrm: stream %d not in use\n", (int) iplsr);
  1533. return;
  1534. }
  1535. /* May be debugging */
  1536. plsc->debug = plsr->debug;
  1537. /* Plot buffer -- need to copy file pointer so that plreplot() works */
  1538. /* This also prevents inadvertent writes into the plot buffer */
  1539. plsc->plbufFile = plsr->plbufFile;
  1540. /* Driver interface */
  1541. /* Transformation must be recalculated in current driver coordinates */
  1542. if (plsr->difilt & PLDI_PLT)
  1543. plsdiplt(plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax);
  1544. if (plsr->difilt & PLDI_DEV)
  1545. plsdidev(plsr->mar, plsr->aspect, plsr->jx, plsr->jy);
  1546. if (plsr->difilt & PLDI_ORI)
  1547. plsdiori(plsr->diorot);
  1548. /* Map device coordinates */
  1549. if ( ! (flags & 0x01)) {
  1550. pldebug("plcpstrm", "mapping parameters: %d %d %d %d %f %f\n",
  1551. plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
  1552. plsr->xpmm, plsr->ypmm);
  1553. plsdimap(plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
  1554. plsr->xpmm, plsr->ypmm);
  1555. }
  1556. /* current color */
  1557. pl_cpcolor(&plsc->curcolor, &plsr->curcolor);
  1558. /* cmap 0 */
  1559. plsc->icol0 = plsr->icol0;
  1560. plsc->ncol0 = plsr->ncol0;
  1561. if (plsc->cmap0 != NULL)
  1562. free((void *) plsc->cmap0);
  1563. plsc->cmap0 = (PLColor *) calloc(1, plsc->ncol0 * sizeof(PLColor));
  1564. for (i = 0; i < plsc->ncol0; i++)
  1565. pl_cpcolor(&plsc->cmap0[i], &plsr->cmap0[i]);
  1566. /* cmap 1 */
  1567. plsc->icol1 = plsr->icol1;
  1568. plsc->ncol1 = plsr->ncol1;
  1569. if (plsc->cmap1 != NULL)
  1570. free((void *) plsc->cmap1);
  1571. plsc->cmap1 = (PLColor *) calloc(1, plsc->ncol1 * sizeof(PLColor));
  1572. for (i = 0; i < plsc->ncol1; i++)
  1573. pl_cpcolor(&plsc->cmap1[i], &plsr->cmap1[i]);
  1574. /* Initialize if it hasn't been done yet. */
  1575. if (plsc->level == 0)
  1576. plinit();
  1577. }
  1578. /*--------------------------------------------------------------------------*\
  1579. * pllib_devinit()
  1580. *
  1581. * Does preliminary setup of device driver.
  1582. *
  1583. * This function (previously plGetDev) used to be what is now shown as
  1584. * plSelectDev below. However, the situation is a bit more complicated now in
  1585. * the dynloadable drivers era. We now have to:
  1586. *
  1587. * 1) Make sure the dispatch table is initialized to the union of static
  1588. * drivers and available dynamic drivers (done from pllib_init now).
  1589. * 2) Allow the user to select the desired device.
  1590. * 3) Initialize the dispatch table entries for the selected device, in the
  1591. * case that it is a dynloadable driver that has not yet been loaded.
  1592. *
  1593. * Also made non-static, in order to allow some device calls to be made prior
  1594. * to calling plinit(). E.g. plframe needs to tell the X driver to create its
  1595. * internal data structure during widget construction time (using the escape
  1596. * function), but doesn't call plinit() until the plframe is actually mapped.
  1597. \*--------------------------------------------------------------------------*/
  1598. void
  1599. pllib_devinit()
  1600. {
  1601. if (plsc->dev_initialized) return;
  1602. plsc->dev_initialized = 1;
  1603. plSelectDev();
  1604. plLoadDriver();
  1605. /* offset by one since table is zero-based, but input list is not */
  1606. plsc->dispatch_table = dispatch_table[plsc->device - 1];
  1607. }
  1608. int plInBuildTree()
  1609. {
  1610. static int inited = 0;
  1611. static int inBuildTree = 0;
  1612. if (inited == 0) {
  1613. char currdir[256];
  1614. /* AM: getcwd has a somewhat strange status on Windows, its proper
  1615. name is _getcwd, this is a problem in the case of DLLs, like with
  1616. the Java bindings.
  1617. */
  1618. #ifdef WIN32
  1619. #define getcwd _getcwd
  1620. #endif
  1621. if (getcwd(currdir, 256) == NULL) {
  1622. pldebug("plInBuildTree():", "Not enough buffer space");
  1623. } else if (strncmp(BUILD_DIR, currdir, strlen(BUILD_DIR)) == 0)
  1624. inBuildTree = 1;
  1625. inited = 1;
  1626. }
  1627. return inBuildTree;
  1628. }
  1629. #ifdef ENABLE_DYNDRIVERS
  1630. static char*
  1631. plGetDrvDir ()
  1632. {
  1633. char* drvdir;
  1634. /* Get drivers directory in PLPLOT_DRV_DIR or DRV_DIR,
  1635. * on this order
  1636. */
  1637. if (plInBuildTree() == 1) {
  1638. drvdir = BUILD_DIR "/drivers";
  1639. pldebug("plGetDrvDir", "Using %s as the driver directory.\n", drvdir);
  1640. } else {
  1641. pldebug("plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n");
  1642. drvdir = getenv ("PLPLOT_DRV_DIR");
  1643. if (drvdir == NULL) {
  1644. pldebug("plGetDrvDir",
  1645. "Will use drivers dir: " DRV_DIR "\n");
  1646. drvdir = DRV_DIR;
  1647. }
  1648. }
  1649. return drvdir;
  1650. }
  1651. #endif
  1652. /*--------------------------------------------------------------------------*\
  1653. * void plInitDispatchTable()
  1654. *
  1655. * ...
  1656. \*--------------------------------------------------------------------------*/
  1657. static int plDispatchSequencer( const void *p1, const void *p2 )
  1658. {
  1659. const PLDispatchTable* t1 = *(PLDispatchTable **) p1;
  1660. const PLDispatchTable* t2 = *(PLDispatchTable **) p2;
  1661. /* printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n", */
  1662. /* t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq ); */
  1663. return t1->pl_seq - t2->pl_seq;
  1664. }
  1665. static void
  1666. plInitDispatchTable()
  1667. {
  1668. int n;
  1669. #ifdef ENABLE_DYNDRIVERS
  1670. char buf[300];
  1671. char* drvdir;
  1672. char *devnam, *devdesc, *devtype, *driver, *tag, *seqstr;
  1673. int seq;
  1674. int i, j, driver_found, done=0;
  1675. FILE *fp_drvdb = NULL;
  1676. DIR* dp_drvdir = NULL;
  1677. struct dirent* entry;
  1678. /* lt_dlhandle dlhand; */
  1679. /* Make sure driver counts are zeroed */
  1680. npldynamicdevices = 0;
  1681. nloadabledrivers = 0;
  1682. /* Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings
  1683. will be stored */
  1684. fp_drvdb = tmpfile ();
  1685. /* Open the drivers directory */
  1686. drvdir = plGetDrvDir ();
  1687. dp_drvdir = opendir (drvdir);
  1688. if (dp_drvdir == NULL) {
  1689. plabort ("plInitDispatchTable: Could not open drivers directory");
  1690. return;
  1691. }
  1692. /* Loop over each entry in the drivers directory */
  1693. pldebug ("plInitDispatchTable", "Scanning dyndrivers dir\n");
  1694. while ((entry = readdir (dp_drvdir)) != NULL)
  1695. {
  1696. char* name = entry->d_name;
  1697. int len = strlen (name) - 3;
  1698. pldebug ("plInitDispatchTable",
  1699. "Consider file %s\n", name);
  1700. /* Only consider entries that have the ".rc" suffix */
  1701. if ((len > 0) && (strcmp (name + len, ".rc") == 0)) {
  1702. char path[300];
  1703. char buf[300];
  1704. FILE* fd;
  1705. /* Open the driver's info file */
  1706. sprintf (path, "%s/%s", drvdir, name);
  1707. fd = fopen (path, "r");
  1708. if (fd == NULL) {
  1709. sprintf (buf,
  1710. "plInitDispatchTable: Could not open driver info file %s\n",
  1711. name);
  1712. plabort (buf);
  1713. return;
  1714. }
  1715. /* Each line in the <driver>.rc file corresponds to a specific device.
  1716. * Write it to the drivers db file and take care of leading newline
  1717. * character */
  1718. pldebug ("plInitDispatchTable",
  1719. "Opened driver info file %s\n", name);
  1720. while (fgets (buf, 300, fd) != NULL)
  1721. {
  1722. fprintf (fp_drvdb, "%s", buf);
  1723. if ( buf [strlen (buf) - 1] != '\n' )
  1724. fprintf (fp_drvdb, "\n");
  1725. npldynamicdevices++;
  1726. }
  1727. fclose (fd);
  1728. }
  1729. }
  1730. /* Make sure that the temporary file containing the driversr database
  1731. * is ready to read and close the directory handle */
  1732. fflush (fp_drvdb);
  1733. closedir (dp_drvdir);
  1734. #endif
  1735. /* Allocate space for the dispatch table. */
  1736. dispatch_table = (PLDispatchTable **)
  1737. malloc( (nplstaticdevices + npldynamicdevices) * sizeof(PLDispatchTable *) );
  1738. /* Initialize the dispatch table entries for the static devices by calling
  1739. the dispatch table initialization function for each static device. This
  1740. is the same function that would be called at load time for dynamic
  1741. drivers. */
  1742. for( n=0; n < nplstaticdevices; n++ )
  1743. {
  1744. dispatch_table[n] = (PLDispatchTable *)malloc( sizeof(PLDispatchTable) );
  1745. (*static_device_initializers[n])( dispatch_table[n] );
  1746. }
  1747. npldrivers = nplstaticdevices;
  1748. #ifdef ENABLE_DYNDRIVERS
  1749. /* Allocate space for the device and driver specs. We may not use all of
  1750. * these driver descriptors, but we obviously won't need more drivers than
  1751. * devices... */
  1752. loadable_device_list = malloc( npldynamicdevices * sizeof(PLLoadableDevice) );
  1753. loadable_driver_list = malloc( npldynamicdevices * sizeof(PLLoadableDriver) );
  1754. rewind( fp_drvdb );
  1755. i = 0;
  1756. done = !(i < npldynamicdevices);
  1757. while( !done ) {
  1758. char *p = fgets( buf, 300, fp_drvdb );
  1759. if (p == 0) {
  1760. done = 1;
  1761. continue;
  1762. }
  1763. devnam = strtok( buf, ":" );
  1764. devdesc = strtok( 0, ":" );
  1765. devtype = strtok( 0, ":" );
  1766. driver = strtok( 0, ":" );
  1767. seqstr = strtok( 0, ":" );
  1768. tag = strtok( 0, "\n" );
  1769. seq = atoi(seqstr);
  1770. n = npldrivers++;
  1771. dispatch_table[n] = malloc( sizeof(PLDispatchTable) );
  1772. /* Fill in the dispatch table entries. */
  1773. dispatch_table[n]->pl_MenuStr = plstrdup(devdesc);
  1774. dispatch_table[n]->pl_DevName = plstrdup(devnam);
  1775. dispatch_table[n]->pl_type = atoi(devtype);
  1776. dispatch_table[n]->pl_seq = seq;
  1777. dispatch_table[n]->pl_init = 0;
  1778. dispatch_table[n]->pl_line = 0;
  1779. dispatch_table[n]->pl_polyline = 0;
  1780. dispatch_table[n]->pl_eop = 0;
  1781. dispatch_table[n]->pl_bop = 0;
  1782. dispatch_table[n]->pl_tidy = 0;
  1783. dispatch_table[n]->pl_state = 0;
  1784. dispatch_table[n]->pl_esc = 0;
  1785. /* Add a record to the loadable device list */
  1786. loadable_device_list[i].devnam = plstrdup(devnam);
  1787. loadable_device_list[i].description = plstrdup(devdesc);
  1788. loadable_device_list[i].drvnam = plstrdup(driver);
  1789. loadable_device_list[i].tag = plstrdup(tag);
  1790. /* Now see if this driver has been seen before. If not, add a driver
  1791. * entry for it. */
  1792. driver_found = 0;
  1793. for( j=0; j < nloadabledrivers; j++ )
  1794. if (strcmp( driver, loadable_driver_list[j].drvnam) == 0)
  1795. {
  1796. driver_found = 1;
  1797. break;
  1798. }
  1799. if (!driver_found)
  1800. {
  1801. loadable_driver_list[nloadabledrivers].drvnam = plstrdup(driver);
  1802. loadable_driver_list[nloadabledrivers].dlhand = 0;
  1803. nloadabledrivers++;
  1804. }
  1805. loadable_device_list[i].drvidx = j;
  1806. /* Get ready for next loadable device spec */
  1807. i++;
  1808. }
  1809. /* RML: close fp_drvdb */
  1810. fclose (fp_drvdb);
  1811. #endif
  1812. /* Finally, we need to sort the list into presentation order, based on the
  1813. sequence number in the dispatch ttable entries. */
  1814. qsort( dispatch_table, npldrivers, sizeof(PLDispatchTable*),
  1815. plDispatchSequencer );
  1816. }
  1817. /*--------------------------------------------------------------------------*\
  1818. * void plSelectDev()
  1819. *
  1820. * If the user has not already specified the output device, or the
  1821. * one specified is either: (a) not available, (b) "?", or (c) NULL, the
  1822. * user is prompted for it.
  1823. *
  1824. * Prompting quits after 10 unsuccessful tries in case the user has
  1825. * run the program in the background with insufficient input.
  1826. \*--------------------------------------------------------------------------*/
  1827. static void
  1828. plSelectDev()
  1829. {
  1830. int dev, i, count, length;
  1831. char response[80];
  1832. /* Device name already specified. See if it is valid. */
  1833. if (*(plsc->DevName) != '\0' && *(plsc->DevName) != '?') {
  1834. length = strlen(plsc->DevName);
  1835. for (i = 0; i < npldrivers; i++) {
  1836. if ((*plsc->DevName == *dispatch_table[i]->pl_DevName) &&
  1837. (strncmp(plsc->DevName,
  1838. dispatch_table[i]->pl_DevName, length) == 0))
  1839. break;
  1840. }
  1841. if (i < npldrivers) {
  1842. plsc->device = i + 1;
  1843. return;
  1844. }
  1845. else {
  1846. fprintf(stderr, "Requested device %s not available\n",
  1847. plsc->DevName);
  1848. }
  1849. }
  1850. dev = 0;
  1851. count = 0;
  1852. if (npldrivers == 1)
  1853. dev = 1;
  1854. /* User hasn't specified it correctly yet, so we prompt */
  1855. while (dev < 1 || dev > npldrivers) {
  1856. fprintf(stdout, "\nPlotting Options:\n");
  1857. for (i = 0; i < npldrivers; i++) {
  1858. fprintf(stdout, " <%2d> %-10s %s\n", i + 1,
  1859. dispatch_table[i]->pl_DevName,
  1860. dispatch_table[i]->pl_MenuStr);
  1861. }
  1862. if (ipls == 0)
  1863. fprintf(stdout, "\nEnter device number or keyword: ");
  1864. else
  1865. fprintf(stdout, "\nEnter device number or keyword (stream %d): ",
  1866. (int) ipls);
  1867. fgets(response, sizeof(response), stdin);
  1868. /* First check to see if device keyword was entered. */
  1869. /* Final "\n" in response messes things up, so ignore it. */
  1870. length = strlen(response);
  1871. if (*(response - 1 + length) == '\n')
  1872. length--;
  1873. for (i = 0; i < npldrivers; i++) {
  1874. if ( ! strncmp(response, dispatch_table[i]->pl_DevName,
  1875. (unsigned int) length))
  1876. break;
  1877. }
  1878. if (i < npldrivers) {
  1879. dev = i + 1;
  1880. }
  1881. else {
  1882. if ((dev = atoi(response)) < 1) {
  1883. fprintf(stdout, "\nInvalid device: %s", response);
  1884. dev = 0;
  1885. }
  1886. }
  1887. if (count++ > 10)
  1888. plexit("plSelectDev: Too many tries.");
  1889. }
  1890. plsc->device = dev;
  1891. strcpy(plsc->DevName, dispatch_table[dev - 1]->pl_DevName);
  1892. }
  1893. /*--------------------------------------------------------------------------*\
  1894. * void plLoadDriver()
  1895. *
  1896. * Make sure the selected driver is loaded. Static drivers are already
  1897. * loaded, but if the user selected a dynamically loadable driver, we may
  1898. * have to take care of that now.
  1899. \*--------------------------------------------------------------------------*/
  1900. static void
  1901. plLoadDriver(void)
  1902. {
  1903. #ifdef ENABLE_D