summaryrefslogtreecommitdiff
path: root/user/sane-airscan
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-30 04:08:43 +0000
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-30 04:08:43 +0000
commitc4068760a6735db6c5b785827ccf2bb9f95eb25c (patch)
tree7cdcccc2b704e7df24ff204f4bbd3b6f318b50ec /user/sane-airscan
parented7aa0624657bf18c5671c3bb460b4a068e8ad68 (diff)
downloadpackages-c4068760a6735db6c5b785827ccf2bb9f95eb25c.tar.gz
packages-c4068760a6735db6c5b785827ccf2bb9f95eb25c.tar.bz2
packages-c4068760a6735db6c5b785827ccf2bb9f95eb25c.tar.xz
packages-c4068760a6735db6c5b785827ccf2bb9f95eb25c.zip
user/sane-airscan: Update to 0.99.10
Diffstat (limited to 'user/sane-airscan')
-rw-r--r--user/sane-airscan/APKBUILD11
-rw-r--r--user/sane-airscan/git.patch1212
2 files changed, 4 insertions, 1219 deletions
diff --git a/user/sane-airscan/APKBUILD b/user/sane-airscan/APKBUILD
index c106204f8..1694d3d0f 100644
--- a/user/sane-airscan/APKBUILD
+++ b/user/sane-airscan/APKBUILD
@@ -1,8 +1,8 @@
# Contributor: A. Wilcox <awilfox@adelielinux.org>
# Maintainer: A. Wilcox <awilfox@adelielinux.org>
pkgname=sane-airscan
-pkgver=0.99.8
-pkgrel=1
+pkgver=0.99.10
+pkgrel=0
pkgdesc="Universal scanner driver for AirScan (eSCL) scanners"
url=" "
arch="all"
@@ -11,9 +11,7 @@ depends=""
makedepends="avahi-dev glib-dev libjpeg-turbo-dev libpng-dev libsoup-dev
libxml2-dev meson ninja sane-dev"
subpackages="$pkgname-doc"
-source="sane-airscan-$pkgver.tar.gz::https://github.com/alexpevzner/sane-airscan/archive/$pkgver.tar.gz
- git.patch
- "
+source="sane-airscan-$pkgver.tar.gz::https://github.com/alexpevzner/sane-airscan/archive/$pkgver.tar.gz"
build() {
meson \
@@ -36,5 +34,4 @@ package() {
rm "$pkgdir"/etc/sane.d/dll.conf
}
-sha512sums="2828deeea31297c64b9927bb2b2b982f16a16cbb446cf2ca685b13f79cb264e94c017b8930fe04004636a6e1122f1882bd58252a3302c0a13b3fc60566072155 sane-airscan-0.99.8.tar.gz
-a195c23edaf399b6fc1ba7693afd34fa87504c9c8ff10d1d793b97c1b592bff90214cd18af764451a3af9860884509fa7701037322a551226a0bcd29473ca1cc git.patch"
+sha512sums="7a3d98e01ad883856eb79c522aff50243b399717a6ba2db07eec66e49a83d365ad4db6d3f87718592f3b85832a2098e86ae094d9f06ed951ebc23887cddb75b7 sane-airscan-0.99.10.tar.gz"
diff --git a/user/sane-airscan/git.patch b/user/sane-airscan/git.patch
deleted file mode 100644
index 818580553..000000000
--- a/user/sane-airscan/git.patch
+++ /dev/null
@@ -1,1212 +0,0 @@
-diff --git a/COPYING b/COPYING
-index 60549be..d159169 100644
---- a/COPYING
-+++ b/COPYING
-@@ -1,12 +1,12 @@
-- GNU GENERAL PUBLIC LICENSE
-- Version 2, June 1991
-+ GNU GENERAL PUBLIC LICENSE
-+ Version 2, June 1991
-
-- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
-+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-- Preamble
-+ Preamble
-
- The licenses for most software are designed to take away your
- freedom to share and change it. By contrast, the GNU General Public
-@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
- General Public License applies to most of the Free Software
- Foundation's software and to any other program whose authors commit to
- using it. (Some other Free Software Foundation software is covered by
--the GNU Library General Public License instead.) You can apply it to
-+the GNU Lesser General Public License instead.) You can apply it to
- your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
- modification follow.
--
-- GNU GENERAL PUBLIC LICENSE
-+
-+ GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
--
-+
- These requirements apply to the modified work as a whole. If
- identifiable sections of that work are not derived from the Program,
- and can be reasonably considered independent and separate works in
-@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
- access to copy the source code from the same place counts as
- distribution of the source code, even though third parties are not
- compelled to copy the source along with the object code.
--
-+
- 4. You may not copy, modify, sublicense, or distribute the Program
- except as expressly provided under this License. Any attempt
- otherwise to copy, modify, sublicense or distribute the Program is
-@@ -225,7 +225,7 @@ impose that choice.
-
- This section is intended to make thoroughly clear what is believed to
- be a consequence of the rest of this License.
--
-+
- 8. If the distribution and/or use of the Program is restricted in
- certain countries either by patents or by copyrighted interfaces, the
- original copyright holder who places the Program under this License
-@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
- of preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
-
-- NO WARRANTY
-+ NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
-
-- END OF TERMS AND CONDITIONS
--
-- How to Apply These Terms to Your New Programs
-+ END OF TERMS AND CONDITIONS
-+
-+ How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
- possible use to the public, the best way to achieve this is to make it
-@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
- the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
-- Copyright (C) 19yy <name of author>
-+ Copyright (C) <year> <name of author>
-
- 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
-@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--
-+ 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.
-
- Also add information on how to contact you by electronic and paper mail.
-
- If the program is interactive, make it output a short notice like this
- when it starts in an interactive mode:
-
-- Gnomovision version 69, Copyright (C) 19yy name of author
-+ Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
- This General Public License does not permit incorporating your program into
- proprietary programs. If your program is a subroutine library, you may
- consider it more useful to permit linking proprietary applications with the
--library. If this is what you want to do, use the GNU Library General
-+library. If this is what you want to do, use the GNU Lesser General
- Public License instead of this License.
-diff --git a/LICENSE b/LICENSE
-index fe71f02..db02cb9 100644
---- a/LICENSE
-+++ b/LICENSE
-@@ -16,8 +16,8 @@ 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., 59 Temple Place - Suite 330, Boston,
--MA 02111-1307, USA.
-+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-+MA 02110-1301 USA.
-
- As a special exception, the authors of sane-airscan give permission for
- additional uses of the libraries contained in this release of sane-airscan.
-diff --git a/Makefile b/Makefile
-index 9d4e082..70555a8 100644
---- a/Makefile
-+++ b/Makefile
-@@ -17,7 +17,7 @@
-
- CC = gcc
- COMPRESS = gzip
--CFLAGS = -O2 -g -W -Wall -Werror
-+CFLAGS += -O2 -g -W -Wall -Werror $(CPPFLAGS)
- MANDIR = /usr/share/man/
- PKG_CONFIG = /usr/bin/pkg-config
- STRIP = -s
-@@ -82,7 +82,7 @@ $(BACKEND): $(OBJDIR)airscan.o $(LIBAIRSCAN) airscan.sym
- $(CC) -o $(BACKEND) -shared $(OBJDIR)/airscan.o $(LIBAIRSCAN) $(airscan_LDFLAGS)
-
- $(DISCOVER): $(OBJDIR)discover.o $(LIBAIRSCAN)
-- $(CC) -o $(DISCOVER) discover.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS) -fPIE
-+ $(CC) -o $(DISCOVER) discover.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS) $(LDFLAGS) -fPIE
-
- $(LIBAIRSCAN): $(OBJ) Makefile
- ar cru $(LIBAIRSCAN) $(OBJ)
-@@ -105,6 +105,13 @@ clean:
- rm -f test $(BACKEND) tags
- rm -rf $(OBJDIR)
-
-+uninstall:
-+ rm -f $(DESTDIR)$(PREFIX)$(BINDIR)/$(DISCOVER)
-+ rm -f $(DESTDIR)$(PREFIX)$(CONFDIR)/dll.d/airscan
-+ rm -f $(DESTDIR)$(PREFIX)$(LIBDIR)/sane/$(BACKEND)
-+ rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man1/$(MAN_DISCOVER)*
-+ rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man5/$(MAN_BACKEND)*
-+
- man: $(MAN_DISCOVER) $(MAN_BACKEND)
-
- $(MAN_DISCOVER): $(MAN_DISCOVER).md
-@@ -114,7 +121,7 @@ $(MAN_BACKEND): $(MAN_BACKEND).md
- ronn --roff --manual=$(MAN_BACKEND_TITLE) $(MAN_BACKEND).md
-
- test: $(BACKEND) test.c
-- $(CC) -o test test.c $(BACKEND) -Wl,-rpath . ${airscan_CFLAGS}
-+ $(CC) -o test test.c $(BACKEND) -Wl,-rpath . $(LDFLAGS) ${airscan_CFLAGS}
-
- test-decode: test-decode.c $(LIBAIRSCAN)
-- $(CC) -o test-decode test-decode.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS)
-+ $(CC) -o test-decode test-decode.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(LDFLAGS) $(airscan_LIBS)
-diff --git a/README.md b/README.md
-index 469a2cd..f05f4d0 100644
---- a/README.md
-+++ b/README.md
-@@ -51,10 +51,13 @@ Legend:
- | Canon D570 | Yes | |
- | Canon ImageCLASS MF743cdw | Yes<sup>[1](#note1)</sup> | |
- | Canon imageRUNNER ADVANCE 4545/4551| Yes | Yes |
-+| Canon imageRUNNER C3120L | Yes | Yes |
- | Canon i-SENSYS MF641C | No | Yes |
--| Canon Lide 400 | Yes | |
-+| Canon Lide 400 | Yes<sup>[2](#note1)</sup> | |
- | Canon MF745C/746C | Yes | Yes |
-+| Canon PIXMA MG5500 Series | No | Yes |
- | Canon PIXMA MG7700 Series | Yes | |
-+| Canon PIXMA TS5000 Series | Yes | |
- | Canon PIXMA TS 9550 Series | Yes | |
- | Canon TR4529 (PIXMA TR4500 Series) | Yes | |
- | Canon TR7500 Series | No | Yes |
-@@ -89,10 +92,10 @@ Legend:
- | HP OfficeJet Pro 8730 | Yes | Yes |
- | HP OfficeJet Pro 9010 series | Yes | |
- | HP Smart Tank Plus 550 series | Yes | |
--| Kyocera ECOSYS M2040dn | Yes | Yes<sup>[2](#note2)</sup> |
--| Lexmark CX317dn | Yes<sup>[3](#note3)</sup> | Yes<sup>[3](#note3)</sup> |
-+| Kyocera ECOSYS M2040dn | Yes | Yes<sup>[3](#note2)</sup> |
-+| Lexmark CX317dn | Yes<sup>[4](#note3)</sup> | Yes<sup>[4](#note3)</sup> |
- | Lexmark MC2535adwe | Yes | |
--| Ricoh MP C3003 | No | Yes<sup>[4](#note3)</sup> |
-+| Ricoh MP C3003 | No | Yes<sup>[5](#note3)</sup> |
- | Samsung M288x Series | No | Yes |
- | Xerox VersaLink B405 | Yes | |
- | TODO | | |
-@@ -102,15 +105,21 @@ Legend:
- scanning on its web console: Home->Menu->Preferences->Network->TCP/IP
- Settings->Network Link Scan Settings->On.
-
--<a name="note2"><sup>[2]</sup></a>: this device requires manual action on its front
-+<a name="note3"><sup>[2]</sup></a>: this USB device supports IPP over USB protocol, which
-+allows it to be used with network protocols like eSCL. To enable IPP over USB, you need
-+to install additional program: either [ippusbxd](https://github.com/OpenPrinting/ippusbxd), which
-+comes with some distros, or [ipp-usb](https://github.com/OpenPrinting/ipp-usb). 'ipp-usb`
-+works better, binary packages available for many popular distros.
-+
-+<a name="note3"><sup>[3]</sup></a>: this device requires manual action on its front
- panel to initiate WSD scan: Send->WSD Scan->From Computer
-
--<a name="note3"><sup>[3]</sup></a>: when low in memory, this device may scan at 400 DPI
-+<a name="note4"><sup>[4]</sup></a>: when low in memory, this device may scan at 400 DPI
- instead of requested 600 DPI. As sane-airscan reports image parameters to SANE before actual
- image is received, and then adjust actual image to reported parameters, image will
- be scaled down by the factor 2/3 at this case. Lower resolutions works well.
-
--<a name="note3"><sup>[4]</sup></a>: by default, WSD scan command is disabled on this
-+<a name="note5"><sup>[5]</sup></a>: by default, WSD scan command is disabled on this
- device and needs to be enabled before use: Click [Configuration], click [Initial Settings]
- under [Scanner], and then set [Prohibit WSD Scan Command] to [Do not Prohibit] (from
- http://support.ricoh.com/bb_v1oi/pub_e/oi_view/0001047/0001047003/view/scanner/int/0095.htm)
-diff --git a/airscan-device.c b/airscan-device.c
-index f76fa23..82e267a 100644
---- a/airscan-device.c
-+++ b/airscan-device.c
-@@ -119,7 +119,6 @@ struct device {
- SANE_Int read_line_end; /* If read_line_num>read_line_end
- no more lines left in image */
- SANE_Int read_line_off; /* Current offset in the line */
-- SANE_Int read_skip_lines; /* How many lines to skip */
- SANE_Int read_skip_bytes; /* How many bytes to skip at line
- beginning */
- };
-@@ -487,6 +486,8 @@ static void
- device_probe_endpoint (device *dev, zeroconf_endpoint *endpoint)
- {
- /* Switch endpoint */
-+ log_assert(dev->log, endpoint->proto != ID_PROTO_UNKNOWN);
-+
- if (dev->endpoint_current == NULL ||
- dev->endpoint_current->proto != endpoint->proto) {
- device_proto_set(dev, endpoint->proto);
-@@ -851,8 +852,8 @@ device_geom;
- * First of all, we use 3 different units to deal with geometrical
- * parameters:
- * 1) we communicate with frontend in millimeters
-- * 2) we communicate with scanner in pixels, assuming protoc-specific DPI
-- * (defined by devcaps::units)
-+ * 2) we communicate with scanner in pixels, assuming
-+ * protocol-specific DPI (defined by devcaps::units)
- * 3) when we deal with image, sizes are in pixels in real resolution
- *
- * Second, scanner returns minimal and maximal window size, but
-@@ -1289,6 +1290,7 @@ device_read_next (device *dev)
- SANE_Parameters params;
- image_decoder *decoder = dev->decoders[dev->proto_ctx.params.format];
- int wid, hei;
-+ int skip_lines = 0;
-
- log_assert(dev->log, decoder != NULL);
-
-@@ -1330,7 +1332,7 @@ device_read_next (device *dev)
- /* Setup image clipping */
- if (dev->job_skip_x >= wid || dev->job_skip_y >= hei) {
- /* Trivial case - just skip everything */
-- dev->read_skip_lines = hei;
-+ dev->read_line_end = 0;
- dev->read_skip_bytes = 0;
- line_capacity = dev->opt.params.bytes_per_line;
- } else {
-@@ -1352,12 +1354,12 @@ device_read_next (device *dev)
- dev->read_skip_bytes = bpp * (dev->job_skip_x - win.x_off);
- }
-
-- dev->read_skip_lines = 0;
- if (win.y_off != dev->job_skip_y) {
-- dev->read_skip_lines = dev->job_skip_y - win.y_off;
-+ skip_lines = dev->job_skip_y - win.y_off;
- }
-
- line_capacity = math_max(dev->opt.params.bytes_per_line, wid * bpp);
-+ line_capacity += dev->read_skip_bytes;
- }
-
- /* Initialize image decoding */
-@@ -1366,7 +1368,14 @@ device_read_next (device *dev)
-
- dev->read_line_num = 0;
- dev->read_line_off = dev->opt.params.bytes_per_line;
-- dev->read_line_end = hei - dev->read_skip_lines;
-+ dev->read_line_end = hei - skip_lines;
-+
-+ for (;skip_lines > 0; skip_lines --) {
-+ err = image_decoder_read_line(decoder, dev->read_line_buf);
-+ if (err != NULL) {
-+ goto DONE;
-+ }
-+ }
-
- /* Wake up reader */
- pollable_signal(dev->read_pollable);
-@@ -1408,8 +1417,9 @@ device_read_decode_line (device *dev)
- return SANE_STATUS_EOF;
- }
-
-- if (n < dev->read_skip_lines || n >= dev->read_line_end) {
-- memset(dev->read_line_buf, 0xff, dev->opt.params.bytes_per_line);
-+ if (n >= dev->read_line_end) {
-+ memset(dev->read_line_buf + dev->read_skip_bytes, 0xff,
-+ dev->opt.params.bytes_per_line);
- } else {
- error err = image_decoder_read_line(decoder, dev->read_line_buf);
-
-@@ -1419,7 +1429,7 @@ device_read_decode_line (device *dev)
- }
- }
-
-- dev->read_line_off = dev->read_skip_bytes;
-+ dev->read_line_off = 0;
- dev->read_line_num ++;
-
- return SANE_STATUS_GOOD;
-@@ -1482,12 +1492,14 @@ device_read (device *dev, SANE_Byte *data, SANE_Int max_len, SANE_Int *len_out)
- /* Read line by line */
- for (len = 0; status == SANE_STATUS_GOOD && len < max_len; ) {
- if (dev->read_line_off == dev->opt.params.bytes_per_line) {
-- status = device_read_decode_line (dev);
-+ status = device_read_decode_line(dev);
- } else {
- SANE_Int sz = math_min(max_len - len,
- dev->opt.params.bytes_per_line - dev->read_line_off);
-
-- memcpy(data, dev->read_line_buf + dev->read_line_off, sz);
-+ memcpy(data, dev->read_line_buf + dev->read_skip_bytes +
-+ dev->read_line_off, sz);
-+
- data += sz;
- dev->read_line_off += sz;
- len += sz;
-diff --git a/airscan-escl.c b/airscan-escl.c
-index dbaa370..163bdd1 100644
---- a/airscan-escl.c
-+++ b/airscan-escl.c
-@@ -335,16 +335,16 @@ escl_devcaps_source_parse (xml_rd *xml, devcaps_source **out)
- goto DONE;
- }
-
-- if (src->max_wid_px != 0 && src->max_hei_px != 0 )
-+ if (src->max_wid_px != 0 && src->max_hei_px != 0)
- {
- /* Validate window size */
-- if (src->min_wid_px >= src->max_wid_px )
-+ if (src->min_wid_px > src->max_wid_px)
- {
- err = ERROR("Invalid scan:MinWidth or scan:MaxWidth");
- goto DONE;
- }
-
-- if (src->min_hei_px >= src->max_hei_px)
-+ if (src->min_hei_px > src->max_hei_px)
- {
- err = ERROR("Invalid scan:MinHeight or scan:MaxHeight");
- goto DONE;
-diff --git a/airscan-http.c b/airscan-http.c
-index 6758368..ca6f8b0 100644
---- a/airscan-http.c
-+++ b/airscan-http.c
-@@ -114,6 +114,7 @@ http_uri_new_relative (const http_uri *base, const char *path,
-
- /* Free the URI
- */
-+#ifndef __clang_analyzer__
- void
- http_uri_free (http_uri *uri)
- {
-@@ -123,6 +124,7 @@ http_uri_free (http_uri *uri)
- g_free(uri);
- }
- }
-+#endif
-
- /* Get URI string
- */
-@@ -689,9 +691,21 @@ http_client_onerror (http_client *client,
- void
- http_client_cancel (http_client *client)
- {
-- while (client->pending->len != 0) {
-- http_query_cancel(client->pending->pdata[0]);
-+ size_t i, len = client->pending->len;
-+ size_t sz = len * sizeof(http_query*);
-+ http_query **qlist = g_alloca(len);
-+
-+ /* Note, without this stupid copying of client->pending->pdata,
-+ * clang analyzer doesn't understand that http_query_cancel()
-+ * has a side effect of removing http_query pointer from the
-+ * array and erroneously claims that memory used after free
-+ */
-+ memcpy(qlist, client->pending->pdata, sz);
-+ for (i = 0; i < len; i ++) {
-+ http_query_cancel(qlist[i]);
- }
-+
-+ log_assert(client->log, client->pending->len == 0);
- }
-
- /* Cancel all pending queries with matching address family and uintptr
-@@ -988,12 +1002,13 @@ http_query_cancel (http_query *q)
- g_object_ref(q->msg);
- soup_session_cancel_message(http_session, q->msg, SOUP_STATUS_CANCELLED);
- soup_message_set_status(q->msg, SOUP_STATUS_CANCELLED);
-- g_object_unref(q->msg);
-
- log_debug(q->client->log, "HTTP %s %s: %s", q->msg->method,
- http_uri_str(q->uri),
- soup_status_get_phrase(SOUP_STATUS_CANCELLED));
-
-+ g_object_unref(q->msg);
-+
- http_query_free(q);
- }
-
-@@ -1225,6 +1240,8 @@ http_start_stop (bool start)
- g_object_set_property(G_OBJECT(http_session),
- SOUP_SESSION_SSL_STRICT, &val);
- } else {
-+ ll_node *node;
-+
- soup_session_abort(http_session);
- g_object_unref(http_session);
- http_session = NULL;
-@@ -1232,10 +1249,8 @@ http_start_stop (bool start)
- /* Note, soup_session_abort() may leave some requests
- * pending, so we must free them here explicitly
- */
-- while (!ll_empty(&http_query_list)) {
-- ll_node *node = ll_first(&http_query_list);
-+ while ((node = ll_pop_beg(&http_query_list)) != NULL) {
- http_query *q = OUTER_STRUCT(node, http_query, list_node);
--
- http_query_free(q);
- }
- }
-diff --git a/airscan-math.c b/airscan-math.c
-index d801304..ee7f301 100644
---- a/airscan-math.c
-+++ b/airscan-math.c
-@@ -99,7 +99,6 @@ math_range_merge (SANE_Range *out, const SANE_Range *r1, const SANE_Range *r2)
- SANE_Word quant = math_lcm(r1->quant, r2->quant);
- SANE_Word min, max, bounds_min, bounds_max;
-
-- min = math_min(r1->min, r2->min);
- bounds_min = math_max(r1->min, r2->min);
- bounds_max = math_min(r1->max, r2->max);
-
-diff --git a/airscan-netif.c b/airscan-netif.c
-index a762377..a086792 100644
---- a/airscan-netif.c
-+++ b/airscan-netif.c
-@@ -92,6 +92,41 @@ netif_distance_get (const struct sockaddr *addr)
- return distance;
- }
-
-+/* Check that interface has non-link-local address
-+ * of particular address family
-+ */
-+bool
-+netif_has_non_link_local_addr (int af, int ifindex)
-+{
-+ struct ifaddrs *ifa;
-+
-+ for (ifa = netif_ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
-+ struct sockaddr *addr;
-+
-+ /* Skip interface without address */
-+ if ((addr = ifa->ifa_addr) == NULL) {
-+ continue;
-+ }
-+
-+ /* Check address family against requested */
-+ if (addr->sa_family != af) {
-+ continue;
-+ }
-+
-+ /* Skip link-local addresses */
-+ if (ip_sockaddr_is_linklocal(addr)) {
-+ continue;
-+ }
-+
-+ /* Check interface index */
-+ if (ifindex == (int) if_nametoindex(ifa->ifa_name)) {
-+ return true;
-+ }
-+ }
-+
-+ return false;
-+}
-+
- /* Get list of network interfaces addresses
- */
- netif_addr*
-diff --git a/airscan-wsdd.c b/airscan-wsdd.c
-index 15bf02a..c53105b 100644
---- a/airscan-wsdd.c
-+++ b/airscan-wsdd.c
-@@ -26,6 +26,12 @@
- #define WSDD_RETRANSMIT_MAX 250 /* Max retransmit time */
- #define WSDD_DISCOVERY_TIME 2500 /* Overall discovery time */
-
-+/* This delay is taken, if we have discovered, say, device's IPv6
-+ * addresses and have a strong suspicion that device has not yet
-+ * discovered IPv4 addresses as well
-+ */
-+#define WSDD_PUBLISH_DELAY 1000
-+
- /* WS-Discovery stable endpoint path
- */
- #define WSDD_STABLE_ENDPOINT \
-@@ -49,12 +55,13 @@ typedef struct {
- * device discovery
- */
- typedef struct {
-- zeroconf_finding finding; /* Base class */
-- const char *address; /* Device "address" in WS-SD sense */
-- ll_head xaddrs; /* List of wsdd_xaddr */
-- http_client *http_client; /* HTTP client */
-- ll_node list_node; /* In wsdd_finding_list */
-- bool published; /* This finding is published */
-+ zeroconf_finding finding; /* Base class */
-+ const char *address; /* Device "address" in WS-SD sense */
-+ ll_head xaddrs; /* List of wsdd_xaddr */
-+ http_client *http_client; /* HTTP client */
-+ ll_node list_node; /* In wsdd_finding_list */
-+ eloop_timer *publish_timer; /* WSDD_PUBLISH_DELAY timer */
-+ bool published; /* This finding is published */
- } wsdd_finding;
-
- /* wsdd_xaddr represents device transport address
-@@ -207,9 +214,8 @@ wsdd_xaddr_list_purge (ll_head *list)
- {
- ll_node *node;
-
-- while ((node = ll_first(list)) != NULL) {
-+ while ((node = ll_pop_beg(list)) != NULL) {
- wsdd_xaddr *xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-- ll_del(&xaddr->list_node);
- wsdd_xaddr_free(xaddr);
- }
- }
-@@ -269,6 +275,10 @@ wsdd_finding_free (wsdd_finding *wsdd)
- http_client_cancel(wsdd->http_client);
- http_client_free(wsdd->http_client);
-
-+ if (wsdd->publish_timer != NULL) {
-+ eloop_timer_cancel(wsdd->publish_timer);
-+ }
-+
- zeroconf_endpoint_list_free(wsdd->finding.endpoints);
- g_free((char*) wsdd->address);
- wsdd_xaddr_list_purge(&wsdd->xaddrs);
-@@ -282,17 +292,100 @@ wsdd_finding_free (wsdd_finding *wsdd)
- static void
- wsdd_finding_publish (wsdd_finding *wsdd)
- {
-- if (!wsdd->published) {
-- wsdd->published = true;
-- zeroconf_finding_publish(&wsdd->finding);
-+ if (wsdd->published) {
-+ return;
-+ }
-+
-+ wsdd->published = true;
-+ wsdd->finding.endpoints = zeroconf_endpoint_list_sort_dedup(
-+ wsdd->finding.endpoints);
-+
-+ if (wsdd->publish_timer != NULL) {
-+ log_debug(wsdd_log, "\"%s\": publish-delay timer canceled",
-+ wsdd->finding.model);
-+
-+ eloop_timer_cancel(wsdd->publish_timer);
-+ wsdd->publish_timer = NULL;
-+ }
-+
-+ zeroconf_finding_publish(&wsdd->finding);
-+}
-+
-+/* WSDD_PUBLISH_DELAY timer callback
-+ */
-+static void
-+wsdd_finding_publish_delay_timer_callback (void *data)
-+{
-+ wsdd_finding *wsdd = data;
-+
-+ wsdd->publish_timer = NULL;
-+ log_debug(wsdd_log, "\"%s\": publish-delay timer expired",
-+ wsdd->finding.model);
-+
-+ wsdd_finding_publish(wsdd);
-+}
-+
-+/* Publish wsdd_finding with optional delay
-+ */
-+static void
-+wsdd_finding_publish_delay (wsdd_finding *wsdd)
-+{
-+ bool delay = false;
-+
-+ if (wsdd->published) {
-+ return;
-+ }
-+
-+ /* Continue discovery, if interface has IPv4/IPv6 address,
-+ * and we have not yet discovered address of the same address
-+ * family of device
-+ *
-+ * Some devices doesn't return their IPv4 endpoints, if
-+ * metadata is queried via IPv6, and visa versa. This is
-+ * possible that we will finish discovery of the particular
-+ * address family, before we'll ever know that the device
-+ * may have address of another address family, so part
-+ * of addresses will be never discovered (see #44 for details).
-+ *
-+ * To prevent this situation, we continue discovery with
-+ * some reasonable delay, if network interface has IPv4/IPv6
-+ * address, but device is not yet.
-+ */
-+
-+ if (netif_has_non_link_local_addr(AF_INET, wsdd->finding.ifindex) &&
-+ !zeroconf_endpoint_list_has_non_link_local_addr(AF_INET,
-+ wsdd->finding.endpoints)) {
-+ log_debug(wsdd_log,
-+ "\"%s\": IPv4 address expected but not yet discovered",
-+ wsdd->finding.model);
-+ delay = true;
-+ }
-+
-+ if (netif_has_non_link_local_addr(AF_INET6, wsdd->finding.ifindex) &&
-+ !zeroconf_endpoint_list_has_non_link_local_addr(AF_INET6,
-+ wsdd->finding.endpoints)) {
-+ log_debug(wsdd_log,
-+ "\"%s\": IPv6 address expected but not yet discovered",
-+ wsdd->finding.model);
-+ delay = true;
-+ }
-+
-+ if (delay) {
-+ if (wsdd->publish_timer == NULL) {
-+ wsdd->publish_timer = eloop_timer_new(WSDD_PUBLISH_DELAY,
-+ wsdd_finding_publish_delay_timer_callback, wsdd);
-+ }
-+
-+ return;
- }
-+
-+ wsdd_finding_publish(wsdd);
- }
-
--/* Add wsdd_finding to the wsdd_finding_list.
-- * If finding already present, does nothing and returns NULL
-+/* Get existent finding or add a new one
- */
- static wsdd_finding*
--wsdd_finding_add (int ifindex, const char *address)
-+wsdd_finding_get (int ifindex, const char *address)
- {
- ll_node *node;
- wsdd_finding *wsdd;
-@@ -302,7 +395,7 @@ wsdd_finding_add (int ifindex, const char *address)
- wsdd = OUTER_STRUCT(node, wsdd_finding, list_node);
- if (wsdd->finding.ifindex == ifindex &&
- !strcmp(wsdd->address, address)) {
-- return NULL;
-+ return wsdd;
- }
- }
-
-@@ -343,6 +436,25 @@ wsdd_finding_by_address (ip_addr addr)
- return NULL;
- }
-
-+/* Check if finding already has particular xaddr
-+ */
-+static bool
-+wsdd_finding_has_xaddr (wsdd_finding *wsdd, const wsdd_xaddr *xaddr)
-+{
-+ ll_node *node;
-+ wsdd_xaddr *xaddr2;
-+
-+ for (LL_FOR_EACH(node, &wsdd->xaddrs)) {
-+ xaddr2 = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-+
-+ if (http_uri_equal(xaddr->uri, xaddr2->uri)) {
-+ return true;
-+ }
-+ }
-+
-+ return false;
-+}
-+
- /* Delete wsdd_finding from the wsdd_finding_list
- */
- static void
-@@ -532,24 +644,7 @@ DONE:
- g_free(manufacturer);
-
- if (http_client_num_pending(wsdd->http_client) == 0) {
-- zeroconf_endpoint *endpoint;
--
-- wsdd->finding.endpoints = zeroconf_endpoint_list_sort_dedup(
-- wsdd->finding.endpoints);
--
-- log_debug(wsdd_log, "\"%s\": address: %s",
-- wsdd->finding.model, wsdd->address);
-- log_debug(wsdd_log, "\"%s\": uuid: %s",
-- wsdd->finding.model, wsdd->finding.uuid.text);
-- log_debug(wsdd_log, "\"%s\": discovered endpoints:",
-- wsdd->finding.model);
--
-- for (endpoint = wsdd->finding.endpoints; endpoint != NULL;
-- endpoint = endpoint->next) {
-- log_debug(wsdd_log, " %s", http_uri_str(endpoint->uri));
-- }
--
-- wsdd_finding_publish(wsdd);
-+ wsdd_finding_publish_delay(wsdd);
- }
- }
-
-@@ -738,28 +833,42 @@ wsdd_resolver_message_dispatch (wsdd_resolver *resolver,
- goto DONE;
- }
-
-- /* Add a finding. Do nothing if device already exist */
-- wsdd = wsdd_finding_add(resolver->ifindex, msg->address);
-- if (wsdd == NULL) {
-- goto DONE;
-- }
-+ /* Add a finding or get existent one */
-+ wsdd = wsdd_finding_get(resolver->ifindex, msg->address);
-
-- /* If device is not scanner or (which is very unlikely)
-- * has no xaddrs, just publish it without endpoints,
-- * so zeroconf stuff will know that there is no need to
-- * wait anymore for a device with this UUID, and we
-- * are done
-+ /* Import newly discovered xaddrs and initiate metadata
-+ * query
- */
-- if (!msg->is_scanner || ll_empty(&msg->xaddrs)) {
-- wsdd_finding_publish(wsdd);
-- goto DONE;
-+ while ((node = ll_pop_beg(&msg->xaddrs)) != NULL) {
-+ xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-+
-+ if (wsdd_finding_has_xaddr(wsdd, xaddr)) {
-+ wsdd_xaddr_free(xaddr);
-+ continue;
-+ }
-+
-+ ll_push_end(&wsdd->xaddrs, &xaddr->list_node);
-+ if (msg->is_scanner) {
-+ wsdd_finding_get_metadata(wsdd, resolver->ifindex, xaddr);
-+ }
- }
-
-- /* Initiate metadata query */
-- ll_cat(&wsdd->xaddrs, &msg->xaddrs);
-- for (LL_FOR_EACH(node, &wsdd->xaddrs)) {
-- xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-- wsdd_finding_get_metadata(wsdd, resolver->ifindex, xaddr);
-+ /* If there is no pending metadata queries, it may mean
-+ * one of the following:
-+ * 1) device is not scanner, metadata won't be requested
-+ * 2) there is no xaddrs (which is very unlikely, but
-+ * just in case...)
-+ * 3) device already known and all metadata queries
-+ * already finished
-+ *
-+ * At this case we can publish device now
-+ */
-+ if (http_client_num_pending(wsdd->http_client) == 0) {
-+ if (msg->is_scanner) {
-+ wsdd_finding_publish_delay(wsdd);
-+ } else {
-+ wsdd_finding_publish(wsdd);
-+ }
- }
- break;
-
-@@ -774,6 +883,7 @@ wsdd_resolver_message_dispatch (wsdd_resolver *resolver,
- /* Cleanup and exit */
- DONE:
- wsdd_message_free(msg);
-+ log_trace(wsdd_log, "");
- }
-
-
-diff --git a/airscan-zeroconf.c b/airscan-zeroconf.c
-index dfff5b8..293a05d 100644
---- a/airscan-zeroconf.c
-+++ b/airscan-zeroconf.c
-@@ -129,11 +129,8 @@ zeroconf_device_add (zeroconf_finding *finding)
- }
-
- ll_init(&device->findings);
--
-- device->ifaces_cap = ZEROCONF_DEVICE_IFACES_INITIAL_LEN;
-- device->ifaces = g_malloc(device->ifaces_cap * sizeof(*device->ifaces));
--
- ll_push_end(&zeroconf_device_list, &device->node_list);
-+
- return device;
- }
-
-@@ -233,7 +230,12 @@ zeroconf_device_ifaces_add (zeroconf_device *device, int ifindex)
- {
- if (!zeroconf_device_ifaces_lookup(device, ifindex)) {
- if (device->ifaces_len == device->ifaces_cap) {
-- device->ifaces_cap *= 2;
-+ if (device->ifaces_cap == 0) {
-+ device->ifaces_cap = ZEROCONF_DEVICE_IFACES_INITIAL_LEN;
-+ } else {
-+ device->ifaces_cap *= 2;
-+ }
-+
- device->ifaces = g_realloc(device->ifaces,
- device->ifaces_cap * sizeof(*device->ifaces));
- }
-@@ -260,7 +262,7 @@ zeroconf_device_rebuild_sets (zeroconf_device *device)
- finding = OUTER_STRUCT(node, zeroconf_finding, list_node);
- proto = zeroconf_method_to_proto(finding->method);
-
-- zeroconf_device_ifaces_add(device, finding->ifindex );
-+ zeroconf_device_ifaces_add(device, finding->ifindex);
- if (proto != ID_PROTO_UNKNOWN) {
- device->protocols |= 1 << proto;
- }
-@@ -316,19 +318,26 @@ static void
- zeroconf_device_borrow_findings (zeroconf_device *device,
- int ifindex, ll_head *output)
- {
-- ll_node *node, *next;
-- zeroconf_finding *finding;
-+ ll_node *node;
-+ ll_head leftover;
-
-- for (node = ll_first(&device->findings); node != NULL; node = next) {
-- next = ll_next(&device->findings, node);
-+ ll_init(&leftover);
-+
-+ while ((node = ll_pop_beg(&device->findings)) != NULL) {
-+ zeroconf_finding *finding;
-
- finding = OUTER_STRUCT(node, zeroconf_finding, list_node);
-+
- if (finding->ifindex == ifindex) {
- finding->device = NULL;
- ll_push_end(output, node);
-+ } else {
-+ ll_push_end(&leftover, node);
- }
- }
-
-+ ll_cat(&device->findings, &leftover);
-+
- if (ll_empty(&device->findings)) {
- zeroconf_device_del(device);
- return;
-@@ -556,7 +565,7 @@ zeroconf_ident_split (const char *ident, unsigned int *devid, ID_PROTO *proto)
-
- /* Decode proto and devid */
- *proto = zeroconf_ident_proto_decode(*ident);
-- if (*proto == NUM_ID_PROTO) {
-+ if (*proto == ID_PROTO_UNKNOWN) {
- return NULL;
- }
-
-@@ -774,6 +783,25 @@ zeroconf_endpoint_list_sort_dedup (zeroconf_endpoint *list)
- return list;
- }
-
-+/* Check if endpoints list contains a non-link-local address
-+ * of the specified address family
-+ */
-+bool
-+zeroconf_endpoint_list_has_non_link_local_addr (int af,
-+ const zeroconf_endpoint *list)
-+{
-+ for (;list != NULL; list = list->next) {
-+ const struct sockaddr *addr = http_uri_addr(list->uri);
-+ if (addr != NULL && addr->sa_family == af) {
-+ if (!ip_sockaddr_is_linklocal(addr)) {
-+ return true;
-+ }
-+ }
-+ }
-+
-+ return false;
-+}
-+
- /******************** Static configuration *********************/
- /* Look for device's static configuration by device name
- */
-@@ -850,7 +878,7 @@ zeroconf_finding_publish (zeroconf_finding *finding)
- */
- device = zeroconf_device_find_by_uuid(finding->uuid);
- if (device != NULL && finding->name != NULL) {
-- if (device->ifaces_len == 1 && device->ifaces[0] == finding->ifindex ){
-+ if (device->ifaces_len == 1 && device->ifaces[0] == finding->ifindex){
- /* Case 2: all findings belongs to the same network
- * interface; upgrade anonymous device to named
- */
-@@ -1055,6 +1083,41 @@ zeroconf_device_list_qsort_cmp (const void *p1, const void *p2)
- return cmp;
- }
-
-+/* Format list of protocols, for zeroconf_device_list_log
-+ */
-+static void
-+zeroconf_device_list_fmt_protocols (char *buf, size_t buflen, unsigned int protocols)
-+{
-+ ID_PROTO proto;
-+ size_t off = 0;
-+
-+ buf[0] = '\0';
-+ for (proto = 0; proto < NUM_ID_PROTO; proto ++) {
-+ if ((protocols & (1 << proto)) != 0) {
-+ off += snprintf(buf + off, buflen - off, " %s",
-+ id_proto_name(proto));
-+ }
-+ }
-+
-+ if (buf[0] == '\0') {
-+ strcpy(buf, " none");
-+ }
-+}
-+
-+/* Log device information in a context of zeroconf_device_list_get
-+ */
-+static void
-+zeroconf_device_list_log (zeroconf_device *device, const char *name, unsigned int protocols)
-+{
-+ char buf[64];
-+
-+ zeroconf_device_list_fmt_protocols(buf, sizeof(buf), device->protocols);
-+ log_debug(zeroconf_log, "%s: supported protocols:%s", name, buf);
-+
-+ zeroconf_device_list_fmt_protocols(buf, sizeof(buf), protocols);
-+ log_debug(zeroconf_log, "%s: chosen protocols:%s", name, buf);
-+}
-+
- /* Get list of devices, in SANE format
- */
- const SANE_Device**
-@@ -1065,10 +1128,14 @@ zeroconf_device_list_get (void)
- const SANE_Device **dev_list = sane_device_array_new();
- ll_node *node;
-
-+ log_debug(zeroconf_log, "zeroconf_device_list_get: requested");
-+
- /* Wait until device table is ready */
- zeroconf_initscan_wait();
-
- /* Build list of devices */
-+ log_debug(zeroconf_log, "zeroconf_device_list_get: building list of devices");
-+
- dev_count = 0;
-
- for (dev_conf = conf.devices; dev_conf != NULL; dev_conf = dev_conf->next) {
-@@ -1097,8 +1164,18 @@ zeroconf_device_list_get (void)
- zeroconf_device_name_model(device, &name, &model);
- protocols = zeroconf_device_protocols(device);
-
-+ zeroconf_device_list_log(device, name, protocols);
-+
- if (zeroconf_find_static_by_name(name) != NULL) {
- /* Static configuration overrides discovery */
-+ log_debug(zeroconf_log,
-+ "%s: skipping, device clashes statically configured", name);
-+ continue;
-+ }
-+
-+ if (protocols == 0) {
-+ log_debug(zeroconf_log,
-+ "%s: skipping, no of supported protocols discovered", name);
- continue;
- }
-
-@@ -1327,6 +1404,8 @@ zeroconf_init (void)
- log_trace(zeroconf_log, " protocol = %s", s);
-
- s = "?";
-+ (void) s; /* Silence CLANG analyzer warning */
-+
- switch (conf.wsdd_mode) {
- case WSDD_FAST: s = "fast"; break;
- case WSDD_FULL: s = "full"; break;
-diff --git a/airscan.h b/airscan.h
-index 3aca207..2a36333 100644
---- a/airscan.h
-+++ b/airscan.h
-@@ -130,8 +130,10 @@ ll_push_beg (ll_head *head, ll_node *node)
- static inline void
- ll_del (ll_node *node)
- {
-- node->ll_prev->ll_next = node->ll_next;
-- node->ll_next->ll_prev = node->ll_prev;
-+ ll_node *p = node->ll_prev, *n = node->ll_next;
-+
-+ p->ll_next = n;
-+ n->ll_prev = p;
-
- /* Make double-delete safe */
- node->ll_next = node->ll_prev = node;
-@@ -143,14 +145,19 @@ ll_del (ll_node *node)
- static inline ll_node*
- ll_pop_beg (ll_head *head)
- {
-- ll_node *node;
-+ ll_node *node, *next;
-
-- if (ll_empty(head)) {
-- return NULL;
-+ node = head->node.ll_next;
-+ if (node == &head->node) {
-+ return NULL; /* List is empty if it is looped to itself */
- }
-
-- node = head->node.ll_next;
-- ll_del(node);
-+ next = node->ll_next;
-+ next->ll_prev = &head->node;
-+ head->node.ll_next = next;
-+
-+ /* Make double-delete safe */
-+ node->ll_next = node->ll_prev = node;
-
- return node;
- }
-@@ -161,14 +168,19 @@ ll_pop_beg (ll_head *head)
- static inline ll_node*
- ll_pop_end (ll_head *head)
- {
-- ll_node *node;
-+ ll_node *node, *prev;
-
-- if (ll_empty(head)) {
-- return NULL;
-+ node = head->node.ll_prev;
-+ if (node == &head->node) {
-+ return NULL; /* List is empty if it is looped to itself */
- }
-
-- node = head->node.ll_prev;
-- ll_del(node);
-+ prev = node->ll_prev;
-+ prev->ll_next = &head->node;
-+ head->node.ll_prev = prev;
-+
-+ /* Make double-delete safe */
-+ node->ll_next = node->ll_prev = node;
-
- return node;
- }
-@@ -702,6 +714,12 @@ typedef enum {
- NETIF_DISTANCE
- netif_distance_get (const struct sockaddr *addr);
-
-+/* Check that interface has non-link-local address
-+ * of particular address family
-+ */
-+bool
-+netif_has_non_link_local_addr (int af, int ifindex);
-+
- /* Compare addresses by distance. Returns:
- * <0, if addr1 is closer that addr2
- * >0, if addr2 is farther that addr2
-@@ -2055,6 +2073,13 @@ zeroconf_endpoint_list_sort (zeroconf_endpoint *list);
- zeroconf_endpoint*
- zeroconf_endpoint_list_sort_dedup (zeroconf_endpoint *list);
-
-+/* Check if endpoints list contains a non-link-local address
-+ * of the specified address family
-+ */
-+bool
-+zeroconf_endpoint_list_has_non_link_local_addr (int af,
-+ const zeroconf_endpoint *list);
-+
- /******************** MDNS Discovery ********************/
- /* Called by zeroconf to notify MDNS about initial scan timer expiration
- */
-@@ -2594,6 +2619,7 @@ log_panic (log_ctx *log, const char *fmt, ...);
- if (!(expr)) { \
- log_panic(log,"file %s: line %d (%s): assertion failed: (%s)",\
- __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
-+ __builtin_unreachable(); \
- } \
- } while (0)
-
-@@ -2603,6 +2629,7 @@ log_panic (log_ctx *log, const char *fmt, ...);
- do { \
- log_panic(log,"file %s: line %d (%s): internal error", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__); \
-+ __builtin_unreachable(); \
- } while (0)
-
- #endif
-diff --git a/sane-airscan.5 b/sane-airscan.5
-index 84ed929..32656e1 100644
---- a/sane-airscan.5
-+++ b/sane-airscan.5
-@@ -1,7 +1,7 @@
- .\" generated with Ronn/v0.7.3
- .\" http://github.com/rtomayko/ronn/tree/0.7.3
- .
--.TH "SANE\-AIRSCAN" "5" "May 2020" "" "AirScan (eSCL) and WSD SANE backend"
-+.TH "SANE\-AIRSCAN" "5" "July 2020" "" "AirScan (eSCL) and WSD SANE backend"
- .
- .SH "NAME"
- \fBsane\-airscan\fR \- SANE backend for AirScan (eSCL) and WSD scanners and MFP
-@@ -82,7 +82,7 @@ To manually configure a device, add the following section to the configuration f
- [devices]
- "Kyocera eSCL" = http://192\.168\.1\.102:9095/eSCL, eSCL
- "Kyocera WSD" = http://192\.168\.1\.102:5358/WSDScanner, WSD
--"Device I don\'t want to see" = disable
-+"Device I do not want to see" = disable
- .
- .fi
- .
-@@ -146,8 +146,8 @@ Debuggung facilities can be controlled using the \fB[debug]\fR section of the co
- enable = false | true
-
- ; Enable protocol trace and configure output directory
--; for trace files\. To specify path relative to user\'s
--; home directory, start it with tilda character, followed
-+; for trace files\. Like in shell, to specify path relative to
-+; the home directory, start it with tilda character, followed
- ; by slash, i\.e\., "~/airscan/trace"\. The directory will
- ; be created automatically\.
- trace = path
-diff --git a/sane-airscan.5.md b/sane-airscan.5.md
-index 4461900..6c6ec10 100644
---- a/sane-airscan.5.md
-+++ b/sane-airscan.5.md
-@@ -46,7 +46,7 @@ file:
- [devices]
- "Kyocera eSCL" = http://192.168.1.102:9095/eSCL, eSCL
- "Kyocera WSD" = http://192.168.1.102:5358/WSDScanner, WSD
-- "Device I don't want to see" = disable
-+ "Device I do not want to see" = disable
-
- The `[devices]` section contains all manually configured devices, one line per
- device, and each line contains a device name on a left side of equation and
-@@ -109,8 +109,8 @@ of the configuration file:
- enable = false | true
-
- ; Enable protocol trace and configure output directory
-- ; for trace files. To specify path relative to user's
-- ; home directory, start it with tilda character, followed
-+ ; for trace files. Like in shell, to specify path relative to
-+ ; the home directory, start it with tilda character, followed
- ; by slash, i.e., "~/airscan/trace". The directory will
- ; be created automatically.
- trace = path
-diff --git a/test-decode.c b/test-decode.c
-index 5b2879e..af774a5 100644
---- a/test-decode.c
-+++ b/test-decode.c
-@@ -26,7 +26,7 @@ typedef struct {
-
- /* Print error message and exit
- */
--void
-+void __attribute__((noreturn))
- die (const char *format, ...)
- {
- va_list ap;
-@@ -218,6 +218,7 @@ main (int argc, char **argv)
- save_write(save, line);
- }
-
-+ g_free(line);
- save_close(save);
-
- return 0;