Hello community,

here is the log from the commit of package libspiro for openSUSE:Factory 
checked in at 2020-09-03 01:12:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libspiro (Old)
 and      /work/SRC/openSUSE:Factory/.libspiro.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libspiro"

Thu Sep  3 01:12:05 2020 rev:9 rq:830130 version:20200505

Changes:
--------
--- /work/SRC/openSUSE:Factory/libspiro/libspiro.changes        2020-01-01 
14:56:37.401878602 +0100
+++ /work/SRC/openSUSE:Factory/.libspiro.new.3399/libspiro.changes      
2020-09-03 01:12:33.712435423 +0200
@@ -1,0 +2,18 @@
+Sat Aug 15 21:50:34 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 20200505:
+  * Bugfix for CVE-2019-19847 affecting {call-test14 to call-test19}.
+  * Fix a memory access bug/error created earlier by patch 2017oct28
+    Users using tagpoint libspiro20150702 are unaffected by this bug.
+    Users using tagpoint libspiro20190731 are recommended to upgrade.
+    Thanks to Frederic Cambus for calling attention to these faults.
+  * Add optional 'end knot' for open curves (useful for displaying).
+  * CRA Version also higher than so-bump 1.0.5 used on some distros;
+    this maybe of interest to distros that bumped an earlier version.
+  * Some garbage-in/garbage-out checks to verify we have 'ah' pairs,
+    and we don't start with ']', or end with '['. Add libspiro.3 man.
+  * Corrected set_di_to_x1y1() to use a constant bandwidth of 0.0005
+  * Code improvements and bug fixes for better tagged/spiro results.
+  * Several improvements added to further increase libspiro's speed.
+
+-------------------------------------------------------------------

Old:
----
  20190731.tar.gz

New:
----
  20200505.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libspiro.spec ++++++
--- /var/tmp/diff_new_pack.4ti5BZ/_old  2020-09-03 01:12:35.472436070 +0200
+++ /var/tmp/diff_new_pack.4ti5BZ/_new  2020-09-03 01:12:35.472436070 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package libspiro
 #
-# Copyright (c) 2019 SUSE LLC
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %define sonum   1
 Name:           libspiro
-Version:        20190731
+Version:        20200505
 Release:        0
 Summary:        A clothoid to bezier spline converter
 License:        GPL-2.0-or-later
@@ -73,14 +73,14 @@
 %postun -n %{name}%{sonum} -p /sbin/ldconfig
 
 %files -n %{name}%{sonum}
-%defattr(-,root,root)
-%doc AUTHORS ChangeLog COPYING README* 
+%license COPYING
+%doc ChangeLog README* 
 %{_libdir}/lib*.so.*
 
 %files devel
-%defattr(-,root,root)
 %{_includedir}/*
 %{_libdir}/*.so
+%{_mandir}/man3/libspiro.3*
 %{_libdir}/pkgconfig/*.pc
 
 %changelog

++++++ 20190731.tar.gz -> 20200505.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/AUTHORS 
new/libspiro-20200505/AUTHORS
--- old/libspiro-20190731/AUTHORS       2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/AUTHORS       2020-05-05 09:46:37.000000000 +0200
@@ -5,7 +5,7 @@
 
 Patent Grant and Copyright (C) 2007 Raph Levien
 
-Extra edits, patches, updates... (2013...,2019)
+Extra edits, patches, updates... (2013...,2020)
 Dave Crossland
 Shriramana Sharma
 Joe Da Silva
@@ -14,3 +14,6 @@
 Jeremy Tan
 Wiesław Šoltés
 Mingye Wang
+Frederic Cambus
+Fredrick Brennan
+C.W. Betts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/ChangeLog 
new/libspiro-20200505/ChangeLog
--- old/libspiro-20190731/ChangeLog     2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/ChangeLog     2020-05-05 09:46:37.000000000 +0200
@@ -1,5 +1,21 @@
+- 2020-May-05
+    * Libspiro Version 20200505 (1.1.0)
+    * Bugfix for CVE-2019-19847 affecting {call-test14 to call-test19}.
+    * Fix a memory access bug/error created earlier by patch 2017oct28
+      Users using tagpoint libspiro20150702 are unaffected by this bug.
+      Users using tagpoint libspiro20190731 are recommended to upgrade.
+      Thanks to Frederic Cambus for calling attention to these faults.
+    * Add optional 'end knot' for open curves (useful for displaying).
+    * CRA Version also higher than so-bump 1.0.5 used on some distros;
+      this maybe of interest to distros that bumped an earlier version.
+    * Some garbage-in/garbage-out checks to verify we have 'ah' pairs,
+      and we don't start with ']', or end with '['. Add libspiro.3 man.
+    * Corrected set_di_to_x1y1() to use a constant bandwidth of 0.0005
+    * Code improvements and bug fixes for better tagged/spiro results.
+    * Several improvements added to further increase libspiro's speed.
+
 - 2019-Jul-31
-    * Libspiro Version 20190731
+    * Libspiro Version 20190731 (1.0.0)
     * Corrected library to report correctly as next version up. This is
       probably a significant change, therefore bumped library to start
       at 1.0 even though backwards compatibility remains close to same.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/Makefile.am 
new/libspiro-20200505/Makefile.am
--- old/libspiro-20190731/Makefile.am   2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/Makefile.am   2020-05-05 09:46:37.000000000 +0200
@@ -5,7 +5,8 @@
 test_programs = call-test0 call-test1 call-test2 call-test3 call-test4 \
                call-test5 call-test6 call-test7 call-test8 call-test9 \
                call-test10 call-test11 call-test12 call-test13        \
-               call-test14 call-test15 call-testm
+               call-test14 call-test15 call-test16 call-test17        \
+               call-test18 call-test19 call-test20 call-testm
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libspiro.pc
@@ -26,15 +27,15 @@
 libspiro_la_SOURCES = spiro.c bezctx.c spiroentrypoints.c
 libspiro_la.$(OBJEXT): bezctx.h bezctx_intf.h spiro.h spiroentrypoints.h
 
-EXTRA_DIST = bezctx.md get-spiro-src.sh README-RaphLevien README.md zmisc.h \
+EXTRA_DIST = bezctx.md get-spiro-src.sh README-RaphLevien README.md        \
        closedspiro.png openspiro.png spiral16.png spiral32.png spiro-a.png \
        java/ShowPlate.java java/Spiro.java java/SpiroBezierContext.java    \
        java/SpiroCanvas.java java/SpiroCP.java java/SpiroGeneralPath.java  \
        java/SpiroPointType.java README-GeorgeWilliams fontforge-debug.txt  \
-       fontforge.sh m4/ax_check_compile_flag.m4 tests/call-test.c          \
-       path5.png path6.png
+       fontforge.sh m4/ax_check_compile_flag.m4 path5.png path6.png libspiro.3
 
 include_HEADERS = bezctx.h bezctx_intf.h spiro.h spiroentrypoints.h
+man_MANS = libspiro.3
 
 libtool: $(LIBTOOL_DEPS)
        $(SHELL) ./config.status libtool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/README.md 
new/libspiro-20200505/README.md
--- old/libspiro-20190731/README.md     2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/README.md     2020-05-05 09:46:37.000000000 +0200
@@ -18,7 +18,7 @@
 
 First, you need to create the ./configure script if you do not have it yet
 ```sh
-autoreconf -i
+autoreconf -i  (or use 'autoreconf --install --force' for more modern setups)
 automake --foreign -Wall
 ```
 
@@ -168,6 +168,7 @@
 
 ```c
 /* int ncq flags and values */
+#define SPIRO_INCLUDE_LAST_KNOT        0x0100
 #define SPIRO_RETRO_VER1       0x0400
 #define SPIRO_REVERSE_SRC      0x0800
 #define SPIRO_ARC_CUB_QUAD_CLR 0x7FFF
@@ -181,6 +182,10 @@
 
 The definitions for ncq (above) are:
 
+SPIRO_INCLUDE_LAST_KNOT:
+Existing libspiro behaviour is to add a knot point to match each spiro point, 
but does not include the last knot.
+This option includes the last knot with the existing output results while the 
spiro is still open. Closed spiros should refer to the first knot point since 
the last and first knot are the same.
+
 SPIRO_RETRO_VER1:
 This newer version of libspiro has modified the way path calculations are made.
 The reason for this was seen as an advantage, because it allows a user to 
scale and move spiro paths, which is a common expectation in graphics, and 
there are other added advantages, such as making the path as part of templates, 
and more.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/config.guess 
new/libspiro-20200505/config.guess
--- old/libspiro-20190731/config.guess  2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/config.guess  2020-05-05 09:46:37.000000000 +0200
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2019 Free Software Foundation, Inc.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
 
-timestamp='2019-07-24'
+timestamp='2020-04-26'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2019 Free Software Foundation, Inc.
+Copyright 1992-2020 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -99,6 +99,8 @@
 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
 
 set_cc_for_build() {
+    # prevent multiple calls if $tmp is already set
+    test "$tmp" && return 0
     : "${TMPDIR=/tmp}"
     # shellcheck disable=SC2039
     { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n 
"$tmp" && test -d "$tmp" ; } ||
@@ -274,6 +276,9 @@
     *:Sortix:*:*)
        echo "$UNAME_MACHINE"-unknown-sortix
        exit ;;
+    *:Twizzler:*:*)
+       echo "$UNAME_MACHINE"-unknown-twizzler
+       exit ;;
     *:Redox:*:*)
        echo "$UNAME_MACHINE"-unknown-redox
        exit ;;
@@ -921,7 +926,7 @@
        echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
        exit ;;
     alpha:Linux:*:*)
-       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 
2>/dev/null` in
          EV5)   UNAME_MACHINE=alphaev5 ;;
          EV56)  UNAME_MACHINE=alphaev56 ;;
          PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -1624,6 +1629,12 @@
   https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
   https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+EOF
+
+year=`echo $timestamp | sed 's,-.*,,'`
+# shellcheck disable=SC2003
+if test "`expr "\`date +%Y\`" - "$year"`" -lt 3 ; then
+   cat >&2 <<EOF
 
 If $0 has already been updated, send the following data and any
 information you think might be pertinent to [email protected] to
@@ -1651,6 +1662,7 @@
 UNAME_SYSTEM  = "$UNAME_SYSTEM"
 UNAME_VERSION = "$UNAME_VERSION"
 EOF
+fi
 
 exit 1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/config.sub 
new/libspiro-20200505/config.sub
--- old/libspiro-20190731/config.sub    2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/config.sub    2020-05-05 09:46:37.000000000 +0200
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2019 Free Software Foundation, Inc.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
 
-timestamp='2019-06-30'
+timestamp='2020-04-24'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2019 Free Software Foundation, Inc.
+Copyright 1992-2020 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -1343,7 +1343,7 @@
             | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
             | sym* | kopensolaris* | plan9* \
             | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
-            | aos* | aros* | cloudabi* | sortix* \
+            | aos* | aros* | cloudabi* | sortix* | twizzler* \
             | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
             | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
             | knetbsd* | mirbsd* | netbsd* \
@@ -1366,7 +1366,7 @@
             | skyos* | haiku* | rdos* | toppers* | drops* | es* \
             | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
             | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
-            | nsk* | powerunix)
+            | nsk* | powerunix*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        qnx*)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/configure.ac 
new/libspiro-20200505/configure.ac
--- old/libspiro-20190731/configure.ac  2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/configure.ac  2020-05-05 09:46:37.000000000 +0200
@@ -1,12 +1,12 @@
 # -*- Autoconf -*-
 dnl Process this file with autoconf to produce a configure script.
 
-# Copyright (C) 2013...2019 by Joe Da Silva
+# Copyright (C) 2013...2020 by Joe Da Silva
 
 AC_PREREQ([2.64])
 #-------------------------------------------
 # PackageTimestamp version
-m4_define([spiro_package_stamp], [20190731])
+m4_define([spiro_package_stamp], [20200505])
 #-------------------------------------------
 # Making point releases:
 #   spiro_major_version += 0;
@@ -21,7 +21,7 @@
 #   spiro_minor_version = 0;
 #
 m4_define([spiro_major_version], [1])
-m4_define([spiro_minor_version], [0])
+m4_define([spiro_minor_version], [1])
 m4_define([spiro_version],[spiro_major_version.spiro_minor_version])
 
 #-------------------------------------------
@@ -45,18 +45,19 @@
 #  spiro_age = 0
 #
 m4_define([spiro_current], [1])
-m4_define([spiro_revision],[0])
+m4_define([spiro_revision],[1])
 m4_define([spiro_age],     [0])
 m4_define([spiro_libver],[spiro_current:spiro_revision:spiro_age])
 
 m4_define([spiro_package_name], [libspiro])
- 
+
 AC_INIT([spiro],[spiro_package_stamp],[[email protected]],
        [spiro_package_name],[https://github.com/fontforge/libspiro])
 
 #-------------------------------------------
 AC_CONFIG_SRCDIR([spiro.c])
 AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_SYSTEM
 AC_CANONICAL_HOST
 AC_CANONICAL_BUILD
 AM_INIT_AUTOMAKE([foreign -Wall])
@@ -115,25 +116,36 @@
 AC_CHECK_FUNCS(hypot, ,[AC_MSG_FAILURE([ERROR: hypot() required but not 
found.],[1])])
 
 #-------------------------------------------
-# Check for C99 finite or isfinite. Use one.
-math_finite=no
+# Check for C99 isfinite or finite. Use one.
 math_isfinite=no
-AC_CHECK_FUNCS(finite,
-  [AC_SUBST(HAVE_FINITE)
-   math_finite=true],
-    AC_CHECK_FUNCS(isfinite,
-      [AC_SUBST(HAVE_ISFINITE)
-       math_isfinite=true]))
+math_finite=no
+AC_CHECK_FUNCS(isfinite,
+  [AC_DEFINE(HAVE_ISFINITE, 1)
+   math_isfinite=true],
+  [AC_LINK_IFELSE(
+    [AC_LANG_PROGRAM(
+      [[#include <math.h>]],
+      [[double f = 0.0; isfinite(f)]])],
+    [AC_DEFINE(HAVE_ISFINITE, 1)
+     math_isfinite=true],
+      [AC_CHECK_FUNCS(finite,
+        [AC_DEFINE(HAVE_FINITE, 1)
+         math_finite=true])])])
 
-if test x"${math_finite}" = xno && test x"${math_isfinite}" = xno; then
-  AC_MSG_FAILURE([ERROR: finite() or isfinite() required but not found.],[1])
+if test x"${math_isfinite}" = xno && test x"${math_finite}" = xno; then
+  AC_MSG_FAILURE([ERROR: isfinite() or finite() required but not found.],[1])
 fi
 
-AH_BOTTOM([/* Define IS_FINITE(x) to finite(x) or isfinite(x) */
-#ifdef HAVE_FINITE
-#define IS_FINITE(x) finite(x)
-#else
+AC_SUBST(HAVE_FINITE)
+AC_SUBST(HAVE_ISFINITE)
+
+AH_BOTTOM([/* Define IS_FINITE(x) to isfinite(x) or finite(x) */
+#if HAVE_ISFINITE
 #define IS_FINITE(x) isfinite(x)
+#else
+#if HAVE_FINITE
+#define IS_FINITE(x) finite(x)
+#endif
 #endif])
 
 #-------------------------------------------
@@ -221,6 +233,7 @@
 AX_CHECK_COMPILE_FLAG([-Wc++-compat],[WCFLAGS="$WCFLAGS -Wc++-compat"])
 AX_CHECK_COMPILE_FLAG([-Wmissing-prototypes],[WCFLAGS="$WCFLAGS 
-Wmissing-prototypes"])
 AX_CHECK_COMPILE_FLAG([-Wunused],[WCFLAGS="$WCFLAGS -Wunused"])
+AX_CHECK_COMPILE_FLAG([-Wdeprecated-declarations],[WCFLAGS="$WCFLAGS 
-Wdeprecated-declarations"])
 
 dnl  AX_CHECK_COMPILE_FLAG([-Wconversion],[WCFLAGS="$WCFLAGS -Wconversion"])
 dnl  AX_CHECK_COMPILE_FLAG([-Wsign-conversion],[WCFLAGS="$WCFLAGS 
-Wsign-conversion"])
@@ -236,6 +249,18 @@
 dnl   AX_CHECK_COMPILE_FLAG([-Wcast-align],[WCFLAGS="$WCFLAGS -Wcast-align"])
 dnl   AX_CHECK_COMPILE_FLAG([-Wpadded],[WCFLAGS="$WCFLAGS -Wpadded"])
 dnl   AX_CHECK_COMPILE_FLAG([-Woverlength-strings],[WCFLAGS="$WCFLAGS 
-Woverlength-strings"])
+
+dnl NOTE: -fsanitize has to be first library
+dnl and will also conflict with other checks
+dnl like valgrind due to similar test checks
+dnl AX_CHECK_COMPILE_FLAG([-fsanitize=address],[CFLAGS=" -fsanitize=address 
$CFLAGS"])
+
+dnl NOTE: -fstack-protector may be simulated
+dnl on 32bit linux using these extra params:
+dnl ./configure CFLAGS="-fstack-protector --param ssp-buffer-size=4 -g -O0"
+dnl out-of-the-box params for open/free bsd:
+dnl AX_CHECK_COMPILE_FLAG([-fstack-protector],[CFLAGS=" -fstack-protector"])
+
 AC_LANG_POP
 # Skip if replacing with LS_LIB instead.
 WLSLIB=""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/libspiro.3 
new/libspiro-20200505/libspiro.3
--- old/libspiro-20190731/libspiro.3    1970-01-01 01:00:00.000000000 +0100
+++ new/libspiro-20200505/libspiro.3    2020-05-05 09:46:37.000000000 +0200
@@ -0,0 +1,52 @@
+.TH SPIRO 3 "2020-May-05"
+.SH NAME
+libspiro \- A clothoid to bezier spline converter
+.SH SYNOPSIS
+.B #include <spiroentrypoints.h>
+and then compile and link with
+.B -lspiro
+.br
+.SH DESCRIPTION
+.B Spiro
+library for curve design which simplifies drawing of
+beautiful curves.
+
+.B libspiro
+takes an array of spiro control points which can be
+easier for an artist to create and modify, and then converts
+these into a series of bezier splines which can then be used
+in the myriad of ways the world has come to use beziers.
+
+.I spiroentrypoints.h
+has technical information on how to connect with
+.I libspiro
+and further information can be found at
+.I http://github.com/fontforge/libspiro
+.SH REPORTING PROBLEMS
+Before reporting a problem, please check the libspiro web
+site to verify that you have the latest version of
+.I libspiro
+
+Great care has been taken to maintain backwards compatibility
+so it is recommended to upgrade if you experience problems with
+earlier
+.I libspiro
+versions.
+.SH AUTHORS AND LICENSE
+.B libspiro
+originated from
+.B ppedit
+which was a pattern plate editor for Spiro splines.
+Copyright (C) 2007 Raph Levien. GNU GPL version 2 or higher.
+
+This version of
+.B libspiro
+Copyright (C) 2007-2020 is GNU GPL version 3 or higher
+and contains a number of significant improvements and fixes.
+
+Please see
+.I AUTHORS
+file for everyone involved in making and improving
+.I libspiro
+
+Further details (on why and what) can also be seen in git history.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/spiro.c 
new/libspiro-20200505/spiro.c
--- old/libspiro-20190731/spiro.c       2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/spiro.c       2020-05-05 09:46:37.000000000 +0200
@@ -22,6 +22,9 @@
 /* C implementation of third-order polynomial spirals. */
 
 #include <math.h>
+#ifdef HAVE_FINITE
+#include <float.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 
@@ -425,6 +428,18 @@
     dm[0] = 1.; dm[1] = dm[2] = 0.;
 }
 
+static void
+set_di_to_x1y1(double *di, double *dm, double x1, double y1)
+{
+    /* assume IEEE 754 rounding errors. */
+    di[3] = di[4] = x1;
+    di[6] = di[7] = y1;
+    di[3] -= di[1]; di[4] += di[1];
+    di[6] -= di[1]; di[7] += di[1];
+    di[2] = x1 * dm[0] + dm[1];
+    di[5] = y1 * dm[0] + dm[2];
+}
+
 static double
 compute_ends(const double ks[4], double ends[2][4], double seg_ch)
 {
@@ -495,11 +510,19 @@
 static spiro_seg *
 setup_path0(const spiro_cp *src, double *dm, int n)
 {
-    int i, ilast, n_seg;
+    int i, ilast, n_seg, z;
     double dx, dy;
     double xmin, xmax, ymin, ymax;
     spiro_seg *r;
 
+    z = -1;
+    if (src[n - 1].ty == 'z') z = --n;
+    if (src[0].ty == ']' || src[n - 1].ty == '[') { /* pair */
+#ifdef VERBOSE
+       fprintf(stderr, "ERROR: LibSpiro: cannot use cp type ']' as start, or 
'[' as end.\n");
+#endif
+       return 0;
+    }
     if (src[0].ty == 'h' || src[n - 1].ty == 'a') { /* pair */
 #ifdef VERBOSE
        fprintf(stderr, "ERROR: LibSpiro: cannot use cp type 'h' as start, or 
'a' as end.\n");
@@ -521,8 +544,8 @@
 #endif
 
     n_seg = src[0].ty == '{' ? n - 1 : n;
-    r = (spiro_seg *)malloc((n_seg + 1) * sizeof(spiro_seg));
-    if (r == NULL) return 0;
+    i = (int)((unsigned int)(n_seg + 1) * sizeof(spiro_seg));
+    if (i <= 0 || (r=(spiro_seg *)malloc((unsigned int)(i))) == NULL) return 0;
 
     if (dm[0] < 0.9) {
        /* for math to be scalable fit it within -0.5..+0.5 */
@@ -539,16 +562,30 @@
        dm[2] /* yoff */ = (ymin + ymax) / 2; ymax -= ymin;
        dm[0] /* scale */ = fabs((fabs(xmax) >= fabs(ymax)) ? xmax : ymax);
        if (xmax >= ymax) dm[0] = xmax; else dm[0] = ymax;
-       dm[0] /* scale */ /= 500.; /* ~ backwards compatible */
+       dm[0] /* scale */ /= 500.; /* ~ backward compatible */
     }
 #ifdef VERBOSE
-       printf("scale=%g, x_offset=%g, y_offset=%g\n", dm[0], dm[1], dm[2]);
+       printf("scale=%g, x_offset=%g, y_offset=%g, n=%d, n_seg=%d\n", dm[0], 
dm[1], dm[2], n, n_seg);
 #endif
 
     for (i = 0; i < n_seg; i++) {
+       /* gigo test: error if src[i].ty isn't a known type */
+       if (src[i].ty == 'a') {
+           if (src[i + 1].ty == 'h' || (i == n_seg-1 && src[i + 1].ty == '}'))
+               ;
+           else
+               /* did not find 'ah' (or 'a}' as last pair) */
+               goto setup_path_error1;
+       } else if (src[i].ty == 'h') {
+           if (src[i - 1].ty == 'a' || (i == 1 || src[0].ty == '{'))
+               ;
+           else
+               /* didn't find 'ah' (or '{h' as first pair) */
+               goto setup_path_error1;
+       }
+       r[i].ty = src[i].ty;
        r[i].x = (src[i].x - dm[1]) / dm[0];
        r[i].y = (src[i].y - dm[2]) / dm[0];
-       r[i].ty = src[i].ty;
        r[i].ks[0] = 0.;
        r[i].ks[1] = 0.;
        r[i].ks[2] = 0.;
@@ -579,8 +616,7 @@
            fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} hypot error.\n", 
\
                    i, src[i].ty, src[i].x, src[i].y);
 #endif
-           free(r);
-           return 0;
+           goto setup_path_error0;
        }
 #endif
        r[i].seg_th = atan2(dy, dx);
@@ -595,14 +631,29 @@
        ilast = i;
 #ifdef VERBOSE
        printf("input #%d={'%c',%g=>%g,%g=>%g}, hypot=%g, atan2=%g, 
bend_th=%g\n", \
-                   i, src[i].ty, src[i].x, r[i].x, src[i].y, r[i].y, 
r[i].seg_ch, r[i].seg_th, r[i].bend_th);
+                   i, src[i].ty, src[i].x, r[i].x * dm[0] + dm[1], \
+                   src[i].y, r[i].y * dm[0] + dm[2], r[i].seg_ch * dm[0], \
+                   r[i].seg_th, r[i].bend_th);
 #endif
     }
 #ifdef VERBOSE
     if (n_seg < n)
-       printf("input #%d={'%c',%g=>%g,%g=>%g}\n", i, src[i].ty, src[i].x, 
r[i].x, src[i].y, r[i].y);
+       printf("input #%d={'%c',%g=>%g,%g=>%g}\n", i, src[i].ty, \
+               src[i].x, r[i].x * dm[0] + dm[1], src[i].y, r[i].y * dm[0] + 
dm[2]);
 #endif
+    if (z >= 0) r[z].ty = 'z'; /* wrong n, maintain z. */
     return r;
+
+setup_path_error1:
+#ifdef VERBOSE
+    fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} found unpaired 
anchor+handle 'ah'.\n", \
+           i, src[i].ty, src[i].x, src[i].y);
+#endif
+#ifdef CHECK_INPUT_FINITENESS
+setup_path_error0:
+#endif
+    free(r);
+    return 0;
 }
 
 /* deprecated / backwards compatibility / not scalable */
@@ -707,14 +758,14 @@
        return 0;
 }
 
-static int count_vec(const spiro_seg *s, int nseg)
+static int count_vec(const spiro_seg *s, int *jinca, int nseg)
 {
     int i, n;
 
     n = 0;
 
     for (i = 0; i < nseg; i++)
-       n += compute_jinc(s[i].ty, s[i + 1].ty);
+       n += (jinca[i] = compute_jinc(s[i].ty, s[i + 1].ty));
     return n;
 }
 
@@ -741,16 +792,15 @@
 }
 
 static double
-spiro_iter(spiro_seg *s, bandmat *m, int *perm, double *v, int n, int nmat)
+spiro_iter(spiro_seg *s, bandmat *m, int *perm, double *v, int *jinca, int n, 
int cyclic, int nmat)
 {
-    int cyclic, i, j, jthl, jthr, jk0l, jk0r, jk1l, jk1r, jk2l, jk2r, jinc, 
jj, k, n_invert;
+    unsigned int l;
+    int i, j, jthl, jthr, jk0l, jk0r, jk1l, jk1r, jk2l, jk2r, jinc, jj, k, 
n_invert;
     char ty0, ty1;
     double dk, norm, th;
     double ends[2][4];
     double derivs[4][2][4];
 
-    cyclic = s[0].ty != '{' && s[0].ty != 'v';
-
     for (i = 0; i < nmat; i++) {
        v[i] = 0.;
        for (j = 0; j < 11; j++)
@@ -769,7 +819,7 @@
     for (i = 0; i < n; i++) {
        ty0 = s[i].ty;
        ty1 = s[i + 1].ty;
-       jinc = compute_jinc(ty0, ty1);
+       jinc = jinca[i];
        th = s[i].bend_th;
        jthl = jk0l = jk1l = jk2l = -1;
        jthr = jk0r = jk1r = jk2r = -1;
@@ -789,20 +839,21 @@
            }
        }
 
-       /* constraints on left */
-       if ((ty0 == '[' || ty0 == 'v' || ty0 == '{' || ty0 == 'c' || \
-            ty0 == 'a') && jinc == 4) {
-           if (ty0 != 'c')
-               jk1l = jj++;
-           jk2l = jj++;
-       }
-
-       /* constraints on right */
-       if ((ty1 == ']' || ty1 == 'v' || ty1 == '}' || ty1 == 'c' || \
-            ty1 == 'h') && jinc == 4) {
-           if (ty1 != 'c')
-               jk1r = jj++;
-           jk2r = jj++;
+       if (jinc == 4) {
+           /* constraints on left */
+           if (ty0 == 'c' || ty0 == 'v' || ty0 == '[' || \
+               ty0 == 'a' || ty0 == '{') {
+               if (ty0 != 'c')
+                   jk1l = jj++;
+               jk2l = jj++;
+           }
+           /* constraints on right */
+           if (ty1 == 'c' || ty1 == 'v' || ty1 == ']' || \
+               ty1 == 'h' || ty1 == '}') {
+               if (ty1 != 'c')
+                   jk1r = jj++;
+               jk2r = jj++;
+           }
        }
 
        /* constraints crossing right */
@@ -831,10 +882,12 @@
        j += jinc;
     }
     if (cyclic) {
-       memcpy(m + nmat, m, sizeof(bandmat) * nmat);
-       memcpy(m + 2 * nmat, m, sizeof(bandmat) * nmat);
-       memcpy(v + nmat, v, sizeof(double) * nmat);
-       memcpy(v + 2 * nmat, v, sizeof(double) * nmat);
+       l = sizeof(bandmat) * (unsigned int)(nmat);
+       memcpy(m + nmat, m, l);
+       memcpy(m + 2 * nmat, m, l);
+       l = sizeof(double) * (unsigned int)(nmat);
+       memcpy(v + nmat, v, l);
+       memcpy(v + 2 * nmat, v, l);
        n_invert = 3 * nmat;
        j = nmat;
 #ifdef VERBOSE
@@ -857,7 +910,7 @@
     banbks11(m, perm, v, n_invert);
     norm = 0.;
     for (i = 0; i < n; i++) {
-       jinc = compute_jinc(s[i].ty, s[i + 1].ty);
+       jinc = jinca[i];
 
        for (k = 0; k < jinc; k++) {
            dk = v[j++];
@@ -867,6 +920,9 @@
 #endif
            s[i].ks[k] += dk;
            norm += dk * dk;
+
+           /* Break if calculations are headed for failure */
+           if (IS_FINITE(s[i].ks[k]) == 0) return s[i].ks[k];
        }
         s[i].ks[0] = 2.0 * mod_2pi(s[i].ks[0]/2.0);
     }
@@ -874,46 +930,64 @@
 }
 
 static int
-check_finiteness(spiro_seg * segs, int num_segs)
-{
-/* Check if all values are "finite", return true=0, else return fail=-1 */
-    int i, j;
-    for (i = 0; i < num_segs; ++i)
-       for (j = 0; j < 4; ++j)
-           if ( IS_FINITE( segs[i].ks[j])==0 ) return -1;
-    return 0;
-}
-
-static int
-solve_spiro(spiro_seg *s, int nseg)
+solve_spiro(spiro_seg *s, int n)
 {
-    int i, converged, nmat, n_alloc;
+    int i, converged, cyclic, nmat, n_alloc, nseg, z;
     bandmat *m;
     double *v;
-    int *perm;
+    int *perm, *jinca;
     double norm;
 
-    nmat = count_vec(s, nseg);
-    n_alloc = nmat;
+    i = converged = 0; /* not solved (yet) */
+    z = -1;
+    if (s[0].ty == '{')
+       nseg = n - 1;
+    else {
+       if (s[n - 1].ty == 'z') {
+           z = --n;
+           s[z].ty = s[0].ty;
+       }
+       nseg = n;
+    }
+
+    if (nseg <= 1) {
+       converged = 1; /* means no convergence problems */
+       goto solve_spiroerr0;
+    }
 
-    if (nmat == 0)
-       return 1; /* just means no convergence problems */
-    if (s[0].ty != '{' && s[0].ty != 'v')
+    if ((jinca = (int *)malloc(sizeof(int) * (int)(nseg))) == NULL) {
+#ifdef VERBOSE
+       fprintf(stderr, "ERROR: LibSpiro: failed to alloc memory.\n");
+#endif
+       goto solve_spiroerr0;
+    }
+    nmat = count_vec(s, jinca, nseg);
+    if (nmat == 0) {
+       converged = 1; /* means no convergence problems */
+       goto solve_spiroerr1;
+    }
+    n_alloc = nmat;
+    cyclic = 0;
+    if (s[0].ty != '{' && s[0].ty != 'v') {
        n_alloc *= 3;
+       ++cyclic;
+    }
     if (n_alloc < 5)
        n_alloc = 5;
-    m = (bandmat *)malloc(sizeof(bandmat) * n_alloc);
-    v = (double *)malloc(sizeof(double) * n_alloc);
-    perm = (int *)malloc(sizeof(int) * n_alloc);
+#ifdef VERBOSE
+    printf("nmat=%d, alloc=%d, cyclic=%d, n=%d, nseg=%d\n", nmat, n_alloc, 
cyclic, n, nseg);
+#endif
+    m = (bandmat *)malloc(sizeof(bandmat) * (unsigned int)(n_alloc));
+    v = (double *)malloc(sizeof(double) * (unsigned int)(n_alloc));
+    perm = (int *)malloc(sizeof(int) * (unsigned int)(n_alloc));
 
-    i = converged = 0; /* not solved (yet) */
     if ( m!=NULL && v!=NULL && perm!=NULL ) {
        while (i++ < 60) {
-           norm = spiro_iter(s, m, perm, v, nseg, nmat);
+           norm = spiro_iter(s, m, perm, v, jinca, nseg, cyclic, nmat);
+           if (IS_FINITE(norm)==0) break;
 #ifdef VERBOSE
            printf("iteration #%d, %% norm = %g\n", i, norm);
 #endif
-           if (check_finiteness(s, nseg)) break;
            if (norm < 1e-12) { converged = 1; break; }
        }
 #ifdef VERBOSE
@@ -924,14 +998,18 @@
 #endif
     }
 
-    free(m);
-    free(v);
     free(perm);
+    free(v);
+    free(m);
+solve_spiroerr1:
+    free(jinca);
+solve_spiroerr0:
+    if (z >= 0) s[z].ty = 'z';
     return converged;
 }
 
 static void
-spiro_seg_to_bpath0(const double ks[4], double *dm,
+spiro_seg_to_bpath1(const double ks[4], double *dm, double *di,
                   double x0, double y0, double x1, double y1,
                   bezctx *bc, int ncq, int depth)
 {
@@ -944,13 +1022,13 @@
        fabs((1./48) * ks[3]);
 
     if (bend <= 1e-8) {
-       if (depth >= 0 || depth < -4) {
+       if (di[3] < x1 && x1 < di[4] && di[6] < y1 && y1 < di[7]) {
 #ifdef VERBOSE
            printf("...to next knot point...\n");
 #endif
-           bezctx_lineto(bc, dm[3], dm[4]);
+           bezctx_lineto(bc, di[2], di[5]);
        } else {
-           bezctx_lineto(bc, (x1 * dm[0] + dm[1]), (y1 * dm[0] + dm[2]));
+           bezctx_lineto(bc, x1 * dm[0] + dm[1], y1 * dm[0] + dm[2]);
        }
     } else {
        seg_ch = hypot(x1 - x0, y1 - y0);
@@ -961,7 +1039,7 @@
        th = atan2(xy[1], xy[0]);
        scale = seg_ch / ch;
        rot = seg_th - th;
-       if ((abs(depth) > 5 || bend < dm[5]) && ncq == 0) {
+       if (ncq == 0 && (depth > 5 || bend < di[0])) {
            /* calculate cubic, and output bezier points */
            th_even = (1./384) * ks[3] + (1./8) * ks[1] + rot;
            th_odd = (1./48) * ks[2] + .5 * ks[0];
@@ -969,13 +1047,13 @@
            vl = (scale * (1./3)) * sin(th_even - th_odd);
            ur = (scale * (1./3)) * cos(th_even + th_odd);
            vr = (scale * (1./3)) * sin(th_even + th_odd);
-           if (depth >= 0 || depth < -4) {
+           if (di[3] < x1 && x1 < di[4] && di[6] < y1 && y1 < di[7]) {
 #ifdef VERBOSE
                printf("...to next knot point...\n");
 #endif
                bezctx_curveto(bc, ((x0 + ul) * dm[0] + dm[1]), ((y0 + vl) * 
dm[0] + dm[2]),
                                ((x1 - ur) * dm[0] + dm[1]), ((y1 - vr) * dm[0] 
+ dm[2]),
-                               dm[3], dm[4]);
+                               di[2], di[5]);
            } else {
                bezctx_curveto(bc, ((x0 + ul) * dm[0] + dm[1]), ((y0 + vl) * 
dm[0] + dm[2]),
                                ((x1 - ur) * dm[0] + dm[1]), ((y1 - vr) * dm[0] 
+ dm[2]),
@@ -993,14 +1071,14 @@
            integrate_spiro(ksub, xysub, N_IS);
            xmid = x0 + cth * xysub[0] - sth * xysub[1];
            ymid = y0 + cth * xysub[1] + sth * xysub[0];
-           if (abs(depth) > 5 || bend < dm[5]) {
+           if (ncq != 0 && (depth > 5 || bend < di[0])) {
                if (ncq < 0) {
-                   /* looks like an arc if needed (use quadto output) */
-                   if (depth >= 0 || depth < -4) {
+                   /* looks like an arc (use quadto output). */
+                   if (di[3] < x1 && x1 < di[4] && di[6] < y1 && y1 < di[7]) {
 #ifdef VERBOSE
                        printf("...to next knot point...\n");
 #endif
-                       bezctx_quadto(bc, (xmid * dm[0] + dm[1]), (ymid * dm[0] 
+ dm[2]), dm[3], dm[4]);
+                       bezctx_quadto(bc, (xmid * dm[0] + dm[1]), (ymid * dm[0] 
+ dm[2]), di[2], di[5]);
                    } else {
                        bezctx_quadto(bc, (xmid * dm[0] + dm[1]), (ymid * dm[0] 
+ dm[2]), (x1 * dm[0] + dm[1]), (y1 * dm[0] + dm[2]));
                    }
@@ -1014,12 +1092,12 @@
                    vr = (scale * (1./6)) * sin(th_even + th_odd);
                    bezctx_quadto(bc, ((x0 + ul) * dm[0] + dm[1]), ((y0 + vl) * 
dm[0] + dm[2]), \
                                        (xmid * dm[0] + dm[1]), (ymid * dm[0] + 
dm[2]));
-                   if (depth >= 0 || depth < -4) {
+                   if (di[3] < x1 && x1 < di[4] && di[6] < y1 && y1 < di[7]) {
 #ifdef VERBOSE
                        printf("...to next knot point...\n");
 #endif
                        bezctx_quadto(bc, ((x1 - ur) * dm[0] + dm[1]), ((y1 - 
vr) * dm[0] + dm[2]), \
-                                           dm[3], dm[4]);
+                                           di[2], di[5]);
                    } else {
                        bezctx_quadto(bc, ((x1 - ur) * dm[0] + dm[1]), ((y1 - 
vr) * dm[0] + dm[2]), \
                                            (x1 * dm[0] + dm[1]), (y1 * dm[0] + 
dm[2]));
@@ -1029,24 +1107,27 @@
 #ifdef VERBOSE
                printf("...subdivide curve...\n");
 #endif
-               spiro_seg_to_bpath0(ksub, dm, x0, y0, xmid, ymid, bc, ncq, 
-(abs(depth) + 1));
+               spiro_seg_to_bpath1(ksub, dm, di, x0, y0, xmid, ymid, bc, ncq, 
depth + 1);
                ksub[0] += .25 * ks[1] + (1./384) * ks[3];
                ksub[1] += .125 * ks[2];
                ksub[2] += (1./16) * ks[3];
-               spiro_seg_to_bpath0(ksub, dm, xmid, ymid, x1, y1, bc, ncq, 
(depth >= 0 ? ++depth : --depth));
+               spiro_seg_to_bpath1(ksub, dm, di, xmid, ymid, x1, y1, bc, ncq, 
depth + 1);
            }
        }
     }
 }
 
+/* deprecated / keep backwards compatibility / not scalable */
 static void
 spiro_seg_to_bpath(const double ks[4],
                   double x0, double y0, double x1, double y1,
                   bezctx *bc, int depth)
 {
-    double dm[6];
-    dm[3] = x1; dm[4] = y1;
-    spiro_seg_to_bpath0(ks, dm, x0, y0, x1, y1, bc, SPIRO_RETRO_VER1, depth);
+    double di[8], dm[6];
+    set_dm_to_1(dm);
+    di[1] = 0.0005 * 500; /* assume size in range {0..1000} */
+    set_di_to_x1y1(di, dm, x1, y1);
+    spiro_seg_to_bpath1(ks, dm, di, x0, y0, x1, y1, bc, SPIRO_RETRO_VER1, 
depth);
 }
 
 /* This function reverses src path for calling application. */
@@ -1071,8 +1152,8 @@
 
     if (src[n - 1].ty == 'z') --n;
 
-    tmp = (spiro_cp *)malloc(n * sizeof(spiro_cp));
-    if (tmp == NULL) return -1;
+    i = (int)((unsigned int)(n) * sizeof(spiro_cp));
+    if ( i <= 0 || (tmp=(spiro_cp *)malloc((unsigned int)(i))) == NULL ) 
return -1;
 
 #ifdef VERBOSE
     printf("reverse n=%d values:\n",n);
@@ -1132,19 +1213,15 @@
 spiro_seg *
 run_spiro0(const spiro_cp *src, double *dm, int ncq, int n)
 {
-    int converged, nseg;
     spiro_seg *s;
 
     if (src==NULL || n <= 0 || ncq < 0) return 0;
 
-    if ( (ncq & SPIRO_RETRO_VER1) ) set_dm_to_1(dm); else dm[0] = -1.;
+    if ((ncq & SPIRO_RETRO_VER1)) set_dm_to_1(dm); else dm[0] = -1.;
 
     s = setup_path0(src, dm, n);
     if (s) {
-       nseg = src[0].ty == '{' ? n - 1 : n;
-       converged = 1 ; /* this value is for when nseg == 1; else actual value 
determined below */
-       if (nseg > 1) converged = solve_spiro(s, nseg);
-       if (converged) return s;
+       if (solve_spiro(s, n)) return s;
        free(s);
     }
     return 0;
@@ -1168,29 +1245,53 @@
 spiro_to_bpath0(const spiro_cp *src, const spiro_seg *s,
                double *dm, int ncq, int n, bezctx *bc)
 {
-    int i, j, nsegs;
-    double x0, y0, x1, y1;
+    int i, j, lk, nsegs, z;
+    double di[8], x0, y0, x1, y1;
 
+    if (s==NULL || n <= 0 || ncq < 0 || bc==NULL) return;
+
+    nsegs = n;
+    if (s[0].ty == '{') {
+       if (n >= 2 && s[n - 2].ty == 'a')
+           --nsegs;
+       --nsegs;
+       z = -1;
+    } else {
+       if (s[n - 1].ty == 'z')
+           --nsegs;
+       z = nsegs - 1;
+    }
 #ifdef VERBOSE
-    printf("spiro_to_bpath0 ncq=0x%x n=%d s=%d bc=%d\n",ncq,n,s==NULL ? 
0:1,bc==NULL ? 0:1);
+    printf("spiro_to_bpath0 ncq=0x%x n=%d nsegs=%d s=%d 
bc=%d\n",ncq,n,nsegs,s==NULL ? 0:1,bc==NULL ? 0:1);
 #endif
 
-    if (s==NULL || n <= 0 || ncq < 0 || bc==NULL) return;
+    x0 = x1 = s[0].x; y0 = y1 = s[0].y;
+    for (i = 1; i < nsegs; i++) {
+       if (s[i].ty != 'z' && s[i].ty != 'h') {
+           if (s[i].x < x0) x0 = s[i].x; else
+           if (s[i].x > x1) x1 = s[i].x;
+           if (s[i].y < y0) y0 = s[i].y; else
+           if (s[i].y > y1) y1 = s[i].y;
+       }
+    }
+    x1 -= x0; y1 -= y0;
+    di[1] = (x1 >= y1) ? x1: y1;
+    di[1] *= 0.0005;
+
+    di[0] = 1.; /* default cubic to bezier bend */
 
-    nsegs = s[n - 1].ty == '}' ? \
-           s[n - 2].ty == 'a' ? n - 2 : n - 1 : n;
-    dm[5] = 1.; /* default cubic to bezier bend */
+    lk = (ncq & SPIRO_INCLUDE_LAST_KNOT) && s[n - 1].ty == '}' ? 1 : 0;
 
     if ( (ncq &= SPIRO_ARC_CUB_QUAD_MASK)==0 ) {
        /* default action = cubic bezier output */;
     } else if (ncq == SPIRO_CUBIC_MIN_MAYBE) { /* visual inspection advised */
        ncq = 0; /* NOTE: experimental, best to look at results first */
-       dm[5] = M_PI / 2 + .000001;
+       di[0] = M_PI / 2 + .000001;
     } else if (ncq == SPIRO_ARC_MAYBE) { /* visual inspection advised */
        ncq = -1; /* NOTE: these are arcs (maybe), not quadratic */
     } else if (ncq == SPIRO_ARC_MIN_MAYBE) { /* visual inspection advised */
        ncq = -1; /* NOTE: these are arcs (maybe), not quadratic */
-       dm[5] = M_PI / 2 + .000001;
+       di[0] = M_PI / 2 + .000001;
     } else if (ncq == SPIRO_QUAD0_TO_BEZIER) {
        /* roughly approximate a cubic using two quadratic arcs. */
        ncq = 0x10;
@@ -1207,20 +1308,24 @@
            if (nsegs > 1 && s[1].ty == 'h') ++i;
        } else
            if (s[i].ty == 'a') ++i;
-       x1 = s[i + 1].x; y1 = s[i + 1].y;
+       if (i == z) {
+           x1 = s[0].x; y1 = s[0].y;
+       } else {
+           x1 = s[i + 1].x; y1 = s[i + 1].y;
+       }
+       set_di_to_x1y1(di, dm, x1, y1);
        if (src != NULL) {
-           if ((i + 1 == n && nsegs == n) || src[i].ty == 'z') {
-               dm[3] = src[0].x; dm[4] = src[0].y;
+           if (i == z) {
+               di[2] = src[0].x; di[5] = src[0].y;
            } else {
-               dm[3] = src[i + 1].x; dm[4] = src[i + 1].y;
+               di[2] = src[i + 1].x; di[5] = src[i + 1].y;
            }
-       } else {
-           dm[3] = (x1 * dm[0] + dm[1]); dm[4] = (y1 * dm[0] + dm[2]);
        }
 
        bezctx_mark_knot(bc, j);
-       spiro_seg_to_bpath0(s[i].ks, dm, x0, y0, x1, y1, bc, ncq, 0);
+       spiro_seg_to_bpath1(s[i].ks, dm, di, x0, y0, x1, y1, bc, ncq, 0);
     }
+    if (lk) bezctx_mark_knot(bc, j);
 }
 
 /* deprecated / backwards compatibility / not scalable */
@@ -1228,6 +1333,7 @@
 spiro_to_bpath(const spiro_seg *s, int n, bezctx *bc)
 {
     double dm[6];
+    set_dm_to_1(dm);
     spiro_to_bpath0(NULL, s, dm, SPIRO_RETRO_VER1, n, bc);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/spiroentrypoints.h 
new/libspiro-20200505/spiroentrypoints.h
--- old/libspiro-20190731/spiroentrypoints.h    2019-07-31 16:22:46.000000000 
+0200
+++ new/libspiro-20200505/spiroentrypoints.h    2020-05-05 09:46:37.000000000 
+0200
@@ -59,6 +59,7 @@
 #define SPIRO_HANDLE           'h'
 
 /* int ncq flags and values */
+#define SPIRO_INCLUDE_LAST_KNOT        0x0100
 #define SPIRO_RETRO_VER1       0x0400
 #define SPIRO_REVERSE_SRC      0x0800
 #define SPIRO_ARC_CUB_QUAD_CLR 0x7FFF
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/tests/Makefile.am 
new/libspiro-20200505/tests/Makefile.am
--- old/libspiro-20190731/tests/Makefile.am     2019-07-31 16:22:46.000000000 
+0200
+++ new/libspiro-20200505/tests/Makefile.am     2020-05-05 09:46:37.000000000 
+0200
@@ -7,6 +7,8 @@
 
 LDADDS = $(top_builddir)/.libs/libspiro.la
 
+EXTRA_DIST = call-test.c
+
 # The tests
 noinst_PROGRAMS = unit-test  call-test0 call-test1 call-test2 call-test3 \
                  call-test4 call-test5 call-test6 call-test7 call-test8 \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/tests/call-test.c 
new/libspiro-20200505/tests/call-test.c
--- old/libspiro-20190731/tests/call-test.c     2019-07-31 16:22:46.000000000 
+0200
+++ new/libspiro-20200505/tests/call-test.c     2020-05-05 09:46:37.000000000 
+0200
@@ -1,5 +1,5 @@
 /* Test libspiro normal library calls
-Copyright (C) 2013,2014,2015,2016,2017,2018,2019 Joe Da Silva
+Copyright (C) 2013... Joe Da Silva
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -15,7 +15,6 @@
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 02110-1301, USA.
-
 */
 
 #include <math.h>
@@ -62,7 +61,7 @@
 } rs_check_vals;
 
 rs_check_vals verify_rs0[] = {         /* iteration5 */
-    {0.000000, 65.741920, 2.027641},   /* v, 34,117 */
+    {0.000000, 65.741920, 2.027641},   /* v,334,117 */
     {0.000000, 99.020200, -2.791096},  /* v,305,176 */
     {-0.851164, 60.415230, 2.640925},  /* c,212,142 */
     {-1.847893, 92.633687, 0.793032},  /* c,159,171 */
@@ -76,7 +75,7 @@
     {-0.158341, 159.806133, -2.489331},        /* c,218,308 */
     {1.237282, 105.304321, -1.252049}, /* c, 91,211 */
     {0.982576, 108.931171, -0.269473}, /* c,124,111 */
-    {-2.528266, 243.238566, -2.797739} /* c,229, 82 */
+    {0.591223, 110.679718, 0.321751}   /* c,229, 82 */
 };                                     /* z */
 
 rs_check_vals verify_rs1[] = {         /* iteration6 */
@@ -414,8 +413,8 @@
        spiro[i].y = path6[i].y;
        spiro[i].ty = path6[i].ty;
        nextknot[i] = knot6[i];
-    } else if ( c==7 || c==8 ) for (i = 0; i < 8; i++) {
-       /* path7[]_co[7]==closed_curve, path8[]_co[8]==open_curve */
+    } else if ( c==7 || c==8 || c==21 ) for (i = 0; i < 8; i++) {
+       /* path7[] is closed curve, path{8,21}[] are open curves. */
        spiro[i].x = path7[i].x;
        spiro[i].y = path7[i].y;
        spiro[i].ty = path7[i].ty;
@@ -479,7 +478,7 @@
        spiro[i].y = path0[i].y;
        spiro[i].ty = path0[i].ty;
        nextknot[i] = knot0[i];
-    } else if ( c==20 || c==21 || c==22) for (i = 0; i < 9; i++) {
+    } else if ( c==20 || c==22) for (i = 0; i < 9; i++) {
        /* path20[]=closed, path21[]=open, path22[]=closed_with_z */
        spiro[i].x = path7[i].x;
        spiro[i].y = path7[i].y;
@@ -536,7 +535,7 @@
 int test_curve(int c) {
     spiro_cp spiro[16];
     int nextknot[17];
-    double d[5];
+    double d[6];
     spiro_seg *segs = NULL;
     bezctx *bc;
     rs_check_vals *rsp;
@@ -545,7 +544,7 @@
     /* Load sample data so that we can see if library is callable */
     load_test_curve(spiro,nextknot,c);
 
-    d[0] = 1.; d[1] = d[1] = 0.;
+    d[0] = 1.; d[1] = d[2] = 0.;
 #if defined(DO_CALL_TEST20)
     /* check if spiro values are reversed correctly on input path */
     printf("---\ntesting spiroreverse() using data=path%d[].\n",c);
@@ -725,6 +724,27 @@
        fprintf(stderr,"error with SpiroCPsToBezier1() using 
data=path%d[].\n",c);
        return -6;
     }
+#if defined(DO_CALL_TEST13)
+    /* Check if SpiroCPsToBezier2() works okay */
+    printf("---\ntesting SpiroCPsToBezier2() using data=path%d[].\n",c);
+    if ( SpiroCPsToBezier2(spiro,cl[c],SPIRO_INCLUDE_LAST_KNOT,co[c],bc)!=1 ) {
+       fprintf(stderr,"error with SpiroCPsToBezier2() using 
data=path%d[].\n",c);
+       return -6;
+    }
+#endif
+#else
+    /* Check if SpiroCPsToBezier2() works okay */
+    printf("---\ntesting SpiroCPsToBezier2() using data=path%d[].\n",c);
+    if ( SpiroCPsToBezier2(spiro,cl[c],SPIRO_INCLUDE_LAST_KNOT,co[c],bc)!=1 ) {
+       fprintf(stderr,"error with SpiroCPsToBezier2() using 
data=path%d[].\n",c);
+       return -6;
+    }
+    /* Check if TaggedSpiroCPsToBezier2() works okay */
+    printf("---\ntesting TaggedSpiroCPsToBezier2() using data=path%d[].\n",c);
+    if ( TaggedSpiroCPsToBezier2(spiro,SPIRO_INCLUDE_LAST_KNOT,bc)!=1 ) {
+       fprintf(stderr,"error with TaggedSpiroCPsToBezier2() using 
data=path%d[].\n",c);
+       return -6;
+    }
 #endif
 #endif
 
@@ -733,6 +753,7 @@
     /* Some reversed paths (above) will fail (like path20), so we */
     /* reverse the reversed spiro path so we can use current test */
     /* functions & values (so that this actually tests something) */
+    bc = new_bezctx_test();
     if (c == 20 || c == 21) {
        /* Check if SpiroCPsToBezier2() works okay */
        printf("---\ntesting SpiroCPsToBezier2(reverse) using 
data=path%d[].\n",c);
@@ -747,6 +768,14 @@
            fprintf(stderr,"error with TaggedSpiroCPsToBezier2(reverse) using 
data=path%d[].\n",c);
            return -10;
        }
+       if (c == 24) {
+           /* reverse it again, ends in v, visually check end points */
+           printf("---\ntesting TaggedSpiroCPsToBezier2(reverse) using 
data=path%d[].\n",c);
+           if ( 
TaggedSpiroCPsToBezier2(spiro,SPIRO_REVERSE_SRC|SPIRO_INCLUDE_LAST_KNOT,bc)!=1 
) {
+               fprintf(stderr,"error with TaggedSpiroCPsToBezier2(reverse) 
using data=path%d[].\n",c);
+               return -10;
+           }
+       }
     }
 #endif
 
@@ -1161,8 +1190,6 @@
     ret = 0; /* ignore result for now until improved. */
 #endif
 #ifdef DO_CALL_TEST12
-    /* TODO: knot counts not matched for taggedspiro, */
-    /* therefore use !defined(DO_CALL_TEST12) for now */
     ret=test_curve(12);        /* do path7[] with a z ending */
 #endif
 #ifdef DO_CALL_TEST13
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/tests/unit-test.c 
new/libspiro-20200505/tests/unit-test.c
--- old/libspiro-20190731/tests/unit-test.c     2019-07-31 16:22:46.000000000 
+0200
+++ new/libspiro-20200505/tests/unit-test.c     2020-05-05 09:46:37.000000000 
+0200
@@ -56,7 +56,6 @@
     double ks[] = {1, 2, 3, 4};
     double xy[2];
     double xynom[2];
-    double ch, th;
     int i, j;
     int nsubdiv;
 
@@ -64,22 +63,28 @@
     integrate_spiro(ks, xynom, n);
     nsubdiv = ORDER < 12 ? 8 : 7;
     for (i = 0; i < nsubdiv; i++) {
-       double st, en;
-       double err;
+#ifdef VERBOSE
+       double ch, th;
+       double st, en, err;
+#endif
        int n_iter = (1 << (20 - i));
 
        n = 1 << i;
+#ifndef VERBOSE
+       for (j = 0; j < n_iter; j++)
+           integrate_spiro(ks, xy, n);
+#else
        st = get_time();
        for (j = 0; j < n_iter; j++)
            integrate_spiro(ks, xy, n);
        en = get_time();
+
        err = hypot(xy[0] - xynom[0], xy[1] - xynom[1]);
-#ifdef VERBOSE
        printf("%d %d %g %g\n", ORDER, n, (en - st) / n_iter, err);
-#endif
+
        ch = hypot(xy[0], xy[1]);
        th = atan2(xy[1], xy[0]);
-#if 0
+
        printf("n = %d: integ(%g %g %g %g) = %g %g, ch = %g, th = %g\n", n,
               ks[0], ks[1], ks[2], ks[3], xy[0], xy[1], ch, th);
        printf("%d: %g %g\n", n, xy[0] - xynom[0], xy[1] - xynom[1]);
@@ -94,8 +99,9 @@
 
     if (bend < 1e-8) {
 #ifdef VERBOSE
-       printf("%g %g lineto\n", x1, y1);
+       printf("%g %g lineto\n", x1, y1)
 #endif
+       ;
     } else {
        double seg_ch = hypot(x1 - x0, y1 - y0);
        double seg_th = atan2(y1 - y0, x1 - x0);
@@ -103,8 +109,9 @@
        double ch, th;
        double scale, rot;
        double th_even, th_odd;
-       double ul, vl;
-       double ur, vr;
+#ifdef VERBOSE
+       double ul, vl, ur, vr;
+#endif
 
        integrate_spiro(ks, xy, n);
        ch = hypot(xy[0], xy[1]);
@@ -114,11 +121,11 @@
        if (bend < 1.) {
            th_even = (1./384) * ks[3] + (1./8) * ks[1] + rot;
            th_odd = (1./48) * ks[2] + .5 * ks[0];
+#ifdef VERBOSE
            ul = (scale * (1./3)) * cos(th_even - th_odd);
            vl = (scale * (1./3)) * sin(th_even - th_odd);
            ur = (scale * (1./3)) * cos(th_even + th_odd);
            vr = (scale * (1./3)) * sin(th_even + th_odd);
-#ifdef VERBOSE
            printf("%g %g %g %g %g %g curveto\n",
                   x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1);
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libspiro-20190731/zmisc.h 
new/libspiro-20200505/zmisc.h
--- old/libspiro-20190731/zmisc.h       2019-07-31 16:22:46.000000000 +0200
+++ new/libspiro-20200505/zmisc.h       1970-01-01 01:00:00.000000000 +0100
@@ -1,15 +0,0 @@
-#ifndef _ZMISC_H
-# define _ZMISC_H
-/**
- * Misc portability and convenience macros.
- **/
-
-#include <stdlib.h>
-
-#define zalloc malloc
-#define zrealloc realloc
-#define zfree free
-
-#define znew(type, n) (type *)zalloc(sizeof(type) * (n))
-#define zrenew(type, p, n) (type *)zrealloc((p), sizeof(type) * (n))
-#endif


Reply via email to