1# This file is part of LilyPond, the GNU music typesetter.
2#
3# Copyright (C) 1998--2021 Han-Wen Nienhuys <hanwen@xs4all.nl>
4#                Jan Nieuwenhuizen <janneke@gnu.org>
5#
6# LilyPond is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# LilyPond is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18
19import __main__
20import codecs
21import gettext
22import optparse
23import os
24import sys
25
26sys.stdin = codecs.getreader('utf8')(sys.stdin.detach())
27sys.stdout = codecs.getwriter('utf8')(sys.stdout.detach())
28sys.stderr = codecs.getwriter('utf8')(sys.stderr.detach())
29
30# Lilylib globals.
31program_name = os.path.basename(sys.argv[0])
32
33# Logging framework: We have the following output functions:
34#    error
35#    warning
36#    progress
37#    debug
38
39# TODO: use the standard logging module
40_loglevels = {"NONE": 0, "ERROR": 1, "WARN": 2,
41              "BASIC": 3, "PROGRESS": 4, "INFO": 5, "DEBUG": 6}
42
43_loglevel = _loglevels["PROGRESS"]
44
45
46def set_loglevel(l):
47    global _loglevel
48    newlevel = _loglevels.get(l, -1)
49    if newlevel > 0:
50        debug_output(_("Setting loglevel to %s") % l)
51        _loglevel = newlevel
52    else:
53        error(_("Unknown or invalid loglevel '%s'") % l)
54
55
56def handle_loglevel_option(option, opt_str, value, parser, *args):
57    if value:
58        set_loglevel(value)
59    elif args:
60        set_loglevel(args[0])
61
62
63def _is_loglevel(l):
64    global _loglevel
65    return _loglevel >= _loglevels[l]
66
67
68def is_verbose():
69    return _is_loglevel("DEBUG")
70
71
72def _print_logmessage(level, s, fullmessage=True, newline=True):
73    if _is_loglevel(level):
74        if fullmessage:
75            s = program_name + ": " + s + "\n"
76        elif newline:
77            s += '\n'
78        sys.stderr.write(s)
79        sys.stderr.flush()
80
81
82def error(s):
83    _print_logmessage("ERROR", _("error: %s") % s)
84
85
86def warning(s):
87    _print_logmessage("WARN", _("warning: %s") % s)
88
89
90def progress(s, fullmessage=False, newline=True):
91    _print_logmessage("PROGRESS", s, fullmessage, newline)
92
93
94def debug_output(s, fullmessage=False, newline=True):
95    _print_logmessage("DEBUG", s, fullmessage, newline)
96
97
98class _NonDentedHeadingFormatter (optparse.IndentedHelpFormatter):
99    def format_heading(self, heading):
100        if heading:
101            return heading[0].upper() + heading[1:] + ':\n'
102        return ''
103
104    def format_option_strings(self, option):
105        sep = ' '
106        if option._short_opts and option._long_opts:
107            sep = ','
108
109        metavar = ''
110        if option.takes_value():
111            metavar = '=%s' % option.metavar or option.dest.upper()
112
113        return "%3s%s %s%s" % (" ".join(option._short_opts),
114                               sep,
115                               " ".join(option._long_opts),
116                               metavar)
117
118    # Only use one level of indentation (even for groups and nested groups),
119    # since we don't indent the headings, either
120    def indent(self):
121        self.current_indent = self.indent_increment
122        self.level += 1
123
124    def dedent(self):
125        self.level -= 1
126        if self.level <= 0:
127            self.current_indent = ''
128            self.level = 0
129
130    def format_usage(self, usage):
131        return _("Usage: %s") % usage + '\n'
132
133    def format_description(self, description):
134        return description
135
136
137class _NonEmptyOptionParser (optparse.OptionParser):
138    "A subclass of OptionParser that gobbles empty string arguments."
139
140    def parse_args(self, args=None, values=None):
141        options, args = optparse.OptionParser.parse_args(self, args, values)
142        return options, [_f for _f in args if _f]
143
144
145def get_option_parser(*args, **kwargs):
146    p = _NonEmptyOptionParser(*args, **kwargs)
147    p.formatter = _NonDentedHeadingFormatter()
148    p.formatter.set_parser(p)
149    return p
150