1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2012-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8
9%%	header
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15/**	Process command line arguments.
16	@param	job	Job to process.
17	@return	1 on success, 0 on error.
18*/
19int
20f2lopt_process(f2l_job_t *job);
21
22#ifdef __cplusplus
23}
24#endif
25
26
27
28%%	module
29
30#include <fig2lat/fig2lat.h>
31
32
33
34$!trace-include
35
36
37
38/**	Options for the fig2lat program.
39*/
40static dk3_option_t const f2lopt_options[] = {
41  { dkT('h'), dkT("help"), 0 },
42  { dkT('v'), dkT("version"), 0 },
43  { dkT('L'), dkT("license-terms"), 0 },
44  { dkT('l'), dkT("language"), 1 },
45  { dkT('m'), dkT("make"), 0 }
46};
47
48/**	Number of options in f2lopt_options.
49*/
50static size_t const f2lopt_sz_options =
51sizeof(f2lopt_options)/sizeof(dk3_option_t);
52
53
54
55/**	Key names for key/value pairs.
56*/
57static dkChar const * f2lopt_key_names[] = {
58$!string-table macro=dkT
59#
60#   0:	Text font (similar or fig)
61#
62tf
63#
64#   1:	Text size (none or scale factor).
65#
66ts
67#
68#   2:  Compatibility for splines.
69#
70cosp
71#
72#   3:  Compatibility for arrowheads.
73#
74coah
75#
76#   4:	X-spline segments Bezier segments.
77#
78xsss
79#
80#   5:	Quadrant Bezier segments.
81#
82qbs
83#
84#   6:	Lighten look.
85#
86#   lighten
87lw
88#
89#   7:	Write debug information.
90#
91debug
92#
93#   8:	Write showpage operator at end of EPS files.
94#
95showpage
96#
97#   9:	PS level.
98#
99level
100#
101#  10:	DSC comments.
102#
103dsc
104#
105#  11:
106#
107xfig
108#
109#  12:
110#
111jfig
112#
113#  13:
114#
115winfig
116#
117#  14:	Arrowhead arc segments
118#
119ahas
120#
121#  15:	Arrowhead spline segments
122#
123ahss
124#
125#  16:	Arrowhead min segments
126#
127ahms
128#
129#  17:	Arrowhead interpolation precision
130#
131ahip
132#
133#  18:	Use smash in LaTeX output
134#
135smash
136#
137#  19:	Use mbox in LaTeX output
138#
139mbox
140#
141#  20:	Use reset@font in LaTeX output
142#
143reset@font
144#
145#  21:	Number of color digits.
146#
147codi
148#
149#  22:	TeX text size.
150#
151dcts
152#
153#  23:	Align SVG output to grid.
154#
155css
156#
157#  24:	Write SVG fragment
158#
159fragment
160#
161#  25:	Where to obtain SVG fonts
162#
163fontbase
164#
165#  26:	Group SVG object with its arrowheads
166#
167group
168#
169#  27:	Miterlimit
170#
171miterlimit
172#
173#  28:	Compatible line styles.
174#
175cols
176#
177#  29:	Use replacement fonts
178#
179replacementfonts
180#
181#  30:	Use text size for bounding box.
182#
183bbts
184#
185#  31:	Special text encoding.
186#
187ste
188#
189#  32:	Compatible fill open paths.
190#
191cofop
192#
193#  33:	X-spline arrowheads.
194#
195xsah
196#
197#  34:	Bisection iteration on X-spline arrowheads.
198#
199ahbs
200$!end
201};
202
203
204
205/**	Values for font base choices.
206*/
207static dkChar const * const f2lopt_svg_font_bases[] = {
208$!string-table macro=dkT
209none
210local
211web
212$!end
213};
214
215
216/**	Fixed keywords used by the module, not localized.
217*/
218static dkChar const * const f2lopt_kw[] = {
219$!string-table macro=dkT
220#
221#   0:	none (used to specify the font size).
222#
223none
224#
225#   1:	lighten
226#
227lighten
228#
229#   2:	automatic
230#
231auto$matic
232$!end
233};
234
235
236
237/**	Units for line width specification.
238*/
239static dkChar const * const	f2lopt_units[] = {
240$!string-table macro=dkT
241bp
242pt
243in
244mm
245cm
246$!end
247};
248
249
250/**	Language (output driver) names.
251	The order of names must correspond the the numbers defined
252	in fig2lat.ctr, see @ref fig2latdrivers.
253*/
254static dkChar const * const	f2lopt_language_names[] = {
255$!string-table	macro=dkT
256pgf
257tex
258tex.pdf
259eps.tex
260pdf.tex
261eps
262svg
263# @DRIVER@
264# Add name of new driver above this comment section
265# The order of driver names must correspond to the
266# driver names defined in fig2lat.ctr.
267$!end
268};
269
270
271
272/**	Keywords for font name decision.
273*/
274static dkChar const * f2lopt_text_font_names[] = {
275$!string-table macro=dkT
276#
277#  0: similar
278#
279similar
280#
281#  1: fig
282#
283fig
284$!end
285};
286
287
288
289/**	Set default options depending on the driver just configured.
290	@param	job	Job structure.
291*/
292static
293void
294f2lopt_set_default_options_for_language(f2l_job_t *job)
295{
296  $? "+ f2lopt_set_default_options_for_language"
297  job->ntf =    0;
298  job->nts = -1.0;
299  job->showpage = 0;
300  job->dsc = 0;
301  job->smash = 1;
302  job->mbox = 0;
303  job->resfont = 0;
304  switch(job->dr) {
305    case FIG2LAT_DRIVER_EPS_STANDALONE: {
306      job->ntf =    1;
307      job->showpage = 1;
308      job->dsc = 1;
309      job->smash = 0;
310      job->mbox = 0;
311      job->resfont = 0;
312    } break;
313    case FIG2LAT_DRIVER_SVG_STANDALONE:
314    {
315      job->smash = 0; job->mbox = 0; job->resfont = 0;
316      job->ntf =   1;
317    } break;
318    case FIG2LAT_DRIVER_TEX_FULL_PGF:
319    case FIG2LAT_DRIVER_TEX_FULL_PDF:
320    {
321      job->ntf =    1;
322    } break;
323  }
324  $? "- f2lopt_set_default_options_for_language"
325}
326
327
328
329/**	Set language.
330	@param	job	Job structure to configure.
331	@param	lstr	Language name without trailing options.
332	@return	1 on success, 0 on error.
333*/
334static
335int
336f2lopt_apply_language(f2l_job_t *job, dkChar const *lstr)
337{
338  int			 back = 0;
339  $? "+ f2lopt_apply_language \"%!ds\"", TR_STR(lstr)
340  job->dr = dk3str_array_index(f2lopt_language_names, lstr, 0);
341  if(job->dr > -1) {
342    back = 1;
343    f2lopt_set_default_options_for_language(job);
344  } else {						$? "! unknown language"
345    /* ERROR: Unknown language ... */
346    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 7, 8, lstr);
347    job->exval = FIG2LAT_EXIT_ERROR_SYNTAX; $? ". exitcode"
348  } $? "- f2lopt_apply_language %d", back
349  return back;
350}
351
352
353
354/**	Set text font.
355	@param	job	Job structure.
356	@param	vptr	Font specification (similar or fig).
357	@return	1 on success, 0 on error.
358*/
359static
360int
361f2lopt_set_text_font(f2l_job_t *job, dkChar const *vptr)
362{
363  int	 i;		/* Decision for font handling. */
364  int	 back = 0;
365  $? "+ f2lopt_set_text_font \"%!ds\"", TR_STR(vptr)
366  switch((i = dk3str_array_index(f2lopt_text_font_names, vptr, 0))) {
367    case 0: case 1: {		$? ". font selection = %d", i
368      job->ntf = i;
369      back = 1;
370    } break;
371    default: {			$? "! wrong font selection"
372      /* ERROR: No such text font selection! */
373      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 9, 10, vptr);
374    } break;
375  }
376  $? "- f2lopt_set_text_font %d", back
377  return back;
378}
379
380
381
382/**	Set text size.
383	@param	job	Job structure.
384	@param	vptr	Text size as string (none or scale factor).
385	@return	1 on success, 0 on error.
386*/
387static
388int
389f2lopt_set_text_size(f2l_job_t *job, dkChar const *vptr)
390{
391  double	 d;		/* Font size factor. */
392  int		 back = 0;
393  $? "+ f2lopt_set_text_font \"%!ds\"", vptr
394  if(dk3str_cmp(vptr, f2lopt_kw[0]) == 0) {		$? ". no size"
395    job->nts = -1.0;
396    back = 1;
397  } else {
398#if VERSION_BEFORE_20140716
399    if(dk3sf_sscanf3(vptr, dkT("%lf"), &d) == 1)
400#else
401    if (0 != dk3ma_d_from_string(&d, vptr, NULL))
402#endif
403    {	$? ". size %lg", d
404      job->nts = d;
405      back = 1;
406    } else {						$? "! invalid size"
407      /* ERROR: Invalid font size specification! */
408      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 11, 12, vptr);
409    }
410  }
411  $? "- f2lopt_set_text_font %d", back
412  return back;
413}
414
415
416
417/**	Read a size_t from text.
418	@param	dptr	Pointer to destination variable.
419	@param	vptr	Source text.
420	@param	job	Job structure.
421	@return	1 on success, 0 on error.
422*/
423static
424int
425f2lopt_read_size_t(size_t *dptr, dkChar const *vptr, f2l_job_t *job)
426{
427#if VERSION_BEFORE_20140809
428  unsigned	u;		/* Conversion result. */
429  int	 	back = 0;
430  if(1 == dk3sf_sscanf3(vptr, dkT("%u"), &u)) {
431    *dptr = (size_t)u;
432    back = 1;
433    if((unsigned)(*dptr) != u) {
434      back = 0;
435      /* ERROR: Range overflow */
436      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 13, 14, vptr);
437    }
438  } else {
439    /* ERRROR: Not a number! */
440    dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, vptr);
441  }
442  return back;
443#else
444  dk3_um_t	um	= DK3_UM_0;
445  int		back	= 0;
446  int		mec	= 0;
447
448  if (dk3ma_um_from_string(&um, vptr, NULL)) {		/* OK: Number */
449    *dptr = dk3ma_um_to_sz(um, &mec);
450    if (0 == mec) {				/* OK: Converted */
451      back = 1;
452    } else {					/* Overflow */
453      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 13, 14, vptr);
454    }
455  } else {					/* Not a number */
456    dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, vptr);
457  }
458  return back;
459#endif
460}
461
462
463
464/**	Read double value from string to configuration variable.
465	@param	job	Job structure.
466	@param	dvar	Pointer to destination variable.
467	@param	src	Source text.
468	@param	min	Minimum value.
469	@param	max	Maximum value.
470	@param	tp	Type (1=check minimum, 2=positive number + check max).
471	@param	optnr	Option index, used for error messages.
472	@return	1 on success, 0 on error.
473*/
474static
475int
476f2lopt_read_double(
477  f2l_job_t		*job,
478  double		*dvar,
479  dkChar const		*src,
480  double		 min,
481  double		 max,
482  int			 tp,
483  size_t		 optnr
484)
485{
486  dkChar	buf[128];	/* Conversion buffer. */
487  double	dval	= 0.0;	/* Conversion result. */
488  int		back	= 0;
489  if(src) {
490#if VERSION_BEFORE_20140716
491    if(dk3sf_sscanf3(src, dkT("%lg"), &dval) == 1)
492#else
493    if (0 != dk3ma_d_from_string(&dval, src, NULL))
494#endif
495    {
496      switch(tp) {
497        case 1: {
498	  if(dval >= min) {
499	    *dvar = dval;
500	    back = 1;
501	  } else {
502	    /* ERROR: Minimum for option ... is ...! */
503#if VERSION_BEFORE_20140716
504	    dk3sf_sprintf3(buf, dkT("%g"), min);
505	    dk3app_log_5(
506	      job->app, DK3_LL_ERROR, job->msg, 15, 16, 17, src, buf
507	    );
508#else
509	    if (0 != dk3ma_d_to_string(buf, DK3_SIZEOF(buf,dkChar), min)) {
510	      dk3app_log_5(
511	        job->app, DK3_LL_ERROR, job->msg, 15, 16, 17, src, buf
512	      );
513	    }
514#endif
515	  }
516	} break;
517	case 2: {
518	  if(dval > 0) {
519	    if(dval < max) {
520	      *dvar = dval;
521	      back = 1;
522	    } else {
523	      /* ERROR: Maximum for option ... is ...! */
524#if VERSION_BEFORE_20140716
525	      dk3sf_sprintf3(buf, dkT("%g"), max);
526	      dk3app_log_5(job->app,DK3_LL_ERROR,job->msg,15,18,17,src,buf);
527#else
528	      if (0 != dk3ma_d_to_string(buf, DK3_SIZEOF(buf,dkChar), max)) {
529	        dk3app_log_5(job->app,DK3_LL_ERROR,job->msg,15,18,17,src,buf);
530	      }
531#endif
532	    }
533	  } else {
534	    /* ERROR: Option ... requires positive value! */
535	    dk3app_log_3(
536	      job->app, DK3_LL_ERROR, job->msg, 19, 20,
537	      f2lopt_key_names[optnr]
538	    );
539	  }
540	} break;
541      }
542    } else {
543      /* ERROR: Option argument is not numeric! */
544      dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, src);
545    }
546  } else {
547    /* ERROR: Option requires an argument. */
548    dk3app_log_3(
549      job->app, DK3_LL_ERROR, job->msg, 21, 22,
550      f2lopt_key_names[optnr]
551    );
552  }
553  return back;
554}
555
556
557/**	Process one option.
558	@param	job	Job structure to configure.
559	@param	str	Key=value text.
560	@return	1 on success, 0 on error.
561*/
562static
563int
564f2lopt_apply_option(f2l_job_t *job, dkChar const *str)
565{
566  dkChar		 bu[1024];	/* Private copy of str. */
567  dkChar		*kptr;		/* Key pointer. */
568  dkChar		*vptr;		/* Value pointer. */
569  int			 back = 0;
570  $? "+ f2lopt_apply_option \"%!ds\"", TR_STR(str)
571  if(dk3str_len(str) < DK3_SIZEOF(bu,dkChar)) {
572    dk3str_cpy_not_overlapped(bu, str);
573    kptr = dk3str_start(bu, NULL);
574    if(kptr) {
575      vptr = dk3str_chr(kptr, dkT('='));
576      if(vptr) {
577        *(vptr++) = dkT('\0');
578	vptr = dk3str_start(vptr, NULL);
579      }
580      switch(dk3str_array_index(f2lopt_key_names, kptr, 0)) {
581        case 0: {	$? ". tf"
582	  if(vptr) {
583	    back = f2lopt_set_text_font(job, vptr);
584	  } else {
585	    /* ERRROR: Key needs an argument! */
586	    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 21, 22, kptr);
587	  }
588	} break;
589	case 1: {	$? ". ts"
590	  if(vptr) {
591	    back = f2lopt_set_text_size(job, vptr);
592	  } else {
593	    job->nts = -1.0;
594	    back = 1;
595	  }
596	} break;
597	case 2: {	$? ". cosp"
598	  if(vptr) {
599	    if(dk3str_is_bool(vptr)) {
600	      job->cosp = (dk3str_is_on(vptr) ? 1 : 0);
601	      back = 1;
602	    } else {
603	      /* ERROR: Not a boolean */
604	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
605	    }
606	  } else {
607	    job->cosp = 1; back = 1;
608	  }
609	} break;
610	case 3: {	$? ". coah"
611	  if(vptr) {
612	    if(dk3str_is_bool(vptr)) {
613	      job->coah = (dk3str_is_on(vptr) ? 1 : 0);
614	      back = 1;
615	    } else {
616	      /* ERROR: Not a boolean */
617	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
618	    }
619	  } else {
620	    job->coah = 1; back = 1;
621	  }
622	} break;
623	case 4: {	$? ". xssbs"
624	  if(vptr) {
625	    back = f2lopt_read_size_t(&(job->xssbs), vptr, job);
626	  } else {
627	    /* ERROR: Argument required! */
628            dk3app_log_i3(job->app, DK3_LL_ERROR, 133, 134, kptr);
629	  }
630	} break;
631	case 5: {	$? ". qbs"
632	  if(vptr) {
633	    back = f2lopt_read_size_t(&(job->qbs), vptr, job);
634	  } else {
635	    /* ERROR: Argument required! */
636	    dk3app_log_i3(job->app, DK3_LL_ERROR, 133, 134, kptr);
637	  }
638	} break;
639	case 6: {
640#if VERSION_BEFORE_20140330
641	  if(vptr) {
642	    if(dk3str_is_bool(vptr)) {
643	      job->lighten = ((dk3str_is_on(vptr)) ? 1 : 0);
644	      back = 1;
645	    } else {
646	      /* ERROR: Not a boolean value! */
647	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
648	    }
649	  } else {
650	    back = 1;
651	    job->lighten = 1;
652	  }
653#else
654	  job->lwbp = 0.9;
655	  job->lwauto = 0;
656	  if (vptr) {
657	    double	x;
658	    size_t	vplen;
659	    vplen = dk3str_len(vptr);
660	    if (0 == dk3str_cmp(f2lopt_kw[1], vptr)) {
661	      job->lwbp = 0.45;
662	      job->lwauto = 0;
663	      back = 1;
664	    } else {
665	      if (dk3str_is_abbr(vptr,f2lopt_kw[2],dkT('$'), 0)) {
666	        job->lwauto = 1;
667		back = 1;
668	      } else {
669	        if (2 < vplen) {
670		  switch (dk3str_array_index(f2lopt_units, &(vptr[vplen-2]), 0))
671		  {
672		    case 0: {	/* bp */
673		      vptr[vplen - 2] = dkT('\0');
674#if VERSION_BEFORE_20140716
675		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
676#else
677		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
678#endif
679		      {
680		        job->lwbp = x;
681			back = 1;
682		      } else {
683		        /* ERROR: Failed to process */
684			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
685		      }
686		    } break;
687		    case 1: {	/* pt */
688		      vptr[vplen - 2] = dkT('\0');
689#if VERSION_BEFORE_20140716
690		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
691#else
692		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
693#endif
694		      {
695		        job->lwbp = x * 72.0 / 72.27;
696			back = 1;
697		      } else {
698		        /* ERROR: Failed to process */
699			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
700		      }
701		    } break;
702		    case 2: {	/* in */
703		      vptr[vplen - 2] = dkT('\0');
704#if VERSION_BEFORE_20140716
705		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
706#else
707		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
708#endif
709		      {
710		        job->lwbp = x * 72.0;
711			back = 1;
712		      } else {
713		        /* ERROR: Failed to process */
714			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
715		      }
716		    } break;
717		    case 3: {	/* mm */
718		      vptr[vplen - 2] = dkT('\0');
719#if VERSION_BEFORE_20140716
720		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
721#else
722		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
723#endif
724		      {
725		        job->lwbp = x * 72.0 / 25.4;
726			back = 1;
727		      } else {
728		        /* ERROR: Failed to process */
729			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
730		      }
731		    } break;
732		    case 4: {	/* cm */
733		      vptr[vplen - 2] = dkT('\0');
734#if VERSION_BEFORE_20140716
735		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
736#else
737		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
738#endif
739		      {
740		        job->lwbp = x * 72.0 / 2.54;
741			back = 1;
742		      } else {
743		        /* ERROR: Failed to process */
744			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
745		      }
746		    } break;
747		    default: {
748#if VERSION_BEFORE_20140716
749		      if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
750#else
751		      if (0 != dk3ma_d_from_string(&x, vptr, NULL))
752#endif
753		      {
754		        job->lwbp = x;
755			back = 1;
756		      } else {
757		        /* ERROR: Failed to process */
758			dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
759		      }
760		    } break;
761		  }
762		} else {
763#if VERSION_BEFORE_20140716
764		  if (dk3sf_sscanf3(vptr, dkT("%lg"), &x) == 1)
765#else
766		  if (0 != dk3ma_d_from_string(&x, vptr, NULL))
767#endif
768		  {
769		    job->lwbp = x;
770		    back = 1;
771		  } else {
772		    /* ERROR: Failed to process */
773		    dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,45,46,vptr);
774		  }
775		}
776	      }
777	    }
778	  } else {
779	    job->lwbp = 0.9;
780	    job->lwauto = 1;
781	    back = 1;
782	    if (job->lwbp < 0.001) {
783	      job->lwbp = 0.001;
784	    }
785	  } $? ". lwbp=%lg lwauto=%d", job->lwbp, job->lwauto
786#endif
787	} break;
788	case 7: {
789	  if(vptr) {
790	    if(dk3str_is_bool(vptr)) {
791	      back = 1;
792	      job->debug = ((dk3str_is_on(vptr)) ? 1 : 0);
793	    } else {
794	      /* ERROR: Not a boolean value! */
795	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
796	    }
797	  } else {
798	    back = 1;
799	    job->debug = 1;
800	  }
801	} break;
802	case 8: {
803	  if(vptr) {
804	    if(dk3str_is_bool(vptr)) {
805	      job->showpage = ((dk3str_is_on(vptr)) ? 1 : 0);
806	      back = 1;
807	    } else {
808	      /* ERROR: Not a boolean value! */
809	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
810	    }
811	  } else {
812	    job->showpage = 1;
813	    back = 1;
814	  }
815	} break;
816	case 9: {
817	  if(vptr) {
818	    int i;
819#if VERSION_BEFORE_20140716
820	    if(dk3sf_sscanf3(vptr, dkT("%d"), &i) == 1)
821#else
822	    if (0 != dk3ma_i_from_string(&i, vptr, NULL))
823#endif
824	    {
825	      if((i >= 2) && (i <= 3)) {
826	        job->pslevel = i;
827	      } else {
828	        /* ERROR: Must be 2 or 3! */
829		dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 33);
830	      }
831	    } else {
832	      /* ERROR: Argument not a number! */
833	      dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, vptr);
834	    }
835	  } else {
836	    /* ERROR: Argument required! */
837	    dk3app_log_i3(job->app, DK3_LL_ERROR, 133, 134, kptr);
838	  }
839	} break;
840	case 10: {
841	  if(vptr) {
842	    if(dk3str_is_bool(vptr)) {
843	      job->dsc = ((dk3str_is_on(vptr)) ? 1 : 0);
844	      back = 1;
845	    } else {
846	      /* ERROR: Not a boolean argument. */
847	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
848	    }
849	  } else {
850	    job->dsc = 1;
851	    back = 1;
852	  }
853	} break;
854	case 11: {
855	  if(DK3_FIG_SRCTYPE_UNKNOWN == job->srctype) {
856	    job->srctype = DK3_FIG_SRCTYPE_XFIG;
857	    back = 1;
858	  } else {
859	    /* ERROR: Source type already set! */
860	    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 23);
861	  }
862	} break;
863	case 12: {
864	  if(DK3_FIG_SRCTYPE_UNKNOWN == job->srctype) {
865	    job->srctype = DK3_FIG_SRCTYPE_JFIG;
866	    back = 1;
867	  } else {
868	    /* ERROR: Source type already set! */
869	    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 23);
870	  }
871	} break;
872	case 13: {
873	  if(DK3_FIG_SRCTYPE_UNKNOWN == job->srctype) {
874	    job->srctype = DK3_FIG_SRCTYPE_WINFIG;
875	    back = 1;
876	  } else {
877	    /* ERROR: Source type already set! */
878	    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 23);
879	  }
880	} break;
881	case 14: {	/* Arrowhead arc segments */
882	  back = f2lopt_read_double(job,&(job->arcspp),vptr,2.0,-1.0,1,14);
883	} break;
884	case 15: {	/* Arrowhead spline segments */
885	  back = f2lopt_read_double(job,&(job->splspp),vptr,2.0,-1.0,1,15);
886	} break;
887	case 16: {	/* Arrowhead min segments. */
888	  unsigned u = 2;
889	  if(vptr) {
890#if VERSION_BEFORE_20140716
891	    if(dk3sf_sscanf3(vptr, dkT("%u"), &u) == 1)
892#else
893	    if (0 != dk3ma_ui_from_string(&u, vptr, NULL))
894#endif
895	    {
896	      if(2 <= u) {
897	        job->minspp = (size_t)u;
898		back = 1;
899	      } else {
900	        /* Warning: Must be at least 2! */
901		job->minspp = 2;
902		dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 34);
903		back = 1;
904	      }
905	    } else {
906	      /* ERROR: Argument is not numeric */
907	      dk3app_log_i3(job->app, DK3_LL_ERROR, 141, 142, vptr);
908	    }
909	  } else {
910	    /* ERROR: Option requires an argument! */
911	    dk3app_log_i3(job->app, DK3_LL_ERROR, 133, 134, kptr);
912	  }
913	} break;
914	case 17: {	/* Arrowhead interpolation precision. */
915	  back = f2lopt_read_double(job,&(job->xsprec),vptr,0.0,0.1,2,17);
916	} break;
917	case 18: {	/* smash */
918	  if(vptr) {
919	    if(dk3str_is_bool(vptr)) {
920	      job->smash = ((dk3str_is_on(vptr)) ? 1 : 0);
921	      back = 1;
922	    } else {
923	      /* ERROR: Option requires boolean argument */
924	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
925	    }
926	  } else {
927	    job->smash = 1;
928	    back = 1;
929	  }
930	} break;
931	case 19: {	/* mbox */
932	  if(vptr) {
933	    if(dk3str_is_bool(vptr)) {
934	      job->mbox = ((dk3str_is_on(vptr)) ? 1 : 0);
935	      back = 1;
936	    } else {
937	      /* ERROR: Option requires boolean argument! */
938	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
939	    }
940	  } else {
941	    job->mbox = 1;
942	    back = 1;
943	  }
944	} break;
945	case 20: {
946	  if(vptr) {
947	    if(dk3str_is_bool(vptr)) {
948	      job->resfont = ((dk3str_is_on(vptr)) ? 1 : 0);
949	      back = 1;
950	    } else {
951	      /* ERROR: Option requires boolean argument! */
952	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
953	    }
954	  } else {
955	    job->resfont = 1;
956	    back = 1;
957	  }
958	} break;
959	case 21: {
960	  if(vptr) {
961	    unsigned u;
962#if VERSION_BEFORE_20140716
963	    if(dk3sf_sscanf3(vptr, dkT("%u"), &u) == 1)
964#else
965	    if (0 != dk3ma_ui_from_string(&u, vptr, NULL))
966#endif
967	    {
968	      job->codi = (size_t)u;
969	      back = 1;
970	    } else {
971	      /* ERROR: Option requires an unsigned numeric argument! */
972	      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 24, 25, kptr);
973	    }
974	  } else {
975	    job->codi = 0;
976	    back = 1;
977	  }
978	} break;
979	case 22: {
980	  if(vptr) {
981	    double d;
982#if VERSION_BEFORE_20140716
983	    if(dk3sf_sscanf3(vptr, dkT("%lg"), &d) == 1)
984#else
985	    if (0 != dk3ma_d_from_string(&d, vptr, NULL))
986#endif
987	    {
988	      if(d > 0.0) {
989	        job->tts = d; back = 1;
990	      } else {
991	        /* ERROR: Cannot handle negative font size! */
992		dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 26);
993	      }
994	    } else {
995	      /* ERROR: Option requires a floating point number arg! */
996	      dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 12, 22, kptr);
997	    }
998	  } else {
999	    job->tts = 12.0; back = 1;
1000	  }
1001	} break;
1002	case 23: {
1003	  if(vptr) {
1004	    if(dk3str_is_bool(vptr)) {
1005	      job->css = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1006	    } else {
1007	      /* ERROR: Option requires boolean argument! */
1008	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1009	    }
1010	  } else {
1011	    job->css = 1; back = 1;
1012	  }
1013	} break;
1014	case 24: {
1015	  if(vptr) {
1016	    if(dk3str_is_bool(vptr)) {
1017	      job->fragment = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1018	    } else {
1019	      /* ERROR: Option requires boolean argument! */
1020	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1021	    }
1022	  } else {
1023	    job->fragment = 1; back = 1;
1024	  }
1025	} break;
1026	case 25: {
1027	  if(vptr) {
1028	    job->svgfontbase = dk3str_array_index(f2lopt_svg_font_bases, vptr, 0);
1029	    if(0 <= job->svgfontbase) {
1030	      back = 1;
1031	    } else {
1032	      /* ##### ERROR: Illegal font base name! */
1033	    }
1034	  } else {
1035	    job->svgfontbase = 0; back = 1;
1036	  }
1037	} break;
1038	case 26: {
1039	  if(vptr) {
1040	    if(dk3str_is_bool(vptr)) {
1041	      job->group = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1042	    } else {
1043	      /* ERROR: Option requires boolean argument! */
1044	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1045	    }
1046	  } else {
1047	    job->group = 1; back = 1;
1048	  }
1049	} break;
1050	case 27: {
1051	  if(vptr) {
1052	    if(dk3str_is_bool(vptr)) {
1053	      job->miterlim = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1054	    } else {
1055	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1056	    }
1057	  } else {
1058	    job->miterlim = 1; back = 1;
1059	  }
1060	} break;
1061	case 28: {
1062	  if(vptr) {
1063	    if(dk3str_is_bool(vptr)) {
1064	      job->cols = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1065	    } else {
1066	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1067	    }
1068	  } else {
1069	    job->cols = 1; back = 1;
1070	  }
1071	} break;
1072	case 29: {
1073	  if(vptr) {
1074	    if(dk3str_is_bool(vptr)) {
1075	      job->otherfonts = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1076	    } else {
1077	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1078	    }
1079	  } else {
1080	    job->otherfonts = 1; back = 1;
1081	  }
1082	} break;
1083	case 30: {
1084	  if(vptr) {
1085	    if(dk3str_is_bool(vptr)) {
1086	      job->bbts = ((dk3str_is_on(vptr)) ? 1 : 0); back = 1;
1087	    } else {
1088	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1089	    }
1090	  } else {
1091	    job->bbts = 1; back = 1;
1092	  }
1093	} break;
1094	case 31: {
1095	  int enc;
1096	  if(vptr) {
1097	    enc = dk3enc_get_text_encoding_app(vptr, job->app);
1098	  } else {
1099	    if(DK3_ENCODING_UTF8 == dk3app_get_encoding(job->app)) {
1100	      enc = DK3_ENCODING_PLAIN;
1101	    } else {
1102	      enc = DK3_ENCODING_UTF8;
1103	    }
1104	  }
1105	  back = 1;
1106	  switch(enc) {
1107	    case DK3_ENCODING_UTF8: {
1108	      job->stu8 = 1;
1109	    } break;
1110	    case DK3_ENCODING_PLAIN: {
1111	      job->stu8 = 0;
1112	    } break;
1113	    default: {
1114	      job->stu8 = 0;
1115	      /* ##### WARNING Only ascii and utf-8 allowed. */
1116	    } break;
1117	  }
1118	} break;
1119	case 32: {
1120	  if(vptr) {
1121	    if(dk3str_is_bool(vptr)) {
1122	      job->cofop = ((dk3str_is_on(vptr)) ? 1 : 0);
1123	      back = 1;
1124	    } else {
1125	      /* ERROR: Not a boolean! */
1126	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1127	    }
1128	  } else {
1129	    job->cofop = 1;
1130	    back = 1;
1131	  }
1132	} break;
1133	case 33: {
1134	  if (vptr) {
1135	    if(dk3str_is_bool(vptr)) {
1136	      job->xsah = ((dk3str_is_on(vptr)) ? 1 : 0);
1137	      back = 1;
1138	    } else {
1139	      /* ERROR: Not a boolean! */
1140	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1141	    }
1142	  } else {
1143	    job->xsah = 1;
1144	    back = 1;
1145	  }
1146	} break;
1147	case 34: {
1148	  if (vptr) {
1149	    if (dk3str_is_bool(vptr)) {
1150	      job->ahbs = ((dk3str_is_on(vptr)) ? 1 : 0);
1151	      back = 1;
1152	    } else {
1153	      /* ERROR: Not a boolean! */
1154	      dk3app_log_i3(job->app, DK3_LL_ERROR, 146, 147, kptr);
1155	    }
1156	  } else {
1157	    job->ahbs = 1;
1158	    back = 1;
1159	  }
1160	} break;
1161	default: {
1162	  /* ERROR: Unknown key name! */
1163	  dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 27, 28, kptr);
1164	} break;
1165      }
1166    } else {					$? "! empty option"
1167      back = 1;
1168    }
1169    if(!(back)) {
1170      job->exval = FIG2LAT_EXIT_ERROR_SYNTAX; $? ". exitcode"
1171    }
1172  } else {
1173    /* ERROR: Option ... too long! */
1174    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 29, 30, str);
1175    job->exval = FIG2LAT_EXIT_ERROR_SYNTAX; $? ". exitcode"
1176  } $? "- f2lopt_apply_option %d", back
1177  return back;
1178}
1179
1180
1181
1182/**	Set language, apply options if any.
1183	@param	job	Job structure to set up.
1184	@param	optarg	Language, optionally with further options.
1185	@return	1 on success, 0 on error.
1186*/
1187static
1188int
1189f2lopt_set_language(f2l_job_t *job, dkChar const *optarg)
1190{
1191  dkChar		 bu[1024];	/* Private copy of optarg. */
1192  dkChar		*pc;		/* Current string. */
1193  dkChar		*pn;		/* Next string. */
1194  int			 back = 0;
1195  $? "+ f2lopt_set_language \"%!ds\"", TR_STR(optarg)
1196  if(dk3str_len(optarg) < DK3_SIZEOF(bu,dkChar)) {
1197    dk3str_cpy_not_overlapped(bu, optarg);
1198    pc = dk3str_chr(bu, dkT(','));
1199    if(pc) {
1200      *(pc++) = dkT('\0');
1201      pc = dk3str_start(pc, NULL);
1202    }
1203    if(f2lopt_apply_language(job, bu)) {
1204      back = 1;
1205      while(pc) {		$? ". pc = \"%!ds\"", TR_STR(pc)
1206        pn = dk3str_chr(pc, dkT(','));
1207	if(pn) { *(pn++) = dkT('\0'); pn = dk3str_start(pn, NULL); }
1208	if(!f2lopt_apply_option(job, pc)) {
1209	  back = 0;		$? "! f2lopt_apply_option"
1210	  pn = NULL;
1211	}
1212	pc = pn;
1213      }
1214    }
1215  } else {
1216    /* ERROR: Option argument too long! */
1217    dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 31, 30, optarg);
1218  } $? "- f2lopt_set_language %d", back
1219  return back;
1220}
1221
1222
1223
1224int
1225f2lopt_process(f2l_job_t *job)
1226{
1227  dkChar const		*optarg;	/* Option argument. */
1228  int			 back = 0;
1229  int			 i;		/* Current file name. */
1230  $? "+ f2lopt_process"
1231  job->opt = dk3opt_open_from_app(
1232    f2lopt_options, f2lopt_sz_options,
1233    dkT('o'), dkT("option"),
1234    job->app
1235  );
1236  if(job->opt) {					$? ". option set"
1237    if(0 == dk3opt_get_error_code(job->opt)) {		$? ". error check"
1238      back = 1;
1239      if(dk3opt_is_set(job->opt, dkT('h'))) {
1240        job->cmd |= DK3_APP_CMD_HELP;
1241      }
1242      if(dk3opt_is_set(job->opt, dkT('v'))) {
1243        job->cmd |= DK3_APP_CMD_VERSION;
1244      }
1245      if(dk3opt_is_set(job->opt, dkT('L'))) {
1246        job->cmd |= DK3_APP_CMD_LICENSE;
1247      }
1248      if(0 == job->cmd) {
1249        if(dk3opt_is_set(job->opt, dkT('m'))) {
1250	  job->mm = 1;
1251	}
1252        if(dk3opt_is_set(job->opt, dkT('l'))) {
1253	  optarg = dk3opt_get_short_arg(job->opt, dkT('l'));
1254	  if(optarg) {					$? ". optarg"
1255	    if(f2lopt_set_language(job, optarg)) {
1256	      for(i = 0; i < dk3opt_get_num_fo(job->opt); i++) {
1257	        optarg = dk3opt_get_fo(job->opt, i);
1258		if(optarg) {
1259		  if(!f2lopt_apply_option(job, optarg)) {
1260		    back = 0;
1261		  }
1262		}
1263	      }
1264	    } else {
1265	      back = 0;
1266	    }
1267	  } else {					$? "! optarg"
1268	    back = 0;
1269	    /* ERROR: Option requires an argument! */
1270	    dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 32);
1271	  }
1272	} else {
1273	}
1274      }
1275      /*	Automatically calculate line width in points
1276      		from TeX text size.
1277      */
1278      if (job->lwauto) {
1279        job->lwbp = 0.4 * 72.0 * job->tts / (10 * 72.27);
1280	$? ". lwbp=%lg", job->lwbp
1281      }
1282    } else {						$? "! error check"
1283    }
1284  } else {						$? "! option set"
1285    job->exval = FIG2LAT_EXIT_ERROR_SYSTEM; $? ". exitcode"
1286  } $? "- f2lopt_process %d", back
1287  return back;
1288}
1289
1290
1291