1 // Maurice LeBrun mjl@dino.ph.utexas.edu
2 // Institute for Fusion Studies University of Texas at Austin
3 //
4 // Copyright (C) 1993-2005 Maurice LeBrun
5 // Copyright (C) 1995 Rady Shouman
6 // Copyright (C) 1998-2000 Geoffrey Furnish
7 // Copyright (C) 2000-2019 Alan W. Irwin
8 // Copyright (C) 2001 Joao Cardoso
9 // Copyright (C) 2004-2011 Andrew Ross
10 // Copyright (C) 2004-2005 Rafael Laboissiere
11 // Copyright (C) 2007 Andrew Roach
12 // Copyright (C) 2008-2009 Werner Smekal
13 // Copyright (C) 2009-2011 Hazen Babcock
14 // Copyright (C) 2009-2010 Hezekiah M. Carty
15 // Copyright (C) 2015 Jim Dishaw
16 // Copyright (C) 2017 Phil Rosenberg
17 //
18 // This file is part of PLplot.
19 //
20 // PLplot is free software; you can redistribute it and/or modify
21 // it under the terms of the GNU Library General Public License as published
22 // by the Free Software Foundation; either version 2 of the License, or
23 // (at your option) any later version.
24 //
25 // PLplot is distributed in the hope that it will be useful,
26 // but WITHOUT ANY WARRANTY; without even the implied warranty of
27 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 // GNU Library General Public License for more details.
29 //
30 // You should have received a copy of the GNU Library General Public License
31 // along with PLplot; if not, write to the Free Software
32 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 //
34 // Some parts of this code were derived from "xterm.c" and "ParseCmd.c" of
35 // the X-windows Version 11 distribution. The copyright notice is
36 // reproduced here:
37 //
38 // Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
39 // and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
40 //
41 // All Rights Reserved
42 //
43 // The full permission notice is given in the PLplot documentation.
44 //
45 //--------------------------------------------------------------------------
46 //
47 //! @file
48 //! This file contains routines to extract & process command flags. The
49 //! command flags recognized by PLplot are stored in the "ploption_table"
50 //! structure, along with strings giving the syntax, long help message, and
51 //! option handler.
52 //!
53 //! The command line parser -- plparseopts() -- removes all recognized flags
54 //! (decreasing argc accordingly), so that invalid input may be readily
55 //! detected. It can also be used to process user command line flags. The
56 //! user can merge an option table of type PLOptionTable into the internal
57 //! option table info structure using plMergeOpts(). Or, the user can
58 //! specify that ONLY the external table(s) be parsed by calling
59 //! plClearOpts() before plMergeOpts().
60 //!
61 //! The default action taken by plparseopts() is as follows:
62 //! - Returns with an error if an unrecognized option or badly formed
63 //! option-value pair are encountered.
64 //! - Returns immediately (return code 0) when the first non-option
65 //! command line argument is found.
66 //! - Returns with the return code of the option handler, if one
67 //! was called.
68 //! - Deletes command line arguments from argv list as they are found,
69 //! and decrements argc accordingly.
70 //! - Does not show "invisible" options in usage or help messages.
71 //! - Assumes the program name is contained in argv[0].
72 //!
73 //! These behaviors may be controlled through the "mode" argument, which can
74 //! have the following bits set:
75 //!
76 //! PL_PARSE_FULL -- Full parsing of command line and all error messages
77 //! enabled, including program exit when an error occurs. Anything on the
78 //! command line that isn't recognized as a valid option or option argument
79 //! is flagged as an error.
80 //!
81 //! PL_PARSE_QUIET -- Turns off all output except in the case of
82 //! errors.
83 //!
84 //! PL_PARSE_NODELETE -- Turns off deletion of processed arguments.
85 //!
86 //! PL_PARSE_SHOWALL -- Show invisible options
87 //!
88 //! PL_PARSE_NOPROGRAM -- Specified if argv[0] is NOT a pointer to the
89 //! program name.
90 //!
91 //! PL_PARSE_NODASH -- Set if leading dash is NOT required.
92 //!
93 //! PL_PARSE_SKIP -- Set to quietly skip over any unrecognized args.
94 //!
95 //! Note: if you want to have both your option and a PLplot option of the
96 //! same name processed (e.g. the -v option in plrender), do the following:
97 //! 1. Tag your option with PL_OPT_NODELETE
98 //! 2. Give it an option handler that uses a return code of 1.
99 //! 3. Merge your option table in.
100 //! By merging your table, your option will be processed before the PLplot
101 //! one. The PL_OPT_NODELETE ensures that the option string is not deleted
102 //! from the argv list, and the return code of 1 ensures that the parser
103 //! continues looking for it.
104 //!
105 //! See plrender.c for examples of actual usage.
106 //!
107
108 #include "plplotP.h"
109 #include <ctype.h>
110 #include <errno.h>
111
112 #ifdef HAVE_CRT_EXTERNS_H
113 //
114 // This include file has the declaration for _NSGetArgc(). See below.
115 //
116 #include <crt_externs.h>
117 #endif
118
119 // Support functions
120
121 static int ParseOpt( int *, char ***, int *, char ***, PLOptionTable * );
122 static int ProcessOpt( char *, PLOptionTable *, int *, char ***, int * );
123 static int GetOptarg( char **, int *, char ***, int * );
124 static void Help( void );
125 static void Syntax( void );
126
127 // Option handlers
128
129 static int opt_a( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
130 static int opt_auto_path( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
131 static int opt_bg( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
132 static int opt_bufmax( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
133 static int opt_bufmax( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
134 static int opt_cmap0( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
135 static int opt_cmap1( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
136 static int opt_db( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
137 static int opt_debug( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
138 static int opt_dev( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
139 static int opt_dev_compression( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
140 static int opt_dpi( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
141 static int opt_drvopt( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
142 static int opt_eofill( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
143 static int opt_fam( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
144 static int opt_fbeg( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
145 static int opt_fflen( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
146 static int opt_finc( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
147 static int opt_freeaspect( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
148 static int opt_fsiz( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
149 static int opt_geo( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
150 static int opt_h( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
151 static int opt_hack( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
152 static int opt_jx( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
153 static int opt_jy( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
154 static int opt_locale( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
155 static int opt_mar( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
156 static int opt_mfi( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
157 static int opt_mfo( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
158 static int opt_ncol0( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
159 static int opt_ncol1( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
160 static int opt_nopixmap( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
161 static int opt_np( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
162 static int opt_o( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
163 static int opt_ori( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
164 static int opt_plserver( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
165 static int opt_plwindow( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
166 static int opt_portrait( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
167 static int opt_px( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
168 static int opt_py( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
169 static int opt_server_name( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
170 static int opt_tk_file( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
171 static int opt_v( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
172 static int opt_verbose( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
173 static int opt_width( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
174 static int opt_wplt( PLCHAR_VECTOR, PLCHAR_VECTOR, void * );
175
176 // Global variables
177
178 static PLCHAR_VECTOR program = NULL;
179 static PLCHAR_VECTOR usage = NULL;
180
181 static int mode_full;
182 static int mode_quiet;
183 static int mode_nodelete;
184 static int mode_showall;
185 static int mode_noprogram;
186 static int mode_nodash;
187 static int mode_skip;
188
189 // Temporary buffer used for parsing
190
191 #define OPTMAX 1024
192 static char opttmp[OPTMAX];
193
194 //--------------------------------------------------------------------------
195 //!
196 //! PLPLOT options data structure definition.
197 //!
198 //! The table is defined as follows
199 //!
200 //! typedef struct {
201 //! PLCHAR_VECTOR opt;
202 //! int (*handler) (PLCHAR_VECTOR, PLCHAR_VECTOR, void *);
203 //! void *client_data;
204 //! void *var;
205 //! long mode;
206 //! PLCHAR_VECTOR syntax;
207 //! PLCHAR_VECTOR desc;
208 //! } PLOptionTable;
209 //!
210 //! where each entry has the following meaning:
211 //!
212 //! opt option string
213 //! handler pointer to function for processing the option and
214 //! (optionally) its argument
215 //! client_data pointer to data that gets passed to (*handler)
216 //! var address of variable to set based on "mode"
217 //! mode governs handling of option (see below)
218 //! syntax short syntax description
219 //! desc long syntax description
220 //!
221 //! The syntax and or desc strings can be NULL if the option is never to be
222 //! described. Usually this is only used for obsolete arguments; those we
223 //! just wish to hide from normal use are better made invisible (which are
224 //! made visible by either specifying -showall first or PL_PARSE_SHOWALL).
225 //!
226 //! The mode bits are:
227 //!
228 //! PL_OPT_ARG Option has an argument
229 //! PL_OPT_NODELETE Don't delete after processing
230 //! PL_OPT_INVISIBLE Make invisible (usually for debugging)
231 //! PL_OPT_DISABLED Ignore this option
232 //!
233 //! The following mode bits cause the option to be processed as specified:
234 //!
235 //! PL_OPT_FUNC Call function handler (opt, opt_arg)
236 //! PL_OPT_BOOL Set *var=1
237 //! PL_OPT_INT Set *var=atoi(opt_arg)
238 //! PL_OPT_FLOAT Set *var=atof(opt_arg)
239 //! PL_OPT_STRING Set *var=opt_arg
240 //!
241 //! where opt points to the option string and opt_arg points to the
242 //! argument string.
243 //!
244 //--------------------------------------------------------------------------
245
246 static PLOptionTable ploption_table[] = {
247 {
248 "showall", // Turns on invisible options
249 NULL,
250 NULL,
251 &mode_showall,
252 PL_OPT_BOOL | PL_OPT_INVISIBLE,
253 "-showall",
254 "Turns on invisible options"
255 },
256 {
257 "h", // Help
258 opt_h,
259 NULL,
260 NULL,
261 PL_OPT_FUNC,
262 "-h",
263 "Print out this message"
264 },
265 {
266 "v", // Version
267 opt_v,
268 NULL,
269 NULL,
270 PL_OPT_FUNC,
271 "-v",
272 "Print out the PLplot library version number"
273 },
274 {
275 "verbose", // Be more verbose than usual
276 opt_verbose,
277 NULL,
278 NULL,
279 PL_OPT_FUNC,
280 "-verbose",
281 "Be more verbose than usual"
282 },
283 {
284 "debug", // Print debugging info
285 opt_debug,
286 NULL,
287 NULL,
288 PL_OPT_FUNC,
289 "-debug",
290 "Print debugging info (implies -verbose)"
291 },
292 {
293 "hack", // Enable driver-specific hack(s)
294 opt_hack,
295 NULL,
296 NULL,
297 PL_OPT_FUNC | PL_OPT_INVISIBLE,
298 "-hack",
299 "Enable driver-specific hack(s)"
300 },
301 {
302 "dev", // Output device
303 opt_dev,
304 NULL,
305 NULL,
306 PL_OPT_FUNC | PL_OPT_ARG,
307 "-dev name",
308 "Output device name"
309 },
310 {
311 "o", // Output filename
312 opt_o,
313 NULL,
314 NULL,
315 PL_OPT_FUNC | PL_OPT_ARG,
316 "-o name",
317 "Output filename"
318 },
319 {
320 "display", // X server
321 opt_o,
322 NULL,
323 NULL,
324 PL_OPT_FUNC | PL_OPT_ARG,
325 "-display name",
326 "X server to contact"
327 },
328 {
329 "px", // Plots per page in x
330 opt_px,
331 NULL,
332 NULL,
333 PL_OPT_FUNC | PL_OPT_ARG,
334 "-px number",
335 "Plots per page in x"
336 },
337 {
338 "py", // Plots per page in y
339 opt_py,
340 NULL,
341 NULL,
342 PL_OPT_FUNC | PL_OPT_ARG,
343 "-py number",
344 "Plots per page in y"
345 },
346 {
347 "geometry", // Geometry
348 opt_geo,
349 NULL,
350 NULL,
351 PL_OPT_FUNC | PL_OPT_ARG,
352 "-geometry geom",
353 "Window size/position specified as in X, e.g., 400x300, 400x300-100+200, +100-200, etc."
354 },
355 {
356 "geo", // Geometry (alias)
357 opt_geo,
358 NULL,
359 NULL,
360 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
361 "-geo geom",
362 "Window size/position specified as in X, e.g., 400x300, 400x300-100+200, +100-200, etc."
363 },
364 {
365 "wplt", // Plot window
366 opt_wplt,
367 NULL,
368 NULL,
369 PL_OPT_FUNC | PL_OPT_ARG,
370 "-wplt xl,yl,xr,yr",
371 "Relative coordinates [0-1] of window into plot"
372 },
373 {
374 "mar", // Margin
375 opt_mar,
376 NULL,
377 NULL,
378 PL_OPT_FUNC | PL_OPT_ARG,
379 "-mar margin",
380 "Margin space in relative coordinates (0 to 0.5, def 0)"
381 },
382 {
383 "a", // Aspect ratio
384 opt_a,
385 NULL,
386 NULL,
387 PL_OPT_FUNC | PL_OPT_ARG,
388 "-a aspect",
389 "Page aspect ratio (def: same as output device)"
390 },
391 {
392 "jx", // Justification in x
393 opt_jx,
394 NULL,
395 NULL,
396 PL_OPT_FUNC | PL_OPT_ARG,
397 "-jx justx",
398 "Page justification in x (-0.5 to 0.5, def 0)"
399 },
400 {
401 "jy", // Justification in y
402 opt_jy,
403 NULL,
404 NULL,
405 PL_OPT_FUNC | PL_OPT_ARG,
406 "-jy justy",
407 "Page justification in y (-0.5 to 0.5, def 0)"
408 },
409 {
410 "ori", // Orientation
411 opt_ori,
412 NULL,
413 NULL,
414 PL_OPT_FUNC | PL_OPT_ARG,
415 "-ori orient",
416 "Plot orientation (0,1,2,3=landscape,portrait,seascape,upside-down)"
417 },
418 {
419 "freeaspect", // floating aspect ratio
420 opt_freeaspect,
421 NULL,
422 NULL,
423 PL_OPT_FUNC,
424 "-freeaspect",
425 "Allow aspect ratio to adjust to orientation swaps"
426 },
427 {
428 "portrait", // floating aspect ratio
429 opt_portrait,
430 NULL,
431 NULL,
432 PL_OPT_FUNC,
433 "-portrait",
434 "Sets portrait mode (both orientation and aspect ratio)"
435 },
436 {
437 "width", // Pen width
438 opt_width,
439 NULL,
440 NULL,
441 PL_OPT_FUNC | PL_OPT_ARG,
442 "-width width",
443 "Sets pen width (0 <= width)"
444 },
445 {
446 "bg", // Background color
447 opt_bg,
448 NULL,
449 NULL,
450 PL_OPT_FUNC | PL_OPT_ARG,
451 "-bg color",
452 "Background color (e.g., FF0000=opaque red, 0000FF_0.1=blue with alpha of 0.1)"
453 },
454 {
455 "ncol0", // Allocated colors in cmap 0
456 opt_ncol0,
457 NULL,
458 NULL,
459 PL_OPT_FUNC | PL_OPT_ARG,
460 "-ncol0 n",
461 "Number of colors to allocate in cmap 0 (upper bound)"
462 },
463 {
464 "ncol1", // Allocated colors in cmap 1
465 opt_ncol1,
466 NULL,
467 NULL,
468 PL_OPT_FUNC | PL_OPT_ARG,
469 "-ncol1 n",
470 "Number of colors to allocate in cmap 1 (upper bound)"
471 },
472 {
473 "fam", // Familying on switch
474 opt_fam,
475 NULL,
476 NULL,
477 PL_OPT_FUNC,
478 "-fam",
479 "Create a family of output files"
480 },
481 {
482 "fsiz", // Family file size
483 opt_fsiz,
484 NULL,
485 NULL,
486 PL_OPT_FUNC | PL_OPT_ARG,
487 "-fsiz size[kKmMgG]",
488 "Output family file size (e.g. -fsiz 0.5G, def MB)"
489 },
490 {
491 "fbeg", // Family starting member
492 opt_fbeg,
493 NULL,
494 NULL,
495 PL_OPT_FUNC | PL_OPT_ARG,
496 "-fbeg number",
497 "First family member number on output"
498 },
499 {
500 "finc", // Family member increment
501 opt_finc,
502 NULL,
503 NULL,
504 PL_OPT_FUNC | PL_OPT_ARG,
505 "-finc number",
506 "Increment between family members"
507 },
508 {
509 "fflen", // Family member min field width
510 opt_fflen,
511 NULL,
512 NULL,
513 PL_OPT_FUNC | PL_OPT_ARG,
514 "-fflen length",
515 "Family member number minimum field width"
516 },
517 {
518 "nopixmap", // Do not use pixmaps
519 opt_nopixmap,
520 NULL,
521 NULL,
522 PL_OPT_FUNC,
523 "-nopixmap",
524 "Don't use pixmaps in X-based drivers"
525 },
526 {
527 "db", // Double buffering on switch
528 opt_db,
529 NULL,
530 NULL,
531 PL_OPT_FUNC,
532 "-db",
533 "Double buffer X window output"
534 },
535 {
536 "np", // Page pause off switch
537 opt_np,
538 NULL,
539 NULL,
540 PL_OPT_FUNC,
541 "-np",
542 "No pause between pages"
543 },
544 {
545 "bufmax", // # bytes sent before flushing output
546 opt_bufmax,
547 NULL,
548 NULL,
549 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
550 "-bufmax",
551 "bytes sent before flushing output"
552 },
553 {
554 "server_name", // Main window name of server
555 opt_server_name,
556 NULL,
557 NULL,
558 PL_OPT_FUNC | PL_OPT_ARG,
559 "-server_name name",
560 "Main window name of PLplot server (tk driver)"
561 },
562 {
563 "plserver", // PLplot server name
564 opt_plserver,
565 NULL,
566 NULL,
567 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
568 "-plserver name",
569 "Invoked name of PLplot server (tk driver)"
570 },
571 {
572 "plwindow", // PLplot container window name
573 opt_plwindow,
574 NULL,
575 NULL,
576 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
577 "-plwindow name",
578 "Name of PLplot container window (tk driver)"
579 },
580 {
581 "auto_path", // Additional directory(s) to autoload
582 opt_auto_path,
583 NULL,
584 NULL,
585 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
586 "-auto_path dir",
587 "Additional directory(s) to autoload (tk driver)"
588 },
589 {
590 "tk_file", // -file option for plserver
591 opt_tk_file,
592 NULL,
593 NULL,
594 PL_OPT_FUNC | PL_OPT_ARG | PL_OPT_INVISIBLE,
595 "-tk_file file",
596 "file for plserver (tk driver)"
597 },
598 {
599 "dpi", // Dots per inch
600 opt_dpi,
601 NULL,
602 NULL,
603 PL_OPT_FUNC | PL_OPT_ARG,
604 "-dpi dpi",
605 "Resolution, in dots per inch (e.g. -dpi 360x360)"
606 },
607 {
608 "compression", // compression
609 opt_dev_compression,
610 NULL,
611 NULL,
612 PL_OPT_FUNC | PL_OPT_ARG,
613 "-compression num",
614 "Sets compression level in supporting devices"
615 },
616 {
617 "cmap0",
618 opt_cmap0,
619 NULL,
620 NULL,
621 PL_OPT_ARG | PL_OPT_FUNC,
622 "-cmap0 file name",
623 "Initializes color table 0 from a cmap0.pal format file in one of standard PLplot paths."
624 },
625 {
626 "cmap1",
627 opt_cmap1,
628 NULL,
629 NULL,
630 PL_OPT_ARG | PL_OPT_FUNC,
631 "-cmap1 file name",
632 "Initializes color table 1 from a cmap1.pal format file in one of standard PLplot paths."
633 },
634 {
635 "locale",
636 opt_locale,
637 NULL,
638 NULL,
639 PL_OPT_FUNC,
640 "-locale",
641 "Use locale environment (e.g., LC_ALL, LC_NUMERIC, or LANG) to set LC_NUMERIC locale (which affects decimal point separator)."
642 },
643 {
644 "eofill",
645 opt_eofill,
646 NULL,
647 NULL,
648 PL_OPT_FUNC,
649 "-eofill",
650 "For the case where the boundary of the filled region is self-intersecting, use the even-odd fill rule rather than the default nonzero fill rule."
651 },
652 {
653 "drvopt", // Driver specific options
654 opt_drvopt,
655 NULL,
656 NULL,
657 PL_OPT_ARG | PL_OPT_FUNC,
658 "-drvopt option[=value][,option[=value]]*",
659 "Driver specific options"
660 },
661 {
662 "mfo", // Metafile output option
663 opt_mfo,
664 NULL,
665 NULL,
666 PL_OPT_ARG | PL_OPT_FUNC,
667 "-mfo PLplot metafile name",
668 "Write the plot to the specified PLplot metafile"
669 },
670 {
671 "mfi", // Metafile output option
672 opt_mfi,
673 NULL,
674 NULL,
675 PL_OPT_ARG | PL_OPT_FUNC,
676 "-mfi PLplot metafile name",
677 "Read the specified PLplot metafile"
678 },
679 {
680 NULL, // option
681 NULL, // handler
682 NULL, // client data
683 NULL, // address of variable to set
684 0, // mode flag
685 NULL, // short syntax
686 NULL
687 } // long syntax
688 };
689
690 static PLCHAR_VECTOR plplot_notes[] = {
691 "All parameters must be white-space delimited. Some options are driver",
692 "dependent. Please see the PLplot reference document for more detail.",
693 NULL
694 };
695
696 //--------------------------------------------------------------------------
697 //! @struct PLOptionInfo
698 //!
699 //! Array of option tables and associated info.
700 //!
701 //! The user may merge up to PL_MAX_OPT_TABLES custom option tables (of type
702 //! PLOptionTable) with the internal one. The resulting treatment is simple,
703 //! powerful, and robust. The tables are parsed in the order of last added
704 //! first, to the internal table last. If multiple options of the same name
705 //! occur, only the first parsed is "seen", thus, the user can easily
706 //! override any PLplot internal option merely by providing the same option.
707 //! This same precedence is followed when printing help and usage messages,
708 //! with each set of options given separately. See example usage in
709 //! plrender.c.
710 //--------------------------------------------------------------------------
711
712 typedef struct
713 {
714 PLOptionTable *options;
715 PLCHAR_VECTOR name;
716 const char **notes;
717 } PLOptionInfo;
718
719 PLOptionInfo ploption_info_default = {
720 ploption_table,
721 "PLplot options",
722 plplot_notes
723 };
724
725 #define PL_MAX_OPT_TABLES 10
726 PLOptionInfo ploption_info[PL_MAX_OPT_TABLES] = {
727 {
728 ploption_table,
729 "PLplot options",
730 plplot_notes
731 }
732 };
733
734 // The structure that hold the driver specific command line options
735
736 typedef struct DrvOptCmd
737 {
738 char *option;
739 char *value;
740 struct DrvOptCmd *next;
741 } DrvOptCmd;
742
743 // the variable where opt_drvopt() stores the driver specific command line options
744 static DrvOptCmd drv_opt = { NULL, NULL, NULL };
745
746 static int tables = 1;
747
748 PLINT
c_plsetopt(PLCHAR_VECTOR opt,PLCHAR_VECTOR opt_arg)749 c_plsetopt( PLCHAR_VECTOR opt, PLCHAR_VECTOR opt_arg )
750 {
751 int mode = 0, argc = 2, status;
752 char *argv[3];
753
754 argv[0] = (char *) opt;
755 argv[1] = (char *) opt_arg;
756 argv[2] = NULL;
757 mode =
758 PL_PARSE_QUIET |
759 PL_PARSE_NODELETE |
760 PL_PARSE_NOPROGRAM |
761 PL_PARSE_NODASH;
762
763 status = plparseopts( &argc, argv, mode );
764 if ( status )
765 {
766 fprintf( stderr, "plsetopt: Unrecognized option %s\n", opt );
767 }
768 return status;
769 }
770
771 //--------------------------------------------------------------------------
772 // plMergeOpts()
773 //
774 //! Merge user option table info structure with internal one.
775 //!
776 //! @param options ?
777 //! @param name ?
778 //! @param notes ?
779 //!
780 //--------------------------------------------------------------------------
781
782 PLINT
plMergeOpts(PLOptionTable * options,PLCHAR_VECTOR name,PLCHAR_VECTOR * notes)783 plMergeOpts( PLOptionTable *options, PLCHAR_VECTOR name, PLCHAR_VECTOR *notes )
784 {
785 PLOptionTable *tab;
786
787 pllib_init();
788
789 // Check to make sure option table has been terminated correctly
790
791 for ( tab = (PLOptionTable *) options; tab->opt; tab++ )
792 ;
793
794 // We've reached the last table entry. All the subentries must be NULL or 0
795
796 if ( ( tab->handler != NULL ) ||
797 ( tab->client_data != NULL ) ||
798 ( tab->var != NULL ) ||
799 ( tab->mode != 0 ) ||
800 ( tab->syntax != NULL ) ||
801 ( tab->desc != NULL ) )
802 {
803 plabort( "plMergeOpts: input table improperly terminated" );
804 return 1;
805 }
806
807 // No room for more tables
808
809 if ( tables++ >= PL_MAX_OPT_TABLES )
810 {
811 plabort( "plMergeOpts: max tables limit exceeded, table not merged" );
812 return 1;
813 }
814
815 ploption_info[tables - 1].options = options;
816 ploption_info[tables - 1].name = name;
817 ploption_info[tables - 1].notes = notes;
818
819 return 0;
820 }
821
822 //--------------------------------------------------------------------------
823 // plClearOpts()
824 //
825 //! Clear internal option table info structure.
826 //!
827 //--------------------------------------------------------------------------
828
829 void
plClearOpts(void)830 plClearOpts( void )
831 {
832 tables = 0;
833 }
834
835 //--------------------------------------------------------------------------
836 // plResetOpts()
837 //
838 //! Reset internal option table info structure.
839 //!
840 //--------------------------------------------------------------------------
841
842 void
plResetOpts(void)843 plResetOpts( void )
844 {
845 ploption_info[0] = ploption_info_default;
846 tables = 1;
847 }
848
849 //--------------------------------------------------------------------------
850 // plparseopts()
851 //
852 //! Process options list using current ploptions_info structure.
853 //! An error in parsing the argument list causes a program exit if
854 //! mode_full is set, otherwise the function returns with an error.
855 //!
856 //! @param p_argc pointer to a value that ONLY keeps track of number of arguments after processing.
857 //! @param argv ?
858 //! @param mode ?
859 //!
860 //! @returns 0 if successful.
861 //!
862 //--------------------------------------------------------------------------
863
864 PLINT
c_plparseopts(int * p_argc,char ** argv,PLINT mode)865 c_plparseopts( int *p_argc, char **argv, PLINT mode )
866 {
867 char **argsave, **argend;
868 int i, myargc, myargcsave, status = 0;
869
870
871 // Initialize
872
873 mode_full = mode & PL_PARSE_FULL;
874 mode_quiet = mode & PL_PARSE_QUIET;
875 mode_nodelete = mode & PL_PARSE_NODELETE;
876 mode_showall = mode & PL_PARSE_SHOWALL;
877 mode_noprogram = mode & PL_PARSE_NOPROGRAM;
878 mode_nodash = mode & PL_PARSE_NODASH;
879 mode_skip = mode & PL_PARSE_SKIP;
880
881 myargc = ( *p_argc );
882 argend = argv + myargc;
883
884 // If program name is first argument, save and advance
885
886 if ( !mode_noprogram )
887 {
888 // Just in case plparseopts has been called previously (e.g., with PL_PARSE_NODELETE).
889 if ( plsc->program )
890 free_mem( plsc->program );
891
892 // If plparseopts is not called again, this is freed in plend1.
893 plsc->program = plstrdup( argv[0] );
894 program = (PLCHAR_VECTOR) plsc->program;
895 --myargc; ++argv;
896 }
897 if ( myargc == 0 )
898 return 0;
899
900 // Process the command line
901
902 // Special hack to deal with -debug option before
903 // pllib_init() is called.
904 argsave = argv;
905 myargcsave = myargc;
906 for (; myargc > 0; --myargc, ++argv )
907 {
908 // Allow for "holes" in argv list
909 if ( *argv == NULL || *argv[0] == '\0' )
910 continue;
911
912 if ( ( !mode_nodash && !strcmp( *argv, "-debug" ) ) || ( mode_nodash && !strcmp( *argv, "debug" ) ) )
913 {
914 //fprintf(stderr, "Found debug option in argv\n");
915 // Loop over all options tables, starting with the last
916 for ( i = tables - 1; i >= 0; i-- )
917 {
918 // Check option table for option
919
920 status = ParseOpt( &myargc, &argv, p_argc, &argsave,
921 ploption_info[i].options );
922
923 if ( !status )
924 break;
925 }
926 break;
927 }
928 }
929 // Restore pointers to condition before the above loop
930 // Although array length and content stored in those pointers
931 // is likely changed.
932 myargc = myargcsave;
933 argv = argsave;
934
935 pllib_init();
936
937 argsave = argv;
938 for (; myargc > 0; --myargc, ++argv )
939 {
940 // Allow for "holes" in argv list
941 if ( *argv == NULL || *argv[0] == '\0' )
942 continue;
943
944 // Loop over all options tables, starting with the last
945 for ( i = tables - 1; i >= 0; i-- )
946 {
947 // Check option table for option
948
949 status = ParseOpt( &myargc, &argv, p_argc, &argsave,
950 ploption_info[i].options );
951
952 if ( !status )
953 break;
954 }
955
956 // Handle error return as specified by the mode flag
957
958 if ( status == -1 )
959 {
960 // No match. Keep going if mode_skip is set, otherwise abort if
961 // fully parsing, else return without error.
962
963 status = 0;
964
965 if ( mode_skip )
966 {
967 if ( !mode_nodelete )
968 *argsave++ = *argv;
969 continue;
970 }
971 if ( !mode_quiet && mode_full )
972 {
973 fprintf( stderr, "\nBad command line option \"%s\"\n", argv[0] );
974 plOptUsage();
975 }
976 if ( mode_full )
977 exit( 1 );
978
979 break;
980 }
981 else if ( status == 1 )
982 {
983 // Illegal or badly formed
984
985 if ( !mode_quiet )
986 {
987 fprintf( stderr, "\nBad command line option \"%s\"\n", argv[0] );
988 plOptUsage();
989 }
990 if ( mode_full )
991 exit( 1 );
992
993 break;
994 }
995 else if ( status == 2 )
996 {
997 // Informational option encountered (-h or -v)
998
999 exit( 0 );
1000 }
1001 }
1002
1003 // Compress and NULL-terminate argv
1004
1005 if ( !mode_nodelete )
1006 {
1007 for ( i = 0; i < myargc; i++ )
1008 *argsave++ = *argv++;
1009
1010 if ( argsave < argend )
1011 {
1012 *argsave = NULL;
1013 #ifdef HAVE_NSGETARGC
1014 //
1015 // Modify the global argc variable to match the shortened argv.
1016 // The global argc and argv must be kept consistent so that future
1017 // users of them (e.g. libraries loaded later with a device driver)
1018 // will not try to dereference the null pointer at the end of the
1019 // shortened argv array.
1020 //
1021 *_NSGetArgc() = *p_argc;
1022 #endif
1023 }
1024 }
1025
1026 return status;
1027 }
1028
1029 //--------------------------------------------------------------------------
1030 // ParseOpt()
1031 //
1032 //! Parses & determines appropriate action for input flag.
1033 //!
1034 //! @param p_myargc ?
1035 //! @param p_argv ?
1036 //! @param p_argc pointer to a value that ONLY keeps track of number of arguments after processing.
1037 //! @param p_argsave ?
1038 //! @param option_table ?
1039 //!
1040 //! @returns ?
1041 //!
1042 //--------------------------------------------------------------------------
1043
1044 static int
ParseOpt(int * p_myargc,char *** p_argv,int * p_argc,char *** p_argsave,PLOptionTable * option_table)1045 ParseOpt( int *p_myargc, char ***p_argv, int *p_argc, char ***p_argsave,
1046 PLOptionTable *option_table )
1047 {
1048 PLOptionTable *tab;
1049 char *opt;
1050
1051 // Only handle actual flags and their arguments
1052
1053 if ( mode_nodash || ( *p_argv )[0][0] == '-' )
1054 {
1055 opt = ( *p_argv )[0];
1056 if ( *opt == '-' )
1057 opt++;
1058
1059 for ( tab = option_table; tab->opt; tab++ )
1060 {
1061 // Skip if option not enabled
1062
1063 if ( tab->mode & PL_OPT_DISABLED )
1064 continue;
1065
1066 // Try to match it
1067
1068 if ( *opt == *tab->opt && !strcmp( opt, tab->opt ) )
1069 {
1070 // Option matched, so remove from argv list if applicable.
1071
1072 if ( !mode_nodelete )
1073 {
1074 if ( tab->mode & PL_OPT_NODELETE )
1075 ( *( *p_argsave )++ ) = ( **p_argv );
1076 else
1077 --( *p_argc );
1078 }
1079
1080 // Process option (and argument if applicable)
1081
1082 return ( ProcessOpt( opt, tab, p_myargc, p_argv, p_argc ) );
1083 }
1084 }
1085 }
1086
1087 return -1;
1088 }
1089
1090 //--------------------------------------------------------------------------
1091 // ProcessOpt()
1092 //
1093 //! Process option (and argument if applicable).
1094 //!
1095 //! @param opt ?
1096 //! @param tab ?
1097 //! @param p_myargc ?
1098 //! @param p_argv ?
1099 //! @param p_argc pointer to a value that ONLY keeps track of number of arguments after processing.
1100 //!
1101 //! @returns 0 if successful.
1102 //--------------------------------------------------------------------------
1103
1104 static int
ProcessOpt(char * opt,PLOptionTable * tab,int * p_myargc,char *** p_argv,int * p_argc)1105 ProcessOpt( char * opt, PLOptionTable *tab, int *p_myargc, char ***p_argv,
1106 int *p_argc )
1107 {
1108 int need_arg, res;
1109 char *opt_arg = NULL;
1110
1111 // Get option argument if necessary
1112
1113 need_arg = PL_OPT_ARG | PL_OPT_INT | PL_OPT_FLOAT | PL_OPT_STRING;
1114
1115 if ( tab->mode & need_arg )
1116 {
1117 if ( GetOptarg( &opt_arg, p_myargc, p_argv, p_argc ) )
1118 return 1;
1119 }
1120
1121 // Process argument
1122
1123 switch ( tab->mode & 0xFF00 )
1124 {
1125 case PL_OPT_FUNC:
1126
1127 // Call function handler to do the job
1128
1129 if ( tab->handler == NULL )
1130 {
1131 fprintf( stderr,
1132 "ProcessOpt: no handler specified for option %s\n",
1133 tab->opt );
1134 return 1;
1135 }
1136
1137 if ( mode_nodelete && opt_arg )
1138 {
1139 // Make a copy, since handler may mung opt_arg with strtok()
1140 char *copy =
1141 (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) );
1142 if ( copy == NULL )
1143 {
1144 plabort( "ProcessOpt: out of memory" );
1145 return 1;
1146 }
1147 strcpy( copy, opt_arg );
1148 res = ( ( *tab->handler )( opt, copy, tab->client_data ) );
1149 free( (void *) copy );
1150 return res;
1151 }
1152 else
1153 {
1154 return ( ( *tab->handler )( opt, opt_arg, tab->client_data ) );
1155 }
1156
1157 case PL_OPT_BOOL:
1158
1159 // Set *var as a boolean
1160
1161 if ( tab->var == NULL )
1162 {
1163 fprintf( stderr,
1164 "ProcessOpt: no variable specified for option %s\n",
1165 tab->opt );
1166 return 1;
1167 }
1168 *(int *) tab->var = 1;
1169 break;
1170
1171 case PL_OPT_INT:
1172
1173 // Set *var as an int
1174
1175 if ( tab->var == NULL )
1176 {
1177 fprintf( stderr,
1178 "ProcessOpt: no variable specified for option %s\n",
1179 tab->opt );
1180 return 1;
1181 }
1182 *(int *) tab->var = atoi( opt_arg );
1183 break;
1184
1185 case PL_OPT_FLOAT:
1186
1187 // Set *var as a float
1188
1189 if ( tab->var == NULL )
1190 {
1191 fprintf( stderr,
1192 "ProcessOpt: no variable specified for option %s\n",
1193 tab->opt );
1194 return 1;
1195 }
1196 *(PLFLT *) tab->var = atof( opt_arg );
1197 break;
1198
1199 case PL_OPT_STRING:
1200
1201 // Set var (can be NULL initially) to point to opt_arg string
1202
1203 *(char **) tab->var = opt_arg;
1204 break;
1205
1206 default:
1207
1208 // Somebody messed up..
1209
1210 fprintf( stderr,
1211 "ProcessOpt: invalid processing mode for option %s\n",
1212 tab->opt );
1213 return 1;
1214 }
1215 return 0;
1216 }
1217
1218 //--------------------------------------------------------------------------
1219 // GetOptarg()
1220 //
1221 //! Retrieves an option argument.
1222 //! If an error occurs here it is a true syntax error.
1223 //!
1224 //! @param popt_arg ?
1225 //! @param p_myargc ?
1226 //! @param p_argv ?
1227 //! @param p_argc pointer to a value that ONLY keeps track of number of arguments after processing.
1228 //!
1229 //! @returns 0 if successful.
1230 //!
1231 //--------------------------------------------------------------------------
1232
1233 static int
GetOptarg(char ** popt_arg,int * p_myargc,char *** p_argv,int * p_argc)1234 GetOptarg( char **popt_arg, int *p_myargc, char ***p_argv, int *p_argc )
1235 {
1236 int result = 0;
1237
1238 --( *p_myargc );
1239
1240 if ( ( *p_myargc ) <= 0 ) // oops, no more arguments
1241 result = 1;
1242
1243 if ( !result )
1244 {
1245 ( *p_argv )++;
1246 // Skip -bg argument checking since, for example, "-ffffff" is
1247 // valid but would be considered invalid by the crude test at
1248 // the end of the if. Instead, -bg always consumes the next
1249 // argument (which exists according to the test above) in any
1250 // form, and that argument is checked for validity by the
1251 // opt_bg routine.
1252 if ( strstr( ( ( *p_argv ) - 1 )[0], "-bg" ) != ( ( *p_argv ) - 1 )[0] && ( *p_argv )[0][0] == '-' && isalpha( ( *p_argv )[0][1] ) )
1253 {
1254 ( *p_argv )--; // oops, next arg is a flag
1255 result = 1;
1256 }
1257 }
1258
1259 if ( !result ) // yeah, the user got it right
1260 {
1261 if ( !mode_nodelete )
1262 ( *p_argc )--;
1263 *popt_arg = ( *p_argv )[0];
1264 }
1265 else
1266 {
1267 if ( !mode_quiet )
1268 {
1269 fprintf( stderr, "Argument missing for %s option.\n", ( *p_argv )[0] );
1270 plOptUsage();
1271 }
1272 }
1273 return result;
1274 }
1275
1276 //--------------------------------------------------------------------------
1277 // plSetUsage()
1278 //
1279 //! Set the strings used in usage and syntax messages.
1280 //!
1281 //! @param program_string The program name.
1282 //! @param usage_string String describing how to use the program.
1283 //!
1284 //--------------------------------------------------------------------------
1285
1286 void
plSetUsage(PLCHAR_VECTOR program_string,PLCHAR_VECTOR usage_string)1287 plSetUsage( PLCHAR_VECTOR program_string, PLCHAR_VECTOR usage_string )
1288 {
1289 if ( program_string != NULL )
1290 program = program_string;
1291
1292 if ( usage_string != NULL )
1293 usage = usage_string;
1294 }
1295
1296 //--------------------------------------------------------------------------
1297 // plOptUsage()
1298 //
1299 //! Print usage & syntax message.
1300 //!
1301 //--------------------------------------------------------------------------
1302
1303 void
plOptUsage(void)1304 plOptUsage( void )
1305 {
1306 if ( usage == NULL )
1307 fprintf( stderr, "\nUsage:\n %s [options]\n", program );
1308 else
1309 fputs( usage, stderr );
1310
1311 Syntax();
1312
1313 fprintf( stderr, "\n\nType %s -h for a full description.\n\n",
1314 program );
1315 }
1316
1317 //--------------------------------------------------------------------------
1318 // Syntax()
1319 //
1320 //! Print short syntax message.
1321 //!
1322 //--------------------------------------------------------------------------
1323
1324 static void
Syntax(void)1325 Syntax( void )
1326 {
1327 PLOptionTable *tab;
1328 int i, col, len;
1329
1330 // Loop over all options tables
1331
1332 for ( i = tables - 1; i >= 0; i-- )
1333 {
1334 // Introducer
1335
1336 if ( ploption_info[i].name )
1337 fprintf( stderr, "\n%s:", ploption_info[i].name );
1338 else
1339 fputs( "\nUser options:", stderr );
1340
1341 // Print syntax for each option
1342
1343 col = 80;
1344 for ( tab = ploption_info[i].options; tab->opt; tab++ )
1345 {
1346 if ( tab->mode & PL_OPT_DISABLED )
1347 continue;
1348
1349 if ( !mode_showall && ( tab->mode & PL_OPT_INVISIBLE ) )
1350 continue;
1351
1352 if ( tab->syntax == NULL )
1353 continue;
1354
1355 len = 3 + (int) strlen( tab->syntax ); // space [ string ]
1356 if ( col + len > 79 )
1357 {
1358 fprintf( stderr, "\n " ); // 3 spaces
1359 col = 3;
1360 }
1361 fprintf( stderr, " [%s]", tab->syntax );
1362 col += len;
1363 }
1364 fprintf( stderr, "\n" );
1365 }
1366 }
1367
1368 //--------------------------------------------------------------------------
1369 // Help()
1370 //
1371 //! Print long help message.
1372 //!
1373 //--------------------------------------------------------------------------
1374
1375 static void
Help(void)1376 Help( void )
1377 {
1378 PLOptionTable *tab;
1379 const char **note;
1380 int i;
1381 FILE *outfile = stderr;
1382
1383 #ifdef HAVE_POPEN
1384 FILE *pager = NULL;
1385 if ( getenv( "PAGER" ) != NULL )
1386 pager = (FILE *) popen( "$PAGER", "w" );
1387 if ( pager == NULL )
1388 pager = (FILE *) popen( "more", "w" );
1389 if ( pager != NULL )
1390 outfile = pager;
1391 #endif
1392
1393 // Usage line
1394
1395 if ( usage == NULL )
1396 fprintf( outfile, "\nUsage:\n %s [options]\n", program );
1397 else
1398 fputs( usage, outfile );
1399
1400 // Loop over all options tables
1401
1402 for ( i = tables - 1; i >= 0; i-- )
1403 {
1404 // Introducer
1405
1406 if ( ploption_info[i].name )
1407 fprintf( outfile, "\n%s:\n", ploption_info[i].name );
1408 else
1409 fputs( "\nUser options:\n", outfile );
1410
1411 // Print description for each option
1412
1413 for ( tab = ploption_info[i].options; tab->opt; tab++ )
1414 {
1415 if ( tab->mode & PL_OPT_DISABLED )
1416 continue;
1417
1418 if ( !mode_showall && ( tab->mode & PL_OPT_INVISIBLE ) )
1419 continue;
1420
1421 if ( tab->desc == NULL )
1422 continue;
1423
1424 if ( tab->mode & PL_OPT_INVISIBLE )
1425 fprintf( outfile, " * %-20s %s\n", tab->syntax, tab->desc );
1426 else
1427 fprintf( outfile, " %-20s %s\n", tab->syntax, tab->desc );
1428 }
1429
1430 // Usage notes
1431
1432 if ( ploption_info[i].notes )
1433 {
1434 putc( '\n', outfile );
1435 for ( note = ploption_info[i].notes; *note; note++ )
1436 {
1437 fputs( *note, outfile );
1438 putc( '\n', outfile );
1439 }
1440 }
1441 }
1442
1443 #ifdef HAVE_POPEN
1444 if ( pager != NULL )
1445 pclose( pager );
1446 #endif
1447 }
1448
1449 //--------------------------------------------------------------------------
1450 // plParseDrvOpts
1451 //
1452 //! Parse driver specific options
1453 //!
1454 //! @param acc_opt ?
1455 //!
1456 //! @returns 0 if successful.
1457 //!
1458 //--------------------------------------------------------------------------
1459
1460 int
plParseDrvOpts(DrvOpt * acc_opt)1461 plParseDrvOpts( DrvOpt *acc_opt )
1462 {
1463 DrvOptCmd *drvp;
1464 DrvOpt *t;
1465 int fl;
1466 char msg[80];
1467 memset( msg, '\0', sizeof ( msg ) );
1468
1469 if ( !drv_opt.option )
1470 return 1;
1471
1472 drvp = &drv_opt;
1473 do
1474 {
1475 t = acc_opt; fl = 0;
1476 while ( t->opt )
1477 {
1478 if ( strcmp( drvp->option, t->opt ) == 0 )
1479 {
1480 fl = 1;
1481 switch ( t->type )
1482 {
1483 case DRV_STR:
1484 *(char **) ( t->var_ptr ) = ( drvp->value );
1485 #ifdef DEBUG
1486 fprintf( stderr, "plParseDrvOpts: %s %s\n", t->opt, *(char **) t->var_ptr );
1487 #endif
1488 break;
1489
1490 case DRV_INT:
1491 if ( sscanf( drvp->value, "%d", (int *) t->var_ptr ) != 1 )
1492 {
1493 snprintf( msg, sizeof ( msg ) - 1, "Incorrect argument to '%s' option", drvp->option );
1494 plexit( msg );
1495 }
1496 #ifdef DEBUG
1497 fprintf( stderr, "plParseDrvOpts: %s %d\n", t->opt, *(int *) t->var_ptr );
1498 #endif
1499 break;
1500
1501 case DRV_FLT:
1502 if ( sscanf( drvp->value, "%f", (float *) t->var_ptr ) != 1 )
1503 {
1504 snprintf( msg, sizeof ( msg ) - 1, "Incorrect argument to '%s' option", drvp->option );
1505 plexit( msg );
1506 }
1507 #ifdef DEBUG
1508 fprintf( stderr, "plParseDrvOpts: %s %f\n", t->opt, *(float *) t->var_ptr );
1509 #endif
1510 break;
1511 }
1512 }
1513 t++;
1514 }
1515
1516 if ( !fl )
1517 {
1518 snprintf( msg, sizeof ( msg ) - 1, "Option '%s' not recognized.\n\nRecognized options for this driver are:\n", drvp->option );
1519 plwarn( msg );
1520 plHelpDrvOpts( acc_opt );
1521 plexit( "" );
1522 }
1523 }
1524 while ( ( drvp = drvp->next ) )
1525 ;
1526
1527 return 0;
1528 }
1529
1530 //--------------------------------------------------------------------------
1531 // plHelpDrvOpts
1532 //
1533 //! Give driver specific help
1534 //!
1535 //! @param acc_opt ?
1536 //!
1537 //--------------------------------------------------------------------------
1538
1539 void
plHelpDrvOpts(DrvOpt * acc_opt)1540 plHelpDrvOpts( DrvOpt *acc_opt )
1541 {
1542 DrvOpt *t;
1543
1544 t = acc_opt;
1545 while ( t->opt )
1546 {
1547 fprintf( stderr, "%s:\t%s\n", t->opt, t->hlp_msg );
1548 t++;
1549 }
1550 }
1551
1552 //--------------------------------------------------------------------------
1553 // tidyDrvOpts
1554 //
1555 //! Tidy up and free memory associated with driver options
1556 //!
1557 //--------------------------------------------------------------------------
1558
1559 void
plP_FreeDrvOpts()1560 plP_FreeDrvOpts()
1561 {
1562 DrvOptCmd *drvp, *drvpl;
1563
1564 drvp = &drv_opt;
1565 do
1566 {
1567 drvpl = drvp;
1568 drvp = drvpl->next;
1569
1570 free( drvpl->option );
1571 free( drvpl->value );
1572 // Free additional DrvOptCmd variables -
1573 // first entry in list is a static global variable
1574 if ( drvpl != &drv_opt )
1575 free( drvpl );
1576 } while ( drvp != NULL );
1577
1578 // initialize drv_opt if it's used again
1579 drv_opt.option = NULL;
1580 drv_opt.value = NULL;
1581 drv_opt.next = NULL;
1582 }
1583
1584
1585 //--------------------------------------------------------------------------
1586 // Option handlers
1587 //--------------------------------------------------------------------------
1588
1589 //--------------------------------------------------------------------------
1590 // opt_h()
1591 //
1592 //! Performs appropriate action for option "h":
1593 //! Issues help message
1594 //!
1595 //! @param PL_UNUSED( opt ) Not used.
1596 //! @param PL_UNUSED( opt_arg ) Not used.
1597 //! @param PL_UNUSED( client_data ) Not used.
1598 //!
1599 //! returns 2.
1600 //!
1601 //--------------------------------------------------------------------------
1602
1603 static int
opt_h(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1604 opt_h( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1605 {
1606 if ( !mode_quiet )
1607 Help();
1608
1609 return 2;
1610 }
1611
1612 //--------------------------------------------------------------------------
1613 // opt_v()
1614 //
1615 //! Performs appropriate action for option "v":
1616 //! Issues version message
1617 //!
1618 //! @param PL_UNUSED( opt ) Not used.
1619 //! @param PL_UNUSED( opt_arg ) Not used.
1620 //! @param PL_UNUSED( client_data ) Not used.
1621 //!
1622 //! returns 2.
1623 //!
1624 //--------------------------------------------------------------------------
1625
1626 static int
opt_v(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1627 opt_v( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1628 {
1629 if ( !mode_quiet )
1630 fprintf( stderr, "PLplot library version: %s\n", PLPLOT_VERSION );
1631
1632 return 2;
1633 }
1634
1635 //--------------------------------------------------------------------------
1636 // opt_verbose()
1637 //
1638 //! Performs appropriate action for option "verbose":
1639 //! Turn on verbosity flag
1640 //!
1641 //! @param PL_UNUSED( opt ) Not used.
1642 //! @param PL_UNUSED( opt_arg ) Not used.
1643 //! @param PL_UNUSED( client_data ) Not used.
1644 //!
1645 //! returns 0.
1646 //!
1647 //--------------------------------------------------------------------------
1648
1649 static int
opt_verbose(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1650 opt_verbose( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1651 {
1652 plsc->verbose = 1;
1653 return 0;
1654 }
1655
1656 //--------------------------------------------------------------------------
1657 // opt_debug()
1658 //
1659 //! Performs appropriate action for option "debug":
1660 //! Turn on debugging flag
1661 //!
1662 //! @param PL_UNUSED( opt ) Not used.
1663 //! @param PL_UNUSED( opt_arg ) Not used.
1664 //! @param PL_UNUSED( client_data ) Not used.
1665 //!
1666 //! returns 0.
1667 //!
1668 //--------------------------------------------------------------------------
1669
1670 static int
opt_debug(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1671 opt_debug( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1672 {
1673 plsc->debug = 1;
1674 plsc->verbose = 1;
1675 return 0;
1676 }
1677
1678 //--------------------------------------------------------------------------
1679 // opt_hack()
1680 //
1681 //! Performs appropriate action for option "hack":
1682 //! Enables driver-specific hack(s)
1683 //!
1684 //! @param PL_UNUSED( opt ) Not used.
1685 //! @param PL_UNUSED( opt_arg ) Not used.
1686 //! @param PL_UNUSED( client_data ) Not used.
1687 //!
1688 //! returns 0.
1689 //!
1690 //--------------------------------------------------------------------------
1691
1692 static int
opt_hack(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1693 opt_hack( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1694 {
1695 plsc->hack = 1;
1696 return 0;
1697 }
1698
1699 //--------------------------------------------------------------------------
1700 // opt_dev()
1701 //
1702 //! Performs appropriate action for option "dev":
1703 //! Sets output device keyword
1704 //!
1705 //! @param PL_UNUSED( opt ) Not used.
1706 //! @param opt_arg The name of the output device.
1707 //! @param PL_UNUSED( client_data ) Not used.
1708 //!
1709 //! returns 0.
1710 //!
1711 //--------------------------------------------------------------------------
1712
1713 static int
opt_dev(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1714 opt_dev( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1715 {
1716 plsdev( opt_arg );
1717 return 0;
1718 }
1719
1720 //--------------------------------------------------------------------------
1721 // opt_o()
1722 //
1723 //! Performs appropriate action for option "o":
1724 //! Sets output file name
1725 //!
1726 //! @param PL_UNUSED( opt ) Not used.
1727 //! @param opt_arg The file family name.
1728 //! @param PL_UNUSED( client_data ) Not used.
1729 //!
1730 //! returns 0.
1731 //!
1732 //--------------------------------------------------------------------------
1733
1734 static int
opt_o(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1735 opt_o( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1736 {
1737 plsfnam( opt_arg );
1738 return 0;
1739 }
1740
1741 //--------------------------------------------------------------------------
1742 // opt_mar()
1743 //
1744 //! Performs appropriate action for option "mar":
1745 //! Sets relative margin width
1746 //!
1747 //! @param PL_UNUSED( opt ) Not used.
1748 //! @param opt_arg Plot margin width.
1749 //! @param PL_UNUSED( client_data ) Not used.
1750 //!
1751 //! returns 0.
1752 //!
1753 //--------------------------------------------------------------------------
1754
1755 static int
opt_mar(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1756 opt_mar( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1757 {
1758 plsdidev( atof( opt_arg ), PL_NOTSET, PL_NOTSET, PL_NOTSET );
1759 return 0;
1760 }
1761
1762 //--------------------------------------------------------------------------
1763 // opt_a()
1764 //
1765 //! Performs appropriate action for option "a":
1766 //! Sets plot aspect ratio on page
1767 //!
1768 //! @param PL_UNUSED( opt ) Not used.
1769 //! @param opt_arg Plot aspect ratio.
1770 //! @param PL_UNUSED( client_data ) Not used.
1771 //!
1772 //! returns 0.
1773 //!
1774 //--------------------------------------------------------------------------
1775
1776 static int
opt_a(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1777 opt_a( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1778 {
1779 plsdidev( PL_NOTSET, atof( opt_arg ), PL_NOTSET, PL_NOTSET );
1780 return 0;
1781 }
1782
1783 //--------------------------------------------------------------------------
1784 // opt_jx()
1785 //
1786 //! Performs appropriate action for option "jx":
1787 //! Sets relative justification in x
1788 //!
1789 //! @param PL_UNUSED( opt ) Not used.
1790 //! @param opt_arg Plot relative justification in x(?)
1791 //! @param PL_UNUSED( client_data ) Not used.
1792 //!
1793 //! returns 0.
1794 //!
1795 //--------------------------------------------------------------------------
1796
1797 static int
opt_jx(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1798 opt_jx( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1799 {
1800 plsdidev( PL_NOTSET, PL_NOTSET, atof( opt_arg ), PL_NOTSET );
1801 return 0;
1802 }
1803
1804 //--------------------------------------------------------------------------
1805 // opt_jy()
1806 //
1807 //! Performs appropriate action for option "jy":
1808 //! Sets relative justification in y
1809 //!
1810 //! @param PL_UNUSED( opt ) Not used.
1811 //! @param opt_arg Plot relative justification in y(?)
1812 //! @param PL_UNUSED( client_data ) Not used.
1813 //!
1814 //! returns 0.
1815 //!
1816 //--------------------------------------------------------------------------
1817
1818 static int
opt_jy(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1819 opt_jy( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1820 {
1821 plsdidev( PL_NOTSET, PL_NOTSET, PL_NOTSET, atof( opt_arg ) );
1822 return 0;
1823 }
1824
1825 //--------------------------------------------------------------------------
1826 // opt_ori()
1827 //
1828 //! Performs appropriate action for option "ori":
1829 //! Sets orientation
1830 //!
1831 //! @param PL_UNUSED( opt ) Not used.
1832 //! @param opt_arg Plot orientation.
1833 //! @param PL_UNUSED( client_data ) Not used.
1834 //!
1835 //! returns 0.
1836 //!
1837 //--------------------------------------------------------------------------
1838
1839 static int
opt_ori(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1840 opt_ori( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1841 {
1842 plsdiori( atof( opt_arg ) );
1843 return 0;
1844 }
1845
1846 //--------------------------------------------------------------------------
1847 // opt_freeaspect()
1848 //
1849 //! Performs appropriate action for option "freeaspect":
1850 //! Allow aspect ratio to adjust to orientation swaps.
1851 //!
1852 //! @param PL_UNUSED( opt ) Not used.
1853 //! @param PL_UNUSED( opt_arg ) Not used.
1854 //! @param PL_UNUSED( client_data ) Not used.
1855 //!
1856 //! returns 0.
1857 //!
1858 //--------------------------------------------------------------------------
1859
1860 static int
opt_freeaspect(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1861 opt_freeaspect( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1862 {
1863 plsc->freeaspect = 1;
1864 return 0;
1865 }
1866
1867 //--------------------------------------------------------------------------
1868 // opt_portrait()
1869 //
1870 //! Performs appropriate action for option "portrait":
1871 //! Set portrait mode. If plsc->portrait = 1, then the orientation for certain
1872 //! drivers is changed by 90 deg to portrait orientation from the default
1873 //! landscape orientation used by PLplot while the aspect ratio allowed to
1874 //! adjust using freeaspect.
1875 //! N.B. the driver list where this flag is honored is currently limited
1876 //! to psc, ps, and pstex. A 90 deg rotation is just not
1877 //! appropriate for certain other drivers. These drivers where portrait
1878 //! mode is ignored include display drivers (e.g., xwin, tk), drivers
1879 //! which are subequently going to be transformed to another form
1880 //! (e.g., meta), or drivers which are normally used for web
1881 //! publishing (e.g., png, jpeg). That said, the case is not entirely clear
1882 //! for all drivers so the list of drivers where portrait mode is honored
1883 //! may increase in the future. To add to the list simply copy the small
1884 //! bit of code from ps.c that has to do with pls->portrait to the
1885 //! appropriate driver file.
1886 //!
1887 //! @param PL_UNUSED( opt ) Not used.
1888 //! @param PL_UNUSED( opt_arg ) Not used.
1889 //! @param PL_UNUSED( client_data ) Not used.
1890 //!
1891 //! returns 0.
1892 //!
1893 //--------------------------------------------------------------------------
1894
1895 static int
opt_portrait(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))1896 opt_portrait( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
1897 {
1898 plsc->portrait = 1;
1899 return 0;
1900 }
1901
1902 //--------------------------------------------------------------------------
1903 // opt_width()
1904 //
1905 //! Performs appropriate action for option "width":
1906 //! Sets pen width
1907 //!
1908 //! @param PL_UNUSED( opt ) Not used.
1909 //! @param opt_arg Plot pen width.
1910 //! @param PL_UNUSED( client_data ) Not used.
1911 //!
1912 //! returns 0.
1913 //!
1914 //--------------------------------------------------------------------------
1915
1916 static int
opt_width(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1917 opt_width( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1918 {
1919 double width;
1920
1921 width = atof( opt_arg );
1922 if ( width < 0. )
1923 {
1924 fprintf( stderr, "?invalid width\n" );
1925 return 1;
1926 }
1927 else
1928 {
1929 plwidth( width );
1930 plsc->widthlock = 1;
1931 }
1932 return 0;
1933 }
1934
1935 //--------------------------------------------------------------------------
1936 // opt_bg()
1937 //
1938 //! Performs appropriate action for option "bg":
1939 //! Sets background color (rgb represented in hex on command line) and alpha
1940 //! (represented as floating point on the command line with underscore
1941 //! delimiter), e.g.,
1942 //! -bg ff0000 (set background to red with an alpha value of MAX_PLFLT_ALPHA ==> opaque)
1943 //! -bg ff0000_0.1 (set background to red with an alpha value of 0.1)
1944 //!
1945 //! @param PL_UNUSED( opt ) Not used.
1946 //! @param opt_arg Background RGB color in hex (in 3-digit of 6-digit format)
1947 //! followed by optional combination of "_" + floating-point alpha value.
1948 //! @param PL_UNUSED( client_data ) Not used.
1949 //!
1950 //! returns 0.
1951 //!
1952 //--------------------------------------------------------------------------
1953
1954 static int
opt_bg(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))1955 opt_bg( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
1956 {
1957 PLCHAR_VECTOR rgb;
1958 char *color_field, *color_field_wp, *color_field_wp_alt, *alpha_field;
1959 char *endptr;
1960 long bgcolor;
1961 PLINT r, g, b;
1962 PLFLT a;
1963 int save_errno;
1964
1965 // Strip off leading "#" (TK-ism) if present.
1966
1967 if ( *opt_arg == '#' )
1968 rgb = opt_arg + 1;
1969 else
1970 rgb = opt_arg;
1971
1972 strncpy( opttmp, rgb, OPTMAX - 1 );
1973 opttmp[OPTMAX - 1] = '\0';
1974
1975 //fprintf( stderr, "-bg option = %s\n", opttmp );
1976 color_field = opttmp;
1977 alpha_field = strchr( opttmp, '_' );
1978 if ( alpha_field != NULL )
1979 {
1980 // null-terminate color_field at the position of the delimiter.
1981 *alpha_field = '\0';
1982 // point alpha_field at the position one beyond the delimiter.
1983 alpha_field++;
1984 }
1985 else
1986 {
1987 // If no delimiter, then assume opaque.
1988 alpha_field = "MAX_PLFLT_ALPHA";
1989 }
1990
1991 //fprintf( stderr, "color_field = %s\n", color_field );
1992 //fprintf( stderr, "alpha_field = %s\n", alpha_field );
1993
1994 // Parse color_field
1995 errno = 0; // To distinguish success/failure after call
1996 bgcolor = strtol( color_field, &endptr, 16 );
1997 save_errno = errno;
1998
1999 // Check for various possible errors
2000
2001 if ( ( errno == ERANGE && ( bgcolor == LONG_MIN || bgcolor == LONG_MAX ) ) || ( errno != 0 && bgcolor == 0 ) )
2002 {
2003 plwarn( "opt_bg: parsing of color_field as hex to a long caused integer overflow so use (warning) red" );
2004 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2005 errno = save_errno;
2006 perror( "opt_bg strtol issue" );
2007 fprintf( stderr, "color_field = %s\n", color_field );
2008 color_field = "ff0000";
2009 fprintf( stderr, "derived color_field = %s\n", color_field );
2010 bgcolor = strtol( color_field, &endptr, 16 );
2011 fprintf( stderr, "derived bgcolor = %#lx\n", bgcolor );
2012 }
2013 else if ( endptr == color_field )
2014 {
2015 plwarn( "opt_bg: color_field could not be parsed as hex to a long so use (warning) red" );
2016 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2017 fprintf( stderr, "color_field = %s\n", color_field );
2018 color_field = "ff0000";
2019 fprintf( stderr, "derived color_field = %s\n", color_field );
2020 bgcolor = strtol( color_field, &endptr, 16 );
2021 fprintf( stderr, "derived bgcolor = %#lx\n", bgcolor );
2022 }
2023 else if ( *endptr != '\0' )
2024 {
2025 plwarn( "opt_bg: color_field could be parsed as hex to a long but there was trailing garbage which was ignored" );
2026 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2027 fprintf( stderr, "color_field = %s\n", color_field );
2028 // Trim trailing garbage off of color_field.
2029 *endptr = '\0';
2030 fprintf( stderr, "derived color_field = %s\n", color_field );
2031 fprintf( stderr, "derived bgcolor = %#lx\n", bgcolor );
2032 }
2033
2034 // If bgcolor has 3 digits, each is "doubled" (i.e. ABC becomes AABBCC).
2035
2036 // Find color_field without prefix where that prefix consists of optional whitespace followed
2037 // by optional sign followed by optional 0x or 0X.
2038 color_field_wp = color_field;
2039 while ( isspace( (unsigned char) *color_field_wp ) )
2040 color_field_wp++;
2041 if ( ( color_field_wp_alt = strstr( color_field_wp, "+" ) ) == color_field_wp ||
2042 ( color_field_wp_alt = strstr( color_field_wp, "-" ) ) == color_field_wp )
2043 color_field_wp += 1;
2044 if ( ( color_field_wp_alt = strstr( color_field_wp, "0x" ) ) == color_field_wp ||
2045 ( color_field_wp_alt = strstr( color_field_wp, "0X" ) ) == color_field_wp )
2046 color_field_wp += 2;
2047
2048 switch ( strlen( color_field_wp ) )
2049 {
2050 case 3:
2051 r = (PLINT) ( ( bgcolor & 0xF00 ) >> 8 );
2052 g = (PLINT) ( ( bgcolor & 0x0F0 ) >> 4 );
2053 b = (PLINT) ( bgcolor & 0x00F );
2054
2055 r = r | ( r << 4 );
2056 g = g | ( g << 4 ); // doubling
2057 b = b | ( b << 4 );
2058 break;
2059
2060 case 6:
2061 r = (PLINT) ( ( bgcolor & 0xFF0000 ) >> 16 );
2062 g = (PLINT) ( ( bgcolor & 0x00FF00 ) >> 8 );
2063 b = (PLINT) ( bgcolor & 0x0000FF );
2064 break;
2065
2066 default:
2067 plwarn( "opt_bg: color_field without prefix is not of the correct form. Therefore use (warning) red" );
2068 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2069 fprintf( stderr, "color_field = %s\n", color_field );
2070 fprintf( stderr, "%s\n", "The correct form of color_field without prefix is exactly 3 or 6 hex digits" );
2071 fprintf( stderr, "color_field without prefix = %s\n", color_field_wp );
2072 r = MAX_PLINT_RGB;
2073 g = 0;
2074 b = 0;
2075 fprintf( stderr, "derived r, g, b = %d, %d, %d\n", r, g, b );
2076 }
2077
2078 // Parse alpha_field using strtod and checking for all potential issues.
2079 errno = 0; // To distinguish success/failure after call
2080 a = (PLFLT) strtod( alpha_field, &endptr );
2081 save_errno = errno;
2082
2083 // Check for various possible errors
2084
2085 if ( errno == ERANGE && ( a == HUGE_VAL || a == -HUGE_VAL ) )
2086 {
2087 plwarn( "opt_bg: parsing of alpha_field to a double caused floating overflow so use opaque" );
2088 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2089 errno = save_errno;
2090 perror( "opt_bg strtod issue" );
2091 fprintf( stderr, "alpha_field = %s\n", alpha_field );
2092 a = MAX_PLFLT_ALPHA;
2093 fprintf( stderr, "derived alpha value = %e\n", a );
2094 }
2095 else if ( endptr == alpha_field )
2096 {
2097 plwarn( "opt_bg: alpha_field could not be parsed to a double so use opaque" );
2098 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2099 fprintf( stderr, "alpha_field = %s\n", alpha_field );
2100 a = MAX_PLFLT_ALPHA;
2101 fprintf( stderr, "derived alpha value = %e\n", a );
2102 }
2103 else if ( *endptr != '\0' )
2104 {
2105 plwarn( "opt_bg: alpha_field could be parsed to a double but there was trailing garbage which was ignored" );
2106 fprintf( stderr, "%s\n", "Further information relevant to this warning:" );
2107 fprintf( stderr, "alpha_field = %s\n", alpha_field );
2108 fprintf( stderr, "derived alpha value = %e\n", a );
2109 }
2110
2111 //fprintf( stderr, "r, g, b, alpha = %d, %d, %d, %e\n", r, g, b, a );
2112 plscolbga( r, g, b, a );
2113
2114 return 0;
2115 }
2116
2117 //--------------------------------------------------------------------------
2118 // opt_ncol0()
2119 //
2120 //! Performs appropriate action for option "ncol0":
2121 //! Sets number of colors to allocate in cmap 0 (upper bound).
2122 //!
2123 //! @param PL_UNUSED( opt ) Not used.
2124 //! @param opt_arg Number of color map 0 colors.
2125 //! @param PL_UNUSED( client_data ) Not used.
2126 //!
2127 //! returns 0.
2128 //!
2129 //--------------------------------------------------------------------------
2130
2131 static int
opt_ncol0(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2132 opt_ncol0( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2133 {
2134 plsc->ncol0 = atoi( opt_arg );
2135 return 0;
2136 }
2137
2138 //--------------------------------------------------------------------------
2139 // opt_ncol1()
2140 //
2141 //! Performs appropriate action for option "ncol1":
2142 //! Sets number of colors to allocate in cmap 1 (upper bound).
2143 //!
2144 //! @param PL_UNUSED( opt ) Not used.
2145 //! @param opt_arg Number of color map 1 colors.
2146 //! @param PL_UNUSED( client_data ) Not used.
2147 //!
2148 //! returns 0.
2149 //!
2150 //--------------------------------------------------------------------------
2151
2152 static int
opt_ncol1(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2153 opt_ncol1( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2154 {
2155 plsc->ncol1 = atoi( opt_arg );
2156 return 0;
2157 }
2158
2159 //--------------------------------------------------------------------------
2160 // opt_wplt()
2161 //
2162 //! Performs appropriate action for option "wplt":
2163 //! Sets (zoom) window into plot (e.g. "0,0,0.5,0.5")
2164 //!
2165 //! @param PL_UNUSED( opt ) Not used.
2166 //! @param opt_arg Zoom setting.
2167 //! @param PL_UNUSED( client_data ) Not used.
2168 //!
2169 //! returns 0.
2170 //!
2171 //--------------------------------------------------------------------------
2172
2173 static int
opt_wplt(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2174 opt_wplt( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2175 {
2176 char *field;
2177 PLFLT xl, yl, xr, yr;
2178
2179 strncpy( opttmp, opt_arg, OPTMAX - 1 );
2180 opttmp[OPTMAX - 1] = '\0';
2181
2182 if ( ( field = strtok( opttmp, "," ) ) == NULL )
2183 return 1;
2184
2185 xl = atof( field );
2186
2187 if ( ( field = strtok( NULL, "," ) ) == NULL )
2188 return 1;
2189
2190 yl = atof( field );
2191
2192 if ( ( field = strtok( NULL, "," ) ) == NULL )
2193 return 1;
2194
2195 xr = atof( field );
2196
2197 if ( ( field = strtok( NULL, "," ) ) == NULL )
2198 return 1;
2199
2200 yr = atof( field );
2201
2202 plsdiplt( xl, yl, xr, yr );
2203 return 0;
2204 }
2205
2206 //--------------------------------------------------------------------------
2207 // opt_drvopt()
2208 //
2209 //! Get driver specific options in the form <option[=value]>[,option[=value]]*
2210 //! If "value" is not specified, it defaults to "1".
2211 //!
2212 //! @param PL_UNUSED( opt ) Not used.
2213 //! @param opt_arg The driver specific option.
2214 //! @param PL_UNUSED( client_data ) Not used.
2215 //!
2216 //! returns 0.
2217 //!
2218 //--------------------------------------------------------------------------
2219
2220 static int
opt_drvopt(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2221 opt_drvopt( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2222 {
2223 char t, *tt, *option, *value;
2224 int fl = 0;
2225 DrvOptCmd *drvp;
2226
2227 option = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) );
2228 if ( option == NULL )
2229 plexit( "opt_drvopt: Out of memory!?" );
2230
2231 value = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) );
2232 if ( value == NULL )
2233 plexit( "opt_drvopt: Out of memory!?" );
2234
2235 drvp = &drv_opt;
2236 *option = *value = '\0';
2237 tt = option;
2238 while ( ( t = *opt_arg++ ) )
2239 {
2240 switch ( t )
2241 {
2242 case ',':
2243 if ( fl )
2244 fl = 0;
2245 else
2246 {
2247 value[0] = '1';
2248 value[1] = '\0';
2249 }
2250
2251 *tt = '\0'; tt = option;
2252 drvp->option = plstrdup( option ); // it should not be release, because of familying
2253 drvp->value = plstrdup( value ); // don't release
2254 drvp->next = (DrvOptCmd *) malloc( sizeof ( DrvOptCmd ) ); // don't release
2255 if ( drvp->next == NULL )
2256 plexit( "opt_drvopt: Out of memory!?\n" );
2257
2258 drvp = drvp->next;
2259 break;
2260
2261 case '=':
2262 fl = 1;
2263 *tt = '\0'; tt = value;
2264 break;
2265
2266 default:
2267 *tt++ = t;
2268 }
2269 }
2270
2271 *tt = '\0';
2272 if ( !fl )
2273 {
2274 value[0] = '1';
2275 value[1] = '\0';
2276 }
2277
2278 drvp->option = plstrdup( option ); // don't release
2279 drvp->value = plstrdup( value ); // don't release
2280 drvp->next = NULL;
2281
2282 #ifdef DEBUG
2283 fprintf( stderr, "\nopt_drvopt: -drvopt parsed options:\n" );
2284 drvp = &drv_opt;
2285 do
2286 fprintf( stderr, "%s %s\n", drvp->option, drvp->value );
2287 while ( drvp = drvp->next );
2288 fprintf( stderr, "\n" );
2289 #endif
2290
2291 free( option ); free( value );
2292
2293 return 0;
2294 }
2295
2296 //--------------------------------------------------------------------------
2297 // opt_fam()
2298 //
2299 //! Performs appropriate action for option "fam":
2300 //! Enables family output files
2301 //!
2302 //! @param PL_UNUSED( opt ) Not used.
2303 //! @param PL_UNUSED( opt_arg ) Not used.
2304 //! @param PL_UNUSED( client_data ) Not used.
2305 //!
2306 //! returns 0.
2307 //!
2308 //--------------------------------------------------------------------------
2309
2310 static int
opt_fam(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2311 opt_fam( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2312 {
2313 plsfam( 1, -1, -1 );
2314 return 0;
2315 }
2316
2317 //--------------------------------------------------------------------------
2318 // opt_fsiz()
2319 //
2320 //! Performs appropriate action for option "fsiz":
2321 //! Sets size of a family member file (may be somewhat larger since eof must
2322 //! occur at a page break). Also turns on familying. Example usage:
2323 //!
2324 //! -fsiz 5M (5 MB)
2325 //! -fsiz 300K (300 KB)
2326 //! -fsiz .3M (same)
2327 //! -fsiz .5G (half a GB)
2328 //!
2329 //! Note case of the trailing suffix doesn't matter.
2330 //! If no suffix, defaults to MB.
2331 //!
2332 //! @param PL_UNUSED( opt ) Not used.
2333 //! @param opt_arg Family size setting.
2334 //! @param PL_UNUSED( client_data ) Not used.
2335 //!
2336 //! returns 0.
2337 //!
2338 //--------------------------------------------------------------------------
2339
2340 static int
opt_fsiz(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2341 opt_fsiz( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2342 {
2343 PLINT bytemax;
2344 size_t len = strlen( opt_arg );
2345 char lastchar = opt_arg[len - 1];
2346 PLFLT multiplier = 1.0e6;
2347 char *spec = (char *) malloc( len + 1 );
2348
2349 if ( spec == NULL )
2350 plexit( "opt_fsiz: Insufficient memory" );
2351
2352 // Interpret optional suffix
2353
2354 switch ( lastchar )
2355 {
2356 case 'k':
2357 case 'K':
2358 multiplier = 1.0e3; len--;
2359 break;
2360 case 'm':
2361 case 'M':
2362 multiplier = 1.0e6; len--;
2363 break;
2364 case 'g':
2365 case 'G':
2366 multiplier = 1.0e9; len--;
2367 break;
2368 }
2369 strncpy( spec, opt_arg, len );
2370 spec[len] = '\0';
2371
2372 bytemax = (PLINT) ( multiplier * atof( spec ) );
2373 if ( bytemax <= 0 )
2374 {
2375 fprintf( stderr, "?invalid file size %d. 2.14G is the maximum.\n", bytemax );
2376 return 1;
2377 }
2378 plsfam( 1, -1, bytemax );
2379
2380 free( spec );
2381 return 0;
2382 }
2383
2384 //--------------------------------------------------------------------------
2385 // opt_fbeg()
2386 //
2387 //! Performs appropriate action for option "fbeg":
2388 //! Starts with the specified family member number.
2389 //!
2390 //! @param PL_UNUSED( opt ) Not used.
2391 //! @param opt_arg Number of the first plot.
2392 //! @param PL_UNUSED( client_data ) Not used.
2393 //!
2394 //! returns 0.
2395 //!
2396 //--------------------------------------------------------------------------
2397
2398 static int
opt_fbeg(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2399 opt_fbeg( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2400 {
2401 plsc->member = atoi( opt_arg );
2402
2403 return 0;
2404 }
2405
2406 //--------------------------------------------------------------------------
2407 // opt_finc()
2408 //
2409 //! Performs appropriate action for option "finc":
2410 //! Specify increment between family members.
2411 //!
2412 //! @param PL_UNUSED( opt ) Not used.
2413 //! @param opt_arg Amount to increment the plot number between plots.
2414 //! @param PL_UNUSED( client_data ) Not used.
2415 //!
2416 //! returns 0.
2417 //!
2418 //--------------------------------------------------------------------------
2419
2420 static int
opt_finc(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2421 opt_finc( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2422 {
2423 plsc->finc = atoi( opt_arg );
2424
2425 return 0;
2426 }
2427
2428 //--------------------------------------------------------------------------
2429 // opt_fflen()
2430 //
2431 //! Performs appropriate action for option "fflen":
2432 //! Specify minimum field length for family member number.
2433 //!
2434 //! @param PL_UNUSED( opt ) Not used.
2435 //! @param opt_arg Size of the family number field (e.g. "1", "01", "001" ?)
2436 //! @param PL_UNUSED( client_data ) Not used.
2437 //!
2438 //! returns 0.
2439 //!
2440 //--------------------------------------------------------------------------
2441
2442 static int
opt_fflen(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2443 opt_fflen( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2444 {
2445 plsc->fflen = atoi( opt_arg );
2446
2447 return 0;
2448 }
2449
2450 //--------------------------------------------------------------------------
2451 // opt_np()
2452 //
2453 //! Performs appropriate action for option "np":
2454 //! Disables pause between pages
2455 //!
2456 //! @param PL_UNUSED( opt ) Not used.
2457 //! @param PL_UNUSED( opt_arg ) Not used.
2458 //! @param PL_UNUSED( client_data ) Not used.
2459 //!
2460 //! returns 0.
2461 //!
2462 //--------------------------------------------------------------------------
2463
2464 static int
opt_np(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2465 opt_np( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2466 {
2467 plspause( 0 );
2468 return 0;
2469 }
2470
2471 //--------------------------------------------------------------------------
2472 // opt_nopixmap()
2473 //
2474 //! Performs appropriate action for option "nopixmap":
2475 //! Disables use of pixmaps in X drivers
2476 //!
2477 //! @param PL_UNUSED( opt ) Not used.
2478 //! @param PL_UNUSED( opt_arg ) Not used.
2479 //! @param PL_UNUSED( client_data ) Not used.
2480 //!
2481 //! returns 0.
2482 //!
2483 //--------------------------------------------------------------------------
2484
2485 static int
opt_nopixmap(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2486 opt_nopixmap( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2487 {
2488 plsc->nopixmap = 1;
2489 return 0;
2490 }
2491
2492 //--------------------------------------------------------------------------
2493 // opt_db()
2494 //
2495 //! Performs appropriate action for option "db":
2496 //! Double buffer X output (update only done on eop or Expose)
2497 //!
2498 //! @param PL_UNUSED( opt ) Not used.
2499 //! @param PL_UNUSED( opt_arg ) Not used.
2500 //! @param PL_UNUSED( client_data ) Not used.
2501 //!
2502 //! returns 0.
2503 //!
2504 //--------------------------------------------------------------------------
2505
2506 static int
opt_db(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2507 opt_db( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2508 {
2509 plsc->db = 1;
2510 return 0;
2511 }
2512
2513 //--------------------------------------------------------------------------
2514 // opt_bufmax()
2515 //
2516 //! Performs appropriate action for option "bufmax":
2517 //! Sets size of data buffer for tk driver
2518 //!
2519 //! @param PL_UNUSED( opt ) Not used.
2520 //! @param opt_arg Size of the data buffer for the tk driver.
2521 //! @param PL_UNUSED( client_data ) Not used.
2522 //!
2523 //! returns 0.
2524 //!
2525 //--------------------------------------------------------------------------
2526
2527 static int
opt_bufmax(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2528 opt_bufmax( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2529 {
2530 plsc->bufmax = atoi( opt_arg );
2531 return 0;
2532 }
2533
2534 //--------------------------------------------------------------------------
2535 // opt_server_name()
2536 //
2537 //! Performs appropriate action for option "server_name":
2538 //! Sets main window name of server (Tcl/TK driver only)
2539 //!
2540 //! @param PL_UNUSED( opt ) Not used.
2541 //! @param opt_arg The name of the main window.
2542 //! @param PL_UNUSED( client_data ) Not used.
2543 //!
2544 //! returns 0.
2545 //!
2546 //--------------------------------------------------------------------------
2547
2548 static int
opt_server_name(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2549 opt_server_name( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2550 {
2551 plsc->server_name = plstrdup( opt_arg );
2552 return 0;
2553 }
2554
2555 //--------------------------------------------------------------------------
2556 // opt_plserver()
2557 //
2558 //! Performs appropriate action for option "plserver":
2559 //! Sets name to use when invoking server (Tcl/TK driver only)
2560 //!
2561 //! @param PL_UNUSED( opt ) Not used.
2562 //! @param opt_arg Name of Tcl/TK server (?).
2563 //! @param PL_UNUSED( client_data ) Not used.
2564 //!
2565 //! returns 0.
2566 //!
2567 //--------------------------------------------------------------------------
2568
2569 static int
opt_plserver(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2570 opt_plserver( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2571 {
2572 plsc->plserver = plstrdup( opt_arg );
2573 return 0;
2574 }
2575
2576 //--------------------------------------------------------------------------
2577 // opt_plwindow()
2578 //
2579 //! Performs appropriate action for option "plwindow":
2580 //! Sets PLplot window name
2581 //!
2582 //! @param PL_UNUSED( opt ) Not used.
2583 //! @param opt_arg Name of the window.
2584 //! @param PL_UNUSED( client_data ) Not used.
2585 //!
2586 //! returns 0.
2587 //!
2588 //--------------------------------------------------------------------------
2589
2590 static int
opt_plwindow(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2591 opt_plwindow( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2592 {
2593 if ( ( plsc->plwindow = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) ) ) == NULL )
2594 {
2595 plexit( "opt_plwindow: Insufficient memory" );
2596 }
2597 strcpy( plsc->plwindow, opt_arg );
2598 return 0;
2599 }
2600
2601 //--------------------------------------------------------------------------
2602 // opt_auto_path()
2603 //
2604 //! Performs appropriate action for option "auto_path":
2605 //! Sets additional directories to autoload
2606 //!
2607 //! @param PL_UNUSED( opt ) Not used.
2608 //! @param opt_arg Additional directories to add the the load path (?).
2609 //! @param PL_UNUSED( client_data ) Not used.
2610 //!
2611 //! returns 0.
2612 //!
2613 //--------------------------------------------------------------------------
2614
2615 static int
opt_auto_path(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2616 opt_auto_path( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2617 {
2618 plsc->auto_path = plstrdup( opt_arg );
2619 return 0;
2620 }
2621
2622 //--------------------------------------------------------------------------
2623 // opt_px()
2624 //
2625 //! Performs appropriate action for option "px":
2626 //! Set packing in x
2627 //!
2628 //! @param PL_UNUSED( opt ) Not used.
2629 //! @param opt_arg X packing (?).
2630 //! @param PL_UNUSED( client_data ) Not used.
2631 //!
2632 //! returns 0.
2633 //!
2634 //--------------------------------------------------------------------------
2635
2636 static int
opt_px(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2637 opt_px( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2638 {
2639 plssub( atoi( opt_arg ), -1 );
2640 return 0;
2641 }
2642
2643 //--------------------------------------------------------------------------
2644 // opt_py()
2645 //
2646 //! Performs appropriate action for option "py":
2647 //! Set packing in y
2648 //!
2649 //! @param PL_UNUSED( opt ) Not used.
2650 //! @param opt_arg Y packing (?).
2651 //! @param PL_UNUSED( client_data ) Not used.
2652 //!
2653 //! returns 0.
2654 //!
2655 //--------------------------------------------------------------------------
2656
2657 static int
opt_py(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2658 opt_py( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2659 {
2660 plssub( -1, atoi( opt_arg ) );
2661 return 0;
2662 }
2663
2664 //--------------------------------------------------------------------------
2665 // opt_geo()
2666 //
2667 //! Performs appropriate action for option "geo": Set geometry for
2668 //! output window, i.e., "-geometry WIDTHxHEIGHT+XOFF+YOFF" where
2669 //! WIDTHxHEIGHT, +XOFF+YOFF, or both must be present, and +XOFF+YOFF
2670 //! stands for one of the four combinations +XOFF+YOFF, +XOFF-YOFF,
2671 //! -XOFF+YOFF, and -XOFF-YOFF. Some examples are the following:
2672 //! -geometry 400x300, -geometry -100+200, and -geometry 400x300-100+200.
2673 //!
2674 //! @param PL_UNUSED( opt ) Not used.
2675 //! @param opt_arg Plot geometry descriptor.
2676 //! @param PL_UNUSED( client_data ) Not used.
2677 //!
2678 //! returns 0.
2679 //!
2680 //--------------------------------------------------------------------------
2681
2682 static int
opt_geo(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2683 opt_geo( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2684 {
2685 int numargs;
2686 PLFLT xdpi = 0., ydpi = 0.;
2687 PLINT xwid, ywid, xoff, yoff;
2688
2689 // The TK driver uses the geometry string directly
2690
2691 if ( ( plsc->geometry = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) ) ) == NULL )
2692 {
2693 plexit( "opt_geo: Insufficient memory" );
2694 }
2695
2696 strcpy( plsc->geometry, opt_arg );
2697
2698 numargs = sscanf( opt_arg, "%dx%d%d%d", &xwid, &ywid, &xoff, &yoff );
2699 if ( numargs == 2 )
2700 {
2701 xoff = 0;
2702 yoff = 0;
2703 if ( xwid == 0 )
2704 fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
2705 if ( ywid == 0 )
2706 fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
2707 if ( xwid < 0 )
2708 {
2709 fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
2710 return 1;
2711 }
2712 if ( ywid < 0 )
2713 {
2714 fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
2715 return 1;
2716 }
2717 }
2718 else if ( numargs == 4 )
2719 {
2720 if ( xwid == 0 )
2721 fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
2722 if ( ywid == 0 )
2723 fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
2724 if ( xwid < 0 )
2725 {
2726 fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
2727 return 1;
2728 }
2729 if ( ywid < 0 )
2730 {
2731 fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
2732 return 1;
2733 }
2734 if ( abs( xoff ) == 0 )
2735 fprintf( stderr, "?invalid xoff in -geometry %s\n", opt_arg );
2736 if ( abs( yoff ) == 0 )
2737 fprintf( stderr, "?invalid yoff in -geometry %s\n", opt_arg );
2738 }
2739 else
2740 {
2741 numargs = sscanf( opt_arg, "%d%d", &xoff, &yoff );
2742 if ( numargs == 2 )
2743 {
2744 xwid = 0;
2745 ywid = 0;
2746 if ( abs( xoff ) == 0 )
2747 fprintf( stderr, "?invalid xoff in -geometry %s\n", opt_arg );
2748 if ( abs( yoff ) == 0 )
2749 fprintf( stderr, "?invalid yoff in -geometry %s\n", opt_arg );
2750 }
2751 else
2752 {
2753 fprintf( stderr, "?invalid -geometry %s\n", opt_arg );
2754 return 1;
2755 }
2756 }
2757 //fprintf( stderr, "xwid, ywid, xoff, yoff = %d, %d, %d, %d\n", xwid, ywid, xoff, yoff );
2758 plspage( xdpi, ydpi, xwid, ywid, xoff, yoff );
2759 return 0;
2760 }
2761
2762 //--------------------------------------------------------------------------
2763 // opt_tk_file()
2764 //
2765 //! File name for plserver tk_file option
2766 //!
2767 //! @param PL_UNUSED( opt ) Not used.
2768 //! @param opt_arg Tk file name.
2769 //! @param PL_UNUSED( client_data ) Not used.
2770 //!
2771 //! returns 0.
2772 //!
2773 //--------------------------------------------------------------------------
2774
2775 static int
opt_tk_file(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2776 opt_tk_file( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2777 {
2778 if ( ( plsc->tk_file = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) ) ) == NULL )
2779 {
2780 plexit( "opt_tk_file: Insufficient memory" );
2781 }
2782
2783 strcpy( plsc->tk_file, opt_arg );
2784 return 0;
2785 }
2786
2787 //--------------------------------------------------------------------------
2788 // opt_dpi()
2789 //
2790 //! Performs appropriate action for option "dpi":
2791 //! Set dpi resolution for output device
2792 //! e.g., "-dpi 600x300", will set X dpi to 600 and Y dpi to 300
2793 //! or
2794 //! e.g., "-dpi 1200"
2795 //! Will set both X and Y dpi to 1200 dpi
2796 //!
2797 //! @param PL_UNUSED( opt ) Not used.
2798 //! @param opt_arg DPI descriptor string.
2799 //! @param PL_UNUSED( client_data ) Not used.
2800 //!
2801 //! returns 0.
2802 //!
2803 //--------------------------------------------------------------------------
2804
2805 static int
opt_dpi(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2806 opt_dpi( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2807 {
2808 char *field;
2809 PLFLT xdpi = 0., ydpi = 0.;
2810 PLINT xwid = 0, ywid = 0, xoff = 0, yoff = 0;
2811
2812 strncpy( opttmp, opt_arg, OPTMAX - 1 );
2813 opttmp[OPTMAX - 1] = '\0';
2814 if ( strchr( opttmp, 'x' ) )
2815 {
2816 field = strtok( opttmp, "x" );
2817 xdpi = atof( field );
2818 if ( xdpi == 0 )
2819 fprintf( stderr, "?invalid xdpi\n" );
2820
2821 if ( ( field = strtok( NULL, " " ) ) == NULL )
2822 return 1;
2823
2824 ydpi = atof( field );
2825 if ( ydpi == 0 )
2826 fprintf( stderr, "?invalid ydpi\n" );
2827 }
2828 else
2829 {
2830 xdpi = atof( opttmp );
2831 ydpi = xdpi;
2832 if ( xdpi == 0 )
2833 return 1;
2834 }
2835
2836 plspage( xdpi, ydpi, xwid, ywid, xoff, yoff );
2837 return 0;
2838 }
2839
2840 //--------------------------------------------------------------------------
2841 // opt_dev_compression()
2842 //
2843 //! Sets device compression
2844 //!
2845 //! @param PL_UNUSED( opt ) Not used.
2846 //! @param opt_arg Device compression (?).
2847 //! @param PL_UNUSED( client_data ) Not used.
2848 //!
2849 //! returns 0.
2850 //!
2851 //--------------------------------------------------------------------------
2852
2853 static int
opt_dev_compression(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2854 opt_dev_compression( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2855 {
2856 PLINT comp = 0;
2857
2858 comp = atoi( opt_arg );
2859 if ( comp == 0 )
2860 {
2861 fprintf( stderr, "?invalid compression\n" );
2862 return 1;
2863 }
2864 plscompression( comp );
2865
2866 return 0;
2867 }
2868
2869 //--------------------------------------------------------------------------
2870 // opt_cmap0()
2871 //
2872 //! Sets color table 0 based on a cmap0.pal file.
2873 //!
2874 //! @param PL_UNUSED( opt ) Not used.
2875 //! @param opt_arg Name of color map 0 .pal file.
2876 //! @param PL_UNUSED( client_data ) Not used.
2877 //!
2878 //! returns 0.
2879 //!
2880 //--------------------------------------------------------------------------
2881
2882 static int
opt_cmap0(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2883 opt_cmap0( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2884 {
2885 plspal0( opt_arg );
2886 return 0;
2887 }
2888
2889 //--------------------------------------------------------------------------
2890 // opt_cmap1()
2891 //
2892 //! Sets color table 1 based on a cmap1.pal file.
2893 //!
2894 //! @param PL_UNUSED( opt ) Not used.
2895 //! @param opt_arg Name of a color map 1 .pal file.
2896 //! @param PL_UNUSED( client_data ) Not used.
2897 //!
2898 //! returns 0.
2899 //!
2900 //--------------------------------------------------------------------------
2901
2902 static int
opt_cmap1(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2903 opt_cmap1( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2904 {
2905 plspal1( opt_arg, TRUE );
2906 return 0;
2907 }
2908
2909 //--------------------------------------------------------------------------
2910 // opt_locale()
2911 //
2912 //! Make PLplot portable to all LC_NUMERIC locales.
2913 //!
2914 //! @param PL_UNUSED( opt ) Not used.
2915 //! @param PL_UNUSED( opt_arg ) Not used.
2916 //! @param PL_UNUSED( client_data ) Not used.
2917 //!
2918 //! returns 0.
2919 //!
2920 //--------------------------------------------------------------------------
2921
2922 static int
opt_locale(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2923 opt_locale( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2924 {
2925 char *locale;
2926 if ( ( locale = setlocale( LC_NUMERIC, "" ) ) )
2927 {
2928 printf( "LC_NUMERIC locale set to \"%s\"\n", locale );
2929 }
2930 else
2931 {
2932 plwarn( "Could not use invalid environment (e.g., LC_ALL, LC_NUMERIC, or LANG) to set LC_NUMERIC locale. Falling back to LC_NUMERIC \"C\" locale instead.\n" );
2933 if ( !( locale = setlocale( LC_NUMERIC, "C" ) ) )
2934 {
2935 plexit( "Your platform is seriously broken. Not even a \"C\" locale could be set." );
2936 }
2937 }
2938 return 0;
2939 }
2940
2941 //--------------------------------------------------------------------------
2942 // opt_eofill()
2943 //
2944 //! For the case where the boundary of the filled region is
2945 //! self-intersecting, use the even-odd fill rule rather than the
2946 //! default nonzero fill rule.
2947 //!
2948 //! @param PL_UNUSED( opt ) Not used.
2949 //! @param PL_UNUSED( opt_arg ) Not used.
2950 //! @param PL_UNUSED( client_data ) Not used.
2951 //!
2952 //! returns 0.
2953 //!
2954 //--------------------------------------------------------------------------
2955
2956 static int
opt_eofill(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR PL_UNUSED (opt_arg),void * PL_UNUSED (client_data))2957 opt_eofill( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR PL_UNUSED( opt_arg ), void * PL_UNUSED( client_data ) )
2958 {
2959 plsc->dev_eofill = 1;
2960 if ( plsc->level > 0 )
2961 plP_state( PLSTATE_EOFILL );
2962 return 0;
2963 }
2964
2965 //--------------------------------------------------------------------------
2966 // opt_mfo()
2967 //
2968 //! Sets the filename of the PLplot metafile that will be written.
2969 //!
2970 //! @param PL_UNUSED( opt ) Not used.
2971 //! @param opt_arg Output PLplot metafile.
2972 //! @param PL_UNUSED( client_data ) Not used.
2973 //!
2974 //! returns 0.
2975 //!
2976 //--------------------------------------------------------------------------
2977
2978 static int
opt_mfo(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))2979 opt_mfo( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
2980 {
2981 if ( ( plsc->mf_outfile = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) ) ) == NULL )
2982 {
2983 plexit( "opt_mfo: Insufficient memory" );
2984 }
2985
2986 strcpy( plsc->mf_outfile, opt_arg );
2987 return 0;
2988 }
2989
2990 //--------------------------------------------------------------------------
2991 // opt_mfi()
2992 //
2993 //! Sets the filename of the PLplot metafile that will be read.
2994 //!
2995 //! @param PL_UNUSED( opt ) Not used.
2996 //! @param opt_arg Input PLplot metafile.
2997 //! @param PL_UNUSED( client_data ) Not used.
2998 //!
2999 //! returns 0.
3000 //!
3001 //--------------------------------------------------------------------------
3002
3003 static int
opt_mfi(PLCHAR_VECTOR PL_UNUSED (opt),PLCHAR_VECTOR opt_arg,void * PL_UNUSED (client_data))3004 opt_mfi( PLCHAR_VECTOR PL_UNUSED( opt ), PLCHAR_VECTOR opt_arg, void * PL_UNUSED( client_data ) )
3005 {
3006 if ( ( plsc->mf_infile = (char *) malloc( (size_t) ( 1 + strlen( opt_arg ) ) * sizeof ( char ) ) ) == NULL )
3007 {
3008 plexit( "opt_mfi: Insufficient memory" );
3009 }
3010
3011 strcpy( plsc->mf_infile, opt_arg );
3012 return 0;
3013 }
3014