Compare commits

...

23 Commits

Author SHA1 Message Date
Max Kellermann
aa0e4500c6 release v0.21.1 2018-11-04 14:08:16 +01:00
Fabian Muscariello
4e6b8edf72 doc/protocol.rst: add missing backticks 2018-11-04 14:04:57 +01:00
Max Kellermann
ac0852b4e3 song/Filter: operator "==" never searches substrings in filter expressions
The protocol documentation says that the difference between `find` and
`search` is that `search` is case insensitive, but that's only half
the truth: `search` also searches for sub strings instead of matching
the whole string.  This part is undocumented and unfortunate, but at
this point, we can't change it.

However leaking this surprising behavior to the new filter expressions
was a bad idea; the "==" operator should never match substrings.  For
people who need that, we should add a new operator.
2018-11-04 13:57:34 +01:00
Max Kellermann
6fe43ed969 song/StringFilter: add flag substring
Prepare to stop using substrings for filter expressions.
2018-11-04 13:49:47 +01:00
Max Kellermann
b34bc06624 song/StringFilter: use std::string::operator== 2018-11-04 13:49:38 +01:00
Max Kellermann
08e41e60e5 meson.build: downgrade Boost 1.67 error to warning
Some Boost 1.67 packages apparently have a workaround for the bug, so
let them build MPD.
2018-11-04 12:45:22 +01:00
Max Kellermann
10ec478a9c meson.build: refuse to build with buggy Boost version 1.67 2018-11-04 12:31:49 +01:00
Max Kellermann
86f1074905 lib/xiph/meson.build: the Vorbis encoder requires the Vorbis decoder
Without the Vorbis decoder, `libvorbis` is never detected, leading to
linker failures when attempting to build the Vorbis encoder.
2018-11-04 12:21:23 +01:00
Max Kellermann
8e66b855a3 doc/protocol.rst: mention that sub-expressios must be enclosed in parantheses
Closes 
2018-11-04 12:12:38 +01:00
Max Kellermann
e3bc85d7bf meson.build: require Meson 0.47.2
Meson 0.47.1 suffers from a bug which breaks linking the MPD
executable because the `-lpthread` flag is not propagated from our
`thread.a`.

See https://github.com/mesonbuild/meson/pull/3895

Closes 
2018-11-04 11:54:40 +01:00
Max Kellermann
6f242836e6 lib/xiph/meson.build: fix typo, replace and with or
Fixes linker failure when building without FLAC support.

Closes 
2018-11-04 11:36:28 +01:00
Max Kellermann
f2c926f3b6 zeroconf/glue: add fallback value for HOST_NAME_MAX
`HOST_NAME_MAX` is not a portable macro; it is undefined on some
systems.

Closes 
2018-11-04 11:12:03 +01:00
Max Kellermann
aba18924ee win32/build.py: link libstdc++ and libcc statically
Fixes 
2018-11-04 11:10:00 +01:00
Max Kellermann
aa6bef54dd python/build/zlib.py: build zlib as a static library
Fixes one part of 
2018-11-04 11:10:00 +01:00
Max Kellermann
528f5b9cb9 song/Filter: allow escaping quotes in filter expressions
Closes 
2018-11-02 19:15:08 +01:00
Max Kellermann
96ae0ec93a remove some autotools remains
Closes 
2018-11-02 18:55:49 +01:00
Max Kellermann
5a5229b499 net/IPv[46]Address: make the initializers more portable
Thanks to C++14, we can declare and fill variables inside `constexpr`
functions.  This means me can stop make assumptions on the `struct`
layouts without losing `constexpr`.

Closes 
2018-11-02 17:47:43 +01:00
Max Kellermann
bba22c9c8c system/FileDescriptor: check __linux__ instead of __linux
`__linux` is the deprecated non-standard macros which appears to be
not present at all on PowerPC.

Closes 
2018-11-02 16:50:38 +01:00
Max Kellermann
694c437a2c NEWS: mention the FFmpeg build fix 2018-11-02 16:50:35 +01:00
Max Kellermann
587172efa3 Merge branch 'patch-1' of git://github.com/joerg-krause/MPD 2018-11-01 19:17:10 +01:00
Max Kellermann
2a926063b2 src/lib/ffmpeg/meson.build: copy dependencies into ffmpeg_dep
Apparently, Meson propagates the linker flags but not the compiler
flags from a `static_library`'s dependencies list.

Closes 
2018-11-01 19:14:00 +01:00
Jörg Krause
d6f239e54f meson: fix typo in options plugins comment 2018-11-01 19:06:54 +01:00
Max Kellermann
b8989fafeb increment version number to 0.21.1 2018-11-01 17:23:47 +01:00
32 changed files with 240 additions and 181 deletions

80
.gitignore vendored

@@ -1,88 +1,8 @@
*.Plo
*.Po
*.a
*.d
*.la
*.lo
*.o
*.exe
*~
.#*
.stgit*
.deps
.dirstamp
tags
/Makefile
/Makefile.in
/aclocal.m4
/autom4te.cache
/config.h
/config.h.in
/config.log
/config.mk
/config.status
/config_detected.h
/config_detected.mk
/configure
/configure.lineno
/depmode
/libtool
/ltmain.sh
/mkinstalldirs
/output/
/src/mpd
/systemd/system/mpd.service
/systemd/user/mpd.service
/stamp-h1
/src/dsd2pcm/dsd2pcm
/src/win32/mpd_win32_rc.rc
/doc/doxygen.conf
/doc/protocol.html
/doc/protocol
/doc/user
/doc/developer
/doc/sticker
/doc/api
/test/software_volume
/test/run_convert
/test/run_decoder
/test/read_tags
/test/run_filter
/test/run_encoder
/test/run_output
/test/read_conf
/test/run_input
/test/read_mixer
/test/dump_playlist
/test/run_normalize
/test/tmp
/test/run_inotify
/test/test_queue_priority
/test/test_protocol
/test/run_ntp_server
/test/run_resolver
/test/run_tcp_connect
/test/test_pcm
/test/dump_rva2
/test/dump_text_file
/test/test_util
/test/test_byte_reverse
/test/test_mixramp
/test/test_vorbis_encoder
/test/DumpDatabase
/lib/
/*.tar.gz
/*.tar.bz2
/*.tar.xz
/mpd-*/
__pycache__/

15
NEWS

@@ -1,3 +1,18 @@
ver 0.21.1 (2018/11/04)
* protocol
- allow escaping quotes in filter expressions
- operator "==" never searches substrings in filter expressions
* decoder
- ffmpeg: fix build failure with non-standard FFmpeg installation path
- flac: fix linker failure when building without FLAC support
* encoder
- vorbis: fix linker failure when building without Vorbis decoder
* fix build failure on Linux-PowerPC
* fix build failure on FreeBSD
* eliminate DLL dependencies on Windows
* add warning about buggy Boost version 1.67
* require Meson 0.47.2 because a Meson 0.47.1 bug breaks our build
ver 0.21 (2018/10/31)
* configuration
- add "include" directive, allows including config files

1
android/.gitignore vendored

@@ -1 +0,0 @@
/build

@@ -1,11 +0,0 @@
#!/bin/sh
set -e
rm -rf config.cache build
mkdir build
aclocal -I m4 $ACLOCAL_FLAGS
autoheader
automake --add-missing $AUTOMAKE_FLAGS
autoconf

2
doc/.gitignore vendored

@@ -1,2 +0,0 @@
/html/
/doctrees/

@@ -38,9 +38,9 @@ author = 'Max Kellermann'
# built documents.
#
# The short X.Y version.
version = '0.21'
version = '0.21.1'
# The full version, including alpha/beta/rc tags.
release = '0.21~git'
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

@@ -175,15 +175,49 @@ of:
matches the audio format with the given mask (i.e. one
or more attributes may be "*").
- ``(!EXPRESSION)``: negate an expression.
- ``(!EXPRESSION)``: negate an expression. Note that each expression
must be enclosed in parantheses, e.g. :code:`(!(artist == 'VALUE'))`
(which is equivalent to :code:`(artist != 'VALUE')`)
- ``(EXPRESSION1 AND EXPRESSION2 ...)``: combine two or
more expressions with logical "and".
more expressions with logical "and". Note that each expression must
be enclosed in parantheses, e.g. :code:`((artist == 'FOO') AND
(album == 'BAR'))`
Prior to MPD 0.21, the syntax looked like this::
find TYPE VALUE
Escaping String Values
----------------------
String values are quoted with single or double quotes, and special
characters within those values must be escaped with the backslash
(``\``). Keep in mind that the backslash is also the escape character
on the protocol level, which means you may need to use double
backslash.
Example expression which matches an artist named ``foo'bar"``::
(artist "foo\'bar\"")
At the protocol level, the command must look like this::
find "(artist \"foo\\'bar\\\"\")"
The double quotes enclosing the artist name must be escaped because
they are inside a double-quoted ``find`` parameter. The single quote
inside that artist name must be escaped with two backslashes; one to
escape the single quote, and another one because the backslash inside
the string inside the parameter needs to be escaped as well. The
double quote has three confusing backslashes: two to build one
backslash, and another one to escape the double quote on the protocol
level. Phew!
To reduce confusion, you should use a library such as `libmpdclient
<https://www.musicpd.org/libs/libmpdclient/>`_ which escapes command
arguments for you.
.. _tags:
Tags
@@ -361,7 +395,7 @@ Querying ``MPD``'s status
- ``consume`` [#since_0_15]_: ``0`` or ``1``
- ``playlist``: 31-bit unsigned integer, the playlist version number
- ``playlistlength``: integer, the length of the playlist
- ``state``: ``play``, ``stop, or ``pause``
- ``state``: ``play``, ``stop``, or ``pause``
- ``song``: playlist song number of the current song stopped on or playing
- ``songid``: playlist songid of the current song stopped on or playing
- ``nextsong`` [#since_0_15]_: playlist song number of the next song to be played

@@ -54,7 +54,7 @@ Download the source tarball from the `MPD home page <https://musicpd.org>`_ and
In any case, you need:
* a C++14 compiler (e.g. gcc 6.0 or clang 3.9)
* `Meson 0.47 <http://mesonbuild.com/>`__ and `Ninja
* `Meson 0.47.2 <http://mesonbuild.com/>`__ and `Ninja
<https://ninja-build.org/>`__
* Boost 1.58
* pkg-config

@@ -1,8 +1,8 @@
project(
'mpd',
['c', 'cpp'],
version: '0.21',
meson_version: '>= 0.47',
version: '0.21.1',
meson_version: '>= 0.47.2',
default_options: [
'c_std=c99',
'cpp_std=c++14'
@@ -172,6 +172,11 @@ inc = include_directories(
)
boost_dep = dependency('boost', version: '>= 1.58')
if boost_dep.version() == '1.67'
# https://github.com/MusicPlayerDaemon/MPD/pull/384
# https://github.com/boostorg/lockfree/commit/12726cda009a855073b9bedbdce57b6ce7763da2
warning('Your Boost version 1.67 is known to be buggy, and the MPD build will fail. Please upgrade to Boost 1.68 or later.')
endif
sources = [
version_cxx,

@@ -133,7 +133,7 @@ option('wavpack', type: 'feature', description: 'WavPack decoder plugin')
option('wildmidi', type: 'feature', description: 'WildMidi decoder plugin')
#
# Decoder plugins
# Encoder plugins
#
option('vorbisenc', type: 'feature', description: 'Vorbis encoder plugin')

@@ -18,5 +18,5 @@ class ZlibProject(Project):
'INCLUDE_PATH='+ os.path.join(toolchain.install_prefix, 'include'),
'LIBRARY_PATH=' + os.path.join(toolchain.install_prefix, 'lib'),
'BINARY_PATH=' + os.path.join(toolchain.install_prefix, 'bin'),
'SHARED_MODE=1'],
],
cwd=src, env=toolchain.env)

@@ -26,4 +26,9 @@ ffmpeg = static_library(
ffmpeg_dep = declare_dependency(
link_with: ffmpeg,
dependencies: [
libavformat_dep,
libavcodec_dep,
libavutil_dep,
],
)

@@ -2,10 +2,15 @@ libflac_dep = dependency('flac', version: '>= 1.2', required: get_option('flac')
libopus_dep = dependency('opus', required: get_option('opus'))
libvorbis_dep = dependency('vorbis', required: get_option('vorbis'))
if need_encoder
libvorbisenc_dep = dependency('vorbisenc', required: get_option('vorbisenc'))
else
libvorbisenc_dep = dependency('', required: false)
libvorbisenc_dep = dependency('', required: false)
if need_encoder and not get_option('vorbisenc').disabled()
if libvorbis_dep.found()
libvorbisenc_dep = dependency('vorbisenc', required: get_option('vorbisenc'))
elif get_option('vorbisenc').enabled()
error('Cannot build the Vorbis encoder without the Vorbis decoder')
else
message('Disabling the Vorbis encoder because the Vorbis decoder is disabled as well')
endif
endif
if libopus_dep.found() or libvorbis_dep.found() or libvorbisenc_dep.found()
@@ -14,7 +19,7 @@ else
libogg_dep = dependency('', required: false)
endif
if not libogg_dep.found() or not libflac_dep.found()
if not libogg_dep.found() and not libflac_dep.found()
xiph_dep = dependency('', required: false)
ogg_dep = dependency('', required: false)
flac_dep = dependency('', required: false)

@@ -53,20 +53,6 @@ class IPv4Address {
uint8_t c, uint8_t d) noexcept {
return {{{ a, b, c, d }}};
}
/**
* @param x the 32 bit IP address in network byte order
*/
static constexpr struct in_addr ConstructInAddrBE(uint32_t x) noexcept {
return (struct in_addr){{.S_addr=x}};
}
/**
* @param x the 32 bit IP address in host byte order
*/
static constexpr struct in_addr ConstructInAddr(uint32_t x) noexcept {
return ConstructInAddr(x >> 24, x >> 16, x >> 8, x);
}
#else
#ifdef __BIONIC__
@@ -78,11 +64,19 @@ class IPv4Address {
return ToBE32((a << 24) | (b << 16) | (c << 8) | d);
}
static constexpr struct in_addr ConstructInAddr(uint8_t a, uint8_t b,
uint8_t c, uint8_t d) noexcept {
return { ConstructInAddrT(a, b, c, d) };
}
#endif
/**
* @param x the 32 bit IP address in network byte order
*/
static constexpr struct in_addr ConstructInAddrBE(uint32_t x) noexcept {
return { x };
struct in_addr ia{};
ia.s_addr = x;
return ia;
}
/**
@@ -92,26 +86,16 @@ class IPv4Address {
return ConstructInAddrBE(ToBE32(x));
}
static constexpr struct in_addr ConstructInAddr(uint8_t a, uint8_t b,
uint8_t c, uint8_t d) noexcept {
return { ConstructInAddrT(a, b, c, d) };
}
#endif
/**
* @param port the port number in host byte order
*/
static constexpr struct sockaddr_in Construct(struct in_addr address,
uint16_t port) noexcept {
return {
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sizeof(struct sockaddr_in),
#endif
AF_INET,
ToBE16(port),
address,
{},
};
struct sockaddr_in sin{};
sin.sin_family = AF_INET;
sin.sin_port = ToBE16(port);
sin.sin_addr = address;
return sin;
}
/**

@@ -68,16 +68,12 @@ class IPv6Address {
static constexpr struct sockaddr_in6 Construct(struct in6_addr address,
uint16_t port,
uint32_t scope_id) noexcept {
return {
#if defined(__APPLE__)
sizeof(struct sockaddr_in6),
#endif
AF_INET6,
ToBE16(port),
0,
address,
scope_id,
};
struct sockaddr_in6 sin{};
sin.sin6_family = AF_INET6;
sin.sin6_port = ToBE16(port);
sin.sin6_addr = address;
sin.sin6_scope_id = scope_id;
return sin;
}
public:

@@ -10,14 +10,6 @@ if have_tcp and not get_option('ipv6').disabled()
if not have_ipv6 and get_option('ipv6').enabled()
error('IPv6 not supported by OS')
endif
conf.set('HAVE_STRUCT_SOCKADDR_IN_SIN_LEN', c_compiler.has_member('struct sockaddr_in', 'sin_len', prefix: '''
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netinet/in.h>
#endif'''))
else
have_ipv6 = false
endif

@@ -19,13 +19,14 @@
#include "config.h"
#include "BaseSongFilter.hxx"
#include "Escape.hxx"
#include "LightSong.hxx"
#include "util/UriUtil.hxx"
std::string
BaseSongFilter::ToExpression() const noexcept
{
return "(base \"" + value + "\")";
return "(base \"" + EscapeFilterString(value) + "\")";
}
bool

41
src/song/Escape.cxx Normal file

@@ -0,0 +1,41 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "Escape.hxx"
static constexpr bool
MustEscape(char ch) noexcept
{
return ch == '"' || ch == '\'' || ch == '\\';
}
std::string
EscapeFilterString(const std::string &src) noexcept
{
std::string result;
result.reserve(src.length() + 16);
for (char ch : src) {
if (MustEscape(ch))
result.push_back('\\');
result.push_back(ch);
}
return result;
}

31
src/song/Escape.hxx Normal file

@@ -0,0 +1,31 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_SONG_ESCAPE_HXX
#define MPD_SONG_ESCAPE_HXX
#include "util/Compiler.h"
#include <string>
gcc_pure
std::string
EscapeFilterString(const std::string &src) noexcept;
#endif

@@ -91,8 +91,11 @@ locate_parse_type(const char *str) noexcept
SongFilter::SongFilter(TagType tag, const char *value, bool fold_case)
{
/* for compatibility with MPD 0.20 and older, "fold_case" also
switches on "substring" */
and_filter.AddItem(std::make_unique<TagSongFilter>(tag, value,
fold_case, false));
fold_case, fold_case,
false));
}
SongFilter::~SongFilter()
@@ -173,13 +176,26 @@ ExpectQuoted(const char *&s)
if (!IsQuote(quote))
throw std::runtime_error("Quoted string expected");
const char *begin = s;
const char *end = strchr(s, quote);
if (end == nullptr)
throw std::runtime_error("Closing quote not found");
char buffer[4096];
size_t length = 0;
s = StripLeft(end + 1);
return {begin, end};
while (*s != quote) {
if (*s == '\\')
/* backslash escapes the following character */
++s;
if (*s == 0)
throw std::runtime_error("Closing quote not found");
buffer[length++] = *s++;
if (length >= sizeof(buffer))
throw std::runtime_error("Quoted value is too long");
}
s = StripLeft(s + 1);
return {buffer, length};
}
ISongFilterPtr
@@ -283,11 +299,13 @@ SongFilter::ParseExpression(const char *&s, bool fold_case)
if (type == LOCATE_TAG_FILE_TYPE)
return std::make_unique<UriSongFilter>(std::move(value),
fold_case,
false,
negated);
return std::make_unique<TagSongFilter>(TagType(type),
std::move(value),
fold_case, negated);
fold_case, false,
negated);
}
}
@@ -312,7 +330,10 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
break;
case LOCATE_TAG_FILE_TYPE:
/* for compatibility with MPD 0.20 and older,
"fold_case" also switches on "substring" */
and_filter.AddItem(std::make_unique<UriSongFilter>(value,
fold_case,
fold_case,
false));
break;
@@ -321,9 +342,12 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
if (tag == LOCATE_TAG_ANY_TYPE)
tag = TAG_NUM_OF_ITEM_TYPES;
/* for compatibility with MPD 0.20 and older,
"fold_case" also switches on "substring" */
and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag),
value,
fold_case,
fold_case,
false));
break;
}

@@ -32,8 +32,12 @@ StringFilter::Match(const char *s) const noexcept
#endif
if (fold_case) {
return fold_case.IsIn(s);
return substring
? fold_case.IsIn(s)
: fold_case == s;
} else {
return StringIsEqual(s, value.c_str());
return substring
? StringFind(s, value.c_str()) != nullptr
: value == s;
}
}

@@ -33,13 +33,19 @@ class StringFilter {
*/
IcuCompare fold_case;
/**
* Search for substrings instead of matching the whole string?
*/
bool substring;
public:
template<typename V>
StringFilter(V &&_value, bool _fold_case)
StringFilter(V &&_value, bool _fold_case, bool _substring)
:value(std::forward<V>(_value)),
fold_case(_fold_case
? IcuCompare(value.c_str())
: IcuCompare()) {}
: IcuCompare()),
substring(_substring) {}
bool empty() const noexcept {
return value.empty();

@@ -19,6 +19,7 @@
#include "config.h"
#include "TagSongFilter.hxx"
#include "Escape.hxx"
#include "LightSong.hxx"
#include "tag/Tag.hxx"
#include "tag/Fallback.hxx"
@@ -30,7 +31,7 @@ TagSongFilter::ToExpression() const noexcept
? "any"
: tag_item_names[type];
return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + EscapeFilterString(filter.GetValue()) + "\")";
}
bool

@@ -42,9 +42,10 @@ class TagSongFilter final : public ISongFilter {
public:
template<typename V>
TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated)
TagSongFilter(TagType _type, V &&_value, bool fold_case, bool substring,
bool _negated)
:type(_type), negated(_negated),
filter(std::forward<V>(_value), fold_case) {}
filter(std::forward<V>(_value), fold_case, substring) {}
TagType GetTagType() const {
return type;

@@ -19,12 +19,13 @@
#include "config.h"
#include "UriSongFilter.hxx"
#include "Escape.hxx"
#include "LightSong.hxx"
std::string
UriSongFilter::ToExpression() const noexcept
{
return std::string("(file ") + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
return std::string("(file ") + (negated ? "!=" : "==") + " \"" + EscapeFilterString(filter.GetValue()) + "\")";
}
bool

@@ -32,8 +32,9 @@ class UriSongFilter final : public ISongFilter {
public:
template<typename V>
UriSongFilter(V &&_value, bool fold_case, bool _negated)
:filter(std::forward<V>(_value), fold_case),
UriSongFilter(V &&_value, bool fold_case, bool substring,
bool _negated)
:filter(std::forward<V>(_value), fold_case, substring),
negated(_negated) {}
const auto &GetValue() const noexcept {

@@ -1,6 +1,7 @@
song = static_library(
'song',
'DetachedSong.cxx',
'Escape.cxx',
'StringFilter.cxx',
'UriSongFilter.cxx',
'BaseSongFilter.cxx',

@@ -76,7 +76,7 @@ FileDescriptor::IsSocket() const noexcept
#endif
#ifdef __linux
#ifdef __linux__
bool
FileDescriptor::Open(FileDescriptor dir, const char *pathname,

@@ -116,7 +116,7 @@ public:
return FileDescriptor(-1);
}
#ifdef __linux
#ifdef __linux__
bool Open(FileDescriptor dir, const char *pathname,
int flags, mode_t mode=0666) noexcept;
#endif

@@ -32,6 +32,12 @@
#include <unistd.h>
#include <limits.h>
#ifndef HOST_NAME_MAX
/* HOST_NAME_MAX is not a portable macro; it is undefined on some
systems */
#define HOST_NAME_MAX 255
#endif
static constexpr Domain zeroconf_domain("zeroconf");
/* The default service name to publish

2
test/.gitignore vendored

@@ -1,2 +0,0 @@
/run_neighbor_explorer
/ReadApeTags

@@ -62,7 +62,8 @@ class CrossGccToolchain:
self.cxxflags = common_flags
self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
self.ldflags = '-L' + os.path.join(install_prefix, 'lib')
self.ldflags = '-L' + os.path.join(install_prefix, 'lib') + \
' -static-libstdc++ -static-libgcc'
self.libs = ''
self.is_arm = arch.startswith('arm')