diff --git a/Doc/howto/abi3t-migration.rst b/Doc/howto/abi3t-migration.rst index c542efbdea8dec..ec78a33ed25820 100644 --- a/Doc/howto/abi3t-migration.rst +++ b/Doc/howto/abi3t-migration.rst @@ -8,14 +8,14 @@ Migrating to Stable ABI for free threading (``abi3t``) Starting with the 3.15 release, CPython supports a variant of the Stable ABI that supports :term:`free-threaded ` Python: -Stable ABI for Free-Threaded Builds, or ``abi3t`` for short. +the Stable ABI for Free-Threaded Builds, or ``abi3t`` for short. This document describes how to adapt C API extensions to support free threading. Why do this =========== -The typical reason to use Stable ABI is to reduce the number of artifacts that -you need to build and distribute for each version of your library. +The typical reason to use the Stable ABI is to reduce the number of artifacts +that you need to build and distribute for each version of your library. Without the Stable ABI, you must build a separate shared library, and typically a *wheel* distribution, for each feature version of CPython you wish @@ -87,16 +87,16 @@ builds; even the 3.15+ ones that this table "attributes" to ``abi3t``.) Why *not* do this ----------------- -There are two main downsides to Stable ABI. +There are two main downsides to the Stable ABI. -First, you extension may become slower, since Stable ABI prioritizes +First, your extension may become slower, since the Stable ABI prioritizes compatibility over performance. The difference is usually not noticeable, and often can be mitigated by using the same source to build both a Stable ABI build and a few version-specific ones for "tier 1" CPython versions. Second, not all of the C API is available. -Extensions need to be ported to build for Stable ABI, which may be difficult +Extensions need to be ported to build for the Stable ABI, which may be difficult or, in rare cases, impossible. Specifically, ``abi3t`` requires APIs added in CPython 3.15. @@ -127,7 +127,7 @@ Prerequisites This guide assumes that you have an extension written directly in C (or C++), which you want to port to ``abi3t``. -If your extenstion uses a code generator (like Cython) or language binding +If your extension uses a code generator (like Cython) or language binding (like PyO3), it's best to wait until that tool has support for ``abi3t``. If you maintain such a tool, you might be able to adapt the instructions here for your tool. @@ -135,7 +135,7 @@ here for your tool. Non-free-threaded Stable ABI ---------------------------- -Your extension should support the Stable ABI (``abi3t``). +Your extension should support the non-free-threaded Stable ABI (``abi3``). If not, either port it first, or follow this guide but be prepared to fix issues it does not mention. @@ -183,7 +183,7 @@ following just after ``#include ``:: #error "abi3t define is not set!" #endif -This should result in a different error than "``abt3t`` define is not set". +This should result in a different error than "``abi3t`` define is not set". .. note:: @@ -705,7 +705,7 @@ Testing Note that when you build an extension compatible with multiple versions of CPython, you should always *test* it with each version it supports (for example, 3.15, 3.16, and so on). -Stable ABI only guarantees *ABI* compatibility; there may also be behavior +The Stable ABI only guarantees *ABI* compatibility; there may also be behavior changes -- both intentional ones (covered by :pep:`387`) and bugs. Be sure to run tests on both free-threaded and non-free-threaded builds diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 87025814aafb9a..2ff221cf258eda 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1955,7 +1955,7 @@ Subclass ``QueueListener`` class NNGSocketListener(logging.handlers.QueueListener): def __init__(self, uri, /, *handlers, **kwargs): - # Have a timeout for interruptability, and open a + # Have a timeout for interruptibility, and open a # subscriber socket socket = pynng.Sub0(listen=uri, recv_timeout=500) # The b'' subscription matches all topics diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index e413cd9d2bef2d..9d0bb239af06df 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1321,6 +1321,8 @@ Reading window contents The bottom 8 bits are the character proper and the upper bits are the attributes; extract them with the :data:`A_CHARTEXT` and :data:`A_ATTRIBUTES` bit-masks, and the color pair with :func:`pair_number`. + The character byte is the locale-encoded byte of the cell's character, + consistent with :meth:`instr`. It cannot represent a cell holding combining characters, a character that does not fit in a single byte, or a color pair outside the :func:`color_pair` range; use :meth:`in_wch` for those, which returns it as a :class:`complexchar`. diff --git a/Doc/library/datatypes.rst b/Doc/library/datatypes.rst index ff51b2779e5fa3..4b4f3b1720accc 100644 --- a/Doc/library/datatypes.rst +++ b/Doc/library/datatypes.rst @@ -8,9 +8,10 @@ The modules described in this chapter provide a variety of specialized data types such as dates and times, fixed-type arrays, heap queues, double-ended queues, and enumerations. -Python also provides some built-in data types, in particular, -:class:`dict`, :class:`list`, :class:`set` and :class:`frozenset`, and -:class:`tuple`. The :class:`str` class is used to hold +Python also provides :ref:`some built-in data types `, in particular, +:class:`list`, :class:`tuple`, :class:`dict`, :class:`frozendict`, +:class:`set`, and :class:`frozenset`. +The :class:`str` class is used to hold Unicode strings, and the :class:`bytes` and :class:`bytearray` classes are used to hold binary data. diff --git a/Doc/library/getopt.rst b/Doc/library/getopt.rst index 5c63009e22d58c..9995f114d063e8 100644 --- a/Doc/library/getopt.rst +++ b/Doc/library/getopt.rst @@ -62,6 +62,8 @@ exception: option ``--fo`` will match as ``--foo``, but ``--f`` will not match uniquely, so :exc:`GetoptError` will be raised. + If *longopts* is a string it gets treated as a list of a single element. + The return value consists of two elements: the first is a list of ``(option, value)`` pairs; the second is the list of program arguments left after the option list was stripped (this is a trailing slice of *args*). Each diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 22a10db976c4fc..fd20ff2cb89810 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -1087,6 +1087,32 @@ Libraries options .. versionadded:: 3.10 +.. option:: --with-curses=ncursesw|ncurses|curses + + Designate a backend library for the :mod:`curses` and :mod:`curses.panel` + modules. + + * ``ncursesw``: Use the wide-character ``libncursesw`` (and ``libpanelw``), + found via ``pkg-config``. + * ``ncurses``: Use ``libncurses`` (and ``libpanel``), found via + ``pkg-config``. + * ``curses``: Use the system's native ``libcurses`` (and ``libpanel``), such + as on NetBSD or Solaris. It is built with wide-character support when the + library provides it. + + Without this option (or with ``--with-curses=auto``, the default), Python + tries ``ncursesw`` and then ``ncurses``; the native ``curses`` is used only + when requested explicitly. + + .. versionadded:: next + +.. option:: --without-curses + + Don't build the :mod:`curses` and :mod:`curses.panel` modules, even when a + curses library is present (built by default when one is found). + + .. versionadded:: next + .. option:: --with-libm=STRING Override ``libm`` math library to *STRING* (default is system-dependent). diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index e6565b186a598c..c06e6930ac78bf 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -365,6 +365,17 @@ os (Contributed by Maurycy Pawłowski-Wieroński in :gh:`149464`.) +pydoc +----- + +* Modernize the HTML output of :mod:`pydoc`. The pages generated by the + :mod:`pydoc` HTTP server now use semantic HTML5 markup and a new style + sheet based on the python-docs-theme used by `docs.python.org + `__, with dark mode support. Class members + inherited from other classes are collapsed by default. + (Contributed by Serhiy Storchaka in :gh:`153906`.) + + re -- @@ -768,6 +779,15 @@ Build changes (Contributed by Stefano Rivera in :gh:`131372`.) +* Add the :option:`--with-curses` :program:`configure` option to select the + curses backend for the :mod:`curses` and :mod:`curses.panel` modules. + In addition to ``ncursesw`` and ``ncurses``, it can now build against the + system's native ``curses`` library (for example on NetBSD or Solaris), with + wide-character support when the library provides it. :option:`--without-curses` + excludes the modules from the build. + + (Contributed by Serhiy Storchaka in :gh:`136687`.) + C API changes ============= diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index b035bfb99feee0..a73422598b2cd9 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -512,7 +512,8 @@ def _process_struct(decorated_class, /, *, align, layout, endian, pack): fields.extend(decorated_class._fields_) anonymous.extend(decorated_class._anonymous_) - for name, hint in annotationlib.get_annotations(decorated_class).items(): + annotations = annotationlib.get_annotations(decorated_class, eval_str=True) + for name, hint in annotations.items(): if get_origin(hint) is ClassVar: continue @@ -531,7 +532,8 @@ def _process_struct(decorated_class, /, *, align, layout, endian, pack): else: field.append(hint) - fields.append(field) + # _fields_ is a list of tuples + fields.append(tuple(field)) if endian == 'big': endian_class = BigEndianStructure @@ -579,7 +581,7 @@ def wrap_dll_function(dll): def decorator(func): name = func.__name__ ptr = getattr(dll, name) - annotations = annotationlib.get_annotations(func) + annotations = annotationlib.get_annotations(func, eval_str=True) try: restype = annotations.pop("return") diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 041ee26c791f36..3140723f49b7d0 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -620,55 +620,41 @@ def page(self, title, contents): def heading(self, title, extras=''): """Format a page heading.""" return ''' - - - -
 
%s
%s
- ''' % (title, extras or ' ') - - def section(self, title, cls, contents, width=6, - prelude='', marginalia=None, gap=' '): - """Format a section with a heading.""" - if marginalia is None: - marginalia = '' + ' ' * width + '' - result = '''

- - - - ''' % (cls, title) +
+

%s

+
%s
+
+''' % (title, extras) + + def _section(self, title, cls, contents, prelude, tag): + result = ''' +
+<%s>%s +''' % (cls, tag, title, tag) if prelude: - result = result + ''' -
- -''' % (cls, marginalia, cls, prelude, gap) - else: - result = result + ''' -''' % (cls, marginalia, gap) + result = result + '
%s
\n' % prelude + return result + '%s\n\n' % contents + + def section(self, title, cls, contents, width=None, + prelude='', marginalia=None, gap=None): + """Format a section with a heading. - return result + '\n
 
%s
%s%s
%s
%s%s%s
' % contents + The width, marginalia and gap arguments are ignored. + """ + return self._section(title, cls, contents, prelude, 'h3') - def bigsection(self, title, *args): + def bigsection(self, title, cls, contents, *ignored): """Format a section with a big heading.""" - title = '%s' % title - return self.section(title, *args) + return self._section(title, cls, contents, '', 'h2') def preformat(self, text): """Format literal preformatted text.""" - text = self.escape(text.expandtabs()) - return replace(text, '\n\n', '\n \n', '\n\n', '\n \n', - ' ', ' ', '\n', '
\n') + return self.escape(text.expandtabs()) def multicolumn(self, list, format): """Format a list of items into a multi-column list.""" - result = '' - rows = (len(list) + 3) // 4 - for col in range(4): - result = result + '' - for i in range(rows*col, rows*col+rows): - if i < len(list): - result = result + format(list[i]) + '
\n' - result = result + '' - return '%s
' % result + result = ''.join('

  • %s
  • \n' % format(item) for item in list) + return '
      \n%s
    ' % result def grey(self, text): return '%s' % text @@ -776,7 +762,7 @@ def formattree(self, tree, modname, parent=None): for entry in tree: if isinstance(entry, tuple): c, bases = entry - result = result + '
    ' + result = result + '
    ' result = result + self.classlink(c, modname) if bases and bases != (parent,): parents = [] @@ -787,7 +773,7 @@ def formattree(self, tree, modname, parent=None): elif isinstance(entry, list): result = result + '
    \n%s
    \n' % self.formattree( entry, modname, c) - return '
    \n%s
    \n' % result + return '
    \n%s
    \n' % result def docmodule(self, object, name=None, mod=None, *ignored): """Produce HTML documentation for a module object.""" @@ -800,10 +786,10 @@ def docmodule(self, object, name=None, mod=None, *ignored): links = [] for i in range(len(parts)-1): links.append( - '%s' % + '%s' % ('.'.join(parts[:i+1]), parts[i])) linkedname = '.'.join(links + parts[-1:]) - head = '%s' % linkedname + head = linkedname try: path = inspect.getabsfile(object) url = urllib.parse.quote(path) @@ -861,8 +847,8 @@ def docmodule(self, object, name=None, mod=None, *ignored): data.append((key, value)) doc = self.markup(getdoc(object), self.preformat, fdict, cdict) - doc = doc and '%s' % doc - result = result + '

    %s

    \n' % doc + doc = doc and '
    %s
    \n' % doc + result = result + doc if hasattr(object, '__path__'): modpkgs = [] @@ -937,11 +923,26 @@ def maybe(self): object.__module__)) push('\n') + # Wrap the groups of members inherited from other classes in + #
    so that they are collapsed by default. + is_inherited = False + + def begingroup(msg): + if is_inherited: + push('
    \n' + '%s\n' % msg) + else: + push('

    %s

    \n' % msg) + + def endgroup(): + if is_inherited: + push('
    \n') + def spill(msg, attrs, predicate): ok, attrs = _split_list(attrs, predicate) if ok: hr.maybe() - push(msg) + begingroup(msg) for name, kind, homecls, value in ok: try: value = getattr(object, name) @@ -953,33 +954,37 @@ def spill(msg, attrs, predicate): push(self.document(value, name, mod, funcs, classes, mdict, object, homecls)) push('\n') + endgroup() return attrs def spilldescriptors(msg, attrs, predicate): ok, attrs = _split_list(attrs, predicate) if ok: hr.maybe() - push(msg) + begingroup(msg) for name, kind, homecls, value in ok: push(self.docdata(value, name, mod)) + endgroup() return attrs def spilldata(msg, attrs, predicate): ok, attrs = _split_list(attrs, predicate) if ok: hr.maybe() - push(msg) + begingroup(msg) for name, kind, homecls, value in ok: base = self.docother(getattr(object, name), name, mod) doc = getdoc(value) if not doc: - push('
    %s
    \n' % base) + push('
    %s
    \n' % base) else: doc = self.markup(getdoc(value), self.preformat, funcs, classes, mdict) - doc = '
    %s' % doc - push('
    %s%s
    \n' % (base, doc)) + push('
    %s
    ' + '
    %s
    \n' + % (base, doc)) push('\n') + endgroup() return attrs attrs = [(name, kind, cls, value) @@ -1014,10 +1019,12 @@ def spilldata(msg, attrs, predicate): continue elif thisclass is object: tag = 'defined here' + is_inherited = False else: tag = 'inherited from %s' % self.classlink(thisclass, object.__module__) - tag += ':
    \n' + is_inherited = True + tag += ':' sort_attributes(attrs, object) @@ -1040,10 +1047,10 @@ def spilldata(msg, attrs, predicate): contents = ''.join(contents) if name == realname: - title = 'class %s' % ( + title = 'class %s' % ( name, realname) else: - title = '%s = class %s' % ( + title = '%s = class %s' % ( name, name, realname) if bases: parents = [] @@ -1060,9 +1067,8 @@ def spilldata(msg, attrs, predicate): if decl: doc = decl + (doc or '') doc = self.markup(doc, self.preformat, funcs, classes, mdict) - doc = doc and '%s
     
    ' % doc - return self.section(title, 'title', contents, 3, doc) + return self.section(title, 'title', contents, prelude=doc) def formatvalue(self, object): """Format an argument default value as text.""" @@ -1115,7 +1121,7 @@ def docroutine(self, object, name=None, mod=None, asyncqualifier = '' if name == realname: - title = '%s' % (anchor, realname) + title = '%s' % (anchor, realname) else: if (cl is not None and inspect.getattr_static(cl, realname, []) is object): @@ -1126,7 +1132,7 @@ def docroutine(self, object, name=None, mod=None, note = '' else: reallink = realname - title = '%s = %s' % ( + title = '%s = %s' % ( anchor, name, reallink) argspec = None if inspect.isroutine(object): @@ -1142,15 +1148,15 @@ def docroutine(self, object, name=None, mod=None, argspec = '(...)' decl = asyncqualifier + title + self.escape(argspec) + (note and - self.grey('%s' % note)) + '%s' % note) if skipdocs: - return '
    %s
    \n' % decl + return '
    %s
    \n' % decl else: doc = self.markup( getdoc(object), self.preformat, funcs, classes, methods) - doc = doc and '
    %s
    ' % doc - return '
    %s
    %s
    \n' % (decl, doc) + doc = doc and '
    %s
    ' % doc + return '
    %s
    %s
    \n' % (decl, doc) def docdata(self, object, name=None, mod=None, cl=None, *ignored): """Produce html documentation for a data descriptor.""" @@ -1158,10 +1164,10 @@ def docdata(self, object, name=None, mod=None, cl=None, *ignored): push = results.append if name: - push('
    %s
    \n' % name) + push('
    %s
    \n' % name) doc = self.markup(getdoc(object), self.preformat) if doc: - push('
    %s
    \n' % doc) + push('
    %s
    \n' % doc) push('
    \n') return ''.join(results) @@ -2471,12 +2477,17 @@ def page(self, title, contents): '' % css_path) return '''\ - + + Pydoc: %s -%s%s
    %s
    +%s +%s +
    +%s +
    ''' % (title, css_link, html_navbar(), contents) @@ -2487,27 +2498,25 @@ def html_navbar(): platform.python_build()[0], platform.python_compiler())) return """ -
    - Python %s
    %s -
    -
    - -
    -
    - - -
      -
    - - -
    -
    -
    - """ % (version, html.escape(platform.platform(terse=True))) + +""" % (version, html.escape(platform.platform(terse=True))) def html_index(): """Module Index page.""" @@ -2515,13 +2524,11 @@ def html_index(): def bltinlink(name): return '%s' % (name, name) - heading = html.heading( - 'Index of Modules' - ) + heading = html.heading('Index of Modules') names = [name for name in sys.builtin_module_names if name != '__main__'] contents = html.multicolumn(names, bltinlink) - contents = [heading, '

    ' + html.bigsection( + contents = [heading, html.bigsection( 'Built-in Modules', 'index', contents)] seen = {} @@ -2529,8 +2536,8 @@ def bltinlink(name): contents.append(html.index(dir, seen)) contents.append( - '

    pydoc by Ka-Ping Yee' - '<ping@lfw.org>

    ') + '
    pydoc by Ka-Ping Yee' + ' <ping@lfw.org>
    ') return 'Index of Modules', ''.join(contents) def html_search(key): @@ -2554,13 +2561,11 @@ def bltinlink(name): return '%s' % (name, name) results = [] - heading = html.heading( - 'Search Results', - ) + heading = html.heading('Search Results') for name, desc in search_result: - results.append(bltinlink(name) + desc) + results.append('
  • %s%s
  • ' % (bltinlink(name), desc)) contents = heading + html.bigsection( - 'key = %s' % key, 'index', '
    '.join(results)) + 'key = %s' % key, 'index', '
      \n%s\n
    ' % '\n'.join(results)) return 'Search Results', contents def html_topics(): @@ -2569,29 +2574,21 @@ def html_topics(): def bltinlink(name): return '%s' % (name, name) - heading = html.heading( - 'INDEX', - ) + heading = html.heading('Topics') names = sorted(Helper.topics.keys()) - contents = html.multicolumn(names, bltinlink) - contents = heading + html.bigsection( - 'Topics', 'index', contents) + contents = heading + html.multicolumn(names, bltinlink) return 'Topics', contents def html_keywords(): """Index of keywords.""" - heading = html.heading( - 'INDEX', - ) + heading = html.heading('Keywords') names = sorted(Helper.keywords.keys()) def bltinlink(name): return '%s' % (name, name) - contents = html.multicolumn(names, bltinlink) - contents = heading + html.bigsection( - 'Keywords', 'index', contents) + contents = heading + html.multicolumn(names, bltinlink) return 'Keywords', contents def html_topicpage(topic): @@ -2603,11 +2600,9 @@ def html_topicpage(topic): title = 'KEYWORD' else: title = 'TOPIC' - heading = html.heading( - '%s' % title, - ) - contents = '
    %s
    ' % html.markup(contents) - contents = html.bigsection(topic , 'index', contents) + heading = html.heading('%s %s' % (title.capitalize(), topic)) + contents = ('
    %s
    ' + % (title.lower(), html.markup(contents))) if xrefs: xrefs = sorted(xrefs.split()) @@ -2615,7 +2610,7 @@ def bltinlink(name): return '%s' % (name, name) xrefs = html.multicolumn(xrefs, bltinlink) - xrefs = html.section('Related help topics: ', 'index', xrefs) + xrefs = html.section('Related help topics', 'index', xrefs) return ('%s %s' % (title, topic), ''.join((heading, contents, xrefs))) @@ -2628,9 +2623,7 @@ def html_getobj(url): return title, content def html_error(url, exc): - heading = html.heading( - 'Error', - ) + heading = html.heading('Error') contents = '
    '.join(html.escape(line) for line in format_exception_only(type(exc), exc)) contents = heading + html.bigsection(url, 'error', contents) diff --git a/Lib/pydoc_data/_pydoc.css b/Lib/pydoc_data/_pydoc.css index a6aa2e4c1a021e..9e5c5c2f6f320d 100644 --- a/Lib/pydoc_data/_pydoc.css +++ b/Lib/pydoc_data/_pydoc.css @@ -3,110 +3,253 @@ Contents of this file are subject to change without notice. + The colors and fonts follow the python-docs-theme used by + docs.python.org. */ +:root { + color-scheme: light dark; + --text-color: #333; + --background-color: #fff; + --link-color: #0072aa; + --link-visited-color: #6363bb; + --link-hover-color: #00b0e4; + --muted-color: #707070; + --code-background-color: #eee; + --border-color: #ccc; + --target-background-color: #fbe54e; + --block-background-color: #eeffcc; + --block-border-color: #ac9; + --error-color: #ba2121; + --repr-color: #c040c0; +} + +@media (prefers-color-scheme: dark) { + :root { + --text-color: rgba(255, 255, 255, 0.87); + --background-color: #222; + --link-color: #77aaff; + --link-visited-color: #0099ee; + --link-hover-color: #00b0e4; + --muted-color: #999; + --code-background-color: #424242; + --border-color: #616161; + --target-background-color: #616161; + --block-background-color: #333; + --block-border-color: #616161; + --error-color: #f44c4e; + --repr-color: #d080d0; + } +} + body { - background-color: #f0f0f8; + font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, + noto, arial, sans-serif; + color: var(--text-color); + background-color: var(--background-color); + line-height: 1.4; + margin: 0; + padding: 0 1em 1em; } -table.heading tr { - background-color: #7799ee; +code, pre, .docstring, dl.doc > dt { + font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, + monospace; + font-size: 96.5%; } -.decor { - color: #ffffff; +a:link { + color: var(--link-color); } -.title-decor { - background-color: #ffc8d8; - color: #000000; +a:visited { + color: var(--link-visited-color); } -.pkg-content-decor { - background-color: #aa55cc; +a:hover { + color: var(--link-hover-color); } -.index-decor { - background-color: #ee77aa; +/* Page heading */ + +header.heading { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-end; + column-gap: 1em; + padding: 0.5em 0; + border-bottom: 1px solid var(--border-color); } -.functions-decor { - background-color: #eeaa77; +header.heading h1 { + margin: 0; + font-size: 1.8em; } -.data-decor { - background-color: #55aa55; +header.heading .extra { + text-align: right; + overflow-wrap: anywhere; } -.author-decor { - background-color: #7799ee; +/* Sections */ + +h2, h3, h4 { + margin: 0.6em 0 0.4em; } -.credits-decor { - background-color: #7799ee; +section > h2 { + border-bottom: 1px solid var(--border-color); + padding-bottom: 0.2em; + font-size: 1.4em; } -.error-decor { - background-color: #bb0000; +section > h3 { + font-size: 1.1em; } -.grey { - color: #909090; +section.error > h2 { + color: var(--error-color); } -.white { - color: #ffffff; +section section { + border: 1px solid var(--border-color); + border-radius: 3px; + padding: 0 0.8em 0.5em; + margin: 0.8em 0; } -.repr { - color: #c040c0; +/* Docstrings and other preformatted text */ + +.docstring { + white-space: pre-wrap; + margin: 0.3em 0; } -table.heading tr td.title { - vertical-align: bottom; +pre.topic, pre.keyword { + background-color: var(--block-background-color); + border: 1px solid var(--block-border-color); + border-radius: 3px; + padding: 0.5em 0.8em; + overflow-x: auto; } -table.heading tr td.extra { - vertical-align: bottom; - text-align: right; +/* Documented names (functions, methods, data) */ + +dl.doc { + margin: 0.5em 0; } -.heading-text { - font-family: helvetica, arial; +dl.doc > dt { + overflow-wrap: anywhere; } -.bigsection { - font-size: larger; +a:target { + background-color: var(--target-background-color); } -.title { - font-size: x-large; +dl.doc > dd { + margin: 0.2em 0 0.8em 2em; } -.code { - font-family: monospace; +.note { + font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, + noto, arial, sans-serif; + color: var(--muted-color); } -table { - width: 100%; - border-spacing : 0; - border-collapse : collapse; +.grey { + color: var(--muted-color); +} + +.repr { + color: var(--repr-color); +} + +hr { border: 0; + border-top: 1px solid var(--border-color); + margin: 0.8em 0; } -td { - padding: 2; +/* Inherited class members are collapsed by default. */ + +details.inherited > summary { + cursor: pointer; + margin: 0.6em 0 0.4em; } -td.section-title { - vertical-align: bottom; +/* Multi-column lists of modules, topics and keywords */ + +ul.multicolumn { + list-style-type: none; + column-width: 14em; + column-gap: 1em; + margin: 0.5em 0; + padding: 0; } -td.multicolumn { - width: 25%; - vertical-align: bottom; +ul.multicolumn > li { + overflow-wrap: anywhere; } -td.singlecolumn { - width: 100%; +/* Class hierarchy trees */ + +dl.tree, dl.tree dl { + margin: 0; +} + +dl.tree dd { + margin: 0 0 0 2em; +} + +/* Navigation bar of the pydoc server */ + +nav.navbar { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + column-gap: 1em; + row-gap: 0.3em; + padding: 0.5em 0; + border-bottom: 1px solid var(--border-color); + font-size: smaller; +} + +nav.navbar .navbar-version { + color: var(--muted-color); +} + +nav.navbar ul { + display: flex; + flex-wrap: wrap; + column-gap: 1em; + list-style-type: none; + margin: 0; + padding: 0; +} + +nav.navbar form { + display: inline-block; +} + +nav.navbar input { + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: var(--background-color); + border: 1px solid #999; + border-radius: 3px; +} + +footer { + margin-top: 1em; + padding-top: 0.3em; + border-top: 1px solid var(--border-color); + color: var(--muted-color); + font-size: smaller; + text-align: right; } diff --git a/Lib/random.py b/Lib/random.py index 4541267bab866a..7db761034509d3 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -861,7 +861,11 @@ def binomialvariate(self, n=1, p=0.5): u = random() u -= 0.5 us = 0.5 - _fabs(u) - k = _floor((2.0 * a / us + b) * u + c) + try: + k = _floor((2.0 * a / us + b) * u + c) + except ZeroDivisionError: + # Reject case where random() returned 0.0 + continue if k < 0 or k > n: continue v = random() diff --git a/Lib/test/test_colorsys.py b/Lib/test/test_colorsys.py index 74d76294b0b4d4..9dfaef44a6a450 100644 --- a/Lib/test/test_colorsys.py +++ b/Lib/test/test_colorsys.py @@ -42,6 +42,10 @@ def test_hsv_values(self): self.assertTripleEqual(hsv, colorsys.rgb_to_hsv(*rgb)) self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(*hsv)) + # test 360 phase shift in hue + h, s, v = hsv + self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(h + 1.0, s, v)) + def test_hls_roundtrip(self): for r in frange(0.0, 1.0, 0.2): for g in frange(0.0, 1.0, 0.2): @@ -89,6 +93,18 @@ def test_yiq_roundtrip(self): colorsys.yiq_to_rgb(*colorsys.rgb_to_yiq(*rgb)) ) + def test_yiq_to_rgb_clamping(self): + values = [ + # rgb, yiq (invalid YIQ values clamped to RGB range) + ((1.0, 0.0, 1.0), (0.0, 0.5, 1.0)), + ((0.0, 1.0, 0.0), (0.25, -1.0, -1.0)), + ((0.0, 0.0, 1.0), (0.0, -1.0, 0.5)) + ] + + for (rgb, yiq) in values: + with self.subTest(rgb=rgb, yiq=yiq): + self.assertTripleEqual(rgb, colorsys.yiq_to_rgb(*yiq)) + def test_yiq_values(self): values = [ # rgb, yiq diff --git a/Lib/test/test_ctypes/struct_str_ann.py b/Lib/test/test_ctypes/struct_str_ann.py new file mode 100644 index 00000000000000..7a924825dd81ee --- /dev/null +++ b/Lib/test/test_ctypes/struct_str_ann.py @@ -0,0 +1,15 @@ +from __future__ import annotations +from ctypes.util import struct +from ctypes import c_int + +class TestAnn: + x: c_int + +# Check that "from __future__ import annotations" works as expected +if not isinstance(TestAnn.__annotations__['x'], str): + raise Exception("annotations must be strings") + +@struct +class Point: + x: c_int + y: c_int diff --git a/Lib/test/test_ctypes/test_aligned_structures.py b/Lib/test/test_ctypes/test_aligned_structures.py index 50b4d729b9db8a..d58d92a19eb33c 100644 --- a/Lib/test/test_ctypes/test_aligned_structures.py +++ b/Lib/test/test_ctypes/test_aligned_structures.py @@ -3,29 +3,64 @@ BigEndianStructure, LittleEndianStructure, BigEndianUnion, LittleEndianUnion, Structure, ) +from ctypes.util import struct as struct_util import struct import unittest from ._support import StructCheckMixin +from test.support import subTests + + +def get_struct_base(endian): + if endian == 'big': + return BigEndianStructure + elif endian == 'little': + return LittleEndianStructure + elif endian == 'native': + return Structure + else: + raise ValueError('invalid endian') + +def get_union_base(endian): + if endian == 'big': + return BigEndianUnion + elif endian == 'little': + return LittleEndianUnion + else: + raise ValueError('invalid endian') + class TestAlignedStructures(unittest.TestCase, StructCheckMixin): - def test_aligned_string(self): - for base, e in ( - (LittleEndianStructure, "<"), - (BigEndianStructure, ">"), + @subTests("use_struct_util", [False, True]) + def test_aligned_string(self, use_struct_util): + for endian, e in ( + ('little', "<"), + ('big', ">"), ): data = bytearray(struct.pack(f"{e}i12x16s", 7, b"hello world!")) - class Aligned(base): - _align_ = 16 - _fields_ = [ - ('value', c_char * 12) - ] + if use_struct_util: + @struct_util(endian=endian, align=16) + class Aligned: + value: c_char * 12 + else: + base = get_struct_base(endian) + class Aligned(base): + _align_ = 16 + _fields_ = [ + ('value', c_char * 12) + ] self.check_struct(Aligned) - class Main(base): - _fields_ = [ - ('first', c_uint32), - ('string', Aligned), - ] + if use_struct_util: + @struct_util(endian=endian) + class Main: + first: c_uint32 + string: Aligned + else: + class Main(base): + _fields_ = [ + ('first', c_uint32), + ('string', Aligned), + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -37,24 +72,39 @@ class Main(base): self.assertEqual(alignment(main.string), 16) self.assertEqual(alignment(main), 16) - def test_aligned_structures(self): - for base, data in ( - (LittleEndianStructure, bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), - (BigEndianStructure, bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), + @subTests("use_struct_util", [False, True]) + def test_aligned_structures(self, use_struct_util): + for endian, data in ( + ('little', bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), + ('big', bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), ): - class SomeBools(base): - _align_ = 4 - _fields_ = [ - ("bool1", c_ubyte), - ("bool2", c_ubyte), - ] + if use_struct_util: + @struct_util(endian=endian, align=4) + class SomeBools: + bool1: c_ubyte + bool2: c_ubyte + else: + base = get_struct_base(endian) + class SomeBools(base): + _align_ = 4 + _fields_ = [ + ("bool1", c_ubyte), + ("bool2", c_ubyte), + ] self.check_struct(SomeBools) - class Main(base): - _fields_ = [ - ("x", c_ubyte), - ("y", SomeBools), - ("z", c_ubyte), - ] + if use_struct_util: + @struct_util(endian=endian) + class Main: + x: c_ubyte + y: SomeBools + z: c_ubyte + else: + class Main(base): + _fields_ = [ + ("x", c_ubyte), + ("y", SomeBools), + ("z", c_ubyte), + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -69,57 +119,93 @@ class Main(base): self.assertEqual(Main.z.offset, 8) self.assertEqual(main.z, 7) - def test_negative_align(self): - for base in (Structure, LittleEndianStructure, BigEndianStructure): + @subTests("use_struct_util", [False, True]) + def test_negative_align(self, use_struct_util): + for endian in ('native', 'little', 'big'): with ( - self.subTest(base=base), + self.subTest(endian=endian), self.assertRaisesRegex( ValueError, '_align_ must be a non-negative integer', ) ): - class MyStructure(base): - _align_ = -1 - _fields_ = [] - - def test_zero_align_no_fields(self): - for base in (Structure, LittleEndianStructure, BigEndianStructure): - with self.subTest(base=base): - class MyStructure(base): - _align_ = 0 - _fields_ = [] + if use_struct_util: + @struct_util(endian=endian, align=-1) + class MyStructure: + pass + else: + base = get_struct_base(endian) + class MyStructure(base): + _align_ = -1 + _fields_ = [] + + @subTests("use_struct_util", [False, True]) + def test_zero_align_no_fields(self, use_struct_util): + for endian in ('native', 'little', 'big'): + with self.subTest(endian=endian): + if use_struct_util: + @struct_util(endian=endian, align=0) + class MyStructure: + pass + else: + base = get_struct_base(endian) + class MyStructure(base): + _align_ = 0 + _fields_ = [] self.assertEqual(alignment(MyStructure), 1) self.assertEqual(alignment(MyStructure()), 1) - def test_zero_align_with_fields(self): - for base in (Structure, LittleEndianStructure, BigEndianStructure): - with self.subTest(base=base): - class MyStructure(base): - _align_ = 0 - _fields_ = [ - ("x", c_ubyte), - ] + @subTests("use_struct_util", [False, True]) + def test_zero_align_with_fields(self, use_struct_util): + for endian in ('native', 'little', 'big'): + with self.subTest(endian=endian): + if use_struct_util: + @struct_util(endian=endian, align=0) + class MyStructure: + x: c_ubyte + else: + base = get_struct_base(endian) + class MyStructure(base): + _align_ = 0 + _fields_ = [ + ("x", c_ubyte), + ] self.assertEqual(alignment(MyStructure), 1) self.assertEqual(alignment(MyStructure()), 1) - def test_oversized_structure(self): + @subTests("use_struct_util", [False, True]) + def test_oversized_structure(self, use_struct_util): data = bytearray(b"\0" * 8) - for base in (LittleEndianStructure, BigEndianStructure): - class SomeBoolsTooBig(base): - _align_ = 8 - _fields_ = [ - ("bool1", c_ubyte), - ("bool2", c_ubyte), - ("bool3", c_ubyte), - ] + for endian in ('little', 'big'): + if use_struct_util: + @struct_util(endian=endian, align=8) + class SomeBoolsTooBig: + bool1: c_ubyte + bool2: c_ubyte + bool3: c_ubyte + else: + base = get_struct_base(endian) + class SomeBoolsTooBig(base): + _align_ = 8 + _fields_ = [ + ("bool1", c_ubyte), + ("bool2", c_ubyte), + ("bool3", c_ubyte), + ] self.check_struct(SomeBoolsTooBig) - class Main(base): - _fields_ = [ - ("y", SomeBoolsTooBig), - ("z", c_uint32), - ] + if use_struct_util: + @struct_util(endian=endian) + class Main: + y: SomeBoolsTooBig + z: c_uint32 + else: + class Main(base): + _fields_ = [ + ("y", SomeBoolsTooBig), + ("z", c_uint32), + ] self.check_struct(Main) with self.assertRaises(ValueError) as ctx: Main.from_buffer(data) @@ -128,31 +214,49 @@ class Main(base): 'Buffer size too small (4 instead of at least 8 bytes)' ) - def test_aligned_subclasses(self): - for base, e in ( - (LittleEndianStructure, "<"), - (BigEndianStructure, ">"), + @subTests("use_struct_util", [False, True]) + def test_aligned_subclasses(self, use_struct_util): + for endian, e in ( + ('little', "<"), + ('big', ">"), ): data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) - class UnalignedSub(base): - x: c_uint32 - _fields_ = [ - ("x", c_uint32), - ] + if use_struct_util: + @struct_util(endian=endian) + class UnalignedSub: + x: c_uint32 + else: + base = get_struct_base(endian) + class UnalignedSub(base): + x: c_uint32 + _fields_ = [ + ("x", c_uint32), + ] self.check_struct(UnalignedSub) - class AlignedStruct(UnalignedSub): - _align_ = 8 - _fields_ = [ - ("y", c_uint32), - ] + if use_struct_util: + @struct_util(endian=endian, align=8) + class AlignedStruct(UnalignedSub): + y: c_uint32 + else: + class AlignedStruct(UnalignedSub): + _align_ = 8 + _fields_ = [ + ("y", c_uint32), + ] self.check_struct(AlignedStruct) - class Main(base): - _fields_ = [ - ("a", c_uint32), - ("b", AlignedStruct) - ] + if use_struct_util: + @struct_util(endian=endian) + class Main: + a: c_uint32 + b: AlignedStruct + else: + class Main(base): + _fields_ = [ + ("a", c_uint32), + ("b", AlignedStruct) + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -166,12 +270,14 @@ class Main(base): self.assertEqual(Main.b.offset, 8) self.assertEqual(Main.b.size, 8) - def test_aligned_union(self): - for sbase, ubase, e in ( - (LittleEndianStructure, LittleEndianUnion, "<"), - (BigEndianStructure, BigEndianUnion, ">"), + @subTests("use_struct_util", [False, True]) + def test_aligned_union(self, use_struct_util): + for sendian, uendian, e in ( + ('little', 'little', "<"), + ('big', 'big', ">"), ): data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) + ubase = get_union_base(uendian) class AlignedUnion(ubase): _align_ = 8 _fields_ = [ @@ -180,11 +286,18 @@ class AlignedUnion(ubase): ] self.check_union(AlignedUnion) - class Main(sbase): - _fields_ = [ - ("first", c_uint32), - ("union", AlignedUnion), - ] + if use_struct_util: + @struct_util(endian=sendian) + class Main: + first: c_uint32 + union: AlignedUnion + else: + sbase = get_struct_base(sendian) + class Main(sbase): + _fields_ = [ + ("first", c_uint32), + ("union", AlignedUnion), + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -196,20 +309,29 @@ class Main(sbase): self.assertEqual(alignment(main.union), 8) self.assertEqual(alignment(main), 8) - def test_aligned_struct_in_union(self): - for sbase, ubase, e in ( - (LittleEndianStructure, LittleEndianUnion, "<"), - (BigEndianStructure, BigEndianUnion, ">"), + @subTests("use_struct_util", [False, True]) + def test_aligned_struct_in_union(self, use_struct_util): + for sendian, uendian, e in ( + ('little', 'little', "<"), + ('big', 'big', ">"), ): data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) - class Sub(sbase): - _align_ = 8 - _fields_ = [ - ("x", c_uint32), - ("y", c_uint32), - ] + if use_struct_util: + @struct_util(endian=sendian, align=8) + class Sub: + x: c_uint32 + y: c_uint32 + else: + sbase = get_struct_base(sendian) + class Sub(sbase): + _align_ = 8 + _fields_ = [ + ("x", c_uint32), + ("y", c_uint32), + ] self.check_struct(Sub) + ubase = get_union_base(uendian) class MainUnion(ubase): _fields_ = [ ("a", c_uint32), @@ -217,11 +339,17 @@ class MainUnion(ubase): ] self.check_union(MainUnion) - class Main(sbase): - _fields_ = [ - ("first", c_uint32), - ("union", MainUnion), - ] + if use_struct_util: + @struct_util(endian=sendian) + class Main: + first: c_uint32 + union: MainUnion + else: + class Main(sbase): + _fields_ = [ + ("first", c_uint32), + ("union", MainUnion), + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -235,12 +363,14 @@ class Main(sbase): self.assertEqual(main.union.b.x, 3) self.assertEqual(main.union.b.y, 4) - def test_smaller_aligned_subclassed_union(self): - for sbase, ubase, e in ( - (LittleEndianStructure, LittleEndianUnion, "<"), - (BigEndianStructure, BigEndianUnion, ">"), + @subTests("use_struct_util", [False, True]) + def test_smaller_aligned_subclassed_union(self, use_struct_util): + for sendian, uendian, e in ( + ('little', 'little', "<"), + ('big', 'big', ">"), ): data = bytearray(struct.pack(f"{e}H2xI", 1, 0xD60102D7)) + ubase = get_union_base(uendian) class SubUnion(ubase): _align_ = 2 _fields_ = [ @@ -255,11 +385,18 @@ class MainUnion(SubUnion): ] self.check_union(SubUnion) - class Main(sbase): - _fields_ = [ - ("first", c_uint16), - ("union", MainUnion), - ] + if use_struct_util: + @struct_util(endian=sendian) + class Main: + first: c_uint16 + union: MainUnion + else: + sbase = get_struct_base(sendian) + class Main(sbase): + _fields_ = [ + ("first", c_uint16), + ("union", MainUnion), + ] self.check_struct(Main) main = Main.from_buffer(data) @@ -273,11 +410,12 @@ class Main(sbase): self.assertEqual(Main.first.size, 2) def test_larger_aligned_subclassed_union(self): - for ubase, e in ( - (LittleEndianUnion, "<"), - (BigEndianUnion, ">"), + for uendian, e in ( + ('little', "<"), + ('big', ">"), ): data = bytearray(struct.pack(f"{e}I4x", 0xD60102D6)) + ubase = get_union_base(uendian) class SubUnion(ubase): _align_ = 8 _fields_ = [ @@ -299,29 +437,44 @@ class Main(SubUnion): self.assertEqual(main.unsigned, 0xD6) self.assertEqual(main.signed, -42) - def test_aligned_packed_structures(self): - for sbase, e in ( - (LittleEndianStructure, "<"), - (BigEndianStructure, ">"), + @subTests("use_struct_util", [False, True]) + def test_aligned_packed_structures(self, use_struct_util): + for sendian, e in ( + ('little', "<"), + ('big', ">"), ): data = bytearray(struct.pack(f"{e}B2H4xB", 1, 2, 3, 4)) - class Inner(sbase): - _align_ = 8 - _fields_ = [ - ("x", c_uint16), - ("y", c_uint16), - ] + if use_struct_util: + @struct_util(endian=sendian, align=8) + class Inner: + x: c_uint16 + y: c_uint16 + else: + sbase = get_struct_base(sendian) + class Inner(sbase): + _align_ = 8 + _fields_ = [ + ("x", c_uint16), + ("y", c_uint16), + ] self.check_struct(Inner) - class Main(sbase): - _pack_ = 1 - _layout_ = "ms" - _fields_ = [ - ("a", c_ubyte), - ("b", Inner), - ("c", c_ubyte), - ] + if use_struct_util: + @struct_util(endian=sendian, pack=1, layout="ms") + class Main: + a: c_ubyte + b: Inner + c: c_ubyte + else: + class Main(sbase): + _pack_ = 1 + _layout_ = "ms" + _fields_ = [ + ("a", c_ubyte), + ("b", Inner), + ("c", c_ubyte), + ] self.check_struct(Main) main = Main.from_buffer(data) diff --git a/Lib/test/test_ctypes/test_funcptr.py b/Lib/test/test_ctypes/test_funcptr.py index 94d03ad553d222..86699ad8109827 100644 --- a/Lib/test/test_ctypes/test_funcptr.py +++ b/Lib/test/test_ctypes/test_funcptr.py @@ -151,6 +151,11 @@ def noexist(): def PyObject_GetAttrString(op: ctypes.py_object, attr: ctypes.c_char_p): pass + def test_wrap_dll_function_str_ann(self): + from test.test_ctypes import wrap_str_ann + version = wrap_str_ann.Py_GetVersion() + self.assertIsInstance(version, bytes) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 4dc1ea867c0700..a74a3548ee7841 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -88,13 +88,14 @@ class X(Structure): self.assertEqual(sizeof(X), min(8, longlong_align) + longlong_size) self.assertEqual(X.b.offset, min(8, longlong_align)) - with self.assertRaises(ValueError): - if use_struct_util: + if use_struct_util: + with self.assertRaises(NameError): @struct_util(pack=-1, layout='ms') class X: a: "b" b: "q" - else: + else: + with self.assertRaises(ValueError): class X(Structure): _fields_ = [("a", "b"), ("b", "q")] _pack_ = -1 @@ -954,6 +955,12 @@ class Foo: self.assertEqual(Foo.__name__, "Foo") + def test_string_annotations(self): + from test.test_ctypes import struct_str_ann + Point = struct_str_ann.Point + fields = [('x', c_int), ('y', c_int)] + self.assertEqual(Point._fields_, fields) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/wrap_str_ann.py b/Lib/test/test_ctypes/wrap_str_ann.py new file mode 100644 index 00000000000000..aa114a640c3a99 --- /dev/null +++ b/Lib/test/test_ctypes/wrap_str_ann.py @@ -0,0 +1,13 @@ +from __future__ import annotations +import ctypes.util + +def test_ann() -> ctypes.c_char_p: + ... + +# Check that "from __future__ import annotations" works as expected +if not isinstance(test_ann.__annotations__['return'], str): + raise Exception("annotations must be strings") + +@ctypes.util.wrap_dll_function(ctypes.pythonapi) +def Py_GetVersion() -> ctypes.c_char_p: + ... diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 915eae5ec233d5..b0592d3f1d92b9 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -785,13 +785,10 @@ def test_output_character(self): stdscr.move(2, 0) stdscr.echochar(v) self.assertEqual(self._read_char(2, 0), c) - # insch() round-trips a byte only where its code point equals - # the byte value (Latin-1): on a wide build ncurses winsch - # stores a printable byte directly as a code point instead of - # decoding it through the locale. - if ord(c) < 0x100: - stdscr.insch(1, 0, v) - self.assertEqual(self._read_char(1, 0), c) + # insch() decodes the byte through the locale like addch(), so + # it round-trips the same character. + stdscr.insch(1, 0, v) + self.assertEqual(self._read_char(1, 0), c) # The same characters supplied as a str. Unlike the int path above, a # str is stored as a wide-character cell on a wide build, so every @@ -958,10 +955,9 @@ def test_read_from_window(self): self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) # A non-ASCII character of an 8-bit locale reads back as its encoded - # byte (see _encodable for the set). instr() returns the locale bytes - # for any single-byte character; inch() packs the text into a chtype, so - # on a wide build it only round-trips a Latin-1 codepoint (byte == - # codepoint). + # byte (see _encodable for the set). Both instr() and inch() return the + # locale byte for any character that fits the locale's single-byte + # encoding. encoding = stdscr.encoding for ch in ('A', 'é', '¤', '€', 'є'): try: @@ -973,8 +969,7 @@ def test_read_from_window(self): with self.subTest(ch=ch): stdscr.addstr(2, 0, ch) self.assertEqual(stdscr.instr(2, 0, 1), b) - if ord(ch) < 0x100: - self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) + self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) def test_coordinate_errors(self): # Addressing a cell outside the window raises curses.error. diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py index 2ad422079b7f23..64edc7b7e191d4 100644 --- a/Lib/test/test_docxmlrpc.py +++ b/Lib/test/test_docxmlrpc.py @@ -127,7 +127,7 @@ def test_lambda(self): self.client.request("GET", "/") response = self.client.getresponse() - self.assertIn((b'
    ' + self.assertIn((b'
    ' b'<lambda>(x, y)
    '), response.read()) @@ -144,16 +144,17 @@ def test_autolinking(self): response = self.client.getresponse().read() self.assertIn( - (b'
    add(x, y)
    ' - b'Add two instances together. This ' - b'follows ' - b'PEP008, but has nothing
    \nto do ' - b'with ' - b'RFC1952. Case should matter: pEp008 ' - b'and rFC1952.  Things
    \nthat start ' - b'with http and ftp should be ' - b'auto-linked, too:
    \n' - b'http://google.com.
    '), response) + (b'
    add' + b'(x, y)
    ' + b'Add two instances together. This ' + b'follows ' + b'PEP008, but has nothing\nto do ' + b'with ' + b'RFC1952. Case should matter: pEp008 ' + b'and rFC1952. Things\nthat start ' + b'with http and ftp should be ' + b'auto-linked, too:\n' + b'http://google.com.
    '), response) @make_request_and_skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") @@ -167,22 +168,24 @@ def test_system_methods(self): response = self.client.getresponse().read() self.assertIn( - (b'
    system.methodHelp' - b'(method_name)
    system.methodHelp(\'add\') => "Adds ' - b'two integers together"
    \n 
    \nReturns a' - b' string containing documentation for ' - b'the specified method.
    \n
    system.methodSignature' - b'(method_name)
    ' - b'system.methodSignature(\'add\') => [double, ' - b'int, int]
    \n 
    \nReturns a list ' - b'describing the signature of the method.' - b' In the
    \nabove example, the add ' - b'method takes two integers as arguments' - b'
    \nand returns a double result.
    \n ' - b'
    \nThis server does NOT support system' - b'.methodSignature.
    '), response) + (b'
    ' + b'system.methodHelp(method_name)
    ' + b'
    system.methodHelp(\'add\') => "Adds ' + b'two integers together"\n\nReturns a' + b' string containing documentation for ' + b'the specified method.
    \n
    system.methodSignature' + b'(method_name)
    ' + b'' + b'system.methodSignature(\'add\') => [double, ' + b'int, int]\n\nReturns a list ' + b'describing the signature of the method.' + b' In the\nabove example, the add ' + b'method takes two integers as arguments' + b'\nand returns a double result.\n\n' + b'This server does NOT support system' + b'.methodSignature.
    '), response) def test_autolink_dotted_methods(self): """Test that selfdot values are made strong automatically in the @@ -190,7 +193,7 @@ def test_autolink_dotted_methods(self): self.client.request("GET", "/") response = self.client.getresponse() - self.assertIn(b"""Try self.add, too.""", + self.assertIn(b"""Try self.add, too.""", response.read()) def test_annotations(self): @@ -198,11 +201,11 @@ def test_annotations(self): self.client.request("GET", "/") response = self.client.getresponse() docstring = (b'' if sys.flags.optimize >= 2 else - b'
    Use function annotations.
    ') + b'
    Use function annotations.
    ') self.assertIn( - (b'
    annotation' - b'(x: int)
    ' + docstring + b'
    \n' - b'
    ' + (b'
    annotation' + b'(x: int)
    ' + docstring + b'
    \n' + b'
    ' b'method_annotation(x: bytes)
    '), response.read()) @@ -217,9 +220,11 @@ def test_server_title_escape(self): generated = self.serv.generate_html_documentation() title = re.search(r'(.+?)', generated).group() - documentation = re.search(r'

    (.+?)

    ', generated).group() + documentation = re.search(r'
    (.+?)
    ', + generated).group() self.assertEqual('Python: test_title<script>', title) - self.assertEqual('

    test_documentation<script>

    ', documentation) + self.assertEqual('
    test_documentation<script>
    ', + documentation) if __name__ == '__main__': diff --git a/Lib/test/test_pathlib/test_read.py b/Lib/test/test_pathlib/test_read.py index 16fb555b2aee05..51eede9d9ebafb 100644 --- a/Lib/test/test_pathlib/test_read.py +++ b/Lib/test/test_pathlib/test_read.py @@ -329,6 +329,11 @@ def test_info_is_symlink(self): self.assertFalse((p / 'fileA\udfff').info.is_symlink()) self.assertFalse((p / 'fileA\x00').info.is_symlink()) + def test_invalid_mode(self): + p = self.root / 'fileA' + with self.assertRaisesRegex(ValueError, 'invalid mode'): + vfsopen(p, 'q') + class ZipPathReadTest(ReadTestBase, unittest.TestCase): ground = ZipPathGround(ReadableZipPath) diff --git a/Lib/test/test_pydoc/test_pydoc.py b/Lib/test/test_pydoc/test_pydoc.py index 25f94c4c740e1e..34d30f54e9c9c7 100644 --- a/Lib/test/test_pydoc/test_pydoc.py +++ b/Lib/test/test_pydoc/test_pydoc.py @@ -369,7 +369,7 @@ def html2text(html): Tailored for pydoc tests only. """ - html = html.replace("
    ", "\n") + html = re.sub(r"]*>", "\n", html) html = html.replace("
    ", "-"*70) html = re.sub("<.*?>", "", html) html = pydoc.replace(html, " ", " ", ">", ">", "<", "<") @@ -1913,7 +1913,7 @@ async def coro_function(ign) -> int: html = pydoc.HTMLDoc().document(coro_function) self.assertIn( - 'async coro_function', + 'async coro_function', html) def test_async_generator_annotation(self): @@ -1925,7 +1925,7 @@ async def an_async_generator(): html = pydoc.HTMLDoc().document(an_async_generator) self.assertIn( - 'async an_async_generator', + 'async an_async_generator', html) @requires_docstrings @@ -2091,7 +2091,7 @@ def test_html_doc_routines_in_module(self): doc = pydoc.HTMLDoc() result = doc.docmodule(pydocfodder) result = html2text(result) - lines = self.getsection(result, ' Functions', None) + lines = self.getsection(result, 'Functions', None) # function alias self.assertIn(' global_func_alias = global_func(x, y)', lines) self.assertIn(' A_staticmethod(x, y)', lines) diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index dbd3b855f536a0..8d093ab1b7014a 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -1082,6 +1082,14 @@ def test_binomialvariate_log_zero(self): self.assertIsInstance(result, int) self.assertIn(result, range(11)) + def test_binomialvariate_btrs_random_zero(self): + for p, expected in ((0.25, 25), (0.75, 75)): + with self.subTest(p=p): + g = random.Random() + with unittest.mock.patch.object( + g, 'random', side_effect=(0.0, 0.5, 0.5)): + self.assertEqual(g.binomialvariate(100, p), expected) + def test_constant(self): g = random.Random() N = 100 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 352a9c2a0c6106..6446f96eab42a4 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -49,12 +49,15 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = socket_helper.HOST IS_AWS_LC = "AWS-LC" in ssl.OPENSSL_VERSION +IS_LIBRESSL = "LibreSSL" in ssl.OPENSSL_VERSION IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0) CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2) CAN_IGNORE_UNKNOWN_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 3) CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5) CAN_GET_AVAILABLE_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 4) -CAN_SET_CLIENT_SIGALGS = not IS_AWS_LC +# LibreSSL does not provide SSL_CTX_set1_(client_)sigalgs_list(). +CAN_SET_CLIENT_SIGALGS = not IS_AWS_LC and not IS_LIBRESSL +CAN_SET_SERVER_SIGALGS = not IS_LIBRESSL CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 3) CAN_GET_SELECTED_OPENSSL_SIGALG = ssl.OPENSSL_VERSION_INFO >= (3, 5) PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS') @@ -1080,6 +1083,8 @@ def test_set_client_sigalgs(self): if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS: self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256:?foo')) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_set_server_sigalgs(self): ctx = ssl.create_default_context() @@ -4593,6 +4598,8 @@ def test_client_sigalgs_mismatch(self): chatty=True, connectionchatty=True, sni_name=hostname) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_server_sigalgs(self): # server rsa_pss_rsae_sha384, client auto sigalg = "rsa_pss_rsae_sha384" @@ -4613,6 +4620,8 @@ def test_server_sigalgs(self): if CAN_GET_SELECTED_OPENSSL_SIGALG: self.assertEqual(stats['server_sigalg'], sigalg) + @unittest.skipUnless(CAN_SET_SERVER_SIGALGS, + "SSL library doesn't support setting server sigalgs") def test_server_sigalgs_mismatch(self): client_context, server_context, hostname = testing_context() client_context.set_server_sigalgs("rsa_pss_rsae_sha256") diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py index 3e6871157d0929..5ef68640a09ba4 100644 --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -752,7 +752,7 @@ def docroutine(self, object, name, mod=None, anchor = (cl and cl.__name__ or '') + '-' + name note = '' - title = '%s' % ( + title = '%s' % ( self.escape(anchor), self.escape(name)) if callable(object): @@ -766,13 +766,13 @@ def docroutine(self, object, name, mod=None, else: docstring = pydoc.getdoc(object) - decl = title + argspec + (note and self.grey( - '%s' % note)) + decl = title + argspec + (note and + '%s' % note) doc = self.markup( docstring, self.preformat, funcs, classes, methods) - doc = doc and '
    %s
    ' % doc - return '
    %s
    %s
    \n' % (decl, doc) + doc = doc and '
    %s
    ' % doc + return '
    %s
    %s
    \n' % (decl, doc) def docserver(self, server_name, package_documentation, methods): """Produce HTML documentation for an XML-RPC server.""" @@ -783,12 +783,11 @@ def docserver(self, server_name, package_documentation, methods): fdict[value] = fdict[key] server_name = self.escape(server_name) - head = '%s' % server_name - result = self.heading(head) + result = self.heading(server_name) doc = self.markup(package_documentation, self.preformat, fdict) - doc = doc and '%s' % doc - result = result + '

    %s

    \n' % doc + doc = doc and '
    %s
    \n' % doc + result = result + doc contents = [] method_items = sorted(methods.items()) @@ -807,12 +806,15 @@ def page(self, title, contents): '' % css_path) return '''\ - + + Python: %s -%s%s''' % (title, css_link, contents) +%s +%s +''' % (title, css_link, contents) class XMLRPCDocGenerator: """Generates documentation for an XML-RPC server. diff --git a/Misc/NEWS.d/next/Build/2026-07-18-14-30-12.gh-issue-136687.teaPCG.rst b/Misc/NEWS.d/next/Build/2026-07-18-14-30-12.gh-issue-136687.teaPCG.rst new file mode 100644 index 00000000000000..a2c7a86f4430be --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-07-18-14-30-12.gh-issue-136687.teaPCG.rst @@ -0,0 +1,4 @@ +Add the :option:`--with-curses` option to :program:`configure` to select the +curses backend (``ncursesw``, ``ncurses`` or the system's native ``curses``) or, +as :option:`--without-curses`, to exclude the :mod:`curses` and +:mod:`curses.panel` modules from the build. diff --git a/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst b/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst new file mode 100644 index 00000000000000..aa646dc6c49174 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-17-20-31-00.gh-issue-153862.X3kjoY.rst @@ -0,0 +1,3 @@ +On a wide :mod:`curses` build, :meth:`curses.window.inch` now returns the +locale-encoded byte of a non-ASCII character, matching +:meth:`~curses.window.instr`, instead of the low byte of its code point. diff --git a/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst b/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst new file mode 100644 index 00000000000000..79857185d7d0c7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-17-20-56-32.gh-issue-153864.WmA9By.rst @@ -0,0 +1,3 @@ +On a wide :mod:`curses` build, :meth:`curses.window.insch` now inserts a +non-ASCII byte as the character it encodes in the window's encoding, +consistently with :meth:`~curses.window.addch`, instead of its code point. diff --git a/Misc/NEWS.d/next/Library/2026-07-18-13-30-00.gh-issue-153906.mHtNdY.rst b/Misc/NEWS.d/next/Library/2026-07-18-13-30-00.gh-issue-153906.mHtNdY.rst new file mode 100644 index 00000000000000..487587145f1a3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-13-30-00.gh-issue-153906.mHtNdY.rst @@ -0,0 +1,4 @@ +Modernize the HTML output of :mod:`pydoc`: use semantic HTML5 markup and +a new style sheet based on the python-docs-theme used by docs.python.org, +with dark mode support. Class members inherited from other classes are +now collapsed by default. diff --git a/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst b/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst new file mode 100644 index 00000000000000..ff019aa3618847 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-18-17-09-49.gh-issue-154001.3brrUv.rst @@ -0,0 +1,2 @@ +Fix :func:`random.binomialvariate` raising :exc:`ZeroDivisionError` +when :func:`random.random` returns zero. diff --git a/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst b/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst new file mode 100644 index 00000000000000..3d453eb7314345 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-19-00-00-00.gh-issue-154053.LibreSSLsigalgs.rst @@ -0,0 +1,4 @@ +Fix compilation of the :mod:`ssl` module against LibreSSL, which does not +provide ``SSL_CTX_set1_sigalgs_list()`` and ``SSL_CTX_set1_client_sigalgs_list()``. +The :meth:`!set_server_sigalgs` and :meth:`!set_client_sigalgs` methods of +:class:`ssl.SSLContext` now raise :exc:`NotImplementedError` on LibreSSL. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index cc68a51f0bed93..2253d9ff3d704f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -774,6 +774,30 @@ curses_getcchar(const cchar_t *wcval, wchar_t *wstr, attr_t *attrs, int *pair) return rtn; } +/* winch() returns the low 8 bits of the character's code point with no locale + conversion, unlike instr(), so recover the locale byte from the wide cell + when the character maps to exactly one byte, keeping the attribute and color + bits in RTN. A character with no single-byte form is left to winch(). */ +static chtype +curses_cell_locale_byte(chtype rtn, const cchar_t *cell) +{ + wchar_t wstr[CCHARW_MAX + 1]; + attr_t attrs; + int pair; + if (curses_getcchar(cell, wstr, &attrs, &pair) == ERR + || wstr[0] == L'\0' || wstr[1] != L'\0') + { + return rtn; + } + /* wctob() mirrors ncurses' own _nc_to_char(): the single-byte form, or EOF + when the character has none in this locale. */ + int byte = wctob(wstr[0]); + if (byte != EOF) { + rtn = (rtn & ~(chtype)A_CHARTEXT) | (unsigned char)byte; + } + return rtn; +} + /* Hash one cell by value (text, attributes, pair) -- consistent with the equality comparison, not the raw cchar_t whose padding and unused text tail it ignores. Zero the key first so those bytes are deterministic, then @@ -3544,6 +3568,24 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, if (type == 0) { return NULL; } + if (type == 1) { + /* winsch() does not locale-decode a byte above 127 on a wide build, + unlike waddch(), so decode it here and insert it as a wide + character. (gh-153864) */ + chtype cch = ch_ & A_CHARTEXT; + if (cch > 127) { + wint_t wc = btowc((int)cch); + if (wc != WEOF) { + wchar_t wstr[2] = { (wchar_t)wc, L'\0' }; + attr_t cattr = (attr_t)((ch_ | attr) & ~(chtype)A_CHARTEXT); + if (curses_setcchar(&wch, wstr, cattr, PAIR_NUMBER(cattr)) == ERR) { + curses_window_set_error(self, "setcchar", "insch"); + return NULL; + } + type = 2; + } + } + } if (type == 2) { if (!group_left_1) { rtn = wins_wch(self->win, &wch); @@ -3609,6 +3651,14 @@ _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, curses_window_set_error(self, funcname, "inch"); return NULL; } +#ifdef HAVE_NCURSESW + curses_cell_t cell = {0}; + if ((group_right_1 ? mvwin_wch(self->win, y, x, &cell) + : win_wch(self->win, &cell)) != ERR) + { + rtn = curses_cell_locale_byte(rtn, &cell); + } +#endif return PyLong_FromUnsignedLong(rtn); } diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 20564e1ba4165a..9f8a6a58cd9327 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3863,6 +3863,10 @@ _ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self, #ifdef OPENSSL_IS_AWSLC _setSSLError(get_state_ctx(self), "can't set client sigalgs on AWS-LC", 0, __FILE__, __LINE__); return NULL; +#elif defined(LIBRESSL_VERSION_NUMBER) + PyErr_SetString(PyExc_NotImplementedError, + "setting client sigalgs is not supported by LibreSSL"); + return NULL; #else if (!SSL_CTX_set1_client_sigalgs_list(self->ctx, sigalgslist)) { _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); @@ -3884,11 +3888,17 @@ _ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self, const char *sigalgslist) /*[clinic end generated code: output=31ecb1d310285644 input=653b752e4f8d801b]*/ { +#ifdef LIBRESSL_VERSION_NUMBER + PyErr_SetString(PyExc_NotImplementedError, + "setting server sigalgs is not supported by LibreSSL"); + return NULL; +#else if (!SSL_CTX_set1_sigalgs_list(self->ctx, sigalgslist)) { _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__); return NULL; } Py_RETURN_NONE; +#endif } static int diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6562546ae2f9cc..a4550c0f5f3363 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8279,7 +8279,10 @@ _PyUnicode_DecodeIconv(const char *encoding, char *outptr = (char *)chunk; size_t outleft = sizeof(chunk); - size_t ret = iconv(cd, &inptr, &inleft, &outptr, &outleft); + /* Cast the input buffer through void*: iconv() declares its second + argument as "char **" on most systems but "const char **" on some + (e.g. illumos), and void* converts to either without a warning. */ + size_t ret = iconv(cd, (void *)&inptr, &inleft, &outptr, &outleft); int err = errno; in = inptr; @@ -8452,7 +8455,8 @@ _PyUnicode_EncodeIconv(const char *encoding, PyObject *unicode, size_t outleft = (size_t)(outend - out); /* When the whole string is converted, a final iconv() call with a NULL input flushes any pending shift sequence (e.g. ISO-2022). */ - size_t ret = iconv(cd, flushing ? NULL : &inptr, &inleft, &out, &outleft); + /* See the note above on the void* cast of the iconv() input buffer. */ + size_t ret = iconv(cd, flushing ? NULL : (void *)&inptr, &inleft, &out, &outleft); if (!flushing) { up = inptr; } diff --git a/configure b/configure index c8494891087d04..9061cf905119c4 100755 --- a/configure +++ b/configure @@ -1147,6 +1147,7 @@ enable_big_digits with_platlibdir with_wheel_pkg_dir with_readline +with_curses with_computed_gotos with_tail_call_interp with_remote_debug @@ -1969,6 +1970,10 @@ Optional Packages: (default: none) --with(out)-readline[=editline|readline|no] use libedit for backend or disable readline module + --with(out)-curses[=ncursesw|ncurses|curses|no] + select the curses backend for the curses and + _curses_panel modules, or disable them (default: + auto) --with-computed-gotos enable computed gotos in evaluation loop (enabled by default on supported compilers) --with-tail-call-interp enable tail-calling interpreter in evaluation loop @@ -29281,26 +29286,777 @@ fi have_curses=no have_panel=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-curses" >&5 +printf %s "checking for --with-curses... " >&6; } + +# Check whether --with-curses was given. +if test ${with_curses+y} +then : + withval=$with_curses; case $with_curses in #( + yes|auto) : + with_curses=auto ;; #( + ncursesw|ncurses|curses|no) : + ;; #( + *) : + as_fn_error $? "proper usage is --with(out)-curses[=ncursesw|ncurses|curses|no]" "$LINENO" 5 ;; +esac +else case e in #( + e) with_curses=auto ;; +esac +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_curses" >&5 +printf "%s\n" "$with_curses" >&6; } + + + +# Detect the selected backend. ncursesw/ncurses are found via pkg-config; +# native curses has no .pc file and is left to the header/link probes below. +# curses_libs/panel_libs drive the AC_SEARCH_LIBS fallback; for "no" they are +# empty so nothing links and have_curses stays "no". +case $with_curses in #( + ncursesw) : + + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 +printf %s "checking for ncursesw... " >&6; } + +if test -n "$CURSES_CFLAGS"; then + pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$CURSES_LIBS"; then + pkg_cv_CURSES_LIBS="$CURSES_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + CURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncursesw" 2>&1` + else + CURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncursesw" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$CURSES_PKG_ERRORS" >&5 + + have_curses=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_curses=no +else + CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS + CURSES_LIBS=$pkg_cv_CURSES_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h + + have_curses=yes + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 +printf %s "checking for panelw... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panelw" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panelw" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + have_panel=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + have_panel=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_PANELW 1" >>confdefs.h + + have_panel=yes +fi +fi + + + curses_libs="ncursesw"; panel_libs="panelw gnupanel" ;; #( + ncurses) : + + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncurses" >&5 +printf %s "checking for ncurses... " >&6; } + +if test -n "$CURSES_CFLAGS"; then + pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncurses") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncurses" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$CURSES_LIBS"; then + pkg_cv_CURSES_LIBS="$CURSES_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncurses\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncurses") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncurses" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + CURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncurses" 2>&1` + else + CURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncurses" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$CURSES_PKG_ERRORS" >&5 + + have_curses=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_curses=no +else + CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS + CURSES_LIBS=$pkg_cv_CURSES_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_NCURSES 1" >>confdefs.h + + have_curses=yes + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panel" >&5 +printf %s "checking for panel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + have_panel=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + have_panel=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_PANEL 1" >>confdefs.h + + have_panel=yes +fi +fi + + + curses_libs="ncurses"; panel_libs="panel gnupanel" ;; #( + curses) : + curses_libs="curses"; panel_libs="panel" ;; #( + no) : + curses_libs=""; panel_libs="" ;; #( + *) : + + + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 +printf %s "checking for ncursesw... " >&6; } + +if test -n "$CURSES_CFLAGS"; then + pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$CURSES_LIBS"; then + pkg_cv_CURSES_LIBS="$CURSES_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + CURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncursesw" 2>&1` + else + CURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncursesw" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$CURSES_PKG_ERRORS" >&5 + + have_curses=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_curses=no +else + CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS + CURSES_LIBS=$pkg_cv_CURSES_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h + + have_curses=yes + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 +printf %s "checking for panelw... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 + ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi -# Check for ncursesw/panelw first. If that fails, try ncurses/panel. +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panelw" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panelw" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 -printf %s "checking for ncursesw... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } -if test -n "$CURSES_CFLAGS"; then - pkg_cv_CURSES_CFLAGS="$CURSES_CFLAGS" +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 - ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_CURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -29308,16 +30064,16 @@ fi else pkg_failed=untried fi -if test -n "$CURSES_LIBS"; then - pkg_cv_CURSES_LIBS="$CURSES_LIBS" +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 - ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_CURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -29338,42 +30094,43 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - CURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncursesw" 2>&1` + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` else - CURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncursesw" 2>&1` + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` fi # Put the nasty error message in config.log where it belongs - echo "$CURSES_PKG_ERRORS" >&5 + echo "$PANEL_PKG_ERRORS" >&5 - have_curses=no + have_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } - have_curses=no + have_panel=no else - CURSES_CFLAGS=$pkg_cv_CURSES_CFLAGS - CURSES_LIBS=$pkg_cv_CURSES_LIBS + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h - - have_curses=yes + have_panel=yes +fi +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } pkg_failed=no -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 -printf %s "checking for panelw... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } if test -n "$PANEL_CFLAGS"; then pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 - ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -29385,12 +30142,12 @@ if test -n "$PANEL_LIBS"; then pkg_cv_PANEL_LIBS="$PANEL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 - ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -29411,9 +30168,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panelw" 2>&1` + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` else - PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panelw" 2>&1` + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PANEL_PKG_ERRORS" >&5 @@ -29423,6 +30180,13 @@ elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi else PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS PANEL_LIBS=$pkg_cv_PANEL_LIBS @@ -29436,7 +30200,7 @@ fi fi -if test "x$have_curses" = xno + if test "x$have_curses" = xno then : @@ -29572,11 +30336,151 @@ fi # Put the nasty error message in config.log where it belongs echo "$PANEL_PKG_ERRORS" >&5 + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + + have_panel=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanel" >&5 +printf %s "checking for gnupanel... " >&6; } + +if test -n "$PANEL_CFLAGS"; then + pkg_cv_PANEL_CFLAGS="$PANEL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_CFLAGS=`$PKG_CONFIG --cflags "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$PANEL_LIBS"; then + pkg_cv_PANEL_LIBS="$PANEL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanel\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gnupanel") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_PANEL_LIBS=`$PKG_CONFIG --libs "gnupanel" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + PANEL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanel" 2>&1` + else + PANEL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanel" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$PANEL_PKG_ERRORS" >&5 + have_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } have_panel=no +else + PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS + PANEL_LIBS=$pkg_cv_PANEL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + have_panel=yes +fi else PANEL_CFLAGS=$pkg_cv_PANEL_CFLAGS PANEL_LIBS=$pkg_cv_PANEL_LIBS @@ -29591,6 +30495,8 @@ fi fi + curses_libs="ncursesw ncurses"; panel_libs="panelw panel gnupanel" ;; +esac save_CFLAGS=$CFLAGS save_CPPFLAGS=$CPPFLAGS @@ -29598,9 +30504,28 @@ save_LDFLAGS=$LDFLAGS save_LIBS=$LIBS - # Make sure we've got the header defines. + # Make sure we've got the header defines. For the native "curses" backend, + # probe only the plain headers: a system may also have ncurses headers (e.g. + # ncurses/curses.h), and picking those while linking the native library mixes + # incompatible declarations (e.g. tparm()) with the native . as_fn_append CPPFLAGS " $CURSES_CFLAGS $PANEL_CFLAGS" - ac_fn_c_check_header_compile "$LINENO" "ncursesw/curses.h" "ac_cv_header_ncursesw_curses_h" "$ac_includes_default" + if test "x$with_curses" = xcurses +then : + ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default" +if test "x$ac_cv_header_curses_h" = xyes +then : + printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h + +fi +ac_fn_c_check_header_compile "$LINENO" "panel.h" "ac_cv_header_panel_h" "$ac_includes_default" +if test "x$ac_cv_header_panel_h" = xyes +then : + printf "%s\n" "#define HAVE_PANEL_H 1" >>confdefs.h + +fi + +else case e in #( + e) ac_fn_c_check_header_compile "$LINENO" "ncursesw/curses.h" "ac_cv_header_ncursesw_curses_h" "$ac_includes_default" if test "x$ac_cv_header_ncursesw_curses_h" = xyes then : printf "%s\n" "#define HAVE_NCURSESW_CURSES_H 1" >>confdefs.h @@ -29654,7 +30579,9 @@ then : printf "%s\n" "#define HAVE_PANEL_H 1" >>confdefs.h fi - + ;; +esac +fi # Check that we're able to link with crucial curses/panel functions. This # also serves as a fallback in case pkg-config failed. @@ -29687,7 +30614,7 @@ return initscr (); return 0; } _ACEOF -for ac_lib in '' ncursesw ncurses +for ac_lib in '' $curses_libs do if test -z "$ac_lib"; then ac_res="none required" @@ -29761,7 +30688,7 @@ return update_panels (); return 0; } _ACEOF -for ac_lib in '' panelw panel +for ac_lib in '' $panel_libs do if test -z "$ac_lib"; then ac_res="none required" @@ -29810,7 +30737,7 @@ fi -if test "have_curses" != "no" +if test "$have_curses" != "no" then : CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') @@ -29825,6 +30752,66 @@ fi PANEL_CFLAGS=$(echo $PANEL_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') +if test "x$with_curses" = xcurses +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether curses supports wide characters" >&5 +printf %s "checking whether curses supports wide characters... " >&6; } +if test ${ac_cv_curses_wide+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#define NCURSES_OPAQUE 0 +#if defined(HAVE_NCURSESW_NCURSES_H) +# include +#elif defined(HAVE_NCURSESW_CURSES_H) +# include +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + +int +main (void) +{ + + cchar_t wcval; + setcchar(&wcval, L"x", A_NORMAL, 0, NULL); + add_wch(&wcval); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_curses_wide=yes +else case e in #( + e) ac_cv_curses_wide=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_curses_wide" >&5 +printf "%s\n" "$ac_cv_curses_wide" >&6; } + if test "x$ac_cv_curses_wide" = xyes +then : + printf "%s\n" "#define HAVE_NCURSESW 1" >>confdefs.h + +fi + +fi + # On Solaris, term.h requires curses.h ac_fn_c_check_header_compile "$LINENO" "term.h" "ac_cv_header_term_h" " #define NCURSES_OPAQUE 0 diff --git a/configure.ac b/configure.ac index ad8280349466e0..97d2091dbf89a7 100644 --- a/configure.ac +++ b/configure.ac @@ -7088,12 +7088,28 @@ then fi dnl check for ncursesw/ncurses and panelw/panel -dnl NOTE: old curses is not detected. dnl have_curses=[no, yes] dnl have_panel=[no, yes] have_curses=no have_panel=no +dnl Select the curses backend, or disable the curses and _curses_panel modules. +dnl "auto" (the default) prefers ncursesw and falls back to ncurses, both via +dnl pkg-config. "curses" links the system's native curses (e.g. on NetBSD or +dnl Solaris), which has no pkg-config file and is never chosen by "auto". +AC_MSG_CHECKING([for --with-curses]) +AC_ARG_WITH( + [curses], + [AS_HELP_STRING([--with(out)-curses@<:@=ncursesw|ncurses|curses|no@:>@], + [select the curses backend for the curses and _curses_panel + modules, or disable them (default: auto)])], + [AS_CASE([$with_curses], + [yes|auto], [with_curses=auto], + [ncursesw|ncurses|curses|no], [], + [AC_MSG_ERROR([proper usage is --with(out)-curses@<:@=ncursesw|ncurses|curses|no@:>@])])], + [with_curses=auto]) +AC_MSG_RESULT([$with_curses]) + dnl PY_CHECK_CURSES(LIBCURSES, LIBPANEL) dnl Sets 'have_curses' and 'have_panel'. dnl For the PKG_CHECK_MODULES() calls, we can safely reuse the first variable @@ -7108,34 +7124,54 @@ PKG_CHECK_MODULES([CURSES], [$1], PKG_CHECK_MODULES([PANEL], [$2], [AC_DEFINE([HAVE_]panel_var, [1], [Define if you have the '$2' library]) AS_VAR_SET([have_panel], [yes])], - [AS_VAR_SET([have_panel], [no])])], + [dnl pkgsrc renames the ncurses panel to "gnupanel" so it does not clash + dnl with a system libpanel; it Requires the same ncurses, so it matches. + PKG_CHECK_MODULES([PANEL], [gnupanel], + [AS_VAR_SET([have_panel], [yes])], + [AS_VAR_SET([have_panel], [no])])])], [AS_VAR_SET([have_curses], [no])]) AS_VAR_POPDEF([curses_var]) AS_VAR_POPDEF([panel_var])]) -# Check for ncursesw/panelw first. If that fails, try ncurses/panel. -PY_CHECK_CURSES([ncursesw], [panelw]) -AS_VAR_IF([have_curses], [no], - [PY_CHECK_CURSES([ncurses], [panel])]) +# Detect the selected backend. ncursesw/ncurses are found via pkg-config; +# native curses has no .pc file and is left to the header/link probes below. +# curses_libs/panel_libs drive the AC_SEARCH_LIBS fallback; for "no" they are +# empty so nothing links and have_curses stays "no". +AS_CASE([$with_curses], + [ncursesw], [PY_CHECK_CURSES([ncursesw], [panelw]) + curses_libs="ncursesw"; panel_libs="panelw gnupanel"], + [ncurses], [PY_CHECK_CURSES([ncurses], [panel]) + curses_libs="ncurses"; panel_libs="panel gnupanel"], + [curses], [curses_libs="curses"; panel_libs="panel"], + [no], [curses_libs=""; panel_libs=""], + [dnl auto: prefer ncursesw, fall back to ncurses; never native curses. + PY_CHECK_CURSES([ncursesw], [panelw]) + AS_VAR_IF([have_curses], [no], [PY_CHECK_CURSES([ncurses], [panel])]) + curses_libs="ncursesw ncurses"; panel_libs="panelw panel gnupanel"]) WITH_SAVE_ENV([ - # Make sure we've got the header defines. + # Make sure we've got the header defines. For the native "curses" backend, + # probe only the plain headers: a system may also have ncurses headers (e.g. + # ncurses/curses.h), and picking those while linking the native library mixes + # incompatible declarations (e.g. tparm()) with the native . AS_VAR_APPEND([CPPFLAGS], [" $CURSES_CFLAGS $PANEL_CFLAGS"]) - AC_CHECK_HEADERS(m4_normalize([ - ncursesw/curses.h ncursesw/ncurses.h ncursesw/panel.h - ncurses/curses.h ncurses/ncurses.h ncurses/panel.h - curses.h ncurses.h panel.h - ])) + AS_VAR_IF([with_curses], [curses], + [AC_CHECK_HEADERS([curses.h panel.h])], + [AC_CHECK_HEADERS(m4_normalize([ + ncursesw/curses.h ncursesw/ncurses.h ncursesw/panel.h + ncurses/curses.h ncurses/ncurses.h ncurses/panel.h + curses.h ncurses.h panel.h + ]))]) # Check that we're able to link with crucial curses/panel functions. This # also serves as a fallback in case pkg-config failed. AS_VAR_APPEND([LIBS], [" $CURSES_LIBS $PANEL_LIBS"]) - AC_SEARCH_LIBS([initscr], [ncursesw ncurses], + AC_SEARCH_LIBS([initscr], [$curses_libs], [AS_VAR_IF([have_curses], [no], [AS_VAR_SET([have_curses], [yes]) CURSES_LIBS=${CURSES_LIBS-"$ac_cv_search_initscr"}])], [AS_VAR_SET([have_curses], [no])]) - AC_SEARCH_LIBS([update_panels], [panelw panel], + AC_SEARCH_LIBS([update_panels], [$panel_libs], [AS_VAR_IF([have_panel], [no], [AS_VAR_SET([have_panel], [yes]) PANEL_LIBS=${PANEL_LIBS-"$ac_cv_search_update_panels"}])], @@ -7163,7 +7199,7 @@ AC_DEFUN([_CURSES_INCLUDES],dnl #endif ]) -AS_IF([test "have_curses" != "no"], [ +AS_IF([test "$have_curses" != "no"], [ dnl remove _XOPEN_SOURCE macro from curses cflags. pyconfig.h sets dnl the macro to 700. CURSES_CFLAGS=$(echo $CURSES_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') @@ -7183,6 +7219,27 @@ AS_VAR_IF([ac_sys_system], [Darwin], [ dnl pyconfig.h defines _XOPEN_SOURCE=700 PANEL_CFLAGS=$(echo $PANEL_CFLAGS | sed 's/-D_XOPEN_SOURCE=600//g') +dnl Native curses ("curses") may be wide-character capable (e.g. on NetBSD) +dnl even though it is not ncursesw. Probe for the wide API; if present, build +dnl the module against it like ncursesw by defining HAVE_NCURSESW. ncursesw +dnl already defines HAVE_NCURSESW, and ncurses must stay narrow, so only the +dnl native backend is probed here. +AS_VAR_IF([with_curses], [curses], [ + AC_CACHE_CHECK([whether curses supports wide characters], + [ac_cv_curses_wide], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([_CURSES_INCLUDES], [[ + cchar_t wcval; + setcchar(&wcval, L"x", A_NORMAL, 0, NULL); + add_wch(&wcval); + ]])], + [ac_cv_curses_wide=yes], + [ac_cv_curses_wide=no])]) + dnl HAVE_NCURSESW marks the wide (cchar_t) curses API; its template comes + dnl from the ncursesw pkg-config check above, so no description here. + AS_VAR_IF([ac_cv_curses_wide], [yes], [AC_DEFINE([HAVE_NCURSESW], [1])]) +]) + # On Solaris, term.h requires curses.h AC_CHECK_HEADERS([term.h], [], [], _CURSES_INCLUDES)