File Coverage

lib/ChordPro.pm
Criterion Covered Total %
statement 314 501 62.6
branch 87 242 35.9
condition 33 127 25.9
subroutine 31 45 68.8
pod 0 9 0.0
total 465 924 50.3


line stmt bran cond sub pod time code
1             #! perl
2              
3 90     90   377686 use v5.26;
  90         349  
4              
5             package ChordPro;
6              
7 90     90   42162 use ChordPro::Logger;
  90         289  
  90         3424  
8 90     90   1419 use ChordPro::Files;
  90         201  
  90         14204  
9 90     90   50542 use ChordPro::Utils;
  90         387  
  90         16159  
10 90     90   57403 use ChordPro::Chords;
  90         471  
  90         5244  
11 90     90   59066 use ChordPro::Output::Common;
  90         453  
  90         8934  
12              
13             # Single line for stupid tools.
14 90     90   52501 use ChordPro::Version; our $VERSION = $ChordPro::Version::VERSION;
  90         660  
  90         7392  
15              
16             =head1 NAME
17              
18             ChordPro - A lyrics and chords formatting program
19              
20             =head1 SYNOPSIS
21              
22             perl -MChordpro -e run -- [ options ] [ file ... ]
23              
24             When the associated B program has been installed correctly:
25              
26             chordpro [ options ] [ file ... ]
27              
28             =head1 DESCRIPTION
29              
30             B will read one or more text files containing the lyrics of
31             one or many songs plus chord information. B will then
32             generate a photo-ready, professional looking, impress-your-friends
33             sheet-music suitable for printing on your nearest printer.
34              
35             Typical ChordPro input:
36              
37             {title: Swing Low Sweet Chariot}
38             {subtitle: Traditional}
39              
40             {start_of_chorus}
41             Swing [D]low, sweet [G]chari[D]ot,
42             Comin' for to carry me [A7]home.
43             Swing [D7]low, sweet [G]chari[D]ot,
44             Comin' for to [A7]carry me [D]home.
45             {end_of_chorus}
46              
47             # Verse
48             I [D]looked over Jordan, and [G]what did I [D]see,
49             Comin' for to carry me [A7]home.
50             A [D]band of angels [G]comin' after [D]me,
51             Comin' for to [A7]carry me [D]home.
52              
53             {c: Chorus}
54              
55             B is a rewrite of the Chordii program.
56              
57             For more information about the ChordPro file format, see
58             L.
59              
60             =cut
61              
62             ################ Common stuff ################
63              
64 90     90   633 use strict;
  90         208  
  90         3033  
65 90     90   521 use warnings;
  90         186  
  90         6141  
66 90     90   590 use Carp;
  90         194  
  90         6283  
67 90     90   729 use Text::ParseWords ();
  90         191  
  90         4299  
68              
69             ################ The Process ################
70              
71             package main;
72              
73             our $options;
74             our $config;
75              
76             package ChordPro;
77              
78 90     90   50273 use ChordPro::Paths;
  90         371  
  90         14328  
79 90     90   816 use Encode qw(decode_utf8);
  90         194  
  90         144013  
80              
81             sub xximport {
82             # Add private library.
83 0     0 0 0 my $lib = CP->privlib;
84 0         0 for ( @INC ) {
85 0 0       0 return if $_ eq $lib;
86             }
87 0         0 unshift( @INC, $lib );
88             }
89              
90             sub ::run {
91 91     91   3032721 binmode(STDERR, ':utf8');
92 91         437 binmode(STDOUT, ':utf8');
93 91         351 for ( @ARGV ) {
94 645 100       3791 next if ref ne "";
95 633         3241 $_ = decode_utf8($_);
96             }
97              
98 91         818 $options = app_setup( "ChordPro", $VERSION );
99 91 50       404 $options->{trace} = 1 if $options->{debug};
100 91 50       368 $options->{verbose} = 1 if $options->{trace};
101 91 50       354 $options->{verbose} = 9 if $options->{debug};
102 91         407 main();
103             }
104              
105             sub main {
106 91     91 0 294 my ($opts) = @_;
107 91 50       312 $options = { %$options, %$opts } if $opts;
108 91 50       427 warn("ChordPro invoked: @{$options->{_argv}}\n") if $options->{debug};
  0         0  
109 91         385 chordpro();
110              
111             }
112              
113             sub chordpro {
114              
115             # Establish backend.
116 91     91 0 304 my $of = $options->{output};
117              
118             # Progress callback, if any.
119             progress( callback => $options->{progress_callback}, index => -1 )
120 91 50       1970 if $options->{progress_callback};
121              
122 91 50       9255 if ( $options->{'convert-config'} ) {
123 0 0       0 die("\"--convert-config\" requires a single config file name\n")
124             if @ARGV;
125 0         0 return ChordPro::Config::convert_config( $options->{'convert-config'}, $of );
126             }
127              
128 91 50 33     780 if ( defined($of) && $of ne "" ) {
    0          
129 91 100       3054 if ( $of =~ /\.pdf$/i ) {
    50          
    50          
    100          
    50          
    100          
    100          
    50          
    50          
    50          
    50          
130 8   50     62 $options->{generate} ||= "PDF";
131             }
132             elsif ( $of =~ /\.ly$/i ) {
133 0   0     0 $options->{generate} ||= "LilyPond";
134             }
135             elsif ( $of =~ /\.(tex|ltx)$/i ) {
136 0   0     0 $options->{generate} ||= "LaTeX";
137             }
138             elsif ( $of =~ /\.cho$/i ) {
139 6   50     46 $options->{generate} ||= "ChordPro";
140             }
141             elsif ( $of =~ /\.msp$/i ) {
142 0   0     0 $options->{generate} ||= "ChordPro";
143 0         0 $options->{'backend-option'}->{variant} = "msp";
144             }
145             elsif ( $of =~ /\.(crd|txt)$/i ) {
146 9   50     68 $options->{generate} ||= "Text";
147             }
148             elsif ( $of =~ /\.html?$/i ) {
149 3   50     20 $options->{generate} ||= "HTML";
150             }
151             elsif ( $of =~ /\.mma?$/i ) {
152 0   0     0 $options->{generate} ||= "MMA";
153             }
154             elsif ( $of =~ /\.(md|markdown)$/i ) {
155 0   0     0 $options->{generate} ||= "Markdown";
156             }
157             elsif ( $of =~ /\.meta$/i ) {
158 0   0     0 $options->{generate} ||= "Meta";
159             }
160             elsif ( $of =~ /\.(debug)$/i ) {
161 0   0     0 $options->{generate} ||= "Debug";
162             }
163             }
164             elsif ( -t STDOUT ) {
165             # No output, and stdout is terminal.
166             # Derive output name from input name.
167 0 0 0     0 if ( @ARGV > 1 || ( $options->{'dump-chords'} && !@ARGV ) ) {
      0        
168             # No default if more than one input document.
169 0         0 die("Please use \"--output\" to specify the output file name\n");
170             }
171 0         0 my $f = CP->sibling( $ARGV[0], ext => ".pdf" );
172 0         0 $options->{output} = $f;
173 0 0       0 warn("Writing output to $f\n") if $options->{verbose};
174             }
175             else {
176             # Write output to stdout.
177 0         0 $options->{output} = "-";
178             }
179              
180 91   50     428 $options->{generate} ||= "PDF";
181 91         495 my $pkg = "ChordPro::Output::".$options->{generate};
182 91         14797 eval "require $pkg;";
183 91 50       693 die("No backend for ", $options->{generate}, "\n$@") if $@;
184 91         495 $options->{backend} = $pkg;
185 91 50 33     475 $pkg->version if $options->{verbose} && $pkg->can("version");
186              
187             # One configurator to bind them all.
188 90     90   7170 use ChordPro::Config;
  90         368  
  90         7979  
189 91         684 $config = ChordPro::Config::configurator({});
190              
191             # Parse the input(s).
192 90     90   58093 use ChordPro::Songbook;
  90         806  
  90         226038  
193 91         1867 my $s = ChordPro::Songbook->new;
194 91         233 my $res;
195              
196             # Shortcut a2crd conversion.
197 91 100       583 if ( $options->{a2crd} ) {
198 19         249 require ChordPro::A2Crd;
199 19         149 $res = ChordPro::A2Crd::a2crd();
200 19         110 push( @$res, '' );
201 19         288 goto WRITE_OUTPUT;
202             }
203              
204             # Check for metadata in filelist. Actually, this works on the
205             # command line as well, but don't tell anybody.
206             progress( phase => "Parsing", index => 0,
207 72 50       363 total => 0+grep { !/^--/ } @ARGV )
  0         0  
208             if @ARGV > 1;
209              
210 72         168 my %gopts;
211 72         269 foreach my $file ( @ARGV ) {
212              
213 72         280 my @w = ( $file );
214 72 50 33     1379 if ( $file =~ /(^|\s)--\w+/ || $file =~ /^["']/ ) {
215 0         0 @w = Text::ParseWords::shellwords($file);
216             }
217 72         447 my %meta;
218             my %defs;
219 72         0 my @cfg;
220 72         0 my %opts;
221 72 0 33     683 die("Error in filelist: $file\n")
      33        
222             unless Getopt::Long::GetOptionsFromArray
223             ( \@w, \%opts, 'config=s@' => \@cfg, 'meta=s%' => \%meta,
224             'define=s%' => \%defs,
225             'title=s', 'subtitle=s', 'dir:s', 'filelist:s',
226             )
227             && ( ( @w == 1 && ! keys(%opts) ) # filename
228             || ( @w == 0 && keys(%opts) ) # options
229             );
230              
231 72         61224 for ( qw( title subtitle ) ) {
232 144 50       587 next unless defined $opts{$_};
233 0         0 $options->{$_} = $opts{$_};
234             }
235 72         241 for ( qw( filelist dir ) ) {
236 144 50       528 next unless defined $opts{$_};
237 0 0       0 $gopts{$_} = $opts{$_} eq "" ? undef : $opts{$_};
238             }
239 72 50       258 unless ( @w ) {
240 0 0 0     0 progress( msg => $file ) if @ARGV > 1 && $file !~ /^--/;
241 0         0 next;
242             }
243              
244 72         221 $file = $w[0];
245 72 50 33     420 if ( defined($gopts{dir})
246             && !fn_is_absolute($file) ) {
247 0         0 $file = fn_catfile( $gopts{dir}, $file );
248             }
249 72         486 my $opts = { meta => { map { $_, [ $meta{$_} ] } keys %meta },
  0         0  
250             defs => \%defs };
251 72 50       279 if ( @cfg ) {
252 0         0 $opts->{meta}->{__config} = \@cfg;
253             }
254 72         353 $opts->{generate} = $options->{generate};
255             # Wx runs on temp files, so pass real filename in.
256 72         257 $opts->{filesource} = $options->{filesource};
257 72 50       285 progress( msg => $file ) if @ARGV > 1;
258 72         567 $s->parse_file( $file, $opts );
259             }
260              
261 72 50       424 if ( $options->{'dump-chords'} ) {
262 0         0 my $d = ChordPro::Song->new;
263 0         0 $d->{title} = "ChordPro $VERSION Built-in Chords";
264 0         0 $d->{subtitle} = [ "https://www.chordpro.org" ];
265 0         0 my @body;
266             my @chords;
267              
268 0         0 my $prev = "";
269 0         0 foreach my $c ( @{ ChordPro::Chords::chordnames() } ) {
  0         0  
270 0 0       0 next if $c =~ /^n\.?c\.?$/i;
271 0 0 0     0 if ( $c =~ /^(.[b#]?)/ and $1 ne $prev ) {
272 0         0 $prev = $1;
273 0 0       0 push( @body, { type => "diagrams",
274             context => "",
275             origin => "__CLI__",
276             chords => [ @chords ]
277             } ) if @chords;
278 0         0 @chords = ();
279             }
280 0         0 push( @chords, $c );
281 0         0 $d->{chordsinfo}->{$c} = ChordPro::Chords::known_chord($c);
282             }
283              
284 0 0       0 push( @body, { type => "diagrams",
285             context => "",
286             origin => "__CLI__",
287             chords => [ @chords ]
288             } ) if @chords;
289              
290 0         0 $d->{body} = \@body;
291 0 0 0     0 if ( @{ $s->{songs} } == 1
  0         0  
292             && !exists $s->{songs}->[0]->{body} ) {
293 0         0 $s->{songs} = [ $d ];
294             }
295             else {
296 0         0 push( @{ $s->{songs} }, $d );
  0         0  
297             }
298             }
299              
300             # Try interpolations.
301 72 50       315 if ( $of ) {
302 72         466 my $f = fmt_subst( $s->{songs}->[0], $of );
303 72 50       8065 if ( $f ne $of ) {
304             # Replace most non-alpha by underscore (but keep the extension).
305 0         0 $f =~ s;(?!\.\w+$)[^\w/-];_;g;
306 0 0       0 warn("Writing output to $f\n") if $options->{verbose};
307 0         0 $options->{output} = $f;
308             }
309             }
310              
311             # Call backend to produce output.
312 72         1136 $res = $pkg->generate_songbook($s);
313 72 100       12939 return $res if $options->{output} eq '*';
314              
315             WRITE_OUTPUT:
316             # Some backends write output themselves, others return an
317             # array of lines to be written.
318 79 100 66     720 if ( $res && @$res > 0 ) {
319 71 50 33     470 if ( $of && $of ne "-" ) {
320 71         514 my $fd = fs_open( $of, '>:utf8' );
321 71 100       489 push( @$res, '' ) unless $res->[-1] eq '';
322 71         194 print { $fd } ( join( "\n", @$res ) );
  71         4843  
323 71         53310 close($fd);
324             }
325             else {
326 0         0 binmode( STDOUT, ":utf8" );
327 0 0       0 push( @$res, '' ) unless $res->[-1] eq '';
328 0         0 print( join( "\n", @$res ) );
329             }
330             # Don't close STDOUT!
331             }
332             }
333              
334             sub ::dump {
335 90     90   53213 use ChordPro::Dumper;
  90         445  
  90         27268  
336 0     0   0 ddp(@_);
337             }
338              
339             ################ Options and Configuration ################
340              
341             =head1 COMMAND LINE OPTIONS
342              
343             =over 4
344              
345             =item B<--about> (short: B<-A>)
346              
347             Prints version information about the ChordPro program. No other
348             processing will be done.
349              
350             =item B<--back-matter=>I
351              
352             Appends the contents of the named PDF document to the output. This can
353             be used to produce documents with back matter pages.
354              
355             =item B<--config=>I (shorter: B<--cfg>)
356              
357             A JSON file that defines the behaviour of the program and the layout
358             of the output. See L for details.
359              
360             This option may be specified more than once. Each additional config
361             file overrides the corresponding definitions that are currently
362             active.
363              
364             =item B<--cover=>I
365              
366             Prepends the contents of the named PDF document to the output. This can
367             be used to add cover pages.
368              
369             See also B<--title>.
370              
371             =item B<--csv>
372              
373             When generating PDF output, also write a CSV file with titles and page
374             numbers. Some tools, e.g., MobileSheets, can use the CSV to process
375             the PDF as a collection of independent songs.
376              
377             The CSV has the same name as the PDF, with extension C<.pdf> replaced
378             by C<.csv>.
379              
380             =item B<--decapo>
381              
382             Eliminate capo settings by transposing the song.
383              
384             =item B<--diagrams=>I
385              
386             Prints diagrams of chords used in a song.
387              
388             I can be C to print all chords used, C to only print
389             the user-defined chords, and C to suppress printing of chord
390             diagrams.
391              
392             =item B<--encoding=>I
393              
394             Specify the encoding for input files. Default is UTF-8.
395             ISO-8859.1 (Latin-1) encoding is automatically sensed.
396              
397             =item B<--filelist=>I
398              
399             Read the names of the files to be processed from the named file.
400              
401             This option may be specified multiple times.
402              
403             Song file names listed on the command line are processed I the
404             files from the filelist arguments.
405              
406             =item B<--front-matter=>I
407              
408             Prepends the contents of the named PDF document to the output. This can
409             be used to produce documents with front matter pages.
410              
411             =item B<--lyrics-only> (short: B<-l>)
412              
413             Only prints lyrics. All chords are suppressed.
414              
415             Useful to make prints for singers and other musicians that do not
416             require chords.
417              
418             =item B<--no-csv>
419              
420             Suppresses generating the CSV file. See B<--toc>.
421              
422             =item B<--no-strict>
423              
424             Enables liberal interpretation of the input with regard to the
425             ChordPro standard. Most notably, unknown directives will not
426             not flagged as warnings but silently ignored.
427              
428             This makes it more convenient to process ChordPro files have custom
429             directives.
430              
431             =item B<--no-toc>
432              
433             Suppresses the table of contents. See B<--toc>.
434              
435             =item B<--output=>I (short: B<-o>)
436              
437             Designates the name of the output file where the results are written
438             to.
439              
440             The filename extension determines the type of the output. It should
441             correspond to one of the backends that are currently supported:
442              
443             =over 6
444              
445             =item pdf
446              
447             Portable document format (PDF).
448              
449             =item txt
450              
451             A textual representation of the input, mostly for visual inspection.
452              
453             =item cho
454              
455             A functional equivalent version of the ChordPro input.
456              
457             =back
458              
459             =item B<--start-page-number=>I (short: B<-p>)
460              
461             Sets the starting page number for the output.
462              
463             =item B<--strict>
464              
465             Requires the input to be strictly compliant to the ChordPro standard.
466              
467             This is enabled by default. See also B<--nostrict>.
468              
469             =item B<--subtitle=>I
470              
471             Subtitle (for songbooks).
472              
473             =item B<--title=>I
474              
475             Title (for songbooks).
476              
477             If specified and a table of contents is requested, a nice coverpage
478             will be added.
479              
480             Note that B<--title> overrides B<--cover>.
481              
482             =item B<--toc> (short: B<-i>)
483              
484             Includes a table of contents.
485              
486             By default a table of contents is included in the PDF output when
487             it contains more than one song.
488              
489             =item B<--transpose=>I (short: -x)
490              
491             Transposes all songs by I semi-tones. Note that I may be
492             specified as B<+>I to transpose upward, using sharps, or as
493             B<->I to transpose downward, using flats.
494              
495             =item B<--version> (short: B<-V>)
496              
497             Prints the program version and exits.
498              
499             =back
500              
501             =head2 Chordii compatibility options
502              
503             The following Chordii command line options are recognized. Note that
504             not all of them actually do something.
505              
506             Options marked with * are better specified in the config file.
507              
508             B Chordii used the term _grid_ for chord diagrams. It
509             should not be confused with ChordPro grids.
510              
511             =over 4
512              
513             =item B<--text-font=>I (short: B<-T>) *
514              
515             Sets the font used to print lyrics and comments.
516              
517             I can be either a full path name to a TrueType font file, or the
518             name of one of the standard fonts. See section L for more
519             details.
520              
521             =item B<--text-size=>I (short: B<-t>) *
522              
523             Sets the font size for lyrics and comments.
524              
525             =item B<--chord-font=>I (short: B<-C>) *
526              
527             Sets the font used to print the chord names.
528              
529             I can be either a full path name to a TrueType font file, or the
530             name of one of the standard fonts. See section L for more
531             details.
532              
533             =item B<--chord-size=>I (short: B<-c>) *
534              
535             Sets the font size for the chord names.
536              
537             =item B<--chord-grid-size=>I (short: B<-s>) *
538              
539             Sets the total width of a chord diagram.
540              
541             =item B<--chord-grids>
542              
543             Prints chord diagrams of all chords used in a song.
544              
545             =item B<--no-chord-grids> (short: B<-G>) *
546              
547             Disables printing of chord diagrams of the chords used in a song.
548              
549             =item B<--easy-chord-grids>
550              
551             Not supported.
552              
553             =item B<--no-easy-chord-grids> (short: B<-g>)
554              
555             Not supported.
556              
557             =item B<--chord-grids-sorted> (short: B<-S>) *
558              
559             Prints chord diagrams of the chords used in a song, ordered by key and
560             type.
561              
562             =item B<--no-chord-grids-sorted> *
563              
564             Prints chord diagrams in the order they appear in the song.
565              
566             =item B<--user-chord-grids> *
567              
568             Prints chord diagrams of all user defined chords used in a song.
569              
570             =item B<--even-pages-number-left> (short B<-L>)
571              
572             Not supported. Use C in the config instead.
573              
574             =item B<--odd-pages-number-left>
575              
576             Not supported. Use C in the config instead.
577              
578             =item B<--page-size=>I (short: B<-P>) *
579              
580             Specifies the page size for the PDF output, e.g. C (default), C.
581              
582             =item B<--single-space> (short B<-a>)) *
583              
584             When a lyrics line has no chords associated, suppresses the vertical
585             space normally occupied by the chords.
586              
587             =item B<--vertical-space=>I (short: B<-w>) *
588              
589             Adds some extra vertical space between the lines.
590              
591             =item B<--2-up> (short: B<-2>)
592              
593             Not supported.
594              
595             =item B<--4-up> (short: B<-4>)
596              
597             Not supported.
598              
599             =item B<--page-number-logical> (short: B<-n>)
600              
601             Not supported.
602              
603             =item B<--dump-chords> (short: B<-D>)
604              
605             Dumps a list of built-in chords in a form dependent of the backend used.
606             The PDF backend will produce neat pages of chord diagrams.
607             The ChordPro backend will produce a list of C directives.
608              
609             =item B<--dump-chords-text> (short: B<-d>)
610              
611             Dumps a list of built-in chords in the form of C directives,
612             and exits.
613              
614             =back
615              
616             =head2 Configuration options
617              
618             See L for details about the configuration
619             files.
620              
621             Note that missing default configuration files are silently ignored.
622             Also, B will never create nor write configuration files.
623              
624             =over
625              
626             =item B<--nosongconfig>
627              
628             Don't use song specific config files, even if they exist.
629              
630             =item B<--sysconfig=>I
631              
632             Designates a system specific config file.
633              
634             The default system config file depends on the operating system and user
635             environment. A common value is C on Linux systems.
636              
637             This is the place where the system manager can put settings like the
638             paper size, assuming that all printers use the same size.
639              
640             =item B<--nosysconfig>
641              
642             Don't use the system specific config file, even if it exists.
643              
644             =item B<--userconfig=>I
645              
646             Designates the config file for the user.
647              
648             The default user config file depends on the operating system and user
649             environment. Common values are C<$HOME/.config/chordpro/chordpro.json>
650             and C<$HOME/.chordpro/chordpro.json>, where C<$HOME> indicates the
651             user home directory.
652              
653             Here you can put settings for your preferred fonts and other layout
654             parameters that you want to apply to all B runs.
655              
656             =item B<--nouserconfig>
657              
658             Don't use the user specific config file, even if it exists.
659              
660             =item B<--config=>I (shorter: B<--cfg>)
661              
662             Designates the config file specific for this run.
663              
664             Default is a file named C in the current directory.
665              
666             Here you can put settings that apply to the files in this
667             directory only.
668              
669             You can specify multiple config files. The settings are accumulated.
670              
671             =item B<--noconfig>
672              
673             Don't use the specific config file, even if it exists.
674              
675             =item B<--define=>I
676              
677             Sets a configuration item. I must be in the format of
678             colon-separated configuration keys, an equal sign, and the value. For
679             example, the equivalent of B<--diagrams=none> is
680             B<--define=diagrams.show=0>.
681              
682             B<--define> may be used multiple times to set multiple items.
683              
684             =item B<--no-default-configs> (short: B<-X>)
685              
686             Do not use any config files except the ones mentioned explicitly on
687             the command line.
688              
689             This guarantees that the program is running with the default
690             configuration.
691              
692             =item B<--print-template-config>
693              
694             Prints a simplified template configuration to standard output, and
695             exits. The configuration is commented to explain its contents.
696              
697             The config contains most of the ChordPro configuration items, all
698             commented out. It is easy to get started with configuring ChordPro
699             by enabling and modifyng just a few items at a time.
700              
701             =item B<--print-default-config>
702              
703             If used once, behaves like `--print-template-config`. This is to avoid
704             confusing novice users.
705              
706             To get the full default configuration, repeat this option.
707              
708             =item B<--print-final-config>
709              
710             Prints the final configuration (after processing all system, user and
711             other config files) to standard output, and exits.
712              
713             =item B<--convert-config=>I
714              
715             This option requires a single file name argument.
716              
717             The specified config file is loaded and immedeately written out in
718             standard format, including schema comments. After this, the program
719             exits. B
720              
721             Output goes to standard output unless `--output` is used to specify an
722             alternative.
723              
724             All other options are ignored.
725              
726             =back
727              
728             =head2 Miscellaneous options
729              
730             =over
731              
732             =item B<--help> (short: -h)
733              
734             Prints a help message. No other output is produced.
735              
736             =item B<--manual>
737              
738             Prints the manual page. No other output is produced.
739              
740             =item B<--ident>
741              
742             Shows the program name and version.
743              
744             =item B<--verbose>
745              
746             Provides more verbose information of what is going on.
747              
748             =back
749              
750             =cut
751              
752 90     90   79388 use Getopt::Long 2.13 qw( :config no_ignorecase );
  90         2001014  
  90         4342  
753              
754             # Package name.
755             my $my_package;
756             # Program name and version.
757             my ($my_name, $my_version);
758             my %configs;
759              
760             sub app_setup {
761 91     91 0 484 my ($appname, $appversion, %args) = @_;
762 91         859 my $help = 0; # handled locally
763 91         226 my $manual = 0; # handled locally
764 91         240 my $ident = 0; # handled locally
765 91         220 my $about = 0; # handled locally
766 91         264 my $version = 0; # handled locally
767 91         233 my $defcfg = 0; # handled locally
768 91         221 my $fincfg = 0; # handled locally
769 91         199 my $deltacfg = 0; # handled locally
770 91         240 my $tmplcfg = 0; # handled locally
771 91         233 my $dump_chords = 0; # handled locally
772              
773             # Package name.
774 91         339 $my_package = $args{package};
775             # Program name and version.
776 91 50       379 if ( defined $appname ) {
777 91         308 ($my_name, $my_version) = ($appname, $appversion);
778             }
779             else {
780 0         0 ($my_name, $my_version) = qw( MyProg 0.01 );
781             }
782              
783 91         341 my $app_lc = lc($my_name);
784 91 50       463 if ( $app_lc eq "a2crd" ) {
785 0         0 $app_lc = "chordpro";
786 0         0 unshift( @ARGV, "--a2crd" );
787             }
788              
789             # Config files.
790 91         250 %configs = %{ CP->configs };
  91         697  
791              
792 91         2108 my $options =
793             {
794             verbose => 0, # verbose processing
795             encoding => "", # input encoding, default UTF-8
796              
797             ### ADDITIONAL CLI OPTIONS ###
798              
799             'vertical-space' => 0, # extra vertical space between lines
800              
801             ### NON-CLI OPTIONS ###
802              
803             'chords-column' => 0, # chords in a separate column
804              
805             # Development options (not shown with -help).
806             debug => 0, # debugging
807             trace => 0, # trace (show process)
808              
809             # Service.
810             _package => $my_package,
811             _name => $my_name,
812             _version => $my_version,
813             _stdin => \*STDIN,
814             _stdout => \*STDOUT,
815             _stderr => \*STDERR,
816             _argv => [ @ARGV ],
817             };
818              
819             # Colled command line options in a hash, for they will be needed
820             # later.
821 91         270 my $clo = {};
822              
823             # When running in reference mode, we carefully defeat everything
824             # the user could change to the built-in default config.
825 91         257 my $reference = 0;
826              
827             # Sorry, layout is a bit ugly...
828             my $ok =
829             GetOptions
830             ($clo,
831              
832             ### Options ###
833              
834             "a2crd!", # perform ascii to cho
835             "crd", # input is ascii, not cho
836             "output|o=s", # Saves the output to FILE
837             "generate=s",
838             "backend-option|bo=s\%",
839             "diagrams=s", # Prints chord diagrams
840             "encoding=s",
841             "csv!", # Generates contents CSV
842             "front-matter=s", # Front matter page(s)
843             "cover=s", # Cover page(s)
844             "back-matter|back=s", # Back matter page(s)
845             "filelist=s@", # List of input files
846             "title=s", # Title (for books)
847             "subtitle=s", # Subtitle (for books)
848             "meta=s\%", # Command line meta data
849             "decapo", # remove capo
850             "fragment|F", # partial (incomplete) song
851             "strict!", # strict conformance
852              
853             ### Experimental ###
854              
855             "progress_callback=s",
856              
857             ### Standard Chordii Options ###
858              
859             "about|A+" => \$about, # About...
860             "chord-font|C=s", # Sets chord font
861             "chord-grid-size|s=f", # Sets chord diagram size [30]
862             "chord-grids-sorted|S!", # Prints chord diagrams ordered
863             "chord-size|c=i", # Sets chord size [9]
864             "dump-chords|D", # Dumps chords definitions (PostScript)
865             "dump-chords-text|d" => \$dump_chords, # Dumps chords definitions (Text)
866 0     0   0 "dump-chords-json" => sub { $dump_chords = 2}, # Dumps instrument defs (json).
867             "even-pages-number-left|L", # Even pages numbers on left
868             "odd-pages-number-left", # Odd pages numbers on left
869             "lyrics-only|l", # Only prints lyrics
870 0     0   0 "G" => sub { $clo->{'chord-grids'} = 0 },
871             "chord-grids!", # En[dis]ables printing of chord diagrams
872             "easy-chord-grids|g!", # Do[esn't] print diagrams for built-in "easy" chords. Ignored.
873             "page-number-logical|n", # Numbers logical pages, not physical
874             "page-size|P=s", # Specifies page size [letter, a4 (default)]
875             "single-space|a!", # Automatic single space lines without chords
876             "start-page-number|p=i", # Starting page number [1]
877             "text-size|t=i", # Sets text size [12]
878             "text-font|T=s", # Sets text font
879 0     0   0 "i" => sub { $clo->{toc} = 1 },
880             "toc!", # Generates a table of contents
881             "transpose|x=i", # Transposes by N semi-tones
882             "transcode|xc=s", # Transcodes to another notation
883             "user-chord-grids!", # Do[esn't] print diagrams for user defined chords.
884             "version|V" => \$version, # Prints version and exits
885             "vertical-space|w=f", # Extra vertical space between lines
886             "2-up|2", # 2 pages per sheet
887             "4-up|4", # 4 pages per sheet
888              
889             ### Configuration handling ###
890              
891             'config|cfg=s@',
892             'noconfig|no-config',
893             'sysconfig=s',
894             'nosysconfig|no-sysconfig',
895             'nolegacyconfig|no-legacyconfig', # legacy
896             'userconfig=s',
897             'nosongconfig|no-songconfig',
898             'nouserconfig|no-userconfig',
899             'nodefaultconfigs|no-default-configs|X',
900             'define=s%',
901             'print-default-config+' => \$defcfg,
902             'print-final-config' => \$fincfg,
903             'print-delta-config' => \$deltacfg,
904             'print-template-config' => \$tmplcfg,
905             'convert-config=s',
906              
907             # This aborts option scanning.
908 0     0   0 'reference|R' => sub { $reference++;
909 0         0 CORE::die("!FINISH!"); },
910              
911             ### Standard options ###
912              
913             'ident' => \$ident,
914             'help|h|?' => \$help,
915 0     0   0 'help-config' => sub { $manual = 2 },
916             'manual' => \$manual,
917             'verbose|v+',
918 0     0   0 I => sub { $clo->{progress_callback} = "warn" },
919 91         3181 'trace',
920             'debug+',
921              
922             );
923              
924             # If --reference was encountered, retry with a very restricted set
925             # of options.
926 91 50       634962 if ( $reference ) {
927 0         0 @ARGV = @{ $options->{_argv} };
  0         0  
928 0         0 warn("Running in reference mode.\n");
929 0         0 $ok =
930             GetOptions
931             ($clo,
932              
933             ### Options for reference run ###
934              
935             "output|o=s", # Saves the output to FILE
936             "strict!", # strict conformance
937             "about|A" => \$about, # About...
938             "version|V" => \$version, # Prints version and exits
939             'reference|R',
940              
941             ### Standard options ###
942              
943             'ident' => \$ident,
944             'help|h|?' => \$help,
945             'verbose|v+',
946             'trace',
947             'debug+',
948              
949             );
950 0         0 $clo->{nodefaultconfigs} = 1;
951 0         0 $clo->{nosongconfig} = 1;
952 0         0 $::options->{reference} = 1;
953             }
954              
955 91   33     951 $clo->{trace} ||= $clo->{debug};
956 91   33     695 $clo->{verbose} ||= $clo->{trace};
957 91 50 0     684 $clo->{progress_callback} //= "warn" if $clo->{verbose};
958              
959 91 50       367 unless ( $ok ) {
960             # GNU convention: message to STDERR upon failure.
961 0         0 app_usage(\*STDERR, 2);
962             }
963              
964             my $pod2usage = sub {
965             # Load Pod::Usage only if needed.
966 0     0   0 require Pod::Usage;
967 0         0 Pod::Usage->import;
968 0 0       0 my $f = $manual == 2 ? "Config.pod" : "ChordPro.pod";
969 0         0 unshift( @_, -input => CP->findres( $f, class => "pod" ) );
970 0         0 &pod2usage;
971 91         668 };
972              
973             # GNU convention: message to STDOUT upon request.
974 91 50 33     1217 app_ident(\*STDOUT) if $ident || $clo->{verbose} || $help || $manual;
      33        
      33        
975 91 50 33     535 if ( $manual or $help ) {
976 0 0       0 app_usage(\*STDOUT, 0) if $help;
977 0 0       0 $pod2usage->(VERBOSE => 2) if $manual;
978             }
979 91 50       304 app_ident(\*STDOUT, 0) if $version;
980              
981             # If the user specified a config, it must exist.
982             # Otherwise, set to a default.
983 91         305 for my $config ( qw(sysconfig userconfig) ) {
984 182         592 for ( $clo->{$config} ) {
985 182 50       534 if ( defined($_) ) {
986 0 0       0 die("$_: $!\n") unless -r $_;
987 0         0 next;
988             }
989             # Use default.
990 182 50       675 next if $clo->{nodefaultconfigs};
991 0 0       0 next unless $configs{$config};
992 0         0 $_ = $configs{$config};
993 0 0       0 undef($_) unless -r $_;
994             }
995             }
996 91         274 for my $config ( qw(config) ) {
997 91         422 for ( $clo->{$config} ) {
998 91 50       340 if ( defined($_) ) {
999 0         0 foreach my $c ( @$_ ) {
1000 0         0 my $try = $c;
1001             # Check for resource names.
1002 0 0       0 if ( !fs_test( 'r', $try ) ) {
1003 0         0 $try = CP->findcfg($c);
1004             }
1005 0 0 0     0 die("$c: $!\n") unless $try && fs_test( 'r', $try );
1006 0         0 $c = $try;
1007             }
1008 0         0 next;
1009             }
1010             # Use default.
1011 91 50       435 next if $clo->{nodefaultconfigs};
1012 0 0       0 next unless $configs{$config};
1013 0         0 $_ = [ $configs{$config} ];
1014 0 0       0 undef($_) unless fs_test( 'fr', $_->[0] );
1015             }
1016             }
1017             # If no config was specified, and no default is available, force no.
1018 91         260 for my $config ( qw(sysconfig userconfig config ) ) {
1019 273 50       1247 $clo->{"no$config"} = 1 unless $clo->{$config};
1020             }
1021 91   33     687 $clo->{nosongconfig} ||= $clo->{nodefaultconfigs};
1022              
1023             # Plug in command-line options.
1024 91         571 @{$options}{keys %$clo} = values %$clo;
  91         890  
1025 91         1494 $::options = $options;
1026             # warn(::dump($options), "\n") if $options->{debug};
1027              
1028             # To avoid confusion, produce a template if the user asks for a
1029             # default config.
1030             # Unless she insists...
1031 91 50       391 if ( $defcfg >= 2 ) {
1032 90     90   206808 use File::Copy;
  90         260  
  90         16926  
1033 0         0 my $cfg = fn_catfile( CP->findresdirs("config")->[-1],
1034             "chordpro.json" );
1035 0         0 binmode STDOUT => ':raw';
1036 0         0 copy( $cfg, \*STDOUT );
1037 0         0 exit 0;
1038             }
1039 91 50 33     544 if ( $tmplcfg || $defcfg ) {
1040 90     90   676 use File::Copy;
  90         236  
  90         138419  
1041 0         0 my $cfg = fn_catfile( CP->findresdirs("config")->[-1],
1042             "config.tmpl" );
1043 0         0 binmode STDOUT => ':raw';
1044 0         0 copy( $cfg, \*STDOUT );
1045 0         0 exit 0;
1046             }
1047 91 50 33     544 if ( $fincfg || $deltacfg ) {
1048 0         0 print ChordPro::Config::config_final( delta => $deltacfg );
1049 0         0 exit 0;
1050             }
1051              
1052 91 50       306 if ( $about ) {
1053 0         0 $::config = ChordPro::Config::configurator({});
1054 0         0 app_about( \*STDOUT, $about, 0 );
1055             }
1056              
1057 91 50       302 if ( $dump_chords ) {
1058 0         0 $::config = ChordPro::Config::configurator($options);
1059 0         0 require ChordPro::Chords;
1060 0         0 ChordPro::Chords::dump_chords($dump_chords);
1061 0         0 exit 0;
1062             }
1063              
1064 91 50       361 if ( $clo->{filelist} ) {
1065 0         0 my @files;
1066 0         0 foreach ( @{ $clo->{filelist} } ) {
  0         0  
1067 0         0 push( @files, "--filelist=" . qquote($_) );
1068 0         0 my $dir = fn_dirname($_);
1069 0         0 my $list = fs_load( $_, $clo );
1070 0         0 push( @files, "--dir=" . qquote($dir) );
1071 0         0 foreach ( @$list ) {
1072 0 0       0 next unless /\S/;
1073 0 0       0 next if /^#/;
1074 0         0 s/[\r\n]+$//;
1075 0         0 push( @files, $_ );
1076             }
1077 0         0 push( @files, "--filelist", "--dir" );
1078             }
1079 0 0       0 if ( @files ) {
1080 0 0       0 if ( $files[0] =~ /\.pdf$/i ) {
1081 0   0     0 $options->{'front-matter'} //= $files[0];
1082 0         0 shift(@files);
1083             }
1084 0 0       0 if ( $files[-1] =~ /\.pdf$/i ) {
1085 0   0     0 $options->{'back-matter'} //= $files[-1];
1086 0         0 pop(@files);
1087             }
1088             }
1089 0 0       0 unshift( @ARGV, @files ) if @files;
1090             }
1091              
1092             # At this point, there should be filename argument(s)
1093             # unless we're embedded or just dumping chords.
1094             app_usage(\*STDERR, 1)
1095             unless $::__EMBEDDED__
1096             || $clo->{'dump-chords'}
1097 91 50 33     1116 || $clo->{'convert-config'}
      33        
      33        
1098             || @ARGV;
1099              
1100             # Return result.
1101 91         1253 $options;
1102             }
1103              
1104             sub app_ident {
1105 0     0 0 0 my ($fh, $exit) = @_;
1106 0         0 print {$fh} ("This is ChordPro ",
1107 0 0       0 $::options->{reference} ? "reference " : "core ",
    0          
1108             $VERSION,
1109             $VERSION =~ /_/ ? " (Unsupported development snapshot)" : "",
1110             "\n"
1111             );
1112 0 0       0 exit $exit if defined $exit;
1113             }
1114              
1115             sub app_about {
1116 0     0 0 0 my ($fh, $level, $exit) = @_;
1117              
1118 0 0       0 if ( $level > 2 ) {
1119 0         0 require JSON::XS;
1120 0         0 select $fh; $| = 1; # otherwise no output on MacOS
  0         0  
1121 0         0 print ${fh} ( JSON::XS->new->canonical->
1122             # pretty->
1123             utf8->convert_blessed->encode(runtime_info()) );
1124             }
1125             else {
1126 0 0       0 print ${fh} <
1127              
1128             ChordPro: A lyrics and chords formatting program.
1129              
1130             ChordPro will read a text file containing the lyrics of one or many
1131             songs plus chord information. ChordPro will then generate a
1132             photo-ready, professional looking, impress-your-friends sheet-music
1133             suitable for printing on your nearest printer.
1134              
1135             To learn more about ChordPro, look for the man page or do
1136             "chordpro --help" for the list of options.
1137              
1138             For more information, see https://www.chordpro.org .
1139              
1140             Run-time information:
1141             EndOfAbout
1142             ::runtimeinfo( $level > 1 ? "extensive" : "normal" );
1143             }
1144 0 0       0 exit $exit if defined $exit;
1145             }
1146              
1147 90     90   946 use List::Util qw(uniq);
  90         217  
  90         199065  
1148              
1149             sub ::runtimeinfo {
1150 17   100 17   2145 my $level = shift // "normal";
1151 17         41 my %i = %{runtime_info($level)};
  17         108  
1152 17         106 my $fmt0 = " %-26.26s %-10s";
1153 17         55 my $fmt2 = $fmt0 . "\n";
1154 17         50 my $fmt3 = $fmt0 . " (%s)\n";
1155              
1156 17         39 my $msg;
1157 17         80 for ( $i{general}->{chordpro} ) {
1158 17 50       83 if ( $_->{aux} ) {
1159             $msg = sprintf( $fmt3,
1160             "ChordPro " . ($_->{type}//"core"), $_->{version},
1161 0   0     0 $_->{aux} );
1162             }
1163             else {
1164             $msg = sprintf( $fmt2,
1165 17   50     196 "ChordPro " . ($_->{type}//"core"), $_->{version} );
1166             }
1167             }
1168 17 100       79 if ( $level eq "short" ) { # used for PDF Creator info
1169 8         56 $msg =~ s/^\s+//;
1170 8         64 $msg =~ s/\s+/ /g;
1171 8         21 $msg =~ s/\n+$//;
1172 8         98 return $msg;
1173             }
1174              
1175 9         38 for ( $i{general}{perl} ) {
1176 9         71 $msg .= sprintf( $fmt3, "Perl", $_->{version}, $_->{dppath} );
1177             }
1178              
1179 9         40 for ( $i{general}{packager} ) {
1180 9 50       44 next unless defined;
1181 0         0 $msg .= sprintf( $fmt2, $_->{packager}." Packager", $_->{version} );
1182             }
1183              
1184             # Determine resource path.
1185 9         25 my @p;
1186 9         49 my $tag = "CHORDPRO_LIB";
1187 9         21 for ( @{$i{general}{library}} ) {
  9         48  
1188 0         0 $msg .= sprintf( $fmt2, $tag, $_->{dppath} );
1189 0         0 $tag = "";
1190             }
1191 9         42 for ( $i{general}{xdg_home} ) {
1192 9 50       40 next unless defined;
1193 0         0 $msg .= sprintf( $fmt2, "XDG_CONFIG_HOME", $_->{dppath} );
1194             }
1195              
1196 9         25 $tag = "Resource path";
1197 9         21 for ( @{$i{resources}} ) {
  9         33  
1198 9         55 $msg .= sprintf( $fmt2, $tag, $_->{dppath} );
1199 9         28 $tag = "";
1200             }
1201              
1202 9         29 $tag = "FONTDIR";
1203 9   50     21 for ( @{$i{general}{fontdir}//[]} ) {
  9         79  
1204 0 0       0 next unless defined;
1205 0         0 $msg .= sprintf( $fmt2, $tag, $_->{dppath} );
1206 0         0 $tag = "";
1207             }
1208              
1209 9         33 for ( $i{general}{abc} ) {
1210 9 50       59 next unless defined;
1211 9         106 $msg .= sprintf( $fmt2, "ABC support", $_ );
1212             }
1213              
1214 9         34 $msg .= "\nModules and libraries:\n";
1215 9         26 for ( @{$i{modules}} ) {
  9         31  
1216 99 50       177 if ( $level eq "normal" ) {
1217 99         337 $msg .= sprintf( $fmt2, $_->{name}, $_->{version} );
1218             }
1219             else {
1220 0 0       0 if ( defined $_->{dppath} ) {
1221 0         0 $msg .= sprintf( $fmt3, $_->{name}, $_->{version}, $_->{dppath} );
1222             }
1223             else {
1224 0         0 $msg .= sprintf( $fmt2, $_->{name}, $_->{version} );
1225             }
1226             }
1227 99 50       227 if ( $_->{library} ) {
1228 0 0       0 if ( $_->{library} =~ /i$/ ) {
1229 0         0 $msg .= sprintf( $fmt3, " library", $_->{library}, "embedded" );
1230             }
1231             else {
1232 0         0 $msg .= sprintf( $fmt2, " library", $_->{library} );
1233             }
1234             }
1235             }
1236              
1237 9         375 return $msg;
1238             }
1239              
1240             # Gather runtime details.
1241             sub runtime_info {
1242 17   50 17 0 70 my $level = shift // "normal";
1243 17         190 my $cp = ChordPro::Paths->get;
1244 17         39 my $res;
1245              
1246             # Sometimes version numbers are localized...
1247 17     116   149 my $dd = sub { my $v = $_[0]; $v =~ s/,/./g; $v };
  116         285  
  116         334  
  116         10290  
1248              
1249 17         97 for ( $res->{general}{chordpro} ) {
1250 17         63 $_->{version} = $dd->($VERSION);
1251 17 50       111 $_->{type} = $::options->{reference} ? "reference" : "core";
1252 17 50       87 $_->{aux} = "Unsupported development snapshot"
1253             if $VERSION =~ /_/;
1254             }
1255 17 100       114 return $res if $level eq "short";
1256              
1257             $res->{general}{perl} =
1258 9         137 { version => "$^V",
1259             path => $^X,
1260             dppath => $cp->display($^X),
1261             };
1262              
1263             $res->{general}{packager} =
1264 9 50       78 { packager => CP->packager,
1265             version => CP->packager_version,
1266             } if CP->packager;
1267              
1268             # Determine resource path.
1269 9         41 $res->{general}{library} = [];
1270 9 50       53 if ( defined $ENV{CHORDPRO_LIB} ) {
1271 0         0 for ( $cp->path($ENV{CHORDPRO_LIB}) ) {
1272 0         0 push( @{$res->{general}{library}},
  0         0  
1273             { path => $_,
1274             dppath => $cp->display($_) } );
1275             }
1276             }
1277              
1278 9 50       47 if ( defined $ENV{FONTDIR} ) {
1279 0         0 for ( $cp->path($ENV{FONTDIR}) ) {
1280 0         0 push( @{$res->{general}{fontdir}},
  0         0  
1281             { path => $_,
1282             dppath => $cp->display($_) } );
1283             }
1284             }
1285              
1286             $res->{resources} =
1287 9         46 [ map { { path => $_, dppath => $cp->display($_) } }
1288 9         26 uniq( @{ $cp->resdirs } ) ];
  9         67  
1289              
1290 9 50 33     26 eval {
1291 9         4917 require ChordPro::Delegate::ABC;
1292 9         79 my $x = ChordPro::Delegate::ABC->info();
1293 9 50       989 $res->{general}{abc} = $x->{info} if $x->{info};
1294 9         101 1;
1295             } or $@ =~ /Can't locate/ or warn($@);
1296              
1297 9         33 my @p;
1298              
1299             my $vv = sub {
1300 99     99   333 my ( $mod ) = @_;
1301 90     90   871 no strict 'refs';
  90         231  
  90         29287  
1302 99         1372 my $pm = $mod =~ s;::;/;gr . ".pm";
1303 99         386 my $loc = $INC{$pm};
1304             push( @p, { name => $mod,
1305 99 50       240 version => "".$dd->(${${"${mod}::"}{VERSION}}),
  99         1337  
  99         1128  
1306             path => $loc,
1307             dppath => $loc =~ /^(.*)\/\Q$pm\E$/ ? $cp->display($1) : $loc,
1308             } );
1309 9         135 };
1310              
1311 9 50       53 if ( defined $Wx::VERSION ) {
1312 90     90   737 no strict 'subs';
  90         258  
  90         147306  
1313 0         0 push( @p,
1314             { name => "wxPerl", version => $dd->($Wx::VERSION) },
1315             { name => "wxWidgets", version => $dd->($Wx::wxVERSION) } );
1316             }
1317              
1318 9     0   98 local $SIG{__WARN__} = sub {};
1319 9     27   140 local $SIG{__DIE__} = sub {};
1320 9         53 $vv->("Storable");
1321 9         90 $vv->("Object::Pad");
1322 9         43 eval {
1323 9         121 require Text::Layout;
1324 9         47 $vv->("Text::Layout");
1325             };
1326 9         24 eval {
1327 9         1650 require HarfBuzz::Shaper;
1328 0         0 $vv->("HarfBuzz::Shaper");
1329 0         0 $p[-1]->{library} = $dd->(HarfBuzz::Shaper::hb_version_string());
1330             };
1331 9         28 eval {
1332 9         53 require String::Interpolate::Named;
1333 9         40 $vv->("String::Interpolate::Named");
1334             };
1335 9         29 eval {
1336 9         87 require File::LoadLines;
1337 9         36 $vv->("File::LoadLines");
1338             };
1339 9         28 eval {
1340 9         1287 require PDF::Builder;
1341 0         0 $vv->("PDF::Builder");
1342             };
1343 9         28 eval {
1344 9         759 require PDF::API2;
1345 9         263988 $vv->("PDF::API2");
1346 9         41 eval {
1347 9         1268 require PDF::API2::XS;
1348 0         0 $vv->("PDF::API2::XS");
1349             };
1350             };
1351 9         25 eval {
1352 9         5392 require SVGPDF;
1353 9         1632 $vv->("SVGPDF");
1354             };
1355 9         29 eval {
1356 9         6114 require Font::TTF;
1357 9         543 $vv->("Font::TTF");
1358             };
1359 9         26 eval {
1360 9         77 require JavaScript::QuickJS;
1361 9         413 $vv->("JavaScript::QuickJS");
1362             };
1363 9         72 my $i = json_parser();
1364 9         264 $vv->( $i->{parser} );
1365 9 50       74 $p[-1]->{relaxed} = "relaxed" if $i->{relaxed};
1366              
1367 9         53 eval {
1368 9         75 require JSON::XS;
1369 9         34 $vv->("JSON::XS");
1370             };
1371              
1372 9         60 $res->{modules} = [ @p ];
1373              
1374 9         75 $res->{metadata} = $::config->{metadata}{keys};
1375              
1376             @p = ( qw(title subtitle),
1377 153   50     328 ( grep { !/^(sub)?title$/ } sort(@{$::config->{metadata}{keys}//[]}) ),
  9         196  
1378 9         30 grep { !/^(sub)?title$/ } (keys(%{ChordPro::Song::_directives()})) );
  315         695  
  9         65  
1379 9         123 $res->{directives} = [ @p ];
1380              
1381 9         44 $res->{directive_abbrevs} = ChordPro::Song::_directive_abbrevs();
1382              
1383 9         388 return $res;
1384             }
1385              
1386             sub splitpath {
1387 0     0 0   my ( $path ) = @_;
1388 0 0         return () unless $path;
1389 0 0         if ( $^O =~ /Win/ ) {
1390 0           return split( /;/, $path );
1391             }
1392 0           return split( /;/, $path );
1393             }
1394              
1395             sub app_usage {
1396 0     0 0   my ($fh, $exit) = @_;
1397 0           my %cfg;
1398 0           for ( qw( config userconfig sysconfig) ) {
1399 0   0       $cfg{$_} = $configs{$_} || "no default";
1400             }
1401              
1402 0 0         if ( $::options->{reference} ) {
1403 0           print ${fh} <
1404             Usage: $0 [ options ] [ file ... ]
1405              
1406             Options:
1407             --[no]strict Strict conformance
1408             --output=FILE -o Saves the output to FILE
1409             --about -A About ChordPro...
1410             --version -V Prints version and exits
1411             --help -h This message
1412             --ident Show identification
1413             --verbose Verbose information. Repeat for more.
1414             EndOfUsage
1415 0 0         exit $exit if defined $exit;
1416 0           return;
1417             }
1418              
1419             ####TODO: weed out for --reference.
1420 0           print ${fh} <
1421             Usage: $0 [ options ] [ file ... ]
1422              
1423             Options:
1424             --a2crd Perform text to ChordPro conversion only
1425             --noa2crd Do not auto-sense text to ChordPro conversion
1426             --about -A About ChordPro...
1427             --back-matter=FILE Add back matter pages from PDF document
1428             --config=JSON --cfg Config definitions (multiple)
1429             --cover=FILE Add cover pages from PDF document
1430             --crd Input is text, not ChordPro
1431             --csv (with PDF) Also generate CSV
1432             --decapo Eliminate capo settings
1433             --diagrams=WHICH Prints chord diagrams
1434             --encoding=ENC Encoding for input files (UTF-8)
1435             --filelist=FILE Reads song file names from FILE
1436             --fragment -F Partial (incomplete) song
1437             --front-matter=FILE Add front matter pages from PDF document
1438             --lyrics-only -l Only prints lyrics
1439             --meta KEY=VALUE Add meta data
1440             --output=FILE -o Saves the output to FILE
1441             --[no]strict Strict conformance
1442             --start-page-number=N -p Starting page number [1]
1443             --subtitle=VALUE Use with --title for a nice subtitle.
1444             --title=VALUE Adds a nice cover page using this title.
1445             --toc --notoc -i Generates/suppresses a table of contents
1446             --transcode=SYS -xc Transcodes to notation system
1447             --transpose=N -x Transposes by N semi-tones
1448             --version -V Prints version and exits
1449              
1450             Chordii compatibility.
1451             Options marked with * are better handled in the config file.
1452             --chord-font=FONT -C *Sets chord font
1453             --chord-grid-size=N -s *Sets chord diagram size [30]
1454             --chord-grids-sorted -S *Prints chord diagrams ordered by key
1455             --chord-size=N -c *Sets chord size [9]
1456             --dump-chords -D Dumps chords definitions (PDF)
1457             --dump-chords-text -d Dumps chords definitions (Text)
1458             --even-pages-number-left -L *Not supported
1459             --odd-pages-number-left *Not supported.
1460             --no-chord-grids -G *Disables printing of chord diagrams
1461             --no-easy-chord-grids -g Not supported
1462             --page-number-logical -n Not supported
1463             --page-size=FMT -P *Specifies page size [letter, a4 (default)]
1464             --single-space -a *Automatic single space lines without chords
1465             --text-size=N -t *Sets text size [12]
1466             --text-font=FONT -T *Sets text font
1467             --user-chord-grids *Prints the user defined chords in the song
1468             --vertical-space=N -w *Extra vertical space between lines
1469             --2-up -2 Not supported
1470             --4-up -4 Not supported
1471              
1472             Configuration options:
1473             --config=CFG Project specific config file ($cfg{config})
1474             --define=XXX=YYY Sets config item XXX to value YYY
1475             --noconfig Don't use a project specific config file
1476             --nodefaultconfigs -X Don't use any default config files
1477             --nosongconfig Don't use song specific configs
1478             --nosysconfig Don't use a system specific config file
1479             --nouserconfig Don't use a user specific config file
1480             --print-default-config Prints the default config and exits
1481             --print-delta-config Prints the diffs for the resultant config and exits
1482             --print-final-config Prints the resultant config and exits
1483             --reference -R Reference mode (no configs etc.)
1484             --sysconfig=CFG System specific config file ($cfg{sysconfig})
1485             --userconfig=CFG User specific config file ($cfg{userconfig})
1486             Missing default configuration files are silently ignored.
1487              
1488             Miscellaneous options:
1489             --help -h This message
1490             --help-config Help for ChordPro configuration
1491             --ident Show identification
1492             --manual The full manual.
1493             --verbose Verbose information. Repeat for more.
1494             EndOfUsage
1495 0 0         exit $exit if defined $exit;
1496             }
1497              
1498             =head1 FONTS
1499              
1500             There are two ways to specify fonts: with a font filename, and a
1501             built-in font name.
1502              
1503             A font filename must be either and absolute filename, or a relative
1504             filename which is interpreted relative to the I, which
1505             consists of configuration setting C, the C resource
1506             dir, and the contents of environment variable C. In any case,
1507             the filename should point to a valid TrueType (C<.ttf>) or OpenType
1508             (C<.otf>) font.
1509              
1510             If it is not a filename, it must be the name one of the built-in PDF core fonts:
1511              
1512             Courier Symbol
1513             Courier-Bold Times-Bold
1514             Courier-BoldOblique Times-BoldItalic
1515             Courier-Oblique Times-Italic
1516             Helvetica Times-Roman
1517             Helvetica-Bold ZapfDingbats
1518             Helvetica-BoldOblique
1519             Helvetica-Oblique
1520              
1521             =head1 MOTIVATION
1522              
1523             Why a rewrite of Chordii?
1524              
1525             Chordii is the de facto reference implementation of the ChordPro file
1526             format standard. It implements ChordPro version 4.
1527              
1528             ChordPro version 5 adds a number of new features, and this was pushing
1529             the limits of the very old program. Unicode support would have been
1530             very hard to add, and the whole program centered around PostScript
1531             generation, while nowadays PDF would be a much better alternative.
1532              
1533             So I decided to create a new reference implementation from the ground
1534             up. I chose a programming language that is flexible and very good at
1535             handling Unicode data. And that is fun to program in.
1536              
1537             =head1 CURRENT STATUS
1538              
1539             This program implements ChordPro version 5. It
1540             supports most of the features of Chordii, and a lot more:
1541              
1542             * Native PDF generation
1543              
1544             * Unicode support (all input is UTF8)
1545              
1546             * User defined chords and tuning, not limited to 6 strings.
1547              
1548             * Support for Nashville Numbering and Roman Numbering.
1549              
1550             * Support for external TrueType and OpenType fonts
1551              
1552             * Font kerning (with external TrueType fonts)
1553              
1554             * Fully customizable layout, fonts and sizes
1555              
1556             * Customizable backends for PDF, ChordPro, LilyPond*, LaTeX* and HTML*.
1557              
1558             (* = under development)
1559              
1560             =head1 AUTHOR
1561              
1562             Johan Vromans C<< >>
1563              
1564             =head1 SUPPORT
1565              
1566             ChordPro (the program) development is hosted on GitHub, repository
1567             L.
1568              
1569             Please report any bugs or feature requests to the GitHub issue tracker,
1570             L.
1571              
1572             A user community discussing ChordPro can be found at
1573             L.
1574              
1575             =head1 LICENSE
1576              
1577             Copyright (C) 2010,2018 Johan Vromans,
1578              
1579             This program is free software; you can redistribute it and/or modify it
1580             under the same terms as Perl itself.
1581              
1582             =cut
1583              
1584             1;