]> TLD Linux GIT Repositories - packages/rpm.git/commitdiff
- backport shrink support for macros
authorMarcin Krol <hawk@tld-linux.org>
Thu, 19 Oct 2017 23:25:36 +0000 (23:25 +0000)
committerMarcin Krol <hawk@tld-linux.org>
Thu, 19 Oct 2017 23:25:36 +0000 (23:25 +0000)
rpm-shrink.patch [new file with mode: 0644]
rpm.spec

diff --git a/rpm-shrink.patch b/rpm-shrink.patch
new file mode 100644 (file)
index 0000000..4c02b61
--- /dev/null
@@ -0,0 +1,623 @@
+diff -urNp rpm-4.5.orig/rpmio/macro.c rpm-4.5/rpmio/macro.c
+--- rpm-4.5.orig/rpmio/macro.c 2017-10-19 22:48:49.000000000 +0000
++++ rpm-4.5/rpmio/macro.c      2017-10-19 23:16:34.301644733 +0000
+@@ -71,6 +71,7 @@ const char * rpmMacrofiles = MACROFILES;
+ #endif
+ #include <rpmmacro.h>
++#include <rpmstring.h>
+ #include "debug.h"
+@@ -1200,6 +1201,28 @@ doFoo(MacroBuf mb, int negate, const cha
+       if ((b = strrchr(buf, '/')) != NULL)
+           *b = '\0';
+       b = buf;
++    } else if (STREQ("shrink", f, fn)) {
++      /*
++       * shrink body by removing all leading and trailing whitespaces and
++       * reducing intermediate whitespaces to a single space character.
++       */
++      size_t i = 0, j = 0;
++      size_t buflen = strlen(buf);
++      int was_space = 0;
++      while (i < buflen) {
++          if (risspace(buf[i])) {
++              was_space = 1;
++              i++;
++              continue;
++          } else if (was_space) {
++              was_space = 0;
++              if (j > 0) /* remove leading blanks at all */
++                  buf[j++] = ' ';
++          }
++          buf[j++] = buf[i++];
++      }
++      buf[j] = '\0';
++      b = buf;
+     } else if (STREQ("suffix", f, fn)) {
+       if ((b = strrchr(buf, '.')) != NULL)
+           b++;
+@@ -1549,6 +1572,7 @@ expandMacro(MacroBuf mb)
+       /* XXX necessary but clunky */
+       if (STREQ("basename", f, fn) ||
+           STREQ("dirname", f, fn) ||
++          STREQ("shrink", f, fn) ||
+           STREQ("suffix", f, fn) ||
+           STREQ("expand", f, fn) ||
+           STREQ("verbose", f, fn) ||
+diff -urNp rpm-4.5.orig/rpmio/Makefile.am rpm-4.5/rpmio/Makefile.am
+--- rpm-4.5.orig/rpmio/Makefile.am     2017-10-19 22:48:49.000000000 +0000
++++ rpm-4.5/rpmio/Makefile.am  2017-10-19 23:16:15.212645871 +0000
+@@ -37,7 +37,7 @@ librpmio_la_SOURCES = \
+       md2.c md4.c rmd128.c rmd160.c rmd256.c rmd320.c sha224.c \
+       salsa10.c salsa20.c tiger.c \
+       rpmdav.c rpmhash.c rpmhook.c rpmio.c rpmlog.c rpmlua.c rpmmalloc.c \
+-      rpmpgp.c rpmrpc.c rpmsq.c rpmsw.c strcasecmp.c strtolocale.c \
++      rpmpgp.c rpmrpc.c rpmsq.c rpmstring.c rpmsw.c strcasecmp.c strtolocale.c \
+       stubs.c url.c ugid.c rpmuuid.c
+ librpmio_la_LDFLAGS = -no-undefined -release $(LT_CURRENT).$(LT_REVISION) $(LDFLAGS) \
+       @WITH_BEECRYPT_LIB@ \
+diff -urNp rpm-4.5.orig/rpmio/Makefile.in rpm-4.5/rpmio/Makefile.in
+--- rpm-4.5.orig/rpmio/Makefile.in     2008-07-09 09:41:32.000000000 +0000
++++ rpm-4.5/rpmio/Makefile.in  2017-10-19 23:16:15.212645871 +0000
+@@ -68,7 +68,7 @@ am_librpmio_la_OBJECTS = argv.lo digest.
+       macro.lo mire.lo md2.lo md4.lo rmd128.lo rmd160.lo rmd256.lo \
+       rmd320.lo sha224.lo salsa10.lo salsa20.lo tiger.lo rpmdav.lo \
+       rpmhash.lo rpmhook.lo rpmio.lo rpmlog.lo rpmlua.lo \
+-      rpmmalloc.lo rpmpgp.lo rpmrpc.lo rpmsq.lo rpmsw.lo \
++      rpmmalloc.lo rpmpgp.lo rpmrpc.lo rpmsq.lo rpmstring.lo rpmsw.lo \
+       strcasecmp.lo strtolocale.lo stubs.lo url.lo ugid.lo \
+       rpmuuid.lo
+ librpmio_la_OBJECTS = $(am_librpmio_la_OBJECTS)
+diff -urNp rpm-4.5.orig/rpmio/rpmstring.c rpm-4.5/rpmio/rpmstring.c
+--- rpm-4.5.orig/rpmio/rpmstring.c     1970-01-01 00:00:00.000000000 +0000
++++ rpm-4.5/rpmio/rpmstring.c  2017-10-19 23:16:15.212645871 +0000
+@@ -0,0 +1,192 @@
++/**
++ * \file rpmio/rpmstring.c
++ */
++
++#include "system.h"
++
++#include <stdarg.h>
++#include <stdio.h>
++
++#include <rpmio/rpmstring.h>
++#include "debug.h"
++
++
++int rstrcasecmp(const char * s1, const char * s2)
++{
++  const char * p1 = s1;
++  const char * p2 = s2;
++  char c1, c2;
++
++  if (p1 == p2)
++    return 0;
++
++  do
++    {
++      c1 = rtolower (*p1++);
++      c2 = rtolower (*p2++);
++      if (c1 == '\0')
++        break;
++    }
++  while (c1 == c2);
++
++  return (int)(c1 - c2);
++}
++
++int rstrncasecmp(const char *s1, const char *s2, size_t n)
++{
++  const char * p1 = s1;
++  const char * p2 = s2;
++  char c1, c2;
++
++  if (p1 == p2 || n == 0)
++    return 0;
++
++  do
++    {
++      c1 = rtolower (*p1++);
++      c2 = rtolower (*p2++);
++      if (c1 == '\0' || c1 != c2)
++      break;
++    } while (--n > 0);
++
++  return (int)(c1 - c2);
++}
++
++/* 
++ * Simple and stupid asprintf() clone.
++ * FIXME: write to work with non-C99 vsnprintf or check for one in configure.
++ */
++int rasprintf(char **strp, const char *fmt, ...)
++{
++    int n;
++    va_list ap;
++    char * p = NULL;
++  
++    if (strp == NULL) 
++      return -1;
++
++    va_start(ap, fmt);
++    n = vsnprintf(NULL, 0, fmt, ap);
++    va_end(ap);
++
++    if (n >= -1) {
++      size_t nb = n + 1;
++      p = xmalloc(nb);
++      va_start(ap, fmt);
++        n = vsnprintf(p, nb, fmt, ap);
++      va_end(ap);
++    } 
++    *strp = p;
++    return n;
++}
++
++/*
++ * Concatenate two strings with dynamically (re)allocated
++ * memory what prevents static buffer overflows by design.
++ * *dest is reallocated to the size of strings to concatenate.
++ *
++ * Note:
++ * 1) char *buf = rstrcat(NULL,"string"); is the same like rstrcat(&buf,"string");
++ * 2) rstrcat(&buf,NULL) returns buf
++ * 3) rstrcat(NULL,NULL) returns NULL
++ * 4) *dest and src can overlap
++ */
++char *rstrcat(char **dest, const char *src)
++{
++    if ( src == NULL ) {
++      return dest != NULL ? *dest : NULL;
++    }
++
++    if ( dest == NULL ) {
++      return xstrdup(src);
++    }
++
++    {
++      size_t dest_size = *dest != NULL ? strlen(*dest) : 0;
++      size_t src_size = strlen(src);
++
++      *dest = xrealloc(*dest, dest_size+src_size+1);          /* include '\0' */
++      memmove(&(*dest)[dest_size], src, src_size+1);
++    }
++
++    return *dest;
++}
++
++/*
++ * Concatenate strings with dynamically (re)allocated
++ * memory what prevents static buffer overflows by design.
++ * *dest is reallocated to the size of strings to concatenate.
++ * List of strings has to be NULL terminated.
++ *
++ * Note:
++ * 1) char *buf = rstrscat(NULL,"string",NULL); is the same like rstrscat(&buf,"string",NULL);
++ * 2) rstrscat(&buf,NULL) returns buf
++ * 3) rstrscat(NULL,NULL) returns NULL
++ * 4) *dest and argument strings can overlap
++ */
++char *rstrscat(char **dest, const char *arg, ...)
++{
++    va_list ap;
++    size_t arg_size, dst_size;
++    const char *s;
++    char *dst, *p;
++
++    dst = dest ? *dest : NULL;
++
++    if ( arg == NULL ) {
++        return dst;
++    }
++
++    va_start(ap, arg);
++    for (arg_size=0, s=arg; s; s = va_arg(ap, const char *))
++        arg_size += strlen(s);
++    va_end(ap);
++
++    dst_size = dst ? strlen(dst) : 0;
++    dst = xrealloc(dst, dst_size+arg_size+1);    /* include '\0' */
++    p = &dst[dst_size];
++
++    va_start(ap, arg);
++    for (s = arg; s; s = va_arg(ap, const char *)) {
++        size_t size = strlen(s);
++        memmove(p, s, size);
++        p += size;
++    }
++    va_end(ap);
++    *p = '\0';
++
++    if ( dest ) {
++        *dest = dst;
++    }
++
++    return dst;
++}
++
++/*
++ * Adapted from OpenBSD, strlcpy() originally developed by
++ * Todd C. Miller <Todd.Miller@courtesan.com>
++ */
++size_t rstrlcpy(char *dest, const char *src, size_t n)
++{
++    char *d = dest;
++    const char *s = src;
++    size_t len = n;
++
++    /* Copy as many bytes as will fit */
++    if (len != 0) {
++      while (--len != 0) {
++          if ((*d++ = *s++) == '\0')
++              break;
++      }
++    }
++
++    /* Not enough room in dst, add NUL and traverse rest of src */
++    if (len == 0) {
++      if (n != 0)
++          *d = '\0'; /* NUL-terminate dst */
++      while (*s++)
++          ;
++    }
++
++    return s - src - 1; /* count does not include NUL */
++}
+diff -urNp rpm-4.5.orig/rpmio/rpmstring.h rpm-4.5/rpmio/rpmstring.h
+--- rpm-4.5.orig/rpmio/rpmstring.h     1970-01-01 00:00:00.000000000 +0000
++++ rpm-4.5/rpmio/rpmstring.h  2017-10-19 23:16:15.212645871 +0000
+@@ -0,0 +1,187 @@
++#ifndef _RPMSTRING_H_
++#define _RPMSTRING_H_
++
++/** \ingroup rpmstring
++ * \file rpmio/rpmstring.h
++ * String manipulation helper functions
++ */
++
++#include <stddef.h>
++#include <string.h>
++
++#include <rpmio/rpmutil.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** \ingroup rpmstring
++ * Locale insensitive islower(3) 
++ */
++RPM_GNUC_CONST
++static inline int rislower(int c)  {
++    return (c >= 'a' && c <= 'z');
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isupper(3)
++ */
++RPM_GNUC_CONST
++static inline int risupper(int c)  {
++    return (c >= 'A' && c <= 'Z');
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isalpha(3)
++ */
++RPM_GNUC_CONST
++static inline int risalpha(int c)  {
++    return (rislower(c) || risupper(c));
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isdigit(3)
++ */
++RPM_GNUC_CONST
++static inline int risdigit(int c)  {
++    return (c >= '0' && c <= '9');
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isalnum(3)
++ */
++RPM_GNUC_CONST
++static inline int risalnum(int c)  {
++    return (risalpha(c) || risdigit(c));
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isblank(3)
++ */
++RPM_GNUC_CONST
++static inline int risblank(int c)  {
++    return (c == ' ' || c == '\t');
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive isspace(3)
++ */
++RPM_GNUC_CONST
++static inline int risspace(int c)  {
++    return (risblank(c) || c == '\n' || c == '\r' || c == '\f' || c == '\v');
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive tolower(3)
++ */
++RPM_GNUC_CONST
++static inline int rtolower(int c)  {
++    return ((risupper(c)) ? (c | ('a' - 'A')) : c);
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive toupper(3)
++ */
++RPM_GNUC_CONST
++static inline int rtoupper(int c)  {
++    return ((rislower(c)) ? (c & ~('a' - 'A')) : c);
++}
++
++/**
++ * Convert hex to binary nibble.
++ * @param c            hex character
++ * @return             binary nibble
++ */
++RPM_GNUC_CONST
++static inline unsigned char rnibble(char c)
++{
++    if (c >= '0' && c <= '9')
++      return (c - '0');
++    if (c >= 'a' && c <= 'f')
++      return (c - 'a') + 10;
++    if (c >= 'A' && c <= 'F')
++      return (c - 'A') + 10;
++    return 0;
++}
++
++/**
++ * Test for string equality
++ * @param s1          string 1
++ * @param s2          string 2
++ * @return            0 if strings differ, 1 if equal
++ */
++static inline int rstreq(const char *s1, const char *s2)
++{
++    return (strcmp(s1, s2) == 0);
++}
++
++/**
++ * Test for string equality
++ * @param s1          string 1
++ * @param s2          string 2
++ * @param n           compare at most n characters
++ * @return            0 if strings differ, 1 if equal
++ */
++static inline int rstreqn(const char *s1, const char *s2, size_t n)
++{
++    return (strncmp(s1, s2, n) == 0);
++}
++
++/** \ingroup rpmstring
++ * Locale insensitive strcasecmp(3).
++ */
++RPM_GNUC_PURE
++int rstrcasecmp(const char * s1, const char * s2)             ;
++
++/** \ingroup rpmstring
++ * Locale insensitive strncasecmp(3).
++ */
++RPM_GNUC_PURE
++int rstrncasecmp(const char *s1, const char * s2, size_t n)   ;
++
++/** \ingroup rpmstring
++ * asprintf() clone
++ */
++int rasprintf(char **strp, const char *fmt, ...) RPM_GNUC_PRINTF(2, 3);
++
++/** \ingroup rpmstring
++ * Concatenate two strings with dynamically (re)allocated memory.
++ * @param dest                pointer to destination string
++ * @param src         source string
++ * @return            realloc'd dest with src appended
++ */
++char *rstrcat(char **dest, const char *src);
++
++/** \ingroup rpmstring
++ * Concatenate multiple strings with dynamically (re)allocated memory.
++ * @param dest                pointer to destination string
++ * @param arg         NULL terminated list of strings to concatenate
++ * @return            realloc'd dest with strings appended
++ */
++char *rstrscat(char **dest, const char *arg, ...) RPM_GNUC_NULL_TERMINATED;
++
++/** \ingroup rpmstring
++ * strlcpy() clone: 
++ * Copy src to string dest of size n. At most n-1 characters
++ * will be copied.  Always zero-terminates (unless n == 0).
++ * Length of src is returned; if retval >= n, truncation occurred.
++ * @param dest                destination buffer
++ * @param src         string to copy
++ * @param n           destination buffer size
++ * @return            length of src string
++ */
++size_t rstrlcpy(char *dest, const char *src, size_t n);
++
++/** \ingroup rpmstring
++ * String hashing function
++ * @param string      string to hash
++ * @return            hash id
++ */
++RPM_GNUC_PURE
++unsigned int rstrhash(const char * string);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif        /* _RPMSTRING_H_ */
+diff -urNp rpm-4.5.orig/rpmio/rpmutil.h rpm-4.5/rpmio/rpmutil.h
+--- rpm-4.5.orig/rpmio/rpmutil.h       1970-01-01 00:00:00.000000000 +0000
++++ rpm-4.5/rpmio/rpmutil.h    2017-10-19 23:16:15.213645871 +0000
+@@ -0,0 +1,160 @@
++#ifndef _RPMUTIL_H
++#define _RPMUTIL_H
++
++#include <unistd.h>
++
++/** \file rpmio/rpmutil.h
++ *
++ * Miscellaneous utility macros:
++ * - portability wrappers for various gcc extensions like __attribute__()
++ * - ...
++ *
++ * Copied from glib, names replaced to avoid clashing with glib.
++ *
++ */
++
++/* Here we provide RPM_GNUC_EXTENSION as an alias for __extension__,
++ * where this is valid. This allows for warningless compilation of
++ * "long long" types even in the presence of '-ansi -pedantic'. 
++ */
++#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
++#  define RPM_GNUC_EXTENSION __extension__
++#else
++#  define RPM_GNUC_EXTENSION
++#endif
++
++/* Provide macros to feature the GCC function attribute.
++ */
++#if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
++#define RPM_GNUC_PURE                            \
++  __attribute__((__pure__))
++#define RPM_GNUC_MALLOC                       \
++  __attribute__((__malloc__))
++#else
++#define RPM_GNUC_PURE
++#define RPM_GNUC_MALLOC
++#endif
++
++#if     (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
++#define RPM_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
++#define RPM_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))
++#else
++#define RPM_GNUC_ALLOC_SIZE(x)
++#define RPM_GNUC_ALLOC_SIZE2(x,y)
++#endif
++
++#if     __GNUC__ >= 4
++#define RPM_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
++#else
++#define RPM_GNUC_NULL_TERMINATED
++#endif
++
++#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
++#define RPM_GNUC_PRINTF( format_idx, arg_idx )    \
++  __attribute__((__format__ (__printf__, format_idx, arg_idx)))
++#define RPM_GNUC_SCANF( format_idx, arg_idx )     \
++  __attribute__((__format__ (__scanf__, format_idx, arg_idx)))
++#define RPM_GNUC_FORMAT( arg_idx )                \
++  __attribute__((__format_arg__ (arg_idx)))
++#define RPM_GNUC_NORETURN                         \
++  __attribute__((__noreturn__))
++#define RPM_GNUC_CONST                            \
++  __attribute__((__const__))
++#define RPM_GNUC_UNUSED                           \
++  __attribute__((__unused__))
++#define RPM_GNUC_NO_INSTRUMENT                        \
++  __attribute__((__no_instrument_function__))
++#else   /* !__GNUC__ */
++#define RPM_GNUC_PRINTF( format_idx, arg_idx )
++#define RPM_GNUC_SCANF( format_idx, arg_idx )
++#define RPM_GNUC_FORMAT( arg_idx )
++#define RPM_GNUC_NORETURN
++#define RPM_GNUC_CONST
++#define RPM_GNUC_UNUSED
++#define RPM_GNUC_NO_INSTRUMENT
++#endif  /* !__GNUC__ */
++
++#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
++#define RPM_GNUC_DEPRECATED                            \
++  __attribute__((__deprecated__))
++#else
++#define RPM_GNUC_DEPRECATED
++#endif /* __GNUC__ */
++
++#if     __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
++#define RPM_GNUC_MAY_ALIAS __attribute__((may_alias))
++#define RPM_GNUC_NONNULL( ... )       \
++  __attribute__((__nonnull__ (__VA_ARGS__)))
++#else
++#define RPM_GNUC_MAY_ALIAS
++#define RPM_GNUC_NONNULL( ... )
++#endif
++
++#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
++#define RPM_GNUC_WARN_UNUSED_RESULT           \
++  __attribute__((warn_unused_result))
++#else
++#define RPM_GNUC_WARN_UNUSED_RESULT
++#endif /* __GNUC__ */
++
++#if    __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
++#  define RPM_GNUC_INTERNAL __attribute__((visibility("hidden")))
++#else
++#  define RPM_GNUC_INTERNAL
++#endif
++
++
++/* Guard C code in headers, while including them from C++ */
++#ifdef  __cplusplus
++# define RPM_BEGIN_DECLS  extern "C" {
++# define RPM_END_DECLS    }
++#else
++# define RPM_BEGIN_DECLS
++# define RPM_END_DECLS
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Rpm specific allocators which never return NULL but terminate on failure */
++RPM_GNUC_MALLOC RPM_GNUC_ALLOC_SIZE(1)
++void * rmalloc(size_t size);
++
++RPM_GNUC_MALLOC RPM_GNUC_ALLOC_SIZE2(1,2)
++void * rcalloc(size_t nmemb, size_t size);
++
++RPM_GNUC_ALLOC_SIZE(2)
++void * rrealloc(void *ptr, size_t size);
++
++char * rstrdup(const char *str);
++
++/* Rpm specific free() which returns NULL */
++void * rfree(void *ptr);
++
++/** \ingroup rpmutil
++ * Memory allocation failure callback prototype. When registered through
++ * rpmSetMemFail(), this gets called if memory allocation through rmalloc()
++ * and friends fails. If the application can somehow recover memory here,
++ * it can return a newly allocated memory block of requested size, otherwise
++ * it must return NULL after performing it's own shutdown deeds or 
++ * terminate itself.
++ * @param size                Size of allocation request in bytes
++ * @param data                User data (or NULL)
++ * @return            Allocated memory block of requested size or NULL
++ */
++typedef void * (*rpmMemFailFunc) (size_t size, void *data);
++
++/** \ingroup rpmutil
++ * Set memory allocation failure callback.
++ * @param func                Allocation failure callback function
++ * @param data                User data (or NULL)
++ * @return            Previous callback function
++ */
++rpmMemFailFunc rpmSetMemFail(rpmMemFailFunc func, void *data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _RPMUTIL_H */
index 328213756d5ce2974847db96fdde2c2cbd120f2d..3a56c79770aedabddfbdf22781fdd4665660944d 100644 (file)
--- a/rpm.spec
+++ b/rpm.spec
@@ -42,7 +42,7 @@ Summary(ru.UTF-8):    Менеджер пакетов от RPM
 Summary(uk.UTF-8):     Менеджер пакетів від RPM
 Name:          rpm
 Version:       4.5
-Release:       79
+Release:       80
 License:       LGPL
 Group:         Base
 Source0:       %{name}-%{version}.tar.gz
@@ -168,6 +168,7 @@ Patch107:   %{name}-debugedit-dwarf4.patch
 Patch108:      %{name}-changelog_order_check_nonfatal.patch
 Patch109:      %{name}-installplatform.patch
 Patch110:      %{name}-xz.patch
+Patch111:      %{name}-shrink.patch
 URL:           http://rpm5.org/
 BuildRequires: autoconf >= 2.57
 BuildRequires: automake >= 1.4
@@ -788,6 +789,7 @@ install %{SOURCE13} scripts/perl.prov
 %patch108 -p1
 %patch109 -p1
 %patch110 -p1
+%patch111 -p1
 
 mv -f po/{sr,sr@Latn}.po
 rm -rf sqlite zlib popt