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