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