1 /* Option processing for xcftools -*- C -*-
2  *
3  * This file was written by Julien Jorge <julien.jorge@gamned.org>
4  * It is hereby in the public domain.
5  *
6  * In jurisdictions that do not recognise grants of copyright to the
7  * public domain: I, the author and (presumably, in those jurisdictions)
8  * copyright holder, hereby permit anyone to distribute and use this code,
9  * in source code or binary form, with or without modifications. This
10  * permission is world-wide and irrevocable.
11  *
12  * Of course, I will not be liable for any errors or shortcomings in the
13  * code, since I give it away without asking any compenstations.
14  *
15  * If you use or distribute this code, I would appreciate receiving
16  * credit for writing it, in whichever way you find proper and customary.
17  */
18 #include "options.h"
19 
20 #include "version.h"
21 
22 #include <string.h>
23 
24 /*----------------------------------------------------------------------------*/
option_show_version(const char * app_name)25 void option_show_version( const char* app_name )
26 {
27   printf( "%s - %s\n", app_name, PACKAGE_STRING );
28 } // option_show_version()
29 
30 /*----------------------------------------------------------------------------*/
option_set_verbose(struct ProcessControl * p)31 void option_set_verbose( struct ProcessControl* p )
32 {
33   p->verboseFlag = 1;
34 } // option_set_verbose()
35 
36 /*----------------------------------------------------------------------------*/
option_set_bzip(struct ProcessControl * p)37 void option_set_bzip( struct ProcessControl* p )
38 {
39   p->unzipper = "bzcat";
40 } // option_set_bzip()
41 
42 /*----------------------------------------------------------------------------*/
option_set_gzip(struct ProcessControl * p)43 void option_set_gzip( struct ProcessControl* p )
44 {
45   p->unzipper = "zcat";
46 } // option_set_gzip()
47 
48 /*----------------------------------------------------------------------------*/
option_set_unpack(struct ProcessControl * p,char * command)49 void option_set_unpack( struct ProcessControl* p, char* command )
50 {
51   p->unzipper = command;
52 } // option_set_unpack()
53 
54 /*----------------------------------------------------------------------------*/
option_set_path_separator(struct ProcessControl * p,char * separator)55 void option_set_path_separator( struct ProcessControl* p, char* separator )
56 {
57   p->pathSeparator = separator;
58 } // option_set_path_separator()
59 
60 /*----------------------------------------------------------------------------*/
option_set_utf8(struct ProcessControl * p)61 void option_set_utf8( struct ProcessControl* p )
62 {
63   p->use_utf8 = 1;
64 } // option_set_utf8()
65 
66 /*----------------------------------------------------------------------------*/
option_set_output(struct FlattenSpec * flatspec,char * filename)67 void option_set_output( struct FlattenSpec* flatspec, char* filename )
68 {
69   flatspec->output_filename = filename;
70 } // option_set_output()
71 
72 /*----------------------------------------------------------------------------*/
option_set_alpha(struct FlattenSpec * flatspec,char * filename)73 void option_set_alpha( struct FlattenSpec* flatspec, char* filename )
74 {
75   flatspec->transmap_filename = filename;
76 } // option_set_alpha()
77 
78 /*----------------------------------------------------------------------------*/
option_set_background(struct FlattenSpec * flatspec,char * color)79 void option_set_background( struct FlattenSpec* flatspec, char* color )
80 {
81   unsigned r,g,b ;
82   unsigned long hex ;
83   int met = 0 ;
84   if( color[0] == '#' )
85     sscanf(color+1,"%lx%n",&hex,&met);
86 
87   if( (met == 3) && (strlen(color) == 4) ) {
88     r = ((hex >> 8) & 0xF) * 0x11 ;
89     g = ((hex >> 4) & 0xF) * 0x11 ;
90     b = ((hex >> 0) & 0xF) * 0x11 ;
91   } else if( met == 6 && strlen(color) == 7 ) {
92     r = ((hex >> 16) & 0xFF) ;
93     g = ((hex >> 8) & 0xFF) ;
94     b = ((hex >> 0) & 0xFF) ;
95   } else if( strcasecmp(color,"black") == 0 )
96     r = g = b = 0 ;
97   else if( strcasecmp(color,"white") == 0 )
98     r = g = b = 255 ;
99   else {
100     const char *filenames[] =  { "/etc/X11/rgb.txt",
101                                  "/usr/lib/X11/rgb.txt",
102                                  "/usr/share/X11/rgb.txt",
103                                  NULL };
104     const char **fnp ;
105     r = (unsigned)-1 ;
106     int any = 0 ;
107     for( fnp = filenames; r == (unsigned)-1 && fnp && *fnp; fnp++ ) {
108       FILE *colortable = fopen(*fnp,"rt");
109       if( colortable ) {
110         any = 1 ;
111         int clen ;
112         char colorbuf[80] ;
113         do {
114           if( !fgets(colorbuf,sizeof colorbuf,colortable) ) {
115             r = (unsigned)-1 ;
116             break ;
117           }
118           clen = strlen(colorbuf);
119           while( clen && isspace(colorbuf[clen-1]) )
120             clen-- ;
121           colorbuf[clen] = '\0' ;
122           clen = 0 ;
123           sscanf(colorbuf," %u %u %u %n",&r,&g,&b,&clen);
124         } while( clen == 0 || strcasecmp(colorbuf+clen,color) != 0 );
125         fclose(colortable) ;
126       }
127     }
128     if( !any ) {
129       fprintf( stderr, gettext("Could not find X11 color database\n") );
130     }
131   }
132 
133   if( r == (unsigned)-1 )
134     FatalGeneric
135       ( 20, gettext("Unknown background color '%s'"), color );
136 
137   flatspec->default_pixel = ((rgba)255 << ALPHA_SHIFT)
138     + ((rgba)r << RED_SHIFT)
139     + ((rgba)g << GREEN_SHIFT)
140     + ((rgba)b << BLUE_SHIFT);
141 } // option_set_background()
142 
143 /*----------------------------------------------------------------------------*/
option_set_checkered_background(struct FlattenSpec * flatspec)144 void option_set_checkered_background
145 ( struct FlattenSpec* flatspec )
146 {
147   flatspec->default_pixel = CHECKERED_BACKGROUND;
148 } // option_set_checkered_background()
149 
150 /*----------------------------------------------------------------------------*/
option_set_force_alpha(struct FlattenSpec * flatspec)151 void option_set_force_alpha( struct FlattenSpec* flatspec )
152 {
153   flatspec->default_pixel = FORCE_ALPHA_CHANNEL ;
154 } // option_set_force_alpha()
155 
156 /*----------------------------------------------------------------------------*/
option_set_color(struct FlattenSpec * flatspec)157 void option_set_color( struct FlattenSpec* flatspec )
158 {
159   flatspec->out_color_mode = COLOR_RGB ;
160 } // option_set_color()
161 
162 /*----------------------------------------------------------------------------*/
option_set_gray(struct FlattenSpec * flatspec)163 void option_set_gray( struct FlattenSpec* flatspec )
164 {
165   flatspec->out_color_mode = COLOR_GRAY ;
166 } // option_set_gray()
167 
168 /*----------------------------------------------------------------------------*/
option_set_mono(struct FlattenSpec * flatspec)169 void option_set_mono( struct FlattenSpec* flatspec )
170 {
171   flatspec->out_color_mode = COLOR_MONO ;
172 } // option_set_mono()
173 
174 /*----------------------------------------------------------------------------*/
option_set_pnm(struct FlattenSpec * flatspec)175 void option_set_pnm( struct FlattenSpec* flatspec )
176 {
177   flatspec->out_color_mode = COLOR_BY_CONTENTS ;
178 } // option_set_pnm()
179 
180 /*----------------------------------------------------------------------------*/
option_set_truecolor(struct FlattenSpec * flatspec)181 void option_set_truecolor( struct FlattenSpec* flatspec )
182 {
183   flatspec->gimpish_indexed = 0 ;
184 } // option_set_truecolor()
185 
186 /*----------------------------------------------------------------------------*/
option_set_for_gif(struct FlattenSpec * flatspec)187 void option_set_for_gif( struct FlattenSpec* flatspec )
188 {
189   flatspec->partial_transparency_mode = FORBID_PARTIAL_TRANSPARENCY ;
190 } // option_set_for_gif()
191 
192 /*----------------------------------------------------------------------------*/
option_set_dissolve(struct FlattenSpec * flatspec)193 void option_set_dissolve( struct FlattenSpec* flatspec )
194 {
195   flatspec->partial_transparency_mode = DISSOLVE_PARTIAL_TRANSPARENCY ;
196 } // option_set_dissolve()
197 
198 /*----------------------------------------------------------------------------*/
option_set_full_image(struct FlattenSpec * flatspec)199 void option_set_full_image( struct FlattenSpec* flatspec )
200 {
201   flatspec->process_in_memory = 1 ;
202 } // option_set_full_image()
203 
204 /*----------------------------------------------------------------------------*/
option_set_size(struct FlattenSpec * flatspec,char * size)205 void option_set_size( struct FlattenSpec* flatspec, char* size )
206 {
207   unsigned w, h;
208   int n = 0 ;
209 
210   sscanf( size,"%ux%u%n", &w, &h, &n );
211 
212   if( ( n != 0 ) && ( n == strlen(size) ) )
213     {
214       if( flatspec->window_mode == AUTOCROP )
215         flatspec->window_mode = USE_CANVAS ;
216 
217       flatspec->window_mode |= MANUAL_CROP ;
218       flatspec->dim.width = w ;
219       flatspec->dim.height = h ;
220     }
221   else
222     FatalGeneric( 20, gettext("The size must have the form WxH") );
223 } // option_set_size()
224 
225 /*----------------------------------------------------------------------------*/
option_set_offset(struct FlattenSpec * flatspec,char * offset)226 void option_set_offset( struct FlattenSpec* flatspec, char* offset )
227 {
228   int x, y;
229   int n = 0;
230 
231   sscanf( offset, "%d,%d%n", &x, &y, &n );
232 
233   if( ( n != 0 ) && ( n == strlen(offset) ) )
234     {
235       if( flatspec->window_mode == AUTOCROP )
236         flatspec->window_mode = USE_CANVAS ;
237 
238       flatspec->window_mode |= MANUAL_OFFSET ;
239       flatspec->dim.c.l = x ;
240       flatspec->dim.c.t = y ;
241     }
242   else
243     FatalGeneric( 20, gettext("The offset must have the form x,y") );
244 } // option_set_offset()
245 
246 /*----------------------------------------------------------------------------*/
option_set_autocrop(struct FlattenSpec * flatspec)247 void option_set_autocrop( struct FlattenSpec* flatspec )
248 {
249   flatspec->window_mode = AUTOCROP ;
250 } // option_set_autocrop()
251 
252 /*----------------------------------------------------------------------------*/
option_set_mode(struct FlattenSpec * flatspec,char * mode)253 void option_set_mode( struct FlattenSpec* flatspec, char* mode )
254 {
255   GimpLayerModeEffects m ;
256   int found = 0;
257 
258   if( flatspec->numLayers == 0 )
259     FatalGeneric
260       ( 20,
261         gettext("There is no layer to which the mode can be applied") );
262 
263   for( m = 0; (found == 0) && (m <= GimpLayerModeEffects_LAST); )
264     if( strcmp( mode, gettext(showGimpLayerModeEffects(m)) ) == 0 )
265       found = 1;
266     else
267       ++m;
268 
269   if ( found == 0 )
270     for( m = 0; (found == 0) && (m <= GimpLayerModeEffects_LAST); )
271       if( strcmp( mode, showGimpLayerModeEffects(m) ) == 0 )
272         found = 1;
273       else
274         ++m;
275 
276   if ( found )
277     lastlayerspec( flatspec )->mode = m;
278   else
279     FatalGeneric( 20, gettext("Layer mode '%s' is unknown"), mode );
280 } // option_set_mode()
281 
282 /*----------------------------------------------------------------------------*/
option_set_percent(struct FlattenSpec * flatspec,char * percent)283 void option_set_percent( struct FlattenSpec* flatspec, char* percent )
284 {
285   unsigned pct ;
286   int n ;
287 
288   if( flatspec->numLayers == 0 )
289     FatalGeneric
290       ( 20,
291         gettext("There is no layer to which the percent can be applied") );
292 
293   sscanf( percent, "%u%n", &pct, &n );
294 
295   if( ( n != strlen(percent) ) || ( pct > 100 ) )
296     FatalGeneric( 20, gettext("The percent value is not a percentage") );
297 
298   lastlayerspec( flatspec )->opacity = pct * 255 / 100;
299 } // option_set_percent()
300 
301 /*----------------------------------------------------------------------------*/
option_set_opacity(struct FlattenSpec * flatspec,char * opacity)302 void option_set_opacity( struct FlattenSpec* flatspec, char* opacity )
303 {
304   unsigned alpha ;
305   int n ;
306 
307   if( flatspec->numLayers == 0 )
308     FatalGeneric
309       ( 20,
310         gettext("There is no layer to which the opacity can be applied") );
311 
312   sscanf( opacity, "%u%n", &alpha, &n );
313 
314   if( ( n != strlen(opacity) ) || ( alpha > 255 ) )
315     FatalGeneric
316       ( 20, gettext("The opacity is not a number between 0 and 255") );
317 
318   lastlayerspec( flatspec )->opacity = alpha ;
319 } // option_set_opacity()
320 
321 /*----------------------------------------------------------------------------*/
option_set_mask(struct FlattenSpec * flatspec)322 void option_set_mask( struct FlattenSpec* flatspec )
323 {
324   if( flatspec->numLayers == 0 )
325     FatalGeneric
326       ( 20,
327         gettext("There is no layer on which the mask can be enabled") );
328 
329   lastlayerspec( flatspec )->hasMask = 1;
330 } // option_set_mask()
331 
332 /*----------------------------------------------------------------------------*/
option_set_nomask(struct FlattenSpec * flatspec)333 void option_set_nomask( struct FlattenSpec* flatspec )
334 {
335   if( flatspec->numLayers == 0 )
336     FatalGeneric
337       ( 20,
338         gettext("There is no layer on which the mask can be disabled") );
339 
340   lastlayerspec( flatspec )->hasMask = 0;
341 } // option_set_nomask()
342 
343 /*----------------------------------------------------------------------------*/
process_option(int option,char * argval,struct ProcessControl * p,struct FlattenSpec * flatspec)344 int process_option
345 ( int option, char* argval,
346   struct ProcessControl* p, struct FlattenSpec* flatspec )
347 {
348   switch(option)
349     {
350     case option_help_value:
351     case '?':
352       return -1;
353     case option_version_value:
354       return 1;
355     case option_verbose_value:
356       option_set_verbose( p );
357       break;
358     case option_bzip_value:
359       option_set_bzip( p );
360       break;
361     case option_gzip_value:
362       option_set_gzip( p );
363       break;
364     case option_unpack_value:
365       option_set_unpack( p, argval );
366       break;
367     case option_output_value:
368       option_set_output( flatspec, argval );
369       break;
370     case option_path_separator_value:
371       option_set_path_separator( p, argval );
372       break;
373     case option_alpha_value:
374       option_set_alpha( flatspec, argval );
375       break;
376     case option_background_value:
377       option_set_background( flatspec, argval );
378       break;
379     case option_checkered_background_value:
380       option_set_checkered_background( flatspec );
381       break;
382     case option_force_alpha_value:
383       option_set_force_alpha( flatspec );
384       break;
385     case option_color_value:
386       option_set_color( flatspec );
387       break;
388     case option_gray_value:
389       option_set_gray( flatspec );
390       break;
391     case option_mono_value:
392       option_set_mono( flatspec );
393       break;
394     case option_pnm_value:
395       option_set_pnm( flatspec );
396       break;
397     case option_truecolor_value:
398       option_set_truecolor( flatspec );
399       break;
400     case option_for_gif_value:
401       option_set_for_gif( flatspec );
402       break;
403     case option_dissolve_value:
404       option_set_dissolve( flatspec );
405       break;
406     case option_full_image_value:
407       option_set_full_image( flatspec );
408       break;
409     case option_size_value:
410       option_set_size( flatspec, argval );
411       break;
412     case option_offset_value:
413       option_set_offset( flatspec, argval );
414       break;
415     case option_autocrop_value:
416       option_set_autocrop( flatspec );
417       break;
418     case option_mode_value:
419       option_set_mode( flatspec, argval );
420       break;
421     case option_percent_value:
422       option_set_percent( flatspec, argval );
423       break;
424     case option_opacity_value:
425       option_set_opacity( flatspec, argval );
426       break;
427     case option_mask_value:
428       option_set_mask( flatspec );
429       break;
430     case option_nomask_value:
431       option_set_nomask( flatspec );
432       break;
433     case option_utf8_value:
434       option_set_utf8( p );
435       break;
436 
437     case 1:
438       if ( p->inputFile == NULL )
439         p->inputFile = argval;
440       else if ( flatspec != NULL )
441         add_layer_request( flatspec, optarg );
442       else
443         FatalGeneric
444           (20, gettext("Only one XCF file per command line, please"));
445       break ;
446     default:
447       FatalUnexpected("Getopt(_long) unexpectedly returned '%c'", option);
448     }
449 
450   return 0;
451 } // process_option()
452 
453 /*----------------------------------------------------------------------------*/
get_option_index(const struct option * long_options,int option)454 int get_option_index( const struct option* long_options, int option )
455 {
456   int i;
457 
458   for ( i=0; long_options[i].name != NULL; ++i )
459     if ( long_options[i].val == option )
460       return i;
461 
462   return -1;
463 } // get_option_index()
464 
465 /*----------------------------------------------------------------------------*/
has_layer_option(const struct option * long_options)466 int has_layer_option( const struct option* long_options )
467 {
468   return (get_option_index( long_options, option_mode_value ) != -1)
469     || (get_option_index( long_options, option_percent_value ) != -1)
470     || (get_option_index( long_options, option_opacity_value ) != -1)
471     || (get_option_index( long_options, option_mask_value ) != -1)
472     || (get_option_index( long_options, option_nomask_value ) != -1)
473     || (get_option_index( long_options, option_path_separator_value ) != -1)
474     || (get_option_index( long_options, option_utf8_value ) != -1);
475 } // has_layer_option()
476 
477 /*----------------------------------------------------------------------------*/
print_option_arg(const struct option * long_options,int option_value,const char * message,const char * command)478 void print_option_arg
479 ( const struct option* long_options, int option_value, const char* message,
480   const char* command )
481 {
482   const int index = get_option_index( long_options, option_value );
483   const struct option* option;
484   int fill = 30;
485 
486   if ( index < 0 )
487     return;
488   else
489     option = &long_options[index];
490 
491   fill -= printf( "  " );
492 
493   if ( isprint( long_options[index].val ) )
494     fill -= printf( "-%c, ", (char)option->val );
495 
496   fill -= printf( "--%s", option->name );
497 
498   if ( command != NULL )
499     fill -= printf( "=%s", command );
500 
501   if ( fill > 0 )
502     printf( "%*.*s%s\n", fill, fill, " ", message );
503   else
504   printf( " %s\n", message );
505 } // print_option_arg()
506 
507 /*----------------------------------------------------------------------------*/
print_option(const struct option * long_options,int option_value,const char * message)508 void print_option
509 ( const struct option* long_options, int option_value, const char* message )
510 {
511   print_option_arg( long_options, option_value, message, NULL );
512 } // print_option()
513 
514 /*----------------------------------------------------------------------------*/
show_help(const char * progname,const struct option * long_options)515 void show_help
516 ( const char* progname, const struct option* long_options )
517 {
518   const int with_layer_option = has_layer_option( long_options );
519   if ( with_layer_option )
520     printf( gettext( "Usage: %s [options] filename.xcf[.gz | .bz2] [layers]\n"),
521             progname );
522   else
523     printf( gettext( "Usage: %s [options] filename.xcf[.gz | .bz2]\n"),
524             progname );
525 
526   printf( gettext( "Options:\n" ) );
527 
528   print_option( long_options, option_help_value, gettext("show this message") );
529   print_option( long_options, option_version_value, gettext("show version") );
530   print_option
531     ( long_options, option_verbose_value, gettext("show progress messages") );
532   print_option
533     ( long_options, option_bzip_value, gettext("input is bzip2 compressed") );
534   print_option
535     ( long_options, option_gzip_value, gettext("input is gzip compressed") );
536   print_option_arg
537     ( long_options, option_unpack_value,
538       gettext("use 'command' to decompress input"), "command" );
539   print_option_arg
540     ( long_options, option_output_value, gettext("name output file"),
541       "filename" );
542   print_option_arg
543     ( long_options, option_alpha_value, gettext("write transparency map"),
544       "filename" );
545   print_option_arg
546     ( long_options, option_background_value,
547       gettext("select background color"), "color" );
548   print_option
549     ( long_options, option_checkered_background_value,
550       gettext("render on a checkered background") );
551   print_option
552     ( long_options, option_force_alpha_value,
553       gettext("force alpha channel in output") );
554   print_option
555     ( long_options, option_color_value, gettext("select color output") );
556   print_option
557     ( long_options, option_gray_value, gettext("select grayscale output") );
558   print_option
559     ( long_options, option_mono_value,
560       gettext("select monochrome output") );
561   print_option
562     ( long_options, option_pnm_value,
563       gettext("select --color, --gray or --mono by image content") );
564   print_option
565     ( long_options, option_truecolor_value,
566       gettext("treat indexed images as RGB for flattening") );
567   print_option
568     ( long_options, option_for_gif_value,
569       gettext("disallow partiel transparency") );
570   print_option
571     ( long_options, option_dissolve_value,
572       gettext("dissolve partial transparency") );
573   print_option
574     ( long_options, option_full_image_value,
575       gettext("flatten to memory; then analyse") );
576   print_option_arg
577     ( long_options, option_size_value, gettext("crop image while converting"),
578       "WxH" );
579   print_option_arg
580     ( long_options, option_offset_value,
581       gettext("translate converted part of image"), "x,y" );
582   print_option
583     ( long_options, option_autocrop_value,
584       gettext("autocrop to visible layer boundaries") );
585 
586   if ( with_layer_option )
587     {
588       printf( gettext( "Layer-selection options:\n" ) );
589 
590       print_option_arg
591         ( long_options, option_mode_value, gettext("set layer mode"), "mode" );
592       print_option_arg
593         ( long_options, option_percent_value,
594           gettext("set opacity in percent"), "n" );
595       print_option_arg
596         ( long_options, option_opacity_value,
597           gettext("set opacity in 1/255 units"), "n" );
598       print_option
599         ( long_options, option_mask_value, gettext("enable layer mask") );
600       print_option
601         ( long_options, option_nomask_value, gettext("disable layer mask") );
602       print_option_arg
603         ( long_options, option_path_separator_value,
604           gettext("use 'string' to separate the groups in the paths"),
605           "string" );
606       print_option
607         ( long_options, option_utf8_value,
608           gettext("use UTF-8 for layer names") );
609     }
610 } // show_help()
611 
612 /*----------------------------------------------------------------------------*/
option_parse(int argc,char ** argv,const char * short_options,const struct option * long_options,struct ProcessControl * p,struct FlattenSpec * flatspec)613 int option_parse
614 ( int argc, char** argv, const char* short_options,
615   const struct option* long_options, struct ProcessControl* p,
616   struct FlattenSpec* flatspec )
617 {
618   int option;
619   const char* progname = argv[0];
620   int option_result = 0;
621 
622   option = getopt_long( argc, argv, short_options, long_options, NULL );
623 
624   while ( (option != -1) && (option_result == 0) )
625     {
626       option_result = process_option( option, optarg, p, flatspec );
627       option = getopt_long( argc, argv, short_options, long_options, NULL );
628     }
629 
630   if ( option_result == 1 )
631     option_show_version( progname );
632   else if ( ( p->inputFile == NULL ) || ( option_result < 0 ) )
633     show_help( progname, long_options );
634 
635   return option_result != 0;
636 } // option_parse()
637