1 /*****************************************************************
2  * gmerlin - a general purpose multimedia framework and applications
3  *
4  * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5  * gmerlin-general@lists.sourceforge.net
6  * http://gmerlin.sourceforge.net
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * *****************************************************************/
21 
22 
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <time.h>
29 
30 #include <config.h>
31 #include <gmerlin/translation.h>
32 
33 #include <gmerlin/cfg_registry.h>
34 #include <gmerlin/cmdline.h>
35 #include <gmerlin/utils.h>
36 
37 static const bg_cmdline_app_data_t * app_data;
38 
39 
40 /* Terminal related functions */
41 
42 #define MAX_COLS 79 /* For line-wrapping */
43 
44 static void opt_help(void * data, int * argc, char *** argv, int arg);
45 static void opt_help_man(void * data, int * argc, char *** argv, int arg);
46 static void opt_help_texi(void * data, int * argc, char *** argv, int arg);
47 static void opt_version(void * data, int * argc, char *** argv, int arg);
48 
do_indent(FILE * out,int num,bg_help_format_t format)49 static void do_indent(FILE * out, int num, bg_help_format_t format)
50   {
51   switch(format)
52     {
53     case BG_HELP_FORMAT_TERM:
54     case BG_HELP_FORMAT_PLAIN:
55       {
56       int i;
57       for(i = 0; i < num; i++)
58         fprintf(out, " ");
59       }
60       break;
61     case BG_HELP_FORMAT_MAN:
62       //      fprintf(out, ".RS %d\n", num);
63       break;
64     case BG_HELP_FORMAT_TEXI:
65       break;
66     }
67   }
68 
dump_string_term(FILE * out,const char * str,int indent,const char * translation_domain,bg_help_format_t format)69 static void dump_string_term(FILE * out, const char * str, int indent,
70                              const char * translation_domain, bg_help_format_t format)
71   {
72   const char * start;
73   const char * end;
74   const char * pos;
75 
76   str = TR_DOM(str);
77 
78   if(format == BG_HELP_FORMAT_MAN)
79     do_indent(out, indent + 2, format);
80 
81   start = str;
82   pos   = str;
83   end   = str;
84 
85   while(1)
86     {
87     if(isspace(*pos))
88       end = pos;
89 
90     if(pos - start + indent + 2 > MAX_COLS)
91       {
92       if(format != BG_HELP_FORMAT_MAN)
93         do_indent(out, indent + 2, format);
94 
95       fwrite(start, 1, end - start, out);
96 
97       fprintf(out, "\n");
98 
99       while(isspace(*end))
100         end++;
101       start = end;
102       }
103     else if(*pos == '\0')
104       {
105       if(format != BG_HELP_FORMAT_MAN)
106         do_indent(out, indent + 2, format);
107 
108       fwrite(start, 1, pos - start, out);
109       fprintf(out, "\n");
110       break;
111       }
112     else if(*pos == '\n')
113       {
114       if(format != BG_HELP_FORMAT_MAN)
115         do_indent(out, indent + 2, format);
116 
117       fwrite(start, 1, pos - start, out);
118 
119       if(format == BG_HELP_FORMAT_TEXI)
120         fprintf(out, "@*\n");
121       else
122         fprintf(out, "\n");
123 
124       pos++;
125 
126       start = pos;
127       end = pos;
128       }
129 
130     else
131       pos++;
132     }
133 
134   }
135 
136 static const char ansi_underline[] = { 27, '[', '4', 'm', '\0' };
137 static const char ansi_normal[] = { 27, '[', '0', 'm', '\0' };
138 static const char ansi_bold[] = { 27, '[', '1', 'm', '\0' };
139 
print_string(FILE * out,const char * str,bg_help_format_t format)140 static void print_string(FILE * out, const char * str, bg_help_format_t format)
141   {
142   switch(format)
143     {
144     case BG_HELP_FORMAT_TEXI:
145       {
146       const char * pos;
147       pos = str;
148       while(*pos)
149         {
150         if((*pos == '{') || (*pos == '}') || (*pos == '@'))
151           fprintf(out, "@%c", *pos);
152         else
153           fprintf(out, "%c", *pos);
154         pos++;
155         }
156       }
157       break;
158     default:
159       fprintf(out, "%s", str);
160       break;
161     }
162   }
163 
print_bold(FILE * out,char * str,bg_help_format_t format)164 static void print_bold(FILE * out, char * str, bg_help_format_t format)
165   {
166   switch(format)
167     {
168     case BG_HELP_FORMAT_TERM:
169       fprintf(out, "%s%s%s", ansi_bold, str, ansi_normal);
170       break;
171     case BG_HELP_FORMAT_PLAIN:
172       fprintf(out, "%s", str);
173       /* Do nothing */
174       break;
175     case BG_HELP_FORMAT_MAN:
176       fprintf(out, ".B %s\n", str);
177       break;
178     case BG_HELP_FORMAT_TEXI:
179       fprintf(out, "@b{");
180       print_string(out, str, format);
181       fprintf(out, "}");
182       break;
183     }
184   }
185 
print_italic(FILE * out,char * str,bg_help_format_t format)186 static void print_italic(FILE * out, char * str, bg_help_format_t format)
187   {
188   switch(format)
189     {
190     case BG_HELP_FORMAT_TERM:
191       fprintf(out, "%s%s%s", ansi_underline, str, ansi_normal);
192       break;
193     case BG_HELP_FORMAT_PLAIN:
194       /* Do nothing */
195       fprintf(out, "%s", str);
196       break;
197     case BG_HELP_FORMAT_MAN:
198       fprintf(out, ".I %s\n", str);
199       break;
200     case BG_HELP_FORMAT_TEXI:
201       fprintf(out, "@i{");
202       print_string(out, str, format);
203       fprintf(out, "}");
204       break;
205     }
206   }
207 
print_linebreak(FILE * out,bg_help_format_t format)208 static void print_linebreak(FILE * out, bg_help_format_t format)
209   {
210   if(format == BG_HELP_FORMAT_MAN)
211     fprintf(out, "\n.P\n");
212   else if(format == BG_HELP_FORMAT_TEXI)
213     fprintf(out, "@*@*\n");
214   else
215     fprintf(out, "\n\n");
216   }
217 
print_version(const bg_cmdline_app_data_t * app_data)218 static void print_version(const bg_cmdline_app_data_t * app_data)
219   {
220   printf("%s (%s) %s\n", app_data->name, app_data->package, app_data->version);
221   printf(TR("Copyright (C) 2001-2007 Members of the gmerlin project\n"));
222   printf(TR("This is free software.  You may redistribute copies of it under the terms of\n\
223 the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n\
224 There is NO WARRANTY.\n"));
225   }
226 
print_help(const bg_cmdline_arg_t * args,bg_help_format_t format)227 static void print_help(const bg_cmdline_arg_t* args, bg_help_format_t format)
228   {
229   int i = 0;
230   FILE * out = stdout;
231   if(format == BG_HELP_FORMAT_TEXI)
232     fprintf(out, "@table @i\n");
233   while(args[i].arg)
234     {
235     switch(format)
236       {
237       case BG_HELP_FORMAT_PLAIN:
238       case BG_HELP_FORMAT_TERM:
239         fprintf(out, "  ");
240         print_bold(out, args[i].arg, format);
241 
242         if(args[i].help_arg)
243           {
244           fprintf(out, " ");
245           print_italic(out, args[i].help_arg, format);
246           }
247         fprintf(out, "\n");
248         dump_string_term(out, args[i].help_string, 0, NULL, format);
249 
250         break;
251       case BG_HELP_FORMAT_TEXI:
252         fprintf(out, "@item %s", args[i].arg);
253         if(args[i].help_arg)
254           {
255           fprintf(out, " ");
256           print_string(out, args[i].help_arg, format);
257           }
258         fprintf(out, "\n");
259         print_string(out, args[i].help_string, format);
260         fprintf(out, "@*\n");
261         break;
262       case BG_HELP_FORMAT_MAN:
263         print_bold(out, args[i].arg, format);
264         if(args[i].help_arg)
265           print_italic(out, args[i].help_arg, format);
266         fprintf(out, "\n");
267         fprintf(out, ".RS 2\n");
268         dump_string_term(out, args[i].help_string, 0, NULL, format);
269         fprintf(out, ".RE\n");
270 
271         break;
272       }
273 
274     if(args[i].parameters)
275       {
276       bg_cmdline_print_help_parameters(args[i].parameters, format);
277       }
278     fprintf(out, "\n");
279     i++;
280     }
281   if(format == BG_HELP_FORMAT_TEXI)
282     fprintf(out, "@end table\n");
283 
284   }
285 
286 static const bg_cmdline_arg_t auto_options[] =
287   {
288     {
289       .arg =         "-help",
290       .help_string = TRS("Print this help message and exit"),
291       .callback =    opt_help,
292     },
293     {
294       .arg =         "-help-man",
295       .help_string = TRS("Print this help message as a manual page and exit"),
296       .callback =    opt_help_man,
297     },
298     {
299       .arg =         "-help-texi",
300       .help_string = TRS("Print this help message in texinfo format and exit"),
301       .callback =    opt_help_texi,
302     },
303     {
304       .arg =         "-version",
305       .help_string = TRS("Print version info and exit"),
306       .callback =    opt_version,
307     },
308     { /* End of options */ }
309   };
310 
bg_cmdline_print_help(char * argv0,bg_help_format_t format)311 void bg_cmdline_print_help(char * argv0, bg_help_format_t format)
312   {
313   int i;
314   char * tmp_string;
315 
316   switch(format)
317     {
318     case BG_HELP_FORMAT_TERM:
319     case BG_HELP_FORMAT_PLAIN:
320       tmp_string = bg_sprintf(TRD(app_data->synopsis, app_data->package), argv0);
321       printf("Usage: %s\n\n", tmp_string);
322       free(tmp_string);
323       printf("%s\n", app_data->help_before);
324       i = 0;
325       while(app_data->args[i].name)
326         {
327         printf("%s\n\n", app_data->args[i].name);
328         print_help(app_data->args[i].args, format);
329         i++;
330         }
331       print_bold(stdout, "Generic options\n", format);
332       printf("\nThe following generic options are available for all gmerlin applications\n");
333       print_linebreak(stdout, format);
334       print_help(auto_options, format);
335 
336       if(app_data->env)
337         {
338         print_bold(stdout, TR("Environment variables\n\n"), format);
339         i = 0;
340         while(app_data->env[i].name)
341           {
342           print_bold(stdout, app_data->env[i].name, format);
343           printf("\n");
344           dump_string_term(stdout, app_data->env[i].desc,
345                            0, NULL, format);
346           i++;
347           print_linebreak(stdout, format);
348           }
349         }
350       if(app_data->files)
351         {
352         print_bold(stdout, TR("Files\n\n"), format);
353         i = 0;
354         while(app_data->files[i].name)
355           {
356           print_bold(stdout, app_data->files[i].name, format);
357           printf("\n");
358           dump_string_term(stdout, app_data->files[i].desc,
359                            0, NULL, format);
360           print_linebreak(stdout, format);
361           i++;
362           }
363         }
364 
365 
366       break;
367     case BG_HELP_FORMAT_MAN:
368       {
369       char date_str[512];
370       struct tm brokentime;
371       time_t t;
372       char ** args;
373       char * string_uc;
374 
375       time(&t);
376       localtime_r(&t, &brokentime);
377       strftime(date_str, 511, "%B %Y", &brokentime);
378 
379       string_uc = bg_toupper(app_data->name);
380 
381       printf(".TH %s 1 \"%s\" Gmerlin \"User Manuals\"\n", string_uc,
382              date_str);
383 
384       free(string_uc);
385 
386       printf(".SH NAME\n%s\n", app_data->name);
387       printf(".SH SYNOPSIS\n.B %s \n", app_data->name);
388       tmp_string = bg_strdup(NULL,
389                              TRD(app_data->synopsis, app_data->package));
390 
391       args = bg_strbreak(tmp_string, ' ');
392       i = 0;
393       while(args[i])
394         {
395         printf(".I %s\n", args[i]);
396         i++;
397         }
398 
399       if(app_data->help_before)
400         printf(".SH DESCRIPTION\n%s\n", TRD(app_data->help_before, app_data->package));
401 
402       i = 0;
403       while(app_data->args[i].name)
404         {
405         string_uc = bg_toupper(app_data->args[i].name);
406         printf(".SH %s\n\n", string_uc);
407         free(string_uc);
408         print_help(app_data->args[i].args, format);
409         i++;
410         }
411       printf(".SH GENERIC OPTIONS\nThe following generic options are available for all gmerlin applications\n\n");
412       print_help(auto_options, format);
413 
414       if(app_data->env)
415         {
416         printf(TR(".SH ENVIRONMENT VARIABLES\n"));
417         i = 0;
418         while(app_data->env[i].name)
419           {
420           print_bold(stdout, app_data->env[i].name, format);
421           printf("\n");
422           printf(".RS 2\n");
423           dump_string_term(stdout, app_data->env[i].desc,
424                            0, NULL, format);
425           printf(".RE\n");
426           i++;
427           }
428         }
429       if(app_data->files)
430         {
431         printf(TR(".SH FILES\n"));
432         i = 0;
433         while(app_data->files[i].name)
434           {
435           print_bold(stdout, app_data->files[i].name, format);
436           printf("\n");
437           printf(".RS 2\n");
438           dump_string_term(stdout, app_data->files[i].desc,
439                            0, NULL, format);
440           printf(".RE\n");
441           print_linebreak(stdout, format);
442           i++;
443           }
444         }
445       }
446       break;
447     case BG_HELP_FORMAT_TEXI:
448       printf("@table @b\n");
449       printf("@item Synopsis\n");
450       printf("@b{%s} @i{%s}@*\n", app_data->name,
451              TRD(app_data->synopsis, app_data->package));
452       if(app_data->help_before)
453         {
454         printf("@item Description\n");
455         printf("%s@*\n", TRD(app_data->help_before, app_data->package));
456         }
457       i = 0;
458       while(app_data->args[i].name)
459         {
460         printf("@item %s\n", app_data->args[i].name);
461         print_help(app_data->args[i].args, format);
462         i++;
463         }
464       printf("@item Generic options\n");
465       printf("The following generic options are available for all gmerlin applications@*\n");
466       print_help(auto_options, format);
467 
468       if(app_data->env)
469         {
470         printf(TR("@item Environment variables\n"));
471         printf("@table @env\n");
472         i = 0;
473         while(app_data->env[i].name)
474           {
475           printf("@item %s\n", app_data->env[i].name);
476           printf("%s@*\n", TRD(app_data->env[i].desc, app_data->package));
477           i++;
478           }
479         printf("@end table\n");
480         }
481 
482       if(app_data->files)
483         {
484         printf(TR("@item Files\n"));
485         printf("@table @file\n");
486         i = 0;
487         while(app_data->files[i].name)
488           {
489           printf("@item %s\n", app_data->files[i].name);
490           printf("%s@*\n", TRD(app_data->files[i].desc, app_data->package));
491           i++;
492           }
493         printf("@end table\n");
494         }
495       printf("@end table\n");
496       break;
497     }
498 
499   }
500 
501 
opt_help(void * data,int * argc,char *** argv,int arg)502 static void opt_help(void * data, int * argc, char *** argv, int arg)
503   {
504   if(isatty(fileno(stdout)))
505     bg_cmdline_print_help((*argv)[0], BG_HELP_FORMAT_TERM);
506   else
507     bg_cmdline_print_help((*argv)[0], BG_HELP_FORMAT_PLAIN);
508   exit(0);
509   }
510 
opt_help_man(void * data,int * argc,char *** argv,int arg)511 static void opt_help_man(void * data, int * argc, char *** argv, int arg)
512   {
513   bg_cmdline_print_help((*argv)[0], BG_HELP_FORMAT_MAN);
514   exit(0);
515   }
516 
opt_help_texi(void * data,int * argc,char *** argv,int arg)517 static void opt_help_texi(void * data, int * argc, char *** argv, int arg)
518   {
519   bg_cmdline_print_help((*argv)[0], BG_HELP_FORMAT_TEXI);
520   exit(0);
521   }
522 
opt_version(void * data,int * argc,char *** argv,int arg)523 static void opt_version(void * data, int * argc, char *** argv, int arg)
524   {
525   print_version(app_data);
526   exit(0);
527   }
528 
529 
530 /* */
531 
bg_cmdline_remove_arg(int * argc,char *** _argv,int arg)532 void bg_cmdline_remove_arg(int * argc, char *** _argv, int arg)
533   {
534   char ** argv = *_argv;
535   /* Move the upper args down */
536   if(arg < *argc - 1)
537     memmove(argv + arg, argv + arg + 1,
538             (*argc - arg - 1) * sizeof(*argv));
539   (*argc)--;
540   }
541 
542 
543 
cmdline_parse(const bg_cmdline_arg_t * args,int * argc,char *** _argv,void * callback_data,int parse_auto)544 static void cmdline_parse(const bg_cmdline_arg_t * args,
545                           int * argc, char *** _argv,
546                           void * callback_data,
547                           int parse_auto)
548   {
549   int found;
550   int i, j;
551   char ** argv = *_argv;
552 
553   i = 1;
554 
555   if(parse_auto)
556     {
557     cmdline_parse(auto_options, argc, _argv, NULL, 0);
558     }
559 
560   if(!args)
561     return;
562 
563   while(i < *argc)
564     {
565     j = 0;
566     found = 0;
567 
568     if(!strcmp(argv[i], "--"))
569       break;
570 
571     while(args[j].arg)
572       {
573       if(!strcmp(args[j].arg, argv[i]))
574         {
575         bg_cmdline_remove_arg(argc, _argv, i);
576         if(args[j].callback)
577           args[j].callback(callback_data, argc, _argv, i);
578         else if(args[j].parameters)
579           {
580           }
581 
582         found = 1;
583         break;
584         }
585       else
586         j++;
587       }
588     if(!found)
589       i++;
590     }
591   }
592 
bg_cmdline_parse(bg_cmdline_arg_t * args,int * argc,char *** _argv,void * callback_data)593 void bg_cmdline_parse(bg_cmdline_arg_t * args, int * argc, char *** _argv,
594                       void * callback_data)
595   {
596   cmdline_parse(args, argc, _argv, callback_data, 1);
597   }
598 
599 
bg_cmdline_get_locations_from_args(int * argc,char *** _argv)600 char ** bg_cmdline_get_locations_from_args(int * argc, char *** _argv)
601   {
602   char ** ret;
603   int seen_dashdash;
604   char ** argv;
605   int i, index;
606   int num_locations = 0;
607   argv = *_argv;
608 
609   /* Count the locations */
610 
611   for(i = 1; i < *argc; i++)
612     {
613     if(!strcmp(argv[i], "--"))
614       {
615       num_locations += *argc - 1 - i;
616       break;
617       }
618     else if(argv[i][0] != '-')
619       num_locations++;
620     }
621 
622   if(!num_locations)
623     return NULL;
624 
625   /* Allocate return value */
626 
627   ret = calloc(num_locations + 1, sizeof(*ret));
628 
629   i = 1;
630   index = 0;
631   seen_dashdash = 0;
632 
633   while(i < *argc)
634     {
635     if(seen_dashdash || (argv[i][0] != '-'))
636       {
637       ret[index++] = argv[i];
638       bg_cmdline_remove_arg(argc, _argv, i);
639       }
640     else if(!strcmp(argv[i], "--"))
641       {
642       seen_dashdash = 1;
643       bg_cmdline_remove_arg(argc, _argv, i);
644       }
645     else
646       {
647       i++;
648       }
649     }
650   return ret;
651   }
652 
653 
bg_cmdline_apply_options(bg_cfg_section_t * section,bg_set_parameter_func_t set_parameter,void * data,const bg_parameter_info_t * parameters,const char * option_string)654 int bg_cmdline_apply_options(bg_cfg_section_t * section,
655                              bg_set_parameter_func_t set_parameter,
656                              void * data,
657                              const bg_parameter_info_t * parameters,
658                              const char * option_string)
659   {
660   if(!bg_cfg_section_set_parameters_from_string(section,
661                                                 parameters,
662                                                 option_string))
663     return 0;
664   /* Now, apply the section */
665   if(set_parameter)
666     bg_cfg_section_apply(section, parameters, set_parameter, data);
667   return 1;
668   }
669 
670 
671 
print_help_parameters(int indent,const bg_parameter_info_t * parameters,bg_help_format_t format)672 static void print_help_parameters(int indent,
673                                   const bg_parameter_info_t * parameters,
674                                   bg_help_format_t format)
675   {
676   int i = 0;
677   int j;
678   FILE * out = stdout;
679 
680   int pos;
681 
682   char time_string[GAVL_TIME_STRING_LEN];
683   char * tmp_string;
684 
685   const char * translation_domain = NULL;
686 
687   indent += 2;
688   if(format == BG_HELP_FORMAT_MAN)
689     fprintf(out, ".RS 2\n");
690   else if(format == BG_HELP_FORMAT_TEXI)
691     fprintf(out, "@table @r\n");
692 
693   if(!indent)
694     {
695     do_indent(out, indent+2, format);
696 
697     fprintf(out, TR("Supported options:\n\n"));
698     }
699 
700   while(parameters[i].name)
701     {
702     if(parameters[i].gettext_domain)
703       translation_domain = parameters[i].gettext_domain;
704     if(parameters[i].gettext_directory)
705       bg_bindtextdomain(translation_domain, parameters[i].gettext_directory);
706 
707     if((parameters[i].type == BG_PARAMETER_SECTION) ||
708        (parameters[i].flags & BG_PARAMETER_HIDE_DIALOG))
709       {
710       i++;
711       continue;
712       }
713     pos = 0;
714 
715     if(format == BG_HELP_FORMAT_MAN)
716       {
717       do_indent(out, indent+2, format);
718       fprintf(out, ".BR ");
719 
720       //      pos += fprintf(out, spaces);
721       //      pos += fprintf(out, "  ");
722 
723       if(parameters[i].opt)
724         {
725         fprintf(out, "%s", parameters[i].opt);
726         pos += strlen(parameters[i].opt);
727         }
728       else
729         {
730         fprintf(out, "%s", parameters[i].name);
731         pos += strlen(parameters[i].name);
732         }
733       fprintf(out, " \"=");
734       }
735     else if(format == BG_HELP_FORMAT_TEXI)
736       {
737       fprintf(out, "@item ");
738 
739       pos += indent+2;
740 
741       if(parameters[i].opt)
742         {
743         print_bold(out, parameters[i].opt, format);
744         pos += strlen(parameters[i].opt);
745         }
746       else
747         {
748         print_bold(out, parameters[i].name, format);
749         pos += strlen(parameters[i].name);
750         }
751       fprintf(out, "=");
752       }
753     else
754       {
755       do_indent(out, indent+2, format);
756       pos += indent+2;
757 
758       if(parameters[i].opt)
759         {
760         print_bold(out, parameters[i].opt, format);
761         pos += strlen(parameters[i].opt);
762         }
763       else
764         {
765         print_bold(out, parameters[i].name, format);
766         pos += strlen(parameters[i].name);
767         }
768       fprintf(out, "=");
769       }
770 
771     switch(parameters[i].type)
772       {
773       case BG_PARAMETER_SECTION:
774       case BG_PARAMETER_BUTTON:
775         break;
776       case BG_PARAMETER_CHECKBUTTON:
777         tmp_string = bg_sprintf(TR("[1|0] (default: %d)"), parameters[i].val_default.val_i);
778         print_string(out, tmp_string, format);
779         free(tmp_string);
780         if(format == BG_HELP_FORMAT_MAN)
781           fprintf(out, "\"");
782         print_linebreak(out, format);
783         break;
784       case BG_PARAMETER_INT:
785       case BG_PARAMETER_SLIDER_INT:
786         pos += fprintf(out, TR("<number> ("));
787         if(parameters[i].val_min.val_i < parameters[i].val_max.val_i)
788           {
789           pos += fprintf(out, "%d..%d, ",
790                          parameters[i].val_min.val_i, parameters[i].val_max.val_i);
791           }
792         fprintf(out, TR("default: %d)"), parameters[i].val_default.val_i);
793 
794         if(format == BG_HELP_FORMAT_MAN)
795           fprintf(out, "\"");
796         print_linebreak(out, format);
797         break;
798       case BG_PARAMETER_SLIDER_FLOAT:
799       case BG_PARAMETER_FLOAT:
800         pos += fprintf(out, TR("<number> ("));
801         if(parameters[i].val_min.val_f < parameters[i].val_max.val_f)
802           {
803           tmp_string = bg_sprintf("%%.%df..%%.%df, ",
804                                   parameters[i].num_digits,
805                                   parameters[i].num_digits);
806           pos += fprintf(out, tmp_string,
807                          parameters[i].val_min.val_f, parameters[i].val_max.val_f);
808           free(tmp_string);
809           }
810         tmp_string =
811           bg_sprintf(TR("default: %%.%df)"),
812                      parameters[i].num_digits);
813         fprintf(out, tmp_string,
814                 parameters[i].val_default.val_f);
815         free(tmp_string);
816 
817         if(format == BG_HELP_FORMAT_MAN)
818           fprintf(out, "\"");
819         print_linebreak(out, format);
820 
821         break;
822       case BG_PARAMETER_STRING:
823       case BG_PARAMETER_FONT:
824       case BG_PARAMETER_DEVICE:
825       case BG_PARAMETER_FILE:
826       case BG_PARAMETER_DIRECTORY:
827         pos += fprintf(out, TR("<string>"));
828         if(parameters[i].val_default.val_str)
829           {
830           tmp_string = bg_sprintf(TR(" (Default: %s)"), parameters[i].val_default.val_str);
831           print_string(out, tmp_string, format);
832           free(tmp_string);
833           }
834         if(format == BG_HELP_FORMAT_MAN)
835           fprintf(out, "\"");
836         print_linebreak(out, format);
837 
838         break;
839       case BG_PARAMETER_STRING_HIDDEN:
840         pos += fprintf(out, TR("<string>"));
841 
842         if(format == BG_HELP_FORMAT_MAN)
843           fprintf(out, "\"");
844         print_linebreak(out, format);
845         break;
846       case BG_PARAMETER_STRINGLIST:
847         pos += fprintf(out, TR("<string>"));
848         if(format == BG_HELP_FORMAT_MAN)
849           fprintf(out, "\"");
850         print_linebreak(out, format);
851 
852         j = 0;
853 
854         pos = 0;
855         do_indent(out, indent+2, format);
856         pos += indent+2;
857         pos += fprintf(out, TR("Supported strings: "));
858 
859         while(parameters[i].multi_names[j])
860           {
861           if(j) pos += fprintf(out, " ");
862 
863           if(pos + strlen(parameters[i].multi_names[j]+1) > MAX_COLS)
864             {
865             if((format == BG_HELP_FORMAT_TERM) || (format == BG_HELP_FORMAT_PLAIN))
866               fprintf(out, "\n");
867             pos = 0;
868             do_indent(out, indent+2, format);
869             pos += indent+2;
870             }
871 
872           pos += fprintf(out, "%s", parameters[i].multi_names[j]);
873           j++;
874           }
875         print_linebreak(out, format);
876         do_indent(out, indent+2, format);
877         pos += indent+2;
878 
879         tmp_string = bg_sprintf(TR("Default: %s"), parameters[i].val_default.val_str);
880         print_string(out, tmp_string, format);
881         free(tmp_string);
882         print_linebreak(out, format);
883 
884         break;
885       case BG_PARAMETER_COLOR_RGB:
886         fprintf(out, TR("<r>,<g>,<b> (default: %.3f,%.3f,%.3f)"),
887                 parameters[i].val_default.val_color[0],
888                 parameters[i].val_default.val_color[1],
889                 parameters[i].val_default.val_color[2]);
890         if(format == BG_HELP_FORMAT_MAN)
891           fprintf(out, "\"");
892         print_linebreak(out, format);
893 
894         do_indent(out, indent+2, format);
895         pos += indent+2;
896 
897         fprintf(out, TR("<r>, <g> and <b> are in the range 0.0..1.0"));
898         if(format != BG_HELP_FORMAT_MAN)
899           fprintf(out, "\n");
900         else
901           fprintf(out, "\n.P\n");
902         break;
903       case BG_PARAMETER_COLOR_RGBA:
904         fprintf(out, TR("<r>,<g>,<b>,<a> (default: %.3f,%.3f,%.3f,%.3f)"),
905                 parameters[i].val_default.val_color[0],
906                 parameters[i].val_default.val_color[1],
907                 parameters[i].val_default.val_color[2],
908                 parameters[i].val_default.val_color[3]);
909         if(format == BG_HELP_FORMAT_MAN)
910           fprintf(out, "\"");
911         print_linebreak(out, format);
912 
913         do_indent(out, indent+2, format);
914         pos += indent+2;
915 
916         fprintf(out, TR("<r>, <g>, <b> and <a> are in the range 0.0..1.0"));
917         if(format != BG_HELP_FORMAT_MAN)
918           fprintf(out, "\n");
919         else
920           fprintf(out, "\n.P\n");
921         break;
922       case BG_PARAMETER_MULTI_MENU:
923         print_string(out, TR("option[{suboptions}]"), format);
924         if(format == BG_HELP_FORMAT_MAN)
925           fprintf(out, "\"");
926         print_linebreak(out, format);
927         pos = 0;
928 
929         do_indent(out, indent+2, format);
930         pos += indent+2;
931 
932         pos += fprintf(out, TR("Supported options: "));
933         j = 0;
934 
935         if(parameters[i].multi_names)
936           {
937           while(parameters[i].multi_names[j])
938             {
939             if(j) pos += fprintf(out, " ");
940 
941             if(pos + strlen(parameters[i].multi_names[j]) > MAX_COLS)
942               {
943               if(format != BG_HELP_FORMAT_MAN)
944                 fprintf(out, "\n");
945               pos = 0;
946               do_indent(out, indent+2, format);
947               pos += indent+2;
948               }
949             pos += fprintf(out, "%s", parameters[i].multi_names[j]);
950             j++;
951             }
952           }
953         else
954           pos += fprintf(out, TR("<None>"));
955 
956         print_linebreak(out, format);
957 
958         do_indent(out, indent+2, format);
959         pos += indent+2;
960         fprintf(out, TR("Default: %s"), parameters[i].val_default.val_str);
961 
962         print_linebreak(out, format);
963         break;
964       case BG_PARAMETER_MULTI_LIST:
965       case BG_PARAMETER_MULTI_CHAIN:
966         print_string(out, TR("{option[{suboptions}][:option[{suboptions}]...]}"), format);
967 
968         if(format == BG_HELP_FORMAT_MAN)
969           fprintf(out, "\"");
970 
971         print_linebreak(out, format);
972 
973         pos = 0;
974 
975         do_indent(out, indent+2, format);
976         pos += indent+2;
977 
978         pos += fprintf(out, TR("Supported options: "));
979         j = 0;
980         while(parameters[i].multi_names[j])
981           {
982           if(j) pos += fprintf(out, " ");
983 
984           if(pos + strlen(parameters[i].multi_names[j]+1) > MAX_COLS)
985             {
986             fprintf(out, "\n");
987             pos = 0;
988             do_indent(out, indent+4, format);
989             pos += indent+4;
990             }
991           pos += fprintf(out, "%s", parameters[i].multi_names[j]);
992           j++;
993           }
994         fprintf(out, "\n\n");
995 
996         break;
997       case BG_PARAMETER_TIME:
998         print_string(out, TR("{[[HH:]MM:]SS} ("), format);
999         if(parameters[i].val_min.val_time < parameters[i].val_max.val_time)
1000           {
1001           gavl_time_prettyprint(parameters[i].val_min.val_time, time_string);
1002           fprintf(out, "%s..", time_string);
1003 
1004           gavl_time_prettyprint(parameters[i].val_max.val_time, time_string);
1005           fprintf(out, "%s, ", time_string);
1006           }
1007         gavl_time_prettyprint(parameters[i].val_default.val_time, time_string);
1008         fprintf(out, TR("default: %s)"), time_string);
1009 
1010         if(format == BG_HELP_FORMAT_MAN)
1011           fprintf(out, "\"");
1012         print_linebreak(out, format);
1013 
1014         do_indent(out, indent+2, format);
1015         pos += indent+2;
1016         fprintf(out, TR("Seconds can be fractional (i.e. with decimal point)\n"));
1017         break;
1018       case BG_PARAMETER_POSITION:
1019         fprintf(out, TR("<x>,<y> (default: %.3f,%.3f)"),
1020                 parameters[i].val_default.val_pos[0],
1021                 parameters[i].val_default.val_pos[1]);
1022         if(format == BG_HELP_FORMAT_MAN)
1023           fprintf(out, "\"");
1024         print_linebreak(out, format);
1025 
1026         do_indent(out, indent+2, format);
1027         pos += indent+2;
1028 
1029         fprintf(out, TR("<r>, <g> and <b> are in the range 0.0..1.0"));
1030         if(format != BG_HELP_FORMAT_MAN)
1031           fprintf(out, "\n");
1032         else
1033           fprintf(out, "\n.P\n");
1034         break;
1035 
1036 
1037       }
1038 
1039     do_indent(out, indent+2, format);
1040     pos += indent+2;
1041 
1042     fprintf(out, "%s", TR_DOM(parameters[i].long_name));
1043 
1044     print_linebreak(out, format);
1045 
1046     if(parameters[i].help_string)
1047       {
1048       dump_string_term(out, parameters[i].help_string, indent, translation_domain, format);
1049       print_linebreak(out, format);
1050       }
1051 
1052     /* Print suboptions */
1053 
1054     if(parameters[i].multi_parameters)
1055       {
1056       j = 0;
1057       while(parameters[i].multi_names[j])
1058         {
1059         if(parameters[i].multi_parameters[j])
1060           {
1061           do_indent(out, indent+2, format);
1062           pos += indent+2;
1063           //          print_linebreak(out, format);
1064 
1065           if(parameters[i].type == BG_PARAMETER_MULTI_MENU)
1066             {
1067             if(parameters[i].opt)
1068               tmp_string = bg_sprintf(TR("Suboptions for %s=%s"),
1069                                       parameters[i].opt,parameters[i].multi_names[j]);
1070             else
1071               tmp_string = bg_sprintf(TR("Suboptions for %s=%s"),
1072                                       parameters[i].name,parameters[i].multi_names[j]);
1073             }
1074           else
1075             {
1076             tmp_string = bg_sprintf(TR("Suboptions for %s"),
1077                                     parameters[i].multi_names[j]);
1078             }
1079           print_bold(out, tmp_string, format);
1080           free(tmp_string);
1081           print_linebreak(out, format);
1082 
1083           //          print_linebreak(out, format);
1084           //          print_linebreak(out, format);
1085           print_help_parameters(indent+2, parameters[i].multi_parameters[j], format);
1086           }
1087         j++;
1088         }
1089       }
1090 
1091     i++;
1092     }
1093 
1094   if(format == BG_HELP_FORMAT_MAN)
1095     fprintf(out, ".RE\n");
1096   else if(format == BG_HELP_FORMAT_TEXI)
1097     fprintf(out, "@end table\n");
1098 
1099   }
1100 
bg_cmdline_print_help_parameters(const bg_parameter_info_t * parameters,bg_help_format_t format)1101 void bg_cmdline_print_help_parameters(const bg_parameter_info_t * parameters,
1102                                       bg_help_format_t format)
1103   {
1104   print_help_parameters(0, parameters, format);
1105   }
1106 
bg_cmdline_init(const bg_cmdline_app_data_t * data)1107 void bg_cmdline_init(const bg_cmdline_app_data_t * data)
1108   {
1109   app_data = data;
1110   }
1111