summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2010-03-10 13:24:58 +0100
committerWerner Koch <wk@gnupg.org>2010-03-10 13:24:58 +0100
commitd8b1099d01ebc1d305d47ec6dcb326980ad56396 (patch)
treecb92563d8b116872c34ad26dcdacfd02ed3da04a /common
parentFix for latest libgpg-error. (diff)
downloadgnupg2-d8b1099d01ebc1d305d47ec6dcb326980ad56396.tar.xz
gnupg2-d8b1099d01ebc1d305d47ec6dcb326980ad56396.zip
Merged jnlib into common.
Diffstat (limited to 'common')
-rw-r--r--common/ChangeLog27
-rw-r--r--common/ChangeLog.jnlib769
-rw-r--r--common/Makefile.am54
-rw-r--r--common/README.jnlib101
-rw-r--r--common/argparse.c1205
-rw-r--r--common/argparse.h183
-rw-r--r--common/audit.h2
-rw-r--r--common/dotlock.c713
-rw-r--r--common/dotlock.h33
-rw-r--r--common/dynload.h86
-rw-r--r--common/exechelp.c10
-rw-r--r--common/exechelp.h2
-rw-r--r--common/http.h2
-rw-r--r--common/i18n.h2
-rw-r--r--common/init.c1
-rw-r--r--common/iobuf.c4
-rw-r--r--common/libjnlib-config.h99
-rw-r--r--common/localename.c4
-rw-r--r--common/logging.c651
-rw-r--r--common/logging.h88
-rw-r--r--common/mischelp.c197
-rw-r--r--common/mischelp.h102
-rw-r--r--common/simple-pwquery.c4
-rw-r--r--common/simple-pwquery.h2
-rw-r--r--common/stringhelp.c1151
-rw-r--r--common/stringhelp.h136
-rw-r--r--common/strlist.c204
-rw-r--r--common/strlist.h50
-rw-r--r--common/sysutils.h2
-rw-r--r--common/t-stringhelp.c414
-rw-r--r--common/t-support.c147
-rw-r--r--common/t-support.h60
-rw-r--r--common/t-timestuff.c145
-rw-r--r--common/t-w32-reg.c70
-rw-r--r--common/ttyio.c1
-rw-r--r--common/types.h114
-rw-r--r--common/utf8conv.c813
-rw-r--r--common/utf8conv.h45
-rw-r--r--common/util.h27
-rw-r--r--common/w32-afunix.c138
-rw-r--r--common/w32-afunix.h52
-rw-r--r--common/w32-reg.c312
-rw-r--r--common/w32help.h32
-rw-r--r--common/xasprintf.c1
-rw-r--r--common/xmalloc.c87
-rw-r--r--common/xmalloc.h30
46 files changed, 8335 insertions, 37 deletions
diff --git a/common/ChangeLog b/common/ChangeLog
index 7408123ec..6f4b70b30 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,5 +1,32 @@
+2010-03-10 Werner Koch <wk@g10code.com>
+
+ * util.h: Replace jnlib path part by common.
+ (snprintf): Use the replacement macro on all platforms.
+
+ * Makefile.am (jnlib_sources): New.
+ (libcommon_a_SOURCES, libcommonpth_a_SOURCES): Add jnlib_sources.
+ (jnlib_tests): New.
+ (noinst_PROGRAMS, TESTS): Add jnlib_tests.
+ (t_common_ldadd): Remove libjnlib.a.
+
+ * README.jnlib, ChangeLog.jnlib, libjnlib-config.h, argparse.c
+ * argparse.h, dotlock.c, dotlock.h, dynload.h, logging.c
+ * logging.h, mischelp.c, mischelp.h, stringhelp.c, stringhelp.h
+ * strlist.c, strlist.h, types.h, utf8conv.c, utf8conv.h
+ * w32-afunix.c, w32-afunix.h, w32-reg.c, w32help.h, xmalloc.c
+ * xmalloc.h, t-stringhelp.c, t-support.c, t-support.h
+ * t-timestuff.c, t-w32-reg.c: Move from jnlib to here.
+
+ * init.c: Remove "estream.h".
+ * util.h: Include "estream.h".
+
+ * xasprintf.c, ttyio.c: Remove "estream-printf.h".
+
2010-03-08 Werner Koch <wk@g10code.com>
+ * exechelp.c [!HAVE_SIGNAL_H]: Do not include signal.h.
+ (DETACHED_PROCESS, CREATE_NEW_PROCESS_GROUP) [W32CE]: Provide stubs.
+
* iobuf.h (iobuf_ioctl_t): New. Use the new macros instead of the
hard wired values.
* iobuf.c (iobuf_append): Remove.
diff --git a/common/ChangeLog.jnlib b/common/ChangeLog.jnlib
new file mode 100644
index 000000000..f51525e42
--- /dev/null
+++ b/common/ChangeLog.jnlib
@@ -0,0 +1,769 @@
+2010-03-10 Werner Koch <wk@g10code.com>
+
+ See gnupg/common/ChangeLog for newer changes.
+
+ JNLIB has been merged into GnuPG's common directory. README.jnlib
+ list the files making up JNLIB.
+
+ * README: Rename to README.jnlib
+ * ChangeLog: Rename to ChangeLog.jnlib.
+ * Makefile.am: Remove.
+
+2010-03-01 Werner Koch <wk@g10code.com>
+
+ * t-w32-reg.c: New.
+
+ * w32-reg.c (read_w32_registry_string)
+ (write_w32_registry_string): Support W32CE.
+
+2010-02-26 Werner Koch <wk@g10code.com>
+
+ * t-timestuff.c: New.
+
+ * dynload.h (dlopen, dlsym) [W32CE]: Map to wchar_t.
+
+ * mischelp.c (_jnlib_free): New.
+ (same_file_p) [W32CE]: Map to wchar_t.
+
+ * utf8conv.c (set_native_charset) [W32CE]: Do not use
+ GetConsoleOutputCP.
+ (wchar_to_utf8, utf8_to_wchar) [W32]: New.
+
+ * Makefile.am (t_jnlib_ldadd) [W32CE]: Add gpg-error.
+
+ * t-support.h (getenv) [HAVE_GETENV]: Add getenv stub.
+ [W32CE]: Include gpg-error.h
+ * t-support.c (gpg_err_code_from_errno)
+ (gpg_err_code_from_syserror) [GPG_ERROR_H]: Do not build.
+
+ * t-stringhelp.c (gethome) [!HAVE_GETPWUID]: Keep result of getenv.
+
+ * dotlock.c [!HAVE_SIGNAL_H]: Don't include signal.h.
+ (create_dotlock) [W32CE]: Map filename top wchar_t.
+
+ * libjnlib-config.h [USE_SIMPLE_GETTEXT]: Include gpg-error.h and
+ remove w32help.h.
+ (jnlib_set_errno): New. Use it everywhere to set ERRNO.
+ (getenv) [!HAVE_GETENV]: New.
+ (getpid) [W32E]: New.
+
+ * stringhelp.c (get_pwdir) [!HAVE_PWD_H]: Mark unused args.
+ (w32_strerror) [W32CE]: Use a simple implementation.
+
+ * w32help.h [USE_SIMPLE_GETTEXT]: Remove all definitions; we are
+ now using the gpg-error included implementation.
+ * w32-gettext.c: Remove.
+
+ * mischelp.c (same_file_p): Fix bug in case the second file can't
+ be opened.
+
+2009-10-19 Werner Koch <wk@g10code.com>
+
+ * strlist.c (add_to_strlist_try): New.
+
+2009-09-22 Werner Koch <wk@g10code.com>
+
+ * dotlock.h (DOTLOCK): Rename to dotlock_t. Change all users.
+
+2009-08-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (do_make_filename): Factor some code out to ..
+ (get_pwdir): .. new.
+
+2009-08-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c [HAVE_PWD_H]: Include pwd.h.
+ (do_make_filename): New.
+ (make_filename, make_filename_try): Implement using the new
+ function.
+ * t-stringhelp.c (test_make_filename_try): New.
+ * t-support.c (gcry_strdup): Fix.
+
+ * stringhelp.h (make_filename, make_filename_try): Add sentinel
+ attribute.
+
+2009-08-25 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c: Include errno.h.
+ (do_strconcat): New.
+ (strconcat, xstrconcat): New.
+ * types.h (GNUPG_GCC_A_SENTINEL): New.
+ * t-stringhelp.c (test_strconcat, test_xstrconcat): New.
+ (main): Run them.
+
+2009-07-07 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_filename_try): Use jnlib_malloc.
+
+ * dotlock.c (read_lockfile): Replace jnlib_xmalloc by jnlib_malloc.
+
+2009-06-04 Werner Koch <wk@g10code.com>
+
+ * mischelp.h: Include SUN_LEN etc also for W32.
+
+2009-05-19 Werner Koch <wk@g10code.com>
+
+ * mischelp.h: Define PF_LOCAL, AF_LOCAL and SUN_LEN if requested.
+ * logging.c (fun_writer): Use SUN_LEN to fix a Mac OS X freeze.
+
+2009-03-25 Werner Koch <wk@g10code.com>
+
+ * logging.c (fun_closer): Never close fd 2.
+ (set_file_fd): Close logstream early.
+
+2009-02-25 Werner Koch <wk@g10code.com>
+
+ * logging.c (get_tid_callback): New.
+ (do_logv): Use it.
+ (log_set_get_tid_callback): New.
+
+2009-01-22 Werner Koch <wk@g10code.com>
+
+ * t-support.c (gpg_err_code_from_errno)
+ (gpg_err_code_from_syserror): New.
+
+2008-11-20 Werner Koch <wk@g10code.com>
+
+ * argparse.c (arg_parse): Fix last change.
+
+2008-11-11 Werner Koch <wk@g10code.com>
+
+ * argparse.h: Add a bunch of macros and constants.
+ * argparse.c: Use the new macros. Re-indent the code. Change
+ license back to LGPL 2.1.
+
+2008-11-04 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c: Merged with code from libgpg-error and rewrote
+ most parts.
+
+ * Makefile.am (AM_CFLAGS): Add -DJNLIB_IN_JNLIB.
+
+2008-10-29 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_filename): Implement using macros. Factor some
+ code out to ..
+ (change_slashes): New.
+ (make_filename_try): New.
+
+ * w32-gettext.c (gettext): Return if no domain is loaded.
+ Reported by Tom Pegios.
+
+2008-10-28 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (gettext): Try the binary search if the string was
+ not found in the hash table.
+
+2008-10-20 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c (_w32_sock_connect): Mark ADDRLEN as unused.
+
+ * dotlock.c (release_dotlock): Do not mix declaration and code.
+
+ * stringhelp.c (make_basename): Silent gcc warning about unused arg.
+ * argparse.c (store_alias): Ditto.
+ (find_long_option):
+
+2008-10-15 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv) [W32]: Flush the log stream.
+
+2008-09-29 Werner Koch <wk@g10code.com>
+
+ * argparse.c (ARGERR_): Use constants for error values.
+ (optfile_parse): Prettify. Replace xmalloc and xrealloc by malloc
+ and realloc.
+ * libjnlib-config.h (jnlib_strdup, jnlib_realloc): New.
+
+2008-06-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (print_sanitized_buffer2): Loose check for control
+ characters to better cope with utf-8. The range 0x80..0x9f is
+ nowadays not anymore accidently used for control charaters.
+
+2008-06-13 Werner Koch <wk@g10code.com>
+
+ * dotlock.c: Reformat code and implement locking for W32.
+ (create_dotlock): Use snprintf.
+
+2008-06-11 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c: Remove useless variable ACTIVE_CHARSET. Suggested
+ by Petr Uzel.
+
+2008-05-26 Werner Koch <wk@g10code.com>
+
+ * argparse.c (usage): Make sure to print a trailing LF for usage(1).
+
+2008-04-08 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (gettext_select_utf8): New.
+ (get_string): Support switching encodings.
+ (load_domain): Allocate space for DATA_NATIVE.
+
+2008-03-25 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (_nl_locale_name): New. Taken from
+ ../common/localename and GNU gettext's localename.c.
+ (set_gettext_file): Rewritten.
+ (gettext_localename): New.
+
+2008-03-17 Werner Koch <wk@g10code.com>
+
+ * logging.c (my_funopen_hook_size_t): New.
+ (fun_writer): Use it to cope with fopencookie/funopen differences.
+ * dotlock.c (read_lockfile): Initialize PID. Reported by Stéphane
+ Corthésy.
+
+2008-02-22 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Set copyright year to 2008.
+
+2007-11-19 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (percent_escape): Factor code out to
+ (do_percent_escape): .. new.
+ (try_percent_escape): New.
+
+2007-10-01 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c: Only keep the client related code.
+ (read_port_and_nonce): New. Taken from Assuan.
+ (_w32_sock_connect): Rewritten.
+
+2007-08-29 Werner Koch <wk@g10code.com>
+
+ * argparse.c (initialize): Make strings translatable and remove
+ extra LF.
+
+2007-08-24 Werner Koch <wk@g10code.com>
+
+ * mischelp.c (same_file_p): New.
+ (libjnlib_dummy_mischelp_func): Remove as we now always have one
+ function.
+
+2007-08-09 Werner Koch <wk@g10code.com>
+
+ * argparse.c (show_help): Expand the @EMAIL@ macro in the package
+ bug reporting address.
+
+2007-08-02 Werner Koch <wk@g10code.com>
+
+ * t-stringhelp.c (test_compare_filenames): New.
+
+ * stringhelp.c (compare_filenames) [HAVE_DRIVE_LETTERS]: Fixed
+ comparison to take slash and backslash in account.
+ (make_filename): Avoid mixing / and \.
+
+2007-07-04 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (load_libiconv): Remove URL from translatble string.
+
+ Switched JNLIB from LGPLv2.1 to LGPLv3.
+
+2007-07-01 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Use id 10 for the license string;
+ default to GPL3+. Change long note to version 3 or later.
+ (show_version): Print the license info.
+
+2007-06-19 Werner Koch <wk@g10code.com>
+
+ * Makefile.am: Add support for regression tests.
+ * t-support.h, t-support.c: New.
+ * t-stringhelp.c: New.
+
+ * stringhelp.c (percent_escape): Add arg EXTRA to make it a more
+ general function. Changed all callers.
+
+2007-06-18 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c (_w32_sock_bind): Changed to properly detect an
+ already used socket.
+
+2007-06-18 Marcus Brinkmann <marcus@g10code.de>
+
+ * stringhelp.h (percent_escape): New prototype.
+ * stringhelp.c (percent_escape): New function.
+
+2007-06-11 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (jnlib_iconv_open, jnlib_iconv, jnlib_iconv_close): New.
+
+2007-06-06 Werner Koch <wk@g10code.com>
+
+ * w32help.h: New.
+ * w32-gettext.c: New. Taken from gnupg 1.4, added ngettext,
+ changed to use jnlib malloc functions and put under the LGPL.
+ * w32-reg.c: New. Taken from../common/w32reg.c and changed to
+ LGPL. Changed API to use the jnlib malloc functions.
+ * Makefile.am (libjnlib_a_SOURCES) [!W32]: Do not build the w32
+ specific modules.
+
+ * dotlock.c: Include stringhelp.h for stpcpy prototype.
+
+2007-06-04 Werner Koch <wk@g10code.com>
+
+ * dynload.h: New. Taken from ../common and changed to LGPL.
+
+ * utf8conv.c (load_libiconv): New. Taken from GnuPG 1.4
+
+2007-05-30 Werner Koch <wk@g10code.com>
+
+ * w32-pth.h, w32-pth.c: Remove.
+
+2007-04-25 Werner Koch <wk@g10code.com>
+
+ * argparse.c (long_opt_strlen): Fixed for utf-8.
+
+2007-03-07 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Set copyright year to 2007.
+
+2007-01-25 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (utf8_charcount): New.
+
+2006-11-29 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (set_native_charset) [HAVE_W32_SYSTEM]: Fixed typo in
+ macro name.
+
+2006-11-15 Werner Koch <wk@g10code.com>
+
+ * logging.c (my_funopen_hook_ret_t): New.
+ (fun_writer): Use it.
+
+2006-10-19 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (memrchr) [!HAVE_MEMRCHR]: Provide a replacement.
+
+2006-09-27 Werner Koch <wk@g10code.com>
+
+ * mischelp.c: New.
+ (timegm): Copied from gnupg 1.4, changed from GPL to LGPL. Fixed
+ a memory leak.
+
+ * stringhelp.h (isascii): New.
+
+ * stringhelp.c (strsep): New. Copied from gnupg 1.4.5
+ util/strgutil.c.
+
+ * strlist.h (STRLIST): Removed deprecated typedef.
+
+ * types.h: Made cpp commands work with old compilers. Also shows
+ up nicer with Emacs' font locking.
+
+ * w32-afunix.c (_w32_sock_connect): Set ERRNO for an invalid port.
+
+ Changed license from GPL to LGPL. Note that all code has either
+ been written by me, David, employees of g10 Code or taken from
+ glibc.
+
+ * libjnlib-config.h, stringhelp.c, stringhelp.h:
+ * strlist.c, strlist.h, utf8conv.c, utf8conv.h:
+ * argparse.c, argparse.h, logging.c, logging.h:
+ * dotlock.c, dotlock.h, types.h, mischelp.h:
+ * xmalloc.c, xmalloc.h, w32-pth.c, w32-pth.h:
+ * w32-afunix.c, w32-afunix.h: Tagged them to be long to jnlib
+ which is a part of GnuPG but also used by other projetcs.
+
+2006-09-22 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c: Reworked to match the gnupg 1.4.5 code. This now
+ requires iconv support but this is reasonable for all modern
+ systems.
+
+2006-08-29 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv): Emit a missing LF for fatal errors.
+
+2006-06-28 Werner Koch <wk@g10code.com>
+
+ * dotlock.c (make_dotlock, release_dotlock, read_lockfile)
+ (maybe_deadlock, destroy_dotlock, create_dotlock): Re-indented.
+ (create_dotlock): Repalces some log_fatal by log_error as it was
+ not intended that they should terminate. Write the nodename to
+ the locking file. Code cleanups.
+ (read_lockfile): Reworked to read the node name.
+ (make_dotlock): Test for identical node name and delete lock stale
+ file.
+ (release_dotlock): Likewise.
+
+2006-05-23 Werner Koch <wk@g10code.com>
+
+ * libjnlib-config.h (JNLIB_NEED_UTF8CONV): Fixed typo in name.
+
+ * dotlock.c (release_dotlock): Don't act if we don't have any
+ locks at all.
+ (destroy_dotlock): New. From 1.4.3.
+ (dotlock_remove_lockfiles): Make use of destroy function.
+
+2006-05-19 Werner Koch <wk@g10code.com>
+
+ * strlist.c (append_to_strlist2): Enabled.
+
+ * stringhelp.c (print_sanitized_buffer2): New. Changed the rules
+ to match the behaviour of print_string2 from gnupg 1.4.3.
+ (print_sanitized_buffer): Use the new function.
+ (print_sanitized_string2): New.
+ (hextobyte): New. Taken from gpg 1.4.3.
+
+2006-04-28 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (print_sanitized_buffer): Fix bug where the count
+ got wrong for the \xNN representation.
+ (sanitize_buffer): Fix bug where some control characters lose part
+ of their \xNN representation.
+
+2006-04-20 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_basename): New arg INPUTPATH for future
+ riscos compatibility.
+
+2006-04-18 Werner Koch <wk@g10code.com>
+
+ * libjnlib-config.h (JNLIB_NEED_UTF8CONF): Defined.
+ * strlist.c (add_to_strlist2) [JNLIB_NEED_UTF8CONV]: Enabled.
+
+2005-06-15 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (sanitize_buffer): Make P a void*.
+ (ascii_memistr, memistr): Ditto.
+ (ascii_memcasecmp): Ditto.
+ * logging.c (writen): Use void * for arg BUFFER.
+ * stringhelp.c (memistr): Fixed unsigned/signed pointer conflict.
+ (ascii_memistr): Ditto.
+ (ascii_memcasemem): Ditto.
+ * utf8conv.c (utf8_to_native): Ditto.
+ (utf8_to_native): Ditto.
+ * argparse.c (show_version): Removed non-required cast.
+
+2005-01-19 Werner Koch <wk@g10code.com>
+
+ * logging.c (fun_writer): Don't fallback to stderr. Print to
+ stderr only if connected to a tty.
+
+2004-12-20 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (do_pth_event_free): The events are hold in a ring
+ buffer. Adjust for that.
+ (do_pth_event_body): Ditto.
+ (pth_event_isolate): Ditto.
+ (do_pth_wait): Ditto.
+ (_pth_event_count): Renamed to ..
+ (event_count): .. and adjusted as above.
+ (pth_init): Define 3 debug levels and change all debug calls to
+ make use of them. This makes the moule now silent.
+
+2004-12-19 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (pth_init): Enable debugging depending on env var.
+ (pth_self): New.
+ (pth_mutex_release, pth_mutex_acquire): Implemented directly using
+ the W32 API.
+
+2004-12-18 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (pth_init): Reverse return values. Use TRUE and FALSE
+ constants.
+ (pth_kill, pth_mutex_acquire, pth_attr_set, pth_join, pth_cancel):
+ Ditto.
+
+2004-12-15 Werner Koch <wk@g10code.com>
+
+ * logging.c [W32]: Don't include unavailable headers.
+
+2004-12-14 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (_pth_strerror): Renamed to ...
+ (w32_strerror): .. this. And let callers provide a buffer.
+ (spawn_helper_thread): Removed HD arg and hardwire the stack size
+ to 32k.
+ (do_pth_wait): Removed use of ATTR; not needed for the helper
+ threads.
+ (helper_thread): Renamed to ..
+ (launch_thread): .. this. Release handle if not joinable.
+ (struct pth_priv_hd_s): Renamed to ...
+ (struct thread_info_s): .. this. Add member JOINABLE and TH.
+
+2004-12-14 Timo Schulz <twoaday@g10code.com>
+
+ * w32-pth.c (pth_kill): Just release the crit section if
+ pth_init was really called. And set all handles to NULL.
+ (_pth_strerror): New.
+ (do_pth_wait): Before we enter the loop we check if there
+ are too much events in the ring.
+
+2004-12-14 Werner Koch <wk@g10code.com>
+
+ * w32-pth.h (pth_event_occured): Removed macro.
+ * w32-pth.c: Fixed license statement; its under the LGPL.
+ (enter_pth, leave_pth): Use them to bracket almost all public
+ functions.
+
+2004-12-13 Timo Schulz <twoaday@g10code.com>
+
+ * w32-pth.c (enter_pth, leave_pth): New.
+ (pth_init): Initialize global mutex section.
+ (pth_kill): Release global mutex section.
+ (helper_thread): New.
+ (pth_spawn): Make sure only one thread is running.
+
+2004-12-13 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (w32_strerror) [W32]: New.
+
+ * w32-pth.c, w32-pth.h: Added real code written by Timo Schulz.
+ Not finished, though.
+
+2004-12-07 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c, w32-pth.h: New.
+
+2004-11-26 Werner Koch <wk@g10code.com>
+
+ * logging.c [_WIN32]: Don't include socket headers.
+
+2004-11-30 Timo Schulz <ts@g10code.com>
+
+ * w32-afunix.c: New. AF_UNIX emulation for W32.
+ * w32-afunix.h: Likewise.
+
+2004-11-22 Werner Koch <wk@g10code.com>
+
+ * logging.c (log_test_fd): Add test on LOGSTREAM. Reported by
+ Barry Schwartz.
+
+2004-11-18 Werner Koch <wk@g10code.com>
+
+ * logging.c: Explicitly include sys/stat.h for the S_I* constants.
+
+2004-10-21 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv): Use set_log_stream to setup a default.
+ (log_set_file): Factored code out to ..
+ (set_file_fd): .. New function to allow using a file descriptor.
+ (log_set_fd): Make use of new fucntion.
+ (fun_writer): Reworked.
+
+2004-08-18 Werner Koch <wk@g10code.de>
+
+ * stringhelp.c (print_sanitized_utf8_string): Actually implement
+ it.
+
+2004-06-21 Werner Koch <wk@g10code.com>
+
+ * logging.c (log_set_file): Do not close an old logstream if it
+ used to be stderr or stdout.
+
+2004-05-05 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_file): Oops, don't close if LOGSTREAM is NULL.
+
+2004-04-30 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_file): Make sure the log stream will be
+ closed even if the stderr fileno will be assigned to a new socket.
+
+2004-04-16 Werner Koch <wk@gnupg.org>
+
+ * logging.h (JNLIB_LOG_WITH_PREFIX): Add constants for the flag
+ values.
+ * logging.c (log_set_prefix): New flag DETACHED.
+ (fun_writer): Take care of this flag.
+ (log_test_fd): New.
+
+2004-02-18 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (print_sanitized_buffer): Don't care about
+ non-ASCII characaters.
+ (sanitize_buffer): Ditto.
+
+2004-02-12 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am: Replaced INCLUDES by AM_CPPFLAGS.
+
+2004-01-05 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (strusage): Changed default copyright year to 2004.
+
+2003-12-17 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (initialize): Replaced use of non-literal format
+ args. Suggested by Florian Weimer.
+
+2003-12-16 Werner Koch <wk@gnupg.org>
+
+ * logging.c (writen, fun_writer, fun_closer): New.
+ (log_set_file): Add feature to log to a socket.
+ (log_set_file, do_logv): Force printing with prefix and pid.
+
+2003-11-13 Werner Koch <wk@gnupg.org>
+
+ * strlist.c (strlist_copy): New.
+
+ * dotlock.c: Define DIRSEP_C et al. if not defined.
+
+2003-11-06 Werner Koch <wk@gnupg.org>
+
+ * strlist.h (strlist_t): New. STRLIST is now deprecated.
+
+2003-06-18 Werner Koch <wk@gnupg.org>
+
+ * strlist.c (strlist_pop): New.
+
+ * dotlock.c (dotlock_remove_lockfiles): Prefixed with dotlock_ and
+ made global.
+
+2003-06-17 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (length_sans_trailing_chars)
+ (length_sans_trailing_ws): New.
+
+ * logging.c (log_inc_errorcount): New.
+
+ * stringhelp.c (print_sanitized_utf8_buffer): Implement utf8
+ conversion.
+ (sanitize_buffer): New. Based on gnupg 1.3.2 make_printable_string.
+
+ * dotlock.c: Updated to match the version from 1.3.2
+ * utf8conv.c: New. Code taken from strgutil.c of gnupg 1.3.2.
+ * utf8conv.h: New.
+
+2003-06-16 Werner Koch <wk@gnupg.org>
+
+ * logging.c (do_logv): Hack to optionally suppress a leading space.
+
+ * stringhelp.c (ascii_strncasecmp): New. Taken from gnupg 1.3.
+ (ascii_memistr): New. Taken from gnupg 1.3
+
+2003-06-13 Werner Koch <wk@gnupg.org>
+
+ * mischelp.h (wipememory2,wipememory): New. Taken from GnuPG 1.3.2.
+
+2002-06-04 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (print_sanitized_utf8_string): New. No real
+ implementation for now.
+ (print_sanitized_utf8_buffer): Ditto.
+
+2002-04-04 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_get_prefix): New.
+
+2002-03-15 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (optfile_parse): Fixed missing argument handling.
+
+2002-02-25 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (ascii_memcasemem): New.
+
+2002-02-14 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am (INCLUDES): Add cflags for libgcrypt.
+
+2002-02-07 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_fd): New.
+
+ * stringhelp.c (print_sanitized_buffer): New.
+ (print_sanitized_string): New.
+
+2002-01-24 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (strusage): Set default copyright notice year to 2002.
+
+ Fixed the copyright notice of this file, as it has always been
+ part of GnuPG and therefore belongs to the FSF.
+
+2001-11-01 Marcus Brinkmann <marcus@g10code.de>
+
+ * logging.c (log_printf): Do not initialize ARG_PTR with 0, we
+ don't know the correct type. Instead, run va_start and va_end
+ unconditionally.
+ Reported by Jose Carlos Garcia Sogo <jsogo@debian.org>.
+
+2002-01-19 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_get_stream): New.
+
+2001-12-05 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_prefix): New.
+ (do_logv): Include prefix and pid only if enabled. Print time only
+ when explicitly enabled.
+ (log_logv): New.
+ * logging.h: Include log_logv() only when requested.
+
+2001-11-06 Werner Koch <wk@gnupg.org>
+
+ * strlist.c, strlist.h: New. Taken from pgnupg/util/strgutil.c
+
+2001-08-30 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_printf): Don't pass NULL instead of arg_ptr.
+
+2001-07-19 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (ascii_memistr,ascii_isupper,ascii_islower,
+ ascii_toupper,ascii_tolower, ascii_strcasecmp, ascii_memcasecmp): New.
+
+2000-07-26 10:02:51 Werner Koch (wk@habibti.openit.de)
+
+ * stringhelp.c.: Add stdarg.h
+ * argparse.h: s/ulong/unsigned long/ although this should be defined
+ by types.h.
+
+2000-06-28 19:40:23 Werner Koch (wk@habibti.openit.de)
+
+ * Makefile.am: Replaced second logging.c by .h
+
+2000-05-24 08:58:15 Werner Koch (wk@habibti.openit.de)
+
+ * logging.c (log_get_errorcount): New.
+
+2000-05-24 08:44:47 Werner Koch (wk@habibti.openit.de)
+
+ * stringhelp.c: Added a few filename related helper functions.
+
+2000-05-11 18:04:43 Werner Koch (wk@habibti.openit.de)
+
+ * xmalloc.c (xstrcat2): Replaced stpcpy to quickly address W32
+ problems.
+
+2000-05-02 19:43:38 Werner Koch (wk@habibti.openit.de)
+
+ * xmalloc.c (xstrcat2): New.
+
+Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
+
+ * README: New.
+ * Makefile.am: new.
+ * argparse.c, argparse.h, logging.c, logging.h:
+ * mischelp.h, stringhelp.c, stringhelp.h, xmalloc.c:
+ * xmalloc.h, dotlock.c: Moved from ../util to here.
+ * dotlock.h: New.
+ * libjnlib-config.h: New.
+
+ * logging.c (log_set_file): New.
+ (log_printf): New.
+ (do_logv): Add kludge to insert LFs.
+
+
+ ***********************************************************
+ * Please note that JNLIB is maintained as part of GnuPG. *
+ * You may find it source-copied in other packages. *
+ ***********************************************************
+
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2010 Free Software Foundation, Inc.
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/common/Makefile.am b/common/Makefile.am
index c7a9f09ba..1a73d31b1 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -1,5 +1,5 @@
# Makefile for common gnupg modules
-# Copyright (C) 2001, 2003, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2007, 2010 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
#
@@ -19,11 +19,11 @@
## Process this file with automake to produce Makefile.in
EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk \
- audit-events.h status-codes.h
+ audit-events.h status-codes.h README.jnlib ChangeLog.jnlib
noinst_LIBRARIES = libcommon.a libcommonpth.a libsimple-pwquery.a libgpgrl.a
-noinst_PROGRAMS = $(module_tests) $(module_maint_tests)
-TESTS = $(module_tests)
+noinst_PROGRAMS = $(jnlib_tests) $(module_tests) $(module_maint_tests)
+TESTS = $(jnlib_tests) $(module_tests)
BUILT_SOURCES = audit-events.h status-codes.h
@@ -35,9 +35,26 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
include $(top_srcdir)/am/cmacros.am
+jnlib_sources = \
+ libjnlib-config.h \
+ types.h dynload.h w32help.h \
+ stringhelp.c stringhelp.h \
+ strlist.c strlist.h \
+ utf8conv.c utf8conv.h \
+ argparse.c argparse.h \
+ logging.c logging.h \
+ dotlock.c dotlock.h \
+ mischelp.c mischelp.h
+
+if HAVE_W32_SYSTEM
+jnlib_sources += w32-reg.c w32-afunix.c w32-afunix.h
+endif
+
+
common_sources = \
common-defs.h \
util.h i18n.c i18n.h \
+ estream.c estream.h estream-printf.c estream-printf.h \
status.c status.h\
openpgpdefs.h \
gc-opt-flags.h \
@@ -62,7 +79,6 @@ common_sources = \
asshelp.c asshelp.h \
exechelp.c exechelp.h \
signal.c \
- estream.c estream.h estream-printf.c estream-printf.h \
audit.c audit.h \
srv.h \
dns-cert.c dns-cert.h \
@@ -78,13 +94,13 @@ without_pth_sources = \
get-passphrase.c get-passphrase.h
-libcommon_a_SOURCES = $(common_sources) $(without_pth_sources)
+libcommon_a_SOURCES = $(jnlib_sources) $(common_sources) $(without_pth_sources)
if USE_DNS_SRV
libcommon_a_SOURCES += srv.c
endif
libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_GNU_PTH=1
-libcommonpth_a_SOURCES = $(common_sources)
+libcommonpth_a_SOURCES = $(jnlib_sources) $(common_sources)
if USE_DNS_SRV
libcommonpth_a_SOURCES += srv.c
endif
@@ -121,13 +137,32 @@ endif
#
# Module tests
#
+t_jnlib_src = t-support.c t-support.h
+jnlib_tests = t-stringhelp t-timestuff
+if HAVE_W32_SYSTEM
+jnlib_tests += t-w32-reg
+endif
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp \
t-session-env
module_maint_tests = t-helpfile t-b64
-t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \
+
+t_common_ldadd = libcommon.a ../gl/libgnu.a \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
+# jnlib tests
+t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src)
+t_stringhelp_LDADD = $(t_common_ldadd)
+
+t_timestuff_SOURCES = t-timestuff.c $(t_jnlib_src)
+t_timestuff_LDADD = $(t_common_ldadd)
+
+if HAVE_W32_SYSTEM
+t_w32_reg_SOURCES = t-w32-reg.c $(t_jnlib_src)
+t_w32_reg_LDADD = $(t_common_ldadd)
+endif
+
+# common tests
t_convert_LDADD = $(t_common_ldadd)
t_percent_LDADD = $(t_common_ldadd)
t_gettime_LDADD = $(t_common_ldadd)
@@ -138,3 +173,6 @@ t_b64_LDADD = $(t_common_ldadd)
t_exechelp_LDADD = $(t_common_ldadd)
t_session_env_LDADD = $(t_common_ldadd)
+
+
+
diff --git a/common/README.jnlib b/common/README.jnlib
new file mode 100644
index 000000000..e8df795cb
--- /dev/null
+++ b/common/README.jnlib
@@ -0,0 +1,101 @@
+JNLIB - This is a collection of utility function which are too small
+to put into a library. The code here is licensed under the LGPL.
+
+libjnlib-config.h should be be modified for each project to make these
+functions fit into the software. Mainly these are memory functions in
+case you need another allocator.
+
+Files which make up jnlib:
+ README.jnlib
+ ChangeLog.jnlib
+ libjnlib-config.h
+ argparse.c
+ argparse.h
+ dotlock.c
+ dotlock.h
+ dynload.h
+ logging.c
+ logging.h
+ mischelp.c
+ mischelp.h
+ stringhelp.c
+ stringhelp.h
+ strlist.c
+ strlist.h
+ types.h
+ utf8conv.c
+ utf8conv.h
+ w32-afunix.c
+ w32-afunix.h
+ w32-reg.c
+ w32help.h
+ xmalloc.c
+ xmalloc.h
+ t-stringhelp.c
+ t-support.c
+ t-support.h
+ t-timestuff.c
+ t-w32-reg.c
+
+
+Here is a template Makefile.am for these jnlib modules:
+===8<==================================================
+EXTRA_DIST = README
+noinst_PROGRAMS = $(module_tests)
+TESTS = $(module_tests)
+
+AM_CPPFLAGS = -I$(top_srcdir)/intl
+
+# We need libgcrypt because libjnlib-config includes gcrypt.h
+AM_CFLAGS = $(LIBGCRYPT_CFLAGS)
+
+noinst_LIBRARIES = libjnlib.a
+
+libjnlib_a_SOURCES = \
+ libjnlib-config.h \
+ stringhelp.c stringhelp.h \
+ strlist.c strlist.h \
+ utf8conv.c utf8conv.h \
+ argparse.c argparse.h \
+ logging.c logging.h \
+ dotlock.c dotlock.h \
+ types.h mischelp.c mischelp.h dynload.h w32help.h \
+ xmalloc.c xmalloc.h
+
+if HAVE_W32_SYSTEM
+libjnlib_a_SOURCES += w32-reg.c w32-afunix.c w32-afunix.h
+endif
+
+#
+# Module tests.
+#
+# These tests should only be used at the canonical location of jnlib
+# which is the GnuPG package. The reason for this is that t-support.c
+# defines replacements for the actual used memory allocation functions
+# so that there is no dependency on libgcrypt.
+#
+module_tests = t-stringhelp t-timestuff
+if HAVE_W32_SYSTEM
+module_tests += t-w32-reg
+endif
+
+t_jnlib_src = t-support.c t-support.h
+t_jnlib_ldadd = libjnlib.a $(LIBINTL) $(LIBICONV)
+# For W32 we need libgpg-error because it provides gettext.
+if HAVE_W32_SYSTEM
+t_jnlib_ldadd += $(GPG_ERROR_LIBS)
+endif
+
+t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src)
+t_stringhelp_LDADD = $(t_jnlib_ldadd)
+
+t_timestuff_SOURCES = t-timestuff.c $(t_jnlib_src)
+t_timestuff_LDADD = $(t_jnlib_ldadd)
+
+if HAVE_W32_SYSTEM
+t_w32_reg_SOURCES = t-w32-reg.c $(t_jnlib_src)
+t_w32_reg_LDADD = $(t_jnlib_ldadd)
+endif
+==>8===================================================
+
+
diff --git a/common/argparse.c b/common/argparse.c
new file mode 100644
index 000000000..ab88922a4
--- /dev/null
+++ b/common/argparse.c
@@ -0,0 +1,1205 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (C) 1998, 1999, 2000, 2001, 2006
+ * 2007, 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "libjnlib-config.h"
+#include "mischelp.h"
+#include "stringhelp.h"
+#include "logging.h"
+#ifdef JNLIB_NEED_UTF8CONV
+#include "utf8conv.h"
+#endif
+#include "argparse.h"
+
+
+
+/*********************************
+ * @Summary arg_parse
+ * #include <wk/lib.h>
+ *
+ * typedef struct {
+ * char *argc; pointer to argc (value subject to change)
+ * char ***argv; pointer to argv (value subject to change)
+ * unsigned flags; Global flags (DO NOT CHANGE)
+ * int err; print error about last option
+ * 1 = warning, 2 = abort
+ * int r_opt; return option
+ * int r_type; type of return value (0 = no argument found)
+ * union {
+ * int ret_int;
+ * long ret_long
+ * ulong ret_ulong;
+ * char *ret_str;
+ * } r; Return values
+ * struct {
+ * int idx;
+ * const char *last;
+ * void *aliases;
+ * } internal; DO NOT CHANGE
+ * } ARGPARSE_ARGS;
+ *
+ * typedef struct {
+ * int short_opt;
+ * const char *long_opt;
+ * unsigned flags;
+ * } ARGPARSE_OPTS;
+ *
+ * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
+ *
+ * @Description
+ * This is my replacement for getopt(). See the example for a typical usage.
+ * Global flags are:
+ * Bit 0 : Do not remove options form argv
+ * Bit 1 : Do not stop at last option but return other args
+ * with r_opt set to -1.
+ * Bit 2 : Assume options and real args are mixed.
+ * Bit 3 : Do not use -- to stop option processing.
+ * Bit 4 : Do not skip the first arg.
+ * Bit 5 : allow usage of long option with only one dash
+ * Bit 6 : ignore --version
+ * all other bits must be set to zero, this value is modified by the
+ * function, so assume this is write only.
+ * Local flags (for each option):
+ * Bit 2-0 : 0 = does not take an argument
+ * 1 = takes int argument
+ * 2 = takes string argument
+ * 3 = takes long argument
+ * 4 = takes ulong argument
+ * Bit 3 : argument is optional (r_type will the be set to 0)
+ * Bit 4 : allow 0x etc. prefixed values.
+ * Bit 7 : this is a command and not an option
+ * You stop the option processing by setting opts to NULL, the function will
+ * then return 0.
+ * @Return Value
+ * Returns the args.r_opt or 0 if ready
+ * r_opt may be -2/-7 to indicate an unknown option/command.
+ * @See Also
+ * ArgExpand
+ * @Notes
+ * You do not need to process the options 'h', '--help' or '--version'
+ * because this function includes standard help processing; but if you
+ * specify '-h', '--help' or '--version' you have to do it yourself.
+ * The option '--' stops argument processing; if bit 1 is set the function
+ * continues to return normal arguments.
+ * To process float args or unsigned args you must use a string args and do
+ * the conversion yourself.
+ * @Example
+ *
+ * ARGPARSE_OPTS opts[] = {
+ * { 'v', "verbose", 0 },
+ * { 'd', "debug", 0 },
+ * { 'o', "output", 2 },
+ * { 'c', "cross-ref", 2|8 },
+ * { 'm', "my-option", 1|8 },
+ * { 500, "have-no-short-option-for-this-long-option", 0 },
+ * {0} };
+ * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+ *
+ * while( ArgParse( &pargs, &opts) ) {
+ * switch( pargs.r_opt ) {
+ * case 'v': opt.verbose++; break;
+ * case 'd': opt.debug++; break;
+ * case 'o': opt.outfile = pargs.r.ret_str; break;
+ * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ * case 500: opt.a_long_one++; break
+ * default : pargs.err = 1; break; -- force warning output --
+ * }
+ * }
+ * if( argc > 1 )
+ * log_fatal( "Too many args");
+ *
+ */
+
+typedef struct alias_def_s *ALIAS_DEF;
+struct alias_def_s {
+ ALIAS_DEF next;
+ char *name; /* malloced buffer with name, \0, value */
+ const char *value; /* ptr into name */
+};
+
+static const char *(*strusage_handler)( int ) = NULL;
+
+static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
+static void show_version(void);
+
+
+static void
+initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
+{
+ if( !(arg->flags & (1<<15)) )
+ {
+ /* Initialize this instance. */
+ arg->internal.idx = 0;
+ arg->internal.last = NULL;
+ arg->internal.inarg = 0;
+ arg->internal.stopped = 0;
+ arg->internal.aliases = NULL;
+ arg->internal.cur_alias = NULL;
+ arg->err = 0;
+ arg->flags |= 1<<15; /* Mark as initialized. */
+ if ( *arg->argc < 0 )
+ jnlib_log_bug ("invalid argument for arg_parsee\n");
+ }
+
+
+ if (arg->err)
+ {
+ /* Last option was erroneous. */
+ const char *s;
+
+ if (filename)
+ {
+ if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ s = _("argument not expected");
+ else if ( arg->r_opt == ARGPARSE_READ_ERROR )
+ s = _("read error");
+ else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
+ s = _("keyword too long");
+ else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ s = _("missing argument");
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ s = _("invalid command");
+ else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
+ s = _("invalid alias definition");
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ s = _("out of core");
+ else
+ s = _("invalid option");
+ jnlib_log_error ("%s:%u: %s\n", filename, *lineno, s);
+ }
+ else
+ {
+ s = arg->internal.last? arg->internal.last:"[??]";
+
+ if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ jnlib_log_error (_("missing argument for option \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ jnlib_log_error (_("option \"%.50s\" does not expect an "
+ "argument\n"), s );
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ jnlib_log_error (_("invalid command \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
+ jnlib_log_error (_("option \"%.50s\" is ambiguous\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
+ jnlib_log_error (_("command \"%.50s\" is ambiguous\n"),s );
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ jnlib_log_error ("%s\n", _("out of core\n"));
+ else
+ jnlib_log_error (_("invalid option \"%.50s\"\n"), s);
+ }
+ if ( arg->err != 1 )
+ exit (2);
+ arg->err = 0;
+ }
+
+ /* Zero out the return value union. */
+ arg->r.ret_str = NULL;
+ arg->r.ret_long = 0;
+}
+
+
+static void
+store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
+{
+ /* TODO: replace this dummy function with a rea one
+ * and fix the probelms IRIX has with (ALIAS_DEV)arg..
+ * used as lvalue
+ */
+ (void)arg;
+ (void)name;
+ (void)value;
+#if 0
+ ALIAS_DEF a = jnlib_xmalloc( sizeof *a );
+ a->name = name;
+ a->value = value;
+ a->next = (ALIAS_DEF)arg->internal.aliases;
+ (ALIAS_DEF)arg->internal.aliases = a;
+#endif
+}
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords "help", "warranty" and "version"
+ * are not valid here.
+ * The special keyword "alias" may be used to store alias definitions,
+ * which are later expanded like long options.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ *
+ * Q: Should we allow the syntax
+ * keyword = value
+ * and accept for boolean options a value of 1/0, yes/no or true/false?
+ * Note: Abbreviation of options is here not allowed.
+ */
+int
+optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int state, i, c;
+ int idx=0;
+ char keyword[100];
+ char *buffer = NULL;
+ size_t buflen = 0;
+ int in_alias=0;
+
+ if (!fp) /* Divert to to arg_parse() in this case. */
+ return arg_parse (arg, opts);
+
+ initialize (arg, filename, lineno);
+
+ /* Find the next keyword. */
+ state = i = 0;
+ for (;;)
+ {
+ c = getc (fp);
+ if (c == '\n' || c== EOF )
+ {
+ if ( c != EOF )
+ ++*lineno;
+ if (state == -1)
+ break;
+ else if (state == 2)
+ {
+ keyword[i] = 0;
+ for (i=0; opts[i].short_opt; i++ )
+ {
+ if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+ break;
+ }
+ idx = i;
+ arg->r_opt = opts[idx].short_opt;
+ if (!opts[idx].short_opt )
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ else if (!(opts[idx].flags & 7))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & 8) )
+ arg->r_type = 0; /* Arg is optional. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ }
+ else if (state == 3)
+ {
+ /* No argument found. */
+ if (in_alias)
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ else if (!(opts[idx].flags & 7))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & 8))
+ arg->r_type = 0; /* No optional argument. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ }
+ else if (state == 4)
+ {
+ /* Has an argument. */
+ if (in_alias)
+ {
+ if (!buffer)
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ buffer[i] = 0;
+ p = strpbrk (buffer, " \t");
+ if (p)
+ {
+ *p++ = 0;
+ trim_spaces (p);
+ }
+ if (!p || !*p)
+ {
+ jnlib_free (buffer);
+ arg->r_opt = ARGPARSE_INVALID_ALIAS;
+ }
+ else
+ {
+ store_alias (arg, buffer, p);
+ }
+ }
+ }
+ else if (!(opts[idx].flags & 7))
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ if (!buffer)
+ {
+ keyword[i] = 0;
+ buffer = jnlib_strdup (keyword);
+ if (!buffer)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ }
+ else
+ buffer[i] = 0;
+
+ if (buffer)
+ {
+ trim_spaces (buffer);
+ p = buffer;
+ if (*p == '"')
+ {
+ /* Remove quotes. */
+ p++;
+ if (*p && p[strlen(p)-1] == '\"' )
+ p[strlen(p)-1] = 0;
+ }
+ if (!set_opt_arg (arg, opts[idx].flags, p))
+ jnlib_free(buffer);
+ }
+ }
+ break;
+ }
+ else if (c == EOF)
+ {
+ if (ferror (fp))
+ arg->r_opt = ARGPARSE_READ_ERROR;
+ else
+ arg->r_opt = 0; /* EOF. */
+ break;
+ }
+ state = 0;
+ i = 0;
+ }
+ else if (state == -1)
+ ; /* Skip. */
+ else if (state == 0 && isascii (c) && isspace(c))
+ ; /* Skip leading white space. */
+ else if (state == 0 && c == '#' )
+ state = 1; /* Start of a comment. */
+ else if (state == 1)
+ ; /* Skip comments. */
+ else if (state == 2 && isascii (c) && isspace(c))
+ {
+ /* Check keyword. */
+ keyword[i] = 0;
+ for (i=0; opts[i].short_opt; i++ )
+ if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+ break;
+ idx = i;
+ arg->r_opt = opts[idx].short_opt;
+ if (!opts[idx].short_opt)
+ {
+ if (!strcmp (keyword, "alias"))
+ {
+ in_alias = 1;
+ state = 3;
+ }
+ else
+ {
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ state = -1; /* Skip rest of line and leave. */
+ }
+ }
+ else
+ state = 3;
+ }
+ else if (state == 3)
+ {
+ /* Skip leading spaces of the argument. */
+ if (!isascii (c) || !isspace(c))
+ {
+ i = 0;
+ keyword[i++] = c;
+ state = 4;
+ }
+ }
+ else if (state == 4)
+ {
+ /* Collect the argument. */
+ if (buffer)
+ {
+ if (i < buflen-1)
+ buffer[i++] = c;
+ else
+ {
+ char *tmp;
+ size_t tmplen = buflen + 50;
+
+ tmp = jnlib_realloc (buffer, tmplen);
+ if (tmp)
+ {
+ buflen = tmplen;
+ buffer = tmp;
+ buffer[i++] = c;
+ }
+ else
+ {
+ jnlib_free (buffer);
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ }
+ else if (i < DIM(keyword)-1)
+ keyword[i++] = c;
+ else
+ {
+ size_t tmplen = DIM(keyword) + 50;
+ buffer = jnlib_malloc (tmplen);
+ if (buffer)
+ {
+ buflen = tmplen;
+ memcpy(buffer, keyword, i);
+ buffer[i++] = c;
+ }
+ else
+ {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ }
+ else if (i >= DIM(keyword)-1)
+ {
+ arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
+ state = -1; /* Skip rest of line and leave. */
+ }
+ else
+ {
+ keyword[i++] = c;
+ state = 2;
+ }
+ }
+
+ return arg->r_opt;
+}
+
+
+
+static int
+find_long_option( ARGPARSE_ARGS *arg,
+ ARGPARSE_OPTS *opts, const char *keyword )
+{
+ int i;
+ size_t n;
+
+ (void)arg;
+
+ /* Would be better if we can do a binary search, but it is not
+ possible to reorder our option table because we would mess
+ up our help strings - What we can do is: Build a nice option
+ lookup table wehn this function is first invoked */
+ if( !*keyword )
+ return -1;
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+ return i;
+#if 0
+ {
+ ALIAS_DEF a;
+ /* see whether it is an alias */
+ for( a = args->internal.aliases; a; a = a->next ) {
+ if( !strcmp( a->name, keyword) ) {
+ /* todo: must parse the alias here */
+ args->internal.cur_alias = a;
+ return -3; /* alias available */
+ }
+ }
+ }
+#endif
+ /* not found, see whether it is an abbreviation */
+ /* aliases may not be abbreviated */
+ n = strlen( keyword );
+ for(i=0; opts[i].short_opt; i++ ) {
+ if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
+ int j;
+ for(j=i+1; opts[j].short_opt; j++ ) {
+ if( opts[j].long_opt
+ && !strncmp( opts[j].long_opt, keyword, n ) )
+ return -2; /* abbreviation is ambiguous */
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int idx;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ initialize( arg, NULL, NULL );
+ argc = *arg->argc;
+ argv = *arg->argv;
+ idx = arg->internal.idx;
+
+ if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
+ {
+ /* Skip the first argument. */
+ argc--; argv++; idx++;
+ }
+
+ next_one:
+ if (!argc)
+ {
+ /* No more args. */
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+
+ s = *argv;
+ arg->internal.last = s;
+
+ if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
+ {
+ arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; idx++; /* set to next one */
+ }
+ else if( arg->internal.stopped )
+ {
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+ else if ( *s == '-' && s[1] == '-' )
+ {
+ /* Long option. */
+ char *argpos;
+
+ arg->internal.inarg = 0;
+ if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
+ {
+ /* Stop option processing. */
+ arg->internal.stopped = 1;
+ argc--; argv++; idx++;
+ goto next_one;
+ }
+
+ argpos = strchr( s+2, '=' );
+ if ( argpos )
+ *argpos = 0;
+ i = find_long_option ( arg, opts, s+2 );
+ if ( argpos )
+ *argpos = '=';
+
+ if ( i < 0 && !strcmp ( "help", s+2) )
+ show_help (opts, arg->flags);
+ else if ( i < 0 && !strcmp ( "version", s+2) )
+ {
+ if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
+ {
+ show_version ();
+ exit(0);
+ }
+ }
+ else if ( i < 0 && !strcmp( "warranty", s+2))
+ {
+ puts ( strusage (16) );
+ exit (0);
+ }
+ else if ( i < 0 && !strcmp( "dump-options", s+2) )
+ {
+ for (i=0; opts[i].short_opt; i++ )
+ {
+ if ( opts[i].long_opt )
+ printf ("--%s\n", opts[i].long_opt);
+ }
+ fputs ("--dump-options\n--help\n--version\n--warranty\n", stdout);
+ exit (0);
+ }
+
+ if ( i == -2 )
+ arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
+ else if ( i == -1 )
+ {
+ arg->r_opt = ARGPARSE_INVALID_OPTION;
+ arg->r.ret_str = s+2;
+ }
+ else
+ arg->r_opt = opts[i].short_opt;
+ if ( i < 0 )
+ ;
+ else if ( (opts[i].flags & 0x07) )
+ {
+ if ( argpos )
+ {
+ s2 = argpos+1;
+ if ( !*s2 )
+ s2 = NULL;
+ }
+ else
+ s2 = argv[1];
+ if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( !argpos && *s2 == '-'
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* The argument is optional and the next seems to be an
+ option. We do not check this possible option but
+ assume no argument */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ else
+ {
+ set_opt_arg (arg, opts[i].flags, s2);
+ if ( !argpos )
+ {
+ argc--; argv++; idx++; /* Skip one. */
+ }
+ }
+ }
+ else
+ {
+ /* Does not take an argument. */
+ if ( argpos )
+ arg->r_type = ARGPARSE_UNEXPECTED_ARG;
+ else
+ arg->r_type = 0;
+ }
+ argc--; argv++; idx++; /* Set to next one. */
+ }
+ else if ( (*s == '-' && s[1]) || arg->internal.inarg )
+ {
+ /* Short option. */
+ int dash_kludge = 0;
+
+ i = 0;
+ if ( !arg->internal.inarg )
+ {
+ arg->internal.inarg++;
+ if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
+ {
+ for (i=0; opts[i].short_opt; i++ )
+ if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
+ {
+ dash_kludge = 1;
+ break;
+ }
+ }
+ }
+ s += arg->internal.inarg;
+
+ if (!dash_kludge )
+ {
+ for (i=0; opts[i].short_opt; i++ )
+ if ( opts[i].short_opt == *s )
+ break;
+ }
+
+ if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
+ show_help (opts, arg->flags);
+
+ arg->r_opt = opts[i].short_opt;
+ if (!opts[i].short_opt )
+ {
+ arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
+ ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
+ arg->internal.inarg++; /* Point to the next arg. */
+ arg->r.ret_str = s;
+ }
+ else if ( (opts[i].flags & 7) )
+ {
+ if ( s[1] && !dash_kludge )
+ {
+ s2 = s+1;
+ set_opt_arg (arg, opts[i].flags, s2);
+ }
+ else
+ {
+ s2 = argv[1];
+ if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( *s2 == '-' && s2[1]
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* The argument is optional and the next seems to
+ be an option. We do not check this possible
+ option but assume no argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ else
+ {
+ set_opt_arg (arg, opts[i].flags, s2);
+ argc--; argv++; idx++; /* Skip one. */
+ }
+ }
+ s = "x"; /* This is so that !s[1] yields false. */
+ }
+ else
+ {
+ /* Does not take an argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->internal.inarg++; /* Point to the next arg. */
+ }
+ if ( !s[1] || dash_kludge )
+ {
+ /* No more concatenated short options. */
+ arg->internal.inarg = 0;
+ argc--; argv++; idx++;
+ }
+ }
+ else if ( arg->flags & ARGPARSE_FLAG_MIXED )
+ {
+ arg->r_opt = ARGPARSE_IS_ARG;
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; idx++; /* Set to next one. */
+ }
+ else
+ {
+ arg->internal.stopped = 1; /* Stop option processing. */
+ goto next_one;
+ }
+
+ leave:
+ *arg->argc = argc;
+ *arg->argv = argv;
+ arg->internal.idx = idx;
+ return arg->r_opt;
+}
+
+
+
+static int
+set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
+{
+ int base = (flags & 16)? 0 : 10;
+
+ switch ( (arg->r_type = (flags & 7)) )
+ {
+ case ARGPARSE_TYPE_INT:
+ arg->r.ret_int = (int)strtol(s,NULL,base);
+ return 0;
+ case ARGPARSE_TYPE_LONG:
+ arg->r.ret_long= strtol(s,NULL,base);
+ return 0;
+ case ARGPARSE_TYPE_ULONG:
+ arg->r.ret_ulong= strtoul(s,NULL,base);
+ return 0;
+ case ARGPARSE_TYPE_STRING:
+ default:
+ arg->r.ret_str = s;
+ return 1;
+ }
+}
+
+
+static size_t
+long_opt_strlen( ARGPARSE_OPTS *o )
+{
+ size_t n = strlen (o->long_opt);
+
+ if ( o->description && *o->description == '|' )
+ {
+ const char *s;
+#ifdef JNLIB_NEED_UTF8CONV
+ int is_utf8 = is_native_utf8 ();
+#endif
+
+ s=o->description+1;
+ if ( *s != '=' )
+ n++;
+ /* For a (mostly) correct length calculation we exclude
+ continuation bytes (10xxxxxx) if we are on a native utf8
+ terminal. */
+ for (; *s && *s != '|'; s++ )
+#ifdef JNLIB_NEED_UTF8CONV
+ if ( is_utf8 && (*s&0xc0) != 0x80 )
+#endif
+ n++;
+ }
+ return n;
+}
+
+
+/****************
+ * Print formatted help. The description string has some special
+ * meanings:
+ * - A description string which is "@" suppresses help output for
+ * this option
+ * - a description,ine which starts with a '@' and is followed by
+ * any other characters is printed as is; this may be used for examples
+ * ans such.
+ * - A description which starts with a '|' outputs the string between this
+ * bar and the next one as arguments of the long option.
+ */
+static void
+show_help (ARGPARSE_OPTS *opts, unsigned int flags)
+{
+ const char *s;
+
+ show_version ();
+ putchar ('\n');
+ s = strusage(41);
+ puts (s);
+ if ( opts[0].description )
+ {
+ /* Auto format the option description. */
+ int i,j, indent;
+
+ /* Get max. length of long options. */
+ for (i=indent=0; opts[i].short_opt; i++ )
+ {
+ if ( opts[i].long_opt )
+ if ( !opts[i].description || *opts[i].description != '@' )
+ if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
+ indent = j;
+ }
+
+ /* Example: " -v, --verbose Viele Sachen ausgeben" */
+ indent += 10;
+ if ( *opts[0].description != '@' )
+ puts ("Options:");
+ for (i=0; opts[i].short_opt; i++ )
+ {
+ s = _( opts[i].description );
+ if ( s && *s== '@' && !s[1] ) /* Hide this line. */
+ continue;
+ if ( s && *s == '@' ) /* Unindented comment only line. */
+ {
+ for (s++; *s; s++ )
+ {
+ if ( *s == '\n' )
+ {
+ if( s[1] )
+ putchar('\n');
+ }
+ else
+ putchar(*s);
+ }
+ putchar('\n');
+ continue;
+ }
+
+ j = 3;
+ if ( opts[i].short_opt < 256 )
+ {
+ printf (" -%c", opts[i].short_opt);
+ if ( !opts[i].long_opt )
+ {
+ if (s && *s == '|' )
+ {
+ putchar (' '); j++;
+ for (s++ ; *s && *s != '|'; s++, j++ )
+ putchar (*s);
+ if ( *s )
+ s++;
+ }
+ }
+ }
+ else
+ fputs(" ", stdout);
+ if ( opts[i].long_opt )
+ {
+ j += printf ("%c --%s", opts[i].short_opt < 256?',':' ',
+ opts[i].long_opt );
+ if (s && *s == '|' )
+ {
+ if ( *++s != '=' )
+ {
+ putchar(' ');
+ j++;
+ }
+ for ( ; *s && *s != '|'; s++, j++ )
+ putchar(*s);
+ if ( *s )
+ s++;
+ }
+ fputs (" ", stdout);
+ j += 3;
+ }
+ for (;j < indent; j++ )
+ putchar(' ');
+ if ( s )
+ {
+ if ( *s && j > indent )
+ {
+ putchar('\n');
+ for (j=0;j < indent; j++ )
+ putchar (' ');
+ }
+ for (; *s; s++ )
+ {
+ if ( *s == '\n' )
+ {
+ if ( s[1] )
+ {
+ putchar ('\n');
+ for (j=0; j < indent; j++ )
+ putchar (' ');
+ }
+ }
+ else
+ putchar (*s);
+ }
+ }
+ putchar ('\n');
+ }
+ if ( (flags & ARGPARSE_FLAG_ONEDASH) )
+ puts ("\n(A single dash may be used instead of the double ones)");
+ }
+ if ( (s=strusage(19)) )
+ {
+ /* bug reports to ... */
+ char *s2;
+
+ putchar('\n');
+ s2 = strstr (s, "@EMAIL@");
+ if (s2)
+ {
+ if (s2-s)
+ fwrite (s, s2-s, 1, stdout);
+#ifdef PACKAGE_BUGREPORT
+ fputs (PACKAGE_BUGREPORT, stdout);
+#else
+ fputs ("bug@example.org", stdout);
+#endif
+ s2 += 7;
+ if (*s2)
+ fputs (s2, stdout);
+ }
+ else
+ fputs(s, stdout);
+ }
+ fflush(stdout);
+ exit(0);
+}
+
+static void
+show_version ()
+{
+ const char *s;
+ int i;
+
+ /* Version line. */
+ fputs (strusage (11), stdout);
+ if ((s=strusage (12)))
+ printf (" (%s)", s );
+ printf (" %s\n", strusage (13) );
+ /* Additional version lines. */
+ for (i=20; i < 30; i++)
+ if ((s=strusage (i)))
+ printf ("%s\n", s );
+ /* Copyright string. */
+ if( (s=strusage (14)) )
+ printf("%s\n", s );
+ /* Licence string. */
+ if( (s=strusage (10)) )
+ printf("%s\n", s );
+ /* Copying conditions. */
+ if ( (s=strusage(15)) )
+ fputs (s, stdout);
+ /* Thanks. */
+ if ((s=strusage(18)))
+ fputs (s, stdout);
+ /* Additional program info. */
+ for (i=30; i < 40; i++ )
+ if ( (s=strusage (i)) )
+ fputs (s, stdout);
+ fflush (stdout);
+}
+
+
+void
+usage (int level)
+{
+ const char *p;
+
+ if (!level)
+ {
+ fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13), strusage (14));
+ fflush (stderr);
+ }
+ else if (level == 1)
+ {
+ p = strusage (40);
+ fputs (p, stderr);
+ if (*p && p[strlen(p)] != '\n')
+ putc ('\n', stderr);
+ exit (2);
+ }
+ else if (level == 2)
+ {
+ puts (strusage(41));
+ exit (0);
+ }
+}
+
+/* Level
+ * 0: Print copyright string to stderr
+ * 1: Print a short usage hint to stderr and terminate
+ * 2: Print a long usage hint to stdout and terminate
+ * 10: Return license info string
+ * 11: Return the name of the program
+ * 12: Return optional name of package which includes this program.
+ * 13: version string
+ * 14: copyright string
+ * 15: Short copying conditions (with LFs)
+ * 16: Long copying conditions (with LFs)
+ * 17: Optional printable OS name
+ * 18: Optional thanks list (with LFs)
+ * 19: Bug report info
+ *20..29: Additional lib version strings.
+ *30..39: Additional program info (with LFs)
+ * 40: short usage note (with LF)
+ * 41: long usage note (with LF)
+ */
+const char *
+strusage( int level )
+{
+ const char *p = strusage_handler? strusage_handler(level) : NULL;
+
+ if ( p )
+ return p;
+
+ switch ( level )
+ {
+ case 10: p = ("License GPLv3+: GNU GPL version 3 or later "
+ "<http://gnu.org/licenses/gpl.html>");
+ break;
+ case 11: p = "foo"; break;
+ case 13: p = "0.0"; break;
+ case 14: p = "Copyright (C) 2010 Free Software Foundation, Inc."; break;
+ case 15: p =
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n";
+ break;
+ case 16: p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 3 of the License, or\n"
+"(at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this software. If not, see <http://www.gnu.org/licenses/>.\n";
+ break;
+ case 40: /* short and long usage */
+ case 41: p = ""; break;
+ }
+
+ return p;
+}
+
+void
+set_strusage ( const char *(*f)( int ) )
+{
+ strusage_handler = f;
+}
+
+
+#ifdef TEST
+static struct {
+ int verbose;
+ int debug;
+ char *outfile;
+ char *crf;
+ int myopt;
+ int echo;
+ int a_long_one;
+}opt;
+
+int
+main(int argc, char **argv)
+{
+ ARGPARSE_OPTS opts[] = {
+ ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
+ ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
+ "was wir ein gegeben haben")),
+ ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
+ ARGPARSE_s_s('o', "output", 0 ),
+ ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
+ /* Note that on a non-utf8 terminal the ß might garble the output. */
+ ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
+ ARGPARSE_o_i('m', "my-option", 0),
+ ARGPARSE_s_n(500, "a-long-option", 0 ),
+ ARGPARSE_end
+ };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
+ int i;
+
+ while( arg_parse ( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break;
+ case 'v': opt.verbose++; break;
+ case 'e': opt.echo++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break;
+ default : pargs.err = ARGPARSE_PRINT_WARNING; break;
+ }
+ }
+ for(i=0; i < argc; i++ )
+ printf("%3d -> (%s)\n", i, argv[i] );
+ puts("Options:");
+ if( opt.verbose )
+ printf(" verbose=%d\n", opt.verbose );
+ if( opt.debug )
+ printf(" debug=%d\n", opt.debug );
+ if( opt.outfile )
+ printf(" outfile=`%s'\n", opt.outfile );
+ if( opt.crf )
+ printf(" crffile=`%s'\n", opt.crf );
+ if( opt.myopt )
+ printf(" myopt=%d\n", opt.myopt );
+ if( opt.a_long_one )
+ printf(" a-long-one=%d\n", opt.a_long_one );
+ if( opt.echo )
+ printf(" echo=%d\n", opt.echo );
+ return 0;
+}
+#endif
+
+/**** bottom of file ****/
diff --git a/common/argparse.h b/common/argparse.h
new file mode 100644
index 000000000..b211e5fdf
--- /dev/null
+++ b/common/argparse.h
@@ -0,0 +1,183 @@
+/* argparse.h - Argument parser for option handling.
+ * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_ARGPARSE_H
+#define LIBJNLIB_ARGPARSE_H
+
+#include <stdio.h>
+#include "types.h"
+
+typedef struct
+{
+ int *argc; /* Pointer to ARGC (value subject to change). */
+ char ***argv; /* Pointer to ARGV (value subject to change). */
+ unsigned int flags; /* Global flags. May be set prior to calling the
+ parser. The parser may change the value. */
+ int err; /* Print error description for last option.
+ Either 0, ARGPARSE_PRINT_WARNING or
+ ARGPARSE_PRINT_ERROR. */
+
+ int r_opt; /* Returns option code. */
+ int r_type; /* Returns type of option value. */
+ union {
+ int ret_int;
+ long ret_long;
+ unsigned long ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+
+ struct {
+ int idx;
+ int inarg;
+ int stopped;
+ const char *last;
+ void *aliases;
+ const void *cur_alias;
+ } internal; /* Private - do not change. */
+} ARGPARSE_ARGS;
+
+typedef struct
+{
+ int short_opt;
+ const char *long_opt;
+ unsigned int flags;
+ const char *description; /* Optional option description. */
+} ARGPARSE_OPTS;
+
+
+/* Global flags (ARGPARSE_ARGS). */
+#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
+#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
+ remaining args with R_OPT set to -1. */
+#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
+#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
+#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
+#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
+#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
+
+/* Flags for each option (ARGPARSE_OPTS). The type code may be
+ ORed with the OPT flags. */
+#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
+#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
+#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
+#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
+#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
+#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
+#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
+#define ARGPARSE_OPT_COMMAND (1<<8) /* The argument is a command. */
+
+/* A set of macros to make option definitions easier to read. */
+#define ARGPARSE_x(s,l,t,f,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
+
+#define ARGPARSE_s(s,l,t,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
+#define ARGPARSE_s_n(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_NONE, (d) }
+#define ARGPARSE_s_i(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_INT, (d) }
+#define ARGPARSE_s_s(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_STRING, (d) }
+#define ARGPARSE_s_l(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_LONG, (d) }
+#define ARGPARSE_s_u(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
+
+#define ARGPARSE_o(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
+
+#define ARGPARSE_p(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_op(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_c(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
+
+
+#define ARGPARSE_group(s,d) \
+ { (s), NULL, 0, (d) }
+
+#define ARGPARSE_end() { 0, NULL, 0, NULL }
+
+
+/* Other constants. */
+#define ARGPARSE_PRINT_WARNING 1
+#define ARGPARSE_PRINT_ERROR 2
+
+
+/* Error values. */
+#define ARGPARSE_IS_ARG (-1)
+#define ARGPARSE_INVALID_OPTION (-2)
+#define ARGPARSE_MISSING_ARG (-3)
+#define ARGPARSE_KEYWORD_TOO_LONG (-4)
+#define ARGPARSE_READ_ERROR (-5)
+#define ARGPARSE_UNEXPECTED_ARG (-6)
+#define ARGPARSE_INVALID_COMMAND (-7)
+#define ARGPARSE_AMBIGUOUS_OPTION (-8)
+#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
+#define ARGPARSE_INVALID_ALIAS (-10)
+#define ARGPARSE_OUT_OF_CORE (-11)
+
+
+int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+int optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+void usage( int level );
+const char *strusage( int level );
+void set_strusage( const char *(*f)( int ) );
+
+#endif /*LIBJNLIB_ARGPARSE_H*/
diff --git a/common/audit.h b/common/audit.h
index 28d1edbd1..8f413aa30 100644
--- a/common/audit.h
+++ b/common/audit.h
@@ -22,7 +22,7 @@
#include <ksba.h>
-#include "estream.h"
+#include "../common/estream.h"
struct audit_ctx_s;
typedef struct audit_ctx_s *audit_ctx_t;
diff --git a/common/dotlock.c b/common/dotlock.c
new file mode 100644
index 000000000..0d5a7bce9
--- /dev/null
+++ b/common/dotlock.c
@@ -0,0 +1,713 @@
+/* dotlock.c - dotfile locking
+ * Copyright (C) 1998, 2000, 2001, 2003, 2004,
+ * 2005, 2006, 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef HAVE_DOSISH_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else
+# include <sys/utsname.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#include "libjnlib-config.h"
+#include "stringhelp.h"
+#include "dotlock.h"
+#include "utf8conv.h"
+
+#if !defined(DIRSEP_C) && !defined(EXTSEP_C) \
+ && !defined(DIRSEP_S) && !defined(EXTSEP_S)
+#ifdef HAVE_DOSISH_SYSTEM
+#define DIRSEP_C '\\'
+#define EXTSEP_C '.'
+#define DIRSEP_S "\\"
+#define EXTSEP_S "."
+#else
+#define DIRSEP_C '/'
+#define EXTSEP_C '.'
+#define DIRSEP_S "/"
+#define EXTSEP_S "."
+#endif
+#endif
+
+
+/* The object describing a lock. */
+struct dotlock_handle
+{
+ struct dotlock_handle *next;
+ char *lockname; /* Name of the actual lockfile. */
+ int locked; /* Lock status. */
+ int disable; /* If true, locking is disabled. */
+
+#ifdef HAVE_DOSISH_SYSTEM
+ HANDLE lockhd; /* The W32 handle of the lock file. */
+#else
+ char *tname; /* Name of the lockfile template. */
+ size_t nodename_off; /* Offset in TNAME of the nodename part. */
+ size_t nodename_len; /* Length of the nodename part. */
+#endif /* HAVE_DOSISH_SYSTEM */
+};
+
+
+/* A list of of all lock handles. */
+static volatile dotlock_t all_lockfiles;
+
+/* If this has the value true all locking is disabled. */
+static int never_lock;
+
+
+/* Local protototypes. */
+#ifndef HAVE_DOSISH_SYSTEM
+static int read_lockfile (dotlock_t h, int *same_node);
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+
+
+
+/* Entirely disable all locking. This function should be called
+ before any locking is done. It may be called right at startup of
+ the process as it only sets a global value. */
+void
+disable_dotlock(void)
+{
+ never_lock = 1;
+}
+
+
+
+/* Create a lockfile for a file name FILE_TO_LOCK and returns an
+ object of type dotlock_t which may be used later to actually acquire
+ the lock. A cleanup routine gets installed to cleanup left over
+ locks or other files used internally by the lock mechanism.
+
+ Calling this function with NULL does only install the atexit
+ handler and may thus be used to assure that the cleanup is called
+ after all other atexit handlers.
+
+ This function creates a lock file in the same directory as
+ FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
+ POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
+ used.
+
+ The function returns an new handle which needs to be released using
+ destroy_dotlock but gets also released at the termination of the
+ process. On error NULL is returned.
+ */
+dotlock_t
+create_dotlock (const char *file_to_lock)
+{
+ static int initialized;
+ dotlock_t h;
+#ifndef HAVE_DOSISH_SYSTEM
+ int fd = -1;
+ char pidstr[16];
+ const char *nodename;
+ const char *dirpart;
+ int dirpartlen;
+ struct utsname utsbuf;
+ size_t tnamelen;
+#endif
+
+ if ( !initialized )
+ {
+ atexit (dotlock_remove_lockfiles);
+ initialized = 1;
+ }
+
+ if ( !file_to_lock )
+ return NULL; /* Only initialization was requested. */
+
+ h = jnlib_calloc (1, sizeof *h);
+ if (!h)
+ return NULL;
+
+ if (never_lock)
+ {
+ h->disable = 1;
+#ifdef _REENTRANT
+ /* fixme: aquire mutex on all_lockfiles */
+#endif
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+ return h;
+ }
+
+#ifndef HAVE_DOSISH_SYSTEM
+ /*
+ This is the POSIX version which uses a temporary file and the
+ link system call to make locking an atomic operation.
+ */
+
+ snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
+
+ /* Create a temporary file. */
+ if ( uname ( &utsbuf ) )
+ nodename = "unknown";
+ else
+ nodename = utsbuf.nodename;
+
+#ifdef __riscos__
+ {
+ char *iter = (char *) nodename;
+ for (; iter[0]; iter++)
+ if (iter[0] == '.')
+ iter[0] = '/';
+ }
+#endif /* __riscos__ */
+
+ if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
+ {
+ dirpart = EXTSEP_S;
+ dirpartlen = 1;
+ }
+ else
+ {
+ dirpartlen = dirpart - file_to_lock;
+ dirpart = file_to_lock;
+ }
+
+#ifdef _REENTRANT
+ /* fixme: aquire mutex on all_lockfiles */
+#endif
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10;
+ h->tname = jnlib_malloc (tnamelen + 1);
+ if (!h->tname)
+ {
+ all_lockfiles = h->next;
+ jnlib_free (h);
+ return NULL;
+ }
+ h->nodename_len = strlen (nodename);
+
+#ifndef __riscos__
+ snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
+ h->nodename_off = strlen (h->tname);
+ snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
+ "%s.%d", nodename, (int)getpid ());
+#else /* __riscos__ */
+ snprintf (h->tname, tnamelen, "%.*s.lk%p/", dirpartlen, dirpart, h );
+ h->nodename_off = strlen (h->tname);
+ snprintf (h->tname+h->nodename_off, tnamelen - h->modename_off,
+ "%s/%d", nodename, (int)getpid () );
+#endif /* __riscos__ */
+
+ do
+ {
+ jnlib_set_errno (0);
+ fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+ }
+ while (fd == -1 && errno == EINTR);
+
+ if ( fd == -1 )
+ {
+ all_lockfiles = h->next;
+ log_error (_("failed to create temporary file `%s': %s\n"),
+ h->tname, strerror(errno));
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+ }
+ if ( write (fd, pidstr, 11 ) != 11 )
+ goto write_failed;
+ if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
+ goto write_failed;
+ if ( write (fd, "\n", 1 ) != 1 )
+ goto write_failed;
+ if ( close (fd) )
+ goto write_failed;
+
+# ifdef _REENTRANT
+ /* release mutex */
+# endif
+ h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
+ if (!h->lockname)
+ {
+ all_lockfiles = h->next;
+ unlink (h->tname);
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+ }
+ strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
+ return h;
+
+ write_failed:
+ all_lockfiles = h->next;
+# ifdef _REENTRANT
+ /* fixme: release mutex */
+# endif
+ log_error ( _("error writing to `%s': %s\n"), h->tname, strerror(errno) );
+ close (fd);
+ unlink (h->tname);
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+
+#else /* HAVE_DOSISH_SYSTEM */
+
+ /* The Windows version does not need a temporary file but uses the
+ plain lock file along with record locking. We create this file
+ here so that we later do only need to do the file locking. For
+ error reporting it is useful to keep the name of the file in the
+ handle. */
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
+ if (!h->lockname)
+ {
+ all_lockfiles = h->next;
+ jnlib_free (h);
+ return NULL;
+ }
+ strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
+
+ /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
+ along with FILE_SHARE_DELETE but that does not work due to a race
+ condition: Despite the OPEN_ALWAYS flag CreateFile may return an
+ error and we can't reliable create/open the lock file unless we
+ would wait here until it works - however there are other valid
+ reasons why a lock file can't be created and thus the process
+ would not stop as expected but spin til until Windows crashes.
+ Our solution is to keep the lock file open; that does not
+ harm. */
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wname = utf8_to_wchar (h->lockname);
+
+ h->lockhd = INVALID_HANDLE_VALUE;
+ if (wname)
+ h->lockhd = CreateFile (wname,
+#else
+ h->lockhd = CreateFile (h->lockname,
+#endif
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, 0, NULL);
+#ifdef HAVE_W32CE_SYSTEM
+ jnlib_free (wname);
+#endif
+ }
+ if (h->lockhd == INVALID_HANDLE_VALUE)
+ {
+ log_error (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
+ all_lockfiles = h->next;
+ jnlib_free (h->lockname);
+ jnlib_free (h);
+ return NULL;
+ }
+ return h;
+
+#endif /* HAVE_DOSISH_SYSTEM */
+}
+
+
+/* Destroy the local handle H and release the lock. */
+void
+destroy_dotlock (dotlock_t h)
+{
+ dotlock_t hprev, htmp;
+
+ if ( !h )
+ return;
+
+ /* First remove the handle from our global list of all locks. */
+ for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
+ if (htmp == h)
+ {
+ if (hprev)
+ hprev->next = htmp->next;
+ else
+ all_lockfiles = htmp->next;
+ h->next = NULL;
+ break;
+ }
+
+ /* Then destroy the lock. */
+ if (!h->disable)
+ {
+#ifdef HAVE_DOSISH_SYSTEM
+ if (h->locked)
+ {
+ UnlockFile (h->lockhd, 0, 0, 1, 0);
+ }
+ CloseHandle (h->lockhd);
+#else /* !HAVE_DOSISH_SYSTEM */
+ if (h->locked && h->lockname)
+ unlink (h->lockname);
+ if (h->tname)
+ unlink (h->tname);
+ jnlib_free (h->tname);
+#endif /* HAVE_DOSISH_SYSTEM */
+ jnlib_free (h->lockname);
+ }
+ jnlib_free(h);
+}
+
+
+#ifndef HAVE_DOSISH_SYSTEM
+static int
+maybe_deadlock (dotlock_t h)
+{
+ dotlock_t r;
+
+ for ( r=all_lockfiles; r; r = r->next )
+ {
+ if ( r != h && r->locked )
+ return 1;
+ }
+ return 0;
+}
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+
+
+/* Do a lock on H. A TIMEOUT of 0 returns immediately, -1 waits
+ forever (hopefully not), other values are reserved (should then be
+ timeouts in milliseconds). Returns: 0 on success */
+int
+make_dotlock (dotlock_t h, long timeout)
+{
+ int backoff = 0;
+#ifndef HAVE_DOSISH_SYSTEM
+ int pid;
+ const char *maybe_dead="";
+ int same_node;
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+ if ( h->disable )
+ return 0; /* Locks are completely disabled. Return success. */
+
+ if ( h->locked )
+ {
+#ifndef __riscos__
+ log_debug ("Oops, `%s' is already locked\n", h->lockname);
+#endif /* !__riscos__ */
+ return 0;
+ }
+
+ for (;;)
+ {
+#ifndef HAVE_DOSISH_SYSTEM
+# ifndef __riscos__
+ if ( !link(h->tname, h->lockname) )
+ {
+ /* fixme: better use stat to check the link count */
+ h->locked = 1;
+ return 0; /* okay */
+ }
+ if ( errno != EEXIST )
+ {
+ log_error ( "lock not made: link() failed: %s\n", strerror(errno) );
+ return -1;
+ }
+# else /* __riscos__ */
+ if ( !renamefile(h->tname, h->lockname) )
+ {
+ h->locked = 1;
+ return 0; /* okay */
+ }
+ if ( errno != EEXIST )
+ {
+ log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
+ return -1;
+ }
+# endif /* __riscos__ */
+
+ if ( (pid = read_lockfile (h, &same_node)) == -1 )
+ {
+ if ( errno != ENOENT )
+ {
+ log_info ("cannot read lockfile\n");
+ return -1;
+ }
+ log_info( "lockfile disappeared\n");
+ continue;
+ }
+ else if ( pid == getpid() && same_node )
+ {
+ log_info( "Oops: lock already held by us\n");
+ h->locked = 1;
+ return 0; /* okay */
+ }
+ else if ( same_node && kill (pid, 0) && errno == ESRCH )
+ {
+# ifndef __riscos__
+ log_info (_("removing stale lockfile (created by %d)\n"), pid );
+ unlink (h->lockname);
+ continue;
+# else /* __riscos__ */
+ /* Under RISCOS we are *pretty* sure that the other task
+ is dead and therefore we remove the stale lock file. */
+ maybe_dead = _(" - probably dead - removing lock");
+ unlink(h->lockname);
+# endif /* __riscos__ */
+ }
+
+ if ( timeout == -1 )
+ {
+ /* Wait until lock has been released. */
+ struct timeval tv;
+
+ log_info (_("waiting for lock (held by %d%s) %s...\n"),
+ pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
+
+
+ /* We can't use sleep, cause signals may be blocked. */
+ tv.tv_sec = 1 + backoff;
+ tv.tv_usec = 0;
+ select(0, NULL, NULL, NULL, &tv);
+ if ( backoff < 10 )
+ backoff++ ;
+ }
+ else
+ return -1;
+#else /*HAVE_DOSISH_SYSTEM*/
+ int w32err;
+
+ if (LockFile (h->lockhd, 0, 0, 1, 0))
+ {
+ h->locked = 1;
+ return 0; /* okay */
+ }
+ w32err = GetLastError ();
+ if (w32err != ERROR_LOCK_VIOLATION)
+ {
+ log_error (_("lock `%s' not made: %s\n"),
+ h->lockname, w32_strerror (w32err));
+ return -1;
+ }
+
+ if ( timeout == -1 )
+ {
+ /* Wait until lock has been released. */
+ log_info (_("waiting for lock %s...\n"), h->lockname);
+ Sleep ((1 + backoff)*1000);
+ if ( backoff < 10 )
+ backoff++ ;
+ }
+ else
+ return -1;
+#endif /*HAVE_DOSISH_SYSTEM*/
+ }
+ /*NOTREACHED*/
+}
+
+
+/* Release a lock. Returns 0 on success. */
+int
+release_dotlock (dotlock_t h)
+{
+#ifndef HAVE_DOSISH_SYSTEM
+ int pid, same_node;
+#endif
+
+ /* To avoid atexit race conditions we first check whether there are
+ any locks left. It might happen that another atexit handler
+ tries to release the lock while the atexit handler of this module
+ already ran and thus H is undefined. */
+ if (!all_lockfiles)
+ return 0;
+
+ if ( h->disable )
+ return 0;
+
+ if ( !h->locked )
+ {
+ log_debug("Oops, `%s' is not locked\n", h->lockname);
+ return 0;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
+ {
+ log_error ("release_dotlock: error removing lockfile `%s': %s\n",
+ h->lockname, w32_strerror (-1));
+ return -1;
+ }
+#else
+
+ pid = read_lockfile (h, &same_node);
+ if ( pid == -1 )
+ {
+ log_error( "release_dotlock: lockfile error\n");
+ return -1;
+ }
+ if ( pid != getpid() || !same_node )
+ {
+ log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
+ return -1;
+ }
+
+#ifndef __riscos__
+ if ( unlink( h->lockname ) )
+ {
+ log_error ("release_dotlock: error removing lockfile `%s'\n",
+ h->lockname);
+ return -1;
+ }
+ /* Fixme: As an extra check we could check whether the link count is
+ now really at 1. */
+#else /* __riscos__ */
+ if ( renamefile (h->lockname, h->tname) )
+ {
+ log_error ("release_dotlock: error renaming lockfile `%s' to `%s'\n",
+ h->lockname, h->tname);
+ return -1;
+ }
+#endif /* __riscos__ */
+
+#endif /* !HAVE_DOSISH_SYSTEM */
+ h->locked = 0;
+ return 0;
+}
+
+
+/* Read the lock file and return the pid, returns -1 on error. True
+ will be stored in the integer at address SAME_NODE if the lock file
+ has been created on the same node. */
+#ifndef HAVE_DOSISH_SYSTEM
+static int
+read_lockfile (dotlock_t h, int *same_node )
+{
+ char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
+ name are usually shorter. */
+ int fd;
+ int pid = -1;
+ char *buffer, *p;
+ size_t expected_len;
+ int res, nread;
+
+ *same_node = 0;
+ expected_len = 10 + 1 + h->nodename_len + 1;
+ if ( expected_len >= sizeof buffer_space)
+ {
+ buffer = jnlib_malloc (expected_len);
+ if (!buffer)
+ return -1;
+ }
+ else
+ buffer = buffer_space;
+
+ if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
+ {
+ int e = errno;
+ log_info ("error opening lockfile `%s': %s\n",
+ h->lockname, strerror(errno) );
+ if (buffer != buffer_space)
+ jnlib_free (buffer);
+ jnlib_set_errno (e); /* Need to return ERRNO here. */
+ return -1;
+ }
+
+ p = buffer;
+ nread = 0;
+ do
+ {
+ res = read (fd, p, expected_len - nread);
+ if (res == -1 && errno == EINTR)
+ continue;
+ if (res < 0)
+ {
+ log_info ("error reading lockfile `%s'", h->lockname );
+ close (fd);
+ if (buffer != buffer_space)
+ jnlib_free (buffer);
+ jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
+ return -1;
+ }
+ p += res;
+ nread += res;
+ }
+ while (res && nread != expected_len);
+ close(fd);
+
+ if (nread < 11)
+ {
+ log_info ("invalid size of lockfile `%s'", h->lockname );
+ if (buffer != buffer_space)
+ jnlib_free (buffer);
+ jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
+ return -1;
+ }
+
+ if (buffer[10] != '\n'
+ || (buffer[10] = 0, pid = atoi (buffer)) == -1
+#ifndef __riscos__
+ || !pid
+#else /* __riscos__ */
+ || (!pid && riscos_getpid())
+#endif /* __riscos__ */
+ )
+ {
+ log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
+ if (buffer != buffer_space)
+ jnlib_free (buffer);
+ jnlib_set_errno (0);
+ return -1;
+ }
+
+ if (nread == expected_len
+ && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
+ && buffer[11+h->nodename_len] == '\n')
+ *same_node = 1;
+
+ if (buffer != buffer_space)
+ jnlib_free (buffer);
+ return pid;
+}
+#endif /* !HAVE_DOSISH_SYSTEM */
+
+
+/* Remove all lockfiles. This is usually called by the atexit handler
+ installed by this module but may also be called by other
+ termination handlers. */
+void
+dotlock_remove_lockfiles (void)
+{
+ dotlock_t h, h2;
+
+ h = all_lockfiles;
+ all_lockfiles = NULL;
+
+ while ( h )
+ {
+ h2 = h->next;
+ destroy_dotlock (h);
+ h = h2;
+ }
+}
+
diff --git a/common/dotlock.h b/common/dotlock.h
new file mode 100644
index 000000000..407a80b37
--- /dev/null
+++ b/common/dotlock.h
@@ -0,0 +1,33 @@
+/* dotlock.h
+ * Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_DOTLOCK_H
+#define LIBJNLIB_DOTLOCK_H
+
+struct dotlock_handle;
+typedef struct dotlock_handle *dotlock_t;
+
+void disable_dotlock (void);
+dotlock_t create_dotlock (const char *file_to_lock);
+void destroy_dotlock ( dotlock_t h );
+int make_dotlock (dotlock_t h, long timeout);
+int release_dotlock (dotlock_t h);
+void dotlock_remove_lockfiles (void);
+
+#endif /*LIBJNLIB_DOTLOCK_H*/
diff --git a/common/dynload.h b/common/dynload.h
new file mode 100644
index 000000000..0c8a3bbaa
--- /dev/null
+++ b/common/dynload.h
@@ -0,0 +1,86 @@
+/* dynload.h - Wrapper functions for run-time dynamic loading
+ * Copyright (C) 2003, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_DYNLOAD_H
+#define LIBJNLIB_DYNLOAD_H
+
+#ifndef __MINGW32__
+# include <dlfcn.h>
+#else
+# include <windows.h>
+# include "utf8conv.h"
+# include "mischelp.h"
+# define RTLD_LAZY 0
+
+static inline void *
+dlopen (const char *name, int flag)
+{
+ void *hd;
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wname = utf8_to_wchar (name);
+ hd = wname? LoadLibrary (wname) : NULL;
+ _jnlib_free (wname);
+#else
+ hd = LoadLibrary (name);
+#endif
+ (void)flag;
+ return hd;
+}
+
+static inline void *
+dlsym (void *hd, const char *sym)
+{
+ if (hd && sym)
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wsym = utf8_to_wchar (sym);
+ void *fnc = wsym? GetProcAddress (hd, wsym) : NULL;
+ _jnlib_free (wsym);
+#else
+ void *fnc = GetProcAddress (hd, sym);
+#endif
+ if (!fnc)
+ return NULL;
+ return fnc;
+ }
+ return NULL;
+}
+
+
+static inline const char *
+dlerror (void)
+{
+ static char buf[32];
+ snprintf (buf, sizeof buf, "ec=%lu", GetLastError ());
+ return buf;
+}
+
+
+static inline int
+dlclose (void * hd)
+{
+ if (hd)
+ {
+ CloseHandle (hd);
+ return 0;
+ }
+ return -1;
+}
+# endif /*__MINGW32__*/
+#endif /*LIBJNLIB_DYNLOAD_H*/
diff --git a/common/exechelp.c b/common/exechelp.c
index 95e5b633c..f71cd7349 100644
--- a/common/exechelp.c
+++ b/common/exechelp.c
@@ -25,7 +25,9 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
-#include <signal.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
#include <unistd.h>
#include <fcntl.h>
@@ -78,6 +80,12 @@
#define X_OK F_OK
#endif /* HAVE_W32_SYSTEM */
+/* Constants not supported by WindowsCE. */
+#ifdef HAVE_W32CE_SYSTEM
+# define DETACHED_PROCESS (0)
+# define CREATE_NEW_PROCESS_GROUP (0)
+#endif
+
#ifdef HAVE_W32_SYSTEM
/* We assume that a HANDLE can be represented by an int which should
diff --git a/common/exechelp.h b/common/exechelp.h
index 06cb79c29..c5ecc0dea 100644
--- a/common/exechelp.h
+++ b/common/exechelp.h
@@ -20,7 +20,7 @@
#ifndef GNUPG_COMMON_EXECHELP_H
#define GNUPG_COMMON_EXECHELP_H
-#include "estream.h"
+#include "../common/estream.h"
/* Return the maximum number of currently allowed file descriptors.
diff --git a/common/http.h b/common/http.h
index 28a5304eb..e7120f561 100644
--- a/common/http.h
+++ b/common/http.h
@@ -22,7 +22,7 @@
#include <gpg-error.h>
#ifdef HTTP_USE_ESTREAM
-#include "estream.h"
+#include "../common/estream.h"
#endif
struct uri_tuple_s {
diff --git a/common/i18n.h b/common/i18n.h
index 7405f9a55..abb8bd83e 100644
--- a/common/i18n.h
+++ b/common/i18n.h
@@ -16,7 +16,7 @@
#ifdef USE_SIMPLE_GETTEXT
-# include "../jnlib/w32help.h"
+# include "../common/w32help.h"
# define _(a) gettext (a)
# define N_(a) (a)
#else
diff --git a/common/init.c b/common/init.c
index 5425acee8..d8e0be7bf 100644
--- a/common/init.c
+++ b/common/init.c
@@ -31,7 +31,6 @@
#include <pth.h>
#endif
-#include "estream.h"
#include "util.h"
diff --git a/common/iobuf.c b/common/iobuf.c
index 87af2868f..441c69467 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -1156,10 +1156,10 @@ iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode)
{
iobuf_t a;
- if (fd == -1)
+ if (fd == GNUPG_INVALID_FD)
a = iobuf_open (fname);
else
- a = iobuf_fdopen_nc (fd, mode);
+ a = iobuf_fdopen_nc (FD2INT(fd), mode);
return a;
}
diff --git a/common/libjnlib-config.h b/common/libjnlib-config.h
new file mode 100644
index 000000000..621e89feb
--- /dev/null
+++ b/common/libjnlib-config.h
@@ -0,0 +1,99 @@
+/* libjnlib-config.h - local configuration of the jnlib functions
+ * Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/****************
+ * This header is to be included only by the files in this directory
+ * it should not be used by other modules.
+ */
+
+#ifndef LIBJNLIB_CONFIG_H
+#define LIBJNLIB_CONFIG_H
+
+#include <gcrypt.h> /* gcry_malloc & Cie. */
+#include "logging.h"
+
+/* We require support for utf-8 conversion. */
+#define JNLIB_NEED_UTF8CONV 1
+
+
+
+#if !defined(JNLIB_NEED_UTF8CONV) && defined(HAVE_W32_SYSTEM)
+#define JNLIB_NEED_UTF8CONV 1
+#endif
+
+/* Gettext stuff */
+#ifdef USE_SIMPLE_GETTEXT
+# include <gpg-error.h>
+# define _(a) gettext (a)
+# define N_(a) (a)
+
+#else
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(a) gettext (a)
+# ifdef gettext_noop
+# define N_(a) gettext_noop (a)
+# else
+# define N_(a) (a)
+# endif
+#else
+# define _(a) (a)
+# define N_(a) (a)
+#endif
+#endif /* !USE_SIMPLE_GETTEXT */
+
+/* Malloc functions to be used by jnlib. */
+#define jnlib_malloc(a) gcry_malloc( (a) )
+#define jnlib_calloc(a,b) gcry_calloc( (a), (b) )
+#define jnlib_realloc(a,b) gcry_realloc( (a), (b) )
+#define jnlib_strdup(a) gcry_strdup( (a) )
+#define jnlib_xmalloc(a) gcry_xmalloc( (a) )
+#define jnlib_xcalloc(a,b) gcry_xcalloc( (a), (b) )
+#define jnlib_xrealloc(a,n) gcry_xrealloc( (a), (n) )
+#define jnlib_xstrdup(a) gcry_xstrdup( (a) )
+#define jnlib_free(a) gcry_free( (a) )
+
+/* Logging functions to be used by jnlib. */
+#define jnlib_log_debug log_debug
+#define jnlib_log_info log_info
+#define jnlib_log_error log_error
+#define jnlib_log_fatal log_fatal
+#define jnlib_log_bug log_bug
+
+/* Wrapper to set ERRNO. */
+#ifdef HAVE_W32CE_SYSTEM
+# define jnlib_set_errno(e) gpg_err_set_errno ((e))
+#else
+# define jnlib_set_errno(e) do { errno = (e); } while (0)
+#endif
+
+/* Dummy replacement for getenv. */
+#ifndef HAVE_GETENV
+#define getenv(a) (NULL)
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+#define getpid() GetCurrentProcessId ()
+#endif
+
+#endif /*LIBJNUTIL_CONFIG_H*/
diff --git a/common/localename.c b/common/localename.c
index cb7fcc2f7..5c46ddd34 100644
--- a/common/localename.c
+++ b/common/localename.c
@@ -30,7 +30,7 @@
#include <locale.h>
#endif
-#include "../jnlib/w32help.h"
+#include "../common/w32help.h"
/* XPG3 defines the result of 'setlocale (category, NULL)' as:
"Directs 'setlocale()' to query 'category' and return the current
@@ -101,7 +101,7 @@ gnupg_messages_locale_name (void)
const char *s;
#ifdef HAVE_W32_SYSTEM
- /* We use the localname function from ../jnlib/w32-gettext.c. */
+ /* We use the localname function from ../common/w32-gettext.c. */
s = gettext_localename ();
#else
s = do_nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
diff --git a/common/logging.c b/common/logging.c
new file mode 100644
index 000000000..028697b78
--- /dev/null
+++ b/common/logging.c
@@ -0,0 +1,651 @@
+/* logging.c - Useful logging functions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ * 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif /*!HAVE_W32_SYSTEM*/
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+
+
+#define JNLIB_NEED_LOG_LOGV 1
+#define JNLIB_NEED_AFLOCAL 1
+#include "libjnlib-config.h"
+#include "logging.h"
+
+#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
+#define USE_FUNWRITER 1
+#endif
+
+#ifdef HAVE_FOPENCOOKIE
+typedef ssize_t my_funopen_hook_ret_t;
+typedef size_t my_funopen_hook_size_t;
+#else
+typedef int my_funopen_hook_ret_t;
+typedef int my_funopen_hook_size_t;
+#endif
+
+
+static FILE *logstream;
+static int log_socket = -1;
+static char prefix_buffer[80];
+static int with_time;
+static int with_prefix;
+static int with_pid;
+static unsigned long (*get_tid_callback)(void);
+static int running_detached;
+static int force_prefixes;
+
+static int missing_lf;
+static int errorcount;
+
+
+int
+log_get_errorcount (int clear)
+{
+ int n = errorcount;
+ if( clear )
+ errorcount = 0;
+ return n;
+}
+
+void
+log_inc_errorcount (void)
+{
+ errorcount++;
+}
+
+
+/* The follwing 3 functions are used by funopen to write logs to a
+ socket. */
+#ifdef USE_FUNWRITER
+struct fun_cookie_s {
+ int fd;
+ int quiet;
+ int want_socket;
+ int is_socket;
+ char name[1];
+};
+
+/* Write NBYTES of BUFFER to file descriptor FD. */
+static int
+writen (int fd, const void *buffer, size_t nbytes)
+{
+ const char *buf = buffer;
+ size_t nleft = nbytes;
+ int nwritten;
+
+ while (nleft > 0)
+ {
+ nwritten = write (fd, buf, nleft);
+ if (nwritten < 0 && errno == EINTR)
+ continue;
+ if (nwritten < 0)
+ return -1;
+ nleft -= nwritten;
+ buf = buf + nwritten;
+ }
+
+ return 0;
+}
+
+
+static my_funopen_hook_ret_t
+fun_writer (void *cookie_arg, const char *buffer, my_funopen_hook_size_t size)
+{
+ struct fun_cookie_s *cookie = cookie_arg;
+
+ /* Note that we always try to reconnect to the socket but print
+ error messages only the first time an error occured. If
+ RUNNING_DETACHED is set we don't fall back to stderr and even do
+ not print any error messages. This is needed because detached
+ processes often close stderr and by writing to file descriptor 2
+ we might send the log message to a file not intended for logging
+ (e.g. a pipe or network connection). */
+ if (cookie->want_socket && cookie->fd == -1)
+ {
+ /* Not yet open or meanwhile closed due to an error. */
+ cookie->is_socket = 0;
+ cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+ if (cookie->fd == -1)
+ {
+ if (!cookie->quiet && !running_detached
+ && isatty (fileno (stderr)))
+ fprintf (stderr, "failed to create socket for logging: %s\n",
+ strerror(errno));
+ }
+ else
+ {
+ struct sockaddr_un addr;
+ size_t addrlen;
+
+ memset (&addr, 0, sizeof addr);
+ addr.sun_family = PF_LOCAL;
+ strncpy (addr.sun_path, cookie->name, sizeof (addr.sun_path)-1);
+ addr.sun_path[sizeof (addr.sun_path)-1] = 0;
+ addrlen = SUN_LEN (&addr);
+
+ if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1)
+ {
+ if (!cookie->quiet && !running_detached
+ && isatty (fileno (stderr)))
+ fprintf (stderr, "can't connect to `%s': %s\n",
+ cookie->name, strerror(errno));
+ close (cookie->fd);
+ cookie->fd = -1;
+ }
+ }
+
+ if (cookie->fd == -1)
+ {
+ if (!running_detached)
+ {
+ /* Due to all the problems with apps not running
+ detached but being called with stderr closed or
+ used for a different purposes, it does not make
+ sense to switch to stderr. We therefore disable it. */
+ if (!cookie->quiet)
+ {
+ /* fputs ("switching logging to stderr\n", stderr);*/
+ cookie->quiet = 1;
+ }
+ cookie->fd = -1; /*fileno (stderr);*/
+ }
+ }
+ else /* Connection has been established. */
+ {
+ cookie->quiet = 0;
+ cookie->is_socket = 1;
+ }
+ }
+
+ log_socket = cookie->fd;
+ if (cookie->fd != -1 && !writen (cookie->fd, buffer, size))
+ return (my_funopen_hook_ret_t)size; /* Okay. */
+
+ if (!running_detached && cookie->fd != -1
+ && isatty (fileno (stderr)))
+ {
+ if (*cookie->name)
+ fprintf (stderr, "error writing to `%s': %s\n",
+ cookie->name, strerror(errno));
+ else
+ fprintf (stderr, "error writing to file descriptor %d: %s\n",
+ cookie->fd, strerror(errno));
+ }
+ if (cookie->is_socket && cookie->fd != -1)
+ {
+ close (cookie->fd);
+ cookie->fd = -1;
+ log_socket = -1;
+ }
+
+ return (my_funopen_hook_ret_t)size;
+}
+
+static int
+fun_closer (void *cookie_arg)
+{
+ struct fun_cookie_s *cookie = cookie_arg;
+
+ if (cookie->fd != -1 && cookie->fd != 2)
+ close (cookie->fd);
+ jnlib_free (cookie);
+ log_socket = -1;
+ return 0;
+}
+#endif /*USE_FUNWRITER*/
+
+
+
+/* Common function to either set the logging to a file or a file
+ descriptor. */
+static void
+set_file_fd (const char *name, int fd)
+{
+ FILE *fp;
+ int want_socket;
+#ifdef USE_FUNWRITER
+ struct fun_cookie_s *cookie;
+#endif
+
+ /* Close an open log stream. */
+ if (logstream)
+ {
+ if (logstream != stderr && logstream != stdout)
+ fclose (logstream);
+ logstream = NULL;
+ }
+
+ /* Figure out what kind of logging we want. */
+ if (name && !strcmp (name, "-"))
+ {
+ name = NULL;
+ fd = fileno (stderr);
+ }
+
+ if (name)
+ {
+ want_socket = (!strncmp (name, "socket://", 9) && name[9]);
+ if (want_socket)
+ name += 9;
+ }
+ else
+ {
+ want_socket = 0;
+ }
+
+ /* Setup a new stream. */
+#ifdef USE_FUNWRITER
+ /* The xmalloc below is justified because we can expect that this
+ function is called only during initialization and there is no
+ easy way out of this error condition. */
+ cookie = jnlib_xmalloc (sizeof *cookie + (name? strlen (name):0));
+ strcpy (cookie->name, name? name:"");
+ cookie->quiet = 0;
+ cookie->is_socket = 0;
+ cookie->want_socket = want_socket;
+ if (!name)
+ cookie->fd = fd;
+ else if (want_socket)
+ cookie->fd = -1;
+ else
+ {
+ do
+ cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
+ (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
+ while (cookie->fd == -1 && errno == EINTR);
+ }
+ log_socket = cookie->fd;
+
+#ifdef HAVE_FOPENCOOKIE
+ {
+ cookie_io_functions_t io = { NULL };
+ io.write = fun_writer;
+ io.close = fun_closer;
+
+ fp = fopencookie (cookie, "w", io);
+ }
+#else /*!HAVE_FOPENCOOKIE*/
+ fp = funopen (cookie, NULL, fun_writer, NULL, fun_closer);
+#endif /*!HAVE_FOPENCOOKIE*/
+
+#else /*!USE_FUNWRITER*/
+
+ /* The system does not feature custom streams. Thus fallback to
+ plain stdio. */
+ if (want_socket)
+ {
+ fprintf (stderr, "system does not support logging to a socket - "
+ "using stderr\n");
+ fp = stderr;
+ }
+ else if (name)
+ fp = fopen (name, "a");
+ else if (fd == 1)
+ fp = stdout;
+ else if (fd == 2)
+ fp = stderr;
+ else
+ fp = fdopen (fd, "a");
+
+ log_socket = -1;
+
+#endif /*!USE_FUNWRITER*/
+
+ /* On error default to stderr. */
+ if (!fp)
+ {
+ if (name)
+ fprintf (stderr, "failed to open log file `%s': %s\n",
+ name, strerror(errno));
+ else
+ fprintf (stderr, "failed to fdopen file descriptor %d: %s\n",
+ fd, strerror(errno));
+ /* We need to make sure that there is a log stream. We use stderr. */
+ fp = stderr;
+ }
+ else
+ setvbuf (fp, NULL, _IOLBF, 0);
+
+ logstream = fp;
+
+ /* We always need to print the prefix and the pid for socket mode,
+ so that the server reading the socket can do something
+ meaningful. */
+ force_prefixes = want_socket;
+
+ missing_lf = 0;
+}
+
+
+/* Set the file to write log to. The special names NULL and "-" may
+ be used to select stderr and names formatted like
+ "socket:///home/foo/mylogs" may be used to write the logging to the
+ socket "/home/foo/mylogs". If the connection to the socket fails
+ or a write error is detected, the function writes to stderr and
+ tries the next time again to connect the socket.
+ */
+void
+log_set_file (const char *name)
+{
+ set_file_fd (name? name: "-", -1);
+}
+
+void
+log_set_fd (int fd)
+{
+ set_file_fd (NULL, fd);
+}
+
+
+void
+log_set_get_tid_callback (unsigned long (*cb)(void))
+{
+ get_tid_callback = cb;
+}
+
+
+void
+log_set_prefix (const char *text, unsigned int flags)
+{
+ if (text)
+ {
+ strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
+ prefix_buffer[sizeof (prefix_buffer)-1] = 0;
+ }
+
+ with_prefix = (flags & JNLIB_LOG_WITH_PREFIX);
+ with_time = (flags & JNLIB_LOG_WITH_TIME);
+ with_pid = (flags & JNLIB_LOG_WITH_PID);
+ running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
+}
+
+
+const char *
+log_get_prefix (unsigned int *flags)
+{
+ if (flags)
+ {
+ *flags = 0;
+ if (with_prefix)
+ *flags |= JNLIB_LOG_WITH_PREFIX;
+ if (with_time)
+ *flags |= JNLIB_LOG_WITH_TIME;
+ if (with_pid)
+ *flags |= JNLIB_LOG_WITH_PID;
+ if (running_detached)
+ *flags |= JNLIB_LOG_RUN_DETACHED;
+ }
+ return prefix_buffer;
+}
+
+/* This function returns true if the file descriptor FD is in use for
+ logging. This is preferable over a test using log_get_fd in that
+ it allows the logging code to use more then one file descriptor. */
+int
+log_test_fd (int fd)
+{
+ if (logstream)
+ {
+ int tmp = fileno (logstream);
+ if ( tmp != -1 && tmp == fd)
+ return 1;
+ }
+ if (log_socket != -1 && log_socket == fd)
+ return 1;
+ return 0;
+}
+
+int
+log_get_fd ()
+{
+ return fileno(logstream?logstream:stderr);
+}
+
+FILE *
+log_get_stream ()
+{
+ /* FIXME: We should not return stderr here but initialize the log
+ stream properly. This might break more things than using stderr,
+ though */
+ return logstream?logstream:stderr;
+}
+
+static void
+do_logv (int level, const char *fmt, va_list arg_ptr)
+{
+ if (!logstream)
+ {
+ log_set_file (NULL); /* Make sure a log stream has been set. */
+ assert (logstream);
+ }
+
+ if (missing_lf && level != JNLIB_LOG_CONT)
+ putc('\n', logstream );
+ missing_lf = 0;
+
+ if (level != JNLIB_LOG_CONT)
+ { /* Note this does not work for multiple line logging as we would
+ * need to print to a buffer first */
+ if (with_time && !force_prefixes)
+ {
+ struct tm *tp;
+ time_t atime = time (NULL);
+
+ tp = localtime (&atime);
+ fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec );
+ }
+ if (with_prefix || force_prefixes)
+ fputs (prefix_buffer, logstream);
+ if (with_pid || force_prefixes)
+ {
+ if (get_tid_callback)
+ fprintf (logstream, "[%u.%lx]",
+ (unsigned int)getpid (), get_tid_callback ());
+ else
+ fprintf (logstream, "[%u]", (unsigned int)getpid ());
+ }
+ if (!with_time || force_prefixes)
+ putc (':', logstream);
+ /* A leading backspace suppresses the extra space so that we can
+ correctly output, programname, filename and linenumber. */
+ if (fmt && *fmt == '\b')
+ fmt++;
+ else
+ putc (' ', logstream);
+ }
+
+ switch (level)
+ {
+ case JNLIB_LOG_BEGIN: break;
+ case JNLIB_LOG_CONT: break;
+ case JNLIB_LOG_INFO: break;
+ case JNLIB_LOG_WARN: break;
+ case JNLIB_LOG_ERROR: break;
+ case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
+ case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
+ case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
+ default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
+ }
+
+
+ if (fmt)
+ {
+ vfprintf(logstream,fmt,arg_ptr) ;
+ if (*fmt && fmt[strlen(fmt)-1] != '\n')
+ missing_lf = 1;
+#ifdef HAVE_W32_SYSTEM
+ else
+ fflush (logstream);
+#endif
+ }
+
+ if (level == JNLIB_LOG_FATAL)
+ {
+ if (missing_lf)
+ putc('\n', logstream );
+ exit(2);
+ }
+ if (level == JNLIB_LOG_BUG)
+ {
+ if (missing_lf)
+ putc('\n', logstream );
+ abort();
+ }
+}
+
+static void
+do_log( int level, const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( level, fmt, arg_ptr );
+ va_end(arg_ptr);
+}
+
+
+void
+log_logv (int level, const char *fmt, va_list arg_ptr)
+{
+ do_logv (level, fmt, arg_ptr);
+}
+
+void
+log_info( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
+ va_end(arg_ptr);
+}
+
+void
+log_error( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
+ va_end(arg_ptr);
+ /* protect against counter overflow */
+ if( errorcount < 30000 )
+ errorcount++;
+}
+
+
+void
+log_fatal( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
+ va_end(arg_ptr);
+ abort(); /* never called, but it makes the compiler happy */
+}
+
+void
+log_bug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
+ va_end(arg_ptr);
+ abort(); /* never called, but it makes the compiler happy */
+}
+
+void
+log_debug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
+ va_end(arg_ptr);
+}
+
+
+void
+log_printf (const char *fmt, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, fmt);
+ do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+/* Print a hexdump of BUFFER. With TEXT of NULL print just the raw
+ dump, with TEXT just an empty string, print a trailing linefeed,
+ otherwise print an entire debug line. */
+void
+log_printhex (const char *text, const void *buffer, size_t length)
+{
+ if (text && *text)
+ log_debug ("%s ", text);
+ if (length)
+ {
+ const unsigned char *p = buffer;
+ log_printf ("%02X", *p);
+ for (length--, p++; length--; p++)
+ log_printf (" %02X", *p);
+ }
+ if (text)
+ log_printf ("\n");
+}
+
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+void
+bug_at( const char *file, int line, const char *func )
+{
+ do_log( JNLIB_LOG_BUG,
+ ("... this is a bug (%s:%d:%s)\n"), file, line, func );
+ abort(); /* never called, but it makes the compiler happy */
+}
+#else
+void
+bug_at( const char *file, int line )
+{
+ do_log( JNLIB_LOG_BUG,
+ _("you found a bug ... (%s:%d)\n"), file, line);
+ abort(); /* never called, but it makes the compiler happy */
+}
+#endif
+
diff --git a/common/logging.h b/common/logging.h
new file mode 100644
index 000000000..0b96108a8
--- /dev/null
+++ b/common/logging.h
@@ -0,0 +1,88 @@
+/* logging.h
+ * Copyright (C) 1999, 2000, 2001, 2004, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_LOGGING_H
+#define LIBJNLIB_LOGGING_H
+
+#include <stdio.h>
+#include "mischelp.h"
+
+/* Flag values for log_set_prefix. */
+#define JNLIB_LOG_WITH_PREFIX 1
+#define JNLIB_LOG_WITH_TIME 2
+#define JNLIB_LOG_WITH_PID 4
+#define JNLIB_LOG_RUN_DETACHED 256
+
+int log_get_errorcount (int clear);
+void log_inc_errorcount (void);
+void log_set_file( const char *name );
+void log_set_fd (int fd);
+void log_set_get_tid_callback (unsigned long (*cb)(void));
+void log_set_prefix (const char *text, unsigned int flags);
+const char *log_get_prefix (unsigned int *flags);
+int log_test_fd (int fd);
+int log_get_fd(void);
+FILE *log_get_stream (void);
+
+#ifdef JNLIB_GCC_M_FUNCTION
+ void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR;
+# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__ )
+#else
+ void bug_at( const char *file, int line );
+# define BUG() bug_at( __FILE__ , __LINE__ )
+#endif
+
+/* To avoid mandatory inclusion of stdarg and other stuff, do it only
+ if explicitly requested to do so. */
+#ifdef JNLIB_NEED_LOG_LOGV
+#include <stdarg.h>
+enum jnlib_log_levels {
+ JNLIB_LOG_BEGIN,
+ JNLIB_LOG_CONT,
+ JNLIB_LOG_INFO,
+ JNLIB_LOG_WARN,
+ JNLIB_LOG_ERROR,
+ JNLIB_LOG_FATAL,
+ JNLIB_LOG_BUG,
+ JNLIB_LOG_DEBUG
+};
+void log_logv (int level, const char *fmt, va_list arg_ptr);
+#endif /*JNLIB_NEED_LOG_LOGV*/
+
+
+void log_bug( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
+void log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
+void log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+void log_info( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+void log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+void log_printf( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+
+/* Print a hexdump of BUFFER. With TEXT passes as NULL print just the
+ raw dump, with TEXT being an empty string, print a trailing
+ linefeed, otherwise print an entire debug line with TEXT followed
+ by the hexdump and a final LF. */
+void log_printhex (const char *text, const void *buffer, size_t length);
+
+
+#endif /*LIBJNLIB_LOGGING_H*/
+
+
+
+
+
diff --git a/common/mischelp.c b/common/mischelp.c
new file mode 100644
index 000000000..e06be21f2
--- /dev/null
+++ b/common/mischelp.c
@@ -0,0 +1,197 @@
+/* mischelp.c - Miscellaneous helper functions
+ * Copyright (C) 1998, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else /*!HAVE_W32_SYSTEM*/
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#endif /*!HAVE_W32_SYSTEM*/
+#include <errno.h>
+
+#include "libjnlib-config.h"
+#include "stringhelp.h"
+#include "utf8conv.h"
+#include "mischelp.h"
+
+
+/* Because we can't use our jnlib_free macro in inline functions we
+ provide this wrapper. */
+void
+_jnlib_free (void *p)
+{
+ if (p)
+ jnlib_free (p);
+}
+
+
+/* Check whether the files NAME1 and NAME2 are identical. This is for
+ example achieved by comparing the inode numbers of the files. */
+int
+same_file_p (const char *name1, const char *name2)
+{
+ int yes;
+
+ /* First try a shortcut. */
+ if (!compare_filenames (name1, name2))
+ yes = 1;
+ else
+ {
+#ifdef HAVE_W32_SYSTEM
+ HANDLE file1, file2;
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+
+#ifdef HAVE_W32CE_SYSTEM
+ {
+ wchar_t *wname = utf8_to_wchar (name1);
+ if (wname)
+ file1 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ else
+ file1 = INVALID_HANDLE_VALUE;
+ jnlib_free (wname);
+ }
+#else
+ file1 = CreateFile (name1, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+#endif
+ if (file1 == INVALID_HANDLE_VALUE)
+ yes = 0; /* If we can't open the file, it is not the same. */
+ else
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ {
+ wchar_t *wname = utf8_to_wchar (name2);
+ if (wname)
+ file2 = CreateFile (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ else
+ file2 = INVALID_HANDLE_VALUE;
+ jnlib_free (wname);
+ }
+#else
+ file2 = CreateFile (name2, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+#endif
+ if (file2 == INVALID_HANDLE_VALUE)
+ yes = 0; /* If we can't open the file, it is not the same. */
+ else
+ {
+ yes = (GetFileInformationByHandle (file1, &info1)
+ && GetFileInformationByHandle (file2, &info2)
+ && info1.dwVolumeSerialNumber==info2.dwVolumeSerialNumber
+ && info1.nFileIndexHigh == info2.nFileIndexHigh
+ && info1.nFileIndexLow == info2.nFileIndexLow);
+ CloseHandle (file2);
+ }
+ CloseHandle (file1);
+ }
+#else /*!HAVE_W32_SYSTEM*/
+ struct stat info1, info2;
+
+ yes = (!stat (name1, &info1) && !stat (name2, &info2)
+ && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino);
+#endif /*!HAVE_W32_SYSTEM*/
+ }
+ return yes;
+}
+
+
+/*
+ timegm() is a GNU function that might not be available everywhere.
+ It's basically the inverse of gmtime() - you give it a struct tm,
+ and get back a time_t. It differs from mktime() in that it handles
+ the case where the struct tm is UTC and the local environment isn't.
+
+ Note, that this replacement implementation might not be thread-safe!
+
+ Some BSDs don't handle the putenv("foo") case properly, so we use
+ unsetenv if the platform has it to remove environment variables.
+*/
+#ifndef HAVE_TIMEGM
+time_t
+timegm (struct tm *tm)
+{
+#ifdef HAVE_W32_SYSTEM
+ /* This one is thread safe. */
+ SYSTEMTIME st;
+ FILETIME ft;
+ unsigned long long cnsecs;
+
+ st.wYear = tm->tm_year + 1900;
+ st.wMonth = tm->tm_mon + 1;
+ st.wDay = tm->tm_mday;
+ st.wHour = tm->tm_hour;
+ st.wMinute = tm->tm_min;
+ st.wSecond = tm->tm_sec;
+ st.wMilliseconds = 0; /* Not available. */
+ st.wDayOfWeek = 0; /* Ignored. */
+
+ /* System time is UTC thus the conversion is pretty easy. */
+ if (!SystemTimeToFileTime (&st, &ft))
+ {
+ jnlib_set_errno (EINVAL);
+ return (time_t)(-1);
+ }
+
+ cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
+ | ft.dwLowDateTime);
+ cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
+ return (time_t)(cnsecs / 10000000ULL);
+
+#else /* (Non thread safe implementation!) */
+
+ time_t answer;
+ char *zone;
+
+ zone=getenv("TZ");
+ putenv("TZ=UTC");
+ tzset();
+ answer=mktime(tm);
+ if(zone)
+ {
+ static char *old_zone;
+
+ if (!old_zone)
+ {
+ old_zone = malloc(3+strlen(zone)+1);
+ if (old_zone)
+ {
+ strcpy(old_zone,"TZ=");
+ strcat(old_zone,zone);
+ }
+ }
+ if (old_zone)
+ putenv (old_zone);
+ }
+ else
+#ifdef HAVE_UNSETENV
+ unsetenv("TZ");
+#else
+ putenv("TZ");
+#endif
+
+ tzset();
+ return answer;
+#endif
+}
+#endif /*!HAVE_TIMEGM*/
+
diff --git a/common/mischelp.h b/common/mischelp.h
new file mode 100644
index 000000000..5a0132aa6
--- /dev/null
+++ b/common/mischelp.h
@@ -0,0 +1,102 @@
+/* mischelp.h - Miscellaneous helper macros and functions
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003,
+ * 2006, 2007, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_MISCHELP_H
+#define LIBJNLIB_MISCHHELP_H
+
+
+/* Because we can't use the internal jnlib_free macro in inline
+ functions we provide a wrapper function as well. */
+void _jnlib_free (void *p);
+
+/* Check whether the files NAME1 and NAME2 are identical. This is for
+ example achieved by comparing the inode numbers of the files. */
+int same_file_p (const char *name1, const char *name2);
+
+
+#ifndef HAVE_TIMEGM
+#include <time.h>
+time_t timegm (struct tm *tm);
+#endif /*!HAVE_TIMEGM*/
+
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+# define JNLIB_GCC_M_FUNCTION 1
+# define JNLIB_GCC_A_NR __attribute__ ((noreturn))
+# define JNLIB_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a)))
+# define JNLIB_GCC_A_NR_PRINTF( f, a ) \
+ __attribute__ ((noreturn, format (printf,f,a)))
+#else
+# define JNLIB_GCC_A_NR
+# define JNLIB_GCC_A_PRINTF( f, a )
+# define JNLIB_GCC_A_NR_PRINTF( f, a )
+#endif
+
+
+/* To avoid that a compiler optimizes certain memset calls away, these
+ macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+ volatile char *_vptr=(volatile char *)(_ptr); \
+ size_t _vlen=(_len); \
+ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+ } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+
+/* Include hacks which are mainly required for Slowaris. */
+#ifdef JNLIB_NEED_AFLOCAL
+#ifndef HAVE_W32_SYSTEM
+# include <sys/socket.h>
+# include <sys/un.h>
+#else
+# include <windows.h>
+#endif
+
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+# define PF_LOCAL PF_UNIX
+# else
+# define PF_LOCAL AF_UNIX
+# endif
+#endif /*PF_LOCAL*/
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif /*AF_UNIX*/
+
+/* We used to avoid this macro in GnuPG and inlined the AF_LOCAL name
+ length computation directly with the little twist of adding 1 extra
+ byte. It seems that this was needed once on an old HP/UX box and
+ there are also rumours that 4.3 Reno and DEC systems need it. This
+ one-off buglet did not harm any current system until it came to Mac
+ OS X where the kernel (as of May 2009) exhibited a strange bug: The
+ systems basically froze in the connect call if the passed name
+ contained an invalid directory part. Ignore the old Unices. */
+#ifndef SUN_LEN
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif /*SUN_LEN*/
+#endif /*JNLIB_NEED_AFLOCAL*/
+
+
+#endif /*LIBJNLIB_MISCHELP_H*/
diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c
index 3598b3598..fd48b6f5a 100644
--- a/common/simple-pwquery.c
+++ b/common/simple-pwquery.c
@@ -41,9 +41,9 @@
#endif
#define JNLIB_NEED_AFLOCAL
-#include "../jnlib/mischelp.h"
+#include "../common/mischelp.h"
#ifdef HAVE_W32_SYSTEM
-#include "../jnlib/w32-afunix.h"
+#include "../common/w32-afunix.h"
#endif
diff --git a/common/simple-pwquery.h b/common/simple-pwquery.h
index 8de9b1bd2..edd834ef4 100644
--- a/common/simple-pwquery.h
+++ b/common/simple-pwquery.h
@@ -24,7 +24,7 @@
/* Include whatever files you need. */
#include <gcrypt.h>
-#include "../jnlib/logging.h"
+#include "../common/logging.h"
/* Try to write error message using the standard log mechanism. The
current implementation requires that the HAVE_JNLIB_LOGGING is also
diff --git a/common/stringhelp.c b/common/stringhelp.c
new file mode 100644
index 000000000..36f96b8ff
--- /dev/null
+++ b/common/stringhelp.c
@@ -0,0 +1,1151 @@
+/* stringhelp.c - standard string helper functions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+ * 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#endif
+
+#include "libjnlib-config.h"
+#include "utf8conv.h"
+#include "stringhelp.h"
+
+
+#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
+
+/* Sometimes we want to avoid mixing slashes and backslashes on W32
+ and prefer backslashes. There is usual no problem with mixing
+ them, however a very few W32 API calls can't grok plain slashes.
+ Printing filenames with mixed slashes also looks a bit strange.
+ This function has no effext on POSIX. */
+static inline char *
+change_slashes (char *name)
+{
+#ifdef HAVE_DRIVE_LETTERS
+ char *p;
+
+ if (strchr (name, '\\'))
+ {
+ for (p=name; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+ }
+#endif /*HAVE_DRIVE_LETTERS*/
+ return name;
+}
+
+
+/*
+ * Look for the substring SUB in buffer and return a pointer to that
+ * substring in BUFFER or NULL if not found.
+ * Comparison is case-insensitive.
+ */
+const char *
+memistr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buffer;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if ( toupper (*t) == toupper (*s) )
+ {
+ for ( buf=t++, buflen = n--, s++;
+ n && toupper (*t) == toupper (*s); t++, s++, n-- )
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+const char *
+ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (ascii_toupper (*t) == ascii_toupper (*s) )
+ {
+ for ( buf=t++, buflen = n--, s++;
+ n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+/* This function is similar to strncpy(). However it won't copy more
+ than N - 1 characters and makes sure that a '\0' is appended. With
+ N given as 0, nothing will happen. With DEST given as NULL, memory
+ will be allocated using jnlib_xmalloc (i.e. if it runs out of core
+ the function terminates). Returns DES or a pointer to the
+ allocated memory.
+ */
+char *
+mem2str( char *dest , const void *src , size_t n )
+{
+ char *d;
+ const char *s;
+
+ if( n ) {
+ if( !dest )
+ dest = jnlib_xmalloc( n ) ;
+ d = dest;
+ s = src ;
+ for(n--; n && *s; n-- )
+ *d++ = *s++;
+ *d = '\0' ;
+ }
+
+ return dest ;
+}
+
+
+/****************
+ * remove leading and trailing white spaces
+ */
+char *
+trim_spaces( char *str )
+{
+ char *string, *p, *mark;
+
+ string = str;
+ /* find first non space character */
+ for( p=string; *p && isspace( *(byte*)p ) ; p++ )
+ ;
+ /* move characters */
+ for( (mark = NULL); (*string = *p); string++, p++ )
+ if( isspace( *(byte*)p ) ) {
+ if( !mark )
+ mark = string ;
+ }
+ else
+ mark = NULL ;
+ if( mark )
+ *mark = '\0' ; /* remove trailing spaces */
+
+ return str ;
+}
+
+/****************
+ * remove trailing white spaces
+ */
+char *
+trim_trailing_spaces( char *string )
+{
+ char *p, *mark;
+
+ for( mark = NULL, p = string; *p; p++ ) {
+ if( isspace( *(byte*)p ) ) {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+ if( mark )
+ *mark = '\0' ;
+
+ return string ;
+}
+
+
+unsigned
+trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
+{
+ byte *p, *mark;
+ unsigned n;
+
+ for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
+ if( strchr(trimchars, *p ) ) {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+
+ if( mark ) {
+ *mark = 0;
+ return mark - line;
+ }
+ return len;
+}
+
+/****************
+ * remove trailing white spaces and return the length of the buffer
+ */
+unsigned
+trim_trailing_ws( byte *line, unsigned len )
+{
+ return trim_trailing_chars( line, len, " \t\r\n" );
+}
+
+size_t
+length_sans_trailing_chars (const unsigned char *line, size_t len,
+ const char *trimchars )
+{
+ const unsigned char *p, *mark;
+ size_t n;
+
+ for( mark=NULL, p=line, n=0; n < len; n++, p++ )
+ {
+ if (strchr (trimchars, *p ))
+ {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+
+ if (mark)
+ return mark - line;
+ return len;
+}
+
+/*
+ * Return the length of line ignoring trailing white-space.
+ */
+size_t
+length_sans_trailing_ws (const unsigned char *line, size_t len)
+{
+ return length_sans_trailing_chars (line, len, " \t\r\n");
+}
+
+
+
+/*
+ * Extract from a given path the filename component. This function
+ * terminates the process on memory shortage.
+ */
+char *
+make_basename(const char *filepath, const char *inputpath)
+{
+#ifdef __riscos__
+ return riscos_make_basename(filepath, inputpath);
+#else
+ char *p;
+
+ (void)inputpath; /* Only required for riscos. */
+
+ if ( !(p=strrchr(filepath, '/')) )
+#ifdef HAVE_DRIVE_LETTERS
+ if ( !(p=strrchr(filepath, '\\')) )
+ if ( !(p=strrchr(filepath, ':')) )
+#endif
+ {
+ return jnlib_xstrdup(filepath);
+ }
+
+ return jnlib_xstrdup(p+1);
+#endif
+}
+
+
+
+/*
+ * Extract from a given filename the path prepended to it. If there
+ * isn't a path prepended to the filename, a dot is returned ('.').
+ * This function terminates the process on memory shortage.
+ */
+char *
+make_dirname(const char *filepath)
+{
+ char *dirname;
+ int dirname_length;
+ char *p;
+
+ if ( !(p=strrchr(filepath, '/')) )
+#ifdef HAVE_DRIVE_LETTERS
+ if ( !(p=strrchr(filepath, '\\')) )
+ if ( !(p=strrchr(filepath, ':')) )
+#endif
+ {
+ return jnlib_xstrdup(".");
+ }
+
+ dirname_length = p-filepath;
+ dirname = jnlib_xmalloc(dirname_length+1);
+ strncpy(dirname, filepath, dirname_length);
+ dirname[dirname_length] = 0;
+
+ return dirname;
+}
+
+
+
+static char *
+get_pwdir (int xmode, const char *name)
+{
+ char *result = NULL;
+#ifdef HAVE_PWD_H
+ struct passwd *pwd = NULL;
+
+ if (name)
+ {
+#ifdef HAVE_GETPWNAM
+ /* Fixme: We should use getpwnam_r if available. */
+ pwd = getpwnam (name);
+#endif
+ }
+ else
+ {
+#ifdef HAVE_GETPWUID
+ /* Fixme: We should use getpwuid_r if available. */
+ pwd = getpwuid (getuid());
+#endif
+ }
+ if (pwd)
+ {
+ if (xmode)
+ result = jnlib_xstrdup (pwd->pw_dir);
+ else
+ result = jnlib_strdup (pwd->pw_dir);
+ }
+#else /*!HAVE_PWD_H*/
+ /* No support at all. */
+ (void)xmode;
+ (void)name;
+#endif /*HAVE_PWD_H*/
+ return result;
+}
+
+static char *
+do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
+{
+ const char *argv[32];
+ int argc;
+ size_t n;
+ int skip = 1;
+ char *home_buffer = NULL;
+ char *name, *home, *p;
+
+ n = strlen (first_part) + 1;
+ argc = 0;
+ while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
+ {
+ n += strlen (argv[argc]) + 1;
+ if (argc >= DIM (argv)-1)
+ {
+ if (xmode)
+ BUG ();
+ jnlib_set_errno (EINVAL);
+ return NULL;
+ }
+ argc++;
+ }
+ n++;
+
+ home = NULL;
+ if (*first_part == '~')
+ {
+ if (first_part[1] == '/' || !first_part[1])
+ {
+ /* This is the "~/" or "~" case. */
+ home = getenv("HOME");
+ if (!home)
+ home = home_buffer = get_pwdir (xmode, NULL);
+ if (home && *home)
+ n += strlen (home);
+ }
+ else
+ {
+ /* This is the "~username/" or "~username" case. */
+ char *user;
+
+ if (xmode)
+ user = jnlib_xstrdup (first_part+1);
+ else
+ {
+ user = jnlib_strdup (first_part+1);
+ if (!user)
+ return NULL;
+ }
+ p = strchr (user, '/');
+ if (p)
+ *p = 0;
+ skip = 1 + strlen (user);
+
+ home = home_buffer = get_pwdir (xmode, user);
+ jnlib_free (user);
+ if (home)
+ n += strlen (home);
+ else
+ skip = 1;
+ }
+ }
+
+ if (xmode)
+ name = jnlib_xmalloc (n);
+ else
+ {
+ name = jnlib_malloc (n);
+ if (!name)
+ {
+ jnlib_free (home_buffer);
+ return NULL;
+ }
+ }
+
+ if (home)
+ p = stpcpy (stpcpy (name, home), first_part + skip);
+ else
+ p = stpcpy (name, first_part);
+
+ jnlib_free (home_buffer);
+
+ for (argc=0; argv[argc]; argc++)
+ p = stpcpy (stpcpy (p, "/"), argv[argc]);
+
+ return change_slashes (name);
+}
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ expansion is done for the first argument. This function terminates
+ the process on memory shortage. */
+char *
+make_filename (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (1, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ expansion is done for the first argument. This function may return
+ NULL on error. */
+char *
+make_filename_try (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (0, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+
+
+/* Compare whether the filenames are identical. This is a
+ special version of strcmp() taking the semantics of filenames in
+ account. Note that this function works only on the supplied names
+ without considereing any context like the current directory. See
+ also same_file_p(). */
+int
+compare_filenames (const char *a, const char *b)
+{
+#ifdef HAVE_DRIVE_LETTERS
+ for ( ; *a && *b; a++, b++ )
+ {
+ if (*a != *b
+ && (toupper (*(const unsigned char*)a)
+ != toupper (*(const unsigned char*)b) )
+ && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
+ break;
+ }
+ if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
+ return 0;
+ else
+ return (toupper (*(const unsigned char*)a)
+ - toupper (*(const unsigned char*)b));
+#else
+ return strcmp(a,b);
+#endif
+}
+
+
+/* Convert 2 hex characters at S to a byte value. Return this value
+ or -1 if there is an error. */
+int
+hextobyte (const char *s)
+{
+ int c;
+
+ if ( *s >= '0' && *s <= '9' )
+ c = 16 * (*s - '0');
+ else if ( *s >= 'A' && *s <= 'F' )
+ c = 16 * (10 + *s - 'A');
+ else if ( *s >= 'a' && *s <= 'f' )
+ c = 16 * (10 + *s - 'a');
+ else
+ return -1;
+ s++;
+ if ( *s >= '0' && *s <= '9' )
+ c += *s - '0';
+ else if ( *s >= 'A' && *s <= 'F' )
+ c += 10 + *s - 'A';
+ else if ( *s >= 'a' && *s <= 'f' )
+ c += 10 + *s - 'a';
+ else
+ return -1;
+ return c;
+}
+
+
+/* Print a BUFFER to stream FP while replacing all control characters
+ and the characters DELIM and DELIM2 with standard C escape
+ sequences. Returns the number of characters printed. */
+size_t
+print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
+ int delim, int delim2)
+{
+ const unsigned char *p = buffer;
+ size_t count = 0;
+
+ for (; length; length--, p++, count++)
+ {
+ if (*p < 0x20
+ || *p == 0x7f
+ || *p == delim
+ || *p == delim2
+ || ((delim || delim2) && *p=='\\'))
+ {
+ putc ('\\', fp);
+ count++;
+ if (*p == '\n')
+ {
+ putc ('n', fp);
+ count++;
+ }
+ else if (*p == '\r')
+ {
+ putc ('r', fp);
+ count++;
+ }
+ else if (*p == '\f')
+ {
+ putc ('f', fp);
+ count++;
+ }
+ else if (*p == '\v')
+ {
+ putc ('v', fp);
+ count++;
+ }
+ else if (*p == '\b')
+ {
+ putc ('b', fp);
+ count++;
+ }
+ else if (!*p)
+ {
+ putc('0', fp);
+ count++;
+ }
+ else
+ {
+ fprintf (fp, "x%02x", *p);
+ count += 3;
+ }
+ }
+ else
+ {
+ putc (*p, fp);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/* Same as print_sanitized_buffer2 but with just one delimiter. */
+size_t
+print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
+ int delim)
+{
+ return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
+}
+
+
+size_t
+print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
+ size_t length, int delim)
+{
+ const char *p = buffer;
+ size_t i;
+
+ /* We can handle plain ascii simpler, so check for it first. */
+ for (i=0; i < length; i++ )
+ {
+ if ( (p[i] & 0x80) )
+ break;
+ }
+ if (i < length)
+ {
+ char *buf = utf8_to_native (p, length, delim);
+ /*(utf8 conversion already does the control character quoting)*/
+ i = strlen (buf);
+ fputs (buf, fp);
+ jnlib_free (buf);
+ return i;
+ }
+ else
+ return print_sanitized_buffer (fp, p, length, delim);
+}
+
+
+size_t
+print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
+{
+ return string? print_sanitized_buffer2 (fp, string, strlen (string),
+ delim, delim2):0;
+}
+
+size_t
+print_sanitized_string (FILE *fp, const char *string, int delim)
+{
+ return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
+}
+
+size_t
+print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
+{
+ return string? print_sanitized_utf8_buffer (fp,
+ string, strlen (string),
+ delim) : 0;
+}
+
+/* Create a string from the buffer P_ARG of length N which is suitable
+ for printing. Caller must release the created string using xfree.
+ This function terminates the process on memory shortage. */
+char *
+sanitize_buffer (const void *p_arg, size_t n, int delim)
+{
+ const unsigned char *p = p_arg;
+ size_t save_n, buflen;
+ const unsigned char *save_p;
+ char *buffer, *d;
+
+ /* First count length. */
+ for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
+ {
+ if ( *p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\'))
+ {
+ if ( *p=='\n' || *p=='\r' || *p=='\f'
+ || *p=='\v' || *p=='\b' || !*p )
+ buflen += 2;
+ else
+ buflen += 5;
+ }
+ else
+ buflen++;
+ }
+ p = save_p;
+ n = save_n;
+ /* And now make the string */
+ d = buffer = jnlib_xmalloc( buflen );
+ for ( ; n; n--, p++ )
+ {
+ if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
+ *d++ = '\\';
+ if( *p == '\n' )
+ *d++ = 'n';
+ else if( *p == '\r' )
+ *d++ = 'r';
+ else if( *p == '\f' )
+ *d++ = 'f';
+ else if( *p == '\v' )
+ *d++ = 'v';
+ else if( *p == '\b' )
+ *d++ = 'b';
+ else if( !*p )
+ *d++ = '0';
+ else {
+ sprintf(d, "x%02x", *p );
+ d += 3;
+ }
+ }
+ else
+ *d++ = *p;
+ }
+ *d = 0;
+ return buffer;
+}
+
+
+/* Given a string containing an UTF-8 encoded text, return the number
+ of characters in this string. It differs from strlen in that it
+ only counts complete UTF-8 characters. Note, that this function
+ does not take combined characters into account. */
+size_t
+utf8_charcount (const char *s)
+{
+ size_t n;
+
+ for (n=0; *s; s++)
+ if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
+ n++;
+
+ return n;
+}
+
+
+/****************************************************
+ ********** W32 specific functions ****************
+ ****************************************************/
+
+#ifdef HAVE_W32_SYSTEM
+const char *
+w32_strerror (int ec)
+{
+ static char strerr[256];
+
+ if (ec == -1)
+ ec = (int)GetLastError ();
+#ifdef HAVE_W32CE_SYSTEM
+ /* There is only a wchar_t FormatMessage. It does not make much
+ sense to play the conversion game; we print only the code. */
+ snprintf (strerr, sizeof strerr, "ec=%d", (int)GetLastError ());
+#else
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ strerr, DIM (strerr)-1, NULL);
+#endif
+ return strerr;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/****************************************************
+ ******** Locale insensitive ctype functions ********
+ ****************************************************/
+/* FIXME: replace them by a table lookup and macros */
+int
+ascii_isupper (int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+int
+ascii_islower (int c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+int
+ascii_toupper (int c)
+{
+ if (c >= 'a' && c <= 'z')
+ c &= ~0x20;
+ return c;
+}
+
+int
+ascii_tolower (int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c |= 0x20;
+ return c;
+}
+
+
+int
+ascii_strcasecmp( const char *a, const char *b )
+{
+ if (a == b)
+ return 0;
+
+ for (; *a && *b; a++, b++) {
+ if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
+ break;
+ }
+ return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+}
+
+int
+ascii_strncasecmp (const char *a, const char *b, size_t n)
+{
+ const unsigned char *p1 = (const unsigned char *)a;
+ const unsigned char *p2 = (const unsigned char *)b;
+ unsigned char c1, c2;
+
+ if (p1 == p2 || !n )
+ return 0;
+
+ do
+ {
+ c1 = ascii_tolower (*p1);
+ c2 = ascii_tolower (*p2);
+
+ if ( !--n || c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+
+
+int
+ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
+{
+ const char *a = a_arg;
+ const char *b = b_arg;
+
+ if (a == b)
+ return 0;
+ for ( ; n; n--, a++, b++ )
+ {
+ if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
+ return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+ }
+ return 0;
+}
+
+int
+ascii_strcmp( const char *a, const char *b )
+{
+ if (a == b)
+ return 0;
+
+ for (; *a && *b; a++, b++) {
+ if (*a != *b )
+ break;
+ }
+ return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
+}
+
+
+void *
+ascii_memcasemem (const void *haystack, size_t nhaystack,
+ const void *needle, size_t nneedle)
+{
+
+ if (!nneedle)
+ return (void*)haystack; /* finding an empty needle is really easy */
+ if (nneedle <= nhaystack)
+ {
+ const char *a = haystack;
+ const char *b = a + nhaystack - nneedle;
+
+ for (; a <= b; a++)
+ {
+ if ( !ascii_memcasecmp (a, needle, nneedle) )
+ return (void *)a;
+ }
+ }
+ return NULL;
+}
+
+/*********************************************
+ ********** missing string functions *********
+ *********************************************/
+
+#ifndef HAVE_STPCPY
+char *
+stpcpy(char *a,const char *b)
+{
+ while( *b )
+ *a++ = *b++;
+ *a = 0;
+
+ return (char*)a;
+}
+#endif
+
+#ifndef HAVE_STRSEP
+/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
+char *
+strsep (char **stringp, const char *delim)
+{
+ char *begin, *end;
+
+ begin = *stringp;
+ if (begin == NULL)
+ return NULL;
+
+ /* A frequent case is when the delimiter string contains only one
+ character. Here we don't need to call the expensive `strpbrk'
+ function and instead work using `strchr'. */
+ if (delim[0] == '\0' || delim[1] == '\0')
+ {
+ char ch = delim[0];
+
+ if (ch == '\0')
+ end = NULL;
+ else
+ {
+ if (*begin == ch)
+ end = begin;
+ else if (*begin == '\0')
+ end = NULL;
+ else
+ end = strchr (begin + 1, ch);
+ }
+ }
+ else
+ /* Find the end of the token. */
+ end = strpbrk (begin, delim);
+
+ if (end)
+ {
+ /* Terminate the token and set *STRINGP past NUL character. */
+ *end++ = '\0';
+ *stringp = end;
+ }
+ else
+ /* No more delimiters; this is the last token. */
+ *stringp = NULL;
+
+ return begin;
+}
+#endif /*HAVE_STRSEP*/
+
+
+#ifndef HAVE_STRLWR
+char *
+strlwr(char *s)
+{
+ char *p;
+ for(p=s; *p; p++ )
+ *p = tolower(*p);
+ return s;
+}
+#endif
+
+
+#ifndef HAVE_STRCASECMP
+int
+strcasecmp( const char *a, const char *b )
+{
+ for( ; *a && *b; a++, b++ ) {
+ if( *a != *b && toupper(*a) != toupper(*b) )
+ break;
+ }
+ return *(const byte*)a - *(const byte*)b;
+}
+#endif
+
+
+/****************
+ * mingw32/cpd has a memicmp()
+ */
+#ifndef HAVE_MEMICMP
+int
+memicmp( const char *a, const char *b, size_t n )
+{
+ for( ; n; n--, a++, b++ )
+ if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
+ return *(const byte *)a - *(const byte*)b;
+ return 0;
+}
+#endif
+
+
+#ifndef HAVE_MEMRCHR
+void *
+memrchr (const void *buffer, int c, size_t n)
+{
+ const unsigned char *p = buffer;
+
+ for (p += n; n ; n--)
+ if (*--p == c)
+ return (void *)p;
+ return NULL;
+}
+#endif /*HAVE_MEMRCHR*/
+
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL all characters in EXTRA are also escaped. */
+static char *
+do_percent_escape (const char *str, const char *extra, int die)
+{
+ int i, j;
+ char *ptr;
+
+ if (!str)
+ return NULL;
+
+ for (i=j=0; str[i]; i++)
+ if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
+ j++;
+ if (die)
+ ptr = jnlib_xmalloc (i + 2 * j + 1);
+ else
+ {
+ ptr = jnlib_malloc (i + 2 * j + 1);
+ if (!ptr)
+ return NULL;
+ }
+ i = 0;
+ while (*str)
+ {
+ if (*str == ':')
+ {
+ ptr[i++] = '%';
+ ptr[i++] = '3';
+ ptr[i++] = 'a';
+ }
+ else if (*str == '%')
+ {
+ ptr[i++] = '%';
+ ptr[i++] = '2';
+ ptr[i++] = '5';
+ }
+ else if (extra && strchr (extra, *str))
+ {
+ ptr[i++] = '%';
+ ptr[i++] = tohex_lower ((*str>>4)&15);
+ ptr[i++] = tohex_lower (*str&15);
+ }
+ else
+ ptr[i++] = *str;
+ str++;
+ }
+ ptr[i] = '\0';
+
+ return ptr;
+}
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL all characters in EXTRA are also escaped. This
+ function terminates the process on memory shortage. */
+char *
+percent_escape (const char *str, const char *extra)
+{
+ return do_percent_escape (str, extra, 1);
+}
+
+/* Same as percent_escape but return NULL instead of exiting on memory
+ error. */
+char *
+try_percent_escape (const char *str, const char *extra)
+{
+ return do_percent_escape (str, extra, 0);
+}
+
+
+
+static char *
+do_strconcat (const char *s1, va_list arg_ptr)
+{
+ const char *argv[48];
+ size_t argc;
+ size_t needed;
+ char *buffer, *p;
+
+ argc = 0;
+ argv[argc++] = s1;
+ needed = strlen (s1);
+ while (((argv[argc] = va_arg (arg_ptr, const char *))))
+ {
+ needed += strlen (argv[argc]);
+ if (argc >= DIM (argv)-1)
+ {
+ jnlib_set_errno (EINVAL);
+ return NULL;
+ }
+ argc++;
+ }
+ needed++;
+ buffer = jnlib_malloc (needed);
+ if (buffer)
+ {
+ for (p = buffer, argc=0; argv[argc]; argc++)
+ p = stpcpy (p, argv[argc]);
+ }
+ return buffer;
+}
+
+
+/* Concatenate the string S1 with all the following strings up to a
+ NULL. Returns a malloced buffer with the new string or NULL on a
+ malloc error or if too many arguments are given. */
+char *
+strconcat (const char *s1, ...)
+{
+ va_list arg_ptr;
+ char *result;
+
+ if (!s1)
+ result = jnlib_strdup ("");
+ else
+ {
+ va_start (arg_ptr, s1);
+ result = do_strconcat (s1, arg_ptr);
+ va_end (arg_ptr);
+ }
+ return result;
+}
+
+/* Same as strconcat but terminate the process with an error message
+ if something goes wrong. */
+char *
+xstrconcat (const char *s1, ...)
+{
+ va_list arg_ptr;
+ char *result;
+
+ if (!s1)
+ result = jnlib_xstrdup ("");
+ else
+ {
+ va_start (arg_ptr, s1);
+ result = do_strconcat (s1, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (!result)
+ {
+ if (errno == EINVAL)
+ fputs ("\nfatal: too many args for xstrconcat\n", stderr);
+ else
+ fputs ("\nfatal: out of memory\n", stderr);
+ exit (2);
+ }
+ return result;
+}
+
diff --git a/common/stringhelp.h b/common/stringhelp.h
new file mode 100644
index 000000000..a560b163e
--- /dev/null
+++ b/common/stringhelp.h
@@ -0,0 +1,136 @@
+/* stringhelp.h
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ * 2006, 2007, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_STRINGHELP_H
+#define LIBJNLIB_STRINGHELP_H
+
+#include "types.h"
+
+const char *memistr (const void *buf, size_t buflen, const char *sub);
+char *mem2str( char *, const void *, size_t);
+char *trim_spaces( char *string );
+char *trim_trailing_spaces( char *string );
+unsigned int trim_trailing_chars( unsigned char *line, unsigned len,
+ const char *trimchars);
+unsigned int trim_trailing_ws( unsigned char *line, unsigned len );
+size_t length_sans_trailing_chars (const unsigned char *line, size_t len,
+ const char *trimchars );
+size_t length_sans_trailing_ws (const unsigned char *line, size_t len);
+
+
+char *make_basename(const char *filepath, const char *inputpath);
+char *make_dirname(const char *filepath);
+char *make_filename( const char *first_part, ... ) GNUPG_GCC_A_SENTINEL(0);
+char *make_filename_try (const char *first_part, ... ) GNUPG_GCC_A_SENTINEL(0);
+int compare_filenames( const char *a, const char *b );
+
+int hextobyte (const char *s);
+
+size_t print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
+ int delim);
+size_t print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
+ int delim, int delim2);
+size_t print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
+ size_t length, int delim);
+size_t print_sanitized_string (FILE *fp, const char *string, int delim);
+size_t print_sanitized_string2 (FILE *fp, const char *string,
+ int delim, int delim2);
+size_t print_sanitized_utf8_string (FILE *fp, const char *string, int delim);
+char *sanitize_buffer (const void *p, size_t n, int delim);
+
+
+size_t utf8_charcount (const char *s);
+
+
+#ifdef HAVE_W32_SYSTEM
+const char *w32_strerror (int ec);
+#endif
+
+
+int ascii_isupper (int c);
+int ascii_islower (int c);
+int ascii_toupper (int c);
+int ascii_tolower (int c);
+int ascii_strcasecmp( const char *a, const char *b );
+int ascii_strncasecmp (const char *a, const char *b, size_t n);
+int ascii_memcasecmp( const void *a, const void *b, size_t n );
+const char *ascii_memistr ( const void *buf, size_t buflen, const char *sub);
+void *ascii_memcasemem (const void *haystack, size_t nhaystack,
+ const void *needle, size_t nneedle);
+
+
+#ifndef HAVE_MEMICMP
+int memicmp( const char *a, const char *b, size_t n );
+#endif
+#ifndef HAVE_STPCPY
+char *stpcpy(char *a,const char *b);
+#endif
+#ifndef HAVE_STRSEP
+char *strsep (char **stringp, const char *delim);
+#endif
+#ifndef HAVE_STRLWR
+char *strlwr(char *a);
+#endif
+#ifndef HAVE_STRTOUL
+# define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c)))
+#endif
+#ifndef HAVE_MEMMOVE
+# define memmove(d, s, n) bcopy((s), (d), (n))
+#endif
+#ifndef HAVE_STRICMP
+# define stricmp(a,b) strcasecmp( (a), (b) )
+#endif
+#ifndef HAVE_MEMRCHR
+void *memrchr (const void *buffer, int c, size_t n);
+#endif
+
+
+#ifndef HAVE_ISASCII
+static inline int
+isascii (int c)
+{
+ return (((c) & ~0x7f) == 0);
+}
+#endif /* !HAVE_ISASCII */
+
+
+#ifndef STR
+# define STR(v) #v
+#endif
+#define STR2(v) STR(v)
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL, also replace all characters given in EXTRA. The
+ "try_" variant fails with NULL if not enough memory can be
+ allocated. */
+char *percent_escape (const char *str, const char *extra);
+char *try_percent_escape (const char *str, const char *extra);
+
+
+/* Concatenate the string S1 with all the following strings up to a
+ NULL. Returns a malloced buffer with the new string or NULL on a
+ malloc error or if too many arguments are given. */
+char *strconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
+/* Ditto, but die on error. */
+char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
+
+
+
+#endif /*LIBJNLIB_STRINGHELP_H*/
diff --git a/common/strlist.c b/common/strlist.c
new file mode 100644
index 000000000..b31e6213a
--- /dev/null
+++ b/common/strlist.c
@@ -0,0 +1,204 @@
+/* strlist.c - string helpers
+ * Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "libjnlib-config.h"
+#include "strlist.h"
+#ifdef JNLIB_NEED_UTF8CONV
+#include "utf8conv.h"
+#endif
+
+void
+free_strlist( strlist_t sl )
+{
+ strlist_t sl2;
+
+ for(; sl; sl = sl2 ) {
+ sl2 = sl->next;
+ jnlib_free(sl);
+ }
+}
+
+
+/* Add STRING to the LIST at the front. This function terminates the
+ process on memory shortage. */
+strlist_t
+add_to_strlist( strlist_t *list, const char *string )
+{
+ strlist_t sl;
+
+ sl = jnlib_xmalloc( sizeof *sl + strlen(string));
+ sl->flags = 0;
+ strcpy(sl->d, string);
+ sl->next = *list;
+ *list = sl;
+ return sl;
+}
+
+
+/* Add STRING to the LIST at the front. This function returns NULL
+ and sets ERRNO on memory shortage. */
+strlist_t
+add_to_strlist_try (strlist_t *list, const char *string)
+{
+ strlist_t sl;
+
+ sl = jnlib_malloc (sizeof *sl + strlen (string));
+ if (sl)
+ {
+ sl->flags = 0;
+ strcpy (sl->d, string);
+ sl->next = *list;
+ *list = sl;
+ }
+ return sl;
+}
+
+
+/* Same as add_to_strlist() but if IS_UTF8 is *not* set, a conversion
+ to UTF-8 is done. This function terminates the process on memory
+ shortage. */
+#ifdef JNLIB_NEED_UTF8CONV
+strlist_t
+add_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
+{
+ strlist_t sl;
+
+ if (is_utf8)
+ sl = add_to_strlist( list, string );
+ else
+ {
+ char *p = native_to_utf8( string );
+ sl = add_to_strlist( list, p );
+ jnlib_free ( p );
+ }
+ return sl;
+}
+#endif /* JNLIB_NEED_UTF8CONV*/
+
+
+/* Add STRING to the LIST at the end. This function terminates the
+ process on memory shortage. */
+strlist_t
+append_to_strlist( strlist_t *list, const char *string )
+{
+ strlist_t r, sl;
+
+ sl = jnlib_xmalloc( sizeof *sl + strlen(string));
+ sl->flags = 0;
+ strcpy(sl->d, string);
+ sl->next = NULL;
+ if( !*list )
+ *list = sl;
+ else {
+ for( r = *list; r->next; r = r->next )
+ ;
+ r->next = sl;
+ }
+ return sl;
+}
+
+
+#ifdef JNLIB_NEED_UTF8CONV
+strlist_t
+append_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
+{
+ strlist_t sl;
+
+ if( is_utf8 )
+ sl = append_to_strlist( list, string );
+ else
+ {
+ char *p = native_to_utf8 (string);
+ sl = append_to_strlist( list, p );
+ jnlib_free( p );
+ }
+ return sl;
+}
+#endif /* JNLIB_NEED_UTF8CONV */
+
+
+/* Return a copy of LIST. This function terminates the process on
+ memory shortage.*/
+strlist_t
+strlist_copy (strlist_t list)
+{
+ strlist_t newlist = NULL, sl, *last;
+
+ last = &newlist;
+ for (; list; list = list->next)
+ {
+ sl = jnlib_xmalloc (sizeof *sl + strlen (list->d));
+ sl->flags = list->flags;
+ strcpy(sl->d, list->d);
+ sl->next = NULL;
+ *last = sl;
+ last = &sl;
+ }
+ return newlist;
+}
+
+
+
+strlist_t
+strlist_prev( strlist_t head, strlist_t node )
+{
+ strlist_t n;
+
+ for(n=NULL; head && head != node; head = head->next )
+ n = head;
+ return n;
+}
+
+strlist_t
+strlist_last( strlist_t node )
+{
+ if( node )
+ for( ; node->next ; node = node->next )
+ ;
+ return node;
+}
+
+
+/* Remove the first item from LIST and return its content in an
+ allocated buffer. This function terminates the process on memory
+ shortage. */
+char *
+strlist_pop (strlist_t *list)
+{
+ char *str=NULL;
+ strlist_t sl=*list;
+
+ if(sl)
+ {
+ str=jnlib_xmalloc(strlen(sl->d)+1);
+ strcpy(str,sl->d);
+
+ *list=sl->next;
+ jnlib_free(sl);
+ }
+
+ return str;
+}
+
diff --git a/common/strlist.h b/common/strlist.h
new file mode 100644
index 000000000..1e2ffa8da
--- /dev/null
+++ b/common/strlist.h
@@ -0,0 +1,50 @@
+/* strlist.h
+ * Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_STRLIST_H
+#define LIBJNLIB_STRLIST_H
+
+struct string_list
+{
+ struct string_list *next;
+ unsigned int flags;
+ char d[1];
+};
+typedef struct string_list *strlist_t;
+
+void free_strlist (strlist_t sl);
+strlist_t add_to_strlist (strlist_t *list, const char *string);
+strlist_t add_to_strlist_try (strlist_t *list, const char *string);
+
+strlist_t add_to_strlist2( strlist_t *list, const char *string, int is_utf8);
+
+strlist_t append_to_strlist (strlist_t *list, const char *string);
+strlist_t append_to_strlist2 (strlist_t *list, const char *string,
+ int is_utf8);
+
+strlist_t strlist_copy (strlist_t list);
+
+strlist_t strlist_prev (strlist_t head, strlist_t node);
+strlist_t strlist_last (strlist_t node);
+char * strlist_pop (strlist_t *list);
+
+#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+
+
+#endif /*LIBJNLIB_STRLIST_H*/
diff --git a/common/sysutils.h b/common/sysutils.h
index fd4340f3d..6f34b9791 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -52,7 +52,7 @@ void gnupg_allow_set_foregound_window (pid_t pid);
#ifdef HAVE_W32_SYSTEM
-#include "../jnlib/w32help.h"
+#include "../common/w32help.h"
#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c
new file mode 100644
index 000000000..0c921b03d
--- /dev/null
+++ b/common/t-stringhelp.c
@@ -0,0 +1,414 @@
+/* t-stringhelp.c - Regression tests for stringhelp.c
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "stringhelp.h"
+
+#include "t-support.h"
+
+
+static char *home_buffer;
+
+
+const char *
+gethome (void)
+{
+ if (!home_buffer)
+ {
+ char *home = getenv("HOME");
+
+ if(home)
+ home_buffer = xstrdup (home);
+#if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
+ else
+ {
+ struct passwd *pwd;
+
+ pwd = getpwuid (getuid());
+ if (pwd)
+ home_buffer = xstrdup (pwd->pw_dir);
+ }
+#endif
+ }
+ return home_buffer;
+}
+
+
+static void
+test_percent_escape (void)
+{
+ char *result;
+ static struct {
+ const char *extra;
+ const char *value;
+ const char *expected;
+ } tests[] =
+ {
+ { NULL, "", "" },
+ { NULL, "%", "%25" },
+ { NULL, "%%", "%25%25" },
+ { NULL, " %", " %25" },
+ { NULL, ":", "%3a" },
+ { NULL, " :", " %3a" },
+ { NULL, ": ", "%3a " },
+ { NULL, " : ", " %3a " },
+ { NULL, "::", "%3a%3a" },
+ { NULL, ": :", "%3a %3a" },
+ { NULL, "%:", "%25%3a" },
+ { NULL, ":%", "%3a%25" },
+ { "\\\n:", ":%", "%3a%25" },
+ { "\\\n:", "\\:%", "%5c%3a%25" },
+ { "\\\n:", "\n:%", "%0a%3a%25" },
+ { "\\\n:", "\xff:%", "\xff%3a%25" },
+ { "\\\n:", "\xfe:%", "\xfe%3a%25" },
+ { "\\\n:", "\x01:%", "\x01%3a%25" },
+ { "\x01", "\x01:%", "%01%3a%25" },
+ { "\xfe", "\xfe:%", "%fe%3a%25" },
+ { "\xfe", "\xff:%", "\xff%3a%25" },
+
+ { NULL, NULL, NULL }
+ };
+ int testno;
+
+ result = percent_escape (NULL, NULL);
+ if (result)
+ fail (0);
+ for (testno=0; tests[testno].value; testno++)
+ {
+ result = percent_escape (tests[testno].value, tests[testno].extra);
+ if (!result)
+ fail (testno);
+ if (strcmp (result, tests[testno].expected))
+ fail (testno);
+ xfree (result);
+ }
+
+}
+
+
+static void
+test_compare_filenames (void)
+{
+ struct {
+ const char *a;
+ const char *b;
+ int result;
+ } tests[] = {
+ { "", "", 0 },
+ { "", "a", -1 },
+ { "a", "", 1 },
+ { "a", "a", 0 },
+ { "a", "aa", -1 },
+ { "aa", "a", 1 },
+ { "a", "b", -1 },
+
+#ifdef HAVE_W32_SYSTEM
+ { "a", "A", 0 },
+ { "A", "a", 0 },
+ { "foo/bar", "foo\\bar", 0 },
+ { "foo\\bar", "foo/bar", 0 },
+ { "foo\\", "foo/", 0 },
+ { "foo/", "foo\\", 0 },
+#endif /*HAVE_W32_SYSTEM*/
+ { NULL, NULL, 0}
+ };
+ int testno, result;
+
+ for (testno=0; tests[testno].a; testno++)
+ {
+ result = compare_filenames (tests[testno].a, tests[testno].b);
+ result = result < 0? -1 : result > 0? 1 : 0;
+ if (result != tests[testno].result)
+ fail (testno);
+ }
+}
+
+
+static void
+test_strconcat (void)
+{
+ char *out;
+
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", NULL);
+ if (!out)
+ fail (0);
+ else
+ xfree (out);
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+
+#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
+ out = strconcat (NULL);
+ if (!out || *out)
+ fail (1);
+#endif
+ out = strconcat (NULL, NULL);
+ if (!out || *out)
+ fail (1);
+ out = strconcat ("", NULL);
+ if (!out || *out)
+ fail (1);
+ xfree (out);
+
+ out = strconcat ("", "", NULL);
+ if (!out || *out)
+ fail (2);
+ xfree (out);
+
+ out = strconcat ("a", "b", NULL);
+ if (!out || strcmp (out, "ab"))
+ fail (3);
+ xfree (out);
+ out = strconcat ("a", "b", "c", NULL);
+ if (!out || strcmp (out, "abc"))
+ fail (3);
+ xfree (out);
+
+ out = strconcat ("a", "b", "cc", NULL);
+ if (!out || strcmp (out, "abcc"))
+ fail (4);
+ xfree (out);
+ out = strconcat ("a1", "b1", "c1", NULL);
+ if (!out || strcmp (out, "a1b1c1"))
+ fail (4);
+ xfree (out);
+
+ out = strconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+
+ out = strconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+}
+
+static void
+test_xstrconcat (void)
+{
+ char *out;
+
+ out = xstrconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", NULL);
+ if (!out)
+ fail (0);
+
+#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
+ out = xstrconcat (NULL);
+ if (!out)
+ fail (1);
+#endif
+ out = xstrconcat (NULL, NULL);
+ if (!out)
+ fail (1);
+ out = xstrconcat ("", NULL);
+ if (!out || *out)
+ fail (1);
+ xfree (out);
+
+ out = xstrconcat ("", "", NULL);
+ if (!out || *out)
+ fail (2);
+ xfree (out);
+
+ out = xstrconcat ("a", "b", NULL);
+ if (!out || strcmp (out, "ab"))
+ fail (3);
+ xfree (out);
+ out = xstrconcat ("a", "b", "c", NULL);
+ if (!out || strcmp (out, "abc"))
+ fail (3);
+ xfree (out);
+
+ out = xstrconcat ("a", "b", "cc", NULL);
+ if (!out || strcmp (out, "abcc"))
+ fail (4);
+ xfree (out);
+ out = xstrconcat ("a1", "b1", "c1", NULL);
+ if (!out || strcmp (out, "a1b1c1"))
+ fail (4);
+ xfree (out);
+
+ out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+
+ out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+}
+
+
+static void
+test_make_filename_try (void)
+{
+ char *out;
+ const char *home = gethome ();
+ size_t homelen = home? strlen (home):0;
+
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+ xfree (out);
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+ xfree (out);
+
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", NULL);
+ if (!out || strcmp (out,
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2"))
+ fail (0);
+ xfree (out);
+
+ out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
+ if (!out || strcmp (out, "foo/~/bar/baz/cde"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("", "~/bar", "baz/cde", NULL);
+ if (!out || strcmp (out, "/~/bar/baz/cde"))
+ fail (1);
+ xfree (out);
+
+
+ out = make_filename_try ("~/foo", "bar", NULL);
+ if (!out)
+ fail (2);
+ if (home)
+ {
+ if (strlen (out) < homelen + 7)
+ fail (2);
+ if (strncmp (out, home, homelen))
+ fail (2);
+ if (strcmp (out+homelen, "/foo/bar"))
+ fail (2);
+ }
+ else
+ {
+ if (strcmp (out, "~/foo/bar"))
+ fail (2);
+ }
+ xfree (out);
+
+ out = make_filename_try ("~", "bar", NULL);
+ if (!out)
+ fail (2);
+ if (home)
+ {
+ if (strlen (out) < homelen + 3)
+ fail (2);
+ if (strncmp (out, home, homelen))
+ fail (2);
+ if (strcmp (out+homelen, "/bar"))
+ fail (2);
+ }
+ else
+ {
+ if (strcmp (out, "~/bar"))
+ fail (2);
+ }
+ xfree (out);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_percent_escape ();
+ test_compare_filenames ();
+ test_strconcat ();
+ test_xstrconcat ();
+ test_make_filename_try ();
+
+ xfree (home_buffer);
+ return 0;
+}
+
diff --git a/common/t-support.c b/common/t-support.c
new file mode 100644
index 000000000..bf05c4c06
--- /dev/null
+++ b/common/t-support.c
@@ -0,0 +1,147 @@
+/* t-support.c - helper functions for the regression tests.
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "t-support.h"
+
+
+/* Replacements for the malloc functions as used here. */
+
+static void
+out_of_memory (void)
+{
+ fprintf (stderr,"error: out of core in regression tests: %s\n",
+ strerror (errno));
+ exit (2);
+}
+
+
+void *
+gcry_malloc (size_t n)
+{
+ return malloc (n);
+}
+
+void *
+gcry_xmalloc (size_t n)
+{
+ void *p = malloc (n);
+ if (!p)
+ out_of_memory ();
+ return p;
+}
+
+char *
+gcry_strdup (const char *string)
+{
+ char *p = malloc (strlen (string)+1);
+ if (p)
+ strcpy (p, string);
+ return p;
+}
+
+
+void *
+gcry_realloc (void *a, size_t n)
+{
+ return realloc (a, n);
+}
+
+void *
+gcry_xrealloc (void *a, size_t n)
+{
+ void *p = realloc (a, n);
+ if (!p)
+ out_of_memory ();
+ return p;
+}
+
+
+
+void *
+gcry_calloc (size_t n, size_t m)
+{
+ return calloc (n, m);
+}
+
+void *
+gcry_xcalloc (size_t n, size_t m)
+{
+ void *p = calloc (n, m);
+ if (!p)
+ out_of_memory ();
+ return p;
+}
+
+
+char *
+gcry_xstrdup (const char *string)
+{
+ void *p = malloc (strlen (string)+1);
+ if (!p)
+ out_of_memory ();
+ strcpy (p, string);
+ return p;
+}
+
+void
+gcry_free (void *a)
+{
+ if (a)
+ free (a);
+}
+
+
+
+/* Stubs for gpg-error functions required because some compilers do
+ not eliminate the supposed-to-be-unused-inline-functions and thus
+ require functions called from these inline fucntions. Although we
+ do not use gpg-error, gpg-error.h may get included via gcrypt.h if
+ it happens to be used used in libjnlib-config.h. */
+#ifndef GPG_ERROR_H /* Don't do this if gpg-error.h has been included. */
+int
+gpg_err_code_from_errno (int err)
+{
+ (void)err;
+ assert (!"stub function");
+ return -1;
+}
+#endif /*GPG_ERROR_H*/
+
+
+/* Retrieve the error code directly from the ERRNO variable. This
+ returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
+ (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
+#ifndef GPG_ERROR_H /* Don't do this if gpg-error.h has been included. */
+int
+gpg_err_code_from_syserror (void)
+{
+ assert (!"stub function");
+ return -1;
+}
+#endif /*GPG_ERROR_H*/
+
+
+
diff --git a/common/t-support.h b/common/t-support.h
new file mode 100644
index 000000000..2dfbc0990
--- /dev/null
+++ b/common/t-support.h
@@ -0,0 +1,60 @@
+/* t-support.h - Helper for the regression tests
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_T_SUPPORT_H
+#define LIBJNLIB_T_SUPPORT_H 1
+
+#ifdef GCRYPT_VERSION
+#error The regression tests should not include with gcrypt.h
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+#include <gpg-error.h> /* Defines strerror. */
+#endif
+
+
+#ifndef HAVE_GETENV
+# define getenv(a) (NULL)
+#endif
+
+
+/* Replacement prototypes. */
+void *gcry_xmalloc (size_t n);
+void *gcry_xcalloc (size_t n, size_t m);
+void *gcry_xrealloc (void *a, size_t n);
+char *gcry_xstrdup (const char * a);
+void gcry_free (void *a);
+
+/* Map the used xmalloc functions to those implemented by t-support.c */
+#define xmalloc(a) gcry_xmalloc ( (a) )
+#define xcalloc(a,b) gcry_xcalloc ( (a), (b) )
+#define xrealloc(a,n) gcry_xrealloc ( (a), (n) )
+#define xstrdup(a) gcry_xstrdup ( (a) )
+#define xfree(a) gcry_free ( (a) )
+
+
+/* Macros to print the result of a test. */
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+
+#endif /*LIBJNLIB_T_SUPPORT_H*/
diff --git a/common/t-timestuff.c b/common/t-timestuff.c
new file mode 100644
index 000000000..46816765d
--- /dev/null
+++ b/common/t-timestuff.c
@@ -0,0 +1,145 @@
+/* t-timestuff.c - Regression tests for time functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "mischelp.h"
+
+#include "t-support.h"
+
+
+static int
+cmp_time_s (struct tm *a, struct tm *b)
+{
+ if (a->tm_year != b->tm_year
+ || a->tm_mon != b->tm_mon
+ || a->tm_mday != b->tm_mday
+ || a->tm_hour != b->tm_hour
+ || a->tm_min != b->tm_min
+ || a->tm_sec != b->tm_sec
+ || a->tm_wday != b->tm_wday
+ || a->tm_yday != b->tm_yday
+ || !a->tm_isdst != !b->tm_isdst)
+ return -1;
+ return 0;
+}
+
+
+
+static void
+test_timegm (void)
+{
+ static struct {
+ int year, mon, mday, hour, min, sec;
+ } tvalues[] = {
+ { -1 },
+ { -2, 1 },
+ { -2, 2 },
+ { -2, 86399 },
+ { -2, 86400 },
+ { -2, 0x7ffffffe },
+ { -2, 0x7fffffff },
+ /* Note: Because we use mktime below we can only start with the
+ day after Epoch. */
+ { 1970, 1, 2, 0, 0 , 1},
+ { 1970, 1, 2, 0, 0 , 2},
+ { 1970, 1, 2, 12, 0 , 0},
+ { 1970, 1, 2, 23, 59 , 59},
+ { 1999, 12, 31, 23, 59 , 59},
+ { 2000, 1, 1, 0, 0, 0},
+ { 2000, 1, 1, 0, 0, 1},
+ { 2010, 12, 31, 23, 59 , 59},
+ { 2010, 1, 1, 0, 0, 0},
+ { 2010, 1, 1, 0, 0, 1},
+ /* The date below is about the last time mktime works in CET on
+ Windows XP; this is a somewhat strange because 32 bit Unices
+ will happily work along for another month until they reach the
+ end of all ticks on 20380119T031408 (unless Uli takes
+ compassion on us and changes time_t to a u64). */
+ { 2037, 12, 18, 23, 59, 59}
+
+ };
+ int tidx;
+ time_t now, atime, counter;
+ struct tm tbuf, tbuf2, *tp;
+
+ counter = 0;
+ for (tidx=0; tidx < DIM (tvalues); tidx++)
+ {
+ if (tvalues[tidx].year == -1)
+ {
+ now = time (NULL);
+ }
+ else if (tvalues[tidx].year == -2)
+ {
+ now = tvalues[tidx].mon;
+ }
+ else
+ {
+ memset (&tbuf, 0, sizeof tbuf);
+ tbuf.tm_year = tvalues[tidx].year - 1900;
+ tbuf.tm_mon = tvalues[tidx].mon;
+ tbuf.tm_mday = tvalues[tidx].mday;
+ tbuf.tm_hour = tvalues[tidx].hour;
+ tbuf.tm_min = tvalues[tidx].min;
+ tbuf.tm_sec = tvalues[tidx].sec;
+ now = mktime (&tbuf);
+ }
+ if (now == (time_t)(-1))
+ fail (tidx);
+
+ tp = gmtime (&now);
+ if (!tp)
+ fail (tidx);
+ tbuf = *tp;
+ tbuf2 = tbuf;
+ atime = timegm (&tbuf);
+ if (atime == (time_t)(-1))
+ fail (tidx);
+ if (atime != now)
+ fail (tidx);
+
+ tp = gmtime (&atime);
+ if (!tp)
+ fail (tidx);
+ if (cmp_time_s (tp, &tbuf))
+ fail (tidx);
+ if (cmp_time_s (tp, &tbuf2))
+ fail (tidx);
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_timegm ();
+
+ return 0;
+}
+
diff --git a/common/t-w32-reg.c b/common/t-w32-reg.c
new file mode 100644
index 000000000..f4848cbaa
--- /dev/null
+++ b/common/t-w32-reg.c
@@ -0,0 +1,70 @@
+/* t-w32-reg.c - Regression tests for W32 registry functions
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "mischelp.h"
+
+#include "t-support.h"
+#include "w32help.h"
+
+
+static void
+test_read_registry (void)
+{
+ char *string;
+
+#ifdef HAVE_W32CE_SYSTEM
+ string = read_w32_registry_string ("HKEY_CLASSES_ROOT",
+ "BOOTSTRAP\\CLSID", NULL);
+ if (!string)
+ fail (0);
+ fprintf (stderr, "Bootstrap clsid: %s\n", string);
+ xfree (string);
+#endif
+
+ string = read_w32_registry_string
+ ("HKEY_CURRENT_USER",
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "User Agent");
+ if (!string)
+ fail (0);
+ fprintf (stderr, "User agent: %s\n", string);
+ xfree (string);
+}
+
+
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_read_registry ();
+
+ return 0;
+}
+
diff --git a/common/ttyio.c b/common/ttyio.c
index fc274070c..ec26b06e8 100644
--- a/common/ttyio.c
+++ b/common/ttyio.c
@@ -48,7 +48,6 @@
#include "util.h"
#include "ttyio.h"
-#include "estream-printf.h"
#include "common-defs.h"
#define CONTROL_D ('D' - 'A' + 1)
diff --git a/common/types.h b/common/types.h
new file mode 100644
index 000000000..62fa0470d
--- /dev/null
+++ b/common/types.h
@@ -0,0 +1,114 @@
+/* types.h - define some extra types
+ * Copyright (C) 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_TYPES_H
+#define LIBJNLIB_TYPES_H
+
+/* The AC_CHECK_SIZEOF() in configure fails for some machines.
+ * we provide some fallback values here */
+#if !SIZEOF_UNSIGNED_SHORT
+# undef SIZEOF_UNSIGNED_SHORT
+# define SIZEOF_UNSIGNED_SHORT 2
+#endif
+#if !SIZEOF_UNSIGNED_INT
+# undef SIZEOF_UNSIGNED_INT
+# define SIZEOF_UNSIGNED_INT 4
+#endif
+#if !SIZEOF_UNSIGNED_LONG
+# undef SIZEOF_UNSIGNED_LONG
+# define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+
+#include <sys/types.h>
+
+
+#ifndef HAVE_BYTE_TYPEDEF
+# undef byte /* There might be a macro with this name. */
+/* Windows typedefs byte in the rpc headers. Avoid warning about
+ double definition. */
+#if !(defined(_WIN32) && defined(cbNDRContext))
+ typedef unsigned char byte;
+#endif
+# define HAVE_BYTE_TYPEDEF
+#endif
+
+#ifndef HAVE_USHORT_TYPEDEF
+# undef ushort /* There might be a macro with this name. */
+ typedef unsigned short ushort;
+# define HAVE_USHORT_TYPEDEF
+#endif
+
+#ifndef HAVE_ULONG_TYPEDEF
+# undef ulong /* There might be a macro with this name. */
+ typedef unsigned long ulong;
+# define HAVE_ULONG_TYPEDEF
+#endif
+
+#ifndef HAVE_U16_TYPEDEF
+# undef u16 /* There might be a macro with this name. */
+# if SIZEOF_UNSIGNED_INT == 2
+ typedef unsigned int u16;
+# elif SIZEOF_UNSIGNED_SHORT == 2
+ typedef unsigned short u16;
+# else
+# error no typedef for u16
+# endif
+# define HAVE_U16_TYPEDEF
+#endif
+
+#ifndef HAVE_U32_TYPEDEF
+# undef u32 /* There might be a macro with this name. */
+# if SIZEOF_UNSIGNED_INT == 4
+ typedef unsigned int u32;
+# elif SIZEOF_UNSIGNED_LONG == 4
+ typedef unsigned long u32;
+# else
+# error no typedef for u32
+# endif
+# define HAVE_U32_TYPEDEF
+#endif
+
+#ifndef HAVE_U64_TYPEDEF
+# undef u64 /* There might be a macro with this name. */
+# if SIZEOF_UNSIGNED_INT == 8
+ typedef unsigned int u64;
+# define HAVE_U64_TYPEDEF
+# elif SIZEOF_UNSIGNED_LONG == 8
+ typedef unsigned long u64;
+# define HAVE_U64_TYPEDEF
+# elif __GNUC__ >= 2 || defined(__SUNPRO_C)
+ typedef unsigned long long u64;
+# define HAVE_U64_TYPEDEF
+# endif
+#endif
+
+
+/* Some GCC attributes. Note that we use also define some in
+ mischelp.h, but this header and types.h are not always included.
+ Should eventually be put into one file (e.g. nlib-common.h). */
+#if __GNUC__ >= 4
+# define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
+#else
+# define GNUPG_GCC_A_SENTINEL(a)
+#endif
+
+
+
+#endif /*LIBJNLIB_TYPES_H*/
diff --git a/common/utf8conv.c b/common/utf8conv.c
new file mode 100644
index 000000000..6cbe4e92c
--- /dev/null
+++ b/common/utf8conv.c
@@ -0,0 +1,813 @@
+/* utf8conf.c - UTF8 character set conversion
+ * Copyright (C) 1994, 1998, 1999, 2000, 2001, 2003, 2006,
+ * 2008, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+#include <errno.h>
+#ifndef HAVE_W32_SYSTEM
+# include <iconv.h>
+#endif
+
+#include "libjnlib-config.h"
+#include "stringhelp.h"
+#include "dynload.h"
+#include "utf8conv.h"
+
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 16
+#endif
+
+static const char *active_charset_name = "iso-8859-1";
+static int no_translation; /* Set to true if we let simply pass through. */
+static int use_iconv; /* iconv comversion fucntions required. */
+
+
+/* Under W32 we dlopen the iconv dll and don't require any iconv
+ related headers at all. However we need to define some stuff. */
+#ifdef HAVE_W32_SYSTEM
+typedef void *iconv_t;
+#ifndef ICONV_CONST
+#define ICONV_CONST
+#endif
+static iconv_t (* __stdcall iconv_open) (const char *tocode,
+ const char *fromcode);
+static size_t (* __stdcall iconv) (iconv_t cd,
+ char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+static int (* __stdcall iconv_close) (iconv_t cd);
+
+static int
+load_libiconv (void)
+{
+ static int done;
+
+ if (!done)
+ {
+ void *handle;
+
+ done = 1; /* Do it right now because we might get called recursivly
+ through gettext. */
+
+ handle = dlopen ("iconv.dll", RTLD_LAZY);
+ if (handle)
+ {
+ iconv_open = dlsym (handle, "libiconv_open");
+ if (iconv_open)
+ iconv = dlsym (handle, "libiconv");
+ if (iconv)
+ iconv_close = dlsym (handle, "libiconv_close");
+ }
+ if (!handle || !iconv_close)
+ {
+ log_info (_("error loading `%s': %s\n"),
+ "iconv.dll", dlerror ());
+ log_info (_("please see %s for more information\n"),
+ "http://www.gnupg.org/download/iconv.html");
+ iconv_open = NULL;
+ iconv = NULL;
+ iconv_close = NULL;
+ if (handle)
+ dlclose (handle);
+ }
+ }
+ return iconv_open? 0: -1;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Error handler for iconv failures. This is needed to not clutter the
+ output with repeated diagnostics about a missing conversion. */
+static void
+handle_iconv_error (const char *to, const char *from, int use_fallback)
+{
+ if (errno == EINVAL)
+ {
+ static int shown1, shown2;
+ int x;
+
+ if (to && !strcmp (to, "utf-8"))
+ {
+ x = shown1;
+ shown1 = 1;
+ }
+ else
+ {
+ x = shown2;
+ shown2 = 1;
+ }
+
+ if (!x)
+ log_info (_("conversion from `%s' to `%s' not available\n"),
+ from, to);
+ }
+ else
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("iconv_open failed: %s\n"), strerror (errno));
+ shown = 1;
+ }
+
+ if (use_fallback)
+ {
+ /* To avoid further error messages we fallback to Latin-1 for the
+ native encoding. This is justified as one can expect that on a
+ utf-8 enabled system nl_langinfo() will work and thus we won't
+ never get to here. Thus Latin-1 seems to be a reasonable
+ default. */
+ active_charset_name = "iso-8859-1";
+ no_translation = 0;
+ use_iconv = 0;
+ }
+}
+
+
+
+int
+set_native_charset (const char *newset)
+{
+ const char *full_newset;
+
+ if (!newset)
+ {
+#ifdef HAVE_W32_SYSTEM
+ static char codepage[30];
+ unsigned int cpno;
+ const char *aliases;
+
+ /* We are a console program thus we need to use the
+ GetConsoleOutputCP function and not the the GetACP which
+ would give the codepage for a GUI program. Note this is not
+ a bulletproof detection because GetConsoleCP might return a
+ different one for console input. Not sure how to cope with
+ that. If the console Code page is not known we fall back to
+ the system code page. */
+#ifndef HAVE_W32CE_SYSTEM
+ cpno = GetConsoleOutputCP ();
+ if (!cpno)
+#endif
+ cpno = GetACP ();
+ sprintf (codepage, "CP%u", cpno );
+ /* Resolve alias. We use a long string string and not the usual
+ array to optimize if the code is taken to a DSO. Taken from
+ libiconv 1.9.2. */
+ newset = codepage;
+ for (aliases = ("CP936" "\0" "GBK" "\0"
+ "CP1361" "\0" "JOHAB" "\0"
+ "CP20127" "\0" "ASCII" "\0"
+ "CP20866" "\0" "KOI8-R" "\0"
+ "CP21866" "\0" "KOI8-RU" "\0"
+ "CP28591" "\0" "ISO-8859-1" "\0"
+ "CP28592" "\0" "ISO-8859-2" "\0"
+ "CP28593" "\0" "ISO-8859-3" "\0"
+ "CP28594" "\0" "ISO-8859-4" "\0"
+ "CP28595" "\0" "ISO-8859-5" "\0"
+ "CP28596" "\0" "ISO-8859-6" "\0"
+ "CP28597" "\0" "ISO-8859-7" "\0"
+ "CP28598" "\0" "ISO-8859-8" "\0"
+ "CP28599" "\0" "ISO-8859-9" "\0"
+ "CP28605" "\0" "ISO-8859-15" "\0"
+ "CP65001" "\0" "UTF-8" "\0");
+ *aliases;
+ aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
+ {
+ if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1]))
+ {
+ newset = aliases + strlen (aliases) + 1;
+ break;
+ }
+ }
+
+#else /*!HAVE_W32_SYSTEM*/
+
+#ifdef HAVE_LANGINFO_CODESET
+ newset = nl_langinfo (CODESET);
+#else /*!HAVE_LANGINFO_CODESET*/
+ /* Try to get the used charset from environment variables. */
+ static char codepage[30];
+ const char *lc, *dot, *mod;
+
+ strcpy (codepage, "iso-8859-1");
+ lc = getenv ("LC_ALL");
+ if (!lc || !*lc)
+ {
+ lc = getenv ("LC_CTYPE");
+ if (!lc || !*lc)
+ lc = getenv ("LANG");
+ }
+ if (lc && *lc)
+ {
+ dot = strchr (lc, '.');
+ if (dot)
+ {
+ mod = strchr (++dot, '@');
+ if (!mod)
+ mod = dot + strlen (dot);
+ if (mod - dot < sizeof codepage && dot != mod)
+ {
+ memcpy (codepage, dot, mod - dot);
+ codepage [mod - dot] = 0;
+ }
+ }
+ }
+ newset = codepage;
+#endif /*!HAVE_LANGINFO_CODESET*/
+#endif /*!HAVE_W32_SYSTEM*/
+ }
+
+ full_newset = newset;
+ if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
+ {
+ newset += 3;
+ if (*newset == '-' || *newset == '_')
+ newset++;
+ }
+
+ /* Note that we silently assume that plain ASCII is actually meant
+ as Latin-1. This makes sense because many Unix system don't have
+ their locale set up properly and thus would get annoying error
+ messages and we have to handle all the "bug" reports. Latin-1 has
+ always been the character set used for 8 bit characters on Unix
+ systems. */
+ if ( !*newset
+ || !ascii_strcasecmp (newset, "8859-1" )
+ || !ascii_strcasecmp (newset, "646" )
+ || !ascii_strcasecmp (newset, "ASCII" )
+ || !ascii_strcasecmp (newset, "ANSI_X3.4-1968" )
+ )
+ {
+ active_charset_name = "iso-8859-1";
+ no_translation = 0;
+ use_iconv = 0;
+ }
+ else if ( !ascii_strcasecmp (newset, "utf8" )
+ || !ascii_strcasecmp(newset, "utf-8") )
+ {
+ active_charset_name = "utf-8";
+ no_translation = 1;
+ use_iconv = 0;
+ }
+ else
+ {
+ iconv_t cd;
+
+#ifdef HAVE_W32_SYSTEM
+ if (load_libiconv ())
+ return -1;
+#endif /*HAVE_W32_SYSTEM*/
+
+ cd = iconv_open (full_newset, "utf-8");
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error (full_newset, "utf-8", 0);
+ return -1;
+ }
+ iconv_close (cd);
+ cd = iconv_open ("utf-8", full_newset);
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error ("utf-8", full_newset, 0);
+ return -1;
+ }
+ iconv_close (cd);
+ active_charset_name = full_newset;
+ no_translation = 0;
+ use_iconv = 1;
+ }
+ return 0;
+}
+
+const char *
+get_native_charset ()
+{
+ return active_charset_name;
+}
+
+/* Return true if the native charset is utf-8. */
+int
+is_native_utf8 (void)
+{
+ return no_translation;
+}
+
+
+/* Convert string, which is in native encoding to UTF8 and return a
+ new allocated UTF-8 string. This function terminates the process
+ on memory shortage. */
+char *
+native_to_utf8 (const char *orig_string)
+{
+ const unsigned char *string = (const unsigned char *)orig_string;
+ const unsigned char *s;
+ char *buffer;
+ unsigned char *p;
+ size_t length = 0;
+
+ if (no_translation)
+ {
+ /* Already utf-8 encoded. */
+ buffer = jnlib_xstrdup (orig_string);
+ }
+ else if (!use_iconv)
+ {
+ /* For Latin-1 we can avoid the iconv overhead. */
+ for (s = string; *s; s++)
+ {
+ length++;
+ if (*s & 0x80)
+ length++;
+ }
+ buffer = jnlib_xmalloc (length + 1);
+ for (p = (unsigned char *)buffer, s = string; *s; s++)
+ {
+ if ( (*s & 0x80 ))
+ {
+ *p++ = 0xc0 | ((*s >> 6) & 3);
+ *p++ = 0x80 | (*s & 0x3f);
+ }
+ else
+ *p++ = *s;
+ }
+ *p = 0;
+ }
+ else
+ {
+ /* Need to use iconv. */
+ iconv_t cd;
+ const char *inptr;
+ char *outptr;
+ size_t inbytes, outbytes;
+
+ cd = iconv_open ("utf-8", active_charset_name);
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error ("utf-8", active_charset_name, 1);
+ return native_to_utf8 (string);
+ }
+
+ for (s=string; *s; s++ )
+ {
+ length++;
+ if ((*s & 0x80))
+ length += 5; /* We may need up to 6 bytes for the utf8 output. */
+ }
+ buffer = jnlib_xmalloc (length + 1);
+
+ inptr = string;
+ inbytes = strlen (string);
+ outptr = buffer;
+ outbytes = length;
+ if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("conversion from `%s' to `%s' failed: %s\n"),
+ active_charset_name, "utf-8", strerror (errno));
+ shown = 1;
+ /* We don't do any conversion at all but use the strings as is. */
+ strcpy (buffer, string);
+ }
+ else /* Success. */
+ {
+ *outptr = 0;
+ /* We could realloc the buffer now but I doubt that it makes
+ much sense given that it will get freed anyway soon
+ after. */
+ }
+ iconv_close (cd);
+ }
+ return buffer;
+}
+
+
+
+static char *
+do_utf8_to_native (const char *string, size_t length, int delim,
+ int with_iconv)
+{
+ int nleft;
+ int i;
+ unsigned char encbuf[8];
+ int encidx;
+ const unsigned char *s;
+ size_t n;
+ char *buffer = NULL;
+ char *p = NULL;
+ unsigned long val = 0;
+ size_t slen;
+ int resync = 0;
+
+ /* First pass (p==NULL): count the extended utf-8 characters. */
+ /* Second pass (p!=NULL): create string. */
+ for (;;)
+ {
+ for (slen = length, nleft = encidx = 0, n = 0,
+ s = (const unsigned char *)string;
+ slen;
+ s++, slen--)
+ {
+ if (resync)
+ {
+ if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
+ {
+ /* Still invalid. */
+ if (p)
+ {
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4;
+ continue;
+ }
+ resync = 0;
+ }
+ if (!nleft)
+ {
+ if (!(*s & 0x80))
+ {
+ /* Plain ascii. */
+ if ( delim != -1
+ && (*s < 0x20 || *s == 0x7f || *s == delim
+ || (delim && *s == '\\')))
+ {
+ n++;
+ if (p)
+ *p++ = '\\';
+ switch (*s)
+ {
+ case '\n': n++; if ( p ) *p++ = 'n'; break;
+ case '\r': n++; if ( p ) *p++ = 'r'; break;
+ case '\f': n++; if ( p ) *p++ = 'f'; break;
+ case '\v': n++; if ( p ) *p++ = 'v'; break;
+ case '\b': n++; if ( p ) *p++ = 'b'; break;
+ case 0: n++; if ( p ) *p++ = '0'; break;
+ default:
+ n += 3;
+ if (p)
+ {
+ sprintf (p, "x%02x", *s);
+ p += 3;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (p)
+ *p++ = *s;
+ n++;
+ }
+ }
+ else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
+ {
+ val = *s & 0x1f;
+ nleft = 1;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
+ {
+ val = *s & 0x0f;
+ nleft = 2;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
+ {
+ val = *s & 0x07;
+ nleft = 3;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
+ {
+ val = *s & 0x03;
+ nleft = 4;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
+ {
+ val = *s & 0x01;
+ nleft = 5;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else /* Invalid encoding: print as \xNN. */
+ {
+ if (p)
+ {
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4;
+ resync = 1;
+ }
+ }
+ else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
+ {
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ {
+ sprintf (p, "\\x%02x", encbuf[i]);
+ p += 4;
+ }
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4 + 4 * encidx;
+ nleft = 0;
+ encidx = 0;
+ resync = 1;
+ }
+ else
+ {
+ encbuf[encidx++] = *s;
+ val <<= 6;
+ val |= *s & 0x3f;
+ if (!--nleft) /* Ready. */
+ {
+ if (no_translation)
+ {
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ *p++ = encbuf[i];
+ }
+ n += encidx;
+ encidx = 0;
+ }
+ else if (with_iconv)
+ {
+ /* Our strategy for using iconv is a bit strange
+ but it better keeps compatibility with
+ previous versions in regard to how invalid
+ encodings are displayed. What we do is to
+ keep the utf-8 as is and have the real
+ translation step then at the end. Yes, I
+ know that this is ugly. However we are short
+ of the 1.4 release and for this branch we
+ should not mess too much around with iconv
+ things. One reason for this is that we don't
+ know enough about non-GNU iconv
+ implementation and want to minimize the risk
+ of breaking the code on too many platforms. */
+ if ( p )
+ {
+ for (i=0; i < encidx; i++ )
+ *p++ = encbuf[i];
+ }
+ n += encidx;
+ encidx = 0;
+ }
+ else /* Latin-1 case. */
+ {
+ if (val >= 0x80 && val < 256)
+ {
+ /* We can simply print this character */
+ n++;
+ if (p)
+ *p++ = val;
+ }
+ else
+ {
+ /* We do not have a translation: print utf8. */
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ {
+ sprintf (p, "\\x%02x", encbuf[i]);
+ p += 4;
+ }
+ }
+ n += encidx * 4;
+ encidx = 0;
+ }
+ }
+ }
+
+ }
+ }
+ if (!buffer)
+ {
+ /* Allocate the buffer after the first pass. */
+ buffer = p = jnlib_xmalloc (n + 1);
+ }
+ else if (with_iconv)
+ {
+ /* Note: See above for comments. */
+ iconv_t cd;
+ const char *inptr;
+ char *outbuf, *outptr;
+ size_t inbytes, outbytes;
+
+ *p = 0; /* Terminate the buffer. */
+
+ cd = iconv_open (active_charset_name, "utf-8");
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error (active_charset_name, "utf-8", 1);
+ jnlib_free (buffer);
+ return utf8_to_native (string, length, delim);
+ }
+
+ /* Allocate a new buffer large enough to hold all possible
+ encodings. */
+ n = p - buffer + 1;
+ inbytes = n - 1;;
+ inptr = buffer;
+ outbytes = n * MB_LEN_MAX;
+ if (outbytes / MB_LEN_MAX != n)
+ BUG (); /* Actually an overflow. */
+ outbuf = outptr = jnlib_xmalloc (outbytes);
+ if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("conversion from `%s' to `%s' failed: %s\n"),
+ "utf-8", active_charset_name, strerror (errno));
+ shown = 1;
+ /* Didn't worked out. Try again but without iconv. */
+ jnlib_free (buffer);
+ buffer = NULL;
+ jnlib_free (outbuf);
+ outbuf = do_utf8_to_native (string, length, delim, 0);
+ }
+ else /* Success. */
+ {
+ *outptr = 0; /* Make sure it is a string. */
+ /* We could realloc the buffer now but I doubt that it
+ makes much sense given that it will get freed
+ anyway soon after. */
+ jnlib_free (buffer);
+ }
+ iconv_close (cd);
+ return outbuf;
+ }
+ else /* Not using iconv. */
+ {
+ *p = 0; /* Make sure it is a string. */
+ return buffer;
+ }
+ }
+}
+
+/* Convert string, which is in UTF-8 to native encoding. Replace
+ illegal encodings by some "\xnn" and quote all control
+ characters. A character with value DELIM will always be quoted, it
+ must be a vanilla ASCII character. A DELIM value of -1 is special:
+ it disables all quoting of control characters. This function
+ terminates the process on memory shortage. */
+char *
+utf8_to_native (const char *string, size_t length, int delim)
+{
+ return do_utf8_to_native (string, length, delim, use_iconv);
+}
+
+
+
+
+/* Wrapper function for iconv_open, required for W32 as we dlopen that
+ library on that system. */
+jnlib_iconv_t
+jnlib_iconv_open (const char *tocode, const char *fromcode)
+{
+#ifdef HAVE_W32_SYSTEM
+ if (load_libiconv ())
+ return (jnlib_iconv_t)(-1);
+#endif /*HAVE_W32_SYSTEM*/
+
+ return (jnlib_iconv_t)iconv_open (tocode, fromcode);
+}
+
+
+/* Wrapper function for iconv, required for W32 as we dlopen that
+ library on that system. */
+size_t
+jnlib_iconv (jnlib_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+
+#ifdef HAVE_W32_SYSTEM
+ if (load_libiconv ())
+ return 0;
+#endif /*HAVE_W32_SYSTEM*/
+
+ return iconv ((iconv_t)cd, (char**)inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+/* Wrapper function for iconv_close, required for W32 as we dlopen that
+ library on that system. */
+int
+jnlib_iconv_close (jnlib_iconv_t cd)
+{
+#ifdef HAVE_W32_SYSTEM
+ if (load_libiconv ())
+ return 0;
+#endif /*HAVE_W32_SYSTEM*/
+
+ return iconv_close ((iconv_t)cd);
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Return a malloced string encoded in UTF-8 from the wide char input
+ string STRING. Caller must free this value. Returns NULL and sets
+ ERRNO on failure. Calling this function with STRING set to NULL is
+ not defined. */
+char *
+wchar_to_utf8 (const wchar_t *string)
+{
+ int n;
+ char *result;
+
+ n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
+ if (n < 0)
+ {
+ jnlib_set_errno (EINVAL);
+ return NULL;
+ }
+
+ result = jnlib_malloc (n+1);
+ if (!result)
+ return NULL;
+
+ n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
+ if (n < 0)
+ {
+ jnlib_free (result);
+ jnlib_set_errno (EINVAL);
+ result = NULL;
+ }
+ return result;
+}
+
+
+/* Return a malloced wide char string from an UTF-8 encoded input
+ string STRING. Caller must free this value. Returns NULL and sets
+ ERRNO on failure. Calling this function with STRING set to NULL is
+ not defined. */
+wchar_t *
+utf8_to_wchar (const char *string)
+{
+ int n;
+ size_t nbytes;
+ wchar_t *result;
+
+ n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
+ if (n < 0)
+ {
+ jnlib_set_errno (EINVAL);
+ return NULL;
+ }
+
+ nbytes = (size_t)(n+1) * sizeof(*result);
+ if (nbytes / sizeof(*result) != (n+1))
+ {
+ jnlib_set_errno (ENOMEM);
+ return NULL;
+ }
+ result = malloc (nbytes);
+ if (!result)
+ return NULL;
+
+ n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
+ if (n < 0)
+ {
+ free (result);
+ jnlib_set_errno (EINVAL);
+ result = NULL;
+ }
+ return result;
+}
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/utf8conv.h b/common/utf8conv.h
new file mode 100644
index 000000000..28dd450dd
--- /dev/null
+++ b/common/utf8conv.h
@@ -0,0 +1,45 @@
+/* utf8conf.h
+ * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_UTF8CONF_H
+#define LIBJNLIB_UTF8CONF_H
+
+int set_native_charset (const char *newset);
+const char *get_native_charset (void);
+int is_native_utf8 (void);
+
+char *native_to_utf8 (const char *string);
+char *utf8_to_native (const char *string, size_t length, int delim);
+
+
+/* Silly wrappers, required for W32 portability. */
+typedef void *jnlib_iconv_t;
+
+jnlib_iconv_t jnlib_iconv_open (const char *tocode, const char *fromcode);
+size_t jnlib_iconv (jnlib_iconv_t cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+int jnlib_iconv_close (jnlib_iconv_t cd);
+
+#ifdef HAVE_W32_SYSTEM
+char *wchar_to_utf8 (const wchar_t *string);
+wchar_t *utf8_to_wchar (const char *string);
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#endif /*LIBJNLIB_UTF8CONF_H*/
diff --git a/common/util.h b/common/util.h
index 56678620b..32d4085e7 100644
--- a/common/util.h
+++ b/common/util.h
@@ -33,29 +33,30 @@
/* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
+/* Estream replaces most uses of stdio. */
+#include "../common/estream.h"
+#include "../common/estream-printf.h"
+
/* Get all the stuff from jnlib. */
-#include "../jnlib/logging.h"
-#include "../jnlib/argparse.h"
-#include "../jnlib/stringhelp.h"
-#include "../jnlib/mischelp.h"
-#include "../jnlib/strlist.h"
-#include "../jnlib/dotlock.h"
-#include "../jnlib/utf8conv.h"
-#include "../jnlib/dynload.h"
+#include "../common/logging.h"
+#include "../common/argparse.h"
+#include "../common/stringhelp.h"
+#include "../common/mischelp.h"
+#include "../common/strlist.h"
+#include "../common/dotlock.h"
+#include "../common/utf8conv.h"
+#include "../common/dynload.h"
#include "init.h"
/* Redefine asprintf by our estream version which uses our own memory
allocator.. */
-#include "estream-printf.h"
#define asprintf estream_asprintf
#define vasprintf estream_vasprintf
-/* Due to a bug in mingw32's snprintf related to the 'l' modifier we
- better use our snprintf. */
-#ifdef HAVE_W32_SYSTEM
+/* Due to a bug in mingw32's snprintf related to the 'l' modifier and
+ for increased portability we use our snprintf on all systems. */
#define snprintf estream_snprintf
-#endif
/* GCC attributes. */
diff --git a/common/w32-afunix.c b/common/w32-afunix.c
new file mode 100644
index 000000000..579621491
--- /dev/null
+++ b/common/w32-afunix.c
@@ -0,0 +1,138 @@
+/* w32-afunix.c - AF_UNIX emulation for Windows (Client only).
+ * Copyright (C) 2004, 2006 g10 Code GmbH
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Use of this code is preprecated - you better use the sockt wrappers
+ from libassuan. */
+
+#ifdef _WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <errno.h>
+
+#include "w32-afunix.h"
+
+
+
+/* The buffer for NONCE needs to be at least 16 bytes. Returns 0 on
+ success. */
+static int
+read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
+{
+ FILE *fp;
+ char buffer[50], *p;
+ size_t nread;
+ int aval;
+
+ fp = fopen (fname, "rb");
+ if (!fp)
+ return -1;
+ nread = fread (buffer, 1, sizeof buffer - 1, fp);
+ fclose (fp);
+ if (!nread)
+ {
+#warning remove this file
+ jnlib_set_errno (EIO);
+ return -1;
+ }
+ buffer[nread] = 0;
+ aval = atoi (buffer);
+ if (aval < 1 || aval > 65535)
+ {
+ jnlib_set_errno (EINVAL);
+ return -1;
+ }
+ *port = (unsigned int)aval;
+ for (p=buffer; nread && *p != '\n'; p++, nread--)
+ ;
+ if (*p != '\n' || nread != 17)
+ {
+ jnlib_set_errno (EINVAL);
+ return -1;
+ }
+ p++; nread--;
+ memcpy (nonce, p, 16);
+ return 0;
+}
+
+
+
+int
+_w32_close (int fd)
+{
+ int rc = closesocket (fd);
+ if (rc && WSAGetLastError () == WSAENOTSOCK)
+ rc = close (fd);
+ return rc;
+}
+
+
+int
+_w32_sock_new (int domain, int type, int proto)
+{
+ if (domain == AF_UNIX || domain == AF_LOCAL)
+ domain = AF_INET;
+ return socket (domain, type, proto);
+}
+
+
+int
+_w32_sock_connect (int sockfd, struct sockaddr *addr, int addrlen)
+{
+ struct sockaddr_in myaddr;
+ struct sockaddr_un *unaddr;
+ unsigned short port;
+ char nonce[16];
+ int ret;
+
+ (void)addrlen;
+
+ unaddr = (struct sockaddr_un *)addr;
+ if (read_port_and_nonce (unaddr->sun_path, &port, nonce))
+ return -1;
+
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_port = htons (port);
+ myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ /* Set return values. */
+ unaddr->sun_family = myaddr.sin_family;
+ unaddr->sun_port = myaddr.sin_port;
+ unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
+
+ ret = connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr);
+ if (!ret)
+ {
+ /* Send the nonce. */
+ ret = send (sockfd, nonce, 16, 0);
+ if (ret >= 0 && ret != 16)
+ {
+ jnlib_set_errno (EIO);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+
+#endif /*_WIN32*/
diff --git a/common/w32-afunix.h b/common/w32-afunix.h
new file mode 100644
index 000000000..23681ddeb
--- /dev/null
+++ b/common/w32-afunix.h
@@ -0,0 +1,52 @@
+/* w32-afunix.h - AF_UNIX emulation for Windows
+ * Copyright (C) 2004, 2006 g10 Code GmbH
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef _WIN32
+#ifndef W32AFUNIX_DEFS_H
+#define W32AFUNIX_DEFS_H
+
+#include <sys/types.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <unistd.h>
+
+/* We can easiliy replace this code by the socket wrappers from libassuan. */
+#warning Please do not use this module anymore
+
+#define DIRSEP_C '\\'
+
+#define AF_LOCAL AF_UNIX
+/* We need to prefix the structure with a sockaddr_in header so we can
+ use it later for sendto and recvfrom. */
+struct sockaddr_un
+{
+ short sun_family;
+ unsigned short sun_port;
+ struct in_addr sun_addr;
+ char sun_path[108-2-4]; /* Path name. */
+};
+
+
+int _w32_close (int fd);
+int _w32_sock_new (int domain, int type, int proto);
+int _w32_sock_connect (int sockfd, struct sockaddr *addr, int addrlen);
+
+
+#endif /*W32AFUNIX_DEFS_H*/
+#endif /*_WIN32*/
diff --git a/common/w32-reg.c b/common/w32-reg.c
new file mode 100644
index 000000000..5809c32bb
--- /dev/null
+++ b/common/w32-reg.c
@@ -0,0 +1,312 @@
+/* w32-reg.c - MS-Windows Registry access
+ * Copyright (C) 1999, 2002, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#ifdef HAVE_W32_SYSTEM
+ /* This module is only used in this environment */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <windows.h>
+
+#include "libjnlib-config.h"
+#include "utf8conv.h"
+#include "w32help.h"
+
+
+static HKEY
+get_root_key(const char *root)
+{
+ HKEY root_key;
+
+ if (!root)
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp( root, "HKEY_CLASSES_ROOT" ) )
+ root_key = HKEY_CLASSES_ROOT;
+ else if (!strcmp( root, "HKEY_CURRENT_USER" ) )
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp( root, "HKEY_LOCAL_MACHINE" ) )
+ root_key = HKEY_LOCAL_MACHINE;
+ else if (!strcmp( root, "HKEY_USERS" ) )
+ root_key = HKEY_USERS;
+ else if (!strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
+ root_key = HKEY_PERFORMANCE_DATA;
+ else if (!strcmp( root, "HKEY_CURRENT_CONFIG" ) )
+ root_key = HKEY_CURRENT_CONFIG;
+ else
+ return NULL;
+
+ return root_key;
+}
+
+
+/* Return a string from the Win32 Registry or NULL in case of error.
+ Caller must release the return value. A NULL for root is an alias
+ for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
+char *
+read_w32_registry_string (const char *root, const char *dir, const char *name)
+{
+#ifdef HAVE_W32CE_SYSTEM
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes, type;
+ char *result = NULL;
+ wchar_t *wdir, *wname;
+
+ if ( !(root_key = get_root_key(root) ) )
+ return NULL;
+
+ wdir = utf8_to_wchar (dir);
+ if (!wdir)
+ return NULL;
+
+ if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) )
+ {
+ if (root)
+ {
+ jnlib_free (wdir);
+ return NULL; /* No need for a RegClose, so return immediately. */
+ }
+ /* It seems to be common practise to fall back to HKLM. */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) )
+ {
+ jnlib_free (wdir);
+ return NULL; /* Still no need for a RegClose. */
+ }
+ }
+ jnlib_free (wdir);
+
+ if (name)
+ {
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ goto leave;
+ }
+ else
+ wname = NULL;
+
+ nbytes = 2;
+ if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes))
+ goto leave;
+ result = jnlib_malloc ((n1=nbytes+2));
+ if (!result)
+ goto leave;
+ if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1))
+ {
+ jnlib_free (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is a string. */
+ result[nbytes+1] = 0;
+ if (type == REG_SZ || type == REG_EXPAND_SZ)
+ {
+ wchar_t *tmp = (void*)result;
+ result = wchar_to_utf8 (tmp);
+ jnlib_free (tmp);
+ }
+
+ leave:
+ jnlib_free (wname);
+ RegCloseKey (key_handle);
+ return result;
+#else /*!HAVE_W32CE_SYSTEM*/
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes, type;
+ char *result = NULL;
+
+ if ( !(root_key = get_root_key(root) ) )
+ return NULL;
+
+ if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) )
+ {
+ if (root)
+ return NULL; /* No need for a RegClose, so return immediately. */
+ /* It seems to be common practise to fall back to HKLM. */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+ return NULL; /* Still no need for a RegClose. */
+ }
+
+ nbytes = 1;
+ if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
+ goto leave;
+ result = jnlib_malloc ((n1=nbytes+1));
+ if (!result)
+ goto leave;
+ if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ))
+ {
+ jnlib_free (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is a string. */
+ if (type == REG_EXPAND_SZ && strchr (result, '%'))
+ {
+ char *tmp;
+
+ n1 += 1000;
+ tmp = jnlib_malloc (n1+1);
+ if (!tmp)
+ goto leave;
+ nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+ if (nbytes && nbytes > n1)
+ {
+ jnlib_free (tmp);
+ n1 = nbytes;
+ tmp = jnlib_malloc (n1 + 1);
+ if (!tmp)
+ goto leave;
+ nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+ if (nbytes && nbytes > n1)
+ {
+ /* Oops - truncated, better don't expand at all. */
+ jnlib_free (tmp);
+ goto leave;
+ }
+ tmp[nbytes] = 0;
+ jnlib_free (result);
+ result = tmp;
+ }
+ else if (nbytes)
+ {
+ /* Okay, reduce the length. */
+ tmp[nbytes] = 0;
+ jnlib_free (result);
+ result = jnlib_malloc (strlen (tmp)+1);
+ if (!result)
+ result = tmp;
+ else
+ {
+ strcpy (result, tmp);
+ jnlib_free (tmp);
+ }
+ }
+ else
+ {
+ /* Error - don't expand. */
+ jnlib_free (tmp);
+ }
+ }
+
+ leave:
+ RegCloseKey (key_handle);
+ return result;
+#endif /*!HAVE_W32CE_SYSTEM*/
+}
+
+
+/* Note: This code is not well tested. However, it is not used in
+ GnuPG. */
+int
+write_w32_registry_string (const char *root, const char *dir,
+ const char *name, const char *value)
+{
+ HKEY root_key, reg_key;
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wdir, *wname, *wvalue;
+ DWORD disp;
+
+ if ( !(root_key = get_root_key(root) ) )
+ return -1;
+
+ wdir = utf8_to_wchar (dir);
+ if (!wdir)
+ return -1;
+
+ if (RegOpenKeyEx (root_key, wdir, 0, 0, &reg_key))
+ {
+ jnlib_free (wdir);
+ return -1;
+ }
+ jnlib_free (wdir);
+
+ if (name)
+ {
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return -1;
+ }
+ else
+ wname = NULL;
+
+ wvalue = utf8_to_wchar (value);
+ if (wvalue)
+ {
+ jnlib_free (wname);
+ return -1;
+ }
+
+ if (RegSetValueEx (reg_key, wname, 0, REG_SZ,
+ (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
+ {
+
+ if (RegCreateKeyEx (root_key, wname, 0, NULL, 0, 0, NULL,
+ &reg_key, &disp) != ERROR_SUCCESS)
+ {
+ RegCloseKey(reg_key);
+ jnlib_free (wname);
+ jnlib_free (wvalue);
+ return -1;
+ }
+ if (RegSetValueEx (reg_key, wname, 0, REG_SZ,
+ (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
+ {
+ RegCloseKey(reg_key);
+ jnlib_free (wname);
+ jnlib_free (wvalue);
+ return -1;
+ }
+ }
+
+ jnlib_free (wname);
+ jnlib_free (wvalue);
+ RegCloseKey (reg_key);
+ return 0;
+#else /*!HAVE_W32CE_SYSTEM*/
+
+ if ( !(root_key = get_root_key(root) ) )
+ return -1;
+
+ if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, &reg_key )
+ != ERROR_SUCCESS )
+ return -1;
+
+ if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value,
+ strlen( value ) ) != ERROR_SUCCESS )
+ {
+ if ( RegCreateKey( root_key, name, &reg_key ) != ERROR_SUCCESS )
+ {
+ RegCloseKey(reg_key);
+ return -1;
+ }
+ if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value,
+ strlen( value ) ) != ERROR_SUCCESS )
+ {
+ RegCloseKey(reg_key);
+ return -1;
+ }
+ }
+
+ RegCloseKey (reg_key);
+ return 0;
+#endif /*!HAVE_W32CE_SYSTEM*/
+}
+
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/w32help.h b/common/w32help.h
new file mode 100644
index 000000000..518d4251c
--- /dev/null
+++ b/common/w32help.h
@@ -0,0 +1,32 @@
+/* w32help.h - W32 speicif functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_W32HELP_H
+#define LIBJNLIB_W32HELP_H
+#ifdef HAVE_W32_SYSTEM
+
+/*-- w32-reg.c --*/
+char *read_w32_registry_string (const char *root,
+ const char *dir, const char *name );
+int write_w32_registry_string (const char *root, const char *dir,
+ const char *name, const char *value);
+
+
+#endif /*HAVE_W32_SYSTEM*/
+#endif /*LIBJNLIB_MISCHELP_H*/
diff --git a/common/xasprintf.c b/common/xasprintf.c
index 9774d06de..f16410dbd 100644
--- a/common/xasprintf.c
+++ b/common/xasprintf.c
@@ -23,7 +23,6 @@
#include "util.h"
#include "iobuf.h"
-#include "estream-printf.h"
#if !defined(_ESTREAM_PRINTF_MALLOC) || !defined(_ESTREAM_PRINTF_FREE)
#error Need to define ESTREAM_PRINTF_MALLOC and _FREE
diff --git a/common/xmalloc.c b/common/xmalloc.c
new file mode 100644
index 000000000..eb6d5ab11
--- /dev/null
+++ b/common/xmalloc.c
@@ -0,0 +1,87 @@
+/* xmalloc.c - standard malloc wrappers
+ * Copyright (C) 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "libjnlib-config.h"
+#include "xmalloc.h"
+
+static void
+out_of_core(void)
+{
+ fputs("\nfatal: out of memory\n", stderr );
+ exit(2);
+}
+
+
+void *
+xmalloc( size_t n )
+{
+ void *p = malloc( n );
+ if( !p )
+ out_of_core();
+ return p;
+}
+
+void *
+xrealloc( void *a, size_t n )
+{
+ void *p = realloc( a, n );
+ if( !p )
+ out_of_core();
+ return p;
+}
+
+void *
+xcalloc( size_t n, size_t m )
+{
+ void *p = calloc( n, m );
+ if( !p )
+ out_of_core();
+ return p;
+}
+
+char *
+xstrdup( const char *string )
+{
+ void *p = xmalloc( strlen(string)+1 );
+ strcpy( p, string );
+ return p;
+}
+
+
+char *
+xstrcat2( const char *a, const char *b )
+{
+ size_t n1;
+ char *p;
+
+ if( !b )
+ return xstrdup( a );
+
+ n1 = strlen(a);
+ p = xmalloc( n1 + strlen(b) + 1 );
+ memcpy(p, a, n1 );
+ strcpy(p+n1, b );
+ return p;
+}
+
diff --git a/common/xmalloc.h b/common/xmalloc.h
new file mode 100644
index 000000000..8c9c5292b
--- /dev/null
+++ b/common/xmalloc.h
@@ -0,0 +1,30 @@
+/* xmalloc.h
+ * Copyright (C) 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * JNLIB is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_XMALLOC_H
+#define LIBJNLIB_XMALLOC_H
+
+void *xmalloc( size_t n );
+void *xrealloc( void *a, size_t n );
+void *xcalloc( size_t n, size_t m );
+char *xstrdup( const char *string );
+char *xstrcat2( const char *a, const char *b );
+
+
+#endif /*LIBJNLIB_XMALLOC_H*/